CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
PostToolUse Fires Even When the Model Won't: Add Deterministic Side-Effects to Every Claude Code Session

PostToolUse Fires Even When the Model Won't: Add Deterministic Side-Effects to Every Claude Code Session

Chris Harper

2 min read

Aug 3, 2026 · 12:07 UTC

AI
Workflow
Claude Code
Best Practices

Claude Code's PostToolUse hook fires after every tool call whether or not the model decides to — use it to build auto-format, checkpoint commits, and test runs that happen deterministically, outside model control.

The critical property of Claude Code hooks is that they run outside the model's decision loop. When PostToolUse fires after a Write call, the model can't skip it, defer it, or decide it's unnecessary. That gap between "the model might do X" and "X will always happen" is the key to building reliable Claude Code workflows in production.

How the hook receives its input

Every hook gets a JSON payload on stdin. For PostToolUse after a Write, the relevant fields are tool_input.path (the file just written) and tool_response (the tool's result). Use that path to trigger follow-on work:

#!/usr/bin/env bash
# .claude/hooks/auto-format.sh
set -euo pipefail
input="$(cat)"
fp="$(printf '%s' "$input" | node -e   'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{
    try{const j=JSON.parse(s);const ti=j.tool_input||{};
    process.stdout.write(ti.path||ti.file_path||"")}catch{process.stdout.write("")}
  })')"
[ -z "$fp" ] && exit 0
npx prettier --write "$fp" 2>&1 || true

Wire it up in .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [{ "type": "command", "command": ".claude/hooks/auto-format.sh" }]
      }
    ]
  }
}

Patterns that become reliable with this setup

  • Auto-format every write. Run Prettier/Black/gofmt after each Write — output is always formatted regardless of what the model produced
  • Checkpoint commits. git add "$fp" && git commit -m "checkpoint: ${fp##*/}" gives a diff trail of every model edit you can roll back to
  • Test on change. After a Write to src/, trigger pnpm test --testPathPattern=$(basename "$fp") so you see red/green before the model continues
  • Audit log. Append echo "$(date -u): wrote $fp" >> .claude/audit.log — useful in regulated environments that need a record of AI-assisted edits

The PreToolUse / PostToolUse split

Use PreToolUse to block: return exit code 2 with a reason to stop the tool entirely (this is how .env* file guards work). Use PostToolUse for side-effects: it runs after the tool completes and Claude receives a summary of what your hook did. That means you can also use PostToolUse to feed structured context back — e.g., "formatted: 3 lines changed" — which Claude can reference in its next step.

Sources: Claude Code Hooks — Official Docs, Claude Code Hooks Practical Guide — DataCamp