How Session Transfer Between Claude Code and Codex Works: A Technical Deep Dive
Session transfer between Claude Code and Codex works by persisting the Codex interaction history to a JSON transcript file that Claude later imports and restores as its own conversation state.
The openai/codex-plugin-cc repository implements this bidirectional handoff through a shared file-based protocol. Codex writes its session after each interaction, Claude reads that transcript when the user invokes the Transfer command, and both agents append updates to maintain continuity. This article breaks down the mechanism using the actual source code implementation.
How the Transcript Path Gets Resolved
Every session transfer starts with identifying where the transcript lives. The plugin uses resolveClaudeSessionPath in plugins/codex/scripts/lib/claude-session-transfer.mjs to determine this location.
The function checks three sources in order:
TRANSCRIPT_PATH_ENVenvironment variable — highest priority override- User-specified path via CLI flag (
--session-path) - Default workspace location (
./.codex/session.json)
import { resolveClaudeSessionPath } from "./lib/claude-session-transfer.mjs";
const transcriptPath = resolveClaudeSessionPath(process.cwd(), {
sessionPath: "./.codex/session.json", // optional override
});
This resolution logic ensures flexibility. Developers can store transcripts alongside project files, in temporary directories, or in CI artifacts without hardcoding paths throughout the codebase.
Writing the Codex Session Transcript
Once the path is resolved, the Codex runtime serializes its full interaction state. This happens in plugins/codex/scripts/lib/state.mjs, where the session is converted to JSON containing:
- Complete message history
- Code snippets and tool outputs
- Tool call metadata
// Persist the current session
await writeFile(transcriptPath, JSON.stringify(sessionState));
The write occurs after each significant operation, ensuring the transcript remains current if the user triggers a transfer mid-session.
Importing the Session into Claude Code
Claude's side of the transfer is handled by session-lifecycle-hook.mjs. When the user invokes the Transfer command, this hook:
- Resolves the same transcript path using
resolveClaudeSessionPath - Reads and parses the JSON content
- Reconstructs Claude's conversation state from the message array
import { resolveClaudeSessionPath } from "./lib/claude-session-transfer.mjs";
export async function importClaudeSession(cwd) {
const path = resolveClaudeSessionPath(cwd);
const content = await readFile(path, "utf-8");
const session = JSON.parse(content);
// Rebuild Claude's conversation from the transcript
await claude.setConversation(session.messages);
}
This restoration is stateful — Claude continues the dialogue exactly where Codex left off, preserving context, file references, and prior reasoning.
Bidirectional Continuity
The session transfer is cyclical, not one-directional. After Claude completes its portion:
- New messages are appended to the same transcript file
- The updated transcript can be re-imported by Codex for subsequent operations
- Both agents maintain synchronization through this single source of truth
This design avoids protocol complexity. There's no direct IPC, no network socket, and no shared memory — just a JSON file both tools can read and write.
Configuring the Transfer Environment
The plugin exposes two configuration mechanisms for controlling transcript behavior:
| Method | Implementation | Use Case |
|---|---|---|
| Environment variable | TRANSCRIPT_PATH_ENV in shell environment |
CI/CD pipelines, persistent workspace setups |
| CLI flag | --session-path handled in plugins/codex/scripts/lib/args.mjs |
Ad-hoc transfers, temporary sessions |
Example with environment variable:
export TRANSCRIPT_PATH_ENV=/tmp/shared-session.json
npx codex --plugin cc
Example with CLI flag:
npx codex --plugin cc --session-path ./sessions/feature-branch.json
Summary
resolveClaudeSessionPathinclaude-session-transfer.mjsdetermines where the transcript lives using environment variables, CLI flags, or defaults- Codex writes its full session state to this JSON file via
state.mjsafter each interaction - Claude reads and restores the same transcript through
session-lifecycle-hook.mjswhen the Transfer command runs - Both agents append updates to maintain bidirectional continuity without direct communication
- Configuration flexibility comes from the
TRANSCRIPT_PATH_ENVvariable and--session-pathCLI argument parsed inargs.mjs
Frequently Asked Questions
How does Claude access the Codex session without direct API communication?
Claude accesses the Codex session through a shared JSON transcript file, not through API calls. Codex writes its interaction history to this file, and Claude reads from the same location when importing. This file-based approach avoids network dependencies and makes the transfer mechanism portable across different environments.
What happens to the transcript file after Claude finishes its session?
New messages from Claude's session are appended to the same transcript file. This updated file can then be re-imported by Codex, creating a continuous loop where both agents contribute to and read from a single conversation history. The transcript serves as the persistent source of truth for the entire collaborative session.
Can multiple Codex sessions point to the same transcript?
Yes, by configuring TRANSCRIPT_PATH_ENV or --session-path to the same location. However, concurrent writes from multiple Codex processes would corrupt the transcript. The plugin assumes single-writer semantics — design your workflow so only one agent writes at a time, or implement external locking if parallel access is required.
Where is the Transfer command documented for end users?
User-facing documentation for the Transfer command resides in plugins/codex/commands/transfer.md. This file explains how to invoke the command, what prerequisites exist for the transcript file, and any limitations or edge cases users should understand when handing off between Claude Code and Codex.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →