PostToolUse hooks do not fire in daemon/background-job sessions (PreToolUse + SessionStart do) — v2.1.208

Open 💬 0 comments Opened Jul 14, 2026 by HiCraigChen

Summary

In a daemon-backed background session (Claude Code's background-job / daemon backend — "backend": "daemon" in the job state, cliVersion 2.1.208), PostToolUse hooks configured in settings.json never fire. PreToolUse and SessionStart hooks from the same settings.json fire normally in the same session, and the identical PostToolUse hooks fire correctly in an interactive session.

The hooks reference documents PostToolUse as running after every successful tool call, with no execution-mode caveat — so this appears to contradict documented behavior.

Environment

  • Claude Code 2.1.208
  • Linux (Ubuntu)
  • Session backend: daemon (the background-job feature; job state.json has "backend": "daemon", "template": "claude")
  • Hooks defined in the user settings.json (symlinked, shared with interactive sessions)

Repro

  1. In settings.json, register a PostToolUse hook with a Bash matcher that appends a marker, e.g.:

``json
{ "hooks": { "PostToolUse": [ { "matcher": "Bash",
"hooks": [ { "type": "command", "command": "echo fired >> /tmp/posttooluse-marker" } ] } ] } }
``

  1. Start a background/daemon session and run any Bash tool call.
  2. Observed: /tmp/posttooluse-marker is never written; the hook does not run.
  3. Run the same tool call in an interactive session → the marker is written.
  4. Feed the hook script its JSON payload manually (echo "$payload" | hook.sh) → it works. The hook script itself is healthy; it is simply never invoked in the daemon session.

Evidence from a real session

  • A PostToolUse hook that appends to ~/.claude/logs/hook-events.jsonl on every Bash/Edit recorded zero new rows across ~30 minutes and dozens of Bash tool calls in a daemon session; its last row predates the session's tool activity entirely.
  • PreToolUse dispatcher hooks (and SessionStart context injection) from the same settings.json fired throughout that same session normally.
  • Confirmed by an independent controlled repro (hook healthy on manual payload; never fired in the background session; PreToolUse fired).

Impact

Any guardrail that relies on PostToolUse is silently bypassed in background/daemon sessions — auto-formatters, post-write secret scanners, telemetry/event logging, doc-regeneration, and (our case) a git worktree add auto-normalizer. Because PreToolUse still fires, the failure is easy to miss.

Not a duplicate of

  • #73586 — MCP tool calls only; this is native Bash.
  • #68970 — Windows ~1.2% trigger rate; this is Linux, 0% for PostToolUse specifically, 100% for PreToolUse.
  • #69519 — path-join bug for edits outside CWD; unrelated.
  • #6305 — reports both Pre and Post not executing; here PreToolUse/SessionStart fire and only PostToolUse is dropped, specifically in the daemon backend.

Question

Is PostToolUse intentionally suppressed in the daemon/background execution mode? If intended, please document the mode caveat; if not, PostToolUse delivery is broken for background sessions and every PostToolUse-based guardrail is unreliable there.

View original on GitHub ↗