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
Summary
A Claude agent can end its turn waiting on a background task (run_in_background) and rely on the completion notification to wake it. If the backend dies in the meantime, the task dies with the agent process. Recovery records exactly what was lost, but the thread stays idle and looks finished. The agent only learns about it when the user next sends a message. In our case a triage thread sat like that for 27 minutes until I noticed it was stuck.
Visual explainer with the full timeline: https://post.patchyhq.com/d/078j555zejie
Steps to reproduce
- In a Claude thread, ask the agent to start
until [ -e /tmp/release-b ]; do sleep 1; donewithrun_in_background: true, then end its turn and wait for the notification. - Once the turn has ended,
kill -9the backend from a terminal outside T3 (its pid is in~/.t3/userdata/server-runtime.json). Let the desktop restart it. touch /tmp/release-band wait.
"Continue threads after restarts" is at its default (off).
Expected behavior
The thread is woken with the cancellation note, or at least shows that its background work was lost.
Actual behavior
The run stays completed and the thread stays idle indefinitely. Recovery stored the loss correctly on the run straight away:
restartCancelledBackgroundWork: [{"kind":"shell","label":"Wait for release-b then record time (id b6w74smo0)","id":"b6w74smo0"}]
Nothing woke the thread. In the original incident, the note reached the agent only when I nudged it 27 minutes later:
Note: the T3 server restarted, and this background work was cancelled before it finished. It will not report back: - shell: Wait for codex trace to finish (id btuwr7ruo)
Cause
RestartBackgroundNote.ts:87builds the note, andProviderTurnStartService.ts:1127prepends it to the next user input.- The automatic path exists (
ProviderRuntimeRecoveryService.ts:635→RestartContinuation.ts:120), but it is gated oncontinueThreadsAfterServerUpdate, which defaults tofalse(packages/contracts/src/settings.ts:1206).
An agent that ended its turn waiting on a task has handed control to that task's notification. Waiting for the user is always wrong in that case, whatever the setting.
The same blind spot affects orchestration. t3_thread_wait returns once the latest run is terminal (ThreadManagementService.ts:610), and t3_thread_read doesn't expose pendingBackgroundTasks (orchestrationV2.ts:831). Our orchestrating thread got completed for this child while it was still waiting on its codex job, and had no way to see that the child had been stranded.
Possible fix
- When recovery cancels a thread's background tasks, always continue that thread with the note, whatever the setting. If that's too aggressive, show a "background work lost" state in the sidebar.
- Return
pendingBackgroundTasksandrestartCancelledBackgroundWorkfromt3_thread_readandt3_thread_wait, so orchestrators can tell "done" from "waiting" and "stranded".
Related
- PR fix(server): restarts keep delegated tasks, queued threads, and stops intact #15323 makes restart continuation keep delegated tasks and carry this note, but only with "Continue threads after restarts" on. With it off, this repro behaves the same.
- [Bug]: A Claude thread waiting on a background command sends a false "Thread completed" alert #15099: background Bash counts as done, so a waiting thread sends a false "Thread completed" alert. It's the same blind spot as the
t3_thread_waitpoint. - [Bug]: Idle-session reaper kills a session whose sub-agent is still running a background job #15235: the idle-session reaper kills a sub-agent's background job, and nobody is told.
- [Feature]: Pause, update, and resume active threads as one operation #15186: feature request for one operation to pause, update and resume active threads.
Impact
Major degradation or frequent failure
Version or commit
0.0.46-nightly.20261003.2632 (f391794), Orchestrator V2
Environment
Linux 7.2.5 (Arch-based), desktop AppImage, Claude Code 2.1.288 via Agent SDK 0.3.276, Claude Opus 5.5
Workaround
Turn on Settings → General → "Continue threads after restarts", or send any message to threads that were waiting when the backend restarted.
Related reports from the same incident: #15357 (agents that were mid-turn survive the crash and keep working, unseen), #15359 (a killed backend is logged as "Failed to read the exit status").
Filed by Allison Mahmood. Investigated and drafted with Claude Opus 5.5 in Claude Code.
Activity
juliusmarminge commentedon Oct 3, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the clear repro and timeline, @allisonmahmood! This reproduces on current
mainwith "Continue threads after restarts" at its default (off). Open PR #15323 only delivers this note when that setting is on, so it doesn't cover this case.What happens
Startup recovery always clears the provider-thread roster and writes
run.background-work-cancelled. That's therestartCancelledBackgroundWorkrow in your report. It only enqueuesprovider-runtime.continuewhencontinueThreadsAfterServerUpdateis on for the project, andcontinueRestartedRunchecks the same setting again, so with the default nothing is sent.A turn that had already finished then stays
completed. Nothing in the web UI readsrestartCancelledBackgroundWork, and clearingpendingBackgroundTasksremoves the only "still working" signal, so the thread looks idle.ProviderTurnStartServiceadds the note to the next user turn, which is why it only showed up after your nudge.The wake itself already exists. A
completedorwaitingrun that lost background work is continued with the cancellation note, and the setting is the only gate.The
t3_thread_read/t3_thread_waitgap is real but separate. Wait returns once the latest run is terminal, and neither result includespendingBackgroundTasksorrestartCancelledBackgroundWork. A parent can see a child as done while it's still waiting on a background command, even without a restart. That's the same blind spot as #15099.Likely fix area
t3_thread_readandt3_thread_wait, could be handled separately.This isn't a duplicate of #15235, #15357, or #15359. Your workaround is the right one for now. A maintainer will decide on the fix direction.
SunkenInTime commentedon Oct 4, 2026
I opened #15438 to wake these threads even with Continue threads after restarts off, and I'm closing it. Two reasons:
claude.exedie with the server while the background command it had started kept running.Proposal: keep automatic continuation opt-in and make the loss visible instead.
restartCancelledBackgroundWorkon the run. Show the thread as needing attention ("Background work lost") on web and mobile rather than idle, with an action that sends the note.t3_thread_readandt3_thread_wait, so an orchestrator can tell a stranded child from a finished one (overlaps [Bug]: A Claude thread waiting on a background command sends a false "Thread completed" alert #15099).Does that direction work for you? If so I'll build it. #15438 also had two fixes that apply when the setting is on: a settle racing a restart continuation could reopen the thread, and a Stop followed by a steer blocked recovery of the steered attempt. I can send those as a separate PR.
t3dotgg commentedon Oct 21, 2026
Note
🤖 Claude Opus 5.5 responding on behalf of Theo
Thanks for the report. This behavior is intended, so we will not change it. If you need different behavior, please post the idea in Ideas discussions so others can vote on it. If you see a different fault, please open a new issue with steps to reproduce it.