fix(plugin): name only claude-code.json in the Claude Code manifest hooks field - #14
Merged
Merged
Conversation
…ooks field
Claude Code loads hooks/hooks.json automatically and reads manifest.hooks as
additional files only. Listing the default file too makes every marketplace
install fail to load ("Duplicate hooks file detected", Claude Code 2.1.270,
reproduced on the 0.4.0 and 0.5.0 installs), taking the hooks, the MCP server
and the skill down with it, while `--plugin-dir`, `plugin details` and
`plugin validate` accept the same tree silently. The test now pins the single
string and the reason; the Codex manifest keeps naming hooks/hooks.json, as
Codex documents no auto-load.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…stack-traps The README hooks section and the stack-traps reference said the Claude Code manifest named both hook files; it now names one, and the new `#hooks-manifest-duplicate` entry gives the symptom, the loader rule, the observed Claude Code version and the scratch-marketplace check that reproduces an install where `--plugin-dir` cannot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hooks/claude-code.json becomes hooks/worktree-remove.json. hooks.json is the name both loaders claim by default, and the trap fixed in the previous commit came from naming that default in the manifest; a second generic name beside it is the kind a loader could claim next. Every file other than hooks.json now holds exactly one event not every harness knows and is named after it, and the test enforces the stem. The manifest test also records why the two manifests differ: Claude Code adds the field's files to the auto-loaded hooks.json, Codex replaces default discovery with the field. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…' field semantics README, AGENTS.md, the drift-tests table and the stack-traps entry now name hooks/worktree-remove.json, state the one-file-per-non-portable-event rule with its reason, and record that Codex's `hooks` field replaces default discovery where Claude Code's adds to it, so no single manifest value serves both. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
claude plugin install colgrep-mcp@cracking-shells(0.5.0, Claude Code 2.1.270) fails to load:Claude Code auto-loads
hooks/hooks.jsonand readsmanifest.hooksas additional files only (the plugins reference documents the field with the example./my-extra-hooks.json). Codex reads the same field the other way round: it discovershooks/hooks.jsononly when the manifest defines nohooks, and an explicit value replaces that discovery. The manifest listed both files since 0.4.0, so every marketplace install of 0.4.0 and 0.5.0 loses the hooks, the MCP server and the skill at once.claude --plugin-dir .,plugin detailsandplugin validatedo not run the duplicate check, which is why the tree-level gates stayed green.What
.claude-plugin/plugin.json:hooksbecomes the single string./hooks/worktree-remove.json. The Codex manifest keeps./hooks/hooks.json.hooks/claude-code.jsonis renamedhooks/worktree-remove.json:hooks.jsonis the name both loaders claim by default, and a second generic name beside it is the kind a loader could claim next. Rule: every file other thanhooks.jsonholds exactly one event not every harness knows and is named after it.server/tests/test_hooks.py: enforces the per-event file stem, that the Claude Code manifest names exactly the extra files and neverhooks.json, and that the Codex manifest nameshooks.json.README.md,AGENTS.md,dev/skills/stack-traps(new#hooks-manifest-duplicateentry with the two loaders' semantics and the scratch-marketplace check) and the drift-tests table follow.Verified by installing the tree through a scratch directory marketplace:
claude plugin listshows✔ enabledandplugin detailslists all four hooks (SessionStart, SubagentStart, PreToolUse, WorktreeRemove).A patch release (0.5.1) is what puts a loadable manifest in front of marketplace users.
Gates
pytest, ruff check, ruff format --check,
cz check --rev-range main..HEAD,claude plugin validate .and./dev: green locally; CI on the PR.🤖 Generated with Claude Code