app-server.md +242 −35
3Codex app-server is the interface Codex uses to power rich clients (for example, the Codex VS Code extension). Use it when you want a deep integration inside your own product: authentication, conversation history, approvals, and streamed agent events. The app-server implementation is open source in the Codex GitHub repository ([openai/codex/codex-rs/app-server](https://github.com/openai/codex/tree/main/codex-rs/app-server)). See the [Open Source](https://developers.openai.com/codex/open-source) page for the full list of open-source Codex components.3Codex app-server is the interface Codex uses to power rich clients (for example, the Codex VS Code extension). Use it when you want a deep integration inside your own product: authentication, conversation history, approvals, and streamed agent events. The app-server implementation is open source in the Codex GitHub repository ([openai/codex/codex-rs/app-server](https://github.com/openai/codex/tree/main/codex-rs/app-server)). See the [Open Source](https://developers.openai.com/codex/open-source) page for the full list of open-source Codex components.
4 4
5If you are automating jobs or running Codex in CI, use the5If you are automating jobs or running Codex in CI, use the
66[Codex SDK](https://developers.openai.com/codex/sdk) instead. <a href="/codex/sdk">Codex SDK</a> instead.
7 7
8## Protocol8## Protocol
9 9
12Supported transports:12Supported transports:
13 13
14- `stdio` (`--listen stdio://`, default): newline-delimited JSON (JSONL).14- `stdio` (`--listen stdio://`, default): newline-delimited JSON (JSONL).
1515- `websocket` (`--listen ws://IP:PORT`, experimental): one JSON-RPC message per WebSocket text frame.- `websocket` (`--listen ws://IP:PORT`, experimental and unsupported): one JSON-RPC message per WebSocket text frame.
16- `off` (`--listen off`): don't expose a local transport.
17
18When you run with `--listen ws://IP:PORT`, the same listener also serves basic HTTP health probes:
19
20- `GET /readyz` returns `200 OK` once the listener accepts new connections.
21- `GET /healthz` returns `200 OK` when the request doesn't include an `Origin` header.
22- Requests with an `Origin` header are rejected with `403 Forbidden`.
23
24WebSocket transport is experimental and unsupported. Loopback listeners such as `ws://127.0.0.1:PORT` are appropriate for localhost and SSH port-forwarding workflows. Non-loopback WebSocket listeners currently allow unauthenticated connections by default during rollout, so configure WebSocket auth before exposing one remotely.
25
26Supported WebSocket auth flags:
27
28- `--ws-auth capability-token --ws-token-file /absolute/path`
29- `--ws-auth capability-token --ws-token-sha256 HEX`
30- `--ws-auth signed-bearer-token --ws-shared-secret-file /absolute/path`
31
32For signed bearer tokens, you can also set `--ws-issuer`, `--ws-audience`, and `--ws-max-clock-skew-seconds`. Clients present the credential as `Authorization: Bearer <token>` during the WebSocket handshake, and app-server enforces auth before JSON-RPC `initialize`.
33
34Prefer `--ws-token-file` over passing raw bearer tokens on the command line. Use `--ws-token-sha256` only when the client keeps the raw high-entropy token in a separate local secret store; the hash is only a verifier, and clients still need the original token.
16 35
17In WebSocket mode, app-server uses bounded queues. When request ingress is full, the server rejects new requests with JSON-RPC error code `-32001` and message `"Server overloaded; retry later."` Clients should retry with an exponentially increasing delay and jitter.36In WebSocket mode, app-server uses bounded queues. When request ingress is full, the server rejects new requests with JSON-RPC error code `-32001` and message `"Server overloaded; retry later."` Clients should retry with an exponentially increasing delay and jitter.
18 37
56Example (Node.js / TypeScript):75Example (Node.js / TypeScript):
57 76
58```ts77```ts
5978import { spawn } from "node:child_process";
6079import readline from "node:readline";
61 80
62const proc = spawn("codex", ["app-server"], {81const proc = spawn("codex", ["app-server"], {
63 stdio: ["pipe", "pipe", "inherit"],82 stdio: ["pipe", "pipe", "inherit"],
199- `thread/resume` - reopen an existing thread by id so later `turn/start` calls append to it.218- `thread/resume` - reopen an existing thread by id so later `turn/start` calls append to it.
200- `thread/fork` - fork a thread into a new thread id by copying stored history; emits `thread/started` for the new thread.219- `thread/fork` - fork a thread into a new thread id by copying stored history; emits `thread/started` for the new thread.
201- `thread/read` - read a stored thread by id without resuming it; set `includeTurns` to return full turn history. Returned `thread` objects include runtime `status`.220- `thread/read` - read a stored thread by id without resuming it; set `includeTurns` to return full turn history. Returned `thread` objects include runtime `status`.
202221- `thread/list` - page through stored thread logs; supports cursor-based pagination plus `modelProviders`, `sourceKinds`, `archived`, and `cwd` filters. Returned `thread` objects include runtime `status`.- `thread/list` - page through stored thread logs; supports cursor-based pagination plus `modelProviders`, `sourceKinds`, `archived`, `cwd`, and `searchTerm` filters. Returned `thread` objects include runtime `status`.
222- `thread/turns/list` - page through a stored thread's turn history without resuming it.
203- `thread/loaded/list` - list the thread ids currently loaded in memory.223- `thread/loaded/list` - list the thread ids currently loaded in memory.
204- `thread/name/set` - set or update a thread's user-facing name for a loaded thread or a persisted rollout; emits `thread/name/updated`.224- `thread/name/set` - set or update a thread's user-facing name for a loaded thread or a persisted rollout; emits `thread/name/updated`.
225- `thread/goal/set` - set the goal for a loaded thread (experimental; requires `capabilities.experimentalApi`); emits `thread/goal/updated`.
226- `thread/goal/get` - read the current goal for a loaded thread (experimental; requires `capabilities.experimentalApi`).
227- `thread/goal/clear` - clear the goal for a loaded thread (experimental; requires `capabilities.experimentalApi`); emits `thread/goal/cleared`.
228- `thread/metadata/update` - patch SQLite-backed stored thread metadata; currently supports persisted `gitInfo`.
205- `thread/archive` - move a thread's log file into the archived directory; returns `{}` on success and emits `thread/archived`.229- `thread/archive` - move a thread's log file into the archived directory; returns `{}` on success and emits `thread/archived`.
206230- `thread/unsubscribe` - unsubscribe this connection from thread turn/item events. If this was the last subscriber, the server unloads the thread and emits `thread/closed`.- `thread/unsubscribe` - unsubscribe this connection from thread turn/item events. If this was the last subscriber, the server unloads the thread after a no-subscriber inactivity grace period and emits `thread/closed`.
207- `thread/unarchive` - restore an archived thread rollout back into the active sessions directory; returns the restored `thread` and emits `thread/unarchived`.231- `thread/unarchive` - restore an archived thread rollout back into the active sessions directory; returns the restored `thread` and emits `thread/unarchived`.
208- `thread/status/changed` - notification emitted when a loaded thread's runtime `status` changes.232- `thread/status/changed` - notification emitted when a loaded thread's runtime `status` changes.
209- `thread/compact/start` - trigger conversation history compaction for a thread; returns `{}` immediately while progress streams via `turn/*` and `item/*` notifications.233- `thread/compact/start` - trigger conversation history compaction for a thread; returns `{}` immediately while progress streams via `turn/*` and `item/*` notifications.
211- `thread/backgroundTerminals/clean` - stop all running background terminals for a thread (experimental; requires `capabilities.experimentalApi`).235- `thread/backgroundTerminals/clean` - stop all running background terminals for a thread (experimental; requires `capabilities.experimentalApi`).
212- `thread/rollback` - drop the last N turns from the in-memory context and persist a rollback marker; returns the updated `thread`.236- `thread/rollback` - drop the last N turns from the in-memory context and persist a rollback marker; returns the updated `thread`.
213- `turn/start` - add user input to a thread and begin Codex generation; responds with the initial `turn` and streams events. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode."237- `turn/start` - add user input to a thread and begin Codex generation; responds with the initial `turn` and streams events. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode."
238- `thread/inject_items` - append raw Responses API items to a loaded thread's model-visible history without starting a user turn.
214- `turn/steer` - append user input to the active in-flight turn for a thread; returns the accepted `turnId`.239- `turn/steer` - append user input to the active in-flight turn for a thread; returns the accepted `turnId`.
215- `turn/interrupt` - request cancellation of an in-flight turn; success is `{}` and the turn ends with `status: "interrupted"`.240- `turn/interrupt` - request cancellation of an in-flight turn; success is `{}` and the turn ends with `status: "interrupted"`.
216- `review/start` - kick off the Codex reviewer for a thread; emits `enteredReviewMode` and `exitedReviewMode` items.241- `review/start` - kick off the Codex reviewer for a thread; emits `enteredReviewMode` and `exitedReviewMode` items.
218- `command/exec/write` - write `stdin` bytes to a running `command/exec` session or close `stdin`.243- `command/exec/write` - write `stdin` bytes to a running `command/exec` session or close `stdin`.
219- `command/exec/resize` - resize a running PTY-backed `command/exec` session.244- `command/exec/resize` - resize a running PTY-backed `command/exec` session.
220- `command/exec/terminate` - stop a running `command/exec` session.245- `command/exec/terminate` - stop a running `command/exec` session.
246- `command/exec/outputDelta` (notify) - emitted for base64-encoded stdout/stderr chunks from a streaming `command/exec` session.
221- `model/list` - list available models (set `includeHidden: true` to include entries with `hidden: true`) with effort options, optional `upgrade`, and `inputModalities`.247- `model/list` - list available models (set `includeHidden: true` to include entries with `hidden: true`) with effort options, optional `upgrade`, and `inputModalities`.
248- `modelProvider/capabilities/read` - read provider capability bounds for model/provider combinations (experimental; requires `capabilities.experimentalApi`).
222- `experimentalFeature/list` - list feature flags with lifecycle stage metadata and cursor pagination.249- `experimentalFeature/list` - list feature flags with lifecycle stage metadata and cursor pagination.
250- `experimentalFeature/enablement/set` - patch in-memory runtime enablement for supported feature keys such as `apps` and `plugins`.
223- `collaborationMode/list` - list collaboration mode presets (experimental, no pagination).251- `collaborationMode/list` - list collaboration mode presets (experimental, no pagination).
224- `skills/list` - list skills for one or more `cwd` values (supports `forceReload` and optional `perCwdExtraUserRoots`).252- `skills/list` - list skills for one or more `cwd` values (supports `forceReload` and optional `perCwdExtraUserRoots`).
225253- `plugin/list` - list discovered plugin marketplaces and plugin state, including install/auth policy metadata, marketplace errors, featured plugin ids, and the development-only `forceRemoteSync` option.- `skills/changed` (notify) - emitted when watched local skill files change.
226254- `plugin/read` - read one plugin by marketplace path and plugin name, including bundled skills, apps, and MCP server names.- `marketplace/add` - add a remote plugin marketplace and persist it into the user's marketplace config.
227255- `plugin/install` - install a plugin from a marketplace path.- `marketplace/upgrade` - refresh a configured Git marketplace, or all configured Git marketplaces when you omit the marketplace name.
256- `plugin/list` - list discovered plugin marketplaces and plugin state, including install/auth policy metadata, marketplace load errors, featured plugin ids, and local, Git, or remote plugin source metadata.
257- `plugin/read` - read one plugin by marketplace path or remote marketplace name and plugin name, including bundled skills, apps, and MCP server names when those details are available.
258- `plugin/install` - install a plugin from a marketplace path or remote marketplace name.
228- `plugin/uninstall` - uninstall an installed plugin.259- `plugin/uninstall` - uninstall an installed plugin.
229- `app/list` - list available apps (connectors) with pagination plus accessibility/enabled metadata.260- `app/list` - list available apps (connectors) with pagination plus accessibility/enabled metadata.
230- `skills/config/write` - enable or disable skills by path.261- `skills/config/write` - enable or disable skills by path.
233- `config/mcpServer/reload` - reload MCP server configuration from disk and queue a refresh for loaded threads.264- `config/mcpServer/reload` - reload MCP server configuration from disk and queue a refresh for loaded threads.
234- `mcpServerStatus/list` - list MCP servers, tools, resources, and auth status (cursor + limit pagination). Use `detail: "full"` for full data or `detail: "toolsAndAuthOnly"` to omit resources.265- `mcpServerStatus/list` - list MCP servers, tools, resources, and auth status (cursor + limit pagination). Use `detail: "full"` for full data or `detail: "toolsAndAuthOnly"` to omit resources.
235- `mcpServer/resource/read` - read a single MCP resource through an initialized MCP server.266- `mcpServer/resource/read` - read a single MCP resource through an initialized MCP server.
267- `mcpServer/tool/call` - call a tool on a thread's configured MCP server.
268- `mcpServer/startupStatus/updated` (notify) - emitted when a configured MCP server's startup status changes for a loaded thread.
236- `windowsSandbox/setupStart` - start Windows sandbox setup for `elevated` or `unelevated` mode; returns quickly and later emits `windowsSandbox/setupCompleted`.269- `windowsSandbox/setupStart` - start Windows sandbox setup for `elevated` or `unelevated` mode; returns quickly and later emits `windowsSandbox/setupCompleted`.
237- `feedback/upload` - submit a feedback report (classification + optional reason/logs + conversation id, plus optional `extraLogFiles` attachments).270- `feedback/upload` - submit a feedback report (classification + optional reason/logs + conversation id, plus optional `extraLogFiles` attachments).
238- `config/read` - fetch the effective configuration on disk after resolving configuration layering.271- `config/read` - fetch the effective configuration on disk after resolving configuration layering.
239- `externalAgentConfig/detect` - detect external-agent artifacts that can be migrated with `includeHome` and optional `cwds`; each detected item includes `cwd` (`null` for home).272- `externalAgentConfig/detect` - detect external-agent artifacts that can be migrated with `includeHome` and optional `cwds`; each detected item includes `cwd` (`null` for home).
240273- `externalAgentConfig/import` - apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home).- `externalAgentConfig/import` - apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home). Supported item types include config, skills, `AGENTS.md`, plugins, MCP server config, subagents, hooks, commands, and sessions; plugin imports emit `externalAgentConfig/import/completed`.
241- `config/value/write` - write a single configuration key/value to the user's `config.toml` on disk.274- `config/value/write` - write a single configuration key/value to the user's `config.toml` on disk.
242- `config/batchWrite` - apply configuration edits atomically to the user's `config.toml` on disk.275- `config/batchWrite` - apply configuration edits atomically to the user's `config.toml` on disk.
243- `configRequirements/read` - fetch requirements from `requirements.toml` and/or MDM, including allow-lists, pinned `featureRequirements`, and residency/network requirements (or `null` if you haven't set any up).276- `configRequirements/read` - fetch requirements from `requirements.toml` and/or MDM, including allow-lists, pinned `featureRequirements`, and residency/network requirements (or `null` if you haven't set any up).
244277- `fs/readFile`, `fs/writeFile`, `fs/createDirectory`, `fs/getMetadata`, `fs/readDirectory`, `fs/remove`, and `fs/copy` - operate on absolute filesystem paths through the app-server v2 filesystem API.- `fs/readFile`, `fs/writeFile`, `fs/createDirectory`, `fs/getMetadata`, `fs/readDirectory`, `fs/remove`, `fs/copy`, `fs/watch`, `fs/unwatch`, and `fs/changed` (notify) - operate on absolute filesystem paths through the app-server v2 filesystem API.
278
279Plugin summaries include a `source` union. Local plugins return
280`{ "type": "local", "path": ... }`, Git-backed marketplace entries return
281`{ "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... }`,
282and remote catalog entries return `{ "type": "remote" }`. For remote-only
283catalog entries, `PluginMarketplaceEntry.path` can be `null`; pass
284`remoteMarketplaceName` instead of `marketplacePath` when reading or installing
285those plugins.
245 286
246## Models287## Models
247 288
310## Threads351## Threads
311 352
312- `thread/read` reads a stored thread without subscribing to it; set `includeTurns` to include turns.353- `thread/read` reads a stored thread without subscribing to it; set `includeTurns` to include turns.
313354- `thread/list` supports cursor pagination plus `modelProviders`, `sourceKinds`, `archived`, and `cwd` filtering.- `thread/turns/list` pages through a stored thread's turn history without resuming it.
355- `thread/list` supports cursor pagination plus `modelProviders`, `sourceKinds`, `archived`, `cwd`, and `searchTerm` filtering.
314- `thread/loaded/list` returns the thread IDs currently in memory.356- `thread/loaded/list` returns the thread IDs currently in memory.
315- `thread/archive` moves the thread's persisted JSONL log into the archived directory.357- `thread/archive` moves the thread's persisted JSONL log into the archived directory.
316358- `thread/unsubscribe` unsubscribes the current connection from a loaded thread and can trigger `thread/closed`.- `thread/metadata/update` patches stored thread metadata, currently including persisted `gitInfo`.
359- `thread/unsubscribe` unsubscribes the current connection from a loaded thread and can trigger `thread/closed` after an inactivity grace period.
317- `thread/unarchive` restores an archived thread rollout back into the active sessions directory.360- `thread/unarchive` restores an archived thread rollout back into the active sessions directory.
318- `thread/compact/start` triggers compaction and returns `{}` immediately.361- `thread/compact/start` triggers compaction and returns `{}` immediately.
319- `thread/rollback` drops the last N turns from the in-memory context and records a rollback marker in the thread's persisted JSONL log.362- `thread/rollback` drops the last N turns from the in-memory context and records a rollback marker in the thread's persisted JSONL log.
363- `thread/inject_items` appends raw Responses API items to a loaded thread's model-visible history without starting a user turn.
320 364
321### Start or resume a thread365### Start or resume a thread
322 366
387 431
388Unlike `thread/resume`, `thread/read` doesn't load the thread into memory or emit `thread/started`.432Unlike `thread/resume`, `thread/read` doesn't load the thread into memory or emit `thread/started`.
389 433
434### List thread turns
435
436Use `thread/turns/list` to page a stored thread's turn history without resuming it. Results default to newest-first so clients can fetch older turns with `nextCursor`. The response also includes `backwardsCursor`; pass it as `cursor` with `sortDirection: "asc"` to fetch turns newer than the first item from the earlier page.
437
438```json
439{ "method": "thread/turns/list", "id": 20, "params": {
440 "threadId": "thr_123",
441 "limit": 50,
442 "sortDirection": "desc"
443} }
444{ "id": 20, "result": {
445 "data": [],
446 "nextCursor": "older-turns-cursor-or-null",
447 "backwardsCursor": "newer-turns-cursor-or-null"
448} }
449```
450
390### List threads (with pagination & filters)451### List threads (with pagination & filters)
391 452
392`thread/list` lets you render a history UI. Results default to newest-first by `createdAt`. Filters apply before pagination. Pass any combination of:453`thread/list` lets you render a history UI. Results default to newest-first by `createdAt`. Filters apply before pagination. Pass any combination of:
398- `sourceKinds` - restrict results to specific thread sources. When omitted or `[]`, the server defaults to interactive sources only: `cli` and `vscode`.459- `sourceKinds` - restrict results to specific thread sources. When omitted or `[]`, the server defaults to interactive sources only: `cli` and `vscode`.
399- `archived` - when `true`, list archived threads only. When `false` or omitted, list non-archived threads (default).460- `archived` - when `true`, list archived threads only. When `false` or omitted, list non-archived threads (default).
400- `cwd` - restrict results to threads whose session current working directory exactly matches this path.461- `cwd` - restrict results to threads whose session current working directory exactly matches this path.
462- `searchTerm` - search stored thread summaries and metadata before pagination.
401 463
402`sourceKinds` accepts the following values:464`sourceKinds` accepts the following values:
403 465
431 493
432When `nextCursor` is `null`, you have reached the final page.494When `nextCursor` is `null`, you have reached the final page.
433 495
496### Update stored thread metadata
497
498Use `thread/metadata/update` to patch stored thread metadata without resuming the thread. Today this supports persisted `gitInfo`; omitted fields are left unchanged, and explicit `null` clears a stored value.
499
500```json
501{ "method": "thread/metadata/update", "id": 21, "params": {
502 "threadId": "thr_123",
503 "gitInfo": { "branch": "feature/sidebar-pr" }
504} }
505{ "id": 21, "result": {
506 "thread": {
507 "id": "thr_123",
508 "gitInfo": { "sha": null, "branch": "feature/sidebar-pr", "originUrl": null }
509 }
510} }
511```
512
434### Track thread status changes513### Track thread status changes
435 514
436`thread/status/changed` is emitted whenever a loaded thread's runtime status changes. The payload includes `threadId` and the new `status`.515`thread/status/changed` is emitted whenever a loaded thread's runtime status changes. The payload includes `threadId` and the new `status`.
462- `notSubscribed` when the connection wasn't subscribed to that thread.541- `notSubscribed` when the connection wasn't subscribed to that thread.
463- `notLoaded` when the thread isn't loaded.542- `notLoaded` when the thread isn't loaded.
464 543
465544If this was the last subscriber, the server unloads the thread and emits a `thread/status/changed` transition to `notLoaded` plus `thread/closed`.If this was the last subscriber, the server keeps the thread loaded until it has no subscribers and no thread activity for 30 minutes. When the grace period expires, app-server unloads the thread and emits a `thread/status/changed` transition to `notLoaded` plus `thread/closed`.
466 545
467```json546```json
468{ "method": "thread/unsubscribe", "id": 22, "params": { "threadId": "thr_123" } }547{ "method": "thread/unsubscribe", "id": 22, "params": { "threadId": "thr_123" } }
469{ "id": 22, "result": { "status": "unsubscribed" } }548{ "id": 22, "result": { "status": "unsubscribed" } }
549```
550
551If the thread later expires:
552
553```json
470{ "method": "thread/status/changed", "params": {554{ "method": "thread/status/changed", "params": {
471 "threadId": "thr_123",555 "threadId": "thr_123",
472 "status": { "type": "notLoaded" }556 "status": { "type": "notLoaded" }
615{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }699{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }
616```700```
617 701
702### Inject items into a thread
703
704Use `thread/inject_items` to append prebuilt Responses API items to a loaded thread's prompt history without starting a user turn. These items are persisted to the rollout and included in subsequent model requests.
705
706```json
707{ "method": "thread/inject_items", "id": 31, "params": {
708 "threadId": "thr_123",
709 "items": [
710 {
711 "type": "message",
712 "role": "assistant",
713 "content": [{ "type": "output_text", "text": "Previously computed context." }]
714 }
715 ]
716} }
717{ "id": 31, "result": {} }
718```
719
618### Steer an active turn720### Steer an active turn
619 721
620Use `turn/steer` to append more user input to the active in-flight turn.722Use `turn/steer` to append more user input to the active in-flight turn.
796- `elevated` - run the elevated Windows sandbox setup path.898- `elevated` - run the elevated Windows sandbox setup path.
797- `unelevated` - run the legacy setup/preflight path.899- `unelevated` - run the legacy setup/preflight path.
798 900
901## Filesystem
902
903The v2 filesystem APIs operate on absolute paths. Use `fs/watch` when a client needs to invalidate UI state after a file or directory changes.
904
905```json
906{ "method": "fs/watch", "id": 54, "params": {
907 "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
908 "path": "/Users/me/project/.git/HEAD"
909} }
910{ "id": 54, "result": { "path": "/Users/me/project/.git/HEAD" } }
911{ "method": "fs/changed", "params": {
912 "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
913 "changedPaths": ["/Users/me/project/.git/HEAD"]
914} }
915{ "method": "fs/unwatch", "id": 55, "params": {
916 "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1"
917} }
918{ "id": 55, "result": {} }
919```
920
921Watching a file emits `fs/changed` for that file path, including updates delivered by replace or rename operations.
922
799## Events923## Events
800 924
801Event notifications are the server-initiated stream for thread lifecycles, turn lifecycles, and the items within them. After you start or resume a thread, keep reading the active transport stream for `thread/started`, `thread/archived`, `thread/unarchived`, `thread/closed`, `thread/status/changed`, `turn/*`, `item/*`, and `serverRequest/resolved` notifications.925Event notifications are the server-initiated stream for thread lifecycles, turn lifecycles, and the items within them. After you start or resume a thread, keep reading the active transport stream for `thread/started`, `thread/archived`, `thread/unarchived`, `thread/closed`, `thread/status/changed`, `turn/*`, `item/*`, and `serverRequest/resolved` notifications.
1016} }1141} }
1017```1142```
1018 1143
1144The server also emits `skills/changed` notifications when watched local skill files change. Treat this as an invalidation signal and rerun `skills/list` with your current params when needed.
1145
1019To enable or disable a skill by path:1146To enable or disable a skill by path:
1020 1147
1021```json1148```json
1222{ "id": 64, "result": {} }1349{ "id": 64, "result": {} }
1223```1350```
1224 1351
12251352Supported `itemType` values are `AGENTS_MD`, `CONFIG`, `SKILLS`, and `MCP_SERVER_CONFIG`. Detection returns only items that still have work to do. For example, AGENTS migration is skipped when `AGENTS.md` already exists and is non-empty, and skill imports don’t overwrite existing skill directories.When a request includes plugin imports, the server emits `externalAgentConfig/import/completed` after the import finishes. This notification may arrive immediately after the response or after background remote imports complete.
1353
1354Supported `itemType` values are `AGENTS_MD`, `CONFIG`, `SKILLS`, `PLUGINS`,
1355and `MCP_SERVER_CONFIG`. For `PLUGINS` items, `details.plugins` lists each
1356`marketplaceName` and the `pluginNames` Codex can try to migrate. Detection
1357returns only items that still have work to do. For example, Codex skips AGENTS
1358migration when `AGENTS.md` already exists and is non-empty, and skill imports
1359don't overwrite existing skill directories.
1360
1361When detecting plugins from `.claude/settings.json`, Codex reads configured
1362marketplace sources from `extraKnownMarketplaces`. If `enabledPlugins` contains
1363plugins from `claude-plugins-official` but the marketplace source is missing,
1364Codex infers `anthropics/claude-plugins-official` as the source.
1226 1365
1227## Auth endpoints1366## Auth endpoints
1228 1367
12291368The JSON-RPC auth/account surface exposes request/response methods plus server-initiated notifications (no `id`). Use these to determine auth state, start or cancel logins, logout, and inspect ChatGPT rate limits.The JSON-RPC auth/account surface exposes request/response methods plus server-initiated notifications (no `id`). Use these to determine auth state, start or cancel logins, logout, inspect ChatGPT rate limits, and notify workspace owners about depleted credits or usage limits.
1230 1369
1231### Authentication modes1370### Authentication modes
1232 1371
12331372Codex supports three authentication modes. `account/updated.authMode` shows the active mode, and `account/read` also reports it.Codex supports these authentication modes. `account/updated.authMode` shows the active mode and includes the current ChatGPT `planType` when available. `account/read` also reports account and plan details.
1234 1373
12351374- **API key (`apikey`)** - the caller supplies an OpenAI API key and Codex stores it for API requests.- **API key (`apikey`)** - the caller supplies an OpenAI API key with `type: "apiKey"`, and Codex stores it for API requests.
12361375- **ChatGPT managed (`chatgpt`)** - Codex owns the ChatGPT OAuth flow, persists tokens, and refreshes them automatically.- **ChatGPT managed (`chatgpt`)** - Codex owns the ChatGPT OAuth flow, persists tokens, and refreshes them automatically. Start with `type: "chatgpt"` for the browser flow or `type: "chatgptDeviceCode"` for the device-code flow.
12371376- **ChatGPT external tokens (`chatgptAuthTokens`)** - a host app supplies `idToken` and `accessToken` directly. Codex stores these tokens in memory, and the host app must refresh them when asked.- **ChatGPT external tokens (`chatgptAuthTokens`)** - experimental and intended for host apps that already own the user's ChatGPT auth lifecycle. The host app supplies an `accessToken`, `chatgptAccountId`, and optional `chatgptPlanType` directly, and must refresh the token when asked.
1238 1377
1239### API overview1378### API overview
1240 1379
1241- `account/read` - fetch current account info; optionally refresh tokens.1380- `account/read` - fetch current account info; optionally refresh tokens.
12421381- `account/login/start` - begin login (`apiKey`, `chatgpt`, or `chatgptAuthTokens`).- `account/login/start` - begin login (`apiKey`, `chatgpt`, `chatgptDeviceCode`, or experimental `chatgptAuthTokens`).
1243- `account/login/completed` (notify) - emitted when a login attempt finishes (success or error).1382- `account/login/completed` (notify) - emitted when a login attempt finishes (success or error).
12441383- `account/login/cancel` - cancel a pending ChatGPT login by `loginId`.- `account/login/cancel` - cancel a pending managed ChatGPT login by `loginId`.
1245- `account/logout` - sign out; triggers `account/updated`.1384- `account/logout` - sign out; triggers `account/updated`.
12461385- `account/updated` (notify) - emitted whenever auth mode changes (`authMode`: `apikey`, `chatgpt`, `chatgptAuthTokens`, or `null`).- `account/updated` (notify) - emitted whenever auth mode changes (`authMode`: `apikey`, `chatgpt`, `chatgptAuthTokens`, or `null`) and includes `planType` when available.
1247- `account/chatgptAuthTokens/refresh` (server request) - request fresh externally managed ChatGPT tokens after an authorization error.1386- `account/chatgptAuthTokens/refresh` (server request) - request fresh externally managed ChatGPT tokens after an authorization error.
1248- `account/rateLimits/read` - fetch ChatGPT rate limits.1387- `account/rateLimits/read` - fetch ChatGPT rate limits.
1249- `account/rateLimits/updated` (notify) - emitted whenever a user's ChatGPT rate limits change.1388- `account/rateLimits/updated` (notify) - emitted whenever a user's ChatGPT rate limits change.
1389- `account/sendAddCreditsNudgeEmail` - ask ChatGPT to email a workspace owner about depleted credits or a reached usage limit.
1250- `mcpServer/oauthLogin/completed` (notify) - emitted after a `mcpServer/oauth/login` flow finishes; payload includes `{ name, success, error? }`.1390- `mcpServer/oauthLogin/completed` (notify) - emitted after a `mcpServer/oauth/login` flow finishes; payload includes `{ name, success, error? }`.
1391- `mcpServer/startupStatus/updated` (notify) - emitted when a configured MCP server's startup status changes for a loaded thread; payload includes `{ name, status, error }`.
1251 1392
1252### 1) Check auth state1393### 1) Check auth state
1253 1394
1319 ```1462 ```
1320 1463
1321 ```json1464 ```json
13221465 { "method": "account/updated", "params": { "authMode": "apikey" } } {
1466 "method": "account/updated",
1467 "params": { "authMode": "apikey", "planType": null }
1468 }
1323 ```1469 ```
1324 1470
1325### 3) Log in with ChatGPT (browser flow)1471### 3) Log in with ChatGPT (browser flow)
1351 ```1498 ```
1352 1499
1353 ```json1500 ```json
13541501 { "method": "account/updated", "params": { "authMode": "chatgpt" } } {
1502 "method": "account/updated",
1503 "params": { "authMode": "chatgpt", "planType": "plus" }
1504 }
1355 ```1505 ```
1356 1506
13571507### 3b) Log in with externally managed ChatGPT tokens (`chatgptAuthTokens`)### 3b) Log in with ChatGPT (device-code flow)
1358 1508
13591509Use this mode when a host application owns the user’s ChatGPT auth lifecycle and supplies tokens directly.Use this flow when your client owns the sign-in ceremony or when a browser callback is brittle.
1510
15111. Start:
1512
1513 ```json
1514 {
1515 "method": "account/login/start",
1516 "id": 4,
1517 "params": { "type": "chatgptDeviceCode" }
1518 }
1519 ```
1520
1521 ```json
1522 {
1523 "id": 4,
1524 "result": {
1525 "type": "chatgptDeviceCode",
1526 "loginId": "<uuid>",
1527 "verificationUrl": "https://auth.openai.com/codex/device",
1528 "userCode": "ABCD-1234"
1529 }
1530 }
1531 ```
1532
15332. Show `verificationUrl` and `userCode` to the user; the frontend owns the UX.
15343. Wait for notifications:
1535
1536 ```json
1537 {
1538 "method": "account/login/completed",
1539 "params": { "loginId": "<uuid>", "success": true, "error": null }
1540 }
1541 ```
1542
1543 ```json
1544 {
1545 "method": "account/updated",
1546 "params": { "authMode": "chatgpt", "planType": "plus" }
1547 }
1548 ```
1549
1550### 3c) Log in with externally managed ChatGPT tokens (`chatgptAuthTokens`)
1551
1552Use this experimental mode only when a host application owns the user's ChatGPT auth lifecycle and supplies tokens directly. Clients must set `capabilities.experimentalApi = true` during `initialize` before using this login type.
1360 1553
13611. Send:15541. Send:
1362 1555
1366 "id": 7,1559 "id": 7,
1367 "params": {1560 "params": {
1368 "type": "chatgptAuthTokens",1561 "type": "chatgptAuthTokens",
13691562 "idToken": "<jwt>", "accessToken": "<jwt>",
13701563 "accessToken": "<jwt>" "chatgptAccountId": "org-123",
1564 "chatgptPlanType": "business"
1371 }1565 }
1372 }1566 }
1373 ```1567 ```
1388 ```json1584 ```json
1389 {1585 {
1390 "method": "account/updated",1586 "method": "account/updated",
13911587 "params": { "authMode": "chatgptAuthTokens" } "params": { "authMode": "chatgptAuthTokens", "planType": "business" }
1392 }1588 }
1393 ```1589 ```
1394 1590
1400 "id": 8,1596 "id": 8,
1401 "params": { "reason": "unauthorized", "previousAccountId": "org-123" }1597 "params": { "reason": "unauthorized", "previousAccountId": "org-123" }
1402}1598}
14031599{ "id": 8, "result": { "idToken": "<jwt>", "accessToken": "<jwt>" } }{ "id": 8, "result": { "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } }
1404```1600```
1405 1601
1406The server retries the original request after a successful refresh response. Requests time out after about 10 seconds.1602The server retries the original request after a successful refresh response. Requests time out after about 10 seconds.
1417```json1613```json
1418{ "method": "account/logout", "id": 5 }1614{ "method": "account/logout", "id": 5 }
1419{ "id": 5, "result": {} }1615{ "id": 5, "result": {} }
14201616{ "method": "account/updated", "params": { "authMode": null } }{ "method": "account/updated", "params": { "authMode": null, "planType": null } }
1421```1617```
1422 1618
1423### 6) Rate limits (ChatGPT)1619### 6) Rate limits (ChatGPT)
1429 "limitId": "codex",1625 "limitId": "codex",
1430 "limitName": null,1626 "limitName": null,
1431 "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },1627 "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
14321628 "secondary": null "secondary": null,
1629 "rateLimitReachedType": null
1433 },1630 },
1434 "rateLimitsByLimitId": {1631 "rateLimitsByLimitId": {
1435 "codex": {1632 "codex": {
1436 "limitId": "codex",1633 "limitId": "codex",
1437 "limitName": null,1634 "limitName": null,
1438 "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },1635 "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
14391636 "secondary": null "secondary": null,
1637 "rateLimitReachedType": null
1440 },1638 },
1441 "codex_other": {1639 "codex_other": {
1442 "limitId": "codex_other",1640 "limitId": "codex_other",
1443 "limitName": "codex_other",1641 "limitName": "codex_other",
1444 "primary": { "usedPercent": 42, "windowDurationMins": 60, "resetsAt": 1730950800 },1642 "primary": { "usedPercent": 42, "windowDurationMins": 60, "resetsAt": 1730950800 },
14451643 "secondary": null "secondary": null,
1644 "rateLimitReachedType": null
1446 }1645 }
1447 }1646 }
1448} }1647} }
1463- `usedPercent` is current usage within the quota window.1662- `usedPercent` is current usage within the quota window.
1464- `windowDurationMins` is the quota window length.1663- `windowDurationMins` is the quota window length.
1465- `resetsAt` is a Unix timestamp (seconds) for the next reset.1664- `resetsAt` is a Unix timestamp (seconds) for the next reset.
1665- `planType` is included when the backend returns the ChatGPT plan associated with a bucket.
1666- `credits` is included when the backend returns remaining workspace credit details.
1667- `rateLimitReachedType` identifies the backend-classified limit state when one has been reached.
1668
1669### 7) Notify a workspace owner about a limit
1670
1671Use `account/sendAddCreditsNudgeEmail` to ask ChatGPT to email a workspace owner when credits are depleted or a usage limit has been reached.
1672
1673```json
1674{ "method": "account/sendAddCreditsNudgeEmail", "id": 7, "params": { "creditType": "credits" } }
1675{ "id": 7, "result": { "status": "sent" } }
1676```
1677
1678Use `creditType: "credits"` when workspace credits are depleted, or `creditType: "usage_limit"` when the workspace usage limit has been reached. If the owner was already notified recently, the response status is `cooldown_active`.