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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeH8SCbcrCAQrtymkNuhKP
This commit is contained in:
2026-09-07 20:36:24 +00:00
parent 598a7c326a
commit 60be7b3232
22 changed files with 115 additions and 6 deletions

View File

@@ -259,8 +259,18 @@ repos:
- | - |
for f in "$@"; do for f in "$@"; do
if [[ -f "$f" ]]; then if [[ -f "$f" ]]; then
if ! grep -q "^name:" "$f" || ! grep -q "^description:" "$f"; then missing=""
echo "ERROR: $f is missing required frontmatter fields (name: and description:)" 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 exit 1
fi fi
fi fi

View File

@@ -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.

View File

@@ -4,6 +4,8 @@ disable-model-invocation: true
description: > description: >
Ultra-compressed output mode that drops articles, filler and pleasantries while Ultra-compressed output mode that drops articles, filler and pleasantries while
keeping technical substance exact, cutting token usage by roughly 75%. 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. Respond terse like smart caveman. All technical substance stay. Only fluff die.

View File

@@ -4,6 +4,8 @@ description: >
Use when the user says "diagnose this" or "debug this", reports something Use when the user says "diagnose this" or "debug this", reports something
broken, throwing, or failing, or says something got slow. Not filing or broken, throwing, or failing, or says something got slow. Not filing or
triaging a reported bug -> `triage`. Not test-first feature work -> `tdd`. triaging a reported bug -> `triage`. Not test-first feature work -> `tdd`.
metadata:
version: "1.0.0"
--- ---
# Diagnose # Diagnose

View File

@@ -5,6 +5,8 @@ description: >
relentless interview — one question at a time, down each branch of the relentless interview — one question at a time, down each branch of the
decision tree. Not a plan to challenge against `CONTEXT.md` and ADRs -> decision tree. Not a plan to challenge against `CONTEXT.md` and ADRs ->
`grill-with-docs`. `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. 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.

View File

@@ -4,6 +4,8 @@ description: >
Use when a plan should be stress-tested against the project's domain model — 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 the interview challenges terms against `CONTEXT.md` and writes decisions into
it and into ADRs as they land. Not a plain interview -> `grill-me`. it and into ADRs as they land. Not a plain interview -> `grill-me`.
metadata:
version: "1.0.0"
--- ---
<what-to-do> <what-to-do>

View File

@@ -6,6 +6,8 @@ description: >
testable and AI-navigable — deepening opportunities that turn shallow modules testable and AI-navigable — deepening opportunities that turn shallow modules
into deep ones, informed by `CONTEXT.md` and `docs/adr/`. Not debugging a into deep ones, informed by `CONTEXT.md` and `docs/adr/`. Not debugging a
failure -> `diagnose`. failure -> `diagnose`.
metadata:
version: "1.0.0"
--- ---
# Improve Codebase Architecture # Improve Codebase Architecture

View File

@@ -5,6 +5,8 @@ description: >
a data model, state machine or business logic, or to mock up a UI in several 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 -> variations. Not production code -> `tdd`. Not talking a design through ->
`grill-me`. `grill-me`.
metadata:
version: "1.0.0"
--- ---
# Prototype # Prototype

View File

@@ -6,6 +6,7 @@ description: >-
documentation written from existing code or specs -> `write-docs`. Not a bug documentation written from existing code or specs -> `write-docs`. Not a bug
or incident -> `diagnose`. or incident -> `diagnose`.
metadata: metadata:
version: "1.0.0"
category: research category: research
allowed-tools: allowed-tools:
- Grep - Grep

View File

@@ -4,6 +4,8 @@ description: >
Use when the user wants a feature built or a bug fixed test-first, in a strict 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 red-green-refactor loop, one behaviour at a time. Not diagnosing an existing
bug -> `diagnose`. Not throwaway exploratory code -> `prototype`. bug -> `diagnose`. Not throwaway exploratory code -> `prototype`.
metadata:
version: "1.0.0"
--- ---
# Test-Driven Development # Test-Driven Development

View File

@@ -4,6 +4,8 @@ description: >
Use when the user wants an issue created, triaged, or moved through the 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 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`. the bug itself -> `diagnose`. Not fleshing out a design -> `grill-with-docs`.
metadata:
version: "1.0.0"
--- ---
# Triage # Triage

View File

@@ -6,10 +6,10 @@ description: >
module", "create docs for this feature", "write a README for this". Not an ADR 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 or other decision record -> `grill-with-docs`. Not an external tool researched
from its docs -> `research`. from its docs -> `research`.
version: "1.0"
updated: 2026-05-17 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 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: metadata:
version: "1.0"
category: implement category: implement
source: source:
- repo: anthropics/skills - repo: anthropics/skills

View File

@@ -2,6 +2,8 @@
name: zoom-out 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. 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 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. 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.

View File

@@ -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. is not actually required for any of this domain's five tools.
metadata: metadata:
version: "1.0.0"
category: gitea category: gitea
source_keys: source_keys:
- gitea-mcp-repo - gitea-mcp-repo

View File

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

View File

@@ -6,6 +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"
category: factory category: factory
source_keys: source_keys:
- context7-websites-code-claude - context7-websites-code-claude

View File

@@ -6,6 +6,7 @@ description: >
authoring, publishing, auditing, or dependency installation for an apm authoring, publishing, auditing, or dependency installation for an apm
package -> `apm-workflow`. package -> `apm-workflow`.
metadata: metadata:
version: "1.0.0"
category: apm category: apm
source_keys: source_keys:
- context7-microsoft-apm - context7-microsoft-apm

View File

@@ -5,6 +5,7 @@ description: >
the dependencies it declares, or an apm marketplace — even when the user does 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`. not say "apm". Not the apm binary or an agent runtime -> `apm-install`.
metadata: metadata:
version: "1.0.0"
category: apm category: apm
source_keys: source_keys:
- context7-microsoft-apm - context7-microsoft-apm

View File

@@ -8,6 +8,7 @@ description: >
already named — invoke `skill-author`, `agent-author` or `apm-workflow` already named — invoke `skill-author`, `agent-author` or `apm-workflow`
directly. directly.
metadata: metadata:
version: "1.0.0"
category: factory category: factory
source_keys: source_keys:
- claude-code-subagents-docs - claude-code-subagents-docs

View File

@@ -7,6 +7,7 @@ description: >
skill-author. skill-author.
allowed-tools: Bash Read allowed-tools: Bash Read
metadata: metadata:
version: "1.0.0"
category: factory category: factory
source_keys: source_keys:
- agentskills-home - agentskills-home

View File

@@ -6,6 +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"
category: factory category: factory
source_keys: source_keys:
- agentskills-home - 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. 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. **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.

View File

@@ -101,8 +101,10 @@ plain sentence and `disable-model-invocation: true` instead.
- `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; use `author`, `version`, `category`; add `source_keys` now (Step 6) - `metadata` — key-value map. `version` is **required** on every skill (ADR-0022), seeded at
if research sources are in context `"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 — - `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