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

> Understand session transfer between Claude Code and Codex plugin. Learn how the codex transfer CLI command reconstructs execution context, including open files and cursor positions.

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

---

**Session transfer imports Claude Code’s JSONL transcript into the Codex plugin via the `codex transfer` CLI command, reconstructing the exact execution context including open files, cursor positions, and job history.**

The `openai/codex-plugin-cc` repository implements a seamless hand-off mechanism that lets developers migrate active coding sessions from Claude Code into the Codex plugin environment. This process preserves the full state of your work—active jobs, file buffers, and conversation history—by parsing Claude’s transcript files and rehydrating them inside Codex’s broker system. Understanding this **session transfer between Claude Code and Codex plugin** requires examining the validation logic, environment variable handling, and lifecycle hooks that make the transition possible.

## The Four-Step Session Transfer Process

The transfer flow follows a strict pipeline from export to restoration. Each step is guarded by validation logic to ensure security and data integrity.

### 1. Export the Claude Code Session

Claude Code automatically persists interaction history to a JSON Lines (`.jsonl`) file located within the user’s home directory. The standard path follows the pattern `~/.claude/projects/<project-id>/session.jsonl`. This file contains the complete transcript of the coding session, including tool calls, file modifications, and user prompts.

### 2. Invoke the Codex Transfer Command

To initiate the transfer, the user runs the CLI command `codex transfer --source <path>`. According to the command documentation in [`plugins/codex/commands/transfer.md`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/commands/transfer.md), this invocation sets the environment variable `CODEX_COMPANION_TRANSCRIPT_PATH` and triggers the resolution workflow. Alternatively, you can set this environment variable manually before starting Codex.

### 3. Load and Validate the Transcript

The companion process (`codex-companion.mjs`) calls `resolveClaudeSessionPath` from `plugins/codex/scripts/lib/claude-session-transfer.mjs` to validate the source file. This function performs critical security checks: it resolves real paths, verifies the `.jsonl` extension, and ensures the file resides within `~/.claude/projects` to prevent directory traversal attacks.

### 4. Restore Session State via Lifecycle Hooks

Once validated, the transcript is parsed and the session state is reconstructed. The `session-lifecycle-hook.mjs` script registers the restored jobs with Codex’s broker, making them available to subsequent commands like `codex review` or `codex result`.

## Security Validation: The Path Resolution Logic

The `resolveClaudeSessionPath` function in `plugins/codex/scripts/lib/claude-session-transfer.mjs` implements strict path validation to prevent arbitrary file access. The function prefers an explicit `--source` flag but falls back to the `CODEX_COMPANION_TRANSCRIPT_PATH` environment variable.

```javascript
export const TRANSCRIPT_PATH_ENV = "CODEX_COMPANION_TRANSCRIPT_PATH";
const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), ".claude", "projects");

export function resolveClaudeSessionPath(cwd, options = {}) {
  const requestedPath = options.source || process.env[TRANSCRIPT_PATH_ENV];
  if (!requestedPath) {
    throw new Error(
      "Could not identify the current Claude transcript. Retry with --source <path-to-claude-jsonl>."
    );
  }

  const sourcePath = resolveUserPath(cwd, requestedPath);
  if (path.extname(sourcePath) !== ".jsonl") {
    throw new Error(`Claude session source must be a JSONL file: ${sourcePath}`);
  }

  // Ensure the file is inside ~/.claude/projects
  const source = fs.realpathSync(sourcePath);
  const projects = fs.realpathSync(CLAUDE_PROJECTS_DIR);
  const relative = path.relative(projects, source);
  if (
    relative === "" ||
    relative === ".." ||
    relative.startsWith(`..${path.sep}`) ||
    path.isAbsolute(relative)
  ) {
    throw new Error(
      `Codex can import Claude sessions only from ${CLAUDE_PROJECTS_DIR}: ${source}`
    );
  }
  return source;
}

```

This validation ensures that **only transcripts within the Claude projects directory** can be imported, effectively sandboxing the file system access. The function normalizes tildes (`~`), resolves symbolic links, and calculates relative paths to confirm the file remains within the allowed boundary.

## Practical Example: Transferring a Session

To transfer a session from Claude Code to the Codex plugin, execute the following workflow in your terminal:

```bash

# Step 1: Locate the Claude session file

# (Typically at ~/.claude/projects/my-project/session.jsonl)

# Step 2: Transfer the session to Codex

$ codex transfer --source ~/.claude/projects/my-project/session.jsonl

# This sets CODEX_COMPANION_TRANSCRIPT_PATH and validates the file

# Step 3: Verify the transferred state

$ codex status

# Output shows jobs recreated from the Claude transcript

# Step 4: Continue working with Codex commands

$ codex review

```

For automation or CI/CD pipelines, you can bypass the transfer command and use the environment variable directly:

```bash
export CODEX_COMPANION_TRANSCRIPT_PATH=~/.claude/projects/my-project/session.jsonl
$ codex status

```

The companion process (`codex-companion.mjs`) automatically detects this variable on startup and invokes the resolution logic before initializing the broker.

## Key Implementation Files

The session transfer functionality spans several modules in the `openai/codex-plugin-cc` repository:

- **`plugins/codex/scripts/lib/claude-session-transfer.mjs`** – Contains `resolveClaudeSessionPath`, which validates transcript paths and enforces directory restrictions.
- **`plugins/codex/scripts/codex-companion.mjs`** – Main entry point that loads the transcript and initializes the broker process.
- **`plugins/codex/scripts/session-lifecycle-hook.mjs`** – Registers restored jobs with the broker after transcript parsing.
- **[`plugins/codex/commands/transfer.md`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/commands/transfer.md)** – Documentation for the `codex transfer` CLI interface.
- **`plugins/codex/scripts/lib/fs.mjs`** – Provides path resolution utilities including `ensureAbsolutePath` used during validation.

## Summary

- **Session transfer** enables seamless migration from Claude Code to Codex by importing `.jsonl` transcript files.
- The `codex transfer --source <path>` command sets `CODEX_COMPANION_TRANSCRIPT_PATH` and triggers validation.
- `resolveClaudeSessionPath` enforces security by restricting imports to the `~/.claude/projects` directory.
- The companion process reconstructs job history and file states, registering them via `session-lifecycle-hook.mjs`.
- Once transferred, standard Codex commands operate on the restored context without requiring manual state replication.

## Frequently Asked Questions

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

Claude Code exports sessions as **JSON Lines (`.jsonl`)** files. Each line represents a discrete interaction or event from the coding session. The Codex plugin specifically checks for this extension in `resolveClaudeSessionPath` and rejects files with mismatched extensions to ensure proper parsing.

### Can I transfer sessions from arbitrary directories outside of Claude’s project folder?

No. The security logic in `claude-session-transfer.mjs` explicitly blocks paths that escape the `~/.claude/projects` directory. The code calculates the relative path between the requested file and the projects directory, throwing an error if the result starts with `..` or resolves to an absolute path, preventing directory traversal vulnerabilities.

### How does Codex handle job history after transferring a session?

The `session-lifecycle-hook.mjs` script parses the JSONL entries and reconstructs each job object (such as `codex-cli-runtime` or `codex-result-handling`), then registers them with the Codex broker. This allows subsequent commands like `codex review` to operate on the exact same job context that existed in Claude Code, preserving the execution state and file handles.

### Is the `CODEX_COMPANION_TRANSCRIPT_PATH` environment variable required for every Codex startup?

Only if you want to resume a transferred session automatically. If the variable is unset, Codex starts with a fresh session. When set—either manually or via the `codex transfer` command—the companion process treats it as a directive to import the specified transcript before initializing the interactive loop.