You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Agents panel keeps a finished Claude subagent as running, or interrupted, after the thread's process restarts #14802
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 main agent start background subagents (Agent tool, run_in_background) whose work takes several minutes.
While they run, restart the thread's Claude process. In our case this happened when the model was switched in the composer's model picker; a provider crash or --resume should do the same.
Let the subagents finish after the restart, then look at the Agents panel.
Expected behavior
Each row shows the subagent's real final state: completed, with the duration it actually ran.
Actual behavior
Two subagents of the same type were affected in one thread. Times are UTC, taken from the subagents' own transcripts (~/.claude/projects/<project>/<session>/subagents/agent-*.jsonl):
subagent
started
finished (last assistant text)
panel at 09:33
A
09:00:04
09:05:58
grey, "Background agent didn't finish before the previous…"
B
09:04:19
09:11:37
blue, still working, "28m 57s", last tool Bash
Both completed: each transcript ends with the subagent's final text, and the main agent received both results ("finished after the restart" in its own summary). Twenty-two minutes after B finished, the panel still showed it as working with a running timer, and A as interrupted. Every other subagent in the thread that did not overlap the restart was shown correctly.
So completion of a subagent that outlives its parent process is never applied to its row: the row either stays on the state recorded before the restart or keeps running. This differs from #14002, which covers a subagent continued with SendMessage; here nothing was resumed, only the parent process restarted.
Impact
Minor bug or occasional failure
Version or commit
Desktop 0.0.44
Environment
macOS 27, T3 Code desktop 0.0.44, Claude Code 2.1.286, Claude provider (Fable 5.1 session).
Workaround
None in the panel. The subagent's transcript, or the main agent's own report, shows the real state.
Related
The model and effort shown on every row are the parent session's, not the subagent's (same thread: rows said medium while the transcripts record high, xhigh and low). That is #7281, closed with #13333 unmerged during the V2 freeze, so it is not repeated here.
Thanks for the detailed timeline, @caitlon. The transcript timestamps made this easy to trace. It's a real Agents panel bug on current main (54084ae), and you're right that it's separate from open issue #14002.
Why the restart happens: switching the model in the composer restarts Claude for claudeAgent and keeps the resume cursor (shouldRestartForModelSelectionChange in ProviderCommandReactor). A crash or --resume goes down the same path.
Subagent A (grey, interrupted): on shutdown, stopSessionInternal writes task.completed with status: "stopped" for every task that's still live. The resumed CLI then reports orphaned tasks with reason: "worker_restart", also as stopped. ClaudeAdapter forwards the status but drops the reason. The panel fold maps stopped to interrupted, and once a row is terminal, a later task.completed only fills in a missing result or usage. It never changes the status or completedAt. So the real completion never replaces the stop.
Subagent B (blue, still running): this row never got a terminal event that the fold kept. The new process starts with an empty live-task set, so the shutdown sweep doesn't cover it. background_tasks_changed is the roster snapshot the SDK says hosts should reconcile with after a CLI restart, but T3 currently ignores it on purpose. So nothing ever corrects the missing bookend. The 28m 57s timer counts from the original 09:04 start, which matches what you saw.
Likely fix: keep reason: "worker_restart" and don't treat a restart-time stopped as final, so a later completed or failed for the same task can set the status, completedAt, and summary. Also reconcile background_tasks_changed after the new process starts so a missed completion can't leave a timer running.
There's no workaround in the panel yet. As you noted, the subagent transcript or the main agent's report shows the real result.
Reproduced on main (54084ae) in an isolated dev server with Claude Code 2.1.287:
A model switch restarts the Claude process. T3's shutdown sweep writes stopped for the live subagents. The resumed CLI then reports each orphan again as stopped, with "Background agent … didn't finish before the previous session ended". That notification carries no reason and no tool_use_id, so keying on worker_restart wouldn't catch this path.
On main, both rows stay grey "Stopped" after the subagents finish ("alpha done", "beta done").
#14696 settles both rows as completed, run 2, with their real result and duration. I've added a regression test with these exact rows, plus before/after captures and a recording, to that PR.
I couldn't reproduce subagent B, the row that keeps running. In every run, the sweep and the orphan notification settled it. @caitlon, if you still have ~/.t3/userdata/logs/provider/events.<threadId>.log for that thread, B's rows around the restart would show which bookend went missing.
@juliusmarminge, would you be OK merging #14696 for #14002 and for subagent A here, and keeping this issue open for B? #14696 has passed triage and Macroscope approved it. Its CI workflows are waiting for approval to run, since it comes from a fork.
Thanks for digging in, @navidnadali. I still have the provider log for that thread (events.f43327d0-….log, desktop 0.0.44). Here are the canonical task events for the two rows. Times are UTC, and I trimmed the summaries:
09:03:54.683 session.started (process restarted after the model switch)
09:03:56.759 task.completed ae57307fc89a2aa86 stopped Background agent "Gemini check: code and consumers" ... <- A
09:04:11.936 task.started af505255719175812 Gemini check: code and consumers <- B
09:05:58.605 task.updated ae57307fc89a2aa86 completed
09:05:58.605 task.completed ae57307fc89a2aa86 completed Angle: code path and every consumer ... <- A
09:11:37.851 task.updated af505255719175812 completed
09:11:37.854 task.completed af505255719175812 completed Angle: code path and every consumer ... <- B
Two things in it differ from your repro:
A finished on its own. After the restart's stopped, A got a real completed at 09:05:58. No SendMessage and no second task_started came in between. So in this run the orphan did continue without being resumed, and the late completed was the only event that could have settled the row. fix(client-runtime): a resumed Claude subagent no longer stays failed or stopped in the Agents panel #14696 may not cover A if it keys on a new SendMessage tool use.
B was not orphaned. It started 17 seconds after the restart, and both bookends are in the log: task.started at 09:04:11 and task.completed with status completed at 09:11:37. At 09:33 the panel still showed it as working, with the timer counting from 09:04. So no event was missing. The completion was in the provider log and never reached the row.
A setup detail that may explain B: on this machine two T3 servers were running against the same ~/.t3/userdata at the time, the desktop app's backend and a t3 serve background service. That is the condition in #14115, where each server runs its own provider session for the same thread. If the client was attached to the server that did not own this session, its projection would never see B's completed, which would also explain why you can't reproduce B with a single server. I haven't confirmed which server the window was attached to.
I can share more lines from this log if you need them. I'd rather not attach the whole file, because it contains the full conversation.
Thanks for the detailed timelines and the additional log excerpt. They make the two cases much clearer.
The orchestrator V2 rewrite has now landed in #2829. It removes the Agents panel and the V1 provider/status-folding paths investigated in this report. Subagent state is now shown through Lineage and the V2 projections, so I am closing this as an obsolete V1 report. Our earlier cleanup missed this one.
This does not establish that every restart or multi-server status problem is fixed. If you see the same symptom on a build containing V2, please open a fresh issue with the build, what Lineage shows, and whether multiple servers share the same data directory. Please link this report so the timelines and the distinction between A and B are preserved. A small, redacted log excerpt like the one above is enough; there is no need to share the full conversation.
Activity
juliusmarminge commentedon Oct 2, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the detailed timeline, @caitlon. The transcript timestamps made this easy to trace. It's a real Agents panel bug on current
main(54084ae), and you're right that it's separate from open issue #14002.Why the restart happens: switching the model in the composer restarts Claude for
claudeAgentand keeps the resume cursor (shouldRestartForModelSelectionChangeinProviderCommandReactor). A crash or--resumegoes down the same path.Subagent A (grey, interrupted): on shutdown,
stopSessionInternalwritestask.completedwithstatus: "stopped"for every task that's still live. The resumed CLI then reports orphaned tasks withreason: "worker_restart", also asstopped.ClaudeAdapterforwards the status but drops thereason. The panel fold mapsstoppedtointerrupted, and once a row is terminal, a latertask.completedonly fills in a missing result or usage. It never changes the status orcompletedAt. So the real completion never replaces the stop.Subagent B (blue, still running): this row never got a terminal event that the fold kept. The new process starts with an empty live-task set, so the shutdown sweep doesn't cover it.
background_tasks_changedis the roster snapshot the SDK says hosts should reconcile with after a CLI restart, but T3 currently ignores it on purpose. So nothing ever corrects the missing bookend. The 28m 57s timer counts from the original 09:04 start, which matches what you saw.How this differs from the open PRs:
SendMessagetool use. That covers [Bug]: A Claude subagent resumed with SendMessage stays "completed" or "failed" in the Agents panel (regression of #5529) #14002, but it wouldn't settle these rows.Likely fix: keep
reason: "worker_restart"and don't treat a restart-timestoppedas final, so a latercompletedorfailedfor the same task can set the status,completedAt, and summary. Also reconcilebackground_tasks_changedafter the new process starts so a missed completion can't leave a timer running.There's no workaround in the panel yet. As you noted, the subagent transcript or the main agent's report shows the real result.
test(client-runtime): cover a subagent resumed after its Claude proce…
navidnadali commentedon Oct 2, 2026
Reproduced on
main(54084ae) in an isolated dev server with Claude Code 2.1.287:stoppedfor the live subagents. The resumed CLI then reports each orphan again asstopped, with "Background agent … didn't finish before the previous session ended". That notification carries noreasonand notool_use_id, so keying onworker_restartwouldn't catch this path.SendMessage. That emits anothertask_startedfor the same task under theSendMessagecall'stool_use_id, which is the [Bug]: A Claude subagent resumed with SendMessage stays "completed" or "failed" in the Agents panel (regression of #5529) #14002 mechanism.main, both rows stay grey "Stopped" after the subagents finish ("alpha done", "beta done").#14696 settles both rows as completed, run 2, with their real result and duration. I've added a regression test with these exact rows, plus before/after captures and a recording, to that PR.
I couldn't reproduce subagent B, the row that keeps running. In every run, the sweep and the orphan notification settled it. @caitlon, if you still have
~/.t3/userdata/logs/provider/events.<threadId>.logfor that thread, B's rows around the restart would show which bookend went missing.@juliusmarminge, would you be OK merging #14696 for #14002 and for subagent A here, and keeping this issue open for B? #14696 has passed triage and Macroscope approved it. Its CI workflows are waiting for approval to run, since it comes from a fork.
caitlon commentedon Oct 2, 2026
Thanks for digging in, @navidnadali. I still have the provider log for that thread (
events.f43327d0-….log, desktop 0.0.44). Here are the canonical task events for the two rows. Times are UTC, and I trimmed the summaries:Two things in it differ from your repro:
stopped, A got a realcompletedat 09:05:58. NoSendMessageand no secondtask_startedcame in between. So in this run the orphan did continue without being resumed, and the latecompletedwas the only event that could have settled the row. fix(client-runtime): a resumed Claude subagent no longer stays failed or stopped in the Agents panel #14696 may not cover A if it keys on a newSendMessagetool use.task.startedat 09:04:11 andtask.completedwith statuscompletedat 09:11:37. At 09:33 the panel still showed it as working, with the timer counting from 09:04. So no event was missing. The completion was in the provider log and never reached the row.A setup detail that may explain B: on this machine two T3 servers were running against the same
~/.t3/userdataat the time, the desktop app's backend and at3 servebackground service. That is the condition in #14115, where each server runs its own provider session for the same thread. If the client was attached to the server that did not own this session, its projection would never see B'scompleted, which would also explain why you can't reproduce B with a single server. I haven't confirmed which server the window was attached to.I can share more lines from this log if you need them. I'd rather not attach the whole file, because it contains the full conversation.
juliusmarminge commentedon Oct 2, 2026
Thanks for the detailed timelines and the additional log excerpt. They make the two cases much clearer.
The orchestrator V2 rewrite has now landed in #2829. It removes the Agents panel and the V1 provider/status-folding paths investigated in this report. Subagent state is now shown through Lineage and the V2 projections, so I am closing this as an obsolete V1 report. Our earlier cleanup missed this one.
This does not establish that every restart or multi-server status problem is fixed. If you see the same symptom on a build containing V2, please open a fresh issue with the build, what Lineage shows, and whether multiple servers share the same data directory. Please link this report so the timelines and the distinction between A and B are preserved. A small, redacted log excerpt like the one above is enough; there is no need to share the full conversation.