PreToolUse/PostToolUse hook events not emitted in stream-json output
Description
When using --output-format stream-json (including via --permission-prompt-tool stdio / the Python SDK), SessionStart and Stop hooks emit hook_started and hook_response system messages in the stream. However, PreToolUse and PostToolUse hooks do not emit these messages, even though the hooks execute successfully (their side effects are observable).
Steps to Reproduce
- Configure a PreToolUse hook in
~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read",
"hooks": [
{
"type": "command",
"command": "date '+Hook fired: %Y-%m-%d %H:%M:%S'"
}
]
}
]
}
}
- Start Claude Code with stream-json output:
claude --output-format stream-json --permission-prompt-tool stdio
- Ask Claude to use the Read tool.
- Observe the stream-json messages — no
hook_startedorhook_responsesystem messages appear for the PreToolUse:Read hook.
- For comparison,
SessionStarthooks do produce these messages:
{"type": "system", "subtype": "hook_started", "hook_id": "...", "hook_name": "SessionStart:startup", "hook_event": "SessionStart"}
{"type": "system", "subtype": "hook_response", "hook_id": "...", "hook_name": "SessionStart:startup", "outcome": "success", "output": "...", "exit_code": 0}
Expected Behavior
All hook lifecycle events (SessionStart, Stop, PreToolUse, PostToolUse, etc.) should emit hook_started/hook_response system messages in the stream-json output, so SDK consumers can observe hook execution.
Actual Behavior
Only SessionStart and Stop hooks emit these messages. PreToolUse and PostToolUse hooks execute silently — their side effects work, but no messages appear in the stream.
Environment
- Claude Code version: 2.1.44
- Platform: Linux (NixOS)
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗