[BUG] Desktop session list: untitled sessions are titled from the raw first prompt with no disambiguation — automated runs collapse into dozens of identical rows
Summary
After using Import CLI sessions, the Desktop session list contained large blocks of
visually identical rows. Sessions that have no customTitle are titled from the first
~55 characters of the raw first prompt, truncated, with nothing appended to tell them
apart — no date, cwd, branch, or index.
Any session driven programmatically (agent harness, scheduled task, eval loop) starts
with the same long preamble, so N such sessions render as N indistinguishable rows.
In my list, one preamble produced 49 identical rows and another 35.
This is not the same as #83051. On this build customTitle is imported correctly —
I verified 273 of 274 titled sessions match their CLI transcript exactly, and the
Desktop record does now contain title + titleSource fields (#83051 reports the
record having "no title field of any kind", which appears to be fixed on 2.1.222).
The defect here is purely the fallback path for sessions that never had a title.
Environment
- Claude Code CLI
2.1.224 - Desktop-bundled claude-code
2.1.222 - Claude Desktop
1.26832.0(macOS 15.5 / Darwin 25.5.0, arm64) - Auth: claude.ai subscription
Steps to reproduce
- Create several CLI sessions whose first prompt begins with an identical long
preamble and which are never /renamed. Anything programmatic does this naturally:
```bash
for i in 1 2 3 4 5; do
claude -p "You are assisting an operator inside the <repo> repository.
## Your capabilities this turn
You have NO filesystem, shell, git, or search tools. The host supplies file
contents below and applies any edits you return.
...
## Operator message
Task $i" ; done
```
(Scheduled tasks reproduce it too — their prompt opens with a
<scheduled-task name="..." file="..."> wrapper.)
- In Desktop, open a session and click Import CLI sessions.
- Look at the sidebar.
Expected: the rows are distinguishable — e.g. preamble text is skipped in favour of
the first genuinely user-authored turn, or the row is disambiguated with cwd / branch /
timestamp.
Actual: every one of those sessions renders as the same truncated preamble string.
Evidence
Across ~/Library/Application Support/Claude/claude-code-sessions/**/local_*.json
(1222 records) cross-referenced against ~/.claude/projects/*/<uuid>.jsonl:
titleSource histogram auto 711 | <none> 510 | user 1
distinct titles 991 across 1222 records
top titles (count × value)
105 × "Heartbeat" <- scheduled task
49 × "You are assisting an operator inside the <redacted>" <- agent preamble
35 × "You are <redacted>, a calm outreach co-pilot. In ONE" <- agent preamble
4 × "Call the wt_list tool now, then call wt_read on READ"
3 × "Call wt_list now. Then list your exact tool names. B"
Confirming the customTitle path itself is healthy on this build:
transcripts WITH a customTitle
desktop title == customTitle : 273
desktop title != customTitle : 1 (benign " (fork)" suffix)
no customTitle in transcript : 224 <- these are the colliding rows
So ~224 untitled sessions all fall through to prompt-prefix titling, and the ones from
repeated automation collapse onto each other.
Why the current fallback is the wrong source
For a human-typed session the first prompt is a reasonable title. For a machine-driven
session the first prompt is boilerplate, and the distinguishing content (the actual task)
sits hundreds of characters later — past the truncation point. The transcripts contain
no summary record to fall back to (0 of 501 files in my ~/.claude/projects have one),
so the title is the only differentiator the sidebar has, and it carries zero signal.
Suggested fixes (any one would resolve it)
- Disambiguate on collision. If a derived title already exists in the list, append
the cwd basename / branch / relative time. Cheap, no heuristics.
- Skip boilerplate when deriving. Prefer the first user turn that isn't the
session-opening programmatic prompt — in practice, skip queue-operation content and
<scheduled-task …> wrappers when a later human turn exists.
- Derive from the transcript, not the prompt. Generate a short auto-title the way
titleSource: "auto" already does for interactive sessions, and apply it to imported
sessions too rather than leaving titleSource unset (510 records here have no
titleSource at all).
Impact
The list is the only way to find a past session in Desktop. With ~7% of rows sharing one
string and another ~3% sharing a second, "which of these 49 was the one I want?" is only
answerable by opening them one at a time.
---
Adjacent but distinct, for triage:
- #83051 — customTitle dropped on import → "General coding session". Different fallback
string, and the title/titleSource fields it reports as missing are present on 2.1.222.
- #32150 — last-prompt text overriding an existing custom-title (VS Code/Linux). Here
there is no custom title to override.
- #59248 — silent retention cleanup. Related only in that it left 724 of my 1222 rows
pointing at deleted transcripts ("Session not found on disk"); not part of this report.