# How Session Transfer Works Between Claude Code and Codex: A Technical Deep Dive

> Learn how session transfer between Claude Code and Codex works. This technical deep dive explains the validated import pipeline for seamless conversation continuity.

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

---

**Session transfer between Claude Code and Codex converts Claude's JSONL transcript files into resumable Codex threads through a validated import pipeline that checks file paths, invokes the Codex app-server's RPC interface, and returns a thread ID for seamless conversation continuity.**

The `openai/codex-plugin-cc` repository enables seamless migration of AI-assisted coding sessions from Claude Code to OpenAI Codex. When developers need to switch between these AI coding assistants, the session transfer functionality preserves conversation history by importing Claude's transcript format directly into Codex's threading system.

## The Session Transfer Pipeline

The transfer process implemented in `openai/codex-plugin-cc` follows a strict validation and migration pipeline across three core modules.

### Path Resolution and Security Validation

In `plugins/codex/scripts/lib/claude-session-transfer.mjs` (lines 20-44), the `resolveClaudeSessionPath()` function performs critical safety checks before any data moves. It expands tildes (`~`) and relative paths into absolute paths, verifies the file extension is `.jsonl`, and ensures the transcript resides within the Claude projects directory at `$HOME/.claude/projects`. This containment guarantee prevents arbitrary file access during the transfer process.

### App-Server Import and RPC Communication

The `importExternalAgentSession()` function in `plugins/codex/scripts/lib/codex.mjs` (lines 58-70) handles the actual migration. First, it validates that the Codex CLI is installed locally. Then it constructs a migration request containing the transcript path and sends it via `requestExternalAgentSessionImport()` to the Codex app-server's RPC interface. This method specifically calls the `externalAgentSessionImport` RPC method to initiate the conversion.

### Thread Extraction and Error Recovery

After the app-server processes the import, `importedThreadIdForSource()` (lines 80-88) extracts the newly created thread ID from the response. If extraction fails, the function raises detailed errors that include stderr output from Codex, enabling developers to diagnose version mismatches or RPC method availability issues immediately.

### Result Formatting and CLI Output

In `plugins/codex/scripts/codex-companion.mjs`, the `executeTransfer()` function (lines 25-38) orchestrates the workflow and packages the results. It returns a payload containing the thread ID, a `codex resume <thread-id>` command string, and the original source path. The `renderTransferResult()` function (lines 16-22) then formats this into human-readable console output.

## Step-by-Step Transfer Execution

When a user runs `codex transfer --source path/to/session.jsonl`, the following sequence executes:

1. **Command Dispatch**: The CLI invokes `executeTransfer()` with the current working directory and source options.
2. **Path Validation**: `resolveClaudeSessionPath()` validates the transcript location and ensures it belongs to the Claude projects directory.
3. **Migration Request**: `importExternalAgentSession()` sends the validated path to the Codex app-server via RPC.
4. **Thread Creation**: The app-server imports the transcript, creates a new thread, and returns the thread identifier.
5. **Result Presentation**: The companion script outputs the thread ID and resume command.

Throughout this process, `emitProgress()` calls provide real-time status updates including "Importing Claude session" and confirmation messages.

## Implementation Examples

### Programmatic Session Transfer

Developers can invoke the transfer logic programmatically using the same functions that power 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 and validate the transcript path
  const transcriptPath = resolveClaudeSessionPath(cwd, { source });

  // Step 2: Request import from Codex app-server
  const { threadId } = await importExternalAgentSession(cwd, {
    sourcePath: transcriptPath,
    onProgress: (msg, state) => console.log(`[${state}] ${msg}`)
  });

  return {
    threadId,
    resumeCommand: `codex resume ${threadId}`
  };
}

// Usage example
(async () => {
  const result = await transferClaudeSession(process.cwd(), "~/myproject/session.jsonl");
  console.log(`✅ Imported successfully. Resume with: ${result.resumeCommand}`);
})();

```

### Command Line Interface

For direct CLI usage:

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

```

Behind the scenes, this executes `executeTransfer()` in `codex-companion.mjs` with the provided source path, running the full validation and import pipeline.

## Key Source Files and Architecture

The session transfer functionality spans three critical files in the `openai/codex-plugin-cc` repository:

- **`plugins/codex/scripts/lib/claude-session-transfer.mjs`**: Implements path resolution and security validation for Claude transcript files.
- **`plugins/codex/scripts/lib/codex.mjs`**: Contains the Codex app-server client, including `importExternalAgentSession()` and RPC handling.
- **`plugins/codex/scripts/codex-companion.mjs`**: Provides the CLI entry point with `executeTransfer()` and `renderTransferResult()` for user interaction.

## Summary

- **Session transfer between Claude Code and Codex** converts `.jsonl` transcripts into Codex threads via the `codex transfer` command.
- **Path validation** enforces that transcripts originate from `$HOME/.claude/projects` to prevent unauthorized file access.
- **RPC communication** uses the `externalAgentSessionImport` method to create threads with full conversation history.
- **Error handling** provides actionable feedback when Codex CLI versions lack required RPC methods or when paths fail validation.
- **Resume capability** generates `codex resume <thread-id>` commands for immediate continuation of transferred sessions.

## Frequently Asked Questions

### What file format does Claude Code use for sessions?

Claude Code stores session transcripts as **JSONL files** (newline-delimited JSON) within the `$HOME/.claude/projects` directory. The transfer pipeline specifically validates the `.jsonl` extension and ensures files reside within this protected directory structure before processing.

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

No. The `resolveClaudeSessionPath()` function enforces strict security constraints. It verifies that the source file ends with `.jsonl` and guarantees the absolute path lives inside `$HOME/.claude/projects`. Attempts to transfer files outside this directory will fail validation to prevent arbitrary file system access.

### What happens if the Codex CLI version is outdated?

The system returns detailed error messages indicating that the `externalAgentSessionImport` RPC method is unavailable. The error output includes stderr from Codex and suggests updating the Codex CLI to a version that supports external agent session imports.

### How do I resume a transferred session in Codex?

After successful transfer, the CLI outputs a resume command in the format `codex resume <thread-id>`. The `executeTransfer()` function packages this command in its return payload, allowing immediate continuation of the conversation history in the new Codex thread.