[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:
- Documented field that does not exist. The hooks doc stated SessionStart input delivers a
modelfield. Runtime-falsified (probe 2026-05-29): the actual SessionStart input key set iscwd, hook_event_name, session_id, source, transcript_path— nomodel, and no$CLAUDE_MODELenv var either. Any plugin trusting the doc readsundefinedforever, silently.
- Undocumented shape that breaks parsers. The
AskUserQuestiontool_result body shape (Your questions have been answered: "<question>"="<answer>". …) is not documented anywhere. Our telemetry recordedanswered_unparseablefor 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.
- Undocumented semantics that require probe batteries.
PreToolUse.updatedInputreplace-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 frontmattermodel. 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.shheader documenting theupdatedInputcharacterization.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗