How to Transfer a Claude Code Session to Codex and Resume It There
Run /codex:transfer inside Claude Code to convert the active JSONL transcript into a resumable Codex thread, then use the printed codex resume <threadId> command to pick up where you left off.
The openai/codex-plugin-cc repository ships a built-in session-transfer mechanism that migrates Claude Code conversation history into Codex format without exposing API secrets. This workflow reads your local Claude transcript files and creates a matching Codex thread that preserves the entire turn-by-turn context.
How the Session Transfer Architecture Works
The transfer process is completely internal to the plugin—no network requests transmit your Claude data to external services during the conversion.
CLI Entry Point and Command Parsing
The codex-companion.mjs script exposes the transfer subcommand through its handleTransfer function. When you invoke /codex:transfer or run the companion CLI directly, the script parses arguments at lines 24‑31 in plugins/codex/scripts/codex-companion.mjs and routes them to the execution pipeline.
Validating the Claude Transcript Path
Before importing history, resolveClaudeSessionPath validates that the supplied --source path (or the CODEX_COMPANION_TRANSCRIPT_PATH environment variable) points to a valid JSONL file inside ~/.claude/projects. This check occurs at lines 20‑44 in plugins/codex/scripts/lib/claude-session-transfer.mjs, ensuring the plugin only ingests legitimate Claude session files.
Converting History to a Codex Thread
The core import logic resides in importExternalAgentSession within plugins/codex/scripts/lib/codex.mjs. This function reads the validated JSONL transcript and generates a new Codex thread that mirrors each conversational turn from Claude Code. The companion script calls this logic at lines 25‑30 of codex-companion.mjs, capturing the resulting thread metadata for display.
Environment Propagation for Resumed Sessions
After successful transfer, session-lifecycle-hook.mjs propagates session identifiers to downstream processes. Lines 77‑81 set CODEX_COMPANION_SESSION_ID and CODEX_COMPANION_TRANSCRIPT_PATH as environment variables, ensuring subsequent Codex commands in the same shell session automatically reference the transferred Claude context.
Step-by-Step: Transferring Your Claude Code Session
Using the Built-In Command
From any directory within your Claude Code workspace, execute the transfer command:
/codex:transfer
This locates the active session transcript in ~/.claude/projects and outputs a human-readable result via renderTransferResult (lines 16‑23 in codex-companion.mjs):
Transferred the Claude session into a Codex thread with visible turn history.
Codex session ID: 12345-abcd-ef01
Resume in Codex: codex resume 12345-abcd-ef01
For programmatic consumption, request JSON output:
/codex:transfer --json
Running the CLI Directly
You can invoke the underlying Node script explicitly with a specific source path:
node plugins/codex/scripts/codex-companion.mjs transfer \
--source ~/.claude/projects/my-project/session-001.jsonl \
--json
The command returns a JSON payload:
{
"threadId": "12345-abcd-ef01",
"resumeCommand": "codex resume 12345-abcd-ef01",
"sourcePath": "/home/you/.claude/projects/my-project/session-001.jsonl",
"sessionId": "session-001"
}
Programmatic Session Transfer
Embed the transfer logic in your own Node.js tooling by importing the core functions:
import { executeTransfer } from "./plugins/codex/scripts/lib/codex.mjs";
import { resolveClaudeSessionPath } from "./plugins/codex/scripts/lib/claude-session-transfer.mjs";
async function transferClaudeToCodex(cwd, source) {
const sourcePath = resolveClaudeSessionPath(cwd, { source });
const { threadId, resumeCommand } = await importExternalAgentSession(cwd, { sourcePath });
console.log(`Codex thread ${threadId} created – resume with: ${resumeCommand}`);
}
This approach gives you fine-grained control over the working directory (cwd) and source selection while maintaining the same validation and thread-creation logic used by the CLI.
Verifying the Transfer State
After running the transfer, confirm the session context is active by checking your environment:
echo $CODEX_COMPANION_SESSION_ID
echo $CODEX_COMPANION_TRANSCRIPT_PATH
The first variable contains the Claude session identifier, while the second points to the exact JSONL file consumed during transfer. These values persist for the lifetime of your shell session, allowing seamless handoff between Claude Code and Codex.
Summary
- Command: Use
/codex:transferinside Claude Code or runcodex-companion.mjs transferfrom the shell to initiate migration. - Validation: The plugin enforces that source transcripts reside within
~/.claude/projectsviaresolveClaudeSessionPath. - Core Logic:
importExternalAgentSessioninlib/codex.mjshandles the JSONL-to-Codex-thread conversion. - Resume: The output provides a
codex resume <threadId>command that restores your conversation history. - State: Environment variables
CODEX_COMPANION_SESSION_IDandCODEX_COMPANION_TRANSCRIPT_PATHmaintain session continuity across tools.
Frequently Asked Questions
Where does the Claude Code transcript come from?
Claude Code writes conversation history to JSONL files inside ~/.claude/projects/<project-name>/. The transfer command automatically resolves the active session path, or you can specify a file explicitly using the --source flag when running the companion CLI directly.
Is the transfer process secure?
Yes. According to the openai/codex-plugin-cc source code, all processing happens locally on your machine. The handleTransfer function in codex-companion.mjs performs filesystem operations only, and no Claude session data is transmitted over the network until you actively invoke the Codex service using the generated resume command.
Can I transfer multiple sessions at once?
The current implementation processes one transcript per invocation. Each call to executeTransfer creates a single Codex thread from one JSONL source. To migrate multiple sessions, run the transfer command sequentially or script the importExternalAgentSession function in a loop with different source paths.
What happens if the transcript path is invalid?
resolveClaudeSessionPath throws a validation error if the supplied path is not a JSONL file or resides outside the ~/.claude/projects directory. The CLI catches this error and exits with a non-zero status, preventing the creation of empty or corrupted Codex threads.
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 →