@ssheleg/make-skill 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,28 +1,52 @@
1
- # Agent Skills open standard — conformance reference
1
+ # Agent Skills — the hard rules, from both authorities
2
2
 
3
3
  **Load this when:** authoring or retrofitting any `SKILL.md`, or when a skill must
4
- install cleanly on agents outside Claude Code.
4
+ install cleanly outside Claude Code. Craft (descriptions, freedom, scripts, evals)
5
+ is `references/authoring.md`; surfaces and the Skills API are
6
+ `references/surfaces.md`.
5
7
 
6
- Upstream sources (verify before locking anything — the spec moves):
7
- - Spec — <https://agentskills.io/specification>
8
- - Repo + reference validator — <https://github.com/agentskills/agentskills>
9
- (`skills-ref validate ./my-skill`; Python, installed from source out of that
10
- repo — it is not on npm or PyPI)
11
- - Best practices — <https://agentskills.io/skill-creation/best-practices>
12
- - Description tuning — <https://agentskills.io/skill-creation/optimizing-descriptions>
8
+ ## Contents
13
9
 
14
- *Field limits and budgets below were read from the spec on 2026-07-28. Re-read
15
- before trusting them in a new quarter.*
10
+ - Two authorities, one floor
11
+ - Frontmatter — the whole field set
12
+ - Notes that bite
13
+ - Directory layout
14
+ - Progressive disclosure — the budgets
15
+ - Validation — who says no
16
+ - Conformance checklist
16
17
 
17
- The ssheleg canon in `SKILL.md` is a **superset** of this spec. It may add rules
18
+ ## Two authorities, one floor
19
+
20
+ | Source | What it governs | Where |
21
+ |---|---|---|
22
+ | **Agent Skills open standard** | the portable format every agent reads | <https://agentskills.io/specification> |
23
+ | **Anthropic platform docs** | what Anthropic's own surfaces accept and enforce | <https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview> |
24
+ | Claude Code plugin reference | host extensions and packaging | `references/claude-code-plugin.md` |
25
+
26
+ They agree on the shape and differ on enforcement — **write to the intersection**,
27
+ because the strictest reader is the one that rejects you:
28
+
29
+ | Rule | agentskills.io | Anthropic platform | Claude Code |
30
+ |---|---|---|---|
31
+ | `name` ≤64, `[a-z0-9-]` | yes | yes | yes |
32
+ | no leading/trailing/double hyphen, `name` == parent dir | **required** | dir must match `name` on upload (case/underscore-insensitive) | `name` overrides the dir for the `/command` |
33
+ | `name` must not contain `anthropic` / `claude` | silent | **enforced** — the Skills API rejects the upload | not enforced |
34
+ | no XML tags in `name` / `description` | silent | **enforced** | not enforced |
35
+ | `description` ≤1024, non-empty | yes | yes | listing truncates `description` + `when_to_use` at 1536 |
36
+ | `license`, `compatibility`, `metadata`, `allowed-tools` | defined | undocumented — don't depend on them there | read, plus ~14 host-only fields |
37
+ | body <500 lines / <5000 tokens | recommended | recommended (level-2 budget) | same |
38
+
39
+ *Read from both on 2026-08-03. Re-read before trusting a limit in a new quarter.*
40
+
41
+ The ssheleg canon in `SKILL.md` is a **superset** of all three. It may add rules
18
42
  (RU triggers, version sync, marketplace layout); it must never violate one.
19
43
 
20
44
  ## Frontmatter — the whole field set
21
45
 
22
46
  | Field | Required | Constraint |
23
47
  |---|---|---|
24
- | `name` | yes | 1–64 chars, `a-z0-9-` only, no leading/trailing `-`, no `--`, MUST equal the parent directory name |
25
- | `description` | yes | 1–1024 chars, non-empty; says what it does AND when to use it |
48
+ | `name` | yes | 1–64 chars, `a-z0-9-` only, no leading/trailing `-`, no `--`, MUST equal the parent directory name, no XML tags, must not contain `anthropic` or `claude` |
49
+ | `description` | yes | 1–1024 chars, non-empty, no XML tags; says what it does AND when to use it; third person |
26
50
  | `license` | no | license name or the name of a bundled license file |
27
51
  | `compatibility` | no | ≤500 chars; environment requirements (product, system packages, network) |
28
52
  | `metadata` | no | map of string→string; arbitrary client-defined keys (use unique key names) |
@@ -41,15 +65,25 @@ allowed-tools: Bash(git:*) Read
41
65
  ---
42
66
  ```
43
67
 
44
- Notes that bite:
68
+ ## Notes that bite
69
+
45
70
  - The **1024-char cap is on `description` alone**, not on the whole frontmatter
46
71
  block. Adding `license`/`metadata` does not eat the description budget.
72
+ - **Reserved words are a substring rule.** `claude-tools`, `anthropic-helper` and
73
+ `my-claude-thing` are all rejected on upload — legal in Claude Code, so the
74
+ failure only appears the day someone ships the skill to the API.
75
+ - **"No XML tags" bites templates.** A placeholder like `name: <skill-name>` reads
76
+ as a tag; seed skeletons with plain placeholders (`skill-name-here`).
47
77
  - `metadata` values are **strings** — quote versions (`version: "1.0"`), or YAML
48
78
  turns `1.0` into a float.
49
- - `allowed-tools` is a single space-separated **string**, not a YAML list.
79
+ - `allowed-tools` is a single space-separated **string**, not a YAML list. Claude
80
+ Code additionally accepts a comma-separated string or a YAML list — write the
81
+ spec form anyway, since it is the only one every host reads.
50
82
  - Nothing in the spec versions a skill. If you want the version visible to agents
51
83
  that never see `plugin.json`, put it in `metadata.version` — then it joins the
52
84
  version-sync rule.
85
+ - The 500-line / 5000-token budget is on the body an agent loads on activation,
86
+ not on the bundle. Bundled files cost nothing until read.
53
87
 
54
88
  ## Directory layout
55
89
 
@@ -69,6 +103,7 @@ Notes that bite:
69
103
  dir), never in a sibling directory: the skills CLI ships only the skill's own
70
104
  folder.
71
105
  - `assets/` — output templates too long for `SKILL.md`, schemas, lookup tables.
106
+ - Paths are relative to the skill root and always use **forward slashes**.
72
107
 
73
108
  ## Progressive disclosure — the budgets
74
109
 
@@ -79,67 +114,44 @@ Notes that bite:
79
114
  | `scripts/` `references/` `assets/` | only when the body sends the agent there | no cap, keep files focused |
80
115
 
81
116
  Rules:
82
- - Relative paths from the skill root; keep references **one level deep**
83
- (`references/mcp.md`, not `references/proto/v1/mcp.md`). No reference chains.
84
- - State **when** to load each file — "read `references/a2a.md` before designing
85
- an agent-to-agent contract" beats "see references/ for details". An unconditional
117
+ - Keep references **one level deep** (`references/mcp.md`, not
118
+ `references/proto/v1/mcp.md`) and link every one of them from `SKILL.md`
119
+ itself. A file reachable only through another file gets previewed with `head`
120
+ and half-read.
121
+ - Give every reference a **load condition** — "read `references/a2a.md` before
122
+ designing an agent-to-agent contract" beats "see references/". An unconditional
86
123
  pointer gets loaded always or never.
124
+ - Reference files over **100 lines carry a `## Contents` list** — that is what a
125
+ partial read sees.
87
126
  - Keep gotchas in `SKILL.md` itself. The agent can't know to load a file about a
88
127
  trap it doesn't know exists.
128
+ - Scripts are executed, not read: their code never enters context, only output
129
+ does. Say which you mean.
130
+
131
+ ## Validation — who says no
132
+
133
+ | Checker | Covers | Note |
134
+ |---|---|---|
135
+ | `skills-ref validate ./<skill dir>` | the open standard's frontmatter rules | Python, installed from source out of `github.com/agentskills/agentskills`; not on npm or PyPI |
136
+ | Skills API upload | Anthropic's extra rules (reserved words, XML tags, dir name, 30 MB) | the only place they are enforced — see `references/surfaces.md` |
137
+ | `claude plugin validate … --strict` | plugin/marketplace **manifests only**, not SKILL.md frontmatter | `references/claude-code-plugin.md` |
138
+ | your `test/validate.py` | house rules + everything the three above miss | the only one that runs on every commit |
139
+
140
+ ## Conformance checklist
89
141
 
90
- ## Description — the whole triggering budget
91
-
92
- The description is the ONLY thing the agent sees before deciding to load the
93
- skill. Spec-aligned rules:
94
-
95
- - **Imperative**: "Use when …", not "This skill does …".
96
- - **User intent, not mechanics** — match what the user asked for.
97
- - **Be pushy**: name the contexts where it applies, including ones where the user
98
- never says the domain word ("even if they don't mention 'CSV'").
99
- - **Concise**: a few sentences. Descriptions grow during tuning — re-check the
100
- 1024 cap after every edit.
101
- - Agents skip skills for tasks they can already do in one step. Descriptions earn
102
- their keep on specialized/multi-step work.
103
-
104
- ### Trigger eval loop (use when a skill fires too rarely or too often)
105
-
106
- 1. Write ~20 realistic queries: 8–10 `should_trigger: true`, 8–10 `false`. The
107
- valuable negatives are **near-misses** that share keywords but need something
108
- else.
109
- 2. Run each 3× against the agent with the skill installed → trigger rate;
110
- pass threshold 0.5.
111
- 3. Split 60% train / 40% validation, fixed across iterations. Tune only on train
112
- failures.
113
- 4. Too narrow → broaden scope/context. False-firing → add what it does NOT do.
114
- Never paste keywords from a failed query — that's overfitting; address the
115
- category instead.
116
- 5. ≤5 iterations; pick the iteration with the best **validation** pass rate (not
117
- necessarily the last).
118
-
119
- ## Body patterns worth copying
120
-
121
- - **Gotchas section** — concrete environment facts that defy assumption. Highest
122
- value content in most skills. Every correction you make by hand becomes a line.
123
- - **Templates** for output format — agents pattern-match structures better than
124
- prose descriptions. Long ones → `assets/`.
125
- - **Checklists** for multi-step workflows with dependencies.
126
- - **Validation loops** — do work → run validator → fix → repeat until green.
127
- - **Plan-validate-execute** for batch/destructive work: emit a plan file, validate
128
- it against a source-of-truth file, only then execute.
129
- - **Defaults, not menus** — one recommended tool + a one-line escape hatch.
130
- - **Add what the agent lacks**; cut anything it already knows. Test: "would the
131
- agent get this wrong without this line?" No → delete it.
132
- - **Procedures over answers** — teach the method, not one instance's result.
133
-
134
- ## Conformance checklist (run in every Retrofit audit)
135
-
136
- - [ ] `name`: matches dir, ≤64 chars, `[a-z0-9-]`, no leading/trailing/double hyphen
137
- - [ ] `description`: 1–1024 chars, imperative "Use when …", triggers listed
142
+ - [ ] `name`: matches dir, ≤64 chars, `[a-z0-9-]`, no leading/trailing/double
143
+ hyphen, no `anthropic`/`claude`, no angle brackets
144
+ - [ ] `description`: 1–1024 chars, no angle brackets, third person, says what it
145
+ does AND when to use it, concrete triggers listed
138
146
  - [ ] optional fields legal: `compatibility` ≤500, `metadata` all-string map,
139
147
  `allowed-tools` a space-separated string
148
+ - [ ] no frontmatter key outside spec ∪ documented host extensions
140
149
  - [ ] `SKILL.md` < 500 lines and < 5000 tokens
141
- - [ ] heavy material lives in `references/` / `scripts/` / `assets/` INSIDE the
142
- skill dir, one level deep, each with a stated load trigger
143
- - [ ] no relative link escapes the skill directory (`../`)
150
+ - [ ] heavy material in `references/` / `scripts/` / `assets/` INSIDE the skill
151
+ dir, one level deep, each linked from the body with a stated load trigger
152
+ - [ ] reference files >100 lines have a `## Contents` list
153
+ - [ ] forward slashes everywhere; no relative link escapes the skill dir (`../`)
154
+ - [ ] runtime needs (network, packages) declared in `compatibility` —
155
+ `references/surfaces.md`
144
156
  - [ ] `skills-ref validate ./<skill dir>` passes (upstream truth), in addition to
145
157
  `test/validate.py` (house rules)
@@ -0,0 +1,244 @@
1
+ # Authoring craft — writing a body an agent actually follows
2
+
3
+ **Load this when:** writing or rewriting a `SKILL.md` body, tuning a description
4
+ that fires too rarely or too often, deciding how prescriptive to be, bundling
5
+ `scripts/`, or building the evaluations that prove the skill works.
6
+
7
+ Hard limits and field rules are in `references/agent-skills-spec.md`; this file is
8
+ the craft on top of them. Sources: Anthropic's
9
+ [skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices)
10
+ and [agentskills.io](https://agentskills.io/skill-creation/best-practices).
11
+ *Read from both on 2026-08-03.*
12
+
13
+ ## Contents
14
+
15
+ - Naming — what to call the skill
16
+ - Description — the entire triggering budget
17
+ - Trigger eval loop — when firing is wrong
18
+ - Degrees of freedom — how prescriptive to be
19
+ - Body patterns worth copying
20
+ - Workflows and feedback loops
21
+ - Content guidelines (terminology, time, paths, table of contents)
22
+ - Scripts — the rules that separate a script from a liability
23
+ - Evaluation and iteration — evals before prose
24
+ - Quality checklist
25
+
26
+ ## Naming — what to call the skill
27
+
28
+ The `name` is a trigger surface, not a filename. Charset rules live in the spec
29
+ reference; the naming *style* rules:
30
+
31
+ - **Gerund form is the recommended default** — `processing-pdfs`,
32
+ `analyzing-spreadsheets`, `writing-documentation`. It states the activity.
33
+ - Acceptable: noun phrase (`pdf-processing`), action form (`process-pdfs`).
34
+ - **Never**: `helper`, `utils`, `tools`, `documents`, `data`, `files` — a vague
35
+ name buys nothing at selection time and collides with the next skill.
36
+ - **Never** `anthropic`/`claude` in the name — reserved, and the Skills API
37
+ rejects the upload (see the spec reference).
38
+ - Pick ONE pattern per collection and hold it. Mixed patterns inside a family are
39
+ the reason nobody can guess a sibling skill's name.
40
+
41
+ ## Description — the entire triggering budget
42
+
43
+ The description is the only thing an agent sees before deciding to load the
44
+ skill, and it competes with every other installed skill's description. Rules,
45
+ each of which changes whether the skill fires:
46
+
47
+ - **Say both halves: what it does AND when to use it.** "Extracts text and tables
48
+ from PDFs, fills forms, merges documents. Use when working with PDF files or
49
+ when the user mentions PDFs, forms, or document extraction."
50
+ - **Third person, always.** The description is injected into the system prompt;
51
+ first/second person ("I can help you…", "You can use this to…") measurably
52
+ degrades selection. Imperative "Use when …" is fine — it is the trigger clause,
53
+ not a point of view.
54
+ - **User intent, not mechanics.** Match the words the user will actually type.
55
+ - **Be pushy about context**: name the situations where it applies, including the
56
+ ones where the user never says the domain word ("even if they don't mention
57
+ 'CSV'").
58
+ - **Say what it is NOT for** when a near-miss skill exists. That sentence is what
59
+ stops trigger theft.
60
+ - Concise, a few sentences. Descriptions grow during tuning — re-check the 1024
61
+ cap after every edit.
62
+ - Vague descriptions are the failure mode: `Helps with documents`, `Processes
63
+ data`, `Does stuff with files` never win a selection against a specific one.
64
+ - Agents skip skills for tasks they can already do in one step. Descriptions earn
65
+ their keep on specialized or multi-step work.
66
+
67
+ ## Trigger eval loop — when firing is wrong
68
+
69
+ 1. Write ~20 realistic queries: 8–10 `should_trigger: true`, 8–10 `false`. The
70
+ valuable negatives are **near-misses** that share keywords but need something
71
+ else.
72
+ 2. Run each 3× against the agent with the skill installed → trigger rate;
73
+ pass threshold 0.5.
74
+ 3. Split 60% train / 40% validation, fixed across iterations. Tune only on train
75
+ failures.
76
+ 4. Too narrow → broaden scope/context. False-firing → add what it does NOT do.
77
+ Never paste keywords from a failed query — that's overfitting; address the
78
+ category instead.
79
+ 5. ≤5 iterations; pick the iteration with the best **validation** pass rate (not
80
+ necessarily the last).
81
+
82
+ ## Degrees of freedom — how prescriptive to be
83
+
84
+ Match specificity to how fragile the task is. Getting this backwards is the most
85
+ common reason a skill is either ignored or actively harmful.
86
+
87
+ | Freedom | Write | Use when |
88
+ |---|---|---|
89
+ | **High** | prose steps, heuristics | many valid approaches, context decides (code review, triage) |
90
+ | **Medium** | pseudocode, parameterized snippet | a preferred pattern exists, some variation is fine (report generation) |
91
+ | **Low** | one exact command, "do not modify it" | fragile, order-dependent, destructive (migrations, releases) |
92
+
93
+ The picture: a narrow bridge with cliffs gets guardrails and one exact command;
94
+ an open field gets a direction and trust. A low-freedom instruction in an open
95
+ field makes the agent worse than it was without the skill.
96
+
97
+ ## Body patterns worth copying
98
+
99
+ - **Gotchas section** — concrete environment facts that defy assumption. Highest
100
+ value content in most skills. Every correction you make by hand becomes a line.
101
+ - **Templates** for output format — agents pattern-match structures better than
102
+ prose. Mark them strict ("ALWAYS use this exact structure") or flexible ("a
103
+ sensible default; use judgement"); an unlabelled template gets both wrong. Long
104
+ ones → `assets/`.
105
+ - **Input/output example pairs** where quality depends on style (commit messages,
106
+ reviews). Three examples beat three paragraphs describing them.
107
+ - **Checklists** for multi-step workflows with dependencies.
108
+ - **Conditional routing** — "creating new content? → workflow A; editing? →
109
+ workflow B" — so the agent never reads the branch it doesn't need.
110
+ - **Validation loops** — do work → run validator → fix → repeat until green.
111
+ - **Plan-validate-execute** for batch/destructive work: emit a plan file, validate
112
+ it against a source-of-truth file, only then execute. Catches "field does not
113
+ exist" before 50 fields are written, and the plan is cheap to iterate on.
114
+ - **Defaults, not menus** — one recommended tool plus a one-line escape hatch.
115
+ "pypdf or pdfplumber or PyMuPDF or pdf2image" is a coin flip, not guidance.
116
+ - **Add what the agent lacks**; cut anything it already knows. Test: "would the
117
+ agent get this wrong without this line?" No → delete it.
118
+ - **Procedures over answers** — teach the method, not one instance's result.
119
+
120
+ ## Workflows and feedback loops
121
+
122
+ For anything multi-step, give a checklist the agent can copy into its reply and
123
+ tick off, then the steps beneath it:
124
+
125
+ ```
126
+ Task progress:
127
+ - [ ] Step 1: analyze the form (run scripts/analyze_form.py)
128
+ - [ ] Step 2: create the field mapping (edit fields.json)
129
+ - [ ] Step 3: validate the mapping (run scripts/validate_fields.py)
130
+ - [ ] Step 4: fill the form (run scripts/fill_form.py)
131
+ - [ ] Step 5: verify output (run scripts/verify_output.py)
132
+ ```
133
+
134
+ Explicit steps are what stop an agent skipping validation. Name the return edge:
135
+ "if verification fails, return to step 2". The same shape works with no code at
136
+ all — the "validator" can be a style guide the agent re-reads.
137
+
138
+ If a workflow grows past a screen, move it into its own file and route to it from
139
+ the body.
140
+
141
+ ## Content guidelines
142
+
143
+ - **No time-sensitive statements.** "Before August, use the old API" is wrong the
144
+ moment it ships. Put superseded material under an `## Old patterns` heading (a
145
+ collapsed `<details>` block works) and keep the current path unqualified. A
146
+ DATED PROVENANCE line is the exception and is encouraged: "*read from the spec
147
+ on 2026-08-03*" tells the next reader what to re-verify.
148
+ - **One term per concept.** Pick "field" or "box", "extract" or "pull", and never
149
+ alternate — synonym drift makes an agent think two things are being described.
150
+ - **Forward slashes in every path**, including on Windows: `scripts/helper.py`,
151
+ never `scripts\helper.py`. Backslash paths break on Unix and in JSON.
152
+ - **Reference files over 100 lines get a `## Contents` list at the top.** Agents
153
+ preview long files with `head`; without a table of contents they act on the
154
+ first 100 lines and never learn the rest exists.
155
+ - **One level deep from `SKILL.md`.** A file reachable only through another file
156
+ gets partially read or missed entirely. Every reference links from the body.
157
+
158
+ ## Scripts — the rules that separate a script from a liability
159
+
160
+ A bundled script is more reliable than generated code, costs no context (only its
161
+ output enters the window), and is consistent across runs. It also fails silently
162
+ if written carelessly.
163
+
164
+ - **Solve, don't defer.** Handle the error inside the script — missing file,
165
+ permission denied — and print what you did. `return open(path).read()` and
166
+ "let the agent figure it out" turns one failure into a debugging session.
167
+ - **No voodoo constants.** Every timeout, retry count and threshold carries a
168
+ comment justifying it. If you don't know why it's 47, the agent has no chance.
169
+ - **State the intent explicitly**: "Run `scripts/analyze_form.py` to extract
170
+ fields" (execute) vs "See `scripts/analyze_form.py` for the extraction
171
+ algorithm" (read). Ambiguity here gets a script pasted into context, which is
172
+ exactly the cost the script existed to avoid.
173
+ - **Declare dependencies and verify they exist** on the surface you target —
174
+ "install required package: `pip install pypdf`", or better, no third-party
175
+ dependency at all. Never write "use the pdf library". The Claude API surface
176
+ cannot install anything at runtime (`references/surfaces.md`).
177
+ - **Verbose, specific error messages**: "Field 'signature_date' not found.
178
+ Available: customer_name, order_total, signature_date_signed" is actionable;
179
+ "invalid field" is not.
180
+ - **Vision is available**: rendering an input to images and letting the agent look
181
+ at it beats describing a layout in prose.
182
+
183
+ ## Evaluation and iteration — evals before prose
184
+
185
+ **Build the evaluations before writing extensive documentation.** Otherwise the
186
+ skill documents imagined problems.
187
+
188
+ 1. **Identify gaps** — run the agent on representative tasks with NO skill.
189
+ Record the specific failures.
190
+ 2. **Create evaluations** — at least three scenarios covering those gaps.
191
+ 3. **Baseline** — measure performance without the skill.
192
+ 4. **Write the minimum** that fixes the gaps.
193
+ 5. **Iterate** — re-run, compare to baseline, refine.
194
+
195
+ Evaluation record — there is no built-in runner, so keep them in the repo as
196
+ data and run them yourself. House layout: `test/evals/triggers.json` (~20
197
+ queries, half near-miss negatives) and `test/evals/scenarios.json` (≥3, the
198
+ shape below), with any input under `test/evals/fixtures/` — **never named
199
+ `SKILL.md`**, which would ship as a real skill:
200
+
201
+ ```json
202
+ {
203
+ "skills": ["pdf-processing"],
204
+ "query": "Extract all text from this PDF file and save it to output.txt",
205
+ "files": ["test-files/document.pdf"],
206
+ "expected_behavior": [
207
+ "Reads the PDF with an appropriate library or CLI tool",
208
+ "Extracts text from every page without skipping any",
209
+ "Saves the result to output.txt in readable form"
210
+ ]
211
+ }
212
+ ```
213
+
214
+ **Test on every model you ship for.** A skill is an addition to a model, so its
215
+ effect varies by model: Haiku may need more guidance, Opus may be slowed by
216
+ over-explanation. Run the evals on Haiku, Sonnet and Opus if all three are in
217
+ scope.
218
+
219
+ **The two-agent loop.** Author with one instance (call it A), test with a fresh
220
+ instance that has the skill installed (B), and bring B's observed failures back to
221
+ A — "B forgot to filter test accounts even though the skill says to; is the rule
222
+ prominent enough?". Refine against observed behavior, never against assumptions.
223
+ Watch for: files read in an unexpected order (structure is wrong), references
224
+ never followed (links not prominent), the same file read every time (it belongs in
225
+ the body), a bundled file never read at all (delete it).
226
+
227
+ Approval gates for a skill other people will install — triggering accuracy,
228
+ isolation, coexistence with the existing skill set, instruction following, output
229
+ quality — are in `references/enterprise.md`.
230
+
231
+ ## Quality checklist
232
+
233
+ - [ ] Description gives what AND when, in third person, with concrete triggers
234
+ - [ ] Name follows one pattern, is not vague, contains no reserved word
235
+ - [ ] Body under 500 lines / 5000 tokens; detail in one-level-deep files
236
+ - [ ] Every reference has a stated load condition; >100-line ones have a TOC
237
+ - [ ] Degrees of freedom match task fragility
238
+ - [ ] No time-sensitive statements outside an "Old patterns" section
239
+ - [ ] Consistent terminology; forward slashes everywhere
240
+ - [ ] Examples concrete, not abstract; a default given instead of a menu
241
+ - [ ] Scripts handle their own errors, document constants, declare packages
242
+ - [ ] Execute-vs-read intent stated for every bundled script
243
+ - [ ] Validation/feedback loop for anything quality-critical or destructive
244
+ - [ ] ≥3 evaluations exist, baselined without the skill, run on every target model
@@ -19,6 +19,21 @@ host layer on top of it**: everything here is Claude-Code-specific and is
19
19
  ignored by other agents — so nothing here may be load-bearing for a skill that
20
20
  must also run on Cursor, Codex, or the skills CLI.
21
21
 
22
+ ## Contents
23
+
24
+ - The gate: `claude plugin validate`
25
+ - `plugin.json` fields
26
+ - `marketplace.json` fields, reserved names, plugin entries
27
+ - Component locations
28
+ - Skill frontmatter — host extensions
29
+ - Agents, hooks, MCP inside a plugin
30
+ - LSP servers and monitors
31
+ - Path variables
32
+ - Caching, symlinks, path traversal
33
+ - Skills-directory plugins
34
+ - CLI
35
+ - Conformance checklist
36
+
22
37
  ## The gate: `claude plugin validate`
23
38
 
24
39
  ```bash
@@ -35,6 +50,12 @@ Both must exit 0. Rules that decide the outcome:
35
50
  - Wrong **types** always fail (`keywords` as a string, not an array).
36
51
  - It runs offline and needs no auth, so it belongs in CI:
37
52
  `npm i -g @anthropic-ai/claude-code && claude plugin validate … --strict`.
53
+ - **It validates the MANIFEST, whatever the docs promise.** The troubleshooting
54
+ table says the command checks "`plugin.json`, skill/agent/command frontmatter,
55
+ and `hooks/hooks.json`"; on 2.1.212 a `SKILL.md` carrying an invented
56
+ front-matter key passed `--strict` untouched, and the output names only the
57
+ manifest it read. Keep front-matter rules in your own validator — this gate
58
+ does not cover them.
38
59
 
39
60
  ## `plugin.json` — `.claude-plugin/plugin.json`
40
61
 
@@ -50,7 +71,7 @@ nothing to validate. **`name` is the only required field.**
50
71
  | `version` | string | semver. **Set it and you must bump it** — CC uses the version as the cache key, so new commits under an unchanged version never reach users. Omit it entirely and the git SHA is the version (every commit ships) |
51
72
  | `description`, `author{name,email,url}`, `homepage`, `repository`, `license`, `keywords[]` | | metadata |
52
73
  | `defaultEnabled` | boolean | `false` = installs disabled until the user opts in (CC ≥ 2.1.154). The marketplace entry's copy wins over this one; an existing `enabledPlugins` entry wins over both |
53
- | `skills` | string\|array | extra skill dirs — **adds to** the default `skills/` scan |
74
+ | `skills` | string\|array | extra skill dirs — **adds to** the default `skills/` scan. One exception: in a marketplace entry whose `source` resolves to the marketplace ROOT, the listed subdirectories REPLACE that scan (if none of them exist, the default scan runs after all) |
54
75
  | `commands`, `agents`, `workflows`, `outputStyles` | string\|array | **replace** the default folder. To keep it, list it: `["./commands/", "./extras/"]` |
55
76
  | `hooks`, `mcpServers`, `lspServers` | string\|array\|object | path(s) or inline config; own merge rules |
56
77
  | `experimental.themes`, `experimental.monitors` | string\|array | still moving; top level warns today, will be required under `experimental` |
@@ -106,7 +127,7 @@ marketplace-only `source`, `category`, `tags`, `strict`, `relevance`,
106
127
  | `github` | `{"source":"github","repo":"owner/repo","ref?":"main","sha?":"…"}` |
107
128
  | `url` | `{"source":"url","url":"https://…​.git","ref?":…,"sha?":…}` |
108
129
  | `git-subdir` | `{"source":"git-subdir","url":"…","path":"packages/x","ref?":…,"sha?":…}` — sparse clone |
109
- | `npm` | `{"source":"npm","package":"@scope/pkg","version?":…,"registry?":…}` — version resolves to `unknown`, so no update detection |
130
+ | `npm` | `{"source":"npm","package":"@scope/pkg","version?":…,"registry?":…}` — no git SHA to fall back on, so set `version` in the manifest or the entry, else it resolves to `unknown` and updates never fire |
110
131
 
111
132
  `sha` beats `ref` when both are set. **Marketplace source ≠ plugin source**: the
112
133
  first says where `marketplace.json` lives (supports `ref` only), the second where
@@ -133,12 +154,17 @@ Version resolution order: `plugin.json` → marketplace entry → git SHA →
133
154
  | MCP | `.mcp.json` |
134
155
  | LSP | `.lsp.json` |
135
156
  | monitors | `monitors/monitors.json` |
157
+ | themes | `themes/*.json` — `base` preset + sparse `overrides` |
136
158
  | executables | `bin/` — on the Bash tool's PATH while enabled |
137
159
  | defaults | `settings.json` (only `agent` and `subagentStatusLine` keys) |
138
160
 
139
- **Only `plugin.json` goes inside `.claude-plugin/`.** Every component directory
140
- sits at the plugin root; components buried in `.claude-plugin/` load as nothing
141
- and the plugin still "works", which is why this one costs an afternoon.
161
+ **Only `plugin.json` goes inside `.claude-plugin/`.** Those are the DEFAULT
162
+ locations, all at the plugin root — a manifest path field may point anywhere
163
+ else inside the plugin (`"commands": ["./specialized/deploy.md"]`), and from
164
+ 2.1.140 Claude Code warns in `claude plugin list` when a manifest key leaves a
165
+ default folder unscanned. What never works is burying components in
166
+ `.claude-plugin/`: they load as nothing while the plugin still "works", which is
167
+ why that one costs an afternoon.
142
168
 
143
169
  A plugin-root `CLAUDE.md` is **not** loaded as context. Ship instructions as a
144
170
  skill.
@@ -151,7 +177,11 @@ string that changes on every update.
151
177
  ## Skill frontmatter — host extensions
152
178
 
153
179
  Portable floor (`name`, `description`, `license`, `compatibility`, `metadata`,
154
- `allowed-tools`) is in `references/agent-skills-spec.md`. Claude Code also reads:
180
+ `allowed-tools`) is in `references/agent-skills-spec.md`. **`allowed-tools` is
181
+ looser here than in the spec**: Claude Code takes a space- OR comma-separated
182
+ string OR a YAML list, the spec takes only the space-separated string. Write the
183
+ spec form — a list works here and breaks everywhere else. Claude Code also
184
+ reads:
155
185
 
156
186
  | Field | Effect |
157
187
  |---|---|
@@ -194,6 +224,39 @@ there.
194
224
  hook's `server` takes `plugin:<plugin>:<server>`. A matcher on the bare server
195
225
  key never fires.
196
226
 
227
+ ## LSP servers and monitors
228
+
229
+ The load condition above promises both; here is the whole of each.
230
+
231
+ **LSP** — `.lsp.json` at the plugin root, or `lspServers` inline. Required per
232
+ server: `command` (binary must be on PATH — the plugin does NOT ship it) and
233
+ `extensionToLanguage`. Optional: `args`, `transport` (`stdio` default or
234
+ `socket`), `env`, `initializationOptions`, `settings`, `workspaceFolder`,
235
+ `startupTimeout`, `shutdownTimeout`, `restartOnCrash` (default `true`),
236
+ `maxRestarts`, `diagnostics` (default `true`). `restartOnCrash` and
237
+ `shutdownTimeout` need CC ≥ 2.1.205 — before that, setting either made Claude
238
+ Code skip the server silently, visible only under `claude --debug`. When two
239
+ enabled servers claim the same extension, the first registered wins and the
240
+ other never starts; an invalid server is skipped and no longer blocks a valid
241
+ one (also 2.1.205).
242
+
243
+ ```json
244
+ { "go": { "command": "gopls", "args": ["serve"],
245
+ "extensionToLanguage": { ".go": "go" } } }
246
+ ```
247
+
248
+ **Monitors** — `monitors/monitors.json`, or `experimental.monitors` inline (a
249
+ path string there loads from a custom location). Array of `{name, command,
250
+ description, when?}`; `when` is `"always"` (default) or
251
+ `"on-skill-invoke:<skill>"`. Each runs as a background process for the session
252
+ and every stdout line reaches Claude as a notification. Interactive CLI only,
253
+ unsandboxed at hook trust level, skipped where the Monitor tool is unavailable,
254
+ and never loaded from a project-scope `@skills-dir` plugin. `${CLAUDE_PLUGIN_ROOT}`,
255
+ `${CLAUDE_PLUGIN_DATA}`, `${CLAUDE_PROJECT_DIR}` and `${ENV_VAR}` substitute;
256
+ `${user_config.*}` is rejected outright (it would reach a shell), and monitor
257
+ processes get no `CLAUDE_PLUGIN_OPTION_*` either — read the value from a config
258
+ file. Disabling a plugin mid-session does not stop a running monitor.
259
+
197
260
  ## Path variables
198
261
 
199
262
  | Variable | Resolves to |
@@ -248,7 +311,7 @@ need `/reload-plugins`. Disable with `claude plugin disable <name>@skills-dir`.
248
311
  | `claude plugin validate <path> [--strict]` | the conformance gate, offline |
249
312
  | `claude plugin init <name> [--with …]` | scaffold a `@skills-dir` plugin |
250
313
  | `claude plugin install <name>@<marketplace> [-s user\|project\|local] [--config k=v]` | install |
251
- | `claude plugin update <name>@<marketplace>` | update — the **full `name@marketplace` form is mandatory** |
314
+ | `claude plugin update <name>@<marketplace>` | update. Docs accept a bare `<name>`; **2.1.212 does not** — `claude plugin update make-skill` answers `Plugin "make-skill" not found`, exits 0, changes nothing. Always pass `name@marketplace` |
252
315
  | `claude plugin enable\|disable <name>@<marketplace>` | toggle without uninstalling |
253
316
  | `claude plugin uninstall <name>@<marketplace> [--keep-data] [--prune]` | remove (deletes the data dir unless `--keep-data`) |
254
317
  | `claude plugin list [--json]` | installed plugins, versions, source, state |