2026-09-22 / BLOG

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:

  1. Claude edits src/services/billing.ts to add a new tax calculation function.
  2. The postToolUse hook fires instantly.
  3. Prettier formats the file to your team's exact style guide.
  4. TypeScript runs. If Claude forgot to type a function parameter, tsc exits with code 1:
    src/services/billing.ts:42:18 - error TS7006: Parameter 'taxRate' implicitly has an 'any' type.
    
  5. Claude receives the TypeScript compiler error automatically in the conversation:

    "I noticed a TypeScript error in billing.ts where taxRate had an implicit any type. I am fixing it now with an explicit number interface."

  6. 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:

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.

CORE SERVICESESTIMATE PROJECT
BACK TO BLOG