@ssheleg/make-skill 0.7.0 → 0.7.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.1 — 2026-07-31
4
+
5
+ Re-read the plugin reference against what the canon actually says, and against
6
+ what Claude Code 2.1.212 actually does. Six corrections, two of them places
7
+ where the docs and the binary disagree.
8
+
9
+ ### Fixed
10
+ - **`claude plugin validate` validates the manifest, not front matter.** The
11
+ docs' troubleshooting table says it checks "`plugin.json`, skill/agent/command
12
+ frontmatter, and `hooks/hooks.json`"; a `SKILL.md` carrying an invented
13
+ front-matter key passes `--strict` untouched. The canon said this gate
14
+ "catches a class your validator cannot see" — true for manifests, misleading
15
+ for front matter, which is exactly where the house validator earns its place.
16
+ - **`claude plugin update <bare-name>` does not work**, though the docs list a
17
+ bare name as accepted: it answers `Plugin "make-skill" not found` **and exits
18
+ 0**, so a release script sees success and ships nothing. The reference now
19
+ records both the documented form and the observed one.
20
+ - **`skills` adds to the default scan — except at a marketplace root.** When a
21
+ plugin entry's `source` resolves to the marketplace root, the listed
22
+ subdirectories replace the default `skills/` scan (and if none exist, the
23
+ default runs after all). The reference stated the rule without its exception.
24
+ - **"Every component directory sits at the plugin root" was too absolute.** That
25
+ is the default; a manifest path field may point anywhere inside the plugin,
26
+ and since 2.1.140 Claude Code warns when a manifest key leaves a default
27
+ folder unscanned. Only `.claude-plugin/` is genuinely off-limits.
28
+ - **`allowed-tools`: Claude Code is looser than the spec.** It accepts a
29
+ space- or comma-separated string or a YAML list; the open standard accepts
30
+ only the space-separated string. Canon, Cursor rule and the validator's own
31
+ error message now say which form travels and why, instead of calling a legal
32
+ Claude Code skill invalid.
33
+ - **npm plugin sources** resolve to `unknown` only when no `version` is set
34
+ anywhere — the entry or manifest version still wins.
35
+
36
+ ### Changed
37
+ - The stray-`SKILL.md` rule is scoped honestly: a plugin-root `SKILL.md` is a
38
+ legal single-skill plugin in Claude Code (2.1.142+). It is multi-channel
39
+ distribution — the skills CLI shipping every `SKILL.md` in the tree — that
40
+ makes the rule, and the validator says so.
41
+ - Version pinning: omitting `version` from both manifests is legal and hands
42
+ updates to the git SHA. This canon pins and bumps by choice, which the gotcha
43
+ now states rather than implies.
44
+
45
+ ### Added
46
+ - **LSP and monitor fields in `references/claude-code-plugin.md`.** Its own load
47
+ condition promised "adding agents / hooks / MCP / LSP / monitors", and the
48
+ file had a table row for each and nothing else: now the required and optional
49
+ LSP keys with the 2.1.205 `restartOnCrash` / `shutdownTimeout` trap and the
50
+ same-extension race, and the monitor entry schema with its trust,
51
+ `${user_config.*}` rejection and session-lifetime rules. Plus the missing
52
+ `themes/` row.
53
+
3
54
  ## v0.7.0 — 2026-07-30
4
55
 
5
56
  Conformance to Anthropic's own plugin reference
@@ -17,7 +17,8 @@ every contract inline and uses **absolute URLs only — never a relative link**
17
17
  - `description`: ≤1024 chars (that cap is on the field, not the whole front-matter).
18
18
  - Portable front-matter keys: `name`, `description`, `license`,
19
19
  `compatibility` (≤500), `metadata` (string→string map), `allowed-tools`
20
- (space-separated string, experimental). Claude Code additionally reads
20
+ (space-separated string — Claude Code also takes a comma-list or YAML list, but
21
+ only the space form is portable). Claude Code additionally reads
21
22
  `when_to_use`, `argument-hint`, `arguments`, `disable-model-invocation`,
22
23
  `user-invocable`, `disallowed-tools`, `model`, `effort`, `context`, `agent`,
23
24
  `background`, `hooks`, `paths`, `shell` — legal, ignored elsewhere, never
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssheleg/make-skill",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Create, retrofit, audit, and ship agent skills & Claude Code plugins the proven ssheleg way — conformance to the Agent Skills open standard (front-matter limits, progressive-disclosure budgets) and the Claude Code plugin reference (manifest schemas, component layout, claude plugin validate --strict), marketplace repo layout, version sync, validator + CI, multi-channel distribution (plugin, vercel skills CLI, npx, Cursor), npm gotchas, and MCP / A2A rules for protocol-connected skills. This package is the installer CLI.",
5
5
  "keywords": [
6
6
  "skill",
@@ -3,7 +3,7 @@
3
3
  "name": "make-skill",
4
4
  "displayName": "Make Skill",
5
5
  "description": "Create, retrofit, audit, and ship agent skills & Claude Code plugins the proven ssheleg way: conformance to the Agent Skills open standard and the Claude Code plugin reference, marketplace repo layout, version sync, validator + CI, multi-channel distribution (plugin, vercel skills CLI, npx, Cursor), npm gotchas, end-to-end first publish, plus MCP / A2A references for protocol-connected skills.",
6
- "version": "0.7.0",
6
+ "version": "0.7.1",
7
7
  "author": {
8
8
  "name": "ssheleg"
9
9
  },
@@ -8,15 +8,15 @@ license: MIT
8
8
 
9
9
  Copy from a working repo (usually `~/DATA/<name>`): **`ssheleg/super-ux`**
10
10
  (multi-skill suite, Cursor rules, templates) or **`ssheleg/task-pipeline`**
11
- (single-skill orchestrator, JSON config-contract + jsonschema in the validator,
12
- release automation). **make-skill itself** is built to this canon.
11
+ (single-skill orchestrator, JSON config-contract, release automation).
12
+ **make-skill itself** is built to this canon.
13
13
 
14
14
  ## References — load on demand
15
15
 
16
16
  | Read | When |
17
17
  |---|---|
18
18
  | `references/agent-skills-spec.md` | authoring or auditing ANY `SKILL.md` — the open standard's hard limits, optional fields, budgets, description-eval loop |
19
- | `references/claude-code-plugin.md` | anything shipping as a **Claude Code plugin/marketplace** — `plugin.json` + `marketplace.json` schemas, component layout, path variables, `claude plugin validate` failures |
19
+ | `references/claude-code-plugin.md` | anything shipping as a **Claude Code plugin/marketplace** — both manifest schemas, component layout, LSP/monitors, path variables, `claude plugin validate` failures |
20
20
  | `references/distribution.md` | publishing, adding a channel, or auditing distribution |
21
21
  | `references/mcp.md` | the skill calls/wraps/documents an **MCP** server, or you're choosing skill vs server |
22
22
  | `references/a2a.md` | the skill spans two autonomous agents (**A2A**): Agent Cards, task lifecycle, delegation |
@@ -42,8 +42,8 @@ detect, ask in one line what to create.
42
42
 
43
43
  Distributable work is a real project: brainstorm → spec
44
44
  (`docs/superpowers/specs/`) → plan → build → validate → publish. The spec locks
45
- target-project file contracts (paths, formats, statuses) FIRST; skills and rules
46
- are written against that contract, never ad hoc.
45
+ target-project file contracts FIRST; skills and rules are written against that
46
+ contract, never ad hoc.
47
47
 
48
48
  ## Authoring rules (every workflow)
49
49
 
@@ -294,12 +294,14 @@ Non-negotiables for any such skill:
294
294
  CLI discovers every one in the tree, so `templates/SKILL.md` lands in every
295
295
  agent as a placeholder (seen live: a skill named `<skill-name>`). Name
296
296
  skeletons `SKILL.template.md`, have the validator reject any `SKILL.md`
297
- outside `plugins/*/skills/*/`, verify with `npx skills add <repo> --list`.
298
- - **Writing the npx installer or the validator?** Four more traps (piped-stdin
299
- readline, raw-mode pickers, ANSI literals, python 3.9 drift) are in
297
+ outside the skill dirs, verify with `npx skills add <repo> --list`. (A
298
+ plugin-root `SKILL.md` is legal in Claude Code alone; multi-channel makes the
299
+ rule.)
300
+ - **Writing the installer or validator?** Four more traps (piped-stdin readline,
301
+ raw-mode pickers, ANSI literals, python 3.9 drift) are in
300
302
  `references/distribution.md` → *Installer implementation traps*.
301
- - **gh auth status may lie** (invalid-token report while git+ssh path
302
- works): attempt the operation before declaring it blocked.
303
+ - **gh auth status may lie** (invalid-token report while git+ssh works): attempt
304
+ the operation before declaring it blocked.
303
305
  - **Duplicate-shadow: one channel per agent — and the shadow regrows.** A plugin
304
306
  install AND a plain `~/.claude/skills/<name>` copy = two listings, and the
305
307
  plain (usually STALE) one wins. Not just `install.sh`: `npx skills
@@ -311,7 +313,8 @@ Non-negotiables for any such skill:
311
313
  <name>@<name>`. Same for install.
312
314
  - **A pinned `version` you forget to bump freezes every user.** The version is
313
315
  the update cache key: twenty commits under `0.6.1` and `/plugin update` still
314
- says "already at the latest version".
316
+ says "already at the latest version". (Omitting `version` from both manifests
317
+ is legal — then the git SHA drives updates. This canon pins and bumps.)
315
318
 
316
319
  ## Release checklist (every version)
317
320
 
@@ -321,7 +324,7 @@ Non-negotiables for any such skill:
321
324
  `claude plugin validate ./plugins/<name> --strict` and
322
325
  `claude plugin validate . --strict` → both exit 0.
323
326
  3. Functional tests: installer against a scratch dir (fresh / rerun-skip /
324
- `--force`), `node --check` on the CLI, pipe-driven menu tests.
327
+ `--force`), `node --check` on the CLI, piped-menu tests.
325
328
  4. Conventional commit; push; confirm CI `success`; tag `v<ver>` + push tag;
326
329
  `gh release create` from the CHANGELOG section (or let the release workflow
327
330
  below do it).
@@ -46,7 +46,9 @@ Notes that bite:
46
46
  block. Adding `license`/`metadata` does not eat the description budget.
47
47
  - `metadata` values are **strings** — quote versions (`version: "1.0"`), or YAML
48
48
  turns `1.0` into a float.
49
- - `allowed-tools` is a single space-separated **string**, not a YAML list.
49
+ - `allowed-tools` is a single space-separated **string**, not a YAML list. Claude
50
+ Code additionally accepts a comma-separated string or a YAML list — write the
51
+ spec form anyway, since it is the only one every host reads.
50
52
  - Nothing in the spec versions a skill. If you want the version visible to agents
51
53
  that never see `plugin.json`, put it in `metadata.version` — then it joins the
52
54
  version-sync rule.
@@ -35,6 +35,12 @@ Both must exit 0. Rules that decide the outcome:
35
35
  - Wrong **types** always fail (`keywords` as a string, not an array).
36
36
  - It runs offline and needs no auth, so it belongs in CI:
37
37
  `npm i -g @anthropic-ai/claude-code && claude plugin validate … --strict`.
38
+ - **It validates the MANIFEST, whatever the docs promise.** The troubleshooting
39
+ table says the command checks "`plugin.json`, skill/agent/command frontmatter,
40
+ and `hooks/hooks.json`"; on 2.1.212 a `SKILL.md` carrying an invented
41
+ front-matter key passed `--strict` untouched, and the output names only the
42
+ manifest it read. Keep front-matter rules in your own validator — this gate
43
+ does not cover them.
38
44
 
39
45
  ## `plugin.json` — `.claude-plugin/plugin.json`
40
46
 
@@ -50,7 +56,7 @@ nothing to validate. **`name` is the only required field.**
50
56
  | `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
57
  | `description`, `author{name,email,url}`, `homepage`, `repository`, `license`, `keywords[]` | | metadata |
52
58
  | `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 |
59
+ | `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
60
  | `commands`, `agents`, `workflows`, `outputStyles` | string\|array | **replace** the default folder. To keep it, list it: `["./commands/", "./extras/"]` |
55
61
  | `hooks`, `mcpServers`, `lspServers` | string\|array\|object | path(s) or inline config; own merge rules |
56
62
  | `experimental.themes`, `experimental.monitors` | string\|array | still moving; top level warns today, will be required under `experimental` |
@@ -106,7 +112,7 @@ marketplace-only `source`, `category`, `tags`, `strict`, `relevance`,
106
112
  | `github` | `{"source":"github","repo":"owner/repo","ref?":"main","sha?":"…"}` |
107
113
  | `url` | `{"source":"url","url":"https://…​.git","ref?":…,"sha?":…}` |
108
114
  | `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 |
115
+ | `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
116
 
111
117
  `sha` beats `ref` when both are set. **Marketplace source ≠ plugin source**: the
112
118
  first says where `marketplace.json` lives (supports `ref` only), the second where
@@ -133,12 +139,17 @@ Version resolution order: `plugin.json` → marketplace entry → git SHA →
133
139
  | MCP | `.mcp.json` |
134
140
  | LSP | `.lsp.json` |
135
141
  | monitors | `monitors/monitors.json` |
142
+ | themes | `themes/*.json` — `base` preset + sparse `overrides` |
136
143
  | executables | `bin/` — on the Bash tool's PATH while enabled |
137
144
  | defaults | `settings.json` (only `agent` and `subagentStatusLine` keys) |
138
145
 
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.
146
+ **Only `plugin.json` goes inside `.claude-plugin/`.** Those are the DEFAULT
147
+ locations, all at the plugin root — a manifest path field may point anywhere
148
+ else inside the plugin (`"commands": ["./specialized/deploy.md"]`), and from
149
+ 2.1.140 Claude Code warns in `claude plugin list` when a manifest key leaves a
150
+ default folder unscanned. What never works is burying components in
151
+ `.claude-plugin/`: they load as nothing while the plugin still "works", which is
152
+ why that one costs an afternoon.
142
153
 
143
154
  A plugin-root `CLAUDE.md` is **not** loaded as context. Ship instructions as a
144
155
  skill.
@@ -151,7 +162,11 @@ string that changes on every update.
151
162
  ## Skill frontmatter — host extensions
152
163
 
153
164
  Portable floor (`name`, `description`, `license`, `compatibility`, `metadata`,
154
- `allowed-tools`) is in `references/agent-skills-spec.md`. Claude Code also reads:
165
+ `allowed-tools`) is in `references/agent-skills-spec.md`. **`allowed-tools` is
166
+ looser here than in the spec**: Claude Code takes a space- OR comma-separated
167
+ string OR a YAML list, the spec takes only the space-separated string. Write the
168
+ spec form — a list works here and breaks everywhere else. Claude Code also
169
+ reads:
155
170
 
156
171
  | Field | Effect |
157
172
  |---|---|
@@ -194,6 +209,39 @@ there.
194
209
  hook's `server` takes `plugin:<plugin>:<server>`. A matcher on the bare server
195
210
  key never fires.
196
211
 
212
+ ## LSP servers and monitors
213
+
214
+ The load condition above promises both; here is the whole of each.
215
+
216
+ **LSP** — `.lsp.json` at the plugin root, or `lspServers` inline. Required per
217
+ server: `command` (binary must be on PATH — the plugin does NOT ship it) and
218
+ `extensionToLanguage`. Optional: `args`, `transport` (`stdio` default or
219
+ `socket`), `env`, `initializationOptions`, `settings`, `workspaceFolder`,
220
+ `startupTimeout`, `shutdownTimeout`, `restartOnCrash` (default `true`),
221
+ `maxRestarts`, `diagnostics` (default `true`). `restartOnCrash` and
222
+ `shutdownTimeout` need CC ≥ 2.1.205 — before that, setting either made Claude
223
+ Code skip the server silently, visible only under `claude --debug`. When two
224
+ enabled servers claim the same extension, the first registered wins and the
225
+ other never starts; an invalid server is skipped and no longer blocks a valid
226
+ one (also 2.1.205).
227
+
228
+ ```json
229
+ { "go": { "command": "gopls", "args": ["serve"],
230
+ "extensionToLanguage": { ".go": "go" } } }
231
+ ```
232
+
233
+ **Monitors** — `monitors/monitors.json`, or `experimental.monitors` inline (a
234
+ path string there loads from a custom location). Array of `{name, command,
235
+ description, when?}`; `when` is `"always"` (default) or
236
+ `"on-skill-invoke:<skill>"`. Each runs as a background process for the session
237
+ and every stdout line reaches Claude as a notification. Interactive CLI only,
238
+ unsandboxed at hook trust level, skipped where the Monitor tool is unavailable,
239
+ and never loaded from a project-scope `@skills-dir` plugin. `${CLAUDE_PLUGIN_ROOT}`,
240
+ `${CLAUDE_PLUGIN_DATA}`, `${CLAUDE_PROJECT_DIR}` and `${ENV_VAR}` substitute;
241
+ `${user_config.*}` is rejected outright (it would reach a shell), and monitor
242
+ processes get no `CLAUDE_PLUGIN_OPTION_*` either — read the value from a config
243
+ file. Disabling a plugin mid-session does not stop a running monitor.
244
+
197
245
  ## Path variables
198
246
 
199
247
  | Variable | Resolves to |
@@ -248,7 +296,7 @@ need `/reload-plugins`. Disable with `claude plugin disable <name>@skills-dir`.
248
296
  | `claude plugin validate <path> [--strict]` | the conformance gate, offline |
249
297
  | `claude plugin init <name> [--with …]` | scaffold a `@skills-dir` plugin |
250
298
  | `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** |
299
+ | `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
300
  | `claude plugin enable\|disable <name>@<marketplace>` | toggle without uninstalling |
253
301
  | `claude plugin uninstall <name>@<marketplace> [--keep-data] [--prune]` | remove (deletes the data dir unless `--keep-data`) |
254
302
  | `claude plugin list [--json]` | installed plugins, versions, source, state |