[BUG] Agent View: reopening a stopped/completed background session respawns with a new session-id, prior conversation is lost (v2.1.195, macOS)

Status Open
Reported on v2.1.193
Maintainer reply None cached
Activity 5 comments · opened Jun 28, 2026

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

  1. Launch a background agent (e.g. via claude --bg or the agents view). Let it accumulate a real conversation.
  2. Stop / let the turn complete so the job leaves the working state (stopped or done in ~/.claude/jobs/<id>/state.json).
  3. Reopen that session from Agent View.
  4. 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.

View original on GitHub ↗

6 Comments

github-actions[bot] · 2 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/68435
  2. https://github.com/anthropics/claude-code/issues/58361
  3. https://github.com/anthropics/claude-code/issues/65216

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yurukusa · 2 months ago

You've already established the load-bearing fact — the original conversation isn't lost, it's intact at ~/.claude/projects/<project>/<original-session-id>.jsonl and 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 .jsonl is fully resumable:

claude --resume <original-session-id>

or just claude --resume and 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 --resume away.
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):

ls -lS ~/.claude/projects/<project>/*.jsonl | head

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 --resume the 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.)

caioribeiroclw-pixel · 2 months ago

This looks closely related to the Desktop </> Code continuity/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:

before_stop:
  desktop_app_version:
  claude_code_version:
  project_path:
  visible_agent_session_id:
  backing_transcript_file: ~/.claude/projects/<encoded-project>/*.jsonl
  last_real_user_turn_timestamp:
  last_assistant_turn_timestamp:

after_reopen:
  visible_agent_session_id:
  backing_transcript_file:
  did_old_jsonl_append? yes/no
  did_new_jsonl_get_created? yes/no
  does UI show prior turns? yes/no
  does model answer as if prior turns are loaded? yes/no
  first generated turn after reopen:

The key fork is:

  1. same transcript keeps appending, but UI/model context starts empty → session rehydration/index link bug;
  2. new transcript file is created and old one stops appending → respawn/new-session routing bug;
  3. old transcript has synthetic/no-op continuation markers → reload attempted continuity but did not rehydrate real context.

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.

ozwxy · 2 months ago

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.195
  • project_path: ~/Workspace
  • visible_agent_session_id: c2147de7-561d-4ef9-a01a-85b9eef5b53f
  • backing_transcript_file: ~/.claude/projects/-Users-oz-Workspace/c2147de7-561d-4ef9-a01a-85b9eef5b53f.jsonl
  • size_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 place
  • size_after: 2873 bytes / 8 lines
  • line types: system / last-prompt / ai-title / agent-name / agent-setting / mode / permission-modezero user/assistant message entries

So 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.json has no parentId / respawnOf linking the stub back to prior turns — only linkScanPath pointing at the session's own (now-truncated) transcript.
  • Attaching to a still-running background session works correctly (roster launches it with mode: resume + correct sessionId/transcriptPath). The regression is specific to reopening a stopped/completed session.
  • Reproduced on multiple sessions today (e.g. b81ae067, f441788b show the identical 6-8 line metadata-only stub pattern).
  • Workaround: 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.

caioribeiroclw-pixel · 2 months ago

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:

  1. Reopening a stopped/completed Agent View session must be append-only with respect to the existing transcript, or copy-on-write into a new transcript/session.
  2. A metadata-only launch stub should never overwrite a transcript file that already contains real user/assistant turns.
  3. If the product intentionally cannot resume a completed background session, it should create a new sessionId/transcript and link it with respawnOf/parentId, while preserving the old transcript read-only.
  4. Before any rewrite, the loader can cheaply gate on previous transcript size/message counts: if prior_user_turns > 0 || prior_assistant_turns > 0, a replacement containing only system/settings rows should fail closed or write a backup first.

A minimal regression test would be:

create background agent transcript with N user/assistant turns
mark job stopped/completed
reopen through Agent View
assert same transcript path still has >= N real turns
assert no metadata-only stub replaced it
assert any new live session has explicit parent/respawn link

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.

MySethPorter · 2 months ago

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:

// ~/.claude/jobs/<id>/state.json
"state": "failed",
"detail": "source session /Users/<me>/.claude/projects/-Users-<me>/<session-id>.jsonl not found",
"template": "bg",
"respawnFlags": [ ... ]

The referenced .jsonl exists at exactly that path. I checked every one of my failed: source session not found jobs:

  • 13/13 referenced transcripts are present on disk
  • 0/13 actually missing
  • The present files are full and intact (e.g. one is 9.6 MB / 517 assistant turns; another a complete 59-turn chat). The internal "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 fresh bg respawn — 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 found on a file that exists.