Background sessions: resume-by-id fails, four sessions share one name, version pins, and there is no documented way out
Summary
A background agent session became effectively unrecoverable through the normal UI. Five individually-defensible behaviours combine so that the documented recovery path (resume by id) fails, the picker cannot disambiguate, quitting does not help, and updating appears not to take effect. This is not the first time; the pattern is reproducible enough that I can give exact ids and command output for every claim below.
The data was never actually lost — transcripts are append-only files — but there was no way to reach it from the product, which is arguably worse, because nothing on screen said so.
Environment
- macOS, Claude Code CLI on disk: 2.1.237
- Session reporting itself as: 2.1.235 (see problem 4)
Session kind: background job · attached(from/status)- Config dir:
~/.config/claude(CLAUDE_CONFIG_DIRset)
What happened
- Long-running session in one repo, named
fix-test. - Ran
/branch todo-board. This forked to a new session id and kept working. - Later wanted to quit and update Claude Code, then return to the same conversation.
- Quitting and resuming landed in a session with the same name but older content, missing hours of work.
claude -r <correct-session-id>refused with an error (see problem 3).- Eventually got back in via the agent view — the only entry listed as reachable.
- The resumed session still reports the old version, so the update still has not taken effect.
The five problems
1. The session picker's key is a name that is neither unique nor stored
claude agents --json for one working directory:
57b37eda-… name="colors" kind=interactive status=idle
344f4738-… name="todo-board-latest" kind=background status=busy <- the live one
489aff26-… name="todo-board" kind=background status=idle
6292243f-… name="todo-board" kind=interactive status=idle
f45fdb21-… name="todo-board" kind=background status=idle
Four sessions share the name todo-board. Worse, the name is not recoverable from the transcript files themselves — grepping the .jsonl for the name yields nothing, so a user cannot inspect the files to work out which row is which. The picker is the only place the mapping exists, and the picker only shows the ambiguous name.
2. /branch forks silently, with nothing marking which fork is current
/branch copies the transcript to a new id and leaves the original live. All three sessions in this lineage start at the identical timestamp and then diverge:
| session id | messages | last activity |
|---|---|---|
| c799bc93-744e-43bd-8cec-29a1241a2fee | 605 | frozen at the branch point |
| 6292243f-9479-441d-9be0-7ed843f8ae99 | 2027 | stops mid-session |
| 344f4738-b333-44ba-9aeb-d5b29ab888db | 3345 | the live one |
Picking either of the first two gives a real, plausible-looking conversation that is silently missing work. Nothing distinguishes them in the UI.
3. claude -r <correct-id> fails on a live background session, and the error does not say why
The id was correct — /status in the running session confirms 344f4738-b333-44ba-9aeb-d5b29ab888db. Resume still refused. The reason appears to be that this is an attachable running process, not a resumable transcript — a different lifecycle with the same-looking id.
If that is the intended behaviour, the error must say so: "this session is a running background job, attach via claude agents instead". Instead the user is left believing the id or the session is broken. (I did not capture the exact error text; happy to add it.)
4. A running background session pins its Claude Code version, with no indication
/status reports Version: 2.1.235 while claude --version on disk reports 2.1.237. The background session launched ~21h earlier and keeps running that binary, which is reasonable — but from the user's side "update Claude Code" simply appears not to work, repeatedly, with nothing explaining that a running background job must end first.
5. There is no terminate action for a background session in the CLI
I read the entire claude agents --help option list. It offers listing (--json) and dispatch defaults. There is no stop/kill/remove option. If the interactive agent view offers one, it is not discoverable from the CLI help.
The only reliable way I could find to end the session was killing the process pair directly:
9655 claude bg-pty-host (parent)
└─ 9678 claude bg-spare (the session)
Requiring kill on an internal process pair is not an acceptable escape hatch for a normal user.
Expected behaviour
- Resume by id either works, or fails with an error that names the actual reason and the correct command.
- The picker disambiguates same-named sessions (id prefix, message count, last-activity, live/stale marker).
/branchmarks which fork is current, or the picker does.- A running background session's pinned version is surfaced when an update is available.
claude agentscan stop a session it can list.
Why this compounds
Each item alone is a papercut. Together they produce a state where the user is told to resume, resuming yields stale content that looks correct, quitting does not release the session, updating does not apply, and the only exit is kill. That sequence is what turns a minor UX gap into lost trust — the user cannot tell whether their work still exists.
Suggested minimum fix
The single highest-value change is problem 3: make the resume error name the cause and the correct command. That alone converts this from "unrecoverable" to "one line of guidance". Problem 1 (show id prefix + last-activity + live marker in the picker) is a close second.
4 Comments
Correction from the reporter — problem 5 is wrong, please disregard it
I need to retract problem 5 ("there is no terminate action"). It is incorrect, and the mistake was mine: I searched
claude agents --helpfor a kill flag and truncated the top-levelclaude --helpoutput before reaching the relevant commands. They exist and are exactly right:There is also
/stopin-session (vs/exit, which only detaches). So there is a clean way out, and the escape hatch I described — killing thebg-pty-host/bg-spareprocess pair — is unnecessary and should not be repeated by anyone reading this.What this correction does not change — and arguably sharpens
Problem 3 is now the whole issue, and it is confirmed by the tool's own help text.
claude stop's description says the conversation is resumed "withclaude attach <id>". So the product knows background sessions useattach, notresume— butclaude -r <background-session-id>still fails without ever mentioningattach. A user holding a correct id is told, in effect, that their session is unreachable, while the right command is one word away and already documented in a sibling command's help.That single error message is the fix. Everything else in this report is a papercut around it.
Problem 1 turns out to be documented behaviour, which I think makes it worse rather than better. The docs state that same-name collisions are auto-renamed for interactive sessions, with an explicit exception: the check is skipped for the
--nameof a background session at startup. So four background sessions sharingtodo-boardis by design. The rename that protects interactive sessions is precisely the one background sessions do not get — and background sessions are the ones you are most likely to accumulate and least likely to remember.Problems 2 and 4 stand as written.
Sorry for the noise on problem 5 — I would rather correct the record than leave a wrong claim in a bug report.
Addendum: the correct commands are absent from
claude --helpFollowing up on my own correction — I found why I concluded there was no way to stop a background session, and it is not just carelessness on my part.
claude --helpprints aCommands:section listing:agents,auth,auto-mode,doctor,gateway,import,install,mcp,plugin,project,setup-token,ultrareview,update.stop,attach,killandrmare not in that list. They exist and are functional:So the entire documented lifecycle for background sessions — the thing this whole report is about — is invisible to
claude --help. You can only discover it if you already know the verb to type.This restores the substance of problem 5 in a narrower and more actionable form: not "there is no way to stop a background session", but "the commands that stop and reattach a background session are undiscoverable from the CLI's own help output". Combined with problem 3 (
-rfailing without namingattach), a user holding a correct session id has no path from the tool itself to the correct command.Suggested fix: list
stop,attach,kill,rminclaude --help, and nameattachin the-rfailure message. Those two changes alone close this report.Addendum 2:
stop/attachtake the job id, not the session id, and nothing says whichThird data point on the same discoverability theme, found by failing at it:
claude stop --helpandclaude attach --helpboth say only<id>. Butclaude agents --jsonreturns two identifiers for a background session:/statusshows the user onlySession ID: 344f4738-b333-44ba-9aeb-d5b29ab888db. So the id the product displays is precisely the id these commands reject. Interactive sessions have no job id at all, which makes the distinction easy to miss.To be fair, the error message here is good — it says "job", and it points at
claude agents. It just cannot rescue a user who has been shown one id and given a flag documented as<id>.Suggested fix: have
stop/attachaccept either identifier (they are trivially distinguishable by length/format), or say<job-id>in the usage line and surface the job id in/statusfor background sessions.Prior art — and why I think this is not simply a duplicate
I should have led with this search. There is a history here, all closed as completed:
/resumepicker permanently hides sessions markedsessionKind: "bg". Its stated workaround: "The only workaround isclaude --resume <sessionId>directly with the UUID."/resumeis cwd-scoped and reports "Session not found" for sessions started elsewhere.--resumedespite intact transcripts", auto-closed as a duplicate of the two above.Same shape as this report: an intact transcript that the product cannot reach, with no signal that it exists.
What has changed, and why I think this is worth a fresh look:
The escape hatch that #59415 documented —
claude --resume <session-uuid>— no longer works for background sessions. That is what I hit on 2.1.235/2.1.237. Background jobs now live under a job model with their own short id, and the working commands areclaude stop <job-id>/claude attach <job-id>.So the previously-blessed workaround is gone, and the replacement is undiscoverable:
claude --helpdoes not liststop,attach,killorrm.claude -r <session-uuid>fails without ever namingattach./statusdisplays the session UUID — the exact identifierstop/attachreject with "No job matching".That combination means a user in 2026-08 is worse off than the workaround in #59415 left them in 2026-05: they have a correct identifier, three commands that reject it, and no path from the tool to the right one.
If maintainers consider this a duplicate of the closed family, that is fair — but I would ask that the fix then cover the discoverability half, because the recoverability half appears to have been addressed while the "how would a user ever find out" half was not.
(Also noting for the duplicate bot: this comment is deliberate, not an attempt to dodge triage. Happy to close in favour of a canonical issue if one is reopened.)