# How the Codex Plugin CC Broker Endpoint and Lifecycle Work: A Complete Guide

> Understand the Codex Plugin CC broker lifecycle. Learn how it spawns, validates, and cleans up app-server brokers using platform-specific endpoints for seamless operation.

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

---

**The Codex Plugin CC manages a temporary app-server broker by generating platform-specific endpoints (Unix sockets or Windows named pipes), validating them through a readiness probe, and orchestrating the full lifecycle from process spawning to resource cleanup via `ensureBrokerSession` and `teardownBrokerSession`.**

The broker in `openai/codex-plugin-cc` mediates communication between the companion process and the Codex runtime. Understanding how the **broker endpoint** is created, parsed, and managed through its **lifecycle** is essential for debugging connection issues or extending the plugin's functionality.

## Endpoint Generation with `createBrokerEndpoint`

The `createBrokerEndpoint` function in `plugins/codex/scripts/lib/broker-endpoint.mjs` generates a platform-specific address string based on a temporary session directory.

### Platform-Specific Creation Logic

On Windows, the function builds a sanitized pipe name using the session directory basename:

```javascript
import path from "node:path";
import process from "node:process";

export function createBrokerEndpoint(sessionDir, platform = process.platform) {
  if (platform === "win32") {
    const pipeName = sanitizePipeName(`${path.win32.basename(sessionDir)}-codex-app-server`);
    return `pipe:\\\\.\\pipe\\${pipeName}`;
  }
  return `unix:${path.join(sessionDir, "broker.sock")}`;
}

```

- **Windows**: Returns a named pipe path like `pipe:\\\\.\\pipe\\my-session-codex-app-server`
- **macOS/Linux**: Returns a Unix-domain socket path like `unix:/tmp/cxc-abcd1234/broker.sock`

The function receives the session directory from `createBrokerSessionDir` in `broker-lifecycle.mjs`, ensuring each broker instance gets an isolated communication channel.

## Endpoint Parsing with `parseBrokerEndpoint`

When the companion process connects to the broker, it uses `parseBrokerEndpoint` (also in `broker-endpoint.mjs`) to validate and destructure the endpoint string:

```javascript
export function parseBrokerEndpoint(endpoint) {
  if (typeof endpoint !== "string" || endpoint.length === 0) {
    throw new Error("Missing broker endpoint.");
  }

  if (endpoint.startsWith("pipe:")) {
    const pipePath = endpoint.slice("pipe:".length);
    if (!pipePath) throw new Error("Broker pipe endpoint is missing its path.");
    return { kind: "pipe", path: pipePath };
  }

  if (endpoint.startsWith("unix:")) {
    const socketPath = endpoint.slice("unix:".length);
    if (!socketPath) throw new Error("Broker Unix socket endpoint is missing its path.");
    return { kind: "unix", path: socketPath };
  }

  throw new Error(`Unsupported broker endpoint: ${endpoint}`);
}

```

The parser strips the protocol prefix and returns a `{kind, path}` object that `net.createConnection` can consume directly. This abstraction allows the rest of the codebase to remain platform-agnostic.

## Session Lifecycle Management

The high-level orchestration happens in `plugins/codex/scripts/lib/broker-lifecycle.mjs` through the `ensureBrokerSession` function, which handles the complete **broker lifecycle** from creation to persistence.

### Session Initialization and Validation

The lifecycle begins with `loadBrokerSession`, which attempts to read existing session data from [`broker.json`](https://github.com/openai/codex-plugin-cc/blob/main/broker.json) in the Codex state directory (`resolveStateDir`). If a session exists, `waitForBrokerEndpoint` validates it by repeatedly attempting to connect via `net.createConnection` until a 2-second timeout expires.

### Broker Process Spawning

If no valid session exists, the lifecycle proceeds to create a fresh broker:

1. **Tear down** any stale session via `teardownBrokerSession`
2. **Create** a temporary directory with `createBrokerSessionDir`
3. **Generate** the endpoint using the injected `createBrokerEndpoint` factory
4. **Spawn** the broker process via `spawnBrokerProcess`, which executes `app-server-broker.mjs`
5. **Write** PID and log files to the session directory for later cleanup
6. **Wait** for readiness using `waitForBrokerEndpoint`—if the broker fails to open its socket within the timeout, the process is terminated and the function returns `null`

### Persistence and Reuse

Once the broker is ready, `saveBrokerSession` persists the session data to disk. Subsequent calls to `ensureBrokerSession` will discover and reuse this existing broker rather than spawning a new process, significantly reducing startup latency.

## Teardown and Cleanup with `teardownBrokerSession`

When the companion shuts down or a new session is requested, `teardownBrokerSession` performs deterministic cleanup:

```javascript
// Simplified conceptual flow
await sendBrokerShutdown(session.endpoint); // Sends JSON-RPC shutdown message
teardownBrokerSession(session, { killProcess: process.kill });

```

The teardown process:

- **Terminates** the broker process if a `killProcess` callback is provided (typically `process.kill`)
- **Removes** PID files and log files from the session directory
- **Unlinks** the Unix socket file (Windows pipes are automatically cleaned up by the OS)
- **Deletes** the temporary session directory using `fs.rmdirSync` (best-effort)

The function tolerates missing files and malformed endpoints to ensure cleanup is robust even when the broker exits unexpectedly.

## Complete Interaction Flow

A typical runtime session follows this deterministic sequence:

1. **Companion startup** calls `ensureBrokerSession(cwd)`
2. **Discovery**: If a valid broker exists, return its endpoint immediately
3. **Creation**: Otherwise, create a temp directory, generate the endpoint string, and spawn `app-server-broker.mjs`
4. **Validation**: Repeatedly connect to the endpoint until the broker signals readiness
5. **Communication**: Use `net.createConnection` with the parsed endpoint path to send JSON-RPC messages (e.g., `broker/shutdown`)
6. **Shutdown**: Call `sendBrokerShutdown` to gracefully exit the broker, then invoke `teardownBrokerSession` to remove all artifacts

This flow ensures no orphaned processes or stale socket files remain after the Codex runtime terminates.

## Practical Usage Example

Below is a minimal implementation showing how to integrate the broker utilities into a companion process:

```javascript
import { ensureBrokerSession, teardownBrokerSession, sendBrokerShutdown } from "./lib/broker-lifecycle.mjs";
import { parseBrokerEndpoint } from "./lib/broker-endpoint.mjs";
import net from "node:net";

async function startAndUseBroker(cwd) {
  // Obtain or create a broker session
  const session = await ensureBrokerSession(cwd);
  if (!session) throw new Error("Failed to start broker");

  // Parse the endpoint and connect
  const { path } = parseBrokerEndpoint(session.endpoint);
  const socket = net.createConnection({ path });
  
  // Send JSON-RPC request
  socket.write(JSON.stringify({ id: 1, method: "ping", params: {} }) + "\n");
  socket.on("data", (data) => console.log("Broker reply:", data.toString()));
  
  // Graceful shutdown sequence
  await sendBrokerShutdown(session.endpoint);
  teardownBrokerSession(session);
}

```

## Summary

- **Endpoint generation** in `broker-endpoint.mjs` produces platform-specific addresses using `createBrokerEndpoint`, returning Windows named pipes (`pipe:\\...`) or Unix sockets (`unix:/...`).
- **Parsing** via `parseBrokerEndpoint` validates endpoint strings and returns structured `{kind, path}` objects for `net.createConnection`.
- **Lifecycle management** in `broker-lifecycle.mjs` uses `ensureBrokerSession` to load existing sessions, validate endpoints with a 2-second timeout, spawn new brokers when needed, and persist session data.
- **Cleanup** through `teardownBrokerSession` removes PID files, unlinks sockets, deletes temporary directories, and terminates processes without leaving orphaned resources.
- **Test coverage** in `tests/broker-endpoint.test.mjs`, `tests/runtime.test.mjs`, and `tests/process.test.mjs` validates parsing logic and the complete start-to-finish lifecycle.

## Frequently Asked Questions

### How does the broker handle platform differences between Windows and Unix systems?

The broker uses a unified endpoint string format handled by `createBrokerEndpoint` and `parseBrokerEndpoint` in `broker-endpoint.mjs`. On Windows, it generates named pipes with the `pipe:` prefix, while on macOS and Linux it uses Unix-domain sockets with the `unix:` prefix. The parsing function abstracts these differences by returning a consistent `{kind, path}` object that the networking layer can consume regardless of platform.

### What happens if the broker process fails to start or crashes?

If `waitForBrokerEndpoint` cannot establish a connection within the default 2-second timeout, `ensureBrokerSession` terminates the spawned process and returns `null`. The calling companion code can then handle the failure appropriately. During teardown, `teardownBrokerSession` is designed to tolerate missing files and malformed endpoints, ensuring that cleanup succeeds even if the broker exited unexpectedly or failed to initialize properly.

### Can multiple Codex sessions reuse the same broker process?

No, each session receives its own isolated broker. The `ensureBrokerSession` function looks for existing sessions in the Codex state directory, but if a session is found to be invalid or if `teardownBrokerSession` has been called, a new temporary directory and endpoint are generated. This design ensures process isolation and prevents JSON-RPC message crosstalk between different companion instances.

### Where is the broker session data stored between runs?

Session data is persisted to a [`broker.json`](https://github.com/openai/codex-plugin-cc/blob/main/broker.json) file inside the Codex state directory, which is resolved via `resolveStateDir` in `broker-lifecycle.mjs`. This file contains the endpoint string and process information. When `ensureBrokerSession` is called subsequently, it reads this file to determine if a valid broker is already running before attempting to spawn a new one.