Skip to content
Β 
Β 

Repository files navigation

Pass the Thread

Move agent conversations without flattening away the structures that make them usable.

Provider-neutral session portability with a shared conversation IR, deterministic plans, and fidelity-aware adapters. This project succeeds codex-to-claude; its original Codex β†’ Claude flow remains available through the same commands and the legacy executable alias.

License: Apache 2.0 Node Runtime dependencies Platform

✨ What's New

Newest first.

The linked pull requests below are historical work from the codex-to-claude predecessor repository.

  • 🧭 Importer-matrix foundation β€” a lossless raw-envelope store, typed historical IR, archive/project/session/date selection, deterministic plans and loss reports, and a version-gated Codex Desktop 26.721.41059 target adapter now live beside the original converter. The built-in Codex importer was audited because β€œ50 succeeded” did not preserve native tool calls, reasoning, images, compaction, world state, or turn context in the observed targets. See the version-pinned research.
  • 🧷 A conversation you carried on in Claude is left alone β€” --force treated "Claude replayed the history into the file" and "you answered in it" as the same kind of change and overwrote both, which cost a message. It now tells them apart and refuses the second, naming what would have been deleted and counting only lines somebody typed. Continuing an import also makes Claude fork it and repoint the record at a session of its own; those records are recognised as no longer ours, left alone rather than duplicated, and searched for messages sent there. (#9, #10)
  • πŸ›‘ A dry run stays dry β€” npm run import -- --dry-run used to import for real. npm owns --dry-run and --force, parses them as its own config and passes an empty argv on, so the flag never arrived and the write path ran. It now detects the swallowed flag and refuses; npm run import:dry has it baked in. (#6)
  • 🧠 Memory citations out of the reply β€” when Codex answers from its memory files it appends an <oai-mem-citation> block, which Codex Desktop parses back out and never shows. Imports used to end an answer with raw markup; the citation is now a readable metadata line after the reply. (#3)
  • 🏷️ Titles the way Codex titles them β€” Codex names the threads you start from the app and lists that name, not your opening message. Imports read those names from ~/.codex/session_index.jsonl, so a conversation is called the same thing on both sides. (#2)
  • 🍎 macOS support β€” the Claude Desktop session-record store resolves per platform now instead of assuming the Windows layout, and project grouping follows current Codex Desktop builds, which dropped the threadβ†’project map in favour of local-projects root paths. (#1)

Contents

On this page β€” Quick start Β· Importer matrix Β· How it works Β· Features Β· Choosing conversations Β· Requirements Β· Safety Β· Limitations

Reference β€” CLI Β· Conversion Β· Formats

Quick start

git clone https://github.com/Agentryx-ai/pass-the-thread
cd pass-the-thread
node --experimental-strip-types --experimental-sqlite src/threadpass.ts list
$ threadpass list
20 conversation(s), 20 after refinements.  [vscode:19  cli:1]

By project:
    3  Agentryx
    2  ReTalk
    2  Itineva
    1  ModuBoza
    1  (no project)
    ...

$ threadpass import --dry-run          # writes nothing
$ threadpass import --title-prefix "[Codex] "

Restart Claude Desktop. The conversations are in the sidebar under the same projects, and you can open and continue them.

Flags belong on node src/threadpass.ts, not on npm run β€” see CLI.

threadpass handoff header|resolve|read creates, selects, and reads inert session handoff files, matched on exact project identity and never executed. --allow-cross-project authorizes reading a file outside the current project and marks the body untrusted β€” see CLI.

Experimental importer matrix

The original Codex β†’ Claude commands remain available. The provider matrix adds the first reverse adapter through the same threadpass entrypoint:

Codex  ── shared typed IR + transactional adapter ──► Claude
Claude ── shared typed IR + 41059 adapter ──────────► Codex

Start with a read-only inventory or a saved deterministic plan:

threadpass scan --archive all
threadpass plan --archive active --project-scope existing-targets \
  --render-mode semantic \
  --evidence reference/codex-desktop/26.721.41059/manifest.json \
  --out import-plan.json

There is no implicit 30-day or 50-session cap. Filters include exact sessions, projects, archive state, existing-target projects, inclusive date bounds, and an explicit --limit. existing-targets means the canonical target project/group/root already exists; it does not mean that the exact target conversation exists. Plans report those facts separately as targetProjectExists and targetConversationExists (plus an exact/collision state). Unknown project membership, archive state, or activity time stays visible in an all/unfiltered inventory and fails closed if a requested filter needs it. Every selected source revision remains byte-exact in the bridge sidecar. semantic (default) renders supported meaning into the target; verbatim renders the entire canonical source as inert historical text. Historical task/access records and superseded Goal events always remain inert. A separately identified authoritative active Goal is restored by default in either render mode; --goal-mode skip keeps it as history without live activation.

Applying a reverse plan is intentionally strict and Windows-only for this first target. It requires Codex Desktop to be closed, the exact saved plan digest, and the pinned 26.721.41059 evidence manifest. The loader re-hashes the installed app.asar and codex.exe; a copied manifest by itself is not accepted as live-version evidence. Apply probes once under the lock, performs Goal/journal/sidecar setup, then full-hashes the active Appx identity again immediately before the first Codex target mutation. A mismatch fails closed. That second probe is the exact batch-start support snapshot; updates during the subsequent multi-session batch are outside atomicity, so artifacts are not re-hashed per session. Unknown/new builds can still be scanned and planned, but receive no private-write capability. Research or dry-run planning for another installed build requires a user-supplied provenance manifest that binds those live artifacts; that manifest does not itself enable writes. The plan independently binds rollout, thread-index, archive, project-identity, and Goal capabilities. apply --dry-run writes nothing, reports static blockers, and names live gates it cannot prove without applying. See CLI.

Semantic Claude history is only made resumable when its compact summary can be recovered into a nonempty Codex replacement_history; otherwise planning fails closed. Verbatim mode instead keeps compact records as inert archival context without claiming native resume semantics. Both modes enforce a conservative serialized UTF-8 byte limit; the offline check does not claim to calculate provider tokens. Project roots are canonicalized before registration so equivalent path spellings do not create a second Codex project identity.

Forward plans (--direction codex-to-claude) are now applicable too. They bind the typed renderer and exact before/after hashes for transcripts and Claude Desktop wrapper records. --dry-run is strictly zero-mutation; existing files require --allow-overwrite plus an unchanged-target proof. Before the first target write, immutable backups and a durable operation journal are created, so an interrupted uncommitted batch can be reconciled or rolled back with threadpass recover --operation <id>. Unsupported protocol, world/access state and unknown records remain in the canonical sidecar instead of leaking as raw chat; task notifications are readable inert metadata, and archived state is preserved in the Claude wrapper. Semantic compaction activates only the latest portable boundary and requires its replacement to contain safely renderable, nonempty content; earlier boundaries remain sidecar-only.

How it works

Claude Desktop keeps a conversation in two places, and needs both to show it:

Layer Location Role
Session record <app-data>/Claude/claude-code-sessions/<account>/<device>/local_<uuid>.json Builds the conversation list. Points at a transcript by cliSessionId and cwd.
Transcript ~/.claude/projects/<encoded-cwd>/<cliSessionId>.jsonl The conversation itself.

The wrapper sessionId and transcript/CLI cliSessionId are distinct identities and are validated separately. Codex plans likewise label the source rollout id, native/index thread id, and deterministic target thread id by role even when native evidence makes two values equal. Writing only a transcript leaves it invisible, so this writes both.

~/.codex/sessions/**/rollout-*.jsonl
        β”‚
        β”œβ”€ select    what Codex Desktop lists
        β”œβ”€ convert   rollout items to transcript lines
        β”œβ”€ validate  replay invariants
        β”‚
        β”œβ”€β”€β–Ί ~/.claude/projects/<enc-cwd>/<id>.jsonl
        └──► claude-code-sessions/.../local_<uuid>.json

Features

  • πŸ“‹ The same list you already see β€” selection replicates the Codex Desktop sidebar, including its project grouping, so you pick from what you recognise
  • πŸ” Whole conversations, not just text β€” messages, tool calls, tool results, images and sub-agent reports
  • 🏷️ Titles that read like titles β€” Codex's own conversation names, and its injected boilerplate marked as metadata so it never becomes one
  • 🧭 Registered, so Claude actually lists it β€” the session record is written alongside the transcript
  • πŸ” Sandbox and approval mapped β€” Codex's two settings collapse into Claude's one permissionMode
  • πŸ“‰ Long sessions still open β€” imports start from the context Codex compacted to; 39 MB of history became 6.5 MB across 20 conversations
  • βœ… Validated before writing β€” every conversion is replay-checked, and one that would fail on resume is repaired or refused
  • 🧾 Semantic or verbatim, in both directions β€” semantic conversion is the default; --render-mode verbatim keeps exact UTF-8 source text inert when canonical representation matters more than native rendering
  • πŸ›Ÿ Your edits win β€” a conversation you continued in Claude is skipped, not overwritten
What it deliberately does not do

Out of scope today: migrating settings, skills, plugins and MCP servers; network/account-backed history that has no local transcript; and pretending historical tasks, superseded goals, or grants are safe live control state. Only the canonical current Goal can be restored, through a separately versioned and verified target-native capability.

Why this is its own repository

It was written for Agentryx, an AI-native agent harness in development, which needs conversation history to move between providers. It depends on the on-disk formats of two proprietary desktop apps, and those change on someone else's schedule. That churn is easier to handle in a small project that can be fixed and released on its own. It works without Agentryx.

Choosing conversations

Codex Desktop groups by project. Conversations without one appear only under Recents, and plenty of people never look at them, so membership is a filter:

Flag Imports
(default) everything the sidebar shows
--projects-only only conversations in a project
--projectless-only only the Recents ones
--project <name> one project, by Codex name or path
--include-archived, --archived-only include or restrict to archived threads
--interactive-only drop codex exec automation runs

list prints the per-project breakdown first. Further limits: --since-days, --max, --from, --to, --id. Full flag reference in CLI.

Requirements

Windows or macOS, and Node.js 22.6 or newer. The runtime has no production dependencies; development installs TypeScript and Node declarations for strict type checking.

Every path resolves per platform: the Claude Desktop session-record store from %APPDATA%, ~/Library/Application Support or $XDG_CONFIG_HOME, and ~/.codex and ~/.claude from the home directory. Linux follows the same rules but has not been run there; --sessions-root and --claude-home override any of it.

Safety

This writes into another application's local data, so it stays cautious.

  • It creates files and deletes none. The only records it rewrites are ones it wrote itself, and only with --force.
  • --dry-run prints every target path and writes nothing.
  • If you continued an imported conversation in Claude, the transcript changed since the import and it is skipped, with a note.
  • --force overrides that for a transcript Claude only rewrote β€” opening a conversation makes it replay the history back into the file β€” and says what it overwrote. It stops at a transcript holding messages you sent after the import, naming the first one, and does not offer to override: the flag exists to get past replay duplicates, not to discard conversation.
  • To undo an import, delete the transcripts and the local_*.json records it created. Both are listed in its output.
  • Prefer running with Claude Desktop closed.

Limitations

  • Built on undocumented internals of two proprietary desktop apps. They can change at any time.
  • Claude β†’ Codex writes are supported only for the exact audited Codex Desktop 26.721.41059 artifacts and are still experimental; create and inspect a plan first, close Codex, and keep a backup.
  • Tested on Windows 11 and macOS 26. Linux resolves the same way but has not been run there.
  • Codex encrypts its compaction summaries, so an import shows where compaction happened but not what it said.
  • Sub-agent threads arrive as messages, not as separate threads.
  • JSONL sources are read incrementally with strict UTF-8 validation and byte-exact hashing. A selected conversion still builds its typed sidecar in memory, while bulk Claude inventory scans release transcript envelopes as they go.

Documentation

CLI Commands, every flag, exit codes
Conversion What each Codex item becomes, injected context, permissions, compaction, replay repairs
Formats The on-disk shapes both sides use, reconstructed by observation

Related

Development

npm run verify

Disclaimer

Unofficial, and not affiliated with OpenAI or Anthropic. "Codex" and "Claude" are trademarks of their respective owners. Back up anything you care about.

License

Apache 2.0, see LICENSE and NOTICE.

You can use, modify and ship this, including commercially. Keep the copyright notice and the NOTICE file, and say what you changed. The license does not grant rights to the project's name or marks.

About

Provenance-preserving, bidirectional session portability for AI coding agents.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages