The obvious way to move a session between agents is to summarize it and paste the summary into the next tool. We tried that first. It fails in a specific, annoying way: the new agent believes the summary, not the history, and confidently re-litigates decisions the old session already settled.
So we write the target's native format instead. For Codex that means emitting a real rollout file, pinned against a captured fixture from a specific Codex release, and inserting the thread into Codex's own state database so it appears in the resume picker. codex resume then treats it as its own past, because at that point it is.
The honest caveats are in the code: reasoning blocks are dropped because they are not portable across providers, and long sessions fold everything older than the last sixty messages into a digest. Both are visible in the output, not hidden behind a spinner.
The failure has a shape worth naming. A summary is a claim about the past; a transcript is the past. An agent handed a claim treats it as one input among many and weighs it against whatever it finds in the code. An agent handed its own history treats it as settled. That difference decides whether you spend the next ten minutes working or re-arguing.
Writing the target format is more work than it sounds, and the work is all in the details nobody sees. Claude Code stores a directed graph of messages linked by parent pointers, so a transcript has to be linearised from the leaf backwards. Codex stores dated rollout files whose function-call arguments are JSON encoded as a string inside JSON, and it will not list a thread in its resume picker unless a row exists in a separate SQLite database. Get either of those wrong and the session is written but invisible.
So the writers are pinned against captured fixtures from a specific release of each tool, and the tests run on Linux, macOS and Windows, because the paths differ on all three. When a tool changes its format, one file changes here and everyone gets the fix. That is the whole argument for doing this in the open.