How Session Transfer Between Claude Code and Codex Plugin Works: A Deep Dive
Session transfer imports Claude Code’s JSONL transcript into the Codex plugin via the codex transfer CLI command, reconstructing the exact execution context including open files, cursor positions, and job history.
The openai/codex-plugin-cc repository implements a seamless hand-off mechanism that lets developers migrate active coding sessions from Claude Code into the Codex plugin environment. This process preserves the full state of your work—active jobs, file buffers, and conversation history—by parsing Claude’s transcript files and rehydrating them inside Codex’s broker system. Understanding this session transfer between Claude Code and Codex plugin requires examining the validation logic, environment variable handling, and lifecycle hooks that make the transition possible.
The Four-Step Session Transfer Process
The transfer flow follows a strict pipeline from export to restoration. Each step is guarded by validation logic to ensure security and data integrity.
1. Export the Claude Code Session
Claude Code automatically persists interaction history to a JSON Lines (.jsonl) file located within the user’s home directory. The standard path follows the pattern ~/.claude/projects/<project-id>/session.jsonl. This file contains the complete transcript of the coding session, including tool calls, file modifications, and user prompts.
2. Invoke the Codex Transfer Command
To initiate the transfer, the user runs the CLI command codex transfer --source <path>. According to the command documentation in plugins/codex/commands/transfer.md, this invocation sets the environment variable CODEX_COMPANION_TRANSCRIPT_PATH and triggers the resolution workflow. Alternatively, you can set this environment variable manually before starting Codex.
3. Load and Validate the Transcript
The companion process (codex-companion.mjs) calls resolveClaudeSessionPath from plugins/codex/scripts/lib/claude-session-transfer.mjs to validate the source file. This function performs critical security checks: it resolves real paths, verifies the .jsonl extension, and ensures the file resides within ~/.claude/projects to prevent directory traversal attacks.
4. Restore Session State via Lifecycle Hooks
Once validated, the transcript is parsed and the session state is reconstructed. The session-lifecycle-hook.mjs script registers the restored jobs with Codex’s broker, making them available to subsequent commands like codex review or codex result.
Security Validation: The Path Resolution Logic
The resolveClaudeSessionPath function in plugins/codex/scripts/lib/claude-session-transfer.mjs implements strict path validation to prevent arbitrary file access. The function prefers an explicit --source flag but falls back to the CODEX_COMPANION_TRANSCRIPT_PATH environment variable.
export const TRANSCRIPT_PATH_ENV = "CODEX_COMPANION_TRANSCRIPT_PATH";
const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), ".claude", "projects");
export function resolveClaudeSessionPath(cwd, options = {}) {
const requestedPath = options.source || process.env[TRANSCRIPT_PATH_ENV];
if (!requestedPath) {
throw new Error(
"Could not identify the current Claude transcript. Retry with --source <path-to-claude-jsonl>."
);
}
const sourcePath = resolveUserPath(cwd, requestedPath);
if (path.extname(sourcePath) !== ".jsonl") {
throw new Error(`Claude session source must be a JSONL file: ${sourcePath}`);
}
// Ensure the file is inside ~/.claude/projects
const source = fs.realpathSync(sourcePath);
const projects = fs.realpathSync(CLAUDE_PROJECTS_DIR);
const relative = path.relative(projects, source);
if (
relative === "" ||
relative === ".." ||
relative.startsWith(`..${path.sep}`) ||
path.isAbsolute(relative)
) {
throw new Error(
`Codex can import Claude sessions only from ${CLAUDE_PROJECTS_DIR}: ${source}`
);
}
return source;
}
This validation ensures that only transcripts within the Claude projects directory can be imported, effectively sandboxing the file system access. The function normalizes tildes (~), resolves symbolic links, and calculates relative paths to confirm the file remains within the allowed boundary.
Practical Example: Transferring a Session
To transfer a session from Claude Code to the Codex plugin, execute the following workflow in your terminal:
# Step 1: Locate the Claude session file
# (Typically at ~/.claude/projects/my-project/session.jsonl)
# Step 2: Transfer the session to Codex
$ codex transfer --source ~/.claude/projects/my-project/session.jsonl
# This sets CODEX_COMPANION_TRANSCRIPT_PATH and validates the file
# Step 3: Verify the transferred state
$ codex status
# Output shows jobs recreated from the Claude transcript
# Step 4: Continue working with Codex commands
$ codex review
For automation or CI/CD pipelines, you can bypass the transfer command and use the environment variable directly:
export CODEX_COMPANION_TRANSCRIPT_PATH=~/.claude/projects/my-project/session.jsonl
$ codex status
The companion process (codex-companion.mjs) automatically detects this variable on startup and invokes the resolution logic before initializing the broker.
Key Implementation Files
The session transfer functionality spans several modules in the openai/codex-plugin-cc repository:
plugins/codex/scripts/lib/claude-session-transfer.mjs– ContainsresolveClaudeSessionPath, which validates transcript paths and enforces directory restrictions.plugins/codex/scripts/codex-companion.mjs– Main entry point that loads the transcript and initializes the broker process.plugins/codex/scripts/session-lifecycle-hook.mjs– Registers restored jobs with the broker after transcript parsing.plugins/codex/commands/transfer.md– Documentation for thecodex transferCLI interface.plugins/codex/scripts/lib/fs.mjs– Provides path resolution utilities includingensureAbsolutePathused during validation.
Summary
- Session transfer enables seamless migration from Claude Code to Codex by importing
.jsonltranscript files. - The
codex transfer --source <path>command setsCODEX_COMPANION_TRANSCRIPT_PATHand triggers validation. resolveClaudeSessionPathenforces security by restricting imports to the~/.claude/projectsdirectory.- The companion process reconstructs job history and file states, registering them via
session-lifecycle-hook.mjs. - Once transferred, standard Codex commands operate on the restored context without requiring manual state replication.
Frequently Asked Questions
What file format does Claude Code use for session exports?
Claude Code exports sessions as JSON Lines (.jsonl) files. Each line represents a discrete interaction or event from the coding session. The Codex plugin specifically checks for this extension in resolveClaudeSessionPath and rejects files with mismatched extensions to ensure proper parsing.
Can I transfer sessions from arbitrary directories outside of Claude’s project folder?
No. The security logic in claude-session-transfer.mjs explicitly blocks paths that escape the ~/.claude/projects directory. The code calculates the relative path between the requested file and the projects directory, throwing an error if the result starts with .. or resolves to an absolute path, preventing directory traversal vulnerabilities.
How does Codex handle job history after transferring a session?
The session-lifecycle-hook.mjs script parses the JSONL entries and reconstructs each job object (such as codex-cli-runtime or codex-result-handling), then registers them with the Codex broker. This allows subsequent commands like codex review to operate on the exact same job context that existed in Claude Code, preserving the execution state and file handles.
Is the CODEX_COMPANION_TRANSCRIPT_PATH environment variable required for every Codex startup?
Only if you want to resume a transferred session automatically. If the variable is unset, Codex starts with a fresh session. When set—either manually or via the codex transfer command—the companion process treats it as a directive to import the specified transcript before initializing the interactive loop.
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 →