# RPC methods reference

> Grouped catalog of v2 `<resource>/<method>` RPCs for threads, turns, filesystem, models, processes, plugins, remote control, and utility commands with stable vs experimental markers.

- Repository: openai/codex
- GitHub: https://github.com/openai/codex
- Human docs: https://grok-wiki.com/public/docs/openai-codex-c82680b15ec1
- Complete Markdown: https://grok-wiki.com/public/docs/openai-codex-c82680b15ec1/llms-full.txt

## Source Files

- `README.md`
- `src/request_processors.rs`
- `src/message_processor.rs`
- `src/request_processors/thread_processor.rs`
- `src/request_processors/fs_processor.rs`
- `src/request_processors/command_exec_processor.rs`
- `src/request_processors/process_exec_processor.rs`

---

---
title: "RPC methods reference"
description: "Grouped catalog of v2 `<resource>/<method>` RPCs for threads, turns, filesystem, models, processes, plugins, remote control, and utility commands with stable vs experimental markers."
---

The `codex app-server` binary exposes a JSON-RPC 2.0 API on each transport connection. Active client methods use singular `<resource>/<method>` wire names (for example `thread/start`, `turn/interrupt`, `config/batchWrite`). The authoritative registry lives in `app-server-protocol` (`client_request_definitions!` in `common.rs`); `MessageProcessor` dispatches each variant to a request processor module under `src/request_processors/`.

<Note>
Send `initialize` once per connection, then the `initialized` notification, before any other RPC. Methods documented here assume a initialized connection unless noted.
</Note>

## Wire conventions

| Convention | Rule |
| --- | --- |
| Method name | Singular resource + `/` + action: `thread/read`, `mcpServer/tool/call` |
| Request shape | `{ "method": "<wire>", "id": <id>, "params": { ... } }` |
| Params / results | camelCase on the wire (`threadId`, `nextCursor`) |
| Config RPCs | snake_case fields mirroring `config.toml` keys |
| Pagination | Cursor methods use `cursor`, `limit`, `data`, `nextCursor`, and often `backwardsCursor` |
| Thread-scoped calls | Most turn/thread mutations require `threadId` and serialize per-thread |

Regenerate client types from the running binary when shapes change:

```bash
codex app-server generate-ts --out DIR
codex app-server generate-json-schema --out DIR
codex app-server generate-ts --out DIR --experimental
```

## Experimental gating

| Level | Marker | Runtime requirement |
| --- | --- | --- |
| Stable method | No `#[experimental(...)]` on the method variant | Default after `initialize` |
| Experimental method | `#[experimental("resource/method")]` on the variant | `initialize.params.capabilities.experimentalApi: true` |
| Experimental field | `#[experimental("resource/method.field")]` on a param field | Same opt-in; method may still be stable with `inspect_params: true` |
| Rejection | — | JSON-RPC error: `<descriptor> requires experimentalApi capability` |

<Info>
Stable methods with experimental fields: `thread/start`, `thread/resume`, `thread/fork`, `thread/settings/update`, `turn/start`, `turn/steer`, `account/login/start`, and `command/exec`. Omit experimental fields unless opted in.
</Info>

## Connection and lifecycle

| Method | Stability | Summary |
| --- | --- | --- |
| `initialize` | Stable | Handshake: `clientInfo`, optional `capabilities.experimentalApi`, `optOutNotificationMethods` |
| `initialized` | Stable (notification) | Client ack after `initialize` result |

## Thread and turn RPCs

### Thread lifecycle

| Method | Stability | Key params | Response / side effects |
| --- | --- | --- | --- |
| `thread/start` | Stable (partial experimental fields) | `cwd`, `model`, `sandbox` or `permissions`, `ephemeral`, `sessionStartSource` | `thread`; notifies `thread/started`; auto-subscribes connection |
| `thread/resume` | Stable (partial experimental fields) | `threadId` or `path`, overrides, `excludeTurns`, `initialTurnsPage` | `thread`; may emit `thread/tokenUsage/updated` |
| `thread/fork` | Stable (partial experimental fields) | `threadId` or `path`, `ephemeral`, `excludeTurns` | New `thread`; `thread/started` |
| `thread/read` | Stable | `threadId`, `includeTurns` | `thread` without resuming |
| `thread/list` | Stable | `cursor`, `limit`, `cwd`, `archived`, `searchTerm`, filters | Paginated `data` |
| `thread/search` | **Experimental** | Search-oriented list params | Paginated `data` |
| `thread/loaded/list` | Stable | — | In-memory loaded thread ids |
| `thread/archive` | Stable | `threadId` | `{}`; `thread/archived` per archived thread |
| `thread/unarchive` | Stable | `threadId` | `thread`; `thread/unarchived` |
| `thread/unsubscribe` | Stable | `threadId` | `status`: `unsubscribed` / `notSubscribed` / `notLoaded` |
| `thread/name/set` | Stable | `threadId`, name | `{}`; `thread/name/updated` |
| `thread/metadata/update` | Stable | `threadId`, `gitInfo` patch | `thread` |
| `thread/settings/update` | **Experimental** (partial fields) | Partial next-turn settings | `{}`; may emit `thread/settings/updated` |
| `thread/memoryMode/set` | **Experimental** | `threadId`, mode | `{}` |
| `thread/goal/set` | Stable | `threadId`, goal | Goal; `thread/goal/updated` |
| `thread/goal/get` | Stable | `threadId` | Goal or `null` |
| `thread/goal/clear` | Stable | `threadId` | Cleared flag; `thread/goal/cleared` |
| `thread/compact/start` | Stable | `threadId` | `{}`; progress via turn/item notifications |
| `thread/shellCommand` | Stable | `threadId`, command | `{}`; unsandboxed shell via turn stream |
| `thread/rollback` | Stable | `threadId`, turn count | Updated `thread` with pruned history |
| `thread/approveGuardianDeniedAction` | Stable | `threadId`, action id | Approval result |
| `thread/backgroundTerminals/clean` | **Experimental** | `threadId` | `{}` |
| `thread/increment_elicitation` | **Experimental** | `threadId` | `{}` |
| `thread/decrement_elicitation` | **Experimental** | `threadId` | `{}` |
| `thread/inject_items` | Stable | `threadId`, raw items | `{}` |
| `thread/turns/list` | **Experimental** | `threadId`, `cursor`, `itemsView` | Paginated turns |
| `thread/turns/items/list` | **Experimental** (unsupported) | Turn item paging shape | Error: not supported yet |

### Realtime (experimental)

| Method | Summary |
| --- | --- |
| `thread/realtime/start` | Start realtime session (`outputModality`, optional WebRTC `transport`) |
| `thread/realtime/appendAudio` | Append input audio |
| `thread/realtime/appendText` | Append text input |
| `thread/realtime/stop` | Stop session |
| `thread/realtime/listVoices` | List voices (global) |

### Turns

| Method | Stability | Summary |
| --- | --- | --- |
| `turn/start` | Stable (partial experimental fields) | Begin generation; returns initial `turn`; streams `turn/started`, `item/*`, `turn/completed` |
| `turn/steer` | Stable (partial experimental fields) | Add input to in-flight regular turn |
| `turn/interrupt` | Stable | Cancel `(threadId, turnId)`; turn ends `interrupted` |
| `review/start` | Stable | Automated code review turn on a thread |

```mermaid
sequenceDiagram
    participant Client
    participant AppServer as MessageProcessor
    participant Thread as ThreadRequestProcessor

    Client->>AppServer: thread/start
    AppServer->>Thread: start
    Thread-->>Client: result.thread
    AppServer-->>Client: notification thread/started
    Client->>AppServer: turn/start
    AppServer-->>Client: result.turn
    AppServer-->>Client: turn/started
    AppServer-->>Client: item/started / deltas
    AppServer-->>Client: turn/completed
```

## Filesystem (`fs/*`)

All `fs/*` methods are **stable** and intentionally **concurrent** (no global serialization). Paths must be absolute.

| Method | Summary |
| --- | --- |
| `fs/readFile` | Read bytes as `dataBase64` |
| `fs/writeFile` | Write from `dataBase64` |
| `fs/createDirectory` | Create directory (`recursive` default true) |
| `fs/getMetadata` | `isDirectory`, `isFile`, `isSymlink`, timestamps |
| `fs/readDirectory` | List child names and types |
| `fs/remove` | Remove file or tree |
| `fs/copy` | Copy paths (`recursive` for directories) |
| `fs/watch` | Subscribe by `watchId`; emits `fs/changed` |
| `fs/unwatch` | Stop watch for `watchId` |

## Models, features, and permissions

| Method | Stability | Summary |
| --- | --- | --- |
| `model/list` | Stable | Models, reasoning options, tiers, availability metadata |
| `modelProvider/capabilities/read` | Stable | Provider capabilities for current config |
| `experimentalFeature/list` | Stable | Feature flags with stage metadata; optional `threadId` |
| `experimentalFeature/enablement/set` | Stable | Patch in-memory feature enablement |
| `permissionProfile/list` | Stable (beta catalog) | Permission profile ids; pass `cwd` for project-local entries |
| `collaborationMode/list` | **Experimental** | Collaboration mode presets |

## Command and process execution

### Sandboxed `command/*` (stable)

| Method | Summary |
| --- | --- |
| `command/exec` | Run argv under server sandbox; optional streaming `command/exec/outputDelta` |
| `command/exec/write` | Stdin (base64) or close stdin for `processId` |
| `command/exec/resize` | Resize PTY session |
| `command/exec/terminate` | Terminate session |

`command/exec` is stable but supports an experimental `permissionProfile` param when opted in.

### Host `process/*` (experimental)

| Method | Summary |
| --- | --- |
| `process/spawn` | Spawn without Codex sandbox on app-server host |
| `process/writeStdin` | Stdin for `processHandle` |
| `process/resizePty` | Resize PTY |
| `process/kill` | Terminate process |

Notifications: `process/outputDelta`, `process/exited`.

```text
  command/exec  --> CommandExecRequestProcessor (sandboxed)
  process/spawn --> ProcessExecRequestProcessor (host, experimental)
```

## Config, MCP, and environment

| Method | Stability | Summary |
| --- | --- | --- |
| `config/read` | Stable | Effective resolved config |
| `config/value/write` | Stable | Single key to user `config.toml` |
| `config/batchWrite` | Stable | Atomic multi-edit; optional `reloadUserConfig` |
| `configRequirements/read` | Stable | `requirements.toml` / MDM constraints |
| `config/mcpServer/reload` | Stable | Reload MCP config; refresh loaded threads |
| `externalAgentConfig/detect` | Stable | Detect migratable external-agent artifacts |
| `externalAgentConfig/import` | Stable | Apply selected migrations |
| `mcpServerStatus/list` | Stable | MCP servers, tools, auth; optional `threadId`, pagination |
| `mcpServer/oauth/login` | Stable | Start OAuth; later `mcpServer/oauthLogin/completed` |
| `mcpServer/resource/read` | Stable | Read MCP resource by `server`, `uri` |
| `mcpServer/tool/call` | Stable | Call tool on thread's MCP server |
| `environment/add` | **Experimental** | Register remote environment by id + `execServerUrl` |

## Account and auth

| Method | Stability | Summary |
| --- | --- | --- |
| `account/read` | Stable | Current account snapshot |
| `account/login/start` | Stable (partial experimental fields) | `apiKey`, `chatgpt`, `chatgptDeviceCode` |
| `account/login/cancel` | Stable | Cancel pending ChatGPT login |
| `account/logout` | Stable | Clear session |
| `account/rateLimits/read` | Stable | Rate limit snapshot |
| `account/sendAddCreditsNudgeEmail` | Stable | Workspace owner nudge |

Notification: `account/login/completed`, `account/updated`.

## Skills, hooks, plugins, and apps

| Method | Stability | Notes |
| --- | --- | --- |
| `skills/list` | Stable | Skills for `cwd` values |
| `skills/extraRoots/set` | Stable | Runtime extra skill roots (not persisted) |
| `skills/config/write` | Stable | User skill config |
| `hooks/list` | Stable | Discovered hooks per `cwd` |
| `marketplace/add` | Stable | Add plugin marketplace |
| `marketplace/remove` | Stable | Remove marketplace |
| `marketplace/upgrade` | Stable | Upgrade Git marketplaces |
| `plugin/list` | Stable | Marketplaces + plugin catalog |
| `plugin/installed` | Stable | Installed rows + suggestions |
| `plugin/read` | Stable | Plugin detail by marketplace path |
| `plugin/skill/read` | Stable | Remote skill markdown preview |
| `plugin/install` | Stable | Install from marketplace |
| `plugin/uninstall` | Stable | Local or remote uninstall |
| `plugin/share/save` | Stable | Save share |
| `plugin/share/updateTargets` | Stable | Update share targets |
| `plugin/share/list` | Stable | List shares |
| `plugin/share/checkout` | Stable | Checkout share |
| `plugin/share/delete` | Stable | Delete share |
| `app/list` | Stable | Available apps |

Notification: `skills/changed`, `app/listUpdated`.

## Remote control (experimental)

| Method | Summary |
| --- | --- |
| `remoteControl/enable` | Enable remote control; return status snapshot |
| `remoteControl/disable` | Disable (does not revoke enrolled devices) |
| `remoteControl/status/read` | Read `disabled` / `connecting` / `connected` / `errored` |
| `remoteControl/pairing/start` | Pairing codes + `expiresAt` |

Notification: `remoteControl/status/changed`.

## Memory, search, sandbox, and utilities

| Method | Stability | Summary |
| --- | --- | --- |
| `memory/reset` | **Experimental** | Clear `CODEX_HOME/memories` and memory stage data |
| `fuzzyFileSearch` | Deprecated v1 wire | Legacy one-shot fuzzy search |
| `fuzzyFileSearch/sessionStart` | **Experimental** | Session-based fuzzy search |
| `fuzzyFileSearch/sessionUpdate` | **Experimental** | Update query/roots |
| `fuzzyFileSearch/sessionStop` | **Experimental** | End session |
| `windowsSandbox/setupStart` | Stable | Start Windows sandbox setup |
| `windowsSandbox/readiness` | Stable | Readiness probe |
| `feedback/upload` | Stable | Submit feedback report |
| `mock/experimentalMethod` | **Experimental** | Test-only gating validation |

## Stable methods with common experimental fields

Use `capabilities.experimentalApi: true` before sending these fields.

| Method | Experimental field examples (descriptor prefix) |
| --- | --- |
| `thread/start` | `runtimeWorkspaceRoots`, `permissions`, `environments`, `dynamicTools`, `experimentalRawEvents` |
| `thread/resume` | `path`, `history`, `excludeTurns`, `initialTurnsPage`, `runtimeWorkspaceRoots`, `permissions` |
| `thread/fork` | `path`, `excludeTurns`, `runtimeWorkspaceRoots`, `permissions` |
| `thread/settings/update` | `permissions`, `collaborationMode` |
| `turn/start` | `runtimeWorkspaceRoots`, `permissions`, `environments`, `additionalContext`, `collaborationMode` |
| `turn/steer` | `additionalContext`, `responsesapiClientMetadata` |
| `account/login/start` | `chatgptAuthTokens` |
| `command/exec` | `permissionProfile` |

Shared types may gate enum variants (for example `approvalPolicy` with `granular` → `askForApproval.granular`).

## Deprecated client methods (v1)

Do not build new integrations on these wire names. Prefer the v2 column.

| Legacy / v1 method | Replacement |
| --- | --- |
| `GetConversationSummary` | `thread/read` with `includeTurns` |
| `GitDiffToRemote` | Host git tooling outside app-server |
| `GetAuthStatus` | `account/read` |
| `FuzzyFileSearch` | `fuzzyFileSearch/session*` (experimental) or client-side search |

## Server-initiated requests (not client RPCs)

The server calls **into** the client during turns. Handle these on the same JSON-RPC connection:

| Wire method | Purpose |
| --- | --- |
| `item/commandExecution/requestApproval` | Approve sandboxed command |
| `item/fileChange/requestApproval` | Approve patch / edit |
| `item/permissions/requestApproval` | Additional permissions |
| `item/tool/requestUserInput` | Tool questions (experimental) |
| `item/tool/call` | Dynamic tool execution on client |
| `mcpServer/elicitation/request` | MCP elicitation |
| `account/chatgptAuthTokens/refresh` | Refresh ChatGPT tokens |
| `attestation/generate` | Upstream attestation when `request_attestation` enabled |

Resolve with the matching client response; the server emits `serverRequest/resolved` when done. See [Approvals and server requests](/approvals-and-server-requests).

## Concurrency and overload

| Behavior | Detail |
| --- | --- |
| Per-thread serialization | Most `thread/*` and `turn/*` mutations for the same `threadId` are serialized |
| Concurrent resources | `fs/*`, `fuzzyFileSearch*`, `model/list`, `thread/turns/list`, and similar read-heavy calls |
| Global locks | `config/*`, `account/*` auth, `remoteControl/*`, `environment/add` use named global serialization keys |
| Overload | Saturated ingress returns JSON-RPC `-32001` — retry with backoff |

## Related pages

<CardGroup>
  <Card title="Experimental API" href="/experimental-api">
    Opt-in, schema generation, and maintainer gating patterns.
  </Card>
  <Card title="Threads, turns, and items" href="/threads-turns-items">
    Core primitives and subscription model.
  </Card>
  <Card title="Config RPC reference" href="/config-rpc">
    Config read/write batch details and snake_case fields.
  </Card>
  <Card title="Schema generation" href="/schema-generation">
    `generate-ts` / `generate-json-schema` and `--experimental`.
  </Card>
  <Card title="Notifications and events" href="/notifications-and-events">
    Server notification catalog and item deltas.
  </Card>
</CardGroup>
