feat(server): support recoverable Codex and Claude session handoff#25476

closed2
main
GitHub fork: feat/codex-shared-daemon-handoff
opened3d agobyMmulyoved
View on GitHubTwo-way sync enabledPR last imported 3d ago

Problem

Moving one native conversation between a terminal controller and full T3 chat currently lacks an explicit ownership-transfer contract. Importing history alone does not coordinate writers, enforce the destination permission ceiling, or distinguish a queued launch from a confirmed release.

Change

Add API-driven native session handoff for Codex and manual handoff for already-stopped Claude sessions. Both variants expose adopt, refresh, status and release through typed RPC and MCP service methods; the environment descriptor advertises supported contracts.

Codex uses a shared native daemon and reconciles native history. Claude binds an exact saved UUID to explicit destination settings, resumes that UUID on the first T3 turn, and tracks managed writes and the exact owned child separately from SDK finalization. Controller epochs and transactional admission/release checks prevent stale controllers and independently scheduled work from crossing ownership changes. History reconciliation updates connected and reconnecting clients, including native removals.

These are two provider implementations of the same terminal-to-T3 conversation handoff. Migrations 070/071 retain ownership and recovery evidence. Other providers do not advertise these contracts. Claude v1 is Linux-local and manual-first; it does not stop an arbitrary running Claude source or infer its effective permissions.

Companion consumer: https://github.com/mulyoved/skills/pull/996.

Scope and approval

Maintainer direction/scope approval has not been obtained. This is a draft submitted at the developer's explicit request. It is a new workflow, and no small-fix or configuration exemption is claimed. Draft status does not satisfy CONTRIBUTING.md's prior-approval requirement. Review or merge should wait for agreement on the direction and scope.

No installation, deployment or live user-session stop/restart was performed. The tested head is a50f12d8ff4c7bfc593be4ef74d7985187aa5bc5, containing Codex commit e3259976c69ea460959b7ecea5c3896a6052d795 and the Claude increment. Tests were run on that committed source, not on a merge with the latest main.

Verification

On Linux, using private HOME/config/runtime/SQL stores and synthetic protocol peers:

text
1vp run check:changed
2 902 tests passed in 44 files
3 31 affected/dependent package typechecks passed
4 format, lint, both Knip checks and GraphQL checks passed
5 exit 0; source drift []
6
7# From apps/server, with a fresh private output directory:
8vp pack --out-dir <private-output>/server-dist --no-clean
9 exit 0; source drift []

Behavior checks include rejected/stale controller admission, exact UUID first-turn resume, existing binding protection, target settings and project races, native history removals, re-adoption identity mismatch, and a schedule arriving during final release. Counterexamples were reproduced before correction. Fresh final independent reviews found no remaining findings in their scopes.

A cross-repository synthetic round trip exercised the exact compiled CLI through the actual selected RPC definitions, authorization middleware, facade/domain services, history readers and SQLite, with private Unix socket/PTY/native peers: 66 assertions passed, zero source/binary drift and zero model queries. A separate actual Claude SDK 0.3.276/default managed-spawn proof passed 22 assertions, showing that close, EOF and SIGTERM are insufficient to prove child exit, followed by an observed exact-child exit.

An earlier private environment run failed because a 118-byte Unix socket path exceeded the platform limit. It remains recorded as failed. Shortening only the private environment paths produced the passing unchanged-source run above.

Not verified: real Claude callback delivery, persistence, ordinary prompt-complete-release, returned loaded-history identity, a live Herdr/browser round trip, complete production WebSocket composition or real credential issuance. The 22-assertion SDK proof uses a synthetic ELF peer with tools disabled and persistence disabled. Installed native source supports the expected Stop roster shape, but source inspection is not delivery evidence. Missing roster fields, unknown writes and unacknowledged elicitation block release.

Written with GPT-6.1 Sol and GPT-6 Astra through the Codex harness in T3 Code. Final backend review used independent Astra/medium and Sol/high seats.

Checks

6 successful · 7 skipped
All checks passed
a50f12d

Added 2 commits

  • feat(server): add manual Claude session handoffa50f12d
  • feat(codex): support shared-daemon session handoffe325997