Agent-type Stop hook runs 42+ minutes despite "timeout": 240
Environment
- Claude Code 2.1.223, macOS (darwin 25.5.0)
- Hook:
Stophook,"type": "agent", configured in project.claude/settings.json
Config (abridged)
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "You are a STRICT rules-compliance reviewer... (reviews `git diff <base>..HEAD` against the repo's CLAUDE.md and rules)",
"timeout": 240,
"model": "claude-opus-5",
"statusMessage": "Rules-compliance review"
}
]
}
]
}
}
Full config: https://github.com/ket-sh/ket/blob/ad98921/.claude/settings.json
Expected
Per the hooks reference, timeout (seconds) is a common field and should bound the entire agent-hook run; the default for agent hooks is 60s. With "timeout": 240, the hook should be cancelled after 4 minutes, fail open, and let the stop proceed.
Observed
The Stop hook ran 42+ minutes in a single turn end. The status line showed Rules-compliance review… 2/6 · 42m 38s · ↓ 76.8k tokens (spinner counter 2/6 is itself undocumented — unclear whether it counts hooks or something else). The session's turn end was blocked the whole time.
Context that may matter for reproduction: the branch diff under review was large (a fresh git worktree, so the agent reviewed the whole merge-base..HEAD diff, six commits plus uncommitted work), and the prompt instructs several git invocations plus reading rule files.
Why it bites
Agent hooks fail open on timeout by design, so an unenforced timeout is the worst of both worlds: you cannot rely on the ceiling to bound latency, and you cannot lower it to bound latency either (that would starve the review and silently disable it). A gate that sometimes costs 40+ minutes per turn end trains users to kill it.
Questions
- Is
timeoutexpected to bound the whole agent loop fortype: "agent"Stop hooks in 2.1.x? (Changelog 2.1.210 mentions a hook-timeout misreport fix; this is 2.1.223.) - What does the
N/Mcounter in the hook status line count?