How Session Transfer Between Claude Code and Codex Works
Session transfer between Claude Code and Codex converts a Claude .jsonl transcript into a new Codex thread, preserving visible turn history and allowing immediate resumption with the codex resume command.
The session transfer between Claude Code and Codex feature in the openai/codex-plugin-cc repository enables seamless migration of conversation history between AI coding assistants. This functionality allows developers to move an active Claude session into OpenAI's Codex CLI tool while maintaining full context. The implementation validates transcript files, communicates with the Codex app-server via RPC, and creates a new thread with all previous conversation turns intact.
The Session Transfer Pipeline
The transfer operates through a six-step validation and migration pipeline defined across three core modules.
Step 1: Path Resolution and Security Validation
The process begins in plugins/codex/scripts/lib/claude-session-transfer.mjs where resolveClaudeSessionPath() (lines 20-44) expands tildes (~) and relative paths, validates the .jsonl file extension, and enforces a security boundary ensuring the transcript resides within $HOME/.claude/projects. This prevents arbitrary file access outside the Claude projects directory.
Step 2: Codex App-Server Import
In plugins/codex/scripts/lib/codex.mjs, the importExternalAgentSession() function (lines 58-70) first validates that the Codex CLI is installed, then invokes requestExternalAgentSessionImport() to transmit a migration request containing the transcript path to the local Codex app-server via RPC.
Step 3: Thread ID Extraction
After the app-server processes the import, importedThreadIdForSource() extracts the newly created thread ID (lines 80-88). If extraction fails, the function raises a detailed error including any stderr output from Codex to aid debugging.
Step 4: Result Construction
The executeTransfer() function in plugins/codex/scripts/codex-companion.mjs (lines 25-38) assembles a payload containing the thread ID, a resume command formatted as codex resume <thread-id>, and the original source path.
Step 5: Console Rendering
renderTransferResult() (lines 16-22) formats the payload into a human-readable message displaying the Codex session ID and the resume command.
Step 6: Progress Reporting and Error Handling
Throughout the pipeline, emitProgress() emits status updates such as "Importing Claude session" and "Claude session imported." Error handling includes specific actionable hints, such as updating Codex if the externalAgentSessionImport RPC method is unavailable.
End-to-End Transfer Flow
When a user executes codex transfer --source path/to/session.jsonl, the command dispatcher invokes executeTransfer().
- The system validates the transcript path using
resolveClaudeSessionPath(). importExternalAgentSession()sends a migration request to the Codex app-server.- The app-server creates a new thread and returns the thread ID.
- The console displays the transfer result:
Transferred the Claude session into a Codex thread with visible turn history.
Codex session ID: 12345-abcde
Resume in Codex: codex resume 12345-abcde
If any step fails—such as a missing transcript, a path outside $HOME/.claude/projects, or an outdated Codex version—the system throws a clear error with specific remediation steps.
Code Examples
Programmatic Session Transfer
You can trigger the same logic programmatically using the internal library functions:
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) {
// Step 1 – Resolve & validate the transcript path
const transcriptPath = resolveClaudeSessionPath(cwd, { source });
// Step 2 – Ask Codex to import the transcript
const { threadId } = await importExternalAgentSession(cwd, {
sourcePath: transcriptPath,
// optional progress callback
onProgress: (msg, state) => console.log(`[${state}] ${msg}`)
});
// Step 3 – Return a ready-to-run resume command
return {
threadId,
resumeCommand: `codex resume ${threadId}`
};
}
// Example usage
(async () => {
const cwd = process.cwd();
const result = await transferClaudeSession(cwd, "~/myproject/session.jsonl");
console.log(`✅ Imported, resume with: ${result.resumeCommand}`);
})();
CLI Invocation
The user-facing command translates directly to the internal execution flow:
# User command
codex transfer --source ~/myproject/session.jsonl
Behind the scenes, this executes:
// In plugins/codex/scripts/codex-companion.mjs
await executeTransfer(process.cwd(), { source: "~/myproject/session.jsonl" });
Key Implementation Files
The session transfer functionality relies on three primary source files:
plugins/codex/scripts/lib/claude-session-transfer.mjs
Handles path resolution, tilde expansion, and security checks ensuring transcripts originate from $HOME/.claude/projects.
plugins/codex/scripts/lib/codex.mjs
Implements the core Codex app-server client, including importExternalAgentSession() and the requestExternalAgentSessionImport() RPC method.
plugins/codex/scripts/codex-companion.mjs
Provides the CLI entry point and orchestration logic through executeTransfer() and renderTransferResult().
Summary
- Session transfer moves Claude Code transcripts (
.jsonlfiles) into Codex threads while preserving conversation history. - The
codex transfercommand validates paths viaresolveClaudeSessionPath()and requires files to reside in$HOME/.claude/projects. - Communication occurs through the
externalAgentSessionImportRPC method implemented inimportExternalAgentSession(). - Successful transfers return a thread ID and generate a
codex resume <thread-id>command for immediate context restoration. - Error handling provides actionable hints for common failures including outdated Codex versions or invalid file paths.
Frequently Asked Questions
What file format does Claude Code use for session transcripts?
Claude Code stores session history as .jsonl (JSON Lines) files. The transfer pipeline explicitly checks for this extension in resolveClaudeSessionPath() and rejects other formats to ensure data integrity.
Can I transfer any JSON file to Codex?
No. The system enforces two constraints: the file must have a .jsonl extension, and it must reside within the $HOME/.claude/projects directory. This security measure prevents arbitrary file access and ensures the transcript originates from a legitimate Claude session.
What happens if my Codex version is too old?
If the Codex CLI lacks the externalAgentSessionImport RPC method, importExternalAgentSession() will fail with an error message hinting that you should update Codex. The error includes any stderr output from the Codex process to help diagnose version mismatches.
Is the conversation history visible in Codex after transfer?
Yes. The transfer creates a new Codex thread with visible turn history from the original Claude session. You can verify this by running codex resume <thread-id> and observing the previous conversation context in the new thread.
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 →