[BUG] v2.1.142 VSCode extension: PostToolUse Bash hook does NOT fire for LLM-initiated Bash tool calls (stream-json mode)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
[Bug] v2.1.142 VSCode extension: PostToolUse Bash hook does NOT fire for LLM-initiated Bash tool calls (stream-json mode)
Environment
- Claude Code VSCode extension: 2.1.142-darwin-arm64 (upgraded from 2.1.141)
- VSCode: 1.120.0 (Electron 39.8.8)
- macOS: Darwin 25.2.0 (Sequoia 14.6+)
- Hardware: Mac Mini ARM (Apple Silicon M-series)
- Mode: stream-json (VSCode native integration default —
--output-format stream-json --input-format stream-json --include-partial-messages --debug --debug-to-stderr) - Permission mode: default
Summary
PostToolUse hook with matcher: "Bash" configured in .claude/settings.json does NOT fire when the LLM (assistant) uses the Bash tool to execute commands. This affects ALL LLM-initiated Bash tool calls, including git commit, ls, cat, grep, etc.
SessionStart and SessionEnd hooks fire correctly. Only PostToolUse specifically does not fire for LLM-initiated tool calls.
Symptoms
- LLM runs
git commit --allow-empty -m "..."via Bash tool → commit succeeds in git history → PostToolUse hook never invoked - Hook command (notify-telegram.sh, /tmp/minimal-hook.sh, anything) never executes
- No error in VSCode Output panel "Claude Code" channel
- Manual invocation of hook script works perfectly (script logic is fine)
100% Reproducer (Minimal)
Step 1: Create minimal hook script
cat > /tmp/minimal-hook.sh <<'EOF'
#!/bin/bash
echo "[$(date +'%H:%M:%S')] MINIMAL_HOOK_FIRED event=${1:-unknown}" >> /tmp/minimal-hook-fired.log
EOF
chmod +x /tmp/minimal-hook.sh
Step 2: Configure .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh post-tool-use-bash",
"timeout": 8
}
]
}
]
}
}
(Note: minimal — no ${CLAUDE_PROJECT_DIR} expansion, no path-with-space, no env var, simplest possible 1-line echo to file)
Step 3: Restart VSCode (to ensure settings.json hot-reload)
Step 4: Have LLM run a Bash command (e.g., git commit --allow-empty -m "test" or any Bash tool call)
Step 5: Check log file
cat /tmp/minimal-hook-fired.log
Expected: Log file contains MINIMAL_HOOK_FIRED event=post-tool-use-bash entry per LLM Bash tool call
Actual: File never created (hook never invoked) → confirms PostToolUse never fires for LLM-initiated tool calls
What Works (SessionStart / SessionEnd)
In the same .claude/settings.json, SessionStart and SessionEnd hooks work correctly:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume|clear|compact",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh session-start",
"timeout": 8
}
]
}
],
"SessionEnd": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh session-end",
"timeout": 8
}
]
}
]
}
}
After Cmd+Q quit + restart VSCode:
- SessionEnd fires for terminated sessions
- SessionStart fires for restarted sessions
- Log file
/tmp/minimal-hook-fired.logcontains entries
Verified via Telegram TOPIC_GOVERNANCE receiving SessionStart/End notifications correctly when hook script also includes curl to Telegram API.
What Does NOT Work (PostToolUse Bash)
In the same setup, PostToolUse Bash hook does NOT fire:
- 4 empty
git commitcalls via LLM Bash tool: 5d78718 / 992d924 / 8f8904a / c6f223a - None triggered the hook (log file not created)
- Verified across multiple session restarts (PID 9525 / 9709 / 11264 etc., all v2.1.142)
Related Output panel logs (no error visible)
[DEBUG] Registered 0 hooks from 0 plugins ← plugin hooks (irrelevant, we use project hooks)
[WARN] [3P telemetry] Event dropped (no event logger initialized): hook_registered ← hooks ARE registered
[DEBUG] Watching for changes in setting files /Users/.../.claude/settings.json
No Hook fire / PostToolUse invoked log visible.
Suspected Root Causes (speculation)
- v2.1.142 stream-json mode IPC path may not invoke PostToolUse hook for tool calls from LLM (only invokes for human-typed Bash commands via slash commands)
- Hook event firing pathway in v2.1.142 may have regression for
Bashtool specifically (other tool matchers untested) - Race condition / timing issue with stream-json
--include-partial-messagesflag (default in VSCode integration)
Workaround
None functional. Currently rely on SessionStart + SessionEnd hooks for session lifecycle audit, plus .githooks/pre-commit (git native, fires for ALL commits including LLM-initiated) for syntax check and commit audit fallback.
Severity
Medium — does not block development but breaks audit/observability hooks for LLM-initiated tool calls (especially git commit notifications, command logging, etc.). PostToolUse is documented as firing for ALL tool calls including built-in tools.
Reference
- Local project sink:
/Users/danielfu/Documents/Ai Project/DevPlan/LESSONS_LEARNED.mdLL-012 Case 21 - Local project commit:
60a8773 docs(infra+lessons): W1-D9 morning ... LL-004 cumulative 18→21 - Confirmed via
claude-code-guideagent: matcher "Bash" is correct, PostToolUse should fire for all tool calls per docs, no--include-hook-events/disableAllHookssetting active
What Should Happen?
Claude code should fix this issue which PostToolUse Bash hook should fire for LLM-initiated Bash tool calls (stream-json mode).
Error Messages/Logs
Steps to Reproduce
100% Reproducer (Minimal)
Step 1: Create minimal hook script
cat > /tmp/minimal-hook.sh <<'EOF'
#!/bin/bash
echo "[$(date +'%H:%M:%S')] MINIMAL_HOOK_FIRED event=${1:-unknown}" >> /tmp/minimal-hook-fired.log
EOF
chmod +x /tmp/minimal-hook.sh
Step 2: Configure .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh post-tool-use-bash",
"timeout": 8
}
]
}
]
}
}
(Note: minimal — no ${CLAUDE_PROJECT_DIR} expansion, no path-with-space, no env var, simplest possible 1-line echo to file)
Step 3: Restart VSCode (to ensure settings.json hot-reload)
Step 4: Have LLM run a Bash command (e.g., git commit --allow-empty -m "test" or any Bash tool call)
Step 5: Check log file
cat /tmp/minimal-hook-fired.log
Expected: Log file contains MINIMAL_HOOK_FIRED event=post-tool-use-bash entry per LLM Bash tool call
Actual: File never created (hook never invoked) → confirms PostToolUse never fires for LLM-initiated tool calls
What Works (SessionStart / SessionEnd)
In the same .claude/settings.json, SessionStart and SessionEnd hooks work correctly:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume|clear|compact",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh session-start",
"timeout": 8
}
]
}
],
"SessionEnd": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "/tmp/minimal-hook.sh session-end",
"timeout": 8
}
]
}
]
}
}
After Cmd+Q quit + restart VSCode:
- SessionEnd fires for terminated sessions
- SessionStart fires for restarted sessions
- Log file
/tmp/minimal-hook-fired.logcontains entries
Verified via Telegram TOPIC_GOVERNANCE receiving SessionStart/End notifications correctly when hook script also includes curl to Telegram API.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.142 (Claude code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗