DEV Community

Vildanden
Vildanden

Posted on

Make Claude Code run your tests after every edit with a PostToolUse hook

Telling a coding agent "run the tests after you change something" works most of the time. A hook makes it work every time, and it costs about a dozen lines.

Claude Code fires PostToolUse hooks after a tool call finishes. If you match on the file-editing tools, you get a reliable "after every edit" moment where you can run a fast check and hand the result straight back to the agent.

The hook

#!/usr/bin/env python3
import json, subprocess, sys

event = json.load(sys.stdin)
path = event.get("tool_input", {}).get("file_path", "")

# Only react to source files; skip docs and lockfiles.
if not path.endswith((".ts", ".tsx", ".py")):
    sys.exit(0)

result = subprocess.run(
    ["npm", "test", "--silent", "--", "--bail"],
    capture_output=True, text=True, timeout=120,
)
if result.returncode != 0:
    print("Tests failed after this edit:\n" + result.stdout[-1500:], file=sys.stderr)
    sys.exit(2)  # blocking status: the failure goes back to the agent
Enter fullscreen mode Exit fullscreen mode

Swap npm test for pytest -x -q or whatever your fastest suite is. Keep it fast: if a check takes longer than the edit, the agent spends the session waiting.

Wire it up

In .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [{ "type": "command", "command": "python3 .claude/hooks/test_after_edit.py" }]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Why this beats an instruction

  • The agent sees the failing output immediately, in the same turn, instead of discovering it three edits later.
  • It never "forgets" on a long session.
  • Your project instructions stay short, because the rule lives in code.

Keep the list short

Two or three hooks is plenty: a pre-edit guard for dangerous commands, a post-edit test run, and maybe a formatter. Past that, every edit gets slow and noisy.

If you want a ready-made set (guard hook, test-after-edit hook, settings file and a short CLAUDE.md), the Vildanden Claude Code Ops Pack bundles them. The free Agent Config sample is a good place to start if you just want the house-rules file.

Top comments (1)

Collapse
 
skillselion profile image
Skillselion •

One gap in the "after every edit" guarantee: the matcher is "Edit|Write|MultiEdit", so it only sees edits made through those tools. The hooks reference says Claude Code does not run a PostToolUse hook matching Edit|Write when a Bash command rewrites the same file. A sed -i, a codegen script or a formatter started from Bash changes source files and this hook stays silent. The reference gives two ways out: omit the matcher and let the script find what changed with git status --porcelain, or use the FileChanged event for specific files. With no matcher, the file_path suffix filter in your script needs another source for the changed paths, because a Bash call has no file_path.