Skill Validator
Validate SKILL.md files against the Agent Skills specification and Claude Code extensions.
When to Run
- After creating a new skill
- After modifying a skill's SKILL.md frontmatter
- Before committing skill changes
- During periodic repo audits
Validation Rules
Required Fields (Agent Skills Spec)
Every SKILL.md must have YAML frontmatter with:
name — kebab-case, matches directory name
description — 1-3 sentences, under 1024 chars, starts with verb or domain noun
Metadata Block
version and tags must be inside metadata:, never top-level:
# CORRECT
metadata:
version: "1.0.0"
tags: "react, performance, optimization"
# WRONG — top-level version
version: 1.0.0
# WRONG — tags as YAML list
metadata:
tags:
- react
- performance
Forbidden Fields
These are not part of any spec:
auto_activate / auto_trigger — removed in 2026-04 migration
risk — not in Agent Skills or Claude Code specs
Claude Code Extensions (Optional)
Valid extension fields (must match allowed_fields in scripts/validate-skill-sync.sh):
| Field |
Purpose |
when_to_use |
Extra trigger phrases appended to description |
disable-model-invocation |
Prevent auto-triggering (for destructive skills) |
user-invocable |
false hides from the / menu |
allowed-tools |
Auto-approve allowlist (not a sandbox — unlisted tools stay callable) |
disallowed-tools |
Removes tools from the pool while active (the actual block mechanism) |
argument-hint |
Autocomplete hint for expected arguments |
compatibility |
Environment prerequisites (packages, network, target agent) |
context |
fork for subagent isolation |
agent |
Subagent type when context: fork |
hooks |
Lifecycle hooks scoped to the skill |
paths |
⚠️ Broken upstream (#49835) — flag if present |
shell |
bash (default) or powershell |
Forbidden Fields (updated)
auto_activate / auto_trigger — removed in 2026-04 migration
risk — not in any spec
metadata.triggers — duplicate activation metadata; put trigger phrases in
description or when_to_use
model / effort — recognized by Claude Code but owned by app/session
configuration, not public reusable skills
- Any top-level field not in the tables above → "Unsupported top-level frontmatter field"
Content Rules
- No hardcoded
/workspace/ paths
- No tool names in instructions (say "search for" not "use Grep")
- Imperative/infinitive style ("Configure X" not "You should configure X")
- Code blocks use real backtick fences, not escaped
\```
- No concrete model names in body,
references/, or scripts/ — reject tier+version IDs (claude-3-7-sonnet-20250219, claude-opus-4.5, gpt-5.5), dated snapshots, and bare family names used as routing keys. Exception: orchestrator skills may name capability tiers in prose. See skill-standards.md → Model references.
- No harness-owned execution parameters in skills, commands, or routine templates.
Apply execution-boundary.md.
- Routine templates follow
routine-standards.md. Run
python3 scripts/audit-routines.py to detect duplicate bodies and app-parameter
leakage without printing prompt or configuration values.
- Provenance (derived skills only): when
metadata.source is set, metadata.last_synced and a README ## Upstream section are required (enforced by check_provenance()). In-house skills need no provenance fields.
Validation Process
- Read the SKILL.md frontmatter
- Check
name matches parent directory name
- Check
description exists and is under 1024 chars
- Check
description plus when_to_use is under 1536 chars
- Check
plugin.json description is present and under 100 chars
- Check
version/tags are NOT top-level (must be inside metadata:)
- Check for forbidden fields (
auto_activate, auto_trigger, risk, model, effort, any field not in the extension tables)
- Check for escaped backtick fences in content
- Validate frontmatter value types:
allowed-tools is a scalar,
metadata.version and metadata.tags are quoted scalars, and metadata is a map
- Reject duplicate
metadata.triggers; keep activation guidance in description
or when_to_use
- Check for hardcoded paths (
/workspace/, project-specific paths)
- Grep body +
references/ + scripts/ for concrete model names (claude-*, gpt-*, sonnet/opus/haiku used as IDs); allow only capability-tier prose in orchestrator skills
- Warn when skills, commands, or templates set harness-owned execution parameters
- Warn when a side-effecting skill lacks both
disable-model-invocation: true
and an explicit Confirmation Required gate
- Check prose routing references across the body, excluding frontmatter and code
fences, and flag missing local skills
- Check provenance for derived skills: if
metadata.source is set, require metadata.last_synced and a README ## Upstream section
- Run
bunx markdownlint-cli on the file
- Run
./scripts/validate-skill-sync.sh for cross-validation
Quick Validation Command
# Single skill
bunx markdownlint-cli skills/<name>/SKILL.md skills/<name>/references/*.md
# All skills
bunx markdownlint-cli --ignore bundles --ignore dist "**/*.md"
# Sync validation
./scripts/validate-skill-sync.sh
1---
2name: skill-validator
3description: |
4 Validate SKILL.md files against the Agent Skills spec and Claude Code extensions.
5 Run on new or modified skills before committing.
6metadata:
7 internal: true
8 version: "1.0.3"
9 tags: "validation, skills, spec-compliance, quality"
10---
11
12# Skill Validator
13
14Validate SKILL.md files against the Agent Skills specification and Claude Code extensions.
15
16## When to Run
17
18- After creating a new skill
19- After modifying a skill's SKILL.md frontmatter
20- Before committing skill changes
21- During periodic repo audits
22
23## Validation Rules
24
25### Required Fields (Agent Skills Spec)
26
27Every SKILL.md must have YAML frontmatter with:
28
29- `name` — kebab-case, matches directory name
30- `description` — 1-3 sentences, under 1024 chars, starts with verb or domain noun
31
32### Metadata Block
33
34`version` and `tags` must be inside `metadata:`, never top-level:
35
36```yaml
37# CORRECT
38metadata:
39 version: "1.0.0"
40 tags: "react, performance, optimization"
41
42# WRONG — top-level version
43version: 1.0.0
44
45# WRONG — tags as YAML list
46metadata:
47 tags:
48 - react
49 - performance
50```
51
52### Forbidden Fields
53
54These are not part of any spec:
55
56- `auto_activate` / `auto_trigger` — removed in 2026-04 migration
57- `risk` — not in Agent Skills or Claude Code specs
58
59### Claude Code Extensions (Optional)
60
61Valid extension fields (must match `allowed_fields` in `scripts/validate-skill-sync.sh`):
62
63| Field | Purpose |
64|-------|---------|
65| `when_to_use` | Extra trigger phrases appended to `description` |
66| `disable-model-invocation` | Prevent auto-triggering (for destructive skills) |
67| `user-invocable` | `false` hides from the `/` menu |
68| `allowed-tools` | Auto-approve **allowlist** (not a sandbox — unlisted tools stay callable) |
69| `disallowed-tools` | Removes tools from the pool while active (the actual block mechanism) |
70| `argument-hint` | Autocomplete hint for expected arguments |
71| `compatibility` | Environment prerequisites (packages, network, target agent) |
72| `context` | `fork` for subagent isolation |
73| `agent` | Subagent type when `context: fork` |
74| `hooks` | Lifecycle hooks scoped to the skill |
75| `paths` | ⚠️ Broken upstream (#49835) — flag if present |
76| `shell` | `bash` (default) or `powershell` |
77
78### Forbidden Fields (updated)
79
80- `auto_activate` / `auto_trigger` — removed in 2026-04 migration
81- `risk` — not in any spec
82- `metadata.triggers` — duplicate activation metadata; put trigger phrases in
83 `description` or `when_to_use`
84- `model` / `effort` — recognized by Claude Code but owned by app/session
85 configuration, not public reusable skills
86- Any top-level field not in the tables above → "Unsupported top-level frontmatter field"
87
88### Content Rules
89
90- No hardcoded `/workspace/` paths
91- No tool names in instructions (say "search for" not "use Grep")
92- Imperative/infinitive style ("Configure X" not "You should configure X")
93- Code blocks use real backtick fences, not escaped `\`\`\``
94- **No concrete model names** in body, `references/`, or `scripts/` — reject tier+version IDs (`claude-3-7-sonnet-20250219`, `claude-opus-4.5`, `gpt-5.5`), dated snapshots, and bare family names used as routing keys. Exception: orchestrator skills may name **capability tiers** in prose. See [skill-standards.md → Model references](../memory/system/skill-standards.md).
95- **No harness-owned execution parameters** in skills, commands, or routine templates.
96 Apply [execution-boundary.md](../memory/system/execution-boundary.md).
97- **Routine templates** follow
98 [routine-standards.md](../memory/system/routine-standards.md). Run
99 `python3 scripts/audit-routines.py` to detect duplicate bodies and app-parameter
100 leakage without printing prompt or configuration values.
101- **Provenance (derived skills only):** when `metadata.source` is set, `metadata.last_synced` and a README `## Upstream` section are required (enforced by `check_provenance()`). In-house skills need no provenance fields.
102
103## Validation Process
104
1051. Read the SKILL.md frontmatter
1062. Check `name` matches parent directory name
1073. Check `description` exists and is under 1024 chars
1084. Check `description` plus `when_to_use` is under 1536 chars
1095. Check `plugin.json` description is present and under 100 chars
1106. Check `version`/`tags` are NOT top-level (must be inside `metadata:`)
1117. Check for forbidden fields (`auto_activate`, `auto_trigger`, `risk`, `model`, `effort`, any field not in the extension tables)
1128. Check for escaped backtick fences in content
1139. Validate frontmatter value types: `allowed-tools` is a scalar,
114 `metadata.version` and `metadata.tags` are quoted scalars, and `metadata` is a map
11510. Reject duplicate `metadata.triggers`; keep activation guidance in `description`
116 or `when_to_use`
11711. Check for hardcoded paths (`/workspace/`, project-specific paths)
11812. Grep body + `references/` + `scripts/` for concrete model names (`claude-*`, `gpt-*`, `sonnet`/`opus`/`haiku` used as IDs); allow only capability-tier prose in orchestrator skills
11913. Warn when skills, commands, or templates set harness-owned execution parameters
12014. Warn when a side-effecting skill lacks both `disable-model-invocation: true`
121 and an explicit `Confirmation Required` gate
12215. Check prose routing references across the body, excluding frontmatter and code
123 fences, and flag missing local skills
12416. Check provenance for derived skills: if `metadata.source` is set, require `metadata.last_synced` and a README `## Upstream` section
12517. Run `bunx markdownlint-cli` on the file
12618. Run `./scripts/validate-skill-sync.sh` for cross-validation
127
128## Quick Validation Command
129
130```bash
131# Single skill
132bunx markdownlint-cli skills/<name>/SKILL.md skills/<name>/references/*.md
133
134# All skills
135bunx markdownlint-cli --ignore bundles --ignore dist "**/*.md"
136
137# Sync validation
138./scripts/validate-skill-sync.sh
139```