Background tasks panel: stopped tasks reappear as Running after session switch / refresh
Summary
In the Claude Code app's Background tasks side panel, clicking Stop on a Running task visibly moves it to the Completed section with status "Stopped" — but the change does not persist. After leaving and returning to the conversation (session switch, app refresh, or closing/reopening the panel), every task that was previously stopped reappears in the Running section with status "Running", even though no process is actually alive.
Net effect: dead background-task slots accumulate in the UI and can't be cleared. The list grows monotonically across the lifetime of a conversation and survives refresh/restart.
Environment
- macOS: 26.3 (build 25D125), Apple silicon
- Claude (desktop app): 1.7196.0
- Claude Code CLI: 2.1.142 (used as a tool; the UI in question is in the desktop app)
- Model in session: Opus 4.7 · Max
Reproduction
Trigger condition (how the dead-but-Running slots get created in the first place):
- In a Claude Code session, have the assistant call the
Tasktool to spawn a sub-agent. - Have that sub-agent call
Bashwithrun_in_background: trueseveral times. - Let the sub-agent finish and return.
Result of the trigger: the sub-agent's run_in_background Bash slots appear in the Background tasks panel as Running, indefinitely. ps on the host confirms the underlying processes are gone — no live PIDs. There appears to be no first-class way (no KillBash-equivalent surfaced to the orchestrator) to clear these slots programmatically, so the only path is the panel's Stop button.
The staleness bug (what this report is about):
- Open the Background tasks panel. Observe the dead tasks listed under Running.
- Click Stop on each dead task one by one. The panel updates correctly: each task moves to Completed with status "Stopped", and the bottom-bar "N shells running" counter decreases as expected.
- Click any other conversation in the left sidebar (or refresh the app, or close+reopen the panel — any of these reproduces it), then return to the original conversation.
- Open the Background tasks panel again.
Expected: the previously-stopped tasks remain under Completed with status "Stopped". Running shows only the tasks that are genuinely alive.
Actual: every task that was stopped in step 5 is back under Running with status "Running". The Completed section forgets they were ever stopped. The bottom-bar counter shows the full revived count.
Frequency
I've observed this multiple times over the past several days. Confirmed reproducible in the screen recording I'll attach as a comment.
Workaround
None that persists. Clicking Stop again works for the current view but the same tasks return on the next session switch / refresh.
Why it matters
- The Background tasks panel becomes unreliable as a status signal — you have to manually re-verify with
pswhether anything in Running is actually alive. - The "N shells running" counter at the bottom of the conversation is similarly misleading: it shows the stale-revived count, not the real count.
- Combined with the upstream issue (sub-agent
run_in_backgroundslots are not reaped when the sub-agent finishes), a single session can accumulate an unbounded number of phantom Running slots that survive every UI refresh, with no in-product way to clear them.
Hypothesis (where to look)
The Stop click handler appears to write to a transient in-memory state, while the panel's render on session open reads from a persisted source (per-session state on disk / server) that still records those slots as Running. Two likely shapes:
- The Stop action is not persisted at all — only the local view state is updated. On re-render the panel rehydrates from the unmodified persisted record.
- The Stop action is persisted, but to a layer that the re-render path does not consult, so the persisted "stopped" status is masked by a stale "running" record from another layer (e.g. the sub-agent's task ledger).
Either way, the persistence layer that backs the panel on open is the place to look.
Screen recording (what it captures)
27.86 s, 4096×2382 @ 120 fps. Sequence:
- t ≈ 0–11 s: I click Stop on each dead Running task; the panel correctly migrates each one to Completed/Stopped; bottom-bar counter "N shells running" drops correctly (from 8 → 6 → … → 2).
- t ≈ 11–17 s: The panel shows only the 2 genuinely-running tasks (two
subscribe-pr-mergeable.shMonitors) in Running; I close the Background tasks panel. - t ≈ 17–21 s: I click away to another conversation in the sidebar, then back to the original.
- t ≈ 21–27 s: I reopen the Background tasks panel — all 8 tasks are back under Running, including every one stopped in the first 11 seconds.
I'll attach the recording + a screenshot in a follow-up comment (file upload).
This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗