# How `runAppServerTurn` Works in the OpenAI Codex Plugin: A Complete Guide

> Discover how runAppServerTurn in the OpenAI Codex Plugin manages prompt-response cycles. This guide details environment validation, connection management, and result aggregation for your app server integration.

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

---

**The `runAppServerTurn` function serves as the high-level entry point that orchestrates a single prompt-response cycle (turn) with the Codex app-server, handling environment validation, connection management, thread lifecycle, and result aggregation.**

The `runAppServerTurn` function is the core execution engine within the OpenAI Codex plugin that manages the complete lifecycle of an AI-assisted coding session. Located in `plugins/codex/scripts/lib/codex.mjs` at line 954, this function abstracts the complexity of JSON-RPC communication with the Codex app-server. It provides a unified interface for running new turns, resuming existing threads, and capturing rich execution metadata including file changes and command outputs.

## Environment Validation and Availability Checks

Before initiating any network communication, `runAppServerTurn` validates that the local environment can support Codex execution. The function calls `getCodexAvailability(cwd)` to verify that the `codex` CLI binary is present and that the required runtime (Node.js ≥ 14) is available.

If the check fails, the function throws an informative error immediately:

```javascript
const availability = getCodexAvailability(cwd);
if (!availability.available) {
  throw new Error("Codex CLI is not installed …");
}

```

This early validation prevents resource leaks and provides clear feedback when prerequisites are missing.

## Establishing the App-Server Connection

The function wraps its core logic inside `withAppServer(cwd, async (client) => { … })`, which manages the transport layer connection to the Codex app-server. According to the source code in `plugins/codex/scripts/lib/app-server.mjs`, this wrapper supports two distinct connection modes:

- **Broker mode**: Reuses a persistent broker process via a Unix socket specified in the `CODEX_COMPANION_APP_SERVER_ENDPOINT` environment variable.
- **Spawned mode**: Launches a fresh `codex app-server` process locally for isolated execution.

The wrapper returns a fully-initialized `client` instance of `CodexAppServerClient` that abstracts the JSON-RPC transport, handling message serialization and socket management automatically.

## Thread Lifecycle Management (Start vs Resume)

`runAppServerTurn` handles both new conversations and continuing existing ones through conditional thread management:

**Resuming an existing thread** occurs when `resumeThreadId` is provided:

```javascript
const response = await resumeThread(client, options.resumeThreadId, cwd, { … });
threadId = response.thread.id;

```

**Starting a new thread** requires model configuration and sandbox permissions:

```javascript
const response = await startThread(client, cwd, {
  model: options.model,
  sandbox: options.sandbox,
  // `ephemeral` = true for one-shot tasks, false when persisting
});
threadId = response.thread.id;

```

Throughout this process, the helper `emitProgress` (from `plugins/codex/scripts/lib/emit-progress.mjs`) reports status updates to any registered UI listeners, enabling real-time progress indicators.

## Prompt Validation and Preparation

Before sending data to the app-server, the function extracts the prompt from `options.prompt` (falling back to `options.defaultPrompt` if undefined). If the resulting string is empty, the function throws an error, ensuring that the JSON-RPC layer never receives invalid input. This validation step acts as a contract enforcement between the plugin interface and the app-server protocol.

## Executing the Turn Request

The core interaction happens via `client.request("turn/start", { … })`, which sends the compiled payload to the app-server. The request includes:

- **`threadId`**: The active thread identifier obtained from the previous step.
- **`input`**: The prepared prompt, wrapped by `buildTurnInput`.
- **Optional fields**: `model`, `effort`, and `outputSchema` for response formatting.

The raw request is wrapped in `captureTurn`, defined in `plugins/codex/scripts/lib/turn.mjs`, which streams the app-server's output events, updates progress callbacks, and assembles the final `turnState` object containing the complete execution context.

## Result Aggregation and Metadata Extraction

After `captureTurn` resolves, `runAppServerTurn` constructs a comprehensive result object that standardizes the output across different plugin commands:

```javascript
return {
  status: buildResultStatus(turnState),
  threadId,
  turnId: turnState.turnId,
  finalMessage: turnState.lastAgentMessage,
  reasoningSummary: turnState.reasoningSummary,
  turn: turnState.finalTurn,
  error: turnState.error,
  stderr: cleanCodexStderr(client.stderr),
  fileChanges: turnState.fileChanges,
  touchedFiles: collectTouchedFiles(turnState.fileChanges),
  commandExecutions: turnState.commandExecutions
};

```

This object includes:
- **`status`**: High-level classification (`succeeded`, `failed`, etc.).
- **`finalMessage`**: The model's response content.
- **`fileChanges`** and **`touchedFiles`**: Arrays describing filesystem modifications made during the turn.
- **`commandExecutions`**: Shell commands executed by the agent.
- **`stderr`**: Sanitized error output from the client.

## Automatic Resource Cleanup

The `withAppServer` wrapper ensures defensive resource management by calling `client.close()` regardless of whether the turn succeeded or failed. This termination signal closes the broker connection or kills the spawned process, preventing zombie processes and socket leaks. On Windows, the cleanup utilizes `terminateProcessTree` from `plugins/codex/scripts/lib/process.mjs` to ensure complete subtree termination.

## Practical Usage Examples

### Running a New Turn

```javascript
import { runAppServerTurn } from "./plugins/codex/scripts/lib/codex.mjs";

async function demo() {
  const cwd = process.cwd();
  const result = await runAppServerTurn(cwd, {
    prompt: "Write a function that returns the nth Fibonacci number in JavaScript.",
    model: "gpt-4o-mini",
    sandbox: "read-write",   // allow the model to edit files if needed
    onProgress: (phase, message, detail) =>
      console.log(`[${phase}] ${message}`, detail ?? "")
  });

  console.log("Turn finished:", result.status);
  console.log("Model reply:", result.finalMessage?.content);
}
demo();

```

### Resuming an Existing Thread

```javascript
await runAppServerTurn(process.cwd(), {
  resumeThreadId: "thread-abc123",
  prompt: "Add unit tests for the new function.",
  onProgress: (p, m) => console.info(p, m)
});

```

Both patterns demonstrate the typical integration: provide a working directory, a prompt (or thread ID to resume), optional model or sandbox settings, and a progress callback to monitor execution.

## Key Implementation Files

The `runAppServerTurn` function relies on several specialized modules across the repository:

- **`plugins/codex/scripts/lib/codex.mjs`**: Implements `runAppServerTurn`, `runAppServerReview`, thread helpers, and result formatting.
- **`plugins/codex/scripts/lib/app-server.mjs`**: Low-level client that manages broker connections and spawned processes.
- **[`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)**: TypeScript definitions for the JSON-RPC protocol between client and server.
- **`plugins/codex/scripts/lib/turn.mjs`**: Contains `captureTurn` which streams turn events and assembles `turnState`.
- **`plugins/codex/scripts/lib/broker-endpoint.mjs`**: Parses the broker socket path used when `CODEX_COMPANION_APP_SERVER_ENDPOINT` is set.
- **`plugins/codex/scripts/lib/process.mjs`**: Utility `terminateProcessTree` for clean shutdown on Windows.

## Summary

- **`runAppServerTurn`** is the primary entry point for executing Codex turns in the openai/codex-plugin-cc repository.
- The function validates environment prerequisites via `getCodexAvailability` before attempting connections.
- Connection management is abstracted through `withAppServer`, supporting both persistent broker sockets and spawned processes.
- Thread lifecycle logic handles both new conversations (`startThread`) and resuming existing sessions (`resumeThread`).
- The function returns a rich result object containing the model's response, file changes, command executions, and execution status.

## Frequently Asked Questions

### What is the difference between broker mode and spawned mode in `runAppServerTurn`?

**Broker mode** connects to a persistent Codex app-server process via a Unix socket defined by the `CODEX_COMPANION_APP_SERVER_ENDPOINT` environment variable, reducing startup overhead for multiple turns. **Spawned mode** launches a fresh `codex app-server` process for each execution, providing better isolation at the cost of initialization time. The `withAppServer` wrapper automatically selects the appropriate mode based on environment configuration.

### How does `runAppServerTurn` handle errors during execution?

The function implements error handling at multiple layers: environment validation throws early if the Codex CLI is missing; the `captureTurn` helper captures runtime errors in the `turnState.error` field; and the `status` field in the result object classifies outcomes as `succeeded`, `failed`, or other terminal states. Additionally, the `stderr` field contains sanitized error output from the client process for debugging purposes.

### Can I resume a previous conversation using `runAppServerTurn`?

Yes, by providing the `resumeThreadId` option with a valid thread identifier, the function invokes `resumeThread` instead of `startThread`, continuing the existing conversation context. This allows multi-turn workflows where subsequent prompts can reference previous exchanges and file modifications maintained in the persistent thread state.

### What information does the result object from `runAppServerTurn` contain?

The result object includes the `threadId` and `turnId` for tracking, a `status` field indicating success or failure, the `finalMessage` containing the model's response, and detailed metadata arrays: `fileChanges` (edits made), `touchedFiles` (affected paths), and `commandExecutions` (shell commands run). The `reasoningSummary` field may also contain the model's chain-of-thought if enabled.