How Session Transfer Works Between Claude Code and Codex: A Technical Deep Dive
Session transfer between Claude Code and Codex converts Claude's JSONL transcript files into resumable Codex threads through a validated import pipeline that checks file paths, invokes the Codex app-server's RPC interface, and returns a thread ID for seamless conversation continuity.
The openai/codex-plugin-cc repository enables seamless migration of AI-assisted coding sessions from Claude Code to OpenAI Codex. When developers need to switch between these AI coding assistants, the session transfer functionality preserves conversation history by importing Claude's transcript format directly into Codex's threading system.
The Session Transfer Pipeline
The transfer process implemented in openai/codex-plugin-cc follows a strict validation and migration pipeline across three core modules.
Path Resolution and Security Validation
In plugins/codex/scripts/lib/claude-session-transfer.mjs (lines 20-44), the resolveClaudeSessionPath() function performs critical safety checks before any data moves. It expands tildes (~) and relative paths into absolute paths, verifies the file extension is .jsonl, and ensures the transcript resides within the Claude projects directory at $HOME/.claude/projects. This containment guarantee prevents arbitrary file access during the transfer process.
App-Server Import and RPC Communication
The importExternalAgentSession() function in plugins/codex/scripts/lib/codex.mjs (lines 58-70) handles the actual migration. First, it validates that the Codex CLI is installed locally. Then it constructs a migration request containing the transcript path and sends it via requestExternalAgentSessionImport() to the Codex app-server's RPC interface. This method specifically calls the externalAgentSessionImport RPC method to initiate the conversion.
Thread Extraction and Error Recovery
After the app-server processes the import, importedThreadIdForSource() (lines 80-88) extracts the newly created thread ID from the response. If extraction fails, the function raises detailed errors that include stderr output from Codex, enabling developers to diagnose version mismatches or RPC method availability issues immediately.
Result Formatting and CLI Output
In plugins/codex/scripts/codex-companion.mjs, the executeTransfer() function (lines 25-38) orchestrates the workflow and packages the results. It returns a payload containing the thread ID, a codex resume <thread-id> command string, and the original source path. The renderTransferResult() function (lines 16-22) then formats this into human-readable console output.
Step-by-Step Transfer Execution
When a user runs codex transfer --source path/to/session.jsonl, the following sequence executes:
- Command Dispatch: The CLI invokes
executeTransfer()with the current working directory and source options. - Path Validation:
resolveClaudeSessionPath()validates the transcript location and ensures it belongs to the Claude projects directory. - Migration Request:
importExternalAgentSession()sends the validated path to the Codex app-server via RPC. - Thread Creation: The app-server imports the transcript, creates a new thread, and returns the thread identifier.
- Result Presentation: The companion script outputs the thread ID and resume command.
Throughout this process, emitProgress() calls provide real-time status updates including "Importing Claude session" and confirmation messages.
Implementation Examples
Programmatic Session Transfer
Developers can invoke the transfer logic programmatically using the same functions that power the CLI:
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 and validate the transcript path
const transcriptPath = resolveClaudeSessionPath(cwd, { source });
// Step 2: Request import from Codex app-server
const { threadId } = await importExternalAgentSession(cwd, {
sourcePath: transcriptPath,
onProgress: (msg, state) => console.log(`[${state}] ${msg}`)
});
return {
threadId,
resumeCommand: `codex resume ${threadId}`
};
}
// Usage example
(async () => {
const result = await transferClaudeSession(process.cwd(), "~/myproject/session.jsonl");
console.log(`✅ Imported successfully. Resume with: ${result.resumeCommand}`);
})();
Command Line Interface
For direct CLI usage:
codex transfer --source ~/myproject/session.jsonl
Behind the scenes, this executes executeTransfer() in codex-companion.mjs with the provided source path, running the full validation and import pipeline.
Key Source Files and Architecture
The session transfer functionality spans three critical files in the openai/codex-plugin-cc repository:
plugins/codex/scripts/lib/claude-session-transfer.mjs: Implements path resolution and security validation for Claude transcript files.plugins/codex/scripts/lib/codex.mjs: Contains the Codex app-server client, includingimportExternalAgentSession()and RPC handling.plugins/codex/scripts/codex-companion.mjs: Provides the CLI entry point withexecuteTransfer()andrenderTransferResult()for user interaction.
Summary
- Session transfer between Claude Code and Codex converts
.jsonltranscripts into Codex threads via thecodex transfercommand. - Path validation enforces that transcripts originate from
$HOME/.claude/projectsto prevent unauthorized file access. - RPC communication uses the
externalAgentSessionImportmethod to create threads with full conversation history. - Error handling provides actionable feedback when Codex CLI versions lack required RPC methods or when paths fail validation.
- Resume capability generates
codex resume <thread-id>commands for immediate continuation of transferred sessions.
Frequently Asked Questions
What file format does Claude Code use for sessions?
Claude Code stores session transcripts as JSONL files (newline-delimited JSON) within the $HOME/.claude/projects directory. The transfer pipeline specifically validates the .jsonl extension and ensures files reside within this protected directory structure before processing.
Can I transfer any JSONL file to Codex?
No. The resolveClaudeSessionPath() function enforces strict security constraints. It verifies that the source file ends with .jsonl and guarantees the absolute path lives inside $HOME/.claude/projects. Attempts to transfer files outside this directory will fail validation to prevent arbitrary file system access.
What happens if the Codex CLI version is outdated?
The system returns detailed error messages indicating that the externalAgentSessionImport RPC method is unavailable. The error output includes stderr from Codex and suggests updating the Codex CLI to a version that supports external agent session imports.
How do I resume a transferred session in Codex?
After successful transfer, the CLI outputs a resume command in the format codex resume <thread-id>. The executeTransfer() function packages this command in its return payload, allowing immediate continuation of the conversation history in the new Codex 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 →