From 60be7b323295572a80499758aff9e922124ef95f Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Mon, 7 Sep 2026 20:36:24 +0000 Subject: [PATCH] refactor(skills): mandate metadata.version on every skill's frontmatter Only 12 of 39 skills carried metadata.version, and adoption tracked which plugin a skill lived in rather than any stated rule: core, gitea and lint were consistent adopters, bin and kyberforge were consistent non-adopters, git was split with one outlier. There was no documented convention, and skill-author's own bump logic was already written as if presence were conditional. metadata.version is now required on every skill. The 19 skills here that never carried one (bin, kyberforge, gitea-files) are seeded at 1.0.0, not 0.1.0 -- that value stays reserved for a skill's actual creation point under skill-author's existing convention. The skill-frontmatter pre-commit hook now fails a SKILL.md missing the field, the same class of failure as a missing name/description. Full rationale in the new ADR. The git-plugin skills that also need this field follow in the next commit, bundled with issue #113's rtk normalization since both touch the same files. Refs: #127 ADR: 0022 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP --- .pre-commit-config.yaml | 14 +++- ...022-skill-metadata-version-is-mandatory.md | 70 +++++++++++++++++++ plugins/bin/.apm/skills/caveman/SKILL.md | 2 + plugins/bin/.apm/skills/diagnose/SKILL.md | 2 + plugins/bin/.apm/skills/grill-me/SKILL.md | 2 + .../bin/.apm/skills/grill-with-docs/SKILL.md | 2 + .../improve-codebase-architecture/SKILL.md | 2 + plugins/bin/.apm/skills/prototype/SKILL.md | 2 + plugins/bin/.apm/skills/research/SKILL.md | 1 + plugins/bin/.apm/skills/tdd/SKILL.md | 2 + plugins/bin/.apm/skills/triage/SKILL.md | 2 + plugins/bin/.apm/skills/write-docs/SKILL.md | 2 +- plugins/bin/.apm/skills/zoom-out/SKILL.md | 2 + .../gitea/.apm/skills/gitea-files/SKILL.md | 1 + .../.apm/skills/agent-audit/SKILL.md | 1 + .../.apm/skills/agent-author/SKILL.md | 1 + .../.apm/skills/apm-install/SKILL.md | 1 + .../.apm/skills/apm-workflow/SKILL.md | 1 + plugins/kyberforge/.apm/skills/forge/SKILL.md | 1 + .../.apm/skills/skill-audit/SKILL.md | 1 + .../.apm/skills/skill-author/SKILL.md | 3 +- .../skills/skill-author/references/create.md | 6 +- 22 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 docs/adr/0022-skill-metadata-version-is-mandatory.md diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce44c29..79c9540 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -259,8 +259,18 @@ repos: - | for f in "$@"; do if [[ -f "$f" ]]; then - if ! grep -q "^name:" "$f" || ! grep -q "^description:" "$f"; then - echo "ERROR: $f is missing required frontmatter fields (name: and description:)" + missing="" + if ! grep -q "^name:" "$f"; then + missing="${missing}name: " + fi + if ! grep -q "^description:" "$f"; then + missing="${missing}description: " + fi + if ! grep -A10 "^metadata:" "$f" | grep -q " version:"; then + missing="${missing}metadata.version " + fi + if [[ -n "$missing" ]]; then + echo "ERROR: $f is missing required frontmatter fields (${missing})" exit 1 fi fi diff --git a/docs/adr/0022-skill-metadata-version-is-mandatory.md b/docs/adr/0022-skill-metadata-version-is-mandatory.md new file mode 100644 index 0000000..637712e --- /dev/null +++ b/docs/adr/0022-skill-metadata-version-is-mandatory.md @@ -0,0 +1,70 @@ +# Every skill's `metadata.version` is mandatory, not a per-plugin option + +**Status: accepted (2026-09-07).** + +## Context + +`metadata.version` is optional SKILL.md frontmatter (`create.md`'s "Optional frontmatter" list: +"uncomment and fill in, or remove entirely"). `skill-author`'s own bump logic was written +conditionally — "with `metadata.version` present, bump the minor version on create... and the +patch version on improve" — which only makes sense if presence is a real per-skill choice. + +Adoption never followed a rule; it followed the plugin. Of 39 skills, 12 carry a version: + +| Plugin | Has it | Total | +|---|---|---| +| `core` | 3 | 3 | +| `gitea` | 6 | 7 | +| `lint` | 2 | 2 | +| `git` | 1 | 9 | +| `bin` | 0 | 11 | +| `kyberforge` | 0 | 7 | + +`core`, `gitea` and `lint` are consistent adopters (`gitea-files` the one gap); `bin` and +`kyberforge` are consistent non-adopters; `git` has one outlier (`git-commits`, versioned for no +plugin-specific reason found on inspection — no comment, no cross-reference, nothing distinguishing +it from its eight siblings). Issue #127 raised this as an undocumented split: two house norms +coexisting with no stated rule for which applies where, the same class of defect as an unstated +`rtk`/bare-`git` convention (#113) found in the same audit pass. + +## Decision + +**Every skill's frontmatter carries `metadata.version`.** It is no longer optional, and no longer a +per-plugin choice. + +- **The 27 skills that never carried one are seeded at `1.0.0`**, not `0.1.0`. `0.1.0` is + `skill-author`'s existing new-skill starting point, chosen for a skill with no revision history to + its name yet. These 27 have all been through the ADR-0020 retrofit and repeated audit passes + without ever tracking a version; crediting them with `0.1.0` would understate that, and there is + no real history to justify seeding higher than a first stable release. `1.0.0` marks "versioned as + of this retrofit," `0.1.0` keeps meaning "created and never yet revised." +- **New skills still start at `0.1.0`.** `skill-author`'s create/improve bump convention is + unchanged; only the presence of the field stops being conditional. +- **The one outlier in the other direction, `git-commits`, keeps its existing value** (`0.1.3`) — + it already had real tracked history under the old conditional rule, and this decision does not + reset skills that were already compliant. +- **`skill-frontmatter`'s pre-commit hook gains the check.** It already fails a SKILL.md missing + `name:` or `description:`; a missing `metadata.version` is now the same class of failure, not a + style nit an audit might or might not catch. + +## Considered options + +**Leave it per-plugin, document the split.** This was the initial framing of #127 and is coherent — +`core`/`gitea`/`lint` keep it, `bin`/`kyberforge` don't, two outliers get normalized to match their +plugin. Rejected on reconsideration: a rule that says "some plugins track this and some don't" is +strictly harder to state, audit and onboard against than "every skill does," for a field whose entire +job is answering "did this change since I last read it" — a question with the same shape everywhere +it's asked, not one that varies by plugin domain. + +**Drop the field corpus-wide.** Rejected: `skill-author` already depends on it to decide whether a +create/improve pass owes a bump, so the 12 skills carrying it are not tracking dead weight — removing +it discards real revision signal for no gain. + +## Consequences + +27 SKILL.md files gain `metadata.version: "1.0.0"`. `skill-author`'s `create.md` moves the field from +"Optional frontmatter" to the required list, citing this ADR. `skill-author`'s own SKILL.md drops the +"with `metadata.version` present" conditional in its bump-rule line, since presence is no longer in +question. `.pre-commit-config.yaml`'s `skill-frontmatter` hook is extended to require the field, +closing the gap #113 and #118 both named in the same audit pass: a stated rule with nothing enforcing +it drifts the same way an unstated one does. diff --git a/plugins/bin/.apm/skills/caveman/SKILL.md b/plugins/bin/.apm/skills/caveman/SKILL.md index dea5b4a..542810f 100644 --- a/plugins/bin/.apm/skills/caveman/SKILL.md +++ b/plugins/bin/.apm/skills/caveman/SKILL.md @@ -4,6 +4,8 @@ disable-model-invocation: true description: > Ultra-compressed output mode that drops articles, filler and pleasantries while keeping technical substance exact, cutting token usage by roughly 75%. +metadata: + version: "1.0.0" --- Respond terse like smart caveman. All technical substance stay. Only fluff die. diff --git a/plugins/bin/.apm/skills/diagnose/SKILL.md b/plugins/bin/.apm/skills/diagnose/SKILL.md index 1e60479..ee85d02 100644 --- a/plugins/bin/.apm/skills/diagnose/SKILL.md +++ b/plugins/bin/.apm/skills/diagnose/SKILL.md @@ -4,6 +4,8 @@ description: > Use when the user says "diagnose this" or "debug this", reports something broken, throwing, or failing, or says something got slow. Not filing or triaging a reported bug -> `triage`. Not test-first feature work -> `tdd`. +metadata: + version: "1.0.0" --- # Diagnose diff --git a/plugins/bin/.apm/skills/grill-me/SKILL.md b/plugins/bin/.apm/skills/grill-me/SKILL.md index 1cc8ede..70bb682 100644 --- a/plugins/bin/.apm/skills/grill-me/SKILL.md +++ b/plugins/bin/.apm/skills/grill-me/SKILL.md @@ -5,6 +5,8 @@ description: > relentless interview — one question at a time, down each branch of the decision tree. Not a plan to challenge against `CONTEXT.md` and ADRs -> `grill-with-docs`. +metadata: + version: "1.0.0" --- Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. diff --git a/plugins/bin/.apm/skills/grill-with-docs/SKILL.md b/plugins/bin/.apm/skills/grill-with-docs/SKILL.md index 8610263..cc93aef 100644 --- a/plugins/bin/.apm/skills/grill-with-docs/SKILL.md +++ b/plugins/bin/.apm/skills/grill-with-docs/SKILL.md @@ -4,6 +4,8 @@ description: > Use when a plan should be stress-tested against the project's domain model — the interview challenges terms against `CONTEXT.md` and writes decisions into it and into ADRs as they land. Not a plain interview -> `grill-me`. +metadata: + version: "1.0.0" --- diff --git a/plugins/bin/.apm/skills/improve-codebase-architecture/SKILL.md b/plugins/bin/.apm/skills/improve-codebase-architecture/SKILL.md index 750876a..48803ca 100644 --- a/plugins/bin/.apm/skills/improve-codebase-architecture/SKILL.md +++ b/plugins/bin/.apm/skills/improve-codebase-architecture/SKILL.md @@ -6,6 +6,8 @@ description: > testable and AI-navigable — deepening opportunities that turn shallow modules into deep ones, informed by `CONTEXT.md` and `docs/adr/`. Not debugging a failure -> `diagnose`. +metadata: + version: "1.0.0" --- # Improve Codebase Architecture diff --git a/plugins/bin/.apm/skills/prototype/SKILL.md b/plugins/bin/.apm/skills/prototype/SKILL.md index 0c9d8e3..b544772 100644 --- a/plugins/bin/.apm/skills/prototype/SKILL.md +++ b/plugins/bin/.apm/skills/prototype/SKILL.md @@ -5,6 +5,8 @@ description: > a data model, state machine or business logic, or to mock up a UI in several variations. Not production code -> `tdd`. Not talking a design through -> `grill-me`. +metadata: + version: "1.0.0" --- # Prototype diff --git a/plugins/bin/.apm/skills/research/SKILL.md b/plugins/bin/.apm/skills/research/SKILL.md index 19fffee..1d114ab 100644 --- a/plugins/bin/.apm/skills/research/SKILL.md +++ b/plugins/bin/.apm/skills/research/SKILL.md @@ -6,6 +6,7 @@ description: >- documentation written from existing code or specs -> `write-docs`. Not a bug or incident -> `diagnose`. metadata: + version: "1.0.0" category: research allowed-tools: - Grep diff --git a/plugins/bin/.apm/skills/tdd/SKILL.md b/plugins/bin/.apm/skills/tdd/SKILL.md index ad3be57..736773a 100644 --- a/plugins/bin/.apm/skills/tdd/SKILL.md +++ b/plugins/bin/.apm/skills/tdd/SKILL.md @@ -4,6 +4,8 @@ description: > Use when the user wants a feature built or a bug fixed test-first, in a strict red-green-refactor loop, one behaviour at a time. Not diagnosing an existing bug -> `diagnose`. Not throwaway exploratory code -> `prototype`. +metadata: + version: "1.0.0" --- # Test-Driven Development diff --git a/plugins/bin/.apm/skills/triage/SKILL.md b/plugins/bin/.apm/skills/triage/SKILL.md index d83ab5e..548026e 100644 --- a/plugins/bin/.apm/skills/triage/SKILL.md +++ b/plugins/bin/.apm/skills/triage/SKILL.md @@ -4,6 +4,8 @@ description: > Use when the user wants an issue created, triaged, or moved through the tracker's triage states, or an issue prepared for an AFK agent. Not debugging the bug itself -> `diagnose`. Not fleshing out a design -> `grill-with-docs`. +metadata: + version: "1.0.0" --- # Triage diff --git a/plugins/bin/.apm/skills/write-docs/SKILL.md b/plugins/bin/.apm/skills/write-docs/SKILL.md index 30ea51d..06a9a54 100644 --- a/plugins/bin/.apm/skills/write-docs/SKILL.md +++ b/plugins/bin/.apm/skills/write-docs/SKILL.md @@ -6,10 +6,10 @@ description: > module", "create docs for this feature", "write a README for this". Not an ADR or other decision record -> `grill-with-docs`. Not an external tool researched from its docs -> `research`. -version: "1.0" updated: 2026-05-17 when: invoked by explicit trigger ("write docs for X", "document this module", "create docs for this feature") or implicit request to produce technical documentation from code or spec metadata: + version: "1.0" category: implement source: - repo: anthropics/skills diff --git a/plugins/bin/.apm/skills/zoom-out/SKILL.md b/plugins/bin/.apm/skills/zoom-out/SKILL.md index 1e7a5dc..4ba619a 100644 --- a/plugins/bin/.apm/skills/zoom-out/SKILL.md +++ b/plugins/bin/.apm/skills/zoom-out/SKILL.md @@ -2,6 +2,8 @@ name: zoom-out description: Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture. disable-model-invocation: true +metadata: + version: "1.0.0" --- I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary. diff --git a/plugins/gitea/.apm/skills/gitea-files/SKILL.md b/plugins/gitea/.apm/skills/gitea-files/SKILL.md index 168e875..26265da 100644 --- a/plugins/gitea/.apm/skills/gitea-files/SKILL.md +++ b/plugins/gitea/.apm/skills/gitea-files/SKILL.md @@ -11,6 +11,7 @@ compatibility: Requires the Gitea MCP server configured with a token scoped to a is not actually required for any of this domain's five tools. metadata: + version: "1.0.0" category: gitea source_keys: - gitea-mcp-repo diff --git a/plugins/kyberforge/.apm/skills/agent-audit/SKILL.md b/plugins/kyberforge/.apm/skills/agent-audit/SKILL.md index 19abac3..cc923e0 100644 --- a/plugins/kyberforge/.apm/skills/agent-audit/SKILL.md +++ b/plugins/kyberforge/.apm/skills/agent-audit/SKILL.md @@ -7,6 +7,7 @@ description: > directory -> skill-audit. allowed-tools: Bash Read metadata: + version: "1.0.0" category: factory source_keys: - context7-websites-code-claude diff --git a/plugins/kyberforge/.apm/skills/agent-author/SKILL.md b/plugins/kyberforge/.apm/skills/agent-author/SKILL.md index c6ca310..b81b5ae 100644 --- a/plugins/kyberforge/.apm/skills/agent-author/SKILL.md +++ b/plugins/kyberforge/.apm/skills/agent-author/SKILL.md @@ -6,6 +6,7 @@ description: > Not read-only review -> `agent-audit`. Not skills -> `skill-author`. allowed-tools: Bash Read Write Edit metadata: + version: "1.0.0" category: factory source_keys: - context7-websites-code-claude diff --git a/plugins/kyberforge/.apm/skills/apm-install/SKILL.md b/plugins/kyberforge/.apm/skills/apm-install/SKILL.md index 054d161..d576504 100644 --- a/plugins/kyberforge/.apm/skills/apm-install/SKILL.md +++ b/plugins/kyberforge/.apm/skills/apm-install/SKILL.md @@ -6,6 +6,7 @@ description: > authoring, publishing, auditing, or dependency installation for an apm package -> `apm-workflow`. metadata: + version: "1.0.0" category: apm source_keys: - context7-microsoft-apm diff --git a/plugins/kyberforge/.apm/skills/apm-workflow/SKILL.md b/plugins/kyberforge/.apm/skills/apm-workflow/SKILL.md index cd258b4..85e2f30 100644 --- a/plugins/kyberforge/.apm/skills/apm-workflow/SKILL.md +++ b/plugins/kyberforge/.apm/skills/apm-workflow/SKILL.md @@ -5,6 +5,7 @@ description: > the dependencies it declares, or an apm marketplace — even when the user does not say "apm". Not the apm binary or an agent runtime -> `apm-install`. metadata: + version: "1.0.0" category: apm source_keys: - context7-microsoft-apm diff --git a/plugins/kyberforge/.apm/skills/forge/SKILL.md b/plugins/kyberforge/.apm/skills/forge/SKILL.md index 860e9db..f63242a 100644 --- a/plugins/kyberforge/.apm/skills/forge/SKILL.md +++ b/plugins/kyberforge/.apm/skills/forge/SKILL.md @@ -8,6 +8,7 @@ description: > already named — invoke `skill-author`, `agent-author` or `apm-workflow` directly. metadata: + version: "1.0.0" category: factory source_keys: - claude-code-subagents-docs diff --git a/plugins/kyberforge/.apm/skills/skill-audit/SKILL.md b/plugins/kyberforge/.apm/skills/skill-audit/SKILL.md index 1a66612..9e45c2d 100644 --- a/plugins/kyberforge/.apm/skills/skill-audit/SKILL.md +++ b/plugins/kyberforge/.apm/skills/skill-audit/SKILL.md @@ -7,6 +7,7 @@ description: > skill-author. allowed-tools: Bash Read metadata: + version: "1.0.0" category: factory source_keys: - agentskills-home diff --git a/plugins/kyberforge/.apm/skills/skill-author/SKILL.md b/plugins/kyberforge/.apm/skills/skill-author/SKILL.md index 33228c5..6d35dfc 100644 --- a/plugins/kyberforge/.apm/skills/skill-author/SKILL.md +++ b/plugins/kyberforge/.apm/skills/skill-author/SKILL.md @@ -6,6 +6,7 @@ description: > Not read-only review -> `skill-audit`. Not agent files -> `agent-author`. allowed-tools: Bash Read Write Edit metadata: + version: "1.0.0" category: factory source_keys: - agentskills-home @@ -56,6 +57,6 @@ Gates `/skill-audit` enforces in both flows: Run `/skill-audit` on the resolved skill directory; resolve every FAIL before reporting done. It checks name-to-directory match, placeholders, both size budgets, boundary-target resolution and script hygiene — do not hand-check those. Hand-check the one thing it misses: an empty body reports `PASS SKILL.md body word count 0 (ADR-0020 target: 600)`, so confirm at least one non-empty section exists. -With `metadata.version` present, bump 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. diff --git a/plugins/kyberforge/.apm/skills/skill-author/references/create.md b/plugins/kyberforge/.apm/skills/skill-author/references/create.md index 677425b..9e754cb 100644 --- a/plugins/kyberforge/.apm/skills/skill-author/references/create.md +++ b/plugins/kyberforge/.apm/skills/skill-author/references/create.md @@ -101,8 +101,10 @@ plain sentence and `disable-model-invocation: true` instead. - `license` — include when distributing the skill externally - `compatibility` — include if the skill requires specific tools, runtimes, or network access (max 500 characters) -- `metadata` — key-value map; use `author`, `version`, `category`; add `source_keys` now (Step 6) - if research sources are in context +- `metadata` — key-value map. `version` is **required** on every skill (ADR-0022), seeded at + `"1.0.0"` for a retrofitted skill with no prior version and at `"0.1.0"` for a newly created + 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 — support varies by client) - `disable-model-invocation` — hand-invoked skills only