[BUG] Bash auto-background-on-timeout eligibility is evaluated post-rewrite and undocumented — hook-rewritten long commands are killed at 2m instead of backgrounded
Summary
Bash auto-background-on-timeout (a foreground command that outlives its timeout is converted to a background task instead of killed) is gated on a canAutoBackground predicate over the post-rewrite command shape, and the eligibility rules are undocumented. Consequences:
- A PreToolUse hook that rewrites a command (e.g. appending
; exit "${PIPESTATUS[0]}"to un-mask a pipeline's exit code) silently strips auto-background eligibility: the identical workload that would have been converted at 120s and completed is instead SIGTERMed (Command timed out after 2m 0s, exit 143). - The model has no way to know which command shapes are eligible, so it cannot predict whether a long foreground command will survive the default timeout (converted) or die (killed).
Environment
- Claude Code 2.1.251, Windows 11 (win32 x64), Git Bash, main agent (not a subagent)
Repro (no hook required)
A/B, both foreground, both without an explicit timeout:
- A:
python -c "import time; time.sleep(150); print('done')" 2>&1 | tail -2
→ at 120s: "Command did not complete within its 120s timeout and was moved to the background (ID: …)" — completes with exit 0.
- B:
python -c "import time; time.sleep(150); print('done')" 2>&1 | tail -2; exit "${PIPESTATUS[0]}"
→ at 120s: Command timed out after 2m 0s, exit 143. Killed.
The only difference is the trailing ; exit … statement — a plain pipeline qualifies as auto-backgroundable, a two-statement command does not. With a PreToolUse hook doing the append via updatedInput, case A silently becomes case B without the model or user seeing the rewritten shape's consequence.
Expected
Any of:
- evaluate
canAutoBackgroundon the original (pre-rewrite) input, since the rewrite was not the model's choice; or - document the eligibility rules (simple/pipeline shapes qualify; multi-statement
;chains, compound&&scripts, loops do not; main-agent only) so hook authors and models can reason about the 120s cliff; or - when an ineligible command is killed at the default timeout, note in the error that auto-backgrounding was skipped and why.
Impact
Long test suites and builds behind rc-instrumentation hooks die at exactly 2 minutes and look like flaky infrastructure. Related: #89495 (auto-background in -p mode), #79321 (updatedInput on Bash), #83353 (rewrite race).
🤖 Generated with Claude Code