Problem
packages/agent-bundle/src/adapters/schemas/claude/hooks.schema.json (pinned at 2.1.250, PROVENANCE.json says it is a direct pin of https://code.claude.com/docs/en/hooks) accepts only:
- handler:
{ type: "command", command, timeout } with additionalProperties: false
- matcher group:
{ matcher, hooks } with additionalProperties: false
The current hooks reference documents considerably more for the same hooks/hooks.json document:
hooks-2.md → Configuration › Hook handler fields › Common fields (L423–433): if, statusMessage, once on every handler type.
hooks-2.md → Command hook fields (L453–462) and Exec form and shell form (L464–): args (exec form, recommended whenever the command references a path placeholder such as ${CLAUDE_PLUGIN_ROOT}), async, asyncRewake, shell.
hooks-2.md → Hook handler fields (L407–413): five handler types — command, http, mcp_tool, prompt, agent — with their own field tables (HTTP hook fields L508, Prompt and agent hook fields L583).
Reproduced on this machine: a hooks/hooks.json using args, async, if, and statusMessage passes claude plugin validate .claude-plugin/plugin.json --strict on Claude Code 2.1.259 (✔ Validation passed), while validateClaudePluginFiles rejects it four times with AB6012 … must NOT have additional properties.
Why it matters
- The compiler itself emits only shell-form
command hooks with command/timeout, so today's emitted bundles are not affected. But the pinned schema is presented (docs/diagnostics.md AB6011/AB6012, capability plugin.devtools) as the Claude hooks contract, and doctor (AB7320) applies it to installed copies — including ones Claude itself accepted.
- The reference explicitly recommends exec form (
args) for path-placeholder commands, which is exactly how the emitted hooks reference ${CLAUDE_PLUGIN_ROOT}/hooks/*.mjs. Adopting exec form is blocked by the pin.
- The
hooks capability JSON (plugin.hooks.features) has no rows for args/async/if/once/statusMessage, http/mcp_tool/prompt/agent handler types, so the generated hosts/events pages cannot say whether the compiler supports them.
Proposed
At the next Claude CLI re-pin (the PROVENANCE.json notes already require a deliberate re-pin): widen hooks.schema.json to the documented handler union (or at least the command-hook field set) and add capability rows stating which of those fields the compiler emits versus passes through. Keep additionalProperties: false so genuinely unknown keys still fail (Claude only warns on them).
Related
Problem
packages/agent-bundle/src/adapters/schemas/claude/hooks.schema.json(pinned at 2.1.250,PROVENANCE.jsonsays it is a direct pin ofhttps://code.claude.com/docs/en/hooks) accepts only:{ type: "command", command, timeout }withadditionalProperties: false{ matcher, hooks }withadditionalProperties: falseThe current hooks reference documents considerably more for the same
hooks/hooks.jsondocument:hooks-2.md→ Configuration › Hook handler fields › Common fields (L423–433):if,statusMessage,onceon every handler type.hooks-2.md→ Command hook fields (L453–462) and Exec form and shell form (L464–):args(exec form, recommended whenever the command references a path placeholder such as${CLAUDE_PLUGIN_ROOT}),async,asyncRewake,shell.hooks-2.md→ Hook handler fields (L407–413): five handler types —command,http,mcp_tool,prompt,agent— with their own field tables (HTTP hook fields L508, Prompt and agent hook fields L583).Reproduced on this machine: a
hooks/hooks.jsonusingargs,async,if, andstatusMessagepassesclaude plugin validate .claude-plugin/plugin.json --stricton Claude Code 2.1.259 (✔ Validation passed), whilevalidateClaudePluginFilesrejects it four times withAB6012 … must NOT have additional properties.Why it matters
commandhooks withcommand/timeout, so today's emitted bundles are not affected. But the pinned schema is presented (docs/diagnostics.mdAB6011/AB6012, capabilityplugin.devtools) as the Claude hooks contract, anddoctor(AB7320) applies it to installed copies — including ones Claude itself accepted.args) for path-placeholder commands, which is exactly how the emitted hooks reference${CLAUDE_PLUGIN_ROOT}/hooks/*.mjs. Adopting exec form is blocked by the pin.hookscapability JSON (plugin.hooks.features) has no rows forargs/async/if/once/statusMessage,http/mcp_tool/prompt/agenthandler types, so the generated hosts/events pages cannot say whether the compiler supports them.Proposed
At the next Claude CLI re-pin (the
PROVENANCE.jsonnotes already require a deliberate re-pin): widenhooks.schema.jsonto the documented handler union (or at least the command-hook field set) and add capability rows stating which of those fields the compiler emits versus passes through. KeepadditionalProperties: falseso genuinely unknown keys still fail (Claude only warns on them).Related
hooks/hooks.jsonthrough Claude itself, which is the authoritative fallback until the pin catches up).