# How Session Transfer Between Claude Code and Codex Works

> Understand Claude Code session transfer to Codex. Convert Claude transcripts to Codex threads with the `codex resume` command and continue your work seamlessly.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: internals
- Published: 2026-07-08

---

**Session transfer between Claude Code and Codex converts a Claude `.jsonl` transcript into a new Codex thread, preserving visible turn history and allowing immediate resumption with the `codex resume` command.**

The **session transfer between Claude Code and Codex** feature in the `openai/codex-plugin-cc` repository enables seamless migration of conversation history between AI coding assistants. This functionality allows developers to move an active Claude session into OpenAI's Codex CLI tool while maintaining full context. The implementation validates transcript files, communicates with the Codex app-server via RPC, and creates a new thread with all previous conversation turns intact.

## The Session Transfer Pipeline

The transfer operates through a six-step validation and migration pipeline defined across three core modules.

### Step 1: Path Resolution and Security Validation

The process begins in `plugins/codex/scripts/lib/claude-session-transfer.mjs` where `resolveClaudeSessionPath()` (lines 20-44) expands tildes (`~`) and relative paths, validates the `.jsonl` file extension, and enforces a security boundary ensuring the transcript resides within `$HOME/.claude/projects`. This prevents arbitrary file access outside the Claude projects directory.

### Step 2: Codex App-Server Import

In `plugins/codex/scripts/lib/codex.mjs`, the `importExternalAgentSession()` function (lines 58-70) first validates that the Codex CLI is installed, then invokes `requestExternalAgentSessionImport()` to transmit a migration request containing the transcript path to the local Codex app-server via RPC.

### Step 3: Thread ID Extraction

After the app-server processes the import, `importedThreadIdForSource()` extracts the newly created thread ID (lines 80-88). If extraction fails, the function raises a detailed error including any stderr output from Codex to aid debugging.

### Step 4: Result Construction

The `executeTransfer()` function in `plugins/codex/scripts/codex-companion.mjs` (lines 25-38) assembles a payload containing the thread ID, a resume command formatted as `codex resume <thread-id>`, and the original source path.

### Step 5: Console Rendering

`renderTransferResult()` (lines 16-22) formats the payload into a human-readable message displaying the Codex session ID and the resume command.

### Step 6: Progress Reporting and Error Handling

Throughout the pipeline, `emitProgress()` emits status updates such as "Importing Claude session" and "Claude session imported." Error handling includes specific actionable hints, such as updating Codex if the `externalAgentSessionImport` RPC method is unavailable.

## End-to-End Transfer Flow

When a user executes `codex transfer --source path/to/session.jsonl`, the command dispatcher invokes `executeTransfer()`.

1. The system validates the transcript path using `resolveClaudeSessionPath()`.
2. `importExternalAgentSession()` sends a migration request to the Codex app-server.
3. The app-server creates a new thread and returns the thread ID.
4. The console displays the transfer result:

```text
Transferred the Claude session into a Codex thread with visible turn history.
Codex session ID: 12345-abcde
Resume in Codex: codex resume 12345-abcde

```

If any step fails—such as a missing transcript, a path outside `$HOME/.claude/projects`, or an outdated Codex version—the system throws a clear error with specific remediation steps.

## Code Examples

### Programmatic Session Transfer

You can trigger the same logic programmatically using the internal library functions:

```javascript
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 Invocation

The user-facing command translates directly to the internal execution flow:

```bash

# User command

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

```

Behind the scenes, this executes:

```javascript
// In plugins/codex/scripts/codex-companion.mjs
await executeTransfer(process.cwd(), { source: "~/myproject/session.jsonl" });

```

## Key Implementation Files

The session transfer functionality relies on three primary source files:

**`plugins/codex/scripts/lib/claude-session-transfer.mjs`**

Handles path resolution, tilde expansion, and security checks ensuring transcripts originate from `$HOME/.claude/projects`.

**`plugins/codex/scripts/lib/codex.mjs`**

Implements the core Codex app-server client, including `importExternalAgentSession()` and the `requestExternalAgentSessionImport()` RPC method.

**`plugins/codex/scripts/codex-companion.mjs`**

Provides the CLI entry point and orchestration logic through `executeTransfer()` and `renderTransferResult()`.

## Summary

- **Session transfer** moves Claude Code transcripts (`.jsonl` files) into Codex threads while preserving conversation history.
- The `codex transfer` command validates paths via `resolveClaudeSessionPath()` and requires files to reside in `$HOME/.claude/projects`.
- Communication occurs through the `externalAgentSessionImport` RPC method implemented in `importExternalAgentSession()`.
- Successful transfers return a thread ID and generate a `codex resume <thread-id>` command for immediate context restoration.
- Error handling provides actionable hints for common failures including outdated Codex versions or invalid file paths.

## Frequently Asked Questions

### What file format does Claude Code use for session transcripts?

Claude Code stores session history as `.jsonl` (JSON Lines) files. The transfer pipeline explicitly checks for this extension in `resolveClaudeSessionPath()` and rejects other formats to ensure data integrity.

### Can I transfer any JSON file to Codex?

No. The system enforces two constraints: the file must have a `.jsonl` extension, and it must reside within the `$HOME/.claude/projects` directory. This security measure prevents arbitrary file access and ensures the transcript originates from a legitimate Claude session.

### What happens if my Codex version is too old?

If the Codex CLI lacks the `externalAgentSessionImport` RPC method, `importExternalAgentSession()` will fail with an error message hinting that you should update Codex. The error includes any stderr output from the Codex process to help diagnose version mismatches.

### Is the conversation history visible in Codex after transfer?

Yes. The transfer creates a new Codex thread with visible turn history from the original Claude session. You can verify this by running `codex resume <thread-id>` and observing the previous conversation context in the new thread.