Motivation
Common workflow: start a thread on one machine (slow Windows work laptop), then want to continue it on another (fast MacBook at home). Today the only option is starting a fresh thread and manually re-explaining context ("check the latest commits, here's what I was doing…"), which is lossy and error-prone.
Wanted: a way to hand off a thread — full chat history, provider session continuity where possible, and the associated code state — from one Threadlines instance to another, e.g. over the same LAN.
What a thread actually is on disk
Handoff has to move three layers of state:
- Threadlines event log (
state.sqlite: orchestration events + checkpoint diff blobs + projections). Event-sourced, so exporting a thread's event slice and replaying it through the projector on the receiving machine is cheap by design. This gives pixel-perfect chat history in the UI.
- Provider-native session state — what the model resumes from, not just what we render. Codex resumes via
thread/resume against a rollout file under CODEX_HOME; Claude sessions are JSONL under ~/.claude/projects/<cwd-derived-slug>/. These exist only on the origin machine and embed machine-specific cwds (C:\Users\… is meaningless on macOS). The resumeCursor in ProviderSessionDirectory points at state the target machine doesn't have.
- Git/working-tree state — the actual code changes. Git solves transport; uncommitted work is the wrinkle.
Difficulty ranking
- Networking/discovery/transport: easy. The server already speaks HTTP+WS with auth access management (migration 020). mDNS/Bonjour for LAN discovery; Tailscale gives off-LAN for free since it's just IP reachability.
- Event history: easy. Export event slice + blobs, replay projector, remap project identity.
- Git state: moderate. Auto-commit to a
handoff/<thread> branch and push; bundle records branch + head SHA, receiver verifies it has the commit. Uncommitted changes travel as a patch.
- Provider session resume: hard, provider-specific. Transplanting rollout/JSONL files across OSes means rewriting embedded cwds in undocumented formats that can break under provider updates.
CodexSessionRuntime already falls back gracefully to a fresh start when resume fails, which points at the degraded mode below.
Proposed phasing
v1 — export/import handoff bundle. "Send to another machine" packages the thread's event slice + git state. Receiver imports events, remaps the project by git-remote identity rather than filesystem path, and starts a fresh provider session seeded with a synthesized context brief built from our own event log (full transcript, files touched, decisions made). No native model-memory continuity yet, but already far better than manual re-explaining. Transport can be dumb at first (file transfer / one-shot HTTP).
v2 — native session transplant. Per-provider exportSession/importSession driver capability that copies and path-rewrites the provider's native session files, with a fidelity level per provider and fallback to the v1 seeded-fresh-session path when transplant fails. The existing multi-provider driver abstraction is the right seam.
v3 — LAN server-to-server sync. mDNS advertisement, device pairing on top of existing auth, authenticated thread-export endpoint. UX: open Threadlines on the second machine → "Continue thread from WILL-WORK-LAPTOP" → click.
Non-goals / alternatives considered
- Thin-client mode (point the second machine's browser at the first machine's server) works today with zero changes, but keeps execution on the slow machine — doesn't address the use case, though worth documenting.
Open questions
- Project identity mapping: git remote URL as canonical key? What about repos with no remote?
- Should handoff be one-shot (move) or sync (thread lives on both)? One-shot move is much simpler and matches the use case; concurrent two-machine editing of one thread is explicitly out of scope.
- Windows origin specifics: path rewriting (backslashes, drive letters) in provider session files; CRLF in patches.
Motivation
Common workflow: start a thread on one machine (slow Windows work laptop), then want to continue it on another (fast MacBook at home). Today the only option is starting a fresh thread and manually re-explaining context ("check the latest commits, here's what I was doing…"), which is lossy and error-prone.
Wanted: a way to hand off a thread — full chat history, provider session continuity where possible, and the associated code state — from one Threadlines instance to another, e.g. over the same LAN.
What a thread actually is on disk
Handoff has to move three layers of state:
state.sqlite: orchestration events + checkpoint diff blobs + projections). Event-sourced, so exporting a thread's event slice and replaying it through the projector on the receiving machine is cheap by design. This gives pixel-perfect chat history in the UI.thread/resumeagainst a rollout file underCODEX_HOME; Claude sessions are JSONL under~/.claude/projects/<cwd-derived-slug>/. These exist only on the origin machine and embed machine-specific cwds (C:\Users\…is meaningless on macOS). TheresumeCursorinProviderSessionDirectorypoints at state the target machine doesn't have.Difficulty ranking
handoff/<thread>branch and push; bundle records branch + head SHA, receiver verifies it has the commit. Uncommitted changes travel as a patch.CodexSessionRuntimealready falls back gracefully to a fresh start when resume fails, which points at the degraded mode below.Proposed phasing
v1 — export/import handoff bundle. "Send to another machine" packages the thread's event slice + git state. Receiver imports events, remaps the project by git-remote identity rather than filesystem path, and starts a fresh provider session seeded with a synthesized context brief built from our own event log (full transcript, files touched, decisions made). No native model-memory continuity yet, but already far better than manual re-explaining. Transport can be dumb at first (file transfer / one-shot HTTP).
v2 — native session transplant. Per-provider
exportSession/importSessiondriver capability that copies and path-rewrites the provider's native session files, with a fidelity level per provider and fallback to the v1 seeded-fresh-session path when transplant fails. The existing multi-provider driver abstraction is the right seam.v3 — LAN server-to-server sync. mDNS advertisement, device pairing on top of existing auth, authenticated thread-export endpoint. UX: open Threadlines on the second machine → "Continue thread from WILL-WORK-LAPTOP" → click.
Non-goals / alternatives considered
Open questions