# Codex App-Server Protocol: How Threads Are Created and Resumed in the OpenAI Plugin

> Understand the Codex app-server protocol for OpenAI plugins. Learn how thread/start and thread/resume methods manage thread lifecycles using JSON-RPC over pipes or sockets.

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

---

**The Codex app-server protocol uses a line-delimited JSON-RPC transport over pipes or Unix sockets, with `thread/start` and `thread/resume` methods managing thread lifecycles.**

The **Codex app-server protocol** defines how the OpenAI Codex plugin communicates with a backing server process to create and manage interactive coding sessions. This lightweight, text-based protocol enables the plugin to spawn new threads for isolated work and resume existing threads to maintain context across interactions.

## JSON-RPC Transport Layer

The protocol runs over newline-separated JSON messages. Each payload is a single JSON object terminated by `\n`, allowing simple line-based parsing without complex framing.

Two transport implementations coexist in `plugins/codex/scripts/lib/app-server.mjs`:

- **`SpawnedCodexAppServerClient`** – Direct child-process pipe to a spawned `codex` binary
- **`BrokerCodexAppServerClient`** – Unix socket connection through a broker process

Both inherit common logic from `AppServerClientBase` at lines 57-78, which handles message serialization, response correlation, and error handling.

### Message Routing

Incoming data accumulates in `lineBuffer`. Each newline triggers `handleLine` (lines 18-31), which parses the JSON and categorizes the payload:

| Direction | Handling logic |
|-----------|---------------|
| **Server → Client request** | Routed to registered handlers via `onRequest` |
| **Response to client request** | Resolved against pending promise by numeric `id` |
| **Notification** | Dispatched to `onNotification` handlers |

Error responses are wrapped as `ProtocolError` objects carrying the JSON-RPC error code and optional data field (lines 44-55).

### Request Lifecycle

The `request(method, params)` method (lines 86-98) generates a unique numeric `id`, stores a pending promise, and sends the JSON line via `sendMessage`. The caller awaits resolution when the matching response arrives.

```javascript
// Core request pattern from app-server.mjs
async request(method, params) {
  const id = this.nextId++;
  const message = { jsonrpc: "2.0", id, method, params };
  this.pending.set(id, { resolve, reject });
  this.sendMessage(JSON.stringify(message));
  // Returns promise resolved by response handler
}

```

## Thread Creation via `thread/start`

New threads are created through the `"thread/start"` JSON-RPC method defined in [`app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts) (lines 59-73). This method accepts a **`ThreadStartParams`** object specifying:

- `cwd` – Working directory for the session
- `model` – Model identifier (nullable for default)
- `approvalPolicy` – When user approval is required (`"never"`, `"prompt"`, etc.)
- `sandbox` – Sandbox mode (`"read-only"`, `"modifiable"`, etc.)
- `serviceName` and `ephemeral` flags

### High-Level Wrapper: `startThread`

The `codex.mjs` module provides `startThread` (lines 32-47) as a convenience wrapper. It uses `buildThreadParams` (lines 62-71) to assemble defaults, then forwards to the underlying client:

```javascript
// From plugins/codex/scripts/lib/codex.mjs
export async function startThread(client, arg, name) {
  const thread = await client.request(
    "thread/start",
    buildThreadParams(arg)  // Assembles ThreadStartParams
  );
  if (name) thread.name = name;
  return thread;
}

```

### Practical Example: Creating a Thread

```javascript
import { CodexAppServerClient } from "./plugins/codex/scripts/lib/app-server.mjs";

async function createThread(cwd) {
  const client = await CodexAppServerClient.connect(cwd);
  
  const thread = await client.request("thread/start", {
    cwd,
    model: null,                    // Use default model
    approvalPolicy: "never",        // Auto-approve low-risk actions
    sandbox: "read-only",           // Restrict filesystem access
    serviceName: "codex",
    ephemeral: true                 // Clean up on process exit
  });
  
  console.log("New thread ID:", thread.thread.id);
  await client.close();
}

```

## Thread Resumption via `thread/resume`

Existing threads are resumed through the `"thread/resume"` method, which accepts **`ThreadResumeParams`** containing the thread ID to reactivate plus optional overrides for model, sandbox, or approval settings.

### High-Level Wrapper: `resumeThread`

The `resumeThread` function (lines 50-52) is simpler than its creation counterpart—it delegates directly to `buildResumeParams` (lines 74-82) without additional naming logic:

```javascript
// From plugins/codex/scripts/lib/codex.mjs
export function resumeThread(client, arg) {
  return client.request("thread/resume", buildResumeParams(arg));
}

```

**`buildResumeParams`** constructs the payload with thread ID, cwd, and any overridden settings from the input argument.

### Practical Example: Resuming a Thread

```javascript
import { CodexAppServerClient } from "./plugins/codex/scripts/lib/app-server.mjs";

async function continueThread(cwd, threadId) {
  const client = await CodexAppServerClient.connect(cwd);
  
  const resumed = await client.request("thread/resume", {
    threadId,                       // Required: existing thread to reactivate
    cwd,
    model: null,                    // Override or null to preserve
    approvalPolicy: "never",
    sandbox: "read-only"
  });
  
  console.log("Resumed thread:", resumed.thread.id);
  await client.close();
}

```

## Connection Bootstrap

Static method `CodexAppServerClient.connect` (lines 35-53) implements the connection strategy:

1. **Detect transport** – Checks `CODEX_BROKER_SOCKET_PATH` environment variable or explicit options to choose broker vs. direct spawn
2. **Instantiate client** – Creates `BrokerCodexAppServerClient` or `SpawnedCodexAppServerClient`
3. **Initialize handshake** – Sends `"initialize"` request and waits for server capabilities

The resulting client is ready for `thread/start` or `thread/resume` calls.

## Summary

- The **Codex app-server protocol** is **line-delimited JSON-RPC** with transport abstraction over pipes or Unix sockets
- **`AppServerClientBase`** in `app-server.mjs` handles message framing, request correlation, and error wrapping
- **Thread creation** uses `"thread/start"` with `ThreadStartParams` assembled by `buildThreadParams` in `codex.mjs`
- **Thread resumption** uses `"thread/resume"` with `ThreadResumeParams` from `buildResumeParams`
- **`CodexAppServerClient.connect`** bootstraps the connection and completes the initialization handshake

## Frequently Asked Questions

### What transport protocols does the Codex app-server support?

The protocol supports two transports: direct child-process pipes via `SpawnedCodexAppServerClient` and Unix domain sockets via `BrokerCodexAppServerClient`. Both use identical JSON-RPC message framing. The `connect` method auto-detects based on the `CODEX_BROKER_SOCKET_PATH` environment variable.

### How are thread IDs managed across sessions?

Thread IDs are generated server-side during `thread/start` and returned in the response payload. To resume, the client passes this same ID to `thread/resume`. The server maintains thread state, allowing context preservation across disconnections and reconnections.

### Can sandbox or approval settings change when resuming a thread?

Yes. The `ThreadResumeParams` type in [`app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts) declares `sandbox`, `approvalPolicy`, and `model` as optional fields. When provided, these override the original thread settings; when null, the server preserves existing values.

### Where is the protocol specification defined?

Type definitions for all methods, parameters, and return types reside in [`plugins/codex/scripts/lib/app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/app-server-protocol.d.ts). The runtime implementation and transport logic are in `plugins/codex/scripts/lib/app-server.mjs`, with high-level wrappers in `plugins/codex/scripts/lib/codex.mjs`.