[BUG] Session forking (backgrounding/resume) has no parent-child linkage — compounds into unbounded duplicate-named entries for recurring jobs

Status Open
Maintainer reply None cached
Activity 3 comments · opened Aug 8, 2026

Summary

Backgrounding a session, resuming from Agent View, or /resume in general all fork a new session ID that continues the conversation — but none of these surface any link back to the session they forked from. For a one-off fork this shows up as mild confusion (which of these two identically-named entries is current?). For a named background job that gets restarted/resumed repeatedly, it compounds into an unbounded, ever-growing list of same-named, unlinked entries with no way to tell which is live.

Evidence

Confirmed directly in local session transcripts: forking writes "Backgrounding after the current tool finishes…" as the terminal entry of the parent session, then the child session's first records (ai-title, agent-name) carry the identical display name forward with no reference to the parent session ID. One recurring named job in my own history has forked across 5+ session IDs over ~2.5 months, all showing identically in the session list.

Related issues (likely same root cause, different symptoms)

  • #78264 — /resume forks duplicate custom titles onto new session IDs
  • #70373 — backgrounding with in-flight subagents forks and orphans the original
  • #83971 — backgrounding seeds the new job with only the last prompt, dropping prior context
  • #76493 — resuming from Agent View forks (new id), freezes the original, empties the task list

Suggested fix

Either (a) collapse fork chains into a single thread in the session list with the ability to expand history, or (b) at minimum surface a "continued from" / "continues to" link between parent and child sessions so stale forks are identifiable and the relationship is discoverable.

Impact

Session list becomes unbounded clutter for any workflow that relies on repeatedly backgrounding/resuming the same logical task — which is exactly the pattern background jobs and named recurring tasks are meant to support.

View original on GitHub ↗

3 Comments

ddanderson · 2 months ago

Independent confirmation of this, with the structural evidence for the parent-child link and a
version data point that may help bisect it.

Same terminal entry, and the child's first record shares the parent's parentUuid. On
2026-08-05 under 2.1.222, a session backgrounded while a long foreground Bash call was in
flight (no subagents involved):

| time (UTC) | session | event |
|---|---|---|
| 17:12:09 | d9dc26b3 | assistant issues a Bash call expected to run ~8 minutes |
| 17:18:14 | d9dc26b3 | system record, level: warning: "Backgrounding after the current tool finishes…" — Ctrl-B |
| 17:18:32 | 4092f917 | new session id re-issues the same command (identical but for a head -20) |

The two transcripts share an identical 212-record prefix, and the first divergent record on each
side has the same parentUuid. So the lineage does exist in the data — two children of one
parent record — it is simply never surfaced. That may be an easier hook for the fix than titles:
the child's first divergent record already points at the parent.

Possible fix already landed, worth checking before you dig. Under 2.1.227 I backgrounded a
long foreground Bash call the same way and it did not fork: the conversation continued in the
same session id, a task id was returned, and no new transcript file appeared. Related #70373 was
filed against 2.1.186 and last updated Aug 7, so nobody there has noted this. If the fork is fixed,
the linkage gap described in this issue still stands for every already-forked session in
~/.claude/projects — mine still lists a dead branch and its live continuation as peers.

What the missing linkage actually costs, beyond duplicate names. claude -r offered three
entries for one directory; two were this fork pair (one abandoned Aug 5, one active through Aug 8).
I picked the first and got the dead branch. That silently reinstated a four-day-old view of the
working tree
: the resumed context described work as unimplemented that the live branch had since
committed. The assistant continued on that basis and re-derived work that already existed, reporting
it as newly done, until we audited file mtimes, git log, and the transcripts — about an hour lost,
and several confidently wrong status reports along the way.

That last part is why I'd argue ordering matters as much as linkage. Concretely, in priority order:

  1. Order the list by most recent activity, best choice first. Position in the list is the only

signal most users will act on.

  1. Mark a superseded fork — "continued as …" — or collapse it under its live descendant.
  2. Show recency and size so a fork pair is recognisable as one conversation rather than two.

One data point that contradicts a related issue: #82489 reports the child session having no
transcript. Here the child had the parent's prefix duplicated in full (consistent with #85179's
"forks duplicate ~90% of content"). Same trigger, opposite symptom — possibly two distinct paths
worth separating during triage.

Environment: Linux, entrypoint: cli, versions 2.1.222 (forked) and 2.1.227 (did not fork). Happy
to provide redacted transcript excerpts; the files themselves contain proprietary source.

DanielRashi · 1 month ago

Corroborating data point, macOS, VS Code terminal, reported from 2.1.235. Adds a detail beyond ambiguity: the picker's timestamp is actively wrong for the stale fork.

Fork observed in transcripts:

  • Parent: 10064 lines, 3 in-file compactions (lines 2014 / 3962 / 8992). Last real message 2026-08-18T07:55:31Z.
  • Child: line 21 is a copy of the parent's line-8992 isCompactSummary, followed by 749 message uuids shared with the parent; new turns begin at line 791. Last message 2026-08-18T18:47:23Z.
  • Child inherited customTitle verbatim. Both rows render identically.

New symptom: /resume labels rows by file mtime, and the parent's mtime is 2026-08-18T19:07Z — 11h11m after its last message. The parent's final 6 lines are timestamp-less metadata records (agent-name, mode, permission-mode, pr-link, last-prompt), so metadata appends bump mtime with no conversation activity. Result: parent and child both displayed "9 hours ago" despite an 11h gap in actual last message. The only distinguishing field left is file size, which does not indicate recency — the parent is 22.5MB and stale, the child 5.1MB and current.

Consequence beyond clutter: resuming the parent branches a third file from a point 11h stale, silently stranding the child's work. A user picking by displayed time has no signal that distinguishes them.

Constraint any fix must satisfy: the row's timestamp needs to come from the last conversation message, not file mtime — otherwise parent/child linkage alone still leaves two rows claiming the same recency.

webby-box · 1 month ago

session forking with no parent-child linkage turns recurring jobs into duplicate-named clones.

treat "ping failed" as retry-message, not spawn-another, until a real liveness check says dead.