How the Broker Endpoint Works for Shared Codex Runtime in openai/codex-plugin-cc

The broker endpoint is a platform-specific address (Unix socket or Windows named pipe) that enables multiple client processes to share a single Codex app-server instance through JSON-RPC communication.

In the openai/codex-plugin-cc repository, the broker endpoint serves as the critical communication bridge for shared runtime mode. When you run multiple Codex commands in the same workspace, this endpoint ensures they all route through one persistent app-server process rather than spawning duplicates. Understanding how this endpoint is generated, parsed, and managed is essential for anyone working with the Codex plugin architecture.

How the Broker Endpoint Is Generated

The endpoint creation logic lives in plugins/codex/scripts/lib/broker-endpoint.mjs. The createBrokerEndpoint(sessionDir, platform) function produces a transport-specific address based on the operating system.

Unix-like platforms

On macOS and Linux, the function returns a Unix socket path prefixed with unix::

// broker-endpoint.mjs, lines 10-16
export function createBrokerEndpoint(sessionDir, platform) {
  if (platform !== 'win32') {
    return `unix:${path.join(sessionDir, 'broker.sock')}`;
  }
  // Windows handling...
}

The resulting string looks like unix:/tmp/cxc-12345/broker.sock.

Windows platforms

On Windows, the function sanitizes the session directory name and creates a named pipe:

// broker-endpoint.mjs, lines 11-14
const sanitized = sessionDir.replace(/[\\/]/g, '-');
const name = `codex-${sanitized}`;
return `pipe:\\\\..\\pipe\\${name}-codex-app-server`;

The pipe: prefix signals the transport type to downstream parsing logic. This abstraction allows the same broker code to operate across platforms without modification.

The generated endpoint is stored in a temporary session directory created by createBrokerSessionDir() in broker-lifecycle.mjs (lines 15-18).

Parsing and Validating the Endpoint

When the broker process starts, it must interpret the endpoint string to open the correct transport. The parseBrokerEndpoint(endpoint) function (lines 19-40) splits the string into a structured {kind, path} object:

  • Pipe transport: Recognized by the pipe: prefix (lines 24-30)
  • Unix transport: Recognized by the unix: prefix (lines 32-38)
  • Invalid transport: Unknown prefixes trigger an explicit error (line 40)

The parsed object is then passed to Node.js net.createConnection or net.createServer to establish the actual socket or pipe connection (see broker-lifecycle.mjs lines 19-22).

This two-phase approach—generate as a string, then parse into structured data—keeps the CLI interface simple while preserving runtime type safety.

Broker Lifecycle Integration

The endpoint orchestrates three critical lifecycle phases in broker-lifecycle.mjs:

Session creation

ensureBrokerSession() (lines 31-34) coordinates endpoint generation with process spawning:

  1. Calls the endpoint factory (defaulting to createBrokerEndpoint)
  2. Writes a PID file for tracking
  3. Spawns app-server-broker.mjs with the endpoint as a command-line argument

Readiness verification

waitForBrokerEndpoint() (lines 24-40) implements an active polling loop that attempts connections until the socket responds. This guarantees the broker is listening before any client transmits JSON-RPC messages, preventing race conditions during startup.

Graceful shutdown

sendBrokerShutdown(endpoint) (lines 43-56) opens a dedicated connection, sends the special broker/shutdown JSON-RPC method, and awaits confirmation. This ensures clean termination rather than orphaned processes.

Broker Process Behavior

The actual broker implementation in plugins/codex/scripts/app-server-broker.mjs consumes the parsed endpoint to establish its server:

Behavior Endpoint Usage
Listen for connections server.listen(listenTarget.path) (line 46), where listenTarget comes from parseBrokerEndpoint(endpoint) (line 64)
Route JSON-RPC requests Messages received on the socket are forwarded to appClient.request; only one active socket allowed—additional connections receive a busy error (lines 73-82)
Handle shutdown broker/shutdown method triggers shutdown(server) which removes the Unix socket file if present (lines 108-110)

The mutual exclusion guarantee is enforced at the socket level: the broker tracks a single active request socket and rejects concurrent attempts. This serializes access to the underlying Codex app-server without requiring complex locking primitives.

Why the Broker Endpoint Matters for Shared Runtime

When developers run sequential Codex commands—codex review followed by codex turn—the shared runtime mode reuses the same broker process for efficiency. The endpoint architecture enables this through three properties:

  • Address stability: The session-derived path remains constant for a given workspace, allowing second and third commands to locate the running broker
  • Cross-platform transport abstraction: Identical JSON-RPC logic operates over Unix sockets or Windows named pipes
  • Explicit lifecycle boundaries: Endpoint creation, polling, and shutdown form a complete state machine with clear failure modes

The test suite in tests/broker-endpoint.test.mjs validates platform-specific formatting and round-trip parsing (lines 6-22), preventing regressions in transport compatibility.

Code Examples

Creating an endpoint for a new shared session

import { createBrokerEndpoint } from 
  'plugins/codex/scripts/lib/broker-endpoint.mjs';

const sessionDir = '/tmp/cxc-abcdef';
const endpoint = createBrokerEndpoint(sessionDir, process.platform);
// macOS/Linux: "unix:/tmp/cxc-abcdef/broker.sock"
// Windows: "pipe:\\\\..\\pipe\\codex-tmp-cxc-abcdef-codex-app-server"

Parsing an endpoint inside the broker process

import { parseBrokerEndpoint } from 
  'plugins/codex/scripts/lib/broker-endpoint.mjs';

const endpointArg = process.argv[3]; // "--endpoint", "unix:/tmp/cxc-abc/broker.sock"
const { kind, path } = parseBrokerEndpoint(endpointArg);

// kind: 'unix', path: '/tmp/cxc-abc/broker.sock'
// These values feed directly into net.createServer()

Spawning the broker with full lifecycle management

import {
  ensureBrokerSession,
  sendBrokerShutdown
} from 'plugins/codex/scripts/lib/broker-lifecycle.mjs';

// Start shared runtime
const session = await ensureBrokerSession(process.cwd());
console.log('Broker ready at:', session.endpoint);

// Later: clean termination
await sendBrokerShutdown(session.endpoint);

Summary

  • The broker endpoint is a platform-prefixed address (unix: or pipe:) stored in a temporary session directory
  • createBrokerEndpoint() generates transport-specific strings while parseBrokerEndpoint() validates and structures them for Node.js networking APIs
  • The broker lifecycle (creation → readiness polling → shutdown) coordinates process management around endpoint availability
  • Mutual exclusion is enforced by socket ownership in app-server-broker.mjs, serializing access to the Codex app-server
  • Platform abstraction allows identical JavaScript code to run on Linux, macOS, and Windows without transport-specific branching

Frequently Asked Questions

What happens if two Codex commands run simultaneously?

The broker endpoint enforces single active connection semantics. The first client socket receives full JSON-RPC service; subsequent connections receive an immediate error response indicating the broker is busy. Commands must serialize through the endpoint or retry.

How does the broker handle stale endpoint files from crashed processes?

ensureBrokerSession() detects stale endpoints during session creation. If the endpoint exists but no process responds to connection attempts, the lifecycle manager tears down the orphaned resources and initializes a fresh broker with a clean endpoint.

Can the broker endpoint be customized for custom deployments?

The ensureBrokerSession() function accepts an optional createEndpoint parameter, allowing injection of alternative endpoint factories. By default it uses createBrokerEndpoint, but deployments with specific socket path requirements can substitute custom logic while maintaining the same kind:path parsing contract.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →