[BUG] Agent View: reopening a stopped/completed background session respawns with a new session-id, prior conversation is lost (v2.1.195, macOS)
Environment
- Claude Code: v2.1.195 (latest stable)
- Platform: macOS (Darwin 27.0)
- Launch: background agents via Agent View (
claude agents/ fleet roster)
Summary
When a background session that has been stopped or completed is reopened from Agent View, Claude Code spawns a new session-id and only injects the original launch intent/prompt. The prior conversation is not carried over, so the session appears empty and the initial prompt is re-sent — effectively restarting the task from scratch.
This happens at sub-compact context sizes (a few KB of transcript), so it is unrelated to auto-compaction.
Reproduction
- Launch a background agent (e.g. via
claude --bgor the agents view). Let it accumulate a real conversation. - Stop / let the turn complete so the job leaves the
workingstate (stoppedordonein~/.claude/jobs/<id>/state.json). - Reopen that session from Agent View.
- The reopened session has a different session-id from the original, shows only the first prompt, and the conversation history is gone.
Evidence
The original conversation is not actually deleted — it still exists at ~/.claude/projects/<project>/<original-session-id>.jsonl (large file). What gets created on reopen is a stub transcript under a new session-id containing only metadata (system, mode, ai-title, agent-name, agent-setting, permission-mode) with zero user/assistant message entries:
$ wc -l < .../<stub-id>.jsonl
8
$ # type breakdown: system / system / last-prompt / ai-title / agent-name / agent-setting / mode / permission-mode
Meanwhile the original (e.g. ~900 KB, dozens of messages) remains intact under the old id. ~/.claude/jobs/<id>/state.json records only linkScanPath pointing at the session's own transcript — there is no parentId / respawnOf field linking the stub back to the original conversation.
~/.claude/daemon/roster.json shows live workers correctly launched with launch.mode: "resume" and the right sessionId/transcriptPath, so attaching to a still-running background session works fine. The regression is specific to reopening a stopped/completed session.
Expected
Reopening a stopped/completed background session should resume the original transcript (same session-id, full history), not spawn an empty stub with a new id.
Workaround
claude --resume <original-session-id> restores the full conversation. Users must manually locate the original id from ~/.claude/projects/<project>/*.jsonl.
Related
- #71729 (history silently lost on restart — Claude doesn't detect the gap; Windows/Desktop variant of the same symptom)
- #65969 (auto-injected "Continue from where you left off" synthetic turn)
- #27242 (data preserved but UI inaccessible)
- changelog 2.1.193 / 2.1.195 partially address background-job data loss but this reopen path still regresses on 2.1.195
Happy to provide sanitized copies of the stub vs. original transcripts if useful.
6 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
You've already established the load-bearing fact — the original conversation isn't lost, it's intact at
~/.claude/projects/<project>/<original-session-id>.jsonland only Agent View's reopen created an empty stub under a new id. Two things worth adding, because the recovery and the data-integrity trap aren't obvious from the bug alone (I'm on Linux so I can't repro the macOS Agent-View respawn itself; the recovery path below is the environment-general part):1. You can get the real session back — don't rebuild it. The original
.jsonlis fully resumable:or just
claude --resumeand pick it from the list. The history, tool results, and accumulated context all come back. So while Agent View shows a stub, the work isn't gone — it's one--resumeaway.To find the original id when you have a stub + an original side by side, sort by size (the original is large, the stub is ~8 lines):
2. The trap: don't keep working in the reopened stub. If you continue in the stub (thinking it's the resumed session), the agent is operating on an empty context — it will redo work it already did, re-run the launch intent from scratch, and can repeat side effects (re-writing files, re-running commands) that the original turn already performed. That's the expensive failure mode here, not the cosmetic "history looks gone": it's a silent restart that looks like a continuation. Treat a reopened session that shows only the first prompt as a fresh run, back out, and
--resumethe original id instead.3. Minor cost note: re-injecting the launch prompt and restarting the task also re-bills the whole task you already paid for. Resuming the original id avoids paying twice.
So: cosmetically alarming, but non-destructive — the fix is
--resume <original-id>, and the thing to actually avoid is letting the agent continue from the empty stub. (The github-actions bot has this flagged as a possible dup of #68435 / #58361 / #65216 — worth a 👎 on the auto-close if you think the new-session-id-on-reopen specifics here are distinct.)This looks closely related to the Desktop
</> Codecontinuity/persistence failures in #71729, but the useful diagnostic for this report is slightly different because Agent View is explicitly respawning with a new session-id.If you can capture one short before/after run, I would separate three things:
The key fork is:
For the product behavior, the safest invariant is: if Agent View reopens a stopped/completed background session under a new session id, it should show an explicit continuity break before accepting edits or tool calls. Silent “new live session, old UI label” is the dangerous case because the user cannot tell whether constraints, task state, and prior tool results survived.
This would also make duplicates easier to classify: #71729 is mostly Desktop session-index / rehydration after restart or idle; this issue sounds like Agent View reopen is creating a new live agent session instead of reattaching to the prior one.
Thanks for the triage. Adding the before/after diagnostic requested — this issue is distinct from the duplicates (#68435 / #58361 / #65216) because the symptom here is same session-id transcript truncation in place, not a new session-id.
Diagnostic (v2.1.195, macOS, Agent View background agent)
before_stop
claude_code_version: 2.1.195project_path:~/Workspacevisible_agent_session_id:c2147de7-561d-4ef9-a01a-85b9eef5b53fbacking_transcript_file:~/.claude/projects/-Users-oz-Workspace/c2147de7-561d-4ef9-a01a-85b9eef5b53f.jsonlsize_before: 63762 bytes (8 real user turns, full conversation)after_reopen (Agent View → reopen the stopped session)
visible_agent_session_id:c2147de7-561d-4ef9-a01a-85b9eef5b53f(SAME id)backing_transcript_file: same path, overwritten in placesize_after: 2873 bytes / 8 linessystem/last-prompt/ai-title/agent-name/agent-setting/mode/permission-mode— zerouser/assistantmessage entriesSo the original 63 KB conversation was truncated to a metadata-only stub under the same session-id and same file path. The original turns are not preserved anywhere under that id.
additional notes
~/.claude/jobs/<id>/state.jsonhas noparentId/respawnOflinking the stub back to prior turns — onlylinkScanPathpointing at the session's own (now-truncated) transcript.mode: resume+ correctsessionId/transcriptPath). The regression is specific to reopening a stopped/completed session.b81ae067,f441788bshow the identical 6-8 line metadata-only stub pattern).claude --resume <original-session-id>— but in the same-id truncation case the data is already gone unless externally snapshotted.Happy to attach sanitized before/after transcript files if useful. Please keep this open — the same-id truncation variant is not covered by the proposed duplicates.
Thanks for posting the diagnostic — this is a much sharper failure than the original “new session id” hypothesis.
The important variant here is: same
sessionId+ same transcript path + in-place truncation to metadata-only JSONL. That is not just a rehydration/index bug; it is a persistence safety bug because the durable transcript object is being rewritten into a non-resumable stub.I’d separate the expected invariants this way:
user/assistantturns.sessionId/transcript and link it withrespawnOf/parentId, while preserving the old transcript read-only.prior_user_turns > 0 || prior_assistant_turns > 0, a replacement containing onlysystem/settings rows should fail closed or write a backup first.A minimal regression test would be:
The workaround note is useful too:
claude --resume <original-session-id>only helps before Agent View has overwritten the backing file. Once the same path is truncated, the failure has crossed from “resume picked wrong context” into “resume destroyed the only durable copy.” That seems distinct enough from the duplicate candidates to keep this issue open.Confirming this on v2.1.195 / macOS, with one additional surfacing the thread hasn't called out yet.
In my case the job doesn't just respawn quietly — the job record marks it failed, claiming the transcript is gone, while the file is physically present:
The referenced
.jsonlexists at exactly that path. I checked every one of myfailed: source session not foundjobs:"cwd"recorded in each transcript is the home dir, matching the-Users-<me>project folder it lives in.So in my variant this is non-destructive — the original transcript is being ignored, not truncated (unlike the in-place-truncation variant reported above). The resolver reports a present file as "not found," marks the job
failed, then falls back to the freshbgrespawn — which is why reopening "enter to resume" starts a blank agent with no recap and no summary/full-chat picker, contrary to the documented attach-with-recap behavior.Net: looks like the same root cause (Agent View link resolution failing to locate an existing transcript), with three observable surfacings depending on path: new-session-id stub, in-place truncation, and a hard
failed: source session not foundon a file that exists.