fix(kyberforge): unblock the scaffold and finish the #125 and ADR-0022 edits

Three related half-applied changes from #130, each leaving the corpus in a state its own
documentation contradicts.

Why:
- `assets/templates/SKILL.md` shipped `metadata:` fully commented out, and `new-skill.sh` only
  substitutes SKILL_NAME. Every scaffolded skill therefore lacked the `metadata.version` ADR-0022
  made mandatory and was blocked at first commit by the very hook this PR added. The commented
  example also read `"1.0"` — neither the `0.1.0` new-skill seed nor valid semver.
- `agent-audit/references/scope-project-user.md` still joined `disable-model-invocation` and
  `user-invocable` with a slash — #125's defect verbatim — while pointing the reader at the file
  this PR had just corrected to say the opposite.
- ADR-0022 required the "when present" bump conditional dropped and `metadata.version` moved into
  create.md's required list. It was dropped from SKILL.md but left in README.md, and the field was
  edited in place under a heading that still authorises removing it entirely.

Implementation notes:
- The template emits `metadata: version: "0.1.0"` live, captioned as required, with the optional
  keys left commented. `new-skill.bats` gains a case asserting a live key and three-part semver, so
  this cannot regress.
- `description-quality.md` now asserts only what the vendored Copilot research supports: two fields
  with opposite defaults, and the retired `infer` replaced by the pair rather than by either alone.
  The unsupported negative it previously stated as fact is gone.
- The `1.0.0` retrofit seed is stated in improve.md and retrofit.md, which the retrofit flow
  actually reads — create.md, where it lived, is unreachable from that path. The compression item
  moved out of the file-churn checklist, whose preamble excluded the wording-only change it covers.
- Executable git commands in these three skills now carry the ADR-0023 rtk prefix.

Refs: #125, #127
ADR: 0022, 0023
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
This commit is contained in:
2026-09-09 05:15:23 +00:00
parent 175ea89c0a
commit 3811f5481b
11 changed files with 81 additions and 32 deletions

View File

@@ -7,7 +7,7 @@ description: >
directory -> skill-audit. directory -> skill-audit.
allowed-tools: Bash Read allowed-tools: Bash Read
metadata: metadata:
version: "1.0.0" version: "1.0.1"
category: factory category: factory
source_keys: source_keys:
- context7-websites-code-claude - context7-websites-code-claude

View File

@@ -36,9 +36,12 @@ Read the frontmatter before judging a single word.
Its Claude Code counterpart has no equivalent field and stays model-invoked, so the two halves of Its Claude Code counterpart has no equivalent field and stays model-invoked, so the two halves of
the pair carrying differently shaped descriptions is expected there rather than a the pair carrying differently shaped descriptions is expected there rather than a
pair-consistency finding. pair-consistency finding.
`user-invocable: false` does not belong in this bullet: it only blocks manual invocation and is `user-invocable: false` does not belong in this bullet. The two are separate fields with opposite
independent of `disable-model-invocation` — an agent can be `user-invocable: false` and still defaults — `disable-model-invocation` (default `false`) governs runtime auto-selection,
model-routed, in which case the three-part shape below still applies. It carries no `user-invocable` (default `true`) governs manual invocation, and the retired `infer` field was
replaced by the pair rather than by either one. So `user-invocable: false` says nothing about
whether the agent is model-routed: judge that from `disable-model-invocation` alone, and where
that is absent the three-part shape below still applies. `user-invocable` carries no
description-quality contract of its own and is out of this file's scope entirely. description-quality contract of its own and is out of this file's scope entirely.
- **No such flag** — the agent is model-invoked and the rest of this file applies. - **No such flag** — the agent is model-invoked and the rest of this file applies.

View File

@@ -41,8 +41,8 @@ those same sections, so any restatement is a copy that can disagree with the che
If it carries one, it still has to be kebab-case. If it carries one, it still has to be kebab-case.
- `Use proactively` is meaningful in a CC description and steers the runtime to offer the agent - `Use proactively` is meaningful in a CC description and steers the runtime to offer the agent
unprompted. In a Copilot description it does nothing; `KyberforgeCopilot.ProactivePhrase` flags unprompted. In a Copilot description it does nothing; `KyberforgeCopilot.ProactivePhrase` flags
it. The Copilot equivalent is `disable-model-invocation` / `user-invocable`, which changes the it. The Copilot equivalent is `disable-model-invocation`, which changes the description contract
description contract entirely — see `references/description-quality.md`, Step 0. entirely — see `references/description-quality.md`, Step 0.
## Pair consistency ## Pair consistency

View File

@@ -6,7 +6,7 @@ description: >
Not read-only review -> `agent-audit`. Not skills -> `skill-author`. Not read-only review -> `agent-audit`. Not skills -> `skill-author`.
allowed-tools: Bash Read Write Edit allowed-tools: Bash Read Write Edit
metadata: metadata:
version: "1.0.0" version: "1.0.1"
category: factory category: factory
source_keys: source_keys:
- context7-websites-code-claude - context7-websites-code-claude
@@ -31,7 +31,7 @@ metadata:
Signals: grill output, `agent-audit` findings, inline feedback, session context describing what went wrong. With none, ask: "No improvement signals found. Did you mean to create a new agent, or do you have feedback to apply?" Signals: grill output, `agent-audit` findings, inline feedback, session context describing what went wrong. With none, ask: "No improvement signals found. Did you mean to create a new agent, or do you have feedback to apply?"
Read only the reference for the resolved flow. Capture `git log --oneline -1` before touching the filesystem; Step 4 needs it. Read only the reference for the resolved flow. Capture `rtk git log --oneline -1` before touching the filesystem; Step 4 needs it.
## Step 2 — Scope ## Step 2 — Scope
@@ -62,4 +62,4 @@ Invoke `agent-audit` on each file written and resolve every FAIL before reportin
At plugin/APM scope bump the resolved package's `apm.yml` `version` — **minor** on create, **patch** on improve — because consumers compare it to detect updates. Project and user scope have no manifest. At plugin/APM scope bump the resolved package's `apm.yml` `version` — **minor** on create, **patch** on improve — because consumers compare it to detect updates. Project and user scope have no manifest.
**Commit verification.** Once the audit is clean, run `git add` and `git commit` — do not stop at staging. Re-run `git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is lost if the tree is cleaned up. Report done only once the hash has changed. **Commit verification.** Once the audit is clean, run `rtk git add` and `rtk git commit` — do not stop at staging. Re-run `rtk git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is lost if the tree is cleaned up. Report done only once the hash has changed.

View File

@@ -4,7 +4,7 @@ Author and refine skills conforming to the [agentskills.io](https://agentskills.
## What it does ## What it does
Routes to one of two flows based on context: if no skill directory exists at the target path, it scaffolds the directory from annotated templates, fills in `SKILL.md` and supporting files, and validates the result. If an existing skill directory and improvement signals are both present, it groups those signals by root cause and applies targeted edits, then re-validates. In both flows, bumps the skill's `metadata.version` when present (minor for create, patch for improve). Routes to one of two flows based on context: if no skill directory exists at the target path, it scaffolds the directory from annotated templates, fills in `SKILL.md` and supporting files, and validates the result. If an existing skill directory and improvement signals are both present, it groups those signals by root cause and applies targeted edits, then re-validates. In both flows, bumps the skill's `metadata.version` — minor for create, patch for improve — which every skill carries (ADR-0022).
`SKILL.md` itself carries only the dispatch table, the invocation-axis decision, the contract gates and the shared close; each flow lives in its own self-contained reference file, per ADR-0020. `SKILL.md` itself carries only the dispatch table, the invocation-axis decision, the contract gates and the shared close; each flow lives in its own self-contained reference file, per ADR-0020.

View File

@@ -6,7 +6,7 @@ description: >
Not read-only review -> `skill-audit`. Not agent files -> `agent-author`. Not read-only review -> `skill-audit`. Not agent files -> `agent-author`.
allowed-tools: Bash Read Write Edit allowed-tools: Bash Read Write Edit
metadata: metadata:
version: "1.0.0" version: "1.0.1"
category: factory category: factory
source_keys: source_keys:
- agentskills-home - agentskills-home
@@ -34,7 +34,7 @@ metadata:
Signals: grill output, `/skill-audit` findings, inline feedback, eval results, session context describing what went wrong. With none, ask whether the user meant to create a new skill or has feedback to apply. Signals: grill output, `/skill-audit` findings, inline feedback, eval results, session context describing what went wrong. With none, ask whether the user meant to create a new skill or has feedback to apply.
Read only the reference matching the resolved flow — each is self-contained. If the target sits inside a git worktree, capture `git log --oneline -1` before touching the filesystem; Step 4 needs it. Read only the reference matching the resolved flow — each is self-contained. If the target sits inside a git worktree, capture `rtk git log --oneline -1` before touching the filesystem; Step 4 needs it.
## Step 2 — Invocation axis ## Step 2 — Invocation axis
@@ -59,4 +59,4 @@ Run `/skill-audit` on the resolved skill directory; resolve every FAIL before re
Bump `metadata.version`: the **minor** version on create (new skills start at `0.1.0`) and the **patch** version on improve. Bump `metadata.version`: the **minor** version on create (new skills start at `0.1.0`) and the **patch** version on improve.
**Commit verification.** Inside a git worktree: once the audit is clean, run `git add` and `git commit` — do not stop at staging. Re-run `git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is silently lost if the tree is cleaned up. Report done only once the hash has changed. Outside a worktree (a skill under `~/.claude/skills/`, say) nothing is committable — report done on a clean audit, naming that as the reason. **Commit verification.** Inside a git worktree: once the audit is clean, run `rtk git add` and `rtk git commit` — do not stop at staging. Re-run `rtk git log --oneline -1` and confirm the hash changed from Step 1's. A non-empty `git diff --stat` is not proof: staged-but-uncommitted work is part of no commit and is silently lost if the tree is cleaned up. Report done only once the hash has changed. Outside a worktree (a skill under `~/.claude/skills/`, say) nothing is committable — report done on a clean audit, naming that as the reason.

View File

@@ -45,14 +45,18 @@ description: >
# Optional. 1–500 characters. State tool requirements, runtime versions, # Optional. 1–500 characters. State tool requirements, runtime versions,
# and network access needs. Omit for skills with no special environment requirements. # and network access needs. Omit for skills with no special environment requirements.
# metadata: metadata:
version: "0.1.0"
# author: your-name # author: your-name
# version: "1.0"
# category: general # category: general
# source_keys: # source_keys:
# - source-slug-one # - source-slug-one
# - source-slug-two # - source-slug-two
# Optional. Arbitrary key-value map. Common keys: author, version, category. # `metadata.version` is REQUIRED on every skill (ADR-0022) and is enforced by the
# `skill-frontmatter` pre-commit hook. Three-component semver. A newly created
# skill starts at "0.1.0" — leave the seeded value as it is; "1.0.0" is the seed
# for a pre-existing skill retrofitted into the rule, not for a new one.
# The rest of the map is optional: author, category, source_keys.
# source_keys: populated when built from /research output. Lists slugs from references/sources.md. # source_keys: populated when built from /research output. Lists slugs from references/sources.md.
# Also add source_keys to each references/*.md file that was informed by research. # Also add source_keys to each references/*.md file that was informed by research.

View File

@@ -84,8 +84,10 @@ already covers the new skill. Use Read/Edit directly on `apm.yml`; this is not p
## Step 3 — Fill in SKILL.md ## Step 3 — Fill in SKILL.md
Open the new skill's `SKILL.md` (the path Step 1 printed) and replace every `FILL IN:` Open the new skill's `SKILL.md` (the path Step 1 printed) and replace every `FILL IN:`
placeholder. The scaffold template already carries the compliant frontmatter and body skeleton — placeholder. The scaffold template carries the ADR-0020 body skeleton and the two frontmatter
fill it rather than restructuring it. fields that cannot be left as placeholders — `name`, substituted by the script, and
`metadata.version`, seeded live at `"0.1.0"` — so fill the template in rather than restructuring
it.
**`name`** — already set by the scaffold script. Must exactly match the directory name. Format: **`name`** — already set by the scaffold script. Must exactly match the directory name. Format:
1–64 characters, lowercase letters, numbers and hyphens only; no leading, trailing or consecutive 1–64 characters, lowercase letters, numbers and hyphens only; no leading, trailing or consecutive
@@ -96,15 +98,18 @@ against `references/contract.md`, which holds the three-part shape, the banned c
boundary-clause form and the length tiers. A hand-invoked skill (`SKILL.md` Step 2) takes one boundary-clause form and the length tiers. A hand-invoked skill (`SKILL.md` Step 2) takes one
plain sentence and `disable-model-invocation: true` instead. plain sentence and `disable-model-invocation: true` instead.
**`metadata.version`** — required on every skill (ADR-0022), not a per-skill or per-plugin choice,
and enforced by the `skill-frontmatter` pre-commit hook. The scaffold seeds a new skill at
`"0.1.0"`; leave that value alone here and let `SKILL.md` Step 4 bump it. (`"1.0.0"` is the seed
for a pre-existing skill retrofitted into the rule, and never applies to a skill created here.)
**Optional frontmatter** — uncomment and fill in, or remove entirely: **Optional frontmatter** — uncomment and fill in, or remove entirely:
- `license` — include when distributing the skill externally - `license` — include when distributing the skill externally
- `compatibility` — include if the skill requires specific tools, runtimes, or network access - `compatibility` — include if the skill requires specific tools, runtimes, or network access
(max 500 characters) (max 500 characters)
- `metadata` — key-value map. `version` is **required** on every skill (ADR-0022), seeded at - `metadata` — the rest of the map, all of it optional: `author` and `category`, plus `source_keys`
`"1.0.0"` for a retrofitted skill with no prior version and at `"0.1.0"` for a newly created now (Step 6) if research sources are in context
skill; `author` and `category` stay optional; add `source_keys` now (Step 6) if research sources
are in context
- `allowed-tools` — space-separated pre-approved tools; reduces permission prompts (experimental — - `allowed-tools` — space-separated pre-approved tools; reduces permission prompts (experimental —
support varies by client) support varies by client)
- `disable-model-invocation` — hand-invoked skills only - `disable-model-invocation` — hand-invoked skills only

View File

@@ -85,6 +85,10 @@ improvise the cuts — four dry runs invented six to ten different answers to th
If a signal points to a script or reference file, edit that file directly rather than adding a If a signal points to a script or reference file, edit that file directly rather than adding a
workaround in SKILL.md. workaround in SKILL.md.
**A skill carrying no `metadata.version` is seeded at `"1.0.0"`, not bumped** — `SKILL.md` Step 4's
patch bump presumes a version to bump, and ADR-0022 reserves `"0.1.0"` for a newly created skill.
`references/retrofit.md` carries the reasoning.
**Check for regressions before handing back.** `SKILL.md` Step 4 tells you to resolve every FAIL, **Check for regressions before handing back.** `SKILL.md` Step 4 tells you to resolve every FAIL,
which says nothing about a check that passed *before* these edits and no longer does. Compare the which says nothing about a check that passed *before* these edits and no longer does. Compare the
closing audit against the skill's pre-edit state — a PASS that has become a SUGGESTION, or a closing audit against the skill's pre-edit state — a PASS that has become a SUGGESTION, or a

View File

@@ -105,16 +105,37 @@ them for you. After every retrofit that adds, removes or renames a file:
zero. zero.
- [ ] Re-run `/skill-audit` and confirm its `### Provenance` dimension does not report the new - [ ] Re-run `/skill-audit` and confirm its `### Provenance` dimension does not report the new
file as missing `source_keys`. file as missing `source_keys`.
- [ ] **Compression must not add authority the source text didn't have.** The bullet above is
about a `sources.md` entry going *stale* — Contributing files left uncited after content ## Compression must not add authority the source text didn't have
moves. This is a distinct failure: a compression or rewrite pass that upgrades an honest
hedge in a Description into an unsupported confident claim, without the underlying source This one is **not** part of the checklist above, and deliberately so: it fires on a wording change
having changed at all — "no forge-specific content drawn directly from it beyond that" with no file change at all, so a retrofit that adds and removes nothing still owes it.
quietly becoming "Grounds Step 2's dispatch table." Nothing in `/skill-audit`'s structural
checks catches this; a bash script can verify an entry is internally consistent, never The `sources.md` bullet above is about an entry going *stale* — Contributing files left uncited
whether the claim is *true*. If a retrofit strengthens or otherwise changes the wording of a after content moves. This is a distinct failure: a compression or rewrite pass that upgrades an
provenance claim, re-read the upstream research doc first and confirm the stronger wording honest hedge in a Description into an unsupported confident claim, without the underlying source
is actually still true before committing it. having changed at all — "no forge-specific content drawn directly from it beyond that" quietly
becoming "Grounds Step 2's dispatch table."
`/skill-audit`'s provenance script does now notice this class: it diffs each slug's `Description`
and `Contributing files` text against a base ref and raises an **INFO** when the wording changed.
That is a prompt, not a verdict — it reports only *that* the claim moved, never whether the new
claim is true, because a bash script can verify an entry is internally consistent and nothing more.
Answering it is this flow's job: if a retrofit strengthens or otherwise changes the wording of a
provenance claim, re-read the upstream research doc first and confirm the stronger wording is
actually still true before committing it.
## Versioning a retrofitted skill
`SKILL.md` Step 4 says to bump the **patch** version on improve, which presumes there is a version
to bump. A pre-ADR-0020 skill often carries none — `metadata.version` only became mandatory under
ADR-0022, and this flow is exactly where those skills surface.
A skill with no `metadata.version` is **seeded at `"1.0.0"`, not bumped**. `"0.1.0"` is reserved
for a skill created new by the create flow: it means "created and never yet revised", which
understates a skill that has been through retrofit and audit passes without tracking a version.
Add the field in this retrofit — the `skill-frontmatter` pre-commit hook blocks the commit without
it.
## Worked example — a description retrofit ## Worked example — a description retrofit

View File

@@ -156,6 +156,18 @@ EOF
assert_success assert_success
} }
@test "scaffold emits a live metadata.version seeded at 0.1.0 (ADR-0022)" {
# The scaffold must clear .pre-commit-config.yaml's `skill-frontmatter` hook
# on its first commit: a commented-out metadata block ships a skill with no
# version and is blocked. Assert the field is live, not a comment.
bash "$SCRIPT" my-tool "$DEST"
run grep -E '^metadata:$' "$DEST/my-tool/SKILL.md"
assert_success
run grep -E '^ version: "[0-9]+\.[0-9]+\.[0-9]+"$' "$DEST/my-tool/SKILL.md"
assert_success
assert_output --partial '0.1.0'
}
@test "walk-up skips a type-less apm.yml (marketplace-only) and finds a real package root further up" { @test "walk-up skips a type-less apm.yml (marketplace-only) and finds a real package root further up" {
mkdir -p "$DEST/mid/sub" mkdir -p "$DEST/mid/sub"
cat > "$DEST/apm.yml" <<'EOF' cat > "$DEST/apm.yml" <<'EOF'