How Session Transfer from Claude to Codex Works Internally

Session transfer from Claude to Codex is a pure RPC-driven migration that validates the transcript locally, sends it to the Codex daemon via JSON-RPC, and retrieves the new thread ID from a ledger file keyed by SHA-256 hash.

The openai/codex-plugin-cc repository implements this transfer through a CLI companion that bridges Claude’s exported conversation history into native Codex threads. This article dissects the internal mechanics using the actual source implementation.

Core Components of the Transfer Pipeline

The architecture relies on three distinct utilities spread across the plugins/codex/scripts/lib/ directory:

resolveClaudeSessionPath

Located in plugins/codex/scripts/lib/claude-session-transfer.mjs (lines 20-44), this function acts as a security and validation gate. It expands ~ shortcuts to absolute paths, verifies the file ends with .jsonl, and guarantees the transcript resides within the Claude projects directory (~/.claude/projects). If any check fails, it throws a descriptive error before network activity begins.

importExternalAgentSession

Defined in plugins/codex/scripts/lib/codex.mjs (lines 58-78), this function orchestrates the RPC communication. It wraps the operation in withDirectAppServer, which establishes a direct connection to the Codex app-server via CodexAppServerClient.connect. The function then dispatches the migration request and installs a temporary notification handler that resolves a Promise upon receiving the EXTERNAL_AGENT_IMPORT_COMPLETED event. A configurable EXTERNAL_AGENT_IMPORT_TIMEOUT_MS guards against hanging imports.

importedThreadIdForSource

Also in plugins/codex/scripts/lib/codex.mjs (lines 61-78), this utility performs the post-import lookup. It reads the ledger file at $CODEX_HOME/external_agent_session_imports.json and matches records where both the source_path and content_sha256 fields correspond to the supplied transcript. This dual-key approach ensures deterministic thread ID retrieval.

Step-by-Step Execution Flow

When a user invokes the transfer command, the following sequence executes:

  1. CLI Entry Point – handleTransfer in plugins/codex/scripts/codex-companion.mjs (lines 26-33) parses arguments and delegates to executeTransfer.

  2. Path Resolution – resolveClaudeSessionPath(cwd, {source}) converts relative paths to absolute, validates the .jsonl extension, and confirms the file lives under ~/.claude/projects.

  3. Server Connection – importExternalAgentSession establishes a direct RPC channel to the Codex daemon.

  4. Payload Construction – externalAgentSessionMigration(sourcePath, cwd) (lines 81-99 of codex.mjs) builds a JSON-RPC-compatible payload containing a migrationItems array with a single entry of type "SESSIONS" and the absolute source path.

  5. RPC Dispatch – The client sends client.request("externalAgentConfig/import", params) and awaits the EXTERNAL_AGENT_IMPORT_COMPLETED notification (handled by requestExternalAgentSessionImport at lines 70-93).

  6. Thread ID Lookup – Upon completion, importedThreadIdForSource(sourcePath) queries the ledger to retrieve the imported_thread_id associated with the file’s SHA-256 hash.

  7. Result Rendering – executeTransfer returns an object containing threadId, a resume command (codex resume <threadId>), and the source path. renderTransferResult formats this for stdout.

CLI Usage Example

Transfer a Claude session using the companion script:

node plugins/codex/scripts/codex-companion.mjs transfer --source ~/my-project/session.jsonl

Example output:

Transferred the Claude session into a Codex thread with visible turn history.
Codex session ID: 7e2c9f93-a1b4-4c12-b8f7-d3e5a6b9c0d1
Resume in Codex: codex resume 7e2c9f93-a1b4-4c12-b8f7-d3e5a6b9c0d1

Under the hood, the CLI expands ~/my-project/session.jsonl to an absolute path, validates it, opens the RPC connection, and performs the migration.

Summary

  • Validation-First Architecture: resolveClaudeSessionPath ensures only valid .jsonl files from the Claude projects directory proceed to import.
  • RPC-Driven Migration: The externalAgentConfig/import method and EXTERNAL_AGENT_IMPORT_COMPLETED notification provide a synchronous handshake with the Codex daemon.
  • Deterministic Ledger: The import ledger at $CODEX_HOME/external_agent_session_imports.json uses SHA-256 content hashing to map transcripts to thread IDs, making repeated transfers idempotent.
  • Timeout Protection: EXTERNAL_AGENT_IMPORT_TIMEOUT_MS prevents the CLI from hanging if the daemon fails to respond.

Frequently Asked Questions

What file format is required for the Claude session?

The transfer requires a *.jsonl (JSON Lines) file containing the Claude conversation history. The resolveClaudeSessionPath function in claude-session-transfer.mjs explicitly validates this extension and rejects other formats before any network activity occurs.

Where must the Claude transcript be located?

For security validation, the transcript must reside within the Claude projects directory at ~/.claude/projects. The path resolution logic expands ~ shortcuts and verifies the absolute path falls within this directory tree, preventing arbitrary file access.

How does the system handle duplicate transfers?

The ledger file ($CODEX_HOME/external_agent_session_imports.json) keys each import by both the absolute file path and the SHA-256 hash of the file contents. When importedThreadIdForSource queries the ledger, it matches on both criteria, ensuring that importing the same transcript multiple times returns the existing thread ID rather than creating a duplicate.

What happens if the Codex daemon is unresponsive?

The importExternalAgentSession function implements a timeout mechanism using EXTERNAL_AGENT_IMPORT_TIMEOUT_MS. If the daemon fails to emit the EXTERNAL_AGENT_IMPORT_COMPLETED notification within this window, the Promise rejects with a timeout error, and the CLI exits gracefully rather than hanging indefinitely.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →