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 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" }] } ] } } 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.