# Codex Runtime Provider

Owns the Codex app-server runtime adapter for Chat Runtime. This directory translates between Cradle `UIMessage` state and the Codex JSON-RPC app-server protocol.
Codex tool identity and the `{ identifier, apiName, args, result }` envelope are owned by `tools/`; this provider only maps app-server protocol items into that stable contract.
Selected chat Skills arrive as Cradle-owned `data-cradle-skill` message parts. The provider reads them and projects them into Codex app-server `UserInput` skill items without writing to any skills namespace.
Codex thread display titles are read from app-server `thread/start`/`thread/resume` responses, `thread/name/updated` notifications, and final `thread/read` metadata, then reported through Chat Runtime's title callback. Provider metadata is normalized as `name`, then persisted `title`, then `preview`; Cradle owns the final `sessions.title` write. When a fresh Codex thread starts without a name, this provider opportunistically starts a separate ephemeral app-server title thread in the background, using Chat-owned title-generation preferences for provider target, explicit model, and thinking effort; when provider/model are unset it follows the active chat session provider/model. The generated title is written back through app-server `thread/name/set` for the main thread and reported to Chat Runtime; the title turn is not awaited by the main `turn/start` path and is not injected into the main Codex session.
Codex app-server child processes receive Cradle-owned `CRADLE_CHAT_SESSION_ID`, `CRADLE_WORKSPACE_ID`, `CRADLE_WORKSPACE_PATH`, and agent context env vars when available so tools and shell subprocesses can call back into Cradle with the current chat/workspace/agent context. These values are convenience context only; authoritative ownership still comes from Chat Runtime resolving `sessions.workspaceId` and `sessions.agentId`.
Because those values are process environment, every chat-bound Codex app-server host is scoped by Cradle chat session id. Provider target still owns auth, model-provider config, and account semantics, but it must not be the reuse boundary for a process that carries `CRADLE_CHAT_SESSION_ID` or workspace env. Provider-target diagnostics use a separate diagnostic scope and are not reusable chat hosts.
Agent-scoped Codex sessions use `~/.cradle/agents/{agentId}` as app-server `cwd`. The original project remains explicit through `runtimeWorkspaceRoots`, sandbox writable roots, and `CRADLE_WORKSPACE_PATH`; the provider does not change Codex's global `CODEX_HOME`, which stays under Cradle's app-server runtime data directory.
Codex auth is selected explicitly on each Cradle provider target and is backed by Cradle-owned encrypted credentials. The supported modes are ordinary OpenAI-compatible API key auth, ChatGPT Login, Codex Personal Access Token, and AWS Bedrock API Key. API-key auth stores the existing provider-kind secret and projects `CRADLE_CODEX_API_KEY`, `CODEX_API_KEY`, and `OPENAI_API_KEY` into the app-server process. ChatGPT Login stores encrypted JSON as a `chatgpt-auth` secret, calls `account/login/start` with `chatgptAuthTokens`, leaves API-key environment variables unset, and handles `account/chatgptAuthTokens/refresh` by refreshing OAuth token material back into that same secret row. Provider-target account diagnostics read Codex-native account identity, auth-required state, rate limits, reset-credit availability, and token usage without projecting auth tokens. Personal Access Token stores a `codex-personal-access-token` secret and projects it only as Codex's native `CODEX_ACCESS_TOKEN`. Bedrock stores a `codex-bedrock-api-key` secret, stores non-secret `bedrock.region` in provider config, projects `AWS_BEARER_TOKEN_BEDROCK` plus `AWS_REGION`, and writes Codex's native `amazon-bedrock` model-provider config. The resolver uses the secret row's `kind`; it does not infer auth type from token prefixes, base URLs, model names, or secret payload shape.
Existing Codex threads are resumed with `excludeTurns: true`. Before a turn, Cradle reads `thread/turns/list` only when the current provider snapshot lacks a complete, full, cursor-free history for that exact thread; it refreshes history after the turn. Cradle stores that best-effort full app-server turn page in the provider snapshot under the Codex namespace it owns; this captures everything app-server can reconstruct from persisted Codex rollout history without writing duplicate native history back into Codex. When a later provider-target change forces a fresh Codex thread, Cradle carries the previous Codex native history snapshot through `StartChatSessionInput.previousProviderStateSnapshot`, projects it to Responses API items, and injects it before the first turn so the new thread receives the richest app-server history Cradle had already fetched.
Goal slash commands and internal goal continuations are provider-native control messages, not chat text. A visible `/goal <objective>` command or goal metadata message sets `thread/goal/set` with an objective, and an internal Chat Runtime goal-continuation message sets `thread/goal/set` with `status: "active"` without calling `turn/start`. The provider then streams the resulting app-server notifications as the current run. When the optional blocked-goal continuation policy is enabled, Chat Runtime resumes a blocked Codex goal through one direct `thread/goal/set` bridge call instead of creating an internal continuation run, so a blocked snapshot cannot self-schedule empty runs. User cancellation pauses an active Codex goal in the provider snapshot before interrupting the current turn so Chat Runtime does not auto-resume from stale active-goal state.
Composer bang commands in Codex runtime are provider-native shell commands, not Chat Runtime local execution. Chat Runtime calls the provider's `executeShellCommand` hook, and the provider resumes/starts the Codex thread, sends `thread/shellCommand`, waits for the matching `commandExecution` item, hydrates native history, and returns bounded result metadata for Cradle's UI snapshots.
Codex conversation rollback is always in place. The provider passes Chat Runtime's requested positive turn count to app-server `thread/rollback` and returns that count; it never substitutes `thread/fork`, provider-session rebinding, or workspace file restoration for rollback.
Side chat remains Cradle-owned and live-only. When Chat Runtime asks for `forkRuntimeSession`, this provider maps the parent Codex thread to app-server `thread/fork` with an ephemeral, turn-excluding child thread, injects a Cradle side-boundary prompt through `thread/inject_items`, and returns the forked provider thread id for the process-local side runtime session. The provider does not create a durable binding for the child; `ProviderRuntimeHostManager` keeps the app-server client alive through the pinned side host lease while the side session is live. Providers that do not expose this hook still receive Chat Runtime's Cradle transcript fallback; Codex's hook only upgrades native fidelity.
Codex app-server stream failures keep user-facing errors short: retry-limit and status failures are summarized through `CodexProviderError.data.details`, while full raw event samples, counts, and app-server error notifications stay in `data.diagnostics` for observability/debugging.
Codex app-server approval callbacks are routed through Chat Runtime pending tool approvals instead of being default-denied. The provider maps command, file-change, permission, `applyPatchApproval`, and `execCommandApproval` server requests into standardized tool chunks with `tool-approval-request`, waits for Chat Runtime's approval promise, then returns the Codex-native response shape such as `accept` / `decline` or `approved` / `denied`.
Codex token usage notifications stay provider-owned at the protocol boundary. Fresh threads opt into raw events so `rawResponse/completed` supplies exact per-response usage and its provider timestamp; the usage projector pairs that fact with the following `thread/tokenUsage/updated` cumulative snapshot. Exact usage becomes the durable event delta, while the cumulative total remains the replay identity and `providerTotal`. Older resumed threads cannot enable raw events through `thread/resume`, so they retain the cumulative notification's `last` usage fallback. Chat Runtime owns the durable `usage_logs` write during run finalization, including cache-read and cache-write input tokens.
Codex UI slots are projected from the app-server capability manifest and declare their intended Cradle surfaces. Slot state stays provider-owned: `goal` reads `thread/goal/get` and can render in composer state plus slash/runtime surfaces; `compact` starts from the provider-native `thread/compact/start` request instead of a raw `turn/start` slash message, keeps lifecycle from `contextCompaction` item `item/started` and `item/completed`, treats deprecated `thread/compacted` only as a compatibility signal, and keeps the usage meter from thread-level `thread/tokenUsage/updated` plus effective config limits such as `model_auto_compact_token_limit`; `status`, `model`, and `reasoning` come from thread start/resume responses, settings/status notifications, config, model list, and model-provider capability reads; `plan` uses `turn/plan/updated` as the canonical session plan snapshot; `toolActivity` summarizes recent `item/started` and `item/completed` lifecycle records; `mcp` merges `mcpServerStatus/list` reads with startup, OAuth, and progress notifications; `diff`, `terminal`, `approvals`, and `alerts` summarize their corresponding app-server notifications without storing full output history, with `alerts` exposed only as runtime-panel snapshot state; `terminal` also reads `thread/backgroundTerminals/list` for live background process rows and maps Chat Runtime terminate requests to `thread/backgroundTerminals/terminate`; `filesystem` and `search` keep bounded notification snapshots from `fs/changed` and fuzzy file search; `usage` reads `account/rateLimits/read`, listens to rate-limit updates, and exposes ChatGPT account usage on slash-command and runtime-panel surfaces with the original primary/secondary window duration and reset timestamps; `skills`, `plugin`, `crew`, and `config` are read from app-server list/read methods at render time. `crew` enumerates Codex-owned subagent threads through paginated app-server `thread/list`, keeps recent collab tool-call lifecycle only as call/activity summary state, and resolves thread metadata so Runtime surfaces can show subagent nickname, role, title, preview, and model provider without depending on a bounded parent-turn window. Cradle stores only the provider snapshot needed to replay those projections across composer state, slash command rows, toolbar option summaries, Right Aside Runtime cards, and stream evidence blocks.

## Files

- `provider.ts`: Codex `ChatRuntime` facade; delegates app-server host leases, stream-turn context preparation, and active-turn tracking to owner modules, then starts/resumes app-server threads, forks ephemeral provider-native side threads, fetches full app-server turn history, reports app-server thread display titles, generates missing titles, injects reconstructed Cradle history and side boundaries, executes user shell commands, exposes provider-native app-server capabilities/invoke/stream hooks, lists and terminates Codex background terminals through app-server thread methods, projects goal invoke results, streams notifications, and wires live steering/cancellation.
- `provider.test.ts`: Regression tests for Codex thread startup, provider title projection, provider config, transcript reconstruction, UI slot state projection, streaming, steering, cancellation, and diagnostics.
- `metadata.ts`: Codex runtime kind, catalog metadata, static capabilities, and app-server capability presentation projection.
- `types.ts`: Codex provider-private client, dependency, and active-turn types shared by package modules.
- `app-server/`: Codex app-server boundary: JSON-RPC client, generated capability manifest, provider-native app-server bridge, interactive server-request method helpers, host lease/resource/fingerprint helpers, ChatGPT auth/account helpers, and model listing.
- `config/`: Runtime config projection: Codex config payloads, sandbox/access policy projection, per-session runtime context, and temporary system-prompt file creation.
- `turn/`: Single-turn orchestration helpers: active-turn registry, stream-turn context preparation, input projection, notification-to-`UIMessageChunk` mapping, stream diagnostics, stream iteration, thread lifecycle/history injection, title generation, shell command execution, and transcript/native-history projection.
- `projection/`: Cradle-owned provider projections: provider snapshot state, context usage, and runtime UI slot state.
- `tools/`: Codex tool identifier and app-server item payload mapper.
- `usage-event-projector.ts`: Projects native per-call usage notifications into deterministic runtime usage events before root-thread filtering.
- `usage-reconciliation.ts`: Replays only Cradle-bound root/descendant rollouts from the dedicated Cradle Codex runtime home into the same usage event identities used by the live path. A binding switches only after its complete rollout is unambiguous; the transaction writes v2 events and removes only that session's legacy summary rows.
- `usage-reconciliation-scheduler.ts`: Runs after the server is available: it prioritizes the newest 200 pending Cradle bindings, then continues in low-priority batches without blocking startup. Binding-owned reconciliation status persists completed and blocked outcomes across restarts.
- `app-server-protocol/`: Generated TypeScript bindings from `codex app-server generate-ts --experimental --out apps/server/src/modules/chat-runtime-providers/codex/app-server-protocol`. Do not edit generated files by hand.

本地资源从同一个 Codex release 同步完整 `codex` 与独立 `codex-app-server`：协议生成固定使用前者的 `codex app-server generate-ts`，Desktop 发行包只携带后者。运行时优先使用独立二进制的 stdio transport，并设置 `--session-source cli`。非 Desktop 环境按 `CRADLE_CODEX_APP_SERVER_PATH`、`PATH` 中的 `codex-app-server`、最后 `codex app-server` 的顺序解析；最后一种 fallback 仍由 Codex 报告为 VSCode session source。

## Regeneration

After regenerating `app-server-protocol/`, run `pnpm --filter @cradle/server generate:codex-app-server-capabilities` to refresh `app-server/capabilities.ts`. The capability generator derives method names and params from the generated protocol files, and keeps only Cradle-owned runtime semantics such as stream-capable methods in the generator.
