Skip to content

Draft: two-way teleport with native CLI sessions - #7136

Closed
baanish wants to merge 62 commits into
pingdotgg:mainfrom
baanish:cursor/teleport-opencode-1e23
Closed

Draft: two-way teleport with native CLI sessions#7136
baanish wants to merge 62 commits into
pingdotgg:mainfrom
baanish:cursor/teleport-opencode-1e23

Conversation

@baanish

@baanish baanish commented Aug 15, 2026

Copy link
Copy Markdown

Draft. Do not merge. Exploration of two-way teleport. Opened as one PR because GitHub cannot stack cross-fork bases on this repo.

What Changed

T3 Code can list, import, and export native CLI sessions for Codex, and Claude.
Native files stay native. Import copies a CLI session onto a T3 thread. Export writes the thread back. Presence (t3 vs native) swaps Import/Export so both sides are not writers at once.
Codex export writes session_meta the CLI can resume. OpenCode imports text turns only, does not treat live opencode.db as a foreign lock, and does not match parent cwds into sibling codex / claude / grok folders. Stop settles Working when the turn is aborted, when there is no live session, or when interrupt fails.

UI

Import lives on the new-thread / sessions view. Export lives in the chat header. Composer send is disabled while the thread is in the native CLI.

New UI

Draft hero Import a native CLI session link

Command palette Import sessions action

Native Claude and Codex sessions in the import picker

Hover

Teleport Out tooltip

Teleport In tooltip

Composer disabled after Teleport Out

Composer disabled when the thread is in the native CLI

Recordings

Codex
codex_teleport_roundtrip_nologo.mp4

Claude
claude_teleport_roundtrip_nologo.mp4

Why

Two-way teleport needs a shared engine, UI, and one adapter per CLI. This PR is that whole stack in one diff because stacked bases have to exist on pingdotgg/t3code.

UI Changes

Import lives on the new-thread / sessions view. Export lives in the chat header. Composer send is disabled while the thread is in the native CLI.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Relates to #207, #5146, #5741, and #6590.

Note

Add two-way teleport between app threads and native CLI sessions

  • Introduces a full teleport system allowing threads to be exported to native CLI sessions (Claude, Codex, Grok, OpenCode) and imported back, with message history synchronization via new thread.history.replace and thread.teleport.set orchestration commands.
  • Adds TeleportService with list/import/export session RPCs (teleport.listSessions, teleport.importSessions, teleport.exportSession) wired into the WS layer with scope-based authorization.
  • Adds per-provider JSONL/directory format adapters with schema-version gating, file-lock detection, and atomic writes; a registry pattern enables runtime format registration.
  • Extends the command palette and chat UI with session browsing, import flows, a TeleportOutButton in the chat header, and composer/send disabling when a thread is teleported-out.
  • Adds DB migration 041 adding teleport_json to projection_threads with backfill from existing runtime telemetry.
  • Risk: thread.turn.start now fails with OrchestrationCommandInvariantError if the thread's teleport presence is native, blocking turn creation on teleported-out threads.
📊 Macroscope summarized 18ed3c0. 52 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

cursoragent and others added 20 commits August 15, 2026 08:54
Contracts, orchestration, and the teleport service land first. Native CLI
formats register later, so list/import/export stay empty until a provider
adapter is added.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
The UI can list, import, and export native sessions. Until a format
adapter is registered, the picker stays empty and export fails closed.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Register the Codex jsonl adapter so T3 can list, import, and export
rollouts the CLI can resume.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Register the OpenCode adapter so T3 can list, import, and export text
turns from opencode.db or JSON storage without treating the live db as a
foreign lock.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Register the Claude jsonl adapter so T3 can list, import, and export
sessions from the Claude projects folder.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Register the Grok session-directory adapter so T3 can list, import, and
export native Grok Build chats.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Stop marked the turn interrupted but left the session running, so the thread stayed Working after abort hung or only emitted turn.aborted.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
A projected running OpenCode thread stayed Working after Stop if the
in-memory provider session was already gone. Interrupt no longer
recovers a session just to abort it, and Stop settles the projection
when there is nothing live to interrupt.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep personal project directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep live-session titles and personal directories out of the public diff.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a86460d-dc34-4a24-9c87-02e715f5dd10

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 15, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small consistency findings in the new teleport UI. Everything else in the changed web files (command palette views, composer disabled/placeholder handling, ChatView toast) follows the existing primitives and layout conventions.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/DraftHeroHeadline.tsx Outdated
Comment thread apps/web/src/components/teleport/TeleportOutButton.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new TeleportService (plus its contract errors). Four convention violations found; details inline.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/teleport/Services/TeleportService.ts Outdated
Comment thread apps/server/src/teleport/Layers/TeleportService.ts Outdated
Comment thread packages/contracts/src/teleport.ts Outdated
Comment thread apps/server/src/teleport/Layers/TeleportService.ts Outdated
Comment thread apps/server/src/teleport/Layers/TeleportService.ts Outdated
Comment thread apps/server/src/orchestration/Layers/ProjectionPipeline.ts
Comment thread apps/server/src/teleport/formats/codex.ts
Comment thread apps/server/src/teleport/formats/opencode.ts Outdated
Comment thread apps/server/src/teleport/formats/opencode.ts Outdated
Comment thread apps/server/src/teleport/cwd.ts Outdated
Comment thread apps/server/src/teleport/formats/grok.ts Outdated
Comment thread apps/server/src/teleport/TeleportService.ts Outdated
Comment thread apps/server/src/teleport/Layers/TeleportService.ts Outdated
Comment thread apps/server/src/teleport/fileLock.ts Outdated
Comment thread apps/server/src/orchestration/decider.ts Outdated
baanish and others added 3 commits August 15, 2026 15:30
The import CTA lacked cursor-pointer, and the header export control used
the text xs size instead of the square icon-xs used by neighboring actions.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Reject unsafe session ids on native reads/writes, fail closed when lock
checks cannot run, keep Codex whitespace, preserve in-place provider
instances, and clear stale history/approvals when replacing a thread.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the new header control's disabled state suppresses the tooltip that explains why it is unavailable.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/teleport/TeleportOutButton.tsx Outdated
Effect 4 does not provide zipRight on Effect. Complete the sendTurn abort latch from a generator finalizer instead.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Comment thread apps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
cursoragent and others added 4 commits August 17, 2026 20:35
Claim the in-flight abort through an atomic gate so a second interrupt waits instead of emitting another turn.aborted or calling session.abort again.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Export writes the native session cwd from the thread worktree, which lives
outside the project root. Listing and import treated only the workspace root
as in-project, so Teleport Out was a one-way door.

Discover extra cwds from the project's thread worktrees, match subdirectory
sessions, and stop accepting ancestor cwds such as / or $HOME.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Export set presence to native with a teleport-pending path before writing
the CLI file, then only reverted on write tapError. Interruptions, defects,
and later directory or teleport.set failures left the thread stuck: the UI
only offered Import, which rejected the fake path.

Wrap the pending presence in acquireUseRelease so any unsuccessful exit
reverts to T3, or persists the real native path if the file was written.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Release-path persist of a written native session can still raise a
filesystem error. Catch that so a failed bind cannot mask the export
failure or skip reverting pending presence.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two error-modeling convention issues in the new teleport code: message stored as data when it is a fixed template over existing attributes, and a helper whose only behavior is constructing that error.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/teleport/fileLock.ts Outdated
Comment thread packages/contracts/src/teleport.ts Outdated
Lock, schema, identity, and file-locked errors now derive `message` from
their fields, so the lockProbeError helper can go. A failed new-thread
import deletes the orphan thread instead of leaving it unbound.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Comment thread apps/server/src/teleport/nativeWrite.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new teleport service against the Effect service conventions. Service shape (Context.Service with inline interface, exported make/layer), dependency acquisition via yield*, and Effect.catchTags usage all look right now. Three remaining error-modelling issues below.

Posted via Macroscope — Effect Service Conventions

Comment thread packages/contracts/src/teleport.ts Outdated
Comment thread packages/contracts/src/teleport.ts Outdated
Comment thread apps/server/src/teleport/formats/codex.ts Outdated
cursoragent and others added 3 commits August 17, 2026 22:33
Store a write stage instead of a free-form message on TeleportNativeWriteError,
derive TeleportUnsupportedProviderError from the provider, and remap schema
verification with catchTags. On Windows, replace native files by moving the
destination aside so a failed rename can restore the previous session.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Persist teleport ownership first so a failed history replace cannot leave an
unbound thread with overwritten messages.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep the teleported-out composer disable path and use main's
disconnected placeholder constant.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Comment thread apps/web/src/components/ChatView.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the new chat-header teleport button loses the themed toolbar control styling because the tooltip wrapper overwrites data-slot="button". See the inline comment for the one-attribute fix.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/teleport/TeleportOutButton.tsx
cursoragent and others added 5 commits August 19, 2026 03:27
TooltipTrigger replaces data-slot=button, so custom themes skipped this
icon. Opt in with data-toolbar-control the same way ProjectScriptsControl does.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Send-disabled only grayed the editor. Type-to-focus, mention drops, and
file drops could still queue hidden draft content. Reject those paths too.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
In-place native session import persisted directory binding, teleport
presence, unarchive, history, and title as separate durable mutations.
A later failure left T3 ownership and history out of sync, and a
concurrent turn could run against that intermediate state.

Commit ownership, history, and unarchive in one orchestration command.
Fence thread.turn.start with importing presence, recover leftover
importing state on startup, and keep title plus directory finalize
best-effort. Import stays atomic per session, not all-or-nothing for
the batch.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Comment thread apps/server/src/teleport/importTransaction.ts Outdated
cursoragent and others added 3 commits August 19, 2026 05:55
tapError only saw typed failures, so a cancelled or defective pre-commit
import step could leave presence "importing" until process restart.
onError reverts for fail, die, and interrupt, and keeps revert running.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep ChatView's teleport send-disabled import. Main moved the collapsed
sidebar titlebar inset into WorkspacePageHeader, so that import is gone.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Keep ChatComposer's teleport lock on the prompt editor after main
moved send/stop into the footer. Native and importing presence still
disable the editor and show the send-disabled reason.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
Comment thread apps/web/src/components/chat/ChatComposer.tsx
Paste/drop could start before teleport lock, then attach compressed
images after compression finished. Stash restore and stash-current
could also write into a native/importing draft. Recheck send-disabled
after awaits and reject those stash mutations while teleport-locked.

Co-authored-by: aanishbhirud <aanishbhirud@gmail.com>
@t3-code

t3-code Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked Draft. Do not merge. and documents cross-fork teleport exploration rather than merge-ready work.

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants