fix(claude): re-pin hooks.schema.json to the documented handler contract; track sub-agents frontmatter drift in agents capability rows - #496
Conversation
🦋 Changeset detectedLatest commit: f3c1271 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d7111a4bf9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
commit: |
…CLI too; omit the 2.1.251 model-switch events until the re-pin
Fixes #477, Fixes #478
#477 —
hooks.schema.jsonre-pinned to the documented handler contractpackages/agent-bundle/src/adapters/schemas/claude/hooks.schema.jsonpreviously admitted one shape: a shell-formcommandhandler withcommandandtimeout, under an openhooksmap. It now encodes the hooks reference (uploadedhooks-2.md):"Hook handler fields"):command,http,mcp_tool,prompt,agent, each a closed$defsentry."Common fields"):if,once,statusMessage,timeout(integer ≥ 1) on every type.command—command(required),args(exec form,"Exec form and shell form"),async,asyncRewake,shell(bash|powershell) ("Command hook fields","Run hooks in the background");http—url(required),headers,allowedEnvVars("HTTP hook fields");mcp_tool—server,tool(required),input("MCP tool hook fields");prompt—prompt(required),model,continueOnBlock;agent—prompt(required),model, nocontinueOnBlock("Prompt and agent hook fields","Agent hook configuration")."Hook events","Prompt-based hooks"): thehooksmap is closed to the 31 documented events the pinned 2.1.250 host knows. 13 admit all five types, 16 admitcommand/http/mcp_tool, andSessionStart/Setupadmitcommand/mcp_toolonly.PreModelSwitchandPostModelSwitch"require Claude Code v2.1.251 or later" (hooks-2.md› "PreModelSwitch" / "PostModelSwitch") and 2.1.250--strictrejects both keys, so they stay out of the pin untilobservedCliVersionmoves past 2.1.251.additionalProperties: falseis kept at every level (document, matcher group, handler).readStandardNativeHookCommands(hook-contract.ts) now skips non-commandhandlers instead of treating the whole native document as invalid, so an authoredclaude.nativeHooksdocument using the wider contract plans without a diagnostic. The ClaudeadapterRevisionis bumped1.25.0 → 1.26.0;PROVENANCE.jsonrecords the new pin (sha256 70cd71b4…, 7229 bytes) and ahooksSchemaNotesentry.Fixtures and CLI agreement
packages/agent-bundle/tests/fixtures/claude-hooks-schema/holds 52hooks.jsoncases and, for each, theclaude plugin validate --strictreport from the pinned Claude Code 2.1.250 (which has no--json; its text reporter is parsed into the same report shape, marked"reporter": "text") and from 2.1.260 (--strict --json), recorded byscripts/record-claude-hooks-schema-fixtures.mjs(CLAUDE_BINselects a scratch-installed pin).tests/claude-hooks-schema.test.tsrequires thePROVENANCE.jsonobservedCliVersiondirectory to be present and asserts, for every recorded version:full.json(every type and field) andall-pinned-events.json(all 31 events) are accepted by both CLIs; an unknown event, unknown handler type, missingtype, each missing required field, and each wrong-typed field are rejected by both.model-switch-events.json: rejected by 2.1.250 and the schema, accepted by 2.1.260 (the "newer than pin" category).--strictsilently accepts (documented inPROVENANCE.json): unknown keys on the document/group/handler (plugins-reference-1.md› "plugin validate" documents unrecognized fields as warnings promoted by--strict, but the CLI ignores unknownhooks.jsonkeys without a warning); a field of another handler type (argsonhttp,continueOnBlockonagent,urloncommand, …);prompt/agent/httphandlers on events the reference excludes them from; emptycommand/server/tool/prompt/url; fractionaltimeout; an empty grouphooksarray.nativeHooksdocument using every handler type builds cleanly and emits it verbatim.Not changed here (follow-ups)
The compiler still emits shell-form
commandhandlers withtype/command/timeoutonly. The reference recommends exec form (args) for${CLAUDE_PLUGIN_ROOT}paths, andasync,statusMessage, andifcould all improve generated hooks; those are separate emission increments. The undocumented top-levelmoduleskey the 2.1.260 validator mentions is not admitted.#478 — agents capability rows track the sub-agents contract
packages/agent-bundle/src/adapters/capabilities/claude-2.1.250.json(sub-agents-3.md› "Supported frontmatter fields", "Project-level hooks for subagent events";hooks-2.md› "Matcher patterns", "SubagentStart"):plugin.agentsrowscolor,initialPrompt,experimentalCacheTtl— allunavailablebehind the Compile capability-aware host component bundles #100 stage-2 G5 gate, with the uploaded-doc evidence.hooks,mcpServers,permissionModerows: reason now states the field is "Ignored for plugin subagents" and that a re-admitted component must reject it with a diagnostic rather than emit a silently dropped field.namerow: colon reserved for plugin-scoped identifiers (not loaded since 2.1.218), delivered to hooks asagent_type.hooks.agentTypeMatcherblock:field: agent_type, template^<plugin-name>:<agent-name>$, with the anchoring rationale (a colon puts the matcher on the unanchored regex path).hooks.handlerContractblock recording the five types, common/per-type fields, and what the compiler emits vs passes through.hooks.features.timeout/toolMatchersevidence updated for the wider schema.The agents component itself stays deferred.
adapter-capability-states.test.tspins the new rows and the matcher note (evidence prefix now admitsuploaded 2026-09-03:alongsideretrieved 2026-09-02:). The generated hosts reference page follows from the JSON;website/docs/{en,zh}/guide/authoring/index.mdxgain a sentence on the widernativeHookscontract.Verification
pnpm typecheck,pnpm lint,pnpm test:unit(full),pnpm docs:site:buildall pass locally.Review status
d7111a4(PR opened) and raised one P2 onPROVENANCE.json: the schema was cross-checked only against 2.1.260 while the pin is 2.1.250. Addressed inf3c1271: fixtures are now recorded against the pinned 2.1.250 as well (scratchnpm install @anthropic-ai/claude-code@2.1.250), the test demands the pinned version's reports, and the one real divergence that surfaced —PreModelSwitch/PostModelSwitchare 2.1.251+ — is removed from the schema and recorded as a re-pin follow-up. The thread is resolved with this note rather than a reply, per the maintainer's no-PR-comments instruction for this work.f3c1271a8. Intermediate14f7feaonly changed the changeset's PR number.