Custom session titles bleed across forked/resumed sessions and overwrite /rename names
Environment
- Claude Code 2.1.218 (CLI), Windows 11 Pro 10.0.26200
- Long-running project with many sessions, frequent
/resume, occasional forks
Summary
Custom session titles set with /rename are later overwritten in the resume picker by titles belonging to other sessions. Inspecting the ~/.claude/projects/<project>/<session-id>.jsonl transcripts shows "type":"custom-title" records from unrelated tasks appended to a session's file, and the same title re-stamped many times (apparently once per resume). The picker shows the last record written, so whichever window/lineage was touched most recently silently relabels its sibling forks.
Observed evidence (from the transcript files)
One long-lived session was renamed twice by the user, then relabeled by title records the user set on different tasks:
- Session A (122 MB transcript, 22 custom-title records):
Performance Improvements, and PRs 5549 + 5550 -> Performance Improvements, PR 5550 (both via /rename in that session) -> then six+ identical records of Analyze Nightly CDash test results (a name belonging to a different task) stamped after them. The picker now shows the wrong name.
- Session B (a fork of session A's lineage, 18 custom-title records):
Analyze Nightly CDash test results -> Review PR for SW-18634 — the second title belongs to a completely different conversation.
- Session C:
Review PR for SW-17136->Review PR for SW-18634(same cross-task overwrite pattern).
All records carry the sessionId of the file they sit in, i.e. the writer believed it was titling that session. The repetition (6/18/22 identical records) suggests the current title is automatically re-appended on every resume, so once a wrong title lands on a shared lineage it keeps propagating.
Expected
- A name set with
/renameshould stick to that session and never be replaced by a title from another session or by automatic re-stamping. - Forked/resumed lineages should not share title state.
Impact
The resume picker becomes untrustworthy for multi-session workflows — the user could no longer find sessions by the names they had set, and stopped using resume entirely. Workaround in use: resuming by raw session ID and keeping an external ID->topic map.
Repro sketch
- Start a session,
/renameit to NAME1. - Resume/fork the same lineage in another window,
/renamethat one to NAME2. - Resume each a few times.
grep '"custom-title"' ~/.claude/projects/<proj>/<id>.jsonl— both files accumulate repeated records, and the original session's effective title becomes NAME2.
3 Comments
Independent confirmation on macOS, v2.1.220 (you're on Windows 2.1.218, so it's cross-platform), plus a version bisect and the exact trigger. This looks like the same bug as #78264 part 2.
The re-stamping you noticed ("apparently once per resume") is actually once per turn — 17 identical
custom-titlerecords in a 400-line live session file here, 53 and 243 in older ones.The mechanism behind the bleed: when a new session id is created, the previous session's title record is written as line 1 of the new file, before any user message. Since the session then already has a title, no
ai-titleis ever generated for it, so the borrowed name sticks permanently and every subsequent turn re-writes it. That is also why/renamegets overwritten: whichever lineage the app holds in memory keeps stamping its own title into the file.Version bisect over my
~/.claude/projects/**, counting sessions whose first title record precedes their first real user message:| CLI version range | sessions | inherited a title |
|---|---|---|
| 2.1.156 → 2.1.202 (9 Jun – 8 Jul) | 21 | 0 |
| 2.1.204 → 2.1.220 (8 Jul – today) | 52 | 26 |
So it landed in 2.1.204 / 2.1.207.
One thing worth flagging because it sends you looking in the wrong place: the dominant trigger is
/new, but/newwrites itself into the transcript under its legacy name<command-name>/clear</command-name>. Here: 75 session files contain a/clearrecord and exactly 1 contains/new, while my typed-prompt history shows/clearunused since April 2026 and/newused 142 times since. Of 43 affected sessions:/new21, background-job dispatch 15,/branch~5,/compact1–2.Relaunching
claudeinstead of using/newavoids it — of 205 sessions started by a plain launch, none inherited a name.Hitting this too, on a third platform and a newer build. Two data points that may narrow the cause.
Environment: Claude Code
2.1.227, macOS (darwin 25.6.0), zsh, CLI. (This issue is Windows/2.1.218; #78264 is Linux/2.1.173 — so all three platforms, still present on 2.1.227.)1. Fork/resume is not required to trigger it
Both this issue and #78264 frame the bleed around
/resumeforking a lineage. My case has no fork and no resume in it at all:/clear, started a day apart (Aug 11 08:08 vs Aug 12 10:17), different first messages. Neither is a fork or resume of the other.ai-titlerecords in either transcript (grep -c '"type":"ai-title"'→ 0), so the ai-title-wins mechanism from #78264 isn't involved either.Titles below are pseudonymized; timestamps, line numbers and ordering are verbatim.
Session A — 517-line transcript, only two distinct
custom-titlevalues in its entire history:No
/renamewas issued in Session A at 08:27 — I was mid-conversation on an unrelated topic.Session B — same project directory:
Session B sets
'Feature work — component X'at 07:57:50. Session A is overwritten with that exact string 29 minutes later at 08:27:09, with no action from me in Session A.Matches the behaviour described here: the record sits in Session A's file carrying Session A's own
sessionId, and it's re-stamped on roughly every turn boundary afterwards (16 identicalcustom-titlerecords), which is why the wrong title reappears after/renamecorrects it.So fork/resume looks like one path to the bug rather than a precondition — plain concurrency in a shared cwd is enough.
2. Possible cause: a single per-cwd session record
~/.claude/sessions/contains only one record for this project despite multiple concurrent sessions in it, and it carries the bled-in name:If title writes resolve the target session through a per-
cwdrecord like this one, a rename in any session would land on whichever session owns that record — which would explain both the fork case reported here and the no-fork case above.Happy to supply the two real session UUIDs privately if that helps reproduce.
Another writer that bypasses
/rename, distinct from the ones described so far: the Remote Control bridge. On 2.1.234/2.1.235, Linux.The reports above cover
/new(recorded as/clear), background dispatch,/branchand/compact. Here the overwrite came from a source none of them names — a bridged session re-stamping the title from its cloud-side copy.What I saw
I renamed two archived sessions from the CLI. Both renames were written and both held. Hours later, without my touching either session locally, both were back to their original — identical — name. The tail of the transcript records it plainly:
I re-applied the rename; ~16 hours later it reverted again the same way.
Why the bridge is implicated
Two different local session files carry the same
bridgeSessionId:One cloud session id mapped onto two local sessions. And the file ends with:
Both reverts land immediately after a
bridge-sessionrecord with a bumpedlastSequenceNum, i.e. on bridge attach. The cloud copy keeps the old name and pushes it back down over the local one. Worth noting the session was not idle: assistant messages arrived in it from the phone/web while I considered it archived — so the bridge is not only relabelling, it is keeping "archived" sessions live.Two details that may help locate the fix
agent-nameis stamped alongsidecustom-title. There appear to be two title-resolution paths: the agent view (getLogDisplayTitle) starts withagentName, while the/resumepicker does not consult it at all. So a rename that only writescustom-titlecan leave the agent view showing the stale name even when/resumeis correct — the two views disagree. Any fix should update both, or the picker path should be the single source of truth.The collision check already exists but is not on this path. The binary contains:
So
/renamealready refuses to create two identically-named live sessions. The bridge write does not go through that check — nor, as far as I can tell, do the compaction and/newpaths described above. Routing every title write through the existing collision resolver would fix the visible symptom across all of these reports at once, independently of the separate question of why the titles are being copied.Impact
Same as the original report: the picker stops being trustworthy. In my case one conversation ended up in three files with the same name and the same first-message timestamp, and I answered in the wrong branch more than once.
I've fallen back to a
SessionStarthook that de-duplicates titles on disk. To be clear that this does not make the bug any less worth fixing: the hook relabels files, it does not stop them being created or bleeding into each other, it cannot merge a conversation that has already been split, it only runs after the damage, and it does nothing on claude.ai or mobile — which, given that the bridge is the writer here, is precisely where I need it. It buys back a readable list, not peace of mind.Filed separately as #87884: even with the naming fixed, compaction creating a second session at all is the thing I'd like to see go away — that issue covers the session-identity layer, this one the title layer.