Browse Source

docs(skills): Document Claude Code top-level frontmatter superset (fixes PR #12 root cause)

SKILL-SUBAGENT-REFERENCE.md was self-contradictory: it said 'no other
top-level keys are permitted' and its validation awk flagged when_to_use/
argument-hint/effort as violations, while a later section listed more
top-level keys and the repo uses them deliberately. An external PR (#12)
read the misleading line and moved those keys under metadata — which
DISABLES them in Claude Code (metadata is an ignored passthrough).

Rewrote the frontmatter section to document two layers: the portable
Agent Skills six-field minimum AND Claude Code's documented top-level
superset (when_to_use, argument-hint, effort, model, context,
disable-model-invocation, user-invocable, arguments, agent, hooks, paths,
shell, disallowed-tools) — each with what Claude Code does with it, the
fact that metadata-nesting drops the behaviour, and a cite to
code.claude.com/docs/en/skills. Precedence stated: Claude Code is the
target, superset fields stay top-level. Validation snippet allowlists the
superset and defers to the official validator.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0xDarkMatter 2 weeks ago
parent
commit
5a999b83aa
2 changed files with 88 additions and 22 deletions
  1. 11 0
      CHANGELOG.md
  2. 77 22
      docs/SKILL-SUBAGENT-REFERENCE.md

+ 11 - 0
CHANGELOG.md

@@ -14,6 +14,17 @@ feature releases live in the README "Recent Updates" section.
   SKILL-SUBAGENT-REFERENCE, naming-conventions, SKILL-RESOURCE-PROTOCOL) and carries a
   precedence table for when they disagree. `skill-agent-updates.md` now routes here first.
 
+### Fixed (docs)
+- **`SKILL-SUBAGENT-REFERENCE.md` was self-contradictory and misleading** (surfaced by
+  external PR #12): it declared "no other top-level keys are permitted" and its
+  validation awk flagged `when_to_use`/`argument-hint`/`effort` as violations — yet those
+  are documented *Claude Code* top-level fields the repo uses deliberately. Rewrote it to
+  document **two layers** (the portable Agent Skills six-field minimum vs Claude Code's
+  top-level superset), with a referenced field table, the precedence rule (Claude Code is
+  our target → superset fields stay top-level), and an explicit warning that burying them
+  under `metadata` *disables* them. Validation snippet now allowlists the superset and
+  defers to `claude plugin validate`.
+
 ### Changed (docs review)
 - Refreshed `WORKFLOWS.md` with a v3.0 orientation banner (skills-first; subagents are
   isolation/worker-only); fixed `naming-conventions.md` frontmatter example (metadata

+ 77 - 22
docs/SKILL-SUBAGENT-REFERENCE.md

@@ -2,13 +2,28 @@
 
 Quick reference for Claude Code skill and subagent APIs. **Always check official docs first** - this may be outdated.
 
-## Skill Frontmatter - Agent Skills Spec
+## Skill Frontmatter - two layers
 
-All skills MUST comply with the [Agent Skills specification](https://agentskills.io/specification). This is an open standard backed by Anthropic, Vercel, Google, Microsoft, and 40+ agent platforms.
+A SKILL.md frontmatter is governed by **two specs at once**, and they are not the same set:
 
-### Allowed Top-Level Fields
+1. **The [Agent Skills spec](https://agentskills.io/specification)** — the portable open
+   standard (Anthropic, Vercel, Google, Microsoft, 40+ platforms). Its top-level allowlist
+   is exactly six keys: `name`, `description`, `license`, `compatibility`, `allowed-tools`,
+   `metadata`. Everything else it expects under `metadata`.
+2. **Claude Code's skill loader** — a documented **superset** that reads *additional*
+   top-level keys (`when_to_use`, `argument-hint`, `effort`, `model`, `context`, …) and
+   acts on them. See [§ Claude Code top-level superset](#claude-code-top-level-superset)
+   and the official table at https://code.claude.com/docs/en/skills.
 
-Only these fields are permitted at the top level of SKILL.md frontmatter:
+**Precedence for claude-mods: Claude Code is our target** (this repo ships as a Claude
+Code plugin). So the Claude Code superset fields are **valid and belong at the top level** —
+that is where Claude Code reads them. **Do NOT move a Claude Code behavioural field under
+`metadata` to satisfy the portable minimum: `metadata` is an arbitrary passthrough Claude
+Code ignores for these semantics, so burying `argument-hint`/`effort`/`when_to_use` there
+silently *disables* them** (no autocomplete hint, no effort override, no trigger surface).
+`metadata` is only for genuinely non-Claude-Code custom fields (author, related-skills, …).
+
+### Agent Skills spec — the six portable top-level fields
 
 ```yaml
 ---
@@ -24,9 +39,15 @@ metadata:                           # Optional: arbitrary key-value map
 ---
 ```
 
-**Everything else goes in `metadata:`**. No other top-level keys are permitted.
+These six are the **only** keys the portable Agent Skills spec recognises at the top
+level. **Claude Code adds more** (next section) — those are also legal top-level keys for
+us. What does NOT belong at the top level is *custom, non-spec, non-Claude-Code* metadata
+(our `author`, `related-skills`, etc.) — that goes under `metadata`.
+
+### Custom (non-spec, non-Claude-Code) fields → `metadata`
 
-### Non-Standard Fields - Where They Go
+These are claude-mods bookkeeping fields neither spec defines. They live under `metadata`
+as comma-separated strings (never arrays, never top-level):
 
 | Field | Location | Format |
 |-------|----------|--------|
@@ -38,6 +59,9 @@ metadata:                           # Optional: arbitrary key-value map
 | `cli-help` | `metadata.cli-help` | String |
 | `author` | `metadata.author` | String |
 
+> **Not in this table?** If a key is a documented *Claude Code* field (below), it stays
+> **top-level** — do not relocate it here.
+
 ### Rules for claude-mods Skills
 
 1. **`license: MIT`** on every skill (exception: skill-creator has custom license)
@@ -49,13 +73,17 @@ metadata:                           # Optional: arbitrary key-value map
 ### Validation
 
 ```bash
-# Quick check: no non-standard top-level keys
+# Quick check: flag any top-level key that is NEITHER a portable Agent Skills field
+# NOR a documented Claude Code top-level field. The allowlist below MUST include the
+# Claude Code superset — otherwise it false-flags when_to_use/argument-hint/effort/…
+# (that mistake is what PR #12 acted on).
 for f in skills/*/SKILL.md; do
-  awk '/^---$/{n++} n==1 && !/^(name|description|license|compatibility|allowed-tools|metadata|  |---):/' "$f"
+  awk '/^---$/{n++}
+       n==1 && !/^(name|description|license|compatibility|allowed-tools|metadata|when_to_use|argument-hint|arguments|disable-model-invocation|user-invocable|model|effort|context|agent|hooks|paths|shell|disallowed-tools|  |---):/' "$f"
 done
 
-# Full spec validation (if skills-ref CLI available)
-npx skills-ref validate ./skills/<name>
+# Authoritative validation: gate on the official validator, never a hand-rolled allowlist.
+claude plugin validate .
 ```
 
 ### Reference
@@ -64,24 +92,51 @@ npx skills-ref validate ./skills/<name>
 - CLI: https://github.com/vercel-labs/skills
 - Directory: https://skills.sh
 
-## Claude Code Skill Fields (Beyond Spec)
-
-These fields are specific to Claude Code's skill loader and are NOT part of the Agent Skills spec. Use only when needed:
+## Claude Code top-level superset
+
+These are **documented Claude Code SKILL.md frontmatter fields** that the loader reads at
+the **top level** and acts on. They are NOT in the portable Agent Skills spec, but since
+this repo targets Claude Code they are legitimate top-level keys here. **Each is inert if
+moved under `metadata`** — Claude Code only reads them at the top level. Authority:
+https://code.claude.com/docs/en/skills (frontmatter table).
+
+| Field | What Claude Code does with it | Moved to `metadata`? |
+|-------|-------------------------------|----------------------|
+| `when_to_use` | Appended to `description` in the skill listing as extra trigger context; counts toward the combined 1,536-char cap | Dropped — no longer supplements triggering |
+| `argument-hint` | Shown in `/` autocomplete to indicate expected args (e.g. `[issue-number]`) | Dropped — no hint shown |
+| `effort` | Overrides session effort while the skill is active (`low\|medium\|high\|xhigh\|max`) | Dropped — no override |
+| `arguments` | Named args for `$name` substitution in the body | Dropped |
+| `model` | Model override while the skill is active | Dropped |
+| `disable-model-invocation` | `true` = manual `/skill` only (no auto-trigger) | Dropped |
+| `user-invocable` | `false` = hidden from `/` menu, Claude-only | Dropped |
+| `context` | `fork` runs the skill in a subagent (with `agent`) | Dropped |
+| `agent` | Subagent type used with `context: fork` | Dropped |
+| `hooks` | Skill-scoped hooks (same shape as settings.json) | Dropped |
+| `paths` | Glob filters — skill loads only when matching files are in play | Dropped |
+| `shell` | Shell for `` !`cmd` `` dynamic context injection (`bash`/`powershell`) | Dropped |
+| `disallowed-tools` | Removes tools from the pool while active | Dropped |
 
 ```yaml
 ---
-disable-model-invocation: false     # true = manual /skill only
-user-invocable: true                # false = hide from slash completion
-context: main                       # main | fork (subagent isolation)
-agent: custom-agent                 # Custom system prompt agent
-hooks:
-  preToolUse:
-    - command: "echo pre"
-  postToolUse:
-    - command: "echo post"
+# example: a Claude Code skill using superset fields AT THE TOP LEVEL
+name: review
+description: "Code review with semantic diffs…"
+when_to_use: "Use when the user asks to review staged changes or a PR…"
+argument-hint: "[target|--all|--pr N] [--security|--perf]"
+effort: high
+license: MIT
+metadata:                 # custom bookkeeping only
+  author: claude-mods
+  related-skills: "testgen, security-ops"
 ---
 ```
 
+> **PR #12 lesson:** moving `when_to_use`/`argument-hint`/`effort` from top-level into
+> `metadata` (to satisfy the portable spec's six-field minimum) **disables** them in
+> Claude Code. For a Claude-Code-targeted repo, keep them top-level. The portable-minimum
+> reading only makes sense for a plugin that must also run on non-Claude-Code Agent Skills
+> platforms — and even then it's a trade (portability bought by losing the behaviour here).
+
 ## Subagent Options
 
 | Field | Values | Purpose |