[FEATURE] Machine-readable hook I/O schemas shipped with the binary (`claude hooks schema --json`)

Open 💬 1 comment Opened Jun 12, 2026 by EfM8caQE9F1v4pFt5x7WrjDI1N2kFqYdydVj

Problem

Hook input/output contracts are documented only on the website, and the docs drift from the binary. Plugin authors discover the real contract by runtime probing, one painful field at a time. Three concrete exhibits from building a telemetry-first Claude Code plugin, all on current versions:

  1. Documented field that does not exist. The hooks doc stated SessionStart input delivers a model field. Runtime-falsified (probe 2026-05-29): the actual SessionStart input key set is cwd, hook_event_name, session_id, source, transcript_path — no model, and no $CLAUDE_MODEL env var either. Any plugin trusting the doc reads undefined forever, silently.
  1. Undocumented shape that breaks parsers. The AskUserQuestion tool_result body shape (Your questions have been answered: "<question>"="<answer>". …) is not documented anywhere. Our telemetry recorded answered_unparseable for 100% of events for two weeks (12/12 live events where the question was asked and answered, 2026-05-28 → 2026-06-11) until we reverse-engineered the shape from transcripts and rewrote the parser against it.
  1. Undocumented semantics that require probe batteries. PreToolUse.updatedInput replace-vs-merge semantics are unspecified. We needed four runtime probes to characterize it on 2.1.172: it replaces wholesale (no per-field merge); omitting required fields fails loudly with schema validation naming the hook (good!); omitted optional fields silently fall to their defaults — including the spawned agent's frontmatter model. All load-bearing facts for any rewrite hook; none documented.

Proposal

Ship the contracts with the binary and make them queryable:

claude hooks schema --json

emitting, per hook event, the input JSONSchema and the accepted output JSONSchema for the installed version — including tool_result shapes for built-in tools that hooks commonly parse (AskUserQuestion at minimum), and explicit semantics annotations where a schema can't express them (e.g. updatedInput: replace).

Benefits:

  • Plugins validate against the binary they actually run under, not against a website snapshot; CI can diff schemas across versions.
  • Doc drift becomes mechanically detectable (docs can be generated from the same source).
  • Changelog entries for schema changes become enforceable ("schema version bumped") instead of best-effort prose.

Environment

  • Claude Code 2.1.172 (CLI), Linux
  • Probe write-ups and the affected parser fix live in a private repo (happy to share specifics on request): the AskUserQuestion parser fix, and the model-router-enforce.sh header documenting the updatedInput characterization.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗