Skip to content

fix(claude): re-pin hooks.schema.json to the documented handler contract; track sub-agents frontmatter drift in agents capability rows - #496

Merged
ScriptedAlchemy merged 3 commits into
mainfrom
fix/claude-hooks-schema-and-agents-capabilities
Sep 4, 2026
Merged

fix(claude): re-pin hooks.schema.json to the documented handler contract; track sub-agents frontmatter drift in agents capability rows#496
ScriptedAlchemy merged 3 commits into
mainfrom
fix/claude-hooks-schema-and-agents-capabilities

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Fixes #477, Fixes #478

#477hooks.schema.json re-pinned to the documented handler contract

packages/agent-bundle/src/adapters/schemas/claude/hooks.schema.json previously admitted one shape: a shell-form command handler with command and timeout, under an open hooks map. It now encodes the hooks reference (uploaded hooks-2.md):

  • Handler types ("Hook handler fields"): command, http, mcp_tool, prompt, agent, each a closed $defs entry.
  • Common fields ("Common fields"): if, once, statusMessage, timeout (integer ≥ 1) on every type.
  • Per-type fields: commandcommand (required), args (exec form, "Exec form and shell form"), async, asyncRewake, shell (bash | powershell) ("Command hook fields", "Run hooks in the background"); httpurl (required), headers, allowedEnvVars ("HTTP hook fields"); mcp_toolserver, tool (required), input ("MCP tool hook fields"); promptprompt (required), model, continueOnBlock; agentprompt (required), model, no continueOnBlock ("Prompt and agent hook fields", "Agent hook configuration").
  • Events ("Hook events", "Prompt-based hooks"): the hooks map is closed to the 31 documented events the pinned 2.1.250 host knows. 13 admit all five types, 16 admit command/http/mcp_tool, and SessionStart / Setup admit command/mcp_tool only. PreModelSwitch and PostModelSwitch "require Claude Code v2.1.251 or later" (hooks-2.md › "PreModelSwitch" / "PostModelSwitch") and 2.1.250 --strict rejects both keys, so they stay out of the pin until observedCliVersion moves past 2.1.251.
  • additionalProperties: false is kept at every level (document, matcher group, handler).

readStandardNativeHookCommands (hook-contract.ts) now skips non-command handlers instead of treating the whole native document as invalid, so an authored claude.nativeHooks document using the wider contract plans without a diagnostic. The Claude adapterRevision is bumped 1.25.0 → 1.26.0; PROVENANCE.json records the new pin (sha256 70cd71b4…, 7229 bytes) and a hooksSchemaNotes entry.

Fixtures and CLI agreement

packages/agent-bundle/tests/fixtures/claude-hooks-schema/ holds 52 hooks.json cases and, for each, the claude plugin validate --strict report 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 by scripts/record-claude-hooks-schema-fixtures.mjs (CLAUDE_BIN selects a scratch-installed pin). tests/claude-hooks-schema.test.ts requires the PROVENANCE.json observedCliVersion directory to be present and asserts, for every recorded version:

  • Schema verdict == CLI verdict on every case except the listed tightenings: full.json (every type and field) and all-pinned-events.json (all 31 events) are accepted by both CLIs; an unknown event, unknown handler type, missing type, each missing required field, and each wrong-typed field are rejected by both.
  • The two CLIs disagree on exactly one case, model-switch-events.json: rejected by 2.1.250 and the schema, accepted by 2.1.260 (the "newer than pin" category).
  • Deliberate tightenings where the schema rejects and 2.1.260 --strict silently accepts (documented in PROVENANCE.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 unknown hooks.json keys without a warning); a field of another handler type (args on http, continueOnBlock on agent, url on command, …); prompt/agent/http handlers on events the reference excludes them from; empty command/server/tool/prompt/url; fractional timeout; an empty group hooks array.
  • Per-event handler partitions, required fields, and field typing.
  • The plan-level end-to-end: a Claude plugin with a nativeHooks document using every handler type builds cleanly and emits it verbatim.

Not changed here (follow-ups)

The compiler still emits shell-form command handlers with type/command/timeout only. The reference recommends exec form (args) for ${CLAUDE_PLUGIN_ROOT} paths, and async, statusMessage, and if could all improve generated hooks; those are separate emission increments. The undocumented top-level modules key 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"):

  • New plugin.agents rows color, initialPrompt, experimentalCacheTtl — all unavailable behind the Compile capability-aware host component bundles #100 stage-2 G5 gate, with the uploaded-doc evidence.
  • hooks, mcpServers, permissionMode rows: 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.
  • name row: colon reserved for plugin-scoped identifiers (not loaded since 2.1.218), delivered to hooks as agent_type.
  • New hooks.agentTypeMatcher block: field: agent_type, template ^<plugin-name>:<agent-name>$, with the anchoring rationale (a colon puts the matcher on the unanchored regex path).
  • New hooks.handlerContract block recording the five types, common/per-type fields, and what the compiler emits vs passes through.
  • hooks.features.timeout / toolMatchers evidence updated for the wider schema.

The agents component itself stays deferred. adapter-capability-states.test.ts pins the new rows and the matcher note (evidence prefix now admits uploaded 2026-09-03: alongside retrieved 2026-09-02:). The generated hosts reference page follows from the JSON; website/docs/{en,zh}/guide/authoring/index.mdx gain a sentence on the wider nativeHooks contract.

Verification

pnpm typecheck, pnpm lint, pnpm test:unit (full), pnpm docs:site:build all pass locally.

Review status

  • Codex reviewed d7111a4 (PR opened) and raised one P2 on PROVENANCE.json: the schema was cross-checked only against 2.1.260 while the pin is 2.1.250. Addressed in f3c1271: fixtures are now recorded against the pinned 2.1.250 as well (scratch npm install @anthropic-ai/claude-code@2.1.250), the test demands the pinned version's reports, and the one real divergence that surfaced — PreModelSwitch/PostModelSwitch are 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.
  • Unreviewed head at merge time (if no fresh Codex review lands): f3c1271a8. Intermediate 14f7fea only changed the changeset's PR number.

…act and track the sub-agents frontmatter drift in the agents capability rows

Fixes #477, Fixes #478
@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f3c1271

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Patch

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T01:03:56.216866Z d7111a4 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/agent-bundle/src/adapters/schemas/claude/PROVENANCE.json Outdated
@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@496
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@496
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@496

commit: f3c1271

…CLI too; omit the 2.1.251 model-switch events until the re-pin
@ScriptedAlchemy
ScriptedAlchemy merged commit 853c31a into main Sep 4, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment