CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Gate Your Subagents: Use SubagentStop Hooks to Run Tests Before Outputs Flow Back

Gate Your Subagents: Use SubagentStop Hooks to Run Tests Before Outputs Flow Back

Chris Harper

3 min read

Jul 22, 2026 · 20:06 UTC

AI
Workflow
Claude Code
Agents
Best Practices

TL;DR: SubagentStop fires when a subagent finishes its task — wire it to your test suite for a soft output gate. Exit 2 + additionalContext pushes a new instruction back without ending the subagent's turn.

The SubagentStop hook is the most underused hook in the Claude Code lifecycle. It fires when a subagent (spawned via the Agent tool) completes, right before its summary reaches the lead agent. That window is a quality gate: run your tests there, and if they fail, the subagent gets another chance to fix things before the lead sees anything.

Wire it in settings.json

{
  "hooks": {
    "SubagentStop": [{
      "matcher": "",
      "hooks": [{
        "type": "command",
        "command": "bash .claude/hooks/subagent-gate.sh"
      }]
    }]
  }
}

The gate script

#!/usr/bin/env bash
# .claude/hooks/subagent-gate.sh
cd "$CLAUDE_PROJECT_DIR"

# Run the test suite
if ! pnpm test --reporter=dot 2>&1; then
    echo '{"hookSpecificOutput":{"additionalContext":"Tests failed. Fix the failing tests before finishing."}}' >&3
    exit 2   # re-enters the subagent turn with the message above
fi

# Tests passed — attach an audit fact for the lead
echo "{"hookSpecificOutput":{"additionalContext":"Tests passed at $(git rev-parse --short HEAD)."}}" >&3
exit 0

How exit codes work

CodeEffect
2Claude Code re-enters the subagent's turn with additionalContext as a new instruction. The subagent sees it and can fix the issue — up to 8 retries before Claude overrides.
0 + additionalContextHook succeeds; the context string is attached to the subagent's output so the lead gets an audit-trail fact without the user seeing a hook message.
1 / no outputTreated as a hook error. Avoid for routine gates — use exit 2 for expected failures.

Three production patterns

1. Test gate (above) — the most common. Ensures every subagent ships working code before the lead synthesizes results.

2. Secret scrubber — grep the diff for API keys, JWTs, and connection strings:

DIFF=$(git diff HEAD)
if echo "$DIFF" | grep -Eq '(sk-[a-zA-Z0-9]{20,}|eyJ[a-zA-Z0-9_-]{20,}|-----BEGIN .* PRIVATE KEY)'; then
    echo '{"hookSpecificOutput":{"additionalContext":"Secret detected in diff. Remove it before finishing."}}' >&3
    exit 2
fi

3. Schema validator — when a subagent should write a specific JSON/YAML shape, validate it before the lead incorporates it:

python3 -c "import json, sys; json.load(open('output.json'))" || {
    echo '{"hookSpecificOutput":{"additionalContext":"output.json is not valid JSON. Fix the schema."}}' >&3
    exit 2
}

SubagentStop vs. Stop

The Stop hook gates the lead agent's end-of-turn. SubagentStop only fires for subagents — so you can apply different policies to different roles: strict test gates for coding subagents, secret scanning for all, no gate for research-only subagents (use the matcher field on the hook to scope by subagent system-prompt keywords).

Sources: Hooks — Claude Code Docs · Claude Code Hooks: Complete Guide to All 12 Lifecycle Events · Claude Code Hooks in 2026: A Production Playbook