# How Session Transfer Works Between Claude Code and Codex

> Discover how session transfer works between Claude Code and Codex. Learn to migrate session transcripts to new Codex threads using the codex transfer command to resume your work.

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

---

**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:

```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 Command Structure

When users run the CLI command:

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

```

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

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