Hooks docs: four payload field divergences vs shipped behavior (2.1.207, captured)

Open 💬 0 comments Opened Jul 13, 2026 by cameronsjo

Summary

Four divergences between the hooks reference documentation and the payloads Claude Code actually delivers, all captured live on v2.1.207 (macOS) with a minimal probe: a project whose .claude/settings.local.json defines hooks that tee stdin to a file, driven by headless claude -p sessions.

Observed vs documented

| Event | Documented | Observed (captured payload) |
|---|---|---|
| PostToolUse | tool_output | tool_response (object) |
| SessionEnd | end_reason | reason |
| UserPromptSubmit | user_prompt | prompt |
| SessionStart | (common-fields table can read as if permission_mode is universal) | no permission_mode on SessionStart; present on UserPromptSubmit / PreToolUse / Stop |

On the fourth row: the current docs do say "Not all events receive this field," which is accurate — the ask is just to make each event's example JSON authoritative and complete, since a hook gating on a field its event never receives fails silently (empty var → the false branch, forever, with no error surface).

Suggested fix

Align the per-event example payloads in the hooks reference with the shipped field names above, and consider noting per event whether permission_mode is delivered.

Raw captured payloads available on request — they're single-line JSON files produced by the tee probe described above, trivially reproducible on any machine.

View original on GitHub ↗