Skip to content

[Bug]: Imported Claude Code threads drop the user's renamed title (custom-title / customTitle) #12276

Closed

Description

@wowlegend

Version: T3 Code 0.0.43-nightly.20260917.1866, macOS.

Summary

Claude Code stores a user-set thread title in its transcript as a custom-title record. The importer never reads it — it reads only aiTitle — so any Claude session the user has explicitly renamed imports under a title derived from the first user message instead of the name the user chose.

Steps

  1. In Claude Code, rename a session (e.g. to Refactor auth module).
  2. Import that project's sessions into T3 Code through onboarding.
  3. Look at the imported thread's title.

Actual: the thread is titled from the first user record. When the session's first message is a slash command, the title becomes the raw wrapper — e.g. <command-name>/effort</command-name>.

Expected: Refactor auth module — the title the user set in Claude Code.

Cause

Claude Code writes two distinct title records into ~/.claude/projects/<project>/<session>.jsonl:

{"type":"ai-title","aiTitle":"...","sessionId":"..."}         // auto-generated
{"type":"custom-title","customTitle":"...","sessionId":"..."} // the user's rename

AgentSessionScanner.ts handles only the first:

  • TranscriptRecord declares aiTitle but not customTitle (L118), so customTitle is dropped at decode.
  • The only title assignment from a record is if (record.aiTitle?.trim()) title = record.aiTitle.trim(); (L407).
  • Everything else falls through to the first-user-message derivation at L501.

Worth noting: shouldRetainDecodedRecord (L514-526) already keeps the record — a custom-title record carries sessionId, so it satisfies record.sessionId !== undefined. The record survives the read and is then discarded purely for lack of a schema field.

In a sample of local transcripts, 53 files carried customTitle against 8 carrying aiTitle — so for renamed sessions this is the common case, not an edge one.

Suggested fix

Add the field to TranscriptRecord and prefer it over the generated title:

customTitle: Schema.optional(Schema.String),
if (record.aiTitle?.trim()) title = record.aiTitle.trim();
if (record.customTitle?.trim()) title = record.customTitle.trim();

Ordering matters: Claude Code writes both kinds, and an explicit user rename should win over the generated one. Both appear repeatedly through a transcript, so last-write-wins on the existing linear scan yields the current title without extra bookkeeping.

Related

#10513 is the Codex-side of the same first-user-message derivation. This one is narrower: for Claude sources a user-authored title already exists inside the transcript and is being dropped.

Activity

  1. juliusmarminge commented on Sep 17, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed on main (2d8378b44048). Imported Claude Code sessions ignore user renames stored as custom-title / customTitle in the transcript JSONL.

    Repro path (as reported)

    1. Rename a session in Claude Code (writes {"type":"custom-title","customTitle":"...","sessionId":"..."}).
    2. Import via T3 onboarding / agent session import.
    3. Thread title comes from first user message (or aiTitle if present), not the rename — slash-command wrappers show up as titles.

    Code

    In AgentSessionScanner.ts:

    • TranscriptRecord declares aiTitle only (L118) — undeclared customTitle is dropped on decode.
    • Claude title assignment reads only aiTitle (L407).
    • Fallback is first-user-message first line (L495–501).
    • shouldRetainDecodedRecord already keeps rows with sessionId (L514–526), so custom-title lines survive the filter and are unused solely for lack of a schema field / assignment.

    Suggested fix (matches reporter)

    customTitle: Schema.optional(Schema.String),
    if (record.aiTitle?.trim()) title = record.aiTitle.trim();
    if (record.customTitle?.trim()) title = record.customTitle.trim(); // prefer user rename; last-write-wins

    Add a scanner regression: both ai-title and later custom-title present → title is customTitle; first user slash-command must not win.

    Related (not duplicates)

    Labels / next

    • Type: bug (accepted). Small, localized server parse change + test.
    • Next: land the customTitle schema + prefer-over-aiTitle assignment above; no change required in Discord/mobile paths for the fix itself.
  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 17, 2026
  3. added a commit that references this issue on Oct 1, 2026
    51b0391
  4. juliusmarminge commented on Oct 20, 2026

    @juliusmarminge
    Member

    Fixed by 4908d8ce46 in #12292.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions