What it does
PostToolUse hooks run immediately after Claude Code executes any tool — Read, Edit, Write, Bash, or any MCP tool. They're shell scripts you define in settings.json that receive the tool result and can inspect, transform, or act on it. Common uses: auto-format files after edits, lint code and feed warnings back into the conversation, sync external systems, or trigger dependent tasks.
The hook receives:
TOOL_NAME(the tool that just ran)TOOL_RESULT(stdout/stderr from the tool, or the tool's return value if structured)TOOL_STATUS(success/failure)TOOL_ARGS(what was passed to the tool, as JSON)
Your script can write to stdout, which gets piped back to Claude as a hook result. If you echo warnings or errors, they appear inline in the conversation so Claude can see them immediately.
When to use it
Format-on-save: After every Edit or Write call to a .ts or .tsx file, auto-run Prettier, then echo the diff so Claude sees what was reformatted.
Lint feedback loop: After Edit, run eslint on the changed file and echo violations back. Claude can read them and fix in the next iteration.
Build check: After pushing code, trigger a build or test suite and fail the hook if tests break, blocking the push.
Sync workflows: After writing a config file, trigger a GitHub Actions workflow or sync a database schema.
Warnings as context: After Read, if the file contains TODO comments or security notes, echo them so Claude is aware before writing.
PostToolUse is the closest thing Claude Code has to pre-commit hooks — it closes the feedback loop so Claude sees the consequences of its edits without you having to tell it.
Try it yourself
Set up a hook in .claude/settings.json that lints TypeScript files after Edit, then echo any errors back. Look for the hooks object under PostToolUse and add an Edit handler that runs your linter of choice (eslint, biome, or a custom check). Run npm run check or your build, watch what gets echoed back, and see how Claude adapts on the next edit.
Gotchas
Hook output is public: Everything you echo in a PostToolUse hook shows up in the conversation. Don't echo secrets, large raw outputs, or binary data — keep it concise and human-readable.
Long hooks block the UI: If your script runs a full test suite, Claude's next response is delayed until the hook completes. Use fast checks (format, lint) for Edit hooks; save slow checks (tests, builds) for manual Bash calls.
Hooks don't auto-retry: If your hook fails, the tool result is still treated as success unless you explicitly set TOOL_STATUS to failure. A failed hook doesn't revert the edit — it just reports the failure.
No stdin for hooks: PostToolUse scripts can't read from stdin. Pass all state via environment variables or config files.
Not all tools support hooks: Hooks fire on standard tools (Read, Edit, Write, Bash, Agent) but custom tools or MCP calls may not trigger them. Check your settings.json hooks config to see what's wired.
Set ignoreErrors: true for non-blocking hooks: If you want a hook to warn but not halt Claude's flow, set ignoreErrors in the hook config. Otherwise, a failed hook blocks the response.
Try it yourself
Type the command in the fake terminal. Nothing leaves your browser.