What Is the app-server Component in OpenAI Codex?

The app-server is the core JSON-RPC 2.0 gateway that powers all Codex clients, exposing a bidirectional API for conversation management, model generation, and sandboxed tool execution.

In the openai/codex repository, the app-server/ component serves as the authoritative server-side interface that abstracts the underlying agent, sandbox, and persistence layers behind a stable, versioned protocol. All rich clients—including the VS Code extension, terminal UI, and SDKs—communicate with Codex exclusively through this server, making the system modular and enabling third-party integrations.

Core Architecture and JSON-RPC 2.0 Protocol

The app-server implements a JSON-RPC 2.0 protocol over stdio by default, with experimental WebSocket support available. According to the source code in codex-rs/app-server/src/transport.rs, the transport layer handles back-pressure queues, logging, and connection management while omitting the standard "jsonrpc":"2.0" envelope on-wire to reduce overhead—a design decision that mirrors the Model Context Protocol (MCP) specification.

The entry point in codex-rs/app-server/src/lib.rs builds the transport infrastructure and request router, creating a unified handler that processes incoming JSON-RPC messages and dispatches them to the appropriate internal services.

Transport Modes

  • stdio (default): Line-delimited JSON (JSONL) streams suitable for local process spawning
  • WebSocket (experimental): Enables remote or browser-based clients to connect over the network

Core Primitives: Thread, Turn, and Item

As defined in codex-rs/app-server-protocol/src/protocol/v2.rs, the API organizes conversation state around three hierarchical primitives:

  • Thread: A container representing a single conversation session
  • Turn: A single exchange within a thread, typically consisting of a user message and the model's response
  • Item: Atomic units within a turn, including user messages, agent messages, tool calls, and tool results

This structure allows clients to resume long-running conversations, inspect historical turns, and stream incremental item updates as the model generates content.

Lifecycle and API Surface

The typical client lifecycle follows a strict handshake pattern implemented in codex-rs/app-server/src/message_processor.rs:

  1. initialize: Exchange client/server capabilities and version information
  2. thread/start: Create a new conversation thread
  3. turn/start: Submit user input and initiate model generation
  4. Streaming events: Receive item/* notifications (e.g., item/agentMessage/delta) in real-time
  5. turn/completed: Final signal that the turn has finished processing

The API surface includes dozens of methods categorized by resource type:

  • Conversation management: thread/start, thread/list, thread/resume
  • Generation control: turn/start, turn/stop
  • Model discovery: model/list, model/select
  • Tool integration: skills/list, shell/exec, file/edit
  • System operations: auth/login, feedback/submit, plugins/install

Security, Approvals, and Sandboxing

Requests that affect the user's system—such as shell commands or file modifications—are gated behind an approval flow defined in the server configuration. The app-server respects the user's approvalPolicy settings and sandbox mode, ensuring that destructive operations require explicit client confirmation before execution.

This approval system is tightly integrated with the JSON-RPC notification stream, allowing clients to render confirmation dialogs when the server emits approval/required events before proceeding with sensitive operations.

Schema Generation and Type Safety

To guarantee type safety across language boundaries, the app-server provides built-in schema generation commands:


# Generate TypeScript definitions matching the current server binary

codex app-server generate-ts --out api-schema

# Generate JSON Schema for validation

codex app-server generate-json-schema --out schemas/

These commands produce types that mirror the Rust structs defined in codex-rs/app-server-protocol/, ensuring that TypeScript clients, Python SDKs, and other consumers remain synchronized with the server's exact API version.

Experimental API Access

Clients can opt into unstable features by setting capabilities.experimentalApi: true during the initialization handshake. This gatekeeping mechanism allows the core protocol to remain stable while enabling rapid iteration on new capabilities without breaking existing integrations.

Key Implementation Files

The app-server implementation spans several critical files in the codex-rs/ directory:

File Purpose
codex-rs/app-server/src/lib.rs Entry point and server initialization
codex-rs/app-server/src/transport.rs stdio and WebSocket transport implementation
codex-rs/app-server/src/message_processor.rs JSON-RPC request routing and dispatch
codex-rs/app-server-protocol/src/protocol/v2.rs Shared protocol structs (Thread, Turn, Item)
codex-rs/debug-client/ Minimal CLI client for testing and examples

Practical Usage Examples

Rust Client Integration

The following example demonstrates connecting to the app-server from Rust using the debug client library:

use codex_app_server_test_client::Client;

fn main() -> anyhow::Result<()> {
    // Spawn the server process with stdio transport
    let mut client = Client::spawn()?;

    // Initialize handshake
    client.initialize(codex_app_server_test_client::InitializeParams {
        client_info: codex_app_server_test_client::ClientInfo {
            name: "my_demo".into(),
            title: "Demo client".into(),
            version: "0.1.0".into(),
        },
        ..Default::default()
    })?;

    // Create conversation thread
    let thread = client.call_thread_start(None)?;

    // Start a turn with user input
    let _turn = client.call_turn_start(
        thread.id,
        codex_app_server_test_client::TurnStartParams {
            user_input: Some("Explain Rust ownership".into()),
            ..Default::default()
        },
    )?;

    // Stream notifications until completion
    for notification in client.notifications()? {
        match notification {
            codex_app_server_test_client::Notification::ItemCompleted { item, .. } => {
                if let Some(content) = &item.content {
                    println!("{}: {}", item.kind, content);
                }
            }
            codex_app_server_test_client::Notification::TurnCompleted { .. } => break,
            _ => {}
        }
    }
    Ok(())
}

Command Line Invocation

For shell scripts or debugging, you can interact with the server directly via JSON-RPC over stdio:


# Start server in background

codex app-server &
SERVER_PID=$!

# Initialize connection

echo '{"method":"initialize","id":0,"params":{"clientInfo":{"name":"cli","version":"1.0"}}}' | codex app-server

# Create thread and capture ID

THREAD_ID=$(echo '{"method":"thread/start","id":1,"params":{}}' | codex app-server | jq -r '.result.id')

# Start turn with streaming output

echo "{\"method\":\"turn/start\",\"id\":2,\"params\":{\"threadId\":\"$THREAD_ID\",\"userInput\":\"Hello\"}}" | codex app-server | jq -r '
  select(.method=="item/agentMessage/delta") | .params.delta
'

Summary

  • The app-server is the centralized JSON-RPC 2.0 gateway that exposes Codex functionality to all client applications.
  • It manages conversation state through Thread/Turn/Item hierarchies defined in codex-rs/app-server-protocol/.
  • All system-interacting operations require explicit approval, respecting user-configured sandbox policies.
  • The server supports schema generation to maintain type safety across TypeScript, Python, and other language bindings.
  • Implementation resides primarily in codex-rs/app-server/src/, with transport logic in transport.rs and request routing in message_processor.rs.

Frequently Asked Questions

How does the app-server communicate with clients?

The app-server uses JSON-RPC 2.0 over stdio (line-delimited JSON) by default, making it easy to spawn as a subprocess from editors or CLI tools. Experimental WebSocket support exists in codex-rs/app-server/src/transport.rs for network-based or browser clients.

What are the main API primitives in the app-server protocol?

The protocol organizes data into three core primitives: Thread (conversation container), Turn (single exchange within a thread), and Item (atomic message or tool call). These structures are defined in codex-rs/app-server-protocol/src/protocol/v2.rs and enable features like conversation resumption and incremental streaming.

How does the app-server handle dangerous operations like shell commands?

The server implements an approval flow that gates sensitive actions behind user confirmation. When a tool request requires system access, the server emits an approval notification and waits for client authorization, respecting the approvalPolicy and sandbox configuration set during initialization.

Can I generate TypeScript types for the app-server API?

Yes. Run codex app-server generate-ts --out <directory> to produce TypeScript definitions that exactly match the current server binary's protocol version. This guarantees type safety for external clients and matches the Rust structs used internally.

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 →