Hook documentation is misleading — Stop hooks broken, prompt hooks can't inject context, capabilities undocumented per event type
Summary
After 3+ sessions (approx 15 hours) trying to implement hooks for enforcing behavior in Claude Code, we've found the documentation to be misleading and several hook types to be non-functional. We're filing this as constructive feedback — we'd love to be corrected if we're doing something wrong, but our testing has been thorough and the results are clear.
Environment
- Claude Code v2.1.81, Windows 11
- Tested with Opus, Sonnet, and Haiku models
- Both interactive and
-p(print) modes
Issue 1: Stop hooks don't work (JSON validation errors)
What we tried:
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "prompt",
"model": "sonnet",
"prompt": "Evaluate if Claude should stop. Has it completed everything the user asked?"
}]
}]
}
}
What happened: Persistent "JSON validation failed" errors across 3 sessions, regardless of:
- Using
model: "sonnet"vsmodel: "haiku" - Natural language prompts vs structured prompts
- Various JSON output format instructions
Related issues: #11947, #11786, #11610 — these appear to still be unresolved as of v2.1.81.
Issue 2: type: "prompt" hooks on UserPromptSubmit can only block — they cannot inject context
What the docs suggest: That prompt hooks evaluate user input and can influence behavior.
What actually happens: A type: "prompt" hook on UserPromptSubmit can only return {"ok": true} (allow) or {"ok": false, "reason": "..."} (block the prompt entirely). When ok: false, the user sees the reason and Claude never sees the prompt at all.
What we expected: The ability to inject context or modify the prompt, similar to what type: "command" hooks can do with additionalContext or replacementPrompt.
This limitation is not documented anywhere. The docs don't distinguish which output fields are available per hook type per event type. We spent hours trying to get prompt hooks to inject context before discovering through trial and error that only type: "command" hooks support additionalContext and replacementPrompt.
Issue 3: No hooks fire in -p (print/non-interactive) mode
Test: We deployed a "block all prompts" hook:
{
"type": "prompt",
"prompt": "Always return {\"ok\": false, \"reason\": \"All prompts blocked\"}."
}
Result: claude -p "What is 2+2?" returned "4" — the hook never fired. This makes automated testing of hooks impossible without interactive sessions.
This is not documented.
Issue 4: Documentation doesn't distinguish capabilities per hook type per event
The hooks documentation at https://code.claude.com/docs/en/hooks presents all hook types (command, prompt, agent) and all events (UserPromptSubmit, Stop, PreToolUse, etc.) but doesn't clearly document:
- Which output fields work with which hook type (e.g.,
additionalContextonly works withtype: "command", nottype: "prompt") - Which hook types work with which events (e.g., Stop + prompt = broken)
- What
ok: falsedoes per event type (UserPromptSubmit blocks the prompt; Stop feeds reason back to Claude — very different behaviors) - Which modes support hooks (
-pmode skips them entirely)
What we'd like
- A capability matrix in the docs: hook type × event type × available output fields
- Fix or remove Stop hooks — if they don't work, document that clearly rather than leaving users to discover it through hours of debugging
- Document
-pmode hook behavior — even a one-liner saying "hooks don't fire in print mode" would save significant time - Consider adding
replacementPromptsupport to prompt hooks — currently only command hooks can modify prompts, which requires writing a script. Prompt hooks being limited to yes/no gatekeeping severely limits their utility.
Our workaround
We use a type: "command" Python script on UserPromptSubmit that injects behavioral rules via additionalContext. This works but is essentially "persuasion" — Claude sees the rules but can choose to ignore them, especially at large context sizes. We'd prefer actual enforcement hooks but the current implementation doesn't support this reliably.
Acknowledgment
We appreciate Claude Code — it's genuinely powerful and we use it extensively across 10+ projects. This feedback comes from wanting it to be better, not from frustration alone. Happy to provide logs, test scripts, or further details if helpful.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗