How Session Transfer Works Between Claude Code and Codex

The codex transfer command migrates Claude Code session transcripts (.jsonl files) into new Codex threads by validating the source path, calling the Codex app-server's externalAgentSessionImport RPC method, and returning a resumable thread ID.

The openai/codex-plugin-cc repository enables seamless migration of conversation history from Claude Code to OpenAI Codex. When developers need to switch AI coding assistants mid-session, the session transfer feature preserves context by converting Claude's .jsonl transcripts into Codex-compatible thread formats.

The Session Transfer Pipeline

The transfer operates through a six-step pipeline defined in plugins/codex/scripts/codex-companion.mjs and its library dependencies.

Step 1: Path Resolution and Validation

The resolveClaudeSessionPath() function in plugins/codex/scripts/lib/claude-session-transfer.mjs handles the initial input validation. It expands ~ and relative paths, ensures the file ends with .jsonl, and verifies the path resides inside the Claude projects directory ($HOME/.claude/projects). This security boundary prevents arbitrary file access.

Step 2: Import Request to Codex

The importExternalAgentSession() function in plugins/codex/scripts/lib/codex.mjs manages the core migration logic. It first validates that the Codex CLI is installed, then calls requestExternalAgentSessionImport() with a migration request containing the validated transcript path. This communicates with the Codex app-server via the externalAgentSessionImport RPC method.

Step 3: Thread ID Extraction

After the app-server processes the import, the function extracts the newly created thread ID via importedThreadIdForSource(). If the ID cannot be found, the function raises a detailed error including any stderr from Codex to aid debugging.

Step 4: Payload Construction

The executeTransfer() function in plugins/codex/scripts/codex-companion.mjs wraps the thread ID, a resume command (codex resume <thread-id>), and the original source path into a structured payload object. This prepares the data for user-facing output.

Step 5: Result Rendering

The renderTransferResult() function builds a human-readable message that prints to the console, confirming the successful transfer and providing the resume command.

Step 6: Progress and Error Handling

Throughout the pipeline, emitProgress() reports status updates such as "Importing Claude session" and "Claude session imported". Errors are enriched with actionable hints, such as updating Codex if the RPC method externalAgentSessionImport is missing.

Code Implementation Examples

Manually Invoking the Transfer Logic

You can programmatically trigger the same transfer logic used by 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 & 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 Command Structure

When users run the CLI command:

codex transfer --source ~/myproject/session.jsonl

The command dispatcher calls executeTransfer() in plugins/codex/scripts/codex-companion.mjs:

await executeTransfer(process.cwd(), { source: "~/myproject/session.jsonl" });

This internal call triggers the full pipeline from path resolution through result rendering.

Key Source Files

The session transfer feature spans three main files in the openai/codex-plugin-cc repository:

  • plugins/codex/scripts/lib/claude-session-transfer.mjs: Implements path resolution and safety checks for Claude transcripts, including the resolveClaudeSessionPath() function.

  • plugins/codex/scripts/lib/codex.mjs: Contains the core Codex app-server client implementing importExternalAgentSession(), requestExternalAgentSessionImport(), and importedThreadIdForSource().

  • plugins/codex/scripts/codex-companion.mjs: Serves as the CLI entry point, orchestrating the transfer flow through executeTransfer() and renderTransferResult().

Summary

  • Session transfer converts Claude Code .jsonl transcripts into Codex threads using the codex transfer command.
  • Path validation ensures transcripts reside within $HOME/.claude/projects and use the .jsonl extension.
  • RPC communication occurs via externalAgentSessionImport to the Codex app-server.
  • Resume capability generates a codex resume <thread-id> command for immediate continuation.
  • Error handling provides actionable hints for common failures like missing CLI installations or outdated Codex versions.

Frequently Asked Questions

What file format does Claude Code use for sessions?

Claude Code stores session transcripts as .jsonl (JSON Lines) files. The resolveClaudeSessionPath() function explicitly validates this extension, rejecting any files that do not end with .jsonl to ensure proper parsing by the transfer pipeline.

How does the transfer validate session file security?

The resolveClaudeSessionPath() function enforces a security boundary by verifying that the transcript path resides inside the Claude projects directory ($HOME/.claude/projects). This prevents the transfer command from accessing arbitrary files outside the expected scope, ensuring only legitimate Claude sessions are imported.

What happens if the Codex app-server lacks the import RPC method?

If the externalAgentSessionImport RPC method is missing, the error handler in plugins/codex/scripts/lib/codex.mjs returns a detailed message suggesting the user update their Codex CLI installation. This check occurs during the importExternalAgentSession() validation phase before attempting the actual import.

Can I programmatically resume a transferred session?

Yes. After successful transfer, the executeTransfer() function returns a thread ID that can be used with the codex resume <thread-id> command. The programmatic API also returns this ID via importExternalAgentSession(), allowing automated workflows to immediately resume sessions without manual CLI interaction.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →