Repository navigation
[Feature]: First-class interop/sync between T3 threads and local Claude Code CLI sessions #6590
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I am describing a concrete problem or use case, not just a vague idea.
Area
apps/server
Problem or use case
T3 Code and the Claude Code CLI already share the same on-disk session storage (~/.claude/projects/<project>/*.jsonl), and T3 already scans those transcripts for the usage page. But the sessions themselves are invisible to each other:
- A session started in a terminal with
claudecannot be continued as a T3 thread./resumeonly knows about T3-born threads (Resume Claude Code sessions that weren't started in T3 #5346, [Bug]: Opened a folder I'd previously used Claude Code inside, tried typing /resume - nothing happens - cannot resume #4519). - Even when a T3 thread resumes its own provider session (via
resume_cursor_jsoninprovider_session_runtime), the UI history comes exclusively from T3's own projections (projection_thread_messages). Anything that happened outside T3 — or before an import — would be model-context-only: the model remembers it, the user can't see it. - There is no sync in the other direction either: continuing a session in the CLI after touching it in T3 works only by accident of shared storage, with no awareness in the T3 UI.
I verified the mechanics by inspecting the server bundle: the Claude adapter resumes via the Agent SDK resume: <sessionId> option, and readClaudeResumeState accepts any UUID — so hand-editing resume_cursor_json in state.sqlite to point at an external CLI session actually works today. The model context comes back fully, but the thread renders empty because no projections exist for the imported turns. That gap is the real work, not the resume plumbing.
Proposed solution
First-class interop/sync with local Claude Code sessions:
- Discovery: list transcripts from
~/.claude/projects/<cwd-slug>/in the resume picker for the current workspace (session id, first user prompt, last activity, turn count — all parseable from the JSONL). - Import: selecting one creates a T3 thread whose resume cursor points at that session id (the adapter already supports this), and backfills
projection_thread_messagesfrom the transcript so the prior conversation is visible in the UI. - Live sync (stretch): watch the project's transcript directory; when a session bound to a T3 thread grows from outside (CLI turn), append those turns to the projections so the thread stays truthful.
Why this matters
People move between terminal and editor constantly. Today the two front-ends silently share provider state but not user-visible state, which is worse than either full sharing or full isolation: you can end up with a thread whose model context and visible history disagree. Import + backfill makes the shared-storage design an actual feature.
Smallest useful scope
Discovery + import with projection backfill for Claude sessions in the current workspace only. No live sync, no Codex, no cross-machine anything. Even import without backfill (model context only, with a visible "resumed from CLI session, prior history not shown" marker) would beat the status quo of hand-editing sqlite.
Alternatives considered
- Running
claude --resume <id>in a terminal inside T3 — works, but it's a CLI session, not a T3 thread (no checkpoints, no approvals UI, no mobile handoff). - Hand-editing
resume_cursor_jsonin~/.t3/userdata/state.sqliteto point an existing thread at an external session UUID — works for model context, but the UI shows none of the imported history, and it requires closing the app and touching a WAL-backed sqlite file.
Risks or tradeoffs
- Transcript JSONL is an internal Claude Code format and changes without notice; the projection backfill needs to be tolerant of unknown record types (the usage scanner already takes this stance).
- Imported sessions may reference tool calls/approvals T3 never mediated; those should render read-only rather than replaying through the approval pipeline.
- Session files can be large; backfill should stream and cap like the existing usage scan does.
Examples or references
- Resume Claude Code sessions that weren't started in T3 #5346 (resume picker for external sessions — this issue is the superset: import with visible history + sync)
- [Bug]: Opened a folder I'd previously used Claude Code inside, tried typing /resume - nothing happens - cannot resume #4519 (
/resumedoes nothing in a folder previously used with the CLI) - The usage scanner already walks
~/.claude/projects/**/*.jsonlwith mtime filtering and a scan cache — prior art in-repo for reading these transcripts safely.
Contribution
- I would be open to helping implement this.
Activity
doasfrancisco commentedon Aug 14, 2026
I think this is useful.
not because of switching between terminal and t3code.
but because it's less friction to choose t3code over cli terminal only.
there would be no reason for me to not do t3code if all my chats are in t3code already