How the OpenAI Codex Plugin Manages Broker Session State: Persistence and Lifecycle Control
The Codex Companion plugin persists broker session state to a JSON file (broker.json) in the repository's state directory, enabling lazy reuse of live broker processes across invocations while ensuring deterministic cleanup of stale or orphaned resources.
The OpenAI Codex Companion plugin (openai/codex-plugin-cc) uses an optional broker process to mediate communication between the plugin and the Codex app-server. To avoid spawning duplicate processes and ensure reliable reconnection, the plugin implements a robust broker session state management system that tracks process metadata, Unix socket endpoints, and lifecycle status on disk.
Where Broker Session State Is Stored
The plugin persists session data as JSON in the repository’s state directory, resolved via resolveStateDir. The helper resolveBrokerStateFile(cwd) constructs the full path to a file named broker.json for a given working directory (lines 13‑14, 72‑74). This file acts as the single source of truth for broker metadata, allowing the plugin to reconnect to an existing broker or determine when a new one must be spawned.
Anatomy of the Session Object
A broker session object contains five critical keys that are populated in ensureBrokerSession:
endpoint– The Unix socket path the broker listens on, created bycreateBrokerEndpointpidFile– Path to a file storing the broker’s process IDlogFile– Path to the broker’s stdout/stderr log filesessionDir– Temporary directory holding the socket, PID file, and logpid– Process ID of the spawned broker process
The object is written to disk as pretty‑printed JSON via saveBrokerSession (lines 89‑93).
The Session Lifecycle: From Creation to Teardown
The core routine ensureBrokerSession(cwd, options) orchestrates the entire lifecycle of the broker session state, handling reuse, cleanup, and spawning.
Loading Existing Sessions
loadBrokerSession(cwd) attempts to read broker.json from the state directory. If the file is missing or contains malformed JSON, the function returns null (lines 76‑86). This allows the client to decide whether to create a new broker or attempt reuse.
Reusing or Cleaning Up Stale Sessions
Before reusing a session, the plugin validates its vitality:
- If
loadBrokerSessionreturns a valid object,isBrokerEndpointReadyconfirms the Unix socket is still alive (lines 13‑17). - If the session file exists but the endpoint is dead, the plugin calls
teardownBrokerSessionto clean up the socket, PID file, log, and temporary directory, followed byclearBrokerSessionto remove the stalebroker.json(lines 19‑29).
This teardown eliminates orphaned resources from crashed or zombie broker processes.
Spawning and Persisting New Brokers
When no valid session exists, the plugin executes a five-step creation flow:
- Directory creation –
createBrokerSessionDirestablishes a new temporary directory. - Endpoint generation –
createBrokerEndpointgenerates the Unix socket path. - Process launch –
spawnBrokerProcesslaunchesapp-server-broker.mjsin detached mode, redirecting stdout/stderr to the log file (lines 31‑48). - Readiness polling –
waitForBrokerEndpointpolls the socket for up to 2 seconds. If the broker never becomes reachable, the plugin tears down the fresh process and returnsnull(lines 49‑60). - Persistence – On success,
saveBrokerSessionwrites the session object tobroker.jsonand returns it to the caller (lines 62‑70).
Cleanup and Resource Management
teardownBrokerSession performs safe, deterministic cleanup of broker resources:
- Optionally terminates the broker process via a custom
killProcessfunction (e.g.,process.kill(pid, "SIGTERM")) - Removes the PID file, log file, and Unix socket if present
- Deletes the temporary session directory, ignoring errors for non‑empty or missing directories
All filesystem operations are wrapped in try / catch blocks to tolerate race conditions or missing resources (lines 73‑99).
Integration Points in the Plugin Architecture
Client-Side Broker Resolution
In app-server.mjs, when a client requests a broker transport, the plugin first attempts to loadBrokerSession if options.reuseExistingBroker is enabled. If no valid session exists, it falls back to ensureBrokerSession to create a new one (lines 339‑345).
Shutdown Lifecycle Hooks
The session-lifecycle-hook.mjs module ensures graceful cleanup during plugin shutdown. It invokes teardownBrokerSession to terminate any broker that was started during the current session, preventing resource leaks when the editor or IDE closes (lines 85‑106).
Test Coverage
The test suite in runtime.test.mjs and broker-endpoint.test.mjs verifies loading, saving, reusing, and cleaning up broker sessions, confirming the intended behavior across edge cases.
Implementation Example
import { ensureBrokerSession, loadBrokerSession, teardownBrokerSession } from "./lib/broker-lifecycle.mjs";
/* 1️⃣ Reuse an existing broker if it is alive */
const cwd = process.cwd();
let broker = loadBrokerSession(cwd);
if (broker && (await waitForBrokerEndpoint(broker.endpoint))) {
console.log("Reusing broker at", broker.endpoint);
} else {
/* 2️⃣ Otherwise, start a fresh broker */
broker = await ensureBrokerSession(cwd, { env: process.env });
console.log("Started new broker:", broker?.endpoint);
}
/* … use broker.endpoint to connect the Codex client … */
/* 3️⃣ Clean up when done */
if (broker) {
await teardownBrokerSession({
endpoint: broker.endpoint,
pidFile: broker.pidFile,
logFile: broker.logFile,
sessionDir: broker.sessionDir,
pid: broker.pid,
killProcess: (pid) => process.kill(pid, "SIGTERM")
});
}
Key Files in the Broker State System
plugins/codex/scripts/lib/broker-lifecycle.mjs– Core implementation of session persistence, creation, and teardownplugins/codex/scripts/lib/broker-endpoint.mjs– Helpers for constructing and parsing the Unix socket endpointplugins/codex/scripts/app-server-broker.mjs– The actual broker process that serves RPC callsplugins/codex/scripts/lib/app-server.mjs– Client side that decides whether to reuse or create a brokerplugins/codex/scripts/session-lifecycle-hook.mjs– Hook that invokes teardown on plugin shutdowntests/runtime.test.mjs– Test suite covering broker session lifecycle scenarios
Summary
- Broker session state is persisted to
broker.jsonin the repository's state directory, tracking the Unix socket endpoint, PID, and temporary resource paths. - The plugin lazily reuses existing brokers by validating socket vitality via
isBrokerEndpointReady, avoiding unnecessary process creation. - Stale sessions are automatically cleaned up through
teardownBrokerSession, which removes orphaned sockets, log files, and temporary directories. - New brokers are spawned with a 2‑second readiness timeout, ensuring the client never waits indefinitely for a failed startup.
- Shutdown hooks in
session-lifecycle-hook.mjsguarantee deterministic cleanup of all broker resources when the plugin exits.
Frequently Asked Questions
Where is the broker session state stored?
The state is stored in a JSON file named broker.json located within the repository’s state directory (resolved via resolveStateDir). The function resolveBrokerStateFile(cwd) constructs the absolute path based on the current working directory.
How does the plugin detect if a broker is still alive?
The plugin uses isBrokerEndpointReady to check if the Unix socket path recorded in the session file is still responsive. This validation occurs before reusing a session in ensureBrokerSession (lines 13‑17), ensuring only active brokers are reclaimed.
What happens if the broker process crashes while the session file exists?
If loadBrokerSession finds a session file but isBrokerEndpointReady determines the socket is dead, the plugin executes teardownBrokerSession to remove the stale socket, PID file, and log, followed by clearBrokerSession to delete the invalid broker.json. A fresh broker is then spawned automatically.
How long does the plugin wait for a new broker to become ready?
The waitForBrokerEndpoint function polls the Unix socket for up to 2 seconds. If the broker fails to become reachable within this window, the plugin tears down the partially started process and returns null, preventing the client from hanging indefinitely.
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 →