Broker Architecture in the OpenAI Codex Plugin: When and How the Process Spawns
The Codex plugin implements a lazy-start broker architecture that spawns a separate Node.js process on demand to mediate communication between the main script and long-running tasks, communicating over Unix sockets or Windows named pipes.
The openai/codex-plugin-cc repository uses a lightweight broker process to isolate long-running operations from the main Codex companion script. This broker architecture ensures that resource-intensive tasks like code review and result handling run in a background process without blocking the primary execution flow.
What Is the Broker Architecture?
The broker architecture is an IPC (Inter-Process Communication) bridge implemented as a minimal app-server. It runs as a detached Node.js child process that handles JSON-RPC messages between the main Codex plugin and persistent operations. According to the source code in app-server-broker.mjs, this process listens on platform-specific endpoints—Unix domain sockets on macOS/Linux or named pipes on Windows—to accept commands and manage stateful workloads.
When Is the Broker Process Spawned?
The broker follows a lazy-start pattern. A new process is spawned only when ensureBrokerSession() is called and no existing broker endpoint is reachable. In practice, this occurs the first time a Codex command requiring the companion app server executes—such as codex review or codex result—and subsequent commands reuse the same process until it crashes, the PID file is removed, or the session is explicitly torn down.
Broker Lifecycle Step-by-Step
The lifecycle implementation in broker-lifecycle.mjs manages the entire span from initialization to shutdown.
1. Session Directory Creation
The createBrokerSessionDir() function generates a temporary directory under the OS temp folder. This directory stores the broker's socket file, PID file, and log file, ensuring isolated storage for each session.
2. Endpoint Resolution
The createBrokerEndpoint() function in broker-endpoint.mjs constructs platform-specific endpoint strings. On Unix systems, it returns a path like unix:/tmp/cxc-{hash}/broker.sock, while on Windows it generates a named pipe such as pipe:\\.\pipe\cxc-{hash}.
3. Session Validation
When ensureBrokerSession() executes, it checks for an existing broker.json state file. If found, the function calls waitForBrokerEndpoint() to verify the socket or pipe is still accepting connections. If reachable, the existing session is reused immediately.
4. Stale Session Teardown
If a broker.json file exists but the endpoint is unreachable (indicating a crash or stale process), teardownBrokerSession() cleans up orphaned PID files, log files, and socket paths before clearing the state file.
5. Process Spawning
When no valid session exists, spawnBrokerProcess() launches app-server-broker.mjs using Node's child_process.spawn. The child receives the endpoint path, working directory, PID file location, and log file location as arguments, then runs detached in the background via child.unref().
6. Readiness Detection
After spawning, ensureBrokerSession() polls the endpoint using waitForBrokerEndpoint(). Once the socket accepts a connection, the broker is considered ready, and session metadata (endpoint, pidFile, logFile) is persisted to broker.json for future reuse.
7. Graceful Shutdown
To terminate the broker, the main process sends a JSON-RPC "broker/shutdown" message via sendBrokerShutdown(). The broker process receives this command, cleans up its socket or pipe, removes its PID and log files, and exits cleanly.
Key Implementation Files
broker-lifecycle.mjs: Core implementation containingensureBrokerSession,spawnBrokerProcess, andteardownBrokerSession.broker-endpoint.mjs: Endpoint generation and parsing logic (createBrokerEndpoint).app-server-broker.mjs: The actual broker process entry point that handles JSON-RPC requests.app-server.mjs: Higher-level wrapper that invokesensureBrokerSessionbefore delegating to the broker.
Code Examples
The following example demonstrates ensuring a broker session before executing Codex commands:
import { ensureBrokerSession } from "./lib/broker-lifecycle.mjs";
import net from "net";
async function runWithBroker(cwd) {
// Starts the broker if needed and returns its endpoint
const session = await ensureBrokerSession(cwd, {
env: process.env,
timeoutMs: 3000,
});
if (!session) {
throw new Error("Failed to start the Codex broker");
}
// Connect to the broker via the platform-specific endpoint
const { path } = parseBrokerEndpoint(session.endpoint);
const socket = net.createConnection({ path });
// Send/receive JSON-RPC messages...
}
For low-level process control, you can spawn the broker directly:
import { spawnBrokerProcess } from "./lib/broker-lifecycle.mjs";
const child = spawnBrokerProcess({
scriptPath: "/path/to/app-server-broker.mjs",
cwd: "/my/project",
endpoint: "unix:/tmp/cxc-abc123/broker.sock",
pidFile: "/tmp/cxc-abc123/broker.pid",
logFile: "/tmp/cxc-abc123/broker.log",
env: process.env,
});
// The child is detached and runs independently
child.unref();
Summary
- The broker architecture isolates long-running tasks in a separate Node.js process to prevent blocking the main Codex execution.
- The process is spawned lazily via
ensureBrokerSession()only when no reachable endpoint exists. - Communication occurs over Unix domain sockets or Windows named pipes using JSON-RPC.
- The lifecycle is managed through
broker-lifecycle.mjs, which handles session creation, validation, spawning, and teardown. - Shutdown is requested via the
"broker/shutdown"JSON-RPC method.
Frequently Asked Questions
When does the Codex plugin spawn a new broker process?
A new broker process spawns the first time ensureBrokerSession() is called and no existing broker endpoint is reachable. This typically happens on the initial execution of commands like codex review or any skill that requires the companion app server.
How does the Codex broker communicate with the main process?
The broker communicates over platform-specific IPC channels: Unix domain sockets on macOS/Linux (paths like unix:/tmp/.../broker.sock) and named pipes on Windows (paths like pipe:\\.\pipe\...). The protocol uses JSON-RPC messages sent over these connections.
What happens if the Codex broker crashes or becomes unreachable?
If ensureBrokerSession() detects an existing broker.json state file but waitForBrokerEndpoint() fails to connect, the system calls teardownBrokerSession() to clean up stale PID files, log files, and socket paths. A fresh broker process is then spawned automatically.
How do I manually shut down the Codex broker process?
Send a JSON-RPC "broker/shutdown" request to the broker endpoint using sendBrokerShutdown(). The broker will remove its socket/pipe, delete its PID and log files, and terminate gracefully.
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 →