Guide · coding agents

Stop your agent saying "done" before the tests pass.

Asking nicely in CLAUDE.md or AGENTS.md is a request the model can skip. A hook is different: the agent host runs it, and a Stop hook that exits with code 2 sends the agent back to work instead of letting it finish. Two small hooks are enough to make "done" mean "the tests passed after the last edit".

The idea

Record two times: when a file was last edited, and when the test suite last passed. When the agent tries to stop, compare them. If the last passing run is older than the last edit, block the stop and say why.

Claude Code: copy this

1. Add to .claude/settings.json in your project:

{
  "hooks": {
    "PostToolUse": [
      { "matcher": "Edit|Write|MultiEdit",
        "hooks": [{ "type": "command", "command": "date +%s > \"$CLAUDE_PROJECT_DIR/.claude/last-edit\"" }] }
    ],
    "Stop": [
      { "hooks": [{ "type": "command", "command": "sh \"$CLAUDE_PROJECT_DIR/.claude/require-green.sh\"" }] }
    ]
  }
}

2. Save this as .claude/require-green.sh:

#!/bin/sh
d="$CLAUDE_PROJECT_DIR/.claude"
[ -f "$d/last-edit" ] || exit 0
edit=$(cat "$d/last-edit")
green=$(cat "$d/last-green" 2>/dev/null || echo 0)
if [ "$green" -lt "$edit" ]; then
  echo "Tests have not passed since your last edit. Run: npm test && date +%s > .claude/last-green" >&2
  exit 2
fi
exit 0

3. Tell the agent how to run tests, in CLAUDE.md: npm test && date +%s > .claude/last-green (swap in your own test command). The marker is written only when the command succeeds.

Claude Code reads what the script prints to stderr and keeps working. It also sends stop_hook_active: true in the hook's input when it is already continuing because of a Stop hook; read it if you want to cap retries. Works on macOS and Linux shells.

Codex

Codex has the same hook events. Register the two commands in .codex/hooks.json and trust them with /hooks. A Codex Stop hook can block with exit code 2 and a reason on stderr, or by printing {"decision": "block", "reason": "..."}; Codex then continues with the reason as its next prompt. Match the PostToolUse hook to the tool your Codex version uses to edit files.

Where this recipe falls short

It trusts a marker file the agent can write itself: an agent that runs date +%s > .claude/last-green without the tests gets through. It only sees edits made through the editing tools, not files changed by shell commands. It says nothing about whether the tests cover what you asked for. It is still a big step up from instructions alone.

What Living Stack's Enforced mode adds

Enforced mode is an opt-in part of Living Stack Complete Local ($19 once, no subscription). Instead of a marker file, the hook watches the test run itself and only counts a run it saw pass after the last edit. A pre-tool gate blocks destructive commands and writes outside the project folder unless you authorized that exact action, and the test runs it saw go into a signed, hash-chained log.

On 13 recorded hook inputs it blocked 10 of 10 risky cases and 0 of 3 safe actions; the best free hook tools we tested blocked at most 3 of the 10 each. What it does not stop: writes made from inside interpreter one-liners or scripts (python -c, node -e, a script file); tests weakened until they pass trivially; a stop allowed after 3 blocked attempts in a row (recorded as unverified, with a warning). Codex support is covered by unit tests only, not by the bench. It does not guarantee agent behavior.

Read the full Enforced mode section · Complete Local, $19 once