Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- In a Claude thread, have the agent start a background subagent (the Agent tool, which runs in the background), or a background Bash command that it marks with
t3_background_wait. - In the same turn, have the agent settle its own thread:
t3_thread_organize {"action": "settle"}. The tool returns{"settlesWhenTurnEnds": true}. End the turn. - Alternatively, settle such a thread from the sidebar after the turn ends while that work is still running.
Expected behavior
Settle is held while the agent waits on that work, as auto-settle already is since #24610 (isAutoSettlementCandidate checks backgroundWorkHoldsCompletion). The thread stays in Working until the work ends and the agent's wake turn finishes.
Actual behavior
thread.settle detaches every provider session of the thread (Orchestrator.ts, "Archive and settle stop idle background work"). For Claude this closes the process, so its background subagents and commands die and never wake the agent. When the thread next runs, Claude reports each of them as having not finished "before the previous session ended".
The agent's own settle is queued by settleAfterRun (ThreadManagementService.ts) and dispatched as thread.settle with command id server:settle-after-run:<runId> as soon as the run completes. That is the end of the turn that just launched the work, so the work is almost always still running.
None of the thread.settle checks (approval or question pending, run active, queued message) looks at background work.
Impact
Major degradation or frequent failure
Version or commit
Observed on 0.1.1 (desktop, local server). The same code path is on main 337c585.
Environment
macOS arm64, T3 Code desktop with its local server, provider claudeAgent (claude-opus-5-5).
Logs or stack traces
About five days of local Claude transcripts joined with orchestration_v2_effect_outbox
(effect_type provider-session.detach), counting background tasks that outlived the turn
that launched them, on threads run through T3:
- 22 tasks died ("didn't finish before the previous session ended"). All 22 had a
provider-session.detach between launch and death:
17 server:settle-after-run:<runId> (13 agents, 4 bash)
4 "Thread settled." from other settles (2 agents, 2 bash)
1 "Provider or model selection changed." (bash; the case #30401 fixed)
- 225 tasks (174 agents, 51 bash) crossed a turn end with no detach in between. All completed.
- No task completed with a detach in between.
- The 6 bash tasks that died on settle were unmarked commands (0.1.1 predates
t3_background_wait). The fix proposed below covers the 15 agents and commands the agent
marks as awaited, not unmarked commands.
- For comparison, the same Claude Code CLI outside T3 (no settle): 190 tasks crossed a
turn end, none died.Workaround
Do not settle a thread while it has background agents or commands running. Put long work in delegate_task: the child runs in its own thread, so the parent's settle does not stop it.
Related
- [Bug]: Thread auto-settles while the agent is still waiting on a background command #17625 / fix(threads): Working holds only background work the agent waits on #24610: auto-settle holds for awaited background work. This report is the same rule missing on an explicit settle.
- Auto-settle stops the agent when the background task it awaited finishes #30790, fix(server): auto-settle no longer cuts off an agent whose awaited background task just finished #29820, fix(server): auto-settle no longer cuts off an agent waking from awaited background work #30837: auto-settle timing when awaited work ends. Different path (
thread.auto-settle). - fix(server): a queued provider switch no longer ends background work #30401: the same detach problem on a queued provider switch, fixed by refusing while background work runs.
- [Bug]: After Settle stops a thread's background server, the thread still shows "Waiting" with a Stop button #15239, [Bug]: processes dont get closed on settling a chat #25062: settle is meant to stop background work such as dev servers. A fix should keep that for unmarked commands.
Proposed fix
In the thread.settle checks in Orchestrator.ts, next to "is still running. Stop it before settling.", refuse while backgroundWorkHoldsCompletion is true for the thread's pending background work, excluding tasks delegated to other threads, which a detach does not stop. Unmarked commands such as dev servers still stop on settle. A PR that references this issue follows.
Activity
bornio commentedon Nov 10, 2026
Still happens on 0.1.8 (desktop app, local server, macOS arm64, claudeAgent / claude-opus-5-5), this time with a Bash command the agent did mark with
t3_background_wait. The earlier counts in this issue only had unmarked commands, because they predate that tool.Timeline (UTC, 2026-11-10), from the provider event log,
server.trace.ndjsonandorchestration_v2_effect_outbox:run_in_background→ taskbawwyfbgi(local_bash)t3_background_wait {"taskIds":["bawwyfbgi"]}→{"matched":["bawwyfbgi"],"unmatched":[]}result/end_turn). Claude process stays upthread.settlearrives over the desktop app's websocket (ws.rpc.orchestration.dispatchCommand, client UUID command id, notserver:settle-after-runorserver:auto-settle)provider-session.detach"Thread settled." in the effect outboxquery.closesent to the Claude process (44 ms after the settle)task_notificationbawwyfbgistatus: "stopped", "Background shell command didn't finish before the previous session ended"The settle was followed within ~65 ms by forward navigation to another thread, which matches a sidebar, menu or ⌘⇧S settle. The user doesn't recall settling. They recall only snoozing the thread, which the trace shows 11 s later from the same connection. They also report that after the turn ended the thread looked stopped rather than Working, even though
t3_background_waithad matched. If that holds up, nothing in the UI warned them that the settle would end the awaited work. I couldn't verify the sidebar state from the logs.Still reproducible on
mainas of today: thethread.settlechecks inOrchestrator.tsstill look only at approvals, questions, running runs and queued messages, notbackgroundWorkHoldsCompletion. #31449 looks like the right fix.Separately, in the same thread three minutes earlier, an unmarked background command died when auto-settle-on-merge fired 146 ms after the turn ended (
server:auto-settle:…→query.close). That one is the intended behavior for unmarked commands, but because it fires so close to the turn end, any command started in the turn where a PR merges is almost certain to die unless the agent marks it.Filed via T3 Code triage by Claude Code (Claude Opus 5.5,
claude-opus-5-5).