How Session Transfer Works Between Claude Code and Codex

Session transfer between Claude Code and Codex converts Claude's .jsonl transcript files into Codex threads via the codex transfer command, which validates the source path, calls the Codex app-server's externalAgentSessionImport RPC method, and returns a resumable thread ID.

The openai/codex-plugin-cc repository enables seamless migration of conversation history from Claude Code to OpenAI Codex through a structured pipeline. When developers need to switch between AI coding assistants without losing context, the session transfer feature imports Claude's transcript format directly into Codex's thread architecture. This process involves path resolution, RPC communication with the Codex app-server, and comprehensive error handling to ensure reliable migration of conversation history.

The Session Transfer Pipeline

The transfer process follows a strictly ordered pipeline that validates, imports, and formats the session data.

Step 1: Path Resolution and Security Validation

The resolveClaudeSessionPath() function in plugins/codex/scripts/lib/claude-session-transfer.mjs (lines 20-44) performs initial validation. It expands ~ and relative paths to absolute paths, verifies the file ends with a .jsonl extension, and ensures the transcript resides within the Claude projects directory at $HOME/.claude/projects. This security boundary prevents unauthorized access to files outside the Claude Code workspace.

Step 2: App-Server Import Request

The importExternalAgentSession() function in plugins/codex/scripts/lib/codex.mjs (lines 58-70) handles the core migration logic. It first validates that the Codex CLI is installed, then constructs a migration request containing the transcript path. The function calls requestExternalAgentSessionImport(), which communicates with the Codex app-server via the externalAgentSessionImport RPC method to create a new thread from the transcript.

Step 3: Thread ID Extraction

After the app-server processes the import, the importedThreadIdForSource() function (lines 80-88 in plugins/codex/scripts/lib/codex.mjs) extracts the newly created thread ID from the response. If the ID cannot be located, the function raises a detailed error that includes stderr output from Codex, providing actionable debugging information.

Step 4: Result Formatting and Output

The executeTransfer() function in plugins/codex/scripts/codex-companion.mjs (lines 25-38) orchestrates the final output. It wraps the thread ID, constructs the resume command (codex resume <thread-id>), and includes the original source path in a payload object. The renderTransferResult() function (lines 16-22) then formats this data into a human-readable console message.

Progress Reporting and Error Handling

Throughout the pipeline, emitProgress() reports status updates such as "Importing Claude session" and "Claude session imported". Error handling includes specific checks for missing transcripts, out-of-scope paths, and outdated Codex versions lacking the externalAgentSessionImport RPC method.

Implementation Examples

Programmatic Session Transfer

You 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 & validate the transcript path
  const transcriptPath = resolveClaudeSessionPath(cwd, { source });

  // Step 2 – Ask Codex to import the transcript
  const { threadId } = await importExternalAgentSession(cwd, {
    sourcePath: transcriptPath,
    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

Behind the scenes, the codex transfer command executes the same flow:

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

This invokes executeTransfer() in plugins/codex/scripts/codex-companion.mjs with the provided source path.

Key Source Files

File Purpose Key Functions
plugins/codex/scripts/lib/claude-session-transfer.mjs Path resolution and security validation resolveClaudeSessionPath()
plugins/codex/scripts/lib/codex.mjs Codex app-server client and RPC handling importExternalAgentSession(), importedThreadIdForSource()
plugins/codex/scripts/codex-companion.mjs CLI orchestration and output formatting executeTransfer(), renderTransferResult()

Summary

  • Session transfer converts Claude Code .jsonl transcripts into Codex threads via the codex transfer command.
  • Path validation ensures transcripts reside within $HOME/.claude/projects and end with the .jsonl extension.
  • RPC communication uses the externalAgentSessionImport method to create threads in the Codex app-server.
  • Thread resumption generates a codex resume <thread-id> command for immediate continuation of the conversation.
  • Error handling provides specific guidance for missing files, permission errors, and version incompatibility.

Frequently Asked Questions

What file format does Claude Code use for sessions?

Claude Code stores sessions as .jsonl (JSON Lines) transcript files located in $HOME/.claude/projects. The transfer pipeline specifically validates this extension and directory structure before processing.

How does the transfer mechanism communicate with Codex?

The importExternalAgentSession() function in plugins/codex/scripts/lib/codex.mjs communicates with the Codex app-server via the externalAgentSessionImport RPC method. This requires a compatible Codex CLI version; older versions will trigger an error prompting the user to update.

Can I resume a transferred session immediately?

Yes. Upon successful transfer, the CLI outputs a codex resume <thread-id> command that allows immediate continuation of the conversation in Codex with full access to the imported conversation history.

What happens if the transcript path is outside the Claude projects directory?

The resolveClaudeSessionPath() function enforces a security boundary that rejects paths outside $HOME/.claude/projects. This prevents unauthorized file access and ensures only legitimate Claude Code transcripts are imported.

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 →