How it works
This explains why switching a conversation between agents is possible, and what
literally happens when you press Ctrl-B c.
The file is the memory
Agent CLIs are stateless between turns. Every time they start, or resume, they reconstruct the whole conversation by reading a transcript file on disk:
~/.claude/projects/<cwd-slug>/<id>.jsonl
~/.codex/sessions/YYYY/MM/DD/rollout-<timestamp>-<id>.jsonl
~/.gemini/tmp/<project-hash>/chats/session-*.json
~/.local/share/opencode/opencode.db (read via `opencode export`)The running process holds no durable memory. The file is the memory. So a switch never touches a live process. It is:
- Stop the outgoing agent.
- Write a session file to disk.
- Start a fresh target agent that reads that file at startup.
The target cannot tell a transcript it wrote from one Constant wrote, because resuming is always "read this file and rebuild context from it."
No replay window
When the target boots, the transcript sits in its context as dormant text. Nothing is absorbed until you send your next message. And that is exactly what happened on every turn anyway: the model has no memory between turns, so each turn the entire transcript is re-read from scratch. The target's first turn after a switch is processed identically to the source's fiftieth turn.
The one real artifact: a freshly resumed session is a prompt-cache miss, so the first reply after a switch can be a beat slower. After that, normal.
It is cheap
A switch runs zero model inference: no embeddings, no API calls, no summarization. It is a deterministic text transformation: read a file, parse JSON lines, map a list, run a redaction pass, write a file. Milliseconds.
It is format-precise
The target's loader is a strict parser. Every record must have the fields the parser expects. Miss one and it rejects the entire file. Match them all and it loads flawlessly. This is why Constant matches each runtime's native session schema field by field. See The alembic cartridge.
What happens on Ctrl-B c (codex to claude)
1. The host sees Ctrl-B then c.
2. It stops the codex child.
3. alembic distills the active codex session:
- find the session the child owns (identity declared at spawn when possible)
- load it into a neutral thread model
- drop scaffold turns and reasoning, redact secrets
(tool history comes along only with --with-tools)
- snapshot the distilled thread to the record (~/.constant/snapshots/…)
- write it into Claude's native session schema
4. It runs `claude -r <id>` in the same directory.
Claude boots, reads the file, and continues the conversation.
5. The receipt is held in the status bar:
✓ ch04 → claude · auth bug · carried 14 turns · 2 redactionsThe reverse (Ctrl-B x, claude to codex) is the same pipeline mirrored — codex
also needs a state_5.sqlite row to appear in its /resume picker, which
Constant writes too — and Ctrl-B o is the same pipeline into opencode, via
opencode import. If the target can't launch, the switch degrades instead of
dying: target resumed → target fresh → back to the previous runtime.