[Bug] Subagents silently terminate long-running background shells on turn end; SendMessage resumption auto-converts to async without warning

Resolved 💬 3 comments Opened Apr 19, 2026 by Delibread0601 Closed May 26, 2026

Bug Description
Title: Claude Code subagents silently drop long-running background shells on turn end; SendMessage resumption can be auto-async'd without warning Summary When a subagent uses run_in_background: true to launch a long-running Bash command (in my case codex exec -p quality, which routinely takes 5–15 minutes), the subagent sometimes ends its turn before the shell exits. The shell dies with the subagent session, discarding whatever the background process was doing — including already-billed external API tokens. Concrete repro My subagent prompt contained explicit, multi-paragraph constraints: "You MUST loop BashOutput until shell exits. Do NOT return an interim message. Do NOT hand off to a future turn." Despite this: 1. First attempt: subagent returned "Codex is still searching. Let me wait for Monitor to signal completion" and ended its turn. Background shell died. ~100K Codex tokens lost. 2. Second attempt (SendMessage to resume + a fresh Agent dispatch): the new Agent call returned "Async agent launched successfully" — the harness itself promoted it to an async background agent. My prompt constraints became irrelevant because the agent was no longer synchronous. I had no visible signal this was going to happen, and no parameter to override it. Why it matters External-CLI workflows (Codex, long builds, test suites) are a core use case where background shells are the only way around Bash's 10-minute ceiling. Each failed attempt is a real external-token/compute loss. Users cannot opt out today — Agent has no synchronous: true flag. Suggested fixes (in order of impact) 1. Add synchronous: true to the Agent tool so callers can reject auto-async classification. The auto-async decision on SendMessage resumption was invisible and surprising. 2. Surface a harness-level warning when a subagent tries to return while it still owns live background shells. Don't silently let the shell die. 3. Document the auto-async trigger conditions for SendMessage-resumed agents. Right now the behavior is hidden and user prompts can't compensate for it. 4. Consider whether Stop-hook-style enforcement on "background shells still alive" is tractable — similar to how PreToolUse hooks already gate tool calls. This is otherwise a tool I rely on heavily for long-running reviews. Smoothing this out would meaningfully reduce wasted external-API spend for CLI-integration workflows.

Environment Info

  • Platform: darwin
  • Terminal: Apple_Terminal
  • Version: 2.1.114
  • Feedback ID: 91e44bbd-b9ae-43fa-b743-7c0d305a2a9b

Errors

[{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/wordsing/.local/share/claude/versions/2.1.114 (expected in multi-process scenarios)\n    at sd_ (/$bunfs/root/src/entrypoints/cli.js:2751:2177)\n    at WH8 (/$bunfs/root/src/entrypoints/cli.js:2751:1257)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-18T23:33:36.904Z"},{"error":"Error: ensureToolResultPairing: repaired missing tool_result blocks (37 -> 37 messages). Message structure: [0] user; [1] assistant(id=msg_01FtBQN5aAMFjq1GV5S2imkM, tool_uses=[]); [2] user; [3] assistant(id=msg_01KaUrxrKy9Y37ZBg4YY26Qo, tool_uses=[]); [4] user; [5] assistant(id=msg_01KMGfYBFPuhstJ6kFEMRe11, tool_uses=[toolu_017toeS2tN1Qce7LJAtmvUaY]); [6] user(tool_results=[toolu_017toeS2tN1Qce7LJAtmvUaY]); [7] assistant(id=msg_01D4J3ndcnGayMioEnGVDUm1, tool_uses=[toolu_0127JKDxhytFpSAZBb8MGfJi]); [8] user(tool_results=[toolu_0127JKDxhytFpSAZBb8MGfJi]); [9] assistant(id=msg_018qqsWiVPRgonNxnGk4tK1o, tool_uses=[toolu_017ELupVJpQtdjBqtV1HfCBN]); [10] user(tool_results=[toolu_017ELupVJpQtdjBqtV1HfCBN]); [11] assistant(id=msg_01HEMLfQkc3pzbmTgRmpi5ZG, tool_uses=[toolu_01LqEGFjXvTmPKVZLT7oJCSe,toolu_016mLHuC4myAuCyJEPjebCaa,toolu_01FrUdtS393g3VcZbk12iWuE]); [12] user(tool_results=[toolu_016mLHuC4myAuCyJEPjebCaa,toolu_01LqEGFjXvTmPKVZLT7oJCSe,toolu_01FrUdtS393g3VcZbk12iWuE]); [13] assistant(id=msg_01XGLrNRBUTXryiVd55PHFVK, tool_uses=[toolu_01LLBDirJTUzb9fDfBbMLw5u,toolu_019ZWTqLk6LykfZBvy9uUpvr]); [14] user(tool_results=[toolu_01LLBDirJTUzb9fDfBbMLw5u,toolu_019ZWTqLk6LykfZBvy9uUpvr]); [15] assistant(id=msg_013yXkKRZPbezRkSaSNWkcaa, tool_uses=[]); [16] user; [17] assistant(id=msg_01WG2DZ4bvwRCWPGLxWNSbD1, tool_uses=[]); [18] user; [19] assistant(id=msg_012GwS8M8P3tDEZ5Pr4eYidp, tool_uses=[toolu_014n9kNzCbWUph2JZmkt2Mht]); [20] user(tool_results=[toolu_014n9kNzCbWUph2JZmkt2Mht]); [21] assistant(id=msg_01T5vpikBEtoU8zoVN28RCZQ, tool_uses=[toolu_019fCRa64i1Bxg6ENvbuRkU8]); [22] user(tool_results=[toolu_019fCRa64i1Bxg6ENvbuRkU8]); [23] assistant(id=msg_01Qyn1XCGvJG299oVYwEQzLy, tool_uses=[toolu_01B3WwG1ukJateC7gCUF2inr]); [24] user(tool_results=[toolu_01B3WwG1ukJateC7gCUF2inr]); [25] assistant(id=msg_01EFwwpa7i69oZT6wXdh1aiS, tool_uses=[toolu_01M6tQUXEB87wN7FHvKpCqLw]); [26] user(tool_results=[toolu_01M6tQUXEB87wN7FHvKpCqLw]); [27] assistant(id=msg_01JzSXnN1TnkUL2AoGPwF7nL, tool_uses=[toolu_015PUQyJstD5VeWUtPZVWRR6]); [28] user(tool_results=[toolu_015PUQyJstD5VeWUtPZVWRR6]); [29] assistant(id=msg_016eXJCEWHcZbcHsQfAHvzGL, tool_uses=[toolu_017yRqmVtLfTTv1Jnm2DwHD2]); [30] user(tool_results=[toolu_017yRqmVtLfTTv1Jnm2DwHD2]); [31] assis…

Note: Content was truncated.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗