How External Agent Sessions Are Imported into Codex: A Technical Deep Dive
Codex imports external agent sessions by constructing a migration payload, sending it to the App Server via the externalAgentConfig/import RPC, and awaiting a completion notification before recording the thread ID in a local ledger.
The openai/codex-plugin-cc repository implements a robust pipeline for migrating external agent conversations—specifically Claude sessions—into Codex's native thread format. Understanding how external agent sessions are imported into Codex requires examining the migration payload structure, the RPC communication protocol, and the persistent ledger system that tracks imported threads.
Building the Migration Payload
The import process begins with constructing a structured payload that describes the external session files to transfer. In plugins/codex/scripts/lib/codex.mjs, the externalAgentSessionMigration(sourcePath, cwd) function (lines 81-98) generates a JSON object containing a migrationItems array.
Each migration item type is categorized as SESSIONS, specifying the absolute path to the Claude session file (sourcePath) and optionally the working directory (cwd) for context preservation. This payload serves as the canonical description of what data should migrate from the external agent into Codex.
// From codex.mjs lines 81-98
const migrationPayload = externalAgentSessionMigration(
"/path/to/claude-session.jsonl", // The exported Claude conversation
"/home/user/projects/demo" // Optional working directory context
);
Sending the Import Request via RPC
Once the payload is constructed, the system initiates asynchronous communication with the Codex App Server. The requestExternalAgentSessionImport(client, params) function (lines 101-130 in codex.mjs) handles this exchange using the CodexAppServerClient provided by plugins/codex/scripts/lib/app-server.mjs.
The function invokes client.request("externalAgentConfig/import", params) to transmit the migration payload. It simultaneously registers a temporary notification handler that listens for the EXTERNAL_AGENT_IMPORT_COMPLETED event (emitted as externalAgentConfig/import/completed). A timeout mechanism guards against hanging operations, rejecting the promise if the server fails to respond within the allocated window.
// From codex.mjs lines 101-130
await requestExternalAgentSessionImport(codexClient, migrationPayload);
Tracking Sessions in the Import Ledger
After successful import, Codex persists a mapping between the external source and the newly generated Codex thread. The ledger resides in external_agent_session_imports.json within the Codex home directory ($CODEX_HOME or ~/.codex).
Each entry records the source file's absolute path and its SHA-256 hash, mapping these identifiers to the generated Codex thread ID. The importedThreadIdForSource function (lines 61-78 in codex.mjs) enables later retrieval of the thread ID using the original source file path, allowing users to resume imported sessions with codex resume <thread-id>.
// From codex.mjs lines 61-78
const threadId = importedThreadIdForSource("/path/to/claude-session.jsonl");
console.log(`Resumable thread ID: ${threadId}`);
Complete Import Workflow Example
The following implementation demonstrates the end-to-end flow for importing a Claude session into Codex, combining payload construction, RPC transmission, and thread retrieval:
import {
externalAgentSessionMigration,
requestExternalAgentSessionImport,
importedThreadIdForSource
} from "./plugins/codex/scripts/lib/codex.mjs";
import { CodexAppServerClient } from "./plugins/codex/scripts/lib/app-server.mjs";
// 1️⃣ Build the migration payload
const payload = externalAgentSessionMigration(
"/exports/claude-session.jsonl",
"/workspace/project"
);
// 2️⃣ Initialize the App Server client
const client = new CodexAppServerClient();
// 3️⃣ Send import request and await completion
await requestExternalAgentSessionImport(client, payload);
// 4️⃣ Retrieve the mapped Codex thread ID
const codexThread = importedThreadIdForSource("/exports/claude-session.jsonl");
console.log(`Import complete. Resume with: codex resume ${codexThread}`);
Summary
- Migration payloads describe external sessions using the
SESSIONSitem type inexternalAgentSessionMigration, specifying source paths and working directories. - RPC communication utilizes the
externalAgentConfig/importendpoint with completion signaled by theEXTERNAL_AGENT_IMPORT_COMPLETEDnotification event. - Timeout protection prevents indefinite hangs during the import operation.
- Persistent ledger stores SHA-256 hashed source mappings in
external_agent_session_imports.json, enabling thread ID lookup viaimportedThreadIdForSource. - Integration occurs through commands like
transfer, which orchestrate the full pipeline from external agent export to resumable Codex thread.
Frequently Asked Questions
What RPC endpoint handles external agent session imports in Codex?
Codex uses the externalAgentConfig/import RPC endpoint to receive migration payloads. According to the source code in plugins/codex/scripts/lib/codex.mjs, the requestExternalAgentSessionImport function transmits the payload via client.request("externalAgentConfig/import", params) and awaits the externalAgentConfig/import/completed notification.
How does Codex prevent duplicate imports of the same session?
The system tracks imported sessions using a ledger file (external_agent_session_imports.json) that stores the SHA-256 hash of the source file content alongside its absolute path. When checking for existing imports via importedThreadIdForSource, Codex verifies these identifiers to return the existing thread ID rather than creating duplicates.
Where does Codex store the mapping between external sessions and Codex threads?
Codex persists the mapping in external_agent_session_imports.json located in the Codex home directory ($CODEX_HOME or ~/.codex). This JSON ledger maps the external source file's path and hash to the generated Codex thread ID, enabling seamless resumption of imported conversations.
What happens if the import request times out?
The requestExternalAgentSessionImport function implements a timeout guard that rejects the promise if the server fails to emit the EXTERNAL_AGENT_IMPORT_COMPLETED event within the expected timeframe. This prevents the client from hanging indefinitely during network interruptions or server-side failures.
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 →