How Session Transfer Between Claude Code and Codex Works: A Technical Deep Dive
The codex transfer command imports a Claude Code session stored as a .jsonl transcript into a new Codex thread through a six-step pipeline that validates paths, calls the Codex app-server via RPC, and returns a resumable thread ID.
The openai/codex-plugin-cc repository enables seamless migration of conversation history from Claude Code to OpenAI Codex. Understanding the internal session transfer between Claude Code and Codex helps developers troubleshoot import failures and integrate the functionality into custom workflows.
The Six-Step Transfer Pipeline
The transfer process orchestrates three core modules to safely move conversation transcripts from Claude's local storage into Codex's thread system.
Step 1: Path Resolution and Security Validation
Before any data moves, the system validates the source transcript. The resolveClaudeSessionPath() function in plugins/codex/scripts/lib/claude-session-transfer.mjs (lines 20-44) expands tildes and relative paths, verifies the .jsonl extension, and ensures the file resides within $HOME/.claude/projects to prevent directory traversal attacks.
Step 2: Codex CLI Verification and RPC Invocation
Once validated, importExternalAgentSession() in plugins/codex/scripts/lib/codex.mjs (lines 58-70) checks that the Codex CLI is installed and dispatches a migration request to the local Codex app-server. This request targets the RPC method externalAgentSessionImport, passing the absolute transcript path.
Step 3: Thread ID Extraction and Error Handling
After the app-server processes the import, the code extracts the new thread ID via importedThreadIdForSource() (lines 80-88). If extraction fails, the function surfaces detailed error messages including stderr output from Codex, with specific hints to update the Codex CLI if the RPC method is missing.
Step 4: Payload Construction and User Feedback
The executeTransfer() function in plugins/codex/scripts/codex-companion.mjs (lines 25-38) packages the thread ID, generates the resume command codex resume <thread-id>, and preserves the original source path. Meanwhile, emitProgress() calls throughout the pipeline provide real-time status updates like "Importing Claude session" and "Claude session imported."
Key Implementation Files
Understanding the module separation clarifies how the plugin maintains clean architecture while handling cross-application data migration.
Claude Session Transfer Module
Located at plugins/codex/scripts/lib/claude-session-transfer.mjs, this module handles filesystem safety. It ensures that only legitimate Claude transcripts within the user's projects directory can be imported, rejecting paths that attempt to escape the sandbox.
Codex App-Server Client
The plugins/codex/scripts/lib/codex.mjs file implements the communication layer with Codex's local daemon. It manages the RPC protocol, version compatibility checks, and response parsing required to instantiate new threads from external agent sessions.
CLI Orchestration Layer
plugins/codex/scripts/codex-companion.mjs serves as the entry point, exposing executeTransfer() and renderTransferResult() to format human-readable output. This separation allows the core logic to remain testable while the presentation layer handles console formatting.
Practical Usage Examples
Developers can invoke the transfer mechanism either through the command line or programmatically via the exposed JavaScript API.
Command Line Interface
Run the transfer directly from your terminal:
codex transfer --source ~/myproject/session.jsonl
Upon success, the CLI outputs:
Transferred the Claude session into a Codex thread with visible turn history.
Codex session ID: 12345-abcde
Resume in Codex: codex resume 12345-abcde
Programmatic API Integration
Import the core functions to embed transfer logic in Node.js applications:
import { resolveClaudeSessionPath } from "./plugins/codex/scripts/lib/claude-session-transfer.mjs";
import { importExternalAgentSession } from "./plugins/codex/scripts/lib/codex.mjs";
async function transferClaudeSession(cwd, source) {
// Validate and resolve the transcript path
const transcriptPath = resolveClaudeSessionPath(cwd, { source });
// Import into Codex with progress tracking
const { threadId } = await importExternalAgentSession(cwd, {
sourcePath: transcriptPath,
onProgress: (msg, state) => console.log(`[${state}] ${msg}`)
});
return {
threadId,
resumeCommand: `codex resume ${threadId}`
};
}
Summary
- The session transfer between Claude Code and Codex relies on a
.jsonltranscript format stored in$HOME/.claude/projects. - Security validation occurs in
resolveClaudeSessionPath(), which restricts imports to the Claude projects directory. - RPC communication happens via
importExternalAgentSession(), targeting theexternalAgentSessionImportmethod in the Codex app-server. - Error handling includes specific version checks, suggesting CLI updates when RPC methods are unavailable.
- The pipeline produces a resumable thread ID and corresponding
codex resumecommand for immediate context continuity.
Frequently Asked Questions
What file format does Claude Code use for session transcripts?
Claude Code stores session history as JSON Lines (.jsonl) files within the $HOME/.claude/projects directory. The transfer pipeline strictly validates this extension and location before processing to ensure data integrity and prevent unauthorized file access.
Why does the transfer require the Codex CLI to be installed?
The importExternalAgentSession() function validates CLI presence because the actual thread creation occurs inside the Codex app-server, a local daemon managed by the Codex CLI. The plugin sends an RPC request to this daemon via the externalAgentSessionImport method, which is only available in recent Codex versions.
How does the plugin handle invalid or malicious file paths?
The resolveClaudeSessionPath() implementation in plugins/codex/scripts/lib/claude-session-transfer.mjs performs path normalization and checks that the resolved file exists within the user's Claude projects directory. Any attempt to reference files outside this sandbox (via .. or symlinks) results in an immediate validation error.
Can I resume a transferred session without using the CLI output?
Yes. The programmatic API returns a threadId that can be used independently. While the CLI displays codex resume <thread-id>, you can store this ID in environment variables or databases and resume later using either the CLI or direct API calls to Codex, maintaining full conversation context from the original Claude session.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →