Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Summary
For Claude threads, the T3 thread title and the native Claude Code session name should always match, in both directions. The native name is the session's custom-title, the name claude --resume and /resume list. Today neither direction syncs:
| # | Scenario | Expected | Actual |
|---|---|---|---|
| 1 | T3 → native: rename the thread in T3 (sidebar, chat header, mobile, t3_thread_update) |
The native session gets the new name | The native name doesn't change |
| 2 | T3 → native: Regenerate title, and the generated title that replaces the first-prompt seed | The native session gets the generated name | The native name stays the 50-character first-prompt seed forever |
| 3 | Native → T3: /rename <name> in the thread |
The T3 thread title becomes <name> |
The chat shows Session renamed to: <name> and the sidebar keeps the old title |
Since #28910, T3 names the native session only once, when it is created, using the 50-character seed. As a result, every T3-launched Claude session appears in claude --resume as a truncated first prompt. The only way to line the two names up is to run /rename <sidebar title> by hand.
Steps to reproduce
- Start a new Claude thread with a prompt longer than 50 characters, and wait for T3's generated title.
- Check the native session name, either with
claude --resumein the project folder or from the lastcustom-titleentry in~/.claude/projects/<encoded cwd>/<session id>.jsonl. It is the truncated prompt followed by..., not the generated title (scenario 2). - Rename the thread in the sidebar. The native name doesn't change (scenario 1).
- Click Regenerate title. The native name doesn't change (scenario 2).
- Send
/rename Something else. Claude repliesSession renamed to: Something elseand the native session is renamed, but the sidebar keeps the T3 title (scenario 3).
Expected behavior
One name per thread, kept in sync both ways:
- T3 → native: every T3 title change renames the native Claude session, including a live one. That covers a manual rename, Regenerate title, and the generated title replacing the seed.
- Native → T3:
/rename <name>updates the T3 thread title as a user rename. A bare/renameuses the name Claude generates. - Neither direction undoes the other. For example, a T3 → native sync on the next turn must not revert a
/rename.
Actual behavior
Reproduced on the reporter's machine:
- Fresh thread. After a sidebar rename and then Regenerate title, the T3 title was
Sync T3 and Claude Session Titles. The session file still contained only the seed,custom-title: "T3 tem um bug. Se eu usar /rename na sessao, isso ...", and the running CLI appended that stale entry again after both changes. - Two other threads. The user had to copy the T3 title into Claude with
/renameby hand. After Regenerate title, a bare/renameproducedcompare-bun-oxc-biomerather than the T3 title. The sidebar never followed any/rename.
Root cause (main @ 691b970)
T3 → native
- The title reaches Claude only as the SDK
titlequery option, passed when T3 spawns the Claude process:title: turnInput.appThread.title(apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts:11043) feeds:1842-1843. This was added in perf(server): skip redundant claude session naming #28910. - That option only applies to new sessions. On resume, the persisted title takes precedence (
sdk.d.ts:2529-2537, SDK 0.3.321). Every spawn after the first one is a resume. - At the first spawn the title is still the 50-character seed.
provider-turn.startand thethread-title.generatejob run concurrently on the effect worker (EffectWorker.ts:885,:945-950), and the turn opens the query before the generated title lands. - Rename (
thread.metadata.update,Orchestrator.ts:4142-4214) and regeneration (thread.title.regeneration.complete,Orchestrator.ts:4438-4446) only update the projection, and nothing reaches the adapter. The title is also not part of the live-query reuse key (ClaudeAdapterV2.ts:10967-10972,:3017-3044), so a rename never touches the live process.
Native → T3
/renameappears in the composer menu (taken from the SDK'sinit.commands) and is sent to Claude verbatim.isNativeMaintenanceCommandonly special-cases/compactand/logout(CommandPolicy.ts:61-70).- In response, the CLI emits
{type:"system", subtype:"session_title_changed", title}and aresultwithlocal_command: "rename".session_title_changedisn't in the SDK 0.3.321 typings, but the SDK passes it through and it shows up in T3's provider logs.ClaudeAdapterV2only special-caseslocal_command === "compact"(:10069), and nothing inapps/serverorpackageshandlessession_title_changed. ProviderAdapterV2Eventhas no event that retitles the root thread (packages/provider-core/src/server/ProviderAdapter.ts:83-204).customTitleis read only when a session is imported (AgentSessionScanner.ts:338-352,:648).
Proposed fix
- T3 → native (live session). Before each turn, compare
appThread.titlewith the title last applied to the live query. If they differ, send the CLI'srename_sessioncontrol request:{subtype: "rename_session", title, source: "host"}(SDKControlRenameSessionRequest,sdk.d.ts:5280-5295; the runtime Query object exposes it as an undeclaredrenameSession(title)). Checked against a live CLI 2.1.322: it writescustom-title,agent-nameand thecustom-title.jsonsidecar, and it emitssession_title_changed. This is the same per-turn pattern as Pi'sset_session_name(packages/provider-pi/src/server/adapter.ts:2778-2787) and OpenCode 2'swriteTitle(fix(opencode): name OpenCode 2 sessions after their thread #17414).- So that a rename with no following turn still reaches
claude --resume, use the exportedrenameSession(sessionId, title, { dir })when no process is live. - Don't append to the JSONL from outside while the CLI is live. The CLI keeps the title in memory and re-appends
custom-titleafter roughly every 32 KB of writes. It only adopts an external line that is still within the last 64 KB, and T3 transcripts have single lines over 140 KB, so the external rename can be reverted.
- So that a rename with no following turn still reaches
- Native → T3. When a
resultwithlocal_command: "rename"arrives, take the latestsession_title_changedtitle and apply it as a user rename: a new root-thread title event that becomesthread.metadata-updatedwithtitleRegeneration: null. Don't ingest everysession_title_changedframe. The CLI emits one at every spawn with the persisted title (and again withoptions.titleon resume), so ingesting them all would bring back the mirror bug from [Bug]: OpenCode provider overwrites user-set thread titles repeatedly (provider title mirror bypasses canReplaceThreadTitle) #5245. - Ship 1 and 2 together, and record the title ingested in step 2 as the applied title, so the next turn's sync in step 1 doesn't revert a
/rename.
Impact
Minor bug or occasional failure
Version or commit
0.1.9-nightly.20261111.4515 (main @ 691b970)
Environment
Windows 11 Pro, T3 Code (Nightly) desktop app, Claude provider (@anthropic-ai/claude-agent-sdk 0.3.321, Claude Code CLI 2.1.322), claude-opus-5-5
Logs or stack traces
# Session file after a sidebar rename + Regenerate title (T3 title: "Sync T3 and Claude Session Titles").
# Only distinct custom-title value; the last copy was appended after both changes:
{"type":"custom-title","customTitle":"T3 tem um bug. Se eu usar /rename na sessao, isso ...","sessionId":"b1c8858a-…"}
# SDK stream for the prompt "/rename sdk-probe-title" (no model call):
{"type":"system","subtype":"session_title_changed","title":"sdk-probe-title"}
{"type":"system","subtype":"init", …}
{"type":"assistant","message":{"model":"<synthetic>", …},"local_command_run":{"command":"rename","args":"sdk-probe-title"}}
{"type":"result","subtype":"success","num_turns":0,"local_command":"rename","result":"Session renamed to: sdk-probe-title"}Related
- Each direction already has an Ideas discussion: Mirror Claude Code's /rename into the thread title, like Codex and OpenCode already do #9588 (native → T3) and Sync thread renames to the provider session (Claude Code custom-title) #14809 (T3 → native). Allow a per-thread Claude session name so native Claude sessions can identify T3 threads #29698, converted to Allow a per-thread Claude session name so native Claude sessions can identify T3 threads #29703, asked for a per-thread native name. This report combines both directions with a repro and a fix plan.
- It is filed as a bug rather than an idea for two reasons. T3 already writes the native title (perf(server): skip redundant claude session naming #28910) but freezes it at the seed. And
/renameis offered in the composer and reports success while the thread keeps its old title. - [Bug]: OpenCode provider overwrites user-set thread titles repeatedly (provider title mirror bypasses canReplaceThreadTitle) #5245 / fix(server): stop the provider title mirror from overwriting real thread titles #5941: the v1 provider title mirror that overwrote user titles. This is why fix 2 ingests only actual renames.
- fix(opencode): name OpenCode 2 sessions after their thread #17414: per-turn title sync for OpenCode 2, a precedent for fix 1.
Workaround
After a rename or Regenerate title in T3, run /rename <sidebar title> in the thread. After a /rename, rename the thread in the sidebar too.
Filed by Claude Code (Claude Opus 5.5), running inside T3 Code at the reporter's request. Reproduced on the reporter's machine.
Activity