Claude Code Stop Hook: Force Task Completion Before Claude Stops
Use the Stop Hook to ensure Claude finishes tasks before responding. Run tests automatically, validate output, and prevent incomplete work.
Agentic Orchestration Kit for Claude Code.
Problem: Claude finishes responding but the task is incomplete. Tests are failing. Files are half-written. You ask "are you done?" and Claude says yes, but the build is broken.
Quick Win: Add this Stop hook and Claude cannot stop until tests pass:
Now Claude literally cannot stop responding until tests pass.
How the Stop Hook Works
The Stop hook fires every time Claude finishes a response. You can:
- Allow stopping - Exit 0, Claude stops normally
- Block stopping - Return
{"decision": "block", "reason": "..."}, Claude continues working - Run validations - Execute tests, checks, or validations automatically
The Payload
The stop_hook_active flag is critical. When true, Claude is already in a "forced continuation" state from a previous block. Always check this to prevent infinite loops.
Pattern 1: Test Gate
Block Claude until all tests pass:
Pattern 2: Build Validation
Ensure the project builds before Claude stops:
Pattern 3: Lint Check
No stopping with lint errors:
Pattern 4: Task Completion Marker
Check if a specific task was completed:
Create the marker when starting work:
Delete it when done:
Preventing Infinite Loops
The stop_hook_active flag prevents loops. Here's why it matters:
Always check the flag first:
Combining Multiple Checks
Chain validations in a single hook:
When to Use Stop Hooks
Good use cases:
- Ensuring tests pass before "task complete"
- Validating builds succeed
- Checking lint/type errors
- Custom completion criteria
Bad use cases:
- Long-running operations (60 second timeout)
- Network-dependent checks (flaky)
- Blocking on user input (can't interact)
Configuration
Add to .claude/settings.json:
Multiple hooks run in parallel. If any returns block, Claude continues.
Debugging
Infinite loop?
- Check that you're reading
stop_hook_activecorrectly - Add logging:
echo "stop_hook_active: $stop_hook_active" >> ~/.claude/stop-debug.log
Hook not blocking?
- Verify JSON output format:
{"decision": "block", "reason": "..."} - Check exit code is 0 (not 2 for blocking)
Tests timing out?
- 60 second hook timeout
- Run subset of tests or increase efficiency
The "Ralph Wilgum" Pattern
Named after a community technique, this pattern uses Stop hooks to create persistent task loops:
- Create task marker at session start
- Stop hook blocks until marker removed
- Claude must explicitly complete task to remove marker
- No accidental "I'm done" when work is incomplete
This transforms Claude from "best effort" to "guaranteed completion." The Code Kit takes this further with a BiomeValidator Stop hook that runs lint and format checks on every file Claude touches, combined with a build-then-validate pattern where a dedicated quality-engineer agent inspects the builder's output before marking tasks complete.
Next Steps
- Set up the main Hooks Guide for all hook types
- Configure Context Recovery to survive compaction
- Learn Skill Activation for automatic skill loading
- Explore Permission Hooks for auto-approval
Last updated on