Skip to content

feat(skills): move the openclaw-cmd skill body beside its candy - #9

Merged
github-actions[bot] merged 1 commit into
mainfrom
fix/skill-bodies
Oct 20, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
fix/skill-bodies

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Summary

Moves the inline skill: body out of candy/plugin-openclaw/charly.yml and into the candy's own
.agents/skills/ directory — beside the candy that declares each node, which is where the loader reads it — leaving each
skill: node carrying only its routing metadata. The exact file paths are in the table below; no placeholder path is
narrated here
, because a path in prose that the diff does not contain is a claim the reader cannot check.

node body lines
openclaw-cmd candy/plugin-openclaw/.agents/skills/openclaw-cmd/SKILL.md 102

Diff against main: 102 insertions and 96 deletions across 2 files — 1 new
SKILL.md and the manifest, whose 1 skill-owned content: block are deleted.

The same hunk also deletes the 1 description: block(s) from the skill: node(s). That is deliberate and part of this change, not collateral: sdk/deploykit/skills_collect.go reads entry.Description = s.Description only on its sf == nil branch — the transitional in-line form — and entry.Description = sf.Description overwrites it unconditionally once a body file exists, so the node field is unreachable after this migration.

Why beside the candy, and how it is proven

sdk/deploykit/skills_collect.go resolves the tree as filepath.Join(layer.GetSourceDir(), ".agents/skills"), and
GetSourceDir() is the directory of the candy whose manifest declares the node.

sdk#430 (merged, v0.2026293.1143) added deploykit.CollectSkillBodies, and plugin-box#57 (merged,
v2026.293.1153) calls it from runValidateEngine — so charly box validate now fails when an authored skill:
node has no body beside its candy. Before those two merges, no command in a repo that composes no box could read a
skill body at all, because CollectSkills gates body reads on BoxCandyChain, a label-size policy.

How tested

Change class: config.

$ charly box validate
charly box validate: OK — checked 1 candy, 7 distros, 7 builders; 0 warnings, 0 errors
$ echo $?
0

Negative control — the body moved to the repository root:

$ charly box validate
charly: error: command "validate": validation error: skills: skill "openclaw-cmd": no body — the node carries no in-line `content:` and no SKILL.md exists under .agents/skills beside the owning candy "plugin-openclaw"
$ echo $?
1

Same tree, same nodes, same manifest — only one body's location differed.

$ git diff --numstat origin/main HEAD
102	0	candy/plugin-openclaw/.agents/skills/openclaw-cmd/SKILL.md
0	96	candy/plugin-openclaw/charly.yml
$ git diff origin/main HEAD -- candy/plugin-openclaw/charly.yml | grep -E '^@@'
@@ -53,101 +53,5 @@ openclaw-skill:

1 hunk(s) in the manifest diff, against 1 stripped content: block(s). The counts differ where two deletions are close enough for git diff to fold them into one hunk - the block count is the one that must match what was stripped, and the hunk count is what the diff actually shows.

Root .agents/ tree check — the body's R5 claim, shown rather than asserted:

$ git ls-tree -r --name-only HEAD | grep -cE '^\.agents/'
0

Rulebook compliance

  • R0: skills loaded before the first action; /charly-internals:git-workflow before any git command.
  • R1: no unfiled finding. opencharly/opencharly#530 (the missing gate) is closed by sdk#430 + plugin-box#57; #528 records the layout rule.
  • R2: no duplication — the check lives in deploykit and plugin-box, not in this repo.
  • R3: no workaround, no script, no git add -f. Non-skill content: blocks are classified, not stripped.
  • R4: the loader's own resolution decided the paths.
  • R5: no legacy path left. Proof pasted, not asserted — the committed tree has no root .agents/ tree:
$ git ls-tree -r --name-only HEAD | grep -cE '^\.agents/'
0

And the manifest carries no skill content: and no root .agents/ tree. Claim-keyed check: the numstat above.

  • R6: git status read first; one branch off origin/main; 1 commit, no amendment, no force-push.
  • R7: coverage fails without the change — the negative control is the same tree with one body's path changed, rc=1.
  • R8: no live service boundary.
  • R9: binary equals source. The charly used is the worktree-local dev build
    (bootstrap-charly.sh --dev-plugin plugin-box=<worktree>, i.e. the merged plugin-box#57 code), and it reports:
$ charly version
2026.289.1441

The source worktree is at ed9a5dad, whose CHANGELOG/ names the same CalVer — so the binary matches the
source it was built from, which is what R9 asks for.

  • R10: config change; charly box validate run on the committed tree with both controls pasted.

Change classification

Config — 1 skill body relocated beside its candy.

Filed issues

  • opencharly/opencharly#530 — no in-repo gate exercises skill-body collection for a repo that authors no box. Closed by sdk#430 + plugin-box#57.
  • opencharly/opencharly#528 — the layout rule the migration depends on.

Agent: charly

Assisted-by: DeepSeek Harness ollama-cloud deepseek-v4.1-flash (analysed on a live system)

The check-family skill body leaves candy/plugin-openclaw/charly.yml for
.agents/skills/openclaw-cmd/SKILL.md beside the candy, keeping full YAML frontmatter. The node
content: and description: blocks are deleted; the description is unreachable after migration
because skills_collect.go reads s.Description only on its sf == nil branch. Two files, 102/96.
@github-actions

Copy link
Copy Markdown

Review — PASS

Head SHA: 8e5b35c0462bb48e6787e4952b9e97cc0919f4af (branch: fix/skill-bodies)

Security screen: PASS — no secrets, no code, no guardrail/rulebook change, no supply-chain edit; body is data, not instruction.
Change class: config (candy manifest + candy-local skill doc). Gate charly box validate matches; negative control proves the changed resolution path (body-beside-candy vs root) fails without the change.
Checklist: All applicable rules PASS or NA (A1–A3, R0–R10, PIL/ADE/SDD, CONC, HC, DISP, QUAL, COORD). Description block in the moved SKILL.md frontmatter folds to the same literal text as the deleted content:/description: — verified line-by-line, no drift.
Placement: CORRECT — the skill body is candy-owned data placed beside the declaring candy; the mechanism stays in sdk/deploykit + plugin-box, not core. No alias/core-import growth.

Verdict: PASS


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

@github-actions
github-actions Bot enabled auto-merge (squash) October 20, 2026 15:38
@github-actions
github-actions Bot merged commit 7095675 into main Oct 20, 2026
1 check passed
charly-auto-merge Bot added a commit that referenced this pull request Oct 20, 2026
github-actions Bot pushed a commit that referenced this pull request Oct 22, 2026
…e the reader now looks (#10)

sdk#445 moved deploykit's skill base from the owning candy's directory to the owning candy's
REPO ROOT: filepath.Join(repoRoot, ".agents/skills"). This commit is the mirror image of #9
(2026.293.1539), which moved the body BESIDE the candy under the old base -- so under the new
reader the node has no body at all, and `charly box validate` at this repo's main says exactly
that (rc=1, naming the repo root).

Pure move: the SKILL.md blob is byte-identical before and after (f3e7bca), the candy
manifest is untouched, and the candy-dir copy is deleted in this same commit.

Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)

Co-authored-by: Andreas Trawoeger <atrawog@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants