Deterministic AI Quality: Mastering Post-Tool-Use Hooks in Claude Code
Deterministic AI Quality: Mastering Post-Tool-Use Hooks in Claude Code
When developers want an AI agent to write clean, linted, test-passing code, their standard instinct is prompt engineering:
"Always remember to run ESLint after editing. Make sure all TypeScript types compile. Run the unit test suite before telling me you are done."
This approach is deeply flawed.
It relies on probabilistic compliance. Sometimes the model remembers; sometimes it hallucinates that it ran the test; and every single prompt in your conversation must pay the token cost of carrying these repetitive instructions.
The production-grade solution is Post-Tool-Use Hooks.
What Are Claude Code Hooks?
Hooks are deterministic lifecycle scripts configured in your .claude/settings.json. They intercept tool events (like edit or write) and execute local bash commands on your operating system before control returns to the user or model.
If your hook fails (for example, if TypeScript fails to compile or Prettier throws an error), the compiler output is automatically fed directly back into Claude's context window. Claude sees the exact compile error and immediately self-corrects without human intervention.
1. Configuring Post-Tool Hooks in .claude/settings.json
In the root of your project, create or update .claude/settings.json:
{
"hooks": {
"postToolUse": {
"edit": "./scripts/validate-edit.sh",
"write": "./scripts/validate-edit.sh"
}
}
}
Now, create a fast, local validation script:
#!/usr/bin/env bash
# scripts/validate-edit.sh
set -e
# 1. Format code automatically
npx prettier --write "$CLAUDE_TOOL_FILE_PATH"
# 2. Check TypeScript types
npx tsc --noEmit
# 3. Run affected unit tests
npm test -- --findRelatedTests "$CLAUDE_TOOL_FILE_PATH" --passWithNoTests
Make the script executable:
chmod +x ./scripts/validate-edit.sh
2. How the Feedback Loop Operates
Here is what happens during an autonomous session:
- Claude edits
src/services/billing.tsto add a new tax calculation function. - The
postToolUsehook fires instantly. - Prettier formats the file to your team's exact style guide.
- TypeScript runs. If Claude forgot to type a function parameter,
tscexits with code1:src/services/billing.ts:42:18 - error TS7006: Parameter 'taxRate' implicitly has an 'any' type. - Claude receives the TypeScript compiler error automatically in the conversation:
"I noticed a TypeScript error in
billing.tswheretaxRatehad an implicitanytype. I am fixing it now with an explicitnumberinterface." - Claude re-edits the file, the hook passes cleanly, and only then does Claude mark the task complete.
You never have to review messy formatting or broken types again.
3. Polyglot Hooks: .NET, Python, and Go
Hooks work across any runtime supported by your host environment:
For .NET & C# Projects
#!/usr/bin/env bash
# validate-dotnet.sh
dotnet format --include "$CLAUDE_TOOL_FILE_PATH" --verify-no-changes
dotnet build --no-restore /clp:ErrorsOnly
For Python / FastAPI Projects
#!/usr/bin/env bash
# validate-python.sh
ruff check --fix "$CLAUDE_TOOL_FILE_PATH"
mypy "$CLAUDE_TOOL_FILE_PATH"
4. The Token & Financial Impact
Moving quality gates from prompt instructions into local hooks yields three immediate benefits:
- Zero Prompt Token Overhead: You can delete 20 lines of formatting instructions from
CLAUDE.md. - 100% Deterministic Enforcement: Code style and compiler checks execute unconditionally on your hardware, not via LLM approximations.
- Instant Error Localization: Claude receives pinpoint line-and-column compiler errors rather than guessing why a build failed.
Hooks turn Claude Code from a conversational assistant into an automated, self-healing continuous integration loop.
READY TO IMPLEMENT THIS?
We specialize in turning these high-impact engineering concepts into production-grade systems.