Background sessions: resume-by-id fails, four sessions share one name, version pins, and there is no documented way out

Status Open
Reported on v2.1.237
Maintainer reply None cached
Activity 4 comments · opened Aug 20, 2026

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_DIR set)

What happened

  1. Long-running session in one repo, named fix-test.
  2. Ran /branch todo-board. This forked to a new session id and kept working.
  3. Later wanted to quit and update Claude Code, then return to the same conversation.
  4. Quitting and resuming landed in a session with the same name but older content, missing hours of work.
  5. claude -r <correct-session-id> refused with an error (see problem 3).
  6. Eventually got back in via the agent view — the only entry listed as reachable.
  7. 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).
  • /branch marks which fork is current, or the picker does.
  • A running background session's pinned version is surfaced when an update is available.
  • claude agents can 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.

View original on GitHub ↗

4 Comments

colangelo · 10 days ago

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 --help for a kill flag and truncated the top-level claude --help output before reaching the relevant commands. They exist and are exactly right:

claude stop <id>     Stop a background session. Its conversation is kept;
                     resume it later with `claude attach <id>`.
claude attach <id>   Open the background session in this terminal.

There is also /stop in-session (vs /exit, which only detaches). So there is a clean way out, and the escape hatch I described — killing the bg-pty-host / bg-spare process 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 "with claude attach <id>". So the product knows background sessions use attach, not resume — but claude -r <background-session-id> still fails without ever mentioning attach. 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 --name of a background session at startup. So four background sessions sharing todo-board is 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.

colangelo · 10 days ago

Addendum: the correct commands are absent from claude --help

Following 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 --help prints a Commands: section listing: agents, auth, auto-mode, doctor, gateway, import, install, mcp, plugin, project, setup-token, ultrareview, update.

stop, attach, kill and rm are not in that list. They exist and are functional:

$ claude stop --help
Usage: claude stop <id>
  Stop a background session. Its conversation is kept; resume it later with `claude attach <id>`.

$ claude attach --help
Usage: claude attach <id>
  Open the background session in this terminal. ← returns to agent view, Ctrl+Z drops back to your shell.

$ claude kill --help
Usage: claude stop <id>          # alias of stop

$ claude rm --help
Usage: claude rm <id>

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 (-r failing without naming attach), a user holding a correct session id has no path from the tool itself to the correct command.

Suggested fix: list stop, attach, kill, rm in claude --help, and name attach in the -r failure message. Those two changes alone close this report.

colangelo · 10 days ago

Addendum 2: stop/attach take the job id, not the session id, and nothing says which

Third data point on the same discoverability theme, found by failing at it:

$ claude stop 344f4738-b333-44ba-9aeb-d5b29ab888db
No job matching '344f4738-b333-44ba-9aeb-d5b29ab888db'. Run 'claude agents' to list running sessions.

$ claude stop 344f4738        # the short *job* id — this is the one

claude stop --help and claude attach --help both say only <id>. But claude agents --json returns two identifiers for a background session:

{"id": "344f4738", "sessionId": "344f4738-b333-44ba-9aeb-d5b29ab888db", "kind": "background", ...}

/status shows the user only Session 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/attach accept either identifier (they are trivially distinguishable by length/format), or say <job-id> in the usage line and surface the job id in /status for background sessions.

colangelo · 10 days ago

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:

  • #59415 (2026-05-15, closed) — /resume picker permanently hides sessions marked sessionKind: "bg". Its stated workaround: "The only workaround is claude --resume <sessionId> directly with the UUID."
  • #65945 (2026-06-06, closed) — /resume is cwd-scoped and reports "Session not found" for sessions started elsewhere.
  • #68204 (2026-06-13, closed) — "Background-job sessions unrecoverable via --resume despite 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 are claude stop <job-id> / claude attach <job-id>.

So the previously-blessed workaround is gone, and the replacement is undiscoverable:

  • claude --help does not list stop, attach, kill or rm.
  • claude -r <session-uuid> fails without ever naming attach.
  • /status displays the session UUID — the exact identifier stop/attach reject 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.)