[BUG] Backgrounding a conversation (left arrow) continues it under a new session id; --resume shows a stalled duplicate of the original

Status Open
Reported on v2.1.233
Maintainer reply ✓ Yes — claude[bot]
Activity 3 comments · opened Aug 19, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Moving a conversation to the background (left arrow in an interactive session) continues it under a new session id. The original transcript stops within a few seconds and remains in ~/.claude/projects/<cwd>/ as a separate file. Both then appear in the --resume picker with the same title, and picking the original reopens the conversation as it was at the moment it was backgrounded. Nothing in the picker or the session indicates that the id changed.

The conversation is not lost — it continues under the new id. The problem is that the old id looks like the same conversation and resumes a stalled copy.

Version: 2.1.233–2.1.235, macOS 26.5.1, zsh, iTerm2. Reproduced in a plain iTerm session with no wrapper. Also reproduced inside a tmux-based wrapper; behaviour is identical.

Reproduction

  1. claude, send one prompt (test), wait for the reply
  2. Press the left arrow. The screen switches to the session list with the banner "Your conversation moved to the background — enter opens it · esc returns to it · ctrl+c twice quits"
  3. Return to the conversation. All three ways behave the same: press esc; press Enter on the highlighted (same) session; or open a different session from the list and come back later
  4. ls ~/.claude/projects/<cwd>/ now shows two jsonl files whose first timestamp field matches to the millisecond. The original has stopped; the new file carries the conversation on
  5. claude --resume lists both with the same title

4 out of 4 attempts (esc, Enter, another session, and once in plain iTerm). 46 other sessions in the same project directory that were never backgrounded have no such twin.

Observed

Transcript files from one attempt (ids shortened; first timestamp of each file, last timestamp, line count):

5cfd35ef  first=03:15:56.647Z  last=03:16:13.286Z  26 lines   original, stopped
81ded1b0  first=03:15:56.647Z  last=03:21:38.639Z  46 lines   continues

~/.claude/sessions/<pid>.json for the same attempt:

pid 68531  sessionId 5cfd35ef…  kind:"interactive"  tmux:"…"  parkedJobId:"81ded1b0"
pid 53456  sessionId 81ded1b0…  kind:"bg"                      jobId:"81ded1b0"

So the interactive process records the new id as parkedJobId, and a second process of kind:"bg" runs under that id. The evidence block of #87131 (a different symptom) shows the same parkedJobId / jobId pair, so this is not specific to my machine.

Why it matters

  • In the --resume picker the two entries show the same title and differ only in age and size, so the stalled one is easy to pick. Resuming it opens a conversation that ends at the background move. In one real case that was five hours of work that appeared to be missing until the other id was found
  • The stalled file's mtime is still touched afterwards. Observed once: content ends 08-18 10:17 local, mtime 08-19 20:43, size 4,096,009 bytes. The picker showed it as "45 minutes ago" while its content was a day old. I have not identified what touches it
  • Inferred, not measured: a tool that remembers the original id and later runs claude --resume <original-id> (a tmux wrapper, a session manager) will reopen the stalled copy after a process restart, with nothing to warn it. I hit this through such a wrapper, which is how I found the issue

Expected

Either keep the session id across the background move, or make the stalled original distinguishable in the picker (and leave its mtime alone), so the two entries can be told apart.

View original on GitHub ↗

3 Comments

claude[bot] contributor · 1 month ago

Confirmed / reproduced on 2.1.235 (Linux): claude → one prompt → empty input → ← ("Your conversation moved to the background") → Esc back → send another prompt. The project directory then holds two transcripts with an identical first message and timestamp: the original stops at the moment of the switch and everything afterwards is written under a new session id owned by the background process. On exit the original file is written to once more, so its mtime jumps and claude --resume lists the stalled original first ("1 second ago"), above the live one, with the same title; only a bg tag and the size tell them apart. That also explains the "45 minutes ago" entry whose content was a day old.

#85004 tracks the broader ask for parent/child linkage between forked transcripts.

🤖 Generated with Claude Code

---
_Generated by Claude Code_

marcindulak · 19 days ago

For your information: the label reproduced on this issue does not prevent it from becoming stale and eventually auto-closed. See https://github.com/anthropics/claude-code/issues/87647 for details, and consider upvoting that for visibility.

This means to avoid auto-closing, this issue needs to acquire at least 10 thumbs up, or get new comments every time before the 14 days stale bot interval expires.

kirgene · 19 days ago

Still present on 2.1.258, 2.1.265 and 2.1.278 (Linux, x86_64). One long-running conversation was backgrounded three times over three weeks, and each move left a stalled original behind:

ebe073ac  (auto title)    stops  09-02  continued-in -> 52ed749a   v2.1.258
52ed749a  "<title> (2)"   stops  09-09  continued-in -> 90d97850   v2.1.265
90d97850  "<title> (3)"   stops  09-20  continued-in -> a9cee61b   v2.1.278
a9cee61b  "<title> (4)"   live (kind:"bg")

Each original ends with a continued-in record naming its successor:

{"type":"continued-in","timestamp":"…","sessionId":"90d97850-…","continuedInSessionId":"a9cee61b-…"}

so the linkage is on disk, but nothing in the UI follows it. The (2)/(3)/(4) suffixes are the documented agent-view name numbering, and are the only visible hint that anything forked.

Some additional details:

  1. The successor does not contain the full conversation. Each new transcript starts at the most recent compact_boundary of the original: the compaction summary plus the messages after it. Earlier history exists only in the stalled originals (each well over 100 MB here). Deleting the "duplicate" that looks stale in --resume loses the full record, and a session manager that treats the newest file as the whole conversation misses it too.
  1. Mtime touches. While the original interactive process stays alive it keeps bumping the stalled file's mtime without writing anything. 90d97850 has had the same size in bytes since 09-20 and its newest message is from 09-20, yet its mtime was refreshed on 09-26 to a whole-millisecond value (…:34.451000000). That suggests an explicit utimes, not a write. Every session file on the machine with such a whole-millisecond mtime from the same night belonged to a still-running claude process. Sessions with real writes had full-nanosecond mtimes. So the "45 minutes ago" ordering in the report is probably not limited to backgrounded sessions: any idle live process seems to refresh its transcript's mtime. I haven't traced this with strace.
  1. The orphaned terminal stays attached to the stalled id. The interactive process that performed the last hop (claude --resume 90d97850-…, running since 09-20) is still alive and registered in ~/.claude/sessions/<pid>.json as sessionId 90d97850-…, kind:"interactive", parkedJobId:"a9cee61b". A background worker on the same machine shows the handoff mechanism in its argv: --session-id <new> --fork-session --resume <old>.jsonl --reply-on-resume.

Expected, as in the report: keep the id across the background move, or have --resume, the picker and agent view follow continued-in so the stalled original is clearly marked, points to its successor, and isn't listed as a separate live conversation.