# Broker Architecture in the OpenAI Codex Plugin: When and How the Process Spawns

> Discover the lazy-start broker architecture in the OpenAI Codex plugin. Learn when and how a separate Node.js process spawns to mediate communication, ensuring efficient long-running task management.

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

---

**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`](https://github.com/openai/codex-plugin-cc/blob/main/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`](https://github.com/openai/codex-plugin-cc/blob/main/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`](https://github.com/openai/codex-plugin-cc/blob/main/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 containing `ensureBrokerSession`, `spawnBrokerProcess`, and `teardownBrokerSession`.
- **`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 invokes `ensureBrokerSession` before delegating to the broker.

## Code Examples

The following example demonstrates ensuring a broker session before executing Codex commands:

```javascript
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:

```javascript
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`](https://github.com/openai/codex-plugin-cc/blob/main/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.