Files
promptfoo--promptfoo/site/docs/providers/openai-codex-app-server.md
T
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

389 lines
26 KiB
Markdown

---
sidebar_position: 42
title: OpenAI Codex App Server
description: Evaluate Codex app-server with streamed agent events, approvals, sandboxing controls, and thread metadata through the Promptfoo JSON-RPC provider guide.
---
# OpenAI Codex App Server
This provider starts `codex app-server` as a local child process and drives the Codex app-server JSON-RPC protocol from promptfoo. Use it when you need to eval the rich client surface of Codex: streamed agent items, approvals, skills, plugins, app connector events, command/file trajectories, and thread lifecycle metadata.
For CI and straightforward automation, prefer the [OpenAI Codex SDK provider](./openai-codex-sdk.md). The app-server protocol is experimental, broader than the SDK, and designed for rich product integrations.
## Provider IDs
```yaml
providers:
- openai:codex-app-server
- openai:codex-app-server:gpt-5.6-sol
- openai:codex-desktop
- openai:codex-desktop:gpt-5.6-sol
```
`openai:codex-desktop` is an alias for the same app-server protocol. Promptfoo starts its own `codex app-server` process; it does not attach to an already-running Codex Desktop app process.
## Codex SDK vs App Server vs Desktop App
Keep this provider separate from the Codex SDK provider. They share Codex concepts, but they expose different runtime contracts.
| Surface | Best for | Runtime | Promptfoo provider |
| ----------------- | --------------------------------------------- | ---------------------------------------------------- | -------------------------------------------------- |
| Codex SDK | CI, automation, simple agentic coding evals | `@openai/codex-sdk` library | [`openai:codex-sdk`](./openai-codex-sdk.md) |
| Codex app-server | Rich-client protocol behavior and event evals | Local `codex app-server` child process over JSON-RPC | `openai:codex-app-server` / `openai:codex-desktop` |
| Codex Desktop app | Interactive human work in the desktop product | Native app process and UI | Not attached directly |
Use this provider when the thing being tested depends on app-server-only behavior such as approval request payloads, streamed item notifications, app connector events, plugin/skill metadata, or thread lifecycle operations. Use the SDK provider when you only need final Codex output, thread reuse, structured output, and traced shell/MCP/search/file steps.
## What Promptfoo Can and Can't Evaluate
| Eval surface | Supported? | Notes |
| ----------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Final assistant text | Yes | Returned in `response.output` as a string. |
| Text, image, local image, skill, mention inputs | Yes | Pass plain text or a JSON array of supported app-server input items. |
| JSON schema output | Yes | Pass `output_schema`; assert with `is-json` or parse `output` yourself. |
| Token usage and estimated cost | Yes | Token usage is read from `thread/tokenUsage/updated`; GPT-5.6 cost stays undefined because the protocol does not report cache-write tokens. |
| Thread IDs and turn IDs | Yes | Available under `sessionId` and `metadata.codexAppServer`. |
| Approval, permission, MCP, and tool requests | Yes | `server_request_policy` gives deterministic responses for non-interactive evals. |
| Streamed item metadata | Yes | Command, file, MCP, dynamic tool, web search, reasoning, and agent-message items are normalized. |
| Deep app-server tracing | Yes | Enable `deep_tracing` to inject OTEL env vars into a fresh app-server process per row. |
| Live partial output in assertions | No | Promptfoo receives the final provider response after the turn completes. |
| Attaching to an existing Desktop app | No | Promptfoo owns a separate app-server child process. |
| WebSocket transport | No | The provider uses stdio; app-server WebSocket mode remains experimental upstream. |
When `service_tier: fast` is used, Promptfoo still reports only the standard model-rate estimate from the returned token ledger. The app-server payload does not expose enough billing metadata to convert Codex fast-mode credit consumption into an exact spend figure.
## Setup
Install the Codex CLI and sign in:
```bash
npm i -g @openai/codex
codex
```
You can also authenticate with an API key:
```bash
export OPENAI_API_KEY=your_api_key_here
```
Promptfoo also accepts `CODEX_API_KEY` or `config.apiKey`. For reproducible evals, prefer API-key-backed runs or set `cli_env.CODEX_HOME` to a fixture home directory that already contains the intended Codex login state.
### Run on Amazon Bedrock
Set `model_provider: amazon-bedrock` with a Bedrock model id to run OpenAI's frontier models on [Amazon Bedrock](/docs/providers/aws-bedrock/#openai-models). Provide AWS credentials and a Region to the Codex CLI through `cli_env`:
```yaml title="promptfooconfig.yaml"
providers:
- id: openai:codex-app-server
config:
model: openai.gpt-5.5 # Bedrock model id (note the openai. prefix)
model_provider: amazon-bedrock
sandbox_mode: read-only
approval_policy: never
cli_env:
AWS_REGION: us-east-2
AWS_ACCESS_KEY_ID: '{{env.AWS_ACCESS_KEY_ID}}'
AWS_SECRET_ACCESS_KEY: '{{env.AWS_SECRET_ACCESS_KEY}}'
```
The same notes as the [Codex SDK Bedrock setup](/docs/providers/openai-codex-sdk/#option-3-run-on-amazon-bedrock) apply: use the `openai.`-prefixed model ids, request model access in a supported Region (`us-east-2` for GPT-5.5), forward `AWS_SESSION_TOKEN` as well when using temporary/SSO credentials, and remember that credentials in `cli_env` are exposed to the agent's shell environment.
## Basic Usage
```yaml title="promptfooconfig.yaml"
providers:
- id: openai:codex-app-server:gpt-5.5
config:
sandbox_mode: read-only
approval_policy: never
prompts:
- 'Review this repository and summarize the highest-risk code paths.'
```
The provider returns Codex's final assistant text as `output`. It also records thread ids, turn ids, item counts, command/file/tool metadata, approval decisions, and token usage under `metadata.codexAppServer`.
For downstream coding-agent checks, `raw` also includes SDK-compatible `items` and `usage` fields alongside the protocol-shaped thread and turn payloads. That keeps trajectory-style assertions aligned between `openai:codex-app-server` and `openai:codex-sdk` without losing the richer app-server metadata.
## Safety Defaults
The app-server protocol can expose shell, filesystem, config, plugin, MCP, and app connector surfaces. Promptfoo defaults to deterministic eval behavior:
| Option | Default |
| --------------------- | ------------- |
| `sandbox_mode` | `read-only` |
| `approval_policy` | `never` |
| `ephemeral` | `true` |
| `thread_cleanup` | `unsubscribe` |
| `reuse_server` | `true` |
| `inherit_process_env` | `false` |
Approval requests are answered without blocking:
| Request type | Default response |
| --------------------------------------- | ---------------------- |
| `item/commandExecution/requestApproval` | `decline` |
| `item/fileChange/requestApproval` | `decline` |
| `item/permissions/requestApproval` | empty grant |
| `item/tool/requestUserInput` | empty answers |
| `mcpServer/elicitation/request` | `decline` |
| `item/tool/call` | failed static response |
Use `accept`, `acceptForSession`, permission grants, or MCP elicitation acceptance only in isolated workspaces where side effects are acceptable.
## Configuration
The provider validates top-level provider config strictly. Prompt-level config is parsed more leniently because promptfoo merges generic test options into `prompt.config`; unrelated keys are ignored there, while invalid values for known Codex fields still return a row-level provider error.
| Parameter | Type | Description | Default |
| -------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `apiKey` | string | OpenAI API key. Optional when Codex is already signed in. | Environment variable |
| `base_url` | string | Custom OpenAI-compatible base URL. Also passed as `OPENAI_BASE_URL` and `OPENAI_API_BASE_URL`. | None |
| `working_dir` | string | Directory Codex operates in. Relative values resolve from the directory containing the config file. | Current process dir |
| `additional_directories` | string[] | Additional directories added to workspace-write sandbox roots. | None |
| `skip_git_repo_check` | boolean | Skip the default Git repository safety check. | `false` |
| `codex_path_override` | string | Path to a specific `codex` binary. | `codex` |
| `model` | string | Model id, such as `gpt-5.6-sol`. Can also be set in the provider id. | Codex default |
| `model_provider` | string | App-server model provider override for `thread/start` and `thread/resume`. | None |
| `service_tier` | string | `fast` or `flex`. | App-server default |
| `sandbox_mode` | string | `read-only`, `workspace-write`, or `danger-full-access`. | `read-only` |
| `sandbox_policy` | object | Raw app-server sandbox policy override for `turn/start`. | Generated from mode |
| `network_access_enabled` | boolean | Adds network access to generated sandbox policies. | `false` |
| `approval_policy` | string/object | `never`, `on-request`, `on-failure`, `untrusted`, or granular approval policy object. `on-failure` is accepted for compatibility but deprecated by Codex. | `never` |
| `approvals_reviewer` | string | `user` or `auto_review`. `guardian_subagent` is still accepted as a legacy alias. | App-server default |
| `model_reasoning_effort` | string | `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, or `ultra`. GPT-5.6 support is catalog-driven; `ultra` enables proactive subagent use. | App-server default |
| `reasoning_summary` | string | `auto`, `concise`, `detailed`, or `none`. | App-server default |
| `personality` | string | `none`, `friendly`, or `pragmatic`. | App-server default |
| `base_instructions` | string | Base instructions passed to `thread/start` and `thread/resume`. | None |
| `developer_instructions` | string | Developer instructions passed to `thread/start` and `thread/resume`. | None |
| `collaboration_mode` | object | Experimental collaboration mode passed to `turn/start`. | None |
| `output_schema` | object | JSON Schema passed to `turn/start`. | None |
| `thread_id` | string | Resume an existing Codex thread. | None |
| `persist_threads` | boolean | Reuse threads across rows with the same prompt template and config. | `false` |
| `thread_pool_size` | number | Max cached thread count when `persist_threads` is enabled. | `1` |
| `thread_cleanup` | string | `unsubscribe`, `archive`, or `none` for non-persistent threads. Resumed `thread_id` rows unsubscribe by default; `archive` is ignored for user-supplied thread IDs. | `unsubscribe` |
| `ephemeral` | boolean | Create ephemeral threads by default. | `true` |
| `persist_extended_history` | boolean | Preserve extended app-server thread history when starting or resuming threads. | `false` |
| `experimental_raw_events` | boolean | Ask app-server to emit raw Responses API items. | `false` |
| `experimental_api` | boolean | Opt into experimental app-server protocol fields during `initialize`. | `true` |
| `include_raw_events` | boolean | Include protocol notifications in `raw`. | `false` |
| `cli_config` | object | Extra `codex app-server -c key=value` config overrides. | None |
| `cli_env` | object | Extra environment variables for the app-server process. | Minimal shell env |
| `inherit_process_env` | boolean | Merge the full Node.js environment into the app-server process. | `false` |
| `reuse_server` | boolean | Reuse the app-server process across rows. Disabled for `deep_tracing`. | `true` |
| `deep_tracing` | boolean | Inject OTEL env vars into a fresh app-server process per call. | `false` |
| `request_timeout_ms` | number | JSON-RPC request timeout. | `30000` |
| `startup_timeout_ms` | number | `initialize` timeout. | `30000` |
| `turn_timeout_ms` | number | Overall turn timeout. | None |
| `server_request_policy` | object | Deterministic responses for approvals, user input, MCP elicitations, and dynamic tools. | Safe declines |
:::note GPT-5.6 requires Codex 0.144.0 or later
The app-server provider starts the `codex` binary on your PATH, or `codex_path_override`. Use version 0.144.0 or later so its model catalog recognizes GPT-5.6 and the corresponding reasoning levels. Confirm the effective reasoning with `deep_tracing` when using a custom binary.
:::
### Granular Approval Policy
```yaml
providers:
- id: openai:codex-app-server:gpt-5.5
config:
approval_policy:
granular:
sandbox_approval: true
rules: true
skill_approval: false
request_permissions: true
mcp_elicitations: true
```
### Collaboration Mode
```yaml
providers:
- id: openai:codex-app-server:gpt-5.5
config:
collaboration_mode:
mode: plan
settings:
model: gpt-5.5
reasoning_effort: none
developer_instructions: null
```
`collaboration_mode` is experimental and is sent on `turn/start`. App-server may let the selected mode override model, reasoning effort, or developer instructions for the turn.
### Goals and Subagents
Codex gates optional capabilities behind [feature flags](https://developers.openai.com/codex/config-basic#feature-flags). Set them under `cli_config.features`, which Promptfoo forwards as `codex app-server -c features.<name>=...` overrides.
```yaml
providers:
- id: openai:codex-app-server:gpt-5.5
config:
cli_config:
features:
goals: true
multi_agent: true
```
`features.goals` enables Codex's experimental goals capability; its lifecycle stage and default shift between Codex versions, so run `codex features list` to confirm them for the build you target. `features.multi_agent` toggles subagent collaboration tools; it is stable and enabled by default in current Codex releases, so set it explicitly only to pin that default or disable it with `false`.
## Server Request Policy
Configure deterministic responses when you intentionally want app-server approval flows:
```yaml
providers:
- id: openai:codex-app-server:gpt-5.5
config:
sandbox_mode: workspace-write
approval_policy: on-request
server_request_policy:
command_execution: decline
file_change: decline
user_input:
severity: high
mcp_elicitation:
action: accept
content:
severity: low
_meta:
source: promptfoo
permissions:
scope: session
strict_auto_review: true
permissions:
network:
enabled: true
fileSystem:
read:
- /tmp/fixture
write: null
dynamic_tools:
classify:
success: true
text: '{"label":"safe"}'
```
For command execution approvals, `command_execution` may also be an app-server decision object:
```yaml
server_request_policy:
command_execution:
applyNetworkPolicyAmendment:
network_policy_amendment:
host: registry.npmjs.org
action: allow
```
Legacy `execCommandApproval` and `applyPatchApproval` callbacks are also handled for older app-server versions. Advanced command decision objects are only supported on the modern `item/commandExecution/requestApproval` flow.
`permissions.strict_auto_review` maps to the app-server `strictAutoReview` response field and asks Codex to review every subsequent command in the current turn before normal sandboxed execution.
## Structured Output
```yaml title="promptfooconfig.yaml"
providers:
- id: openai:codex-app-server:gpt-5.5
config:
sandbox_mode: read-only
output_schema:
type: object
properties:
summary:
type: string
risks:
type: array
items:
type: string
required: [summary, risks]
additionalProperties: false
prompts:
- 'Return a JSON review summary for this repo.'
tests:
- assert:
- type: is-json
```
The final app-server response is returned as a string. Use `is-json` or a JavaScript assertion to parse it.
## Prompt Inputs
Plain text prompts work as usual. To include images, skills, or mentions, pass a JSON array:
```json
[
{ "type": "text", "text": "$skill-creator Write a test plan for this provider." },
{ "type": "image", "url": "https://example.com/screenshot.png" },
{ "type": "local_image", "path": "/Users/me/screenshots/failure.png" },
{
"type": "skill",
"name": "skill-creator",
"path": "/Users/me/.codex/skills/skill-creator/SKILL.md"
},
{
"type": "mention",
"name": "workspace",
"path": "app://connector/resource"
}
]
```
Supported input item types are `text`, `image`, `local_image`, `localImage`, `skill`, and `mention`.
## Metadata
The provider records app-server details for assertions and debugging:
```js
providerResponse.metadata.codexAppServer.threadId;
providerResponse.metadata.codexAppServer.turnId;
providerResponse.metadata.codexAppServer.itemCounts;
providerResponse.metadata.codexAppServer.items;
providerResponse.metadata.codexAppServer.serverRequests;
```
Command output, tool arguments, and approval metadata are sanitized before they are placed in metadata or tracing attributes.
## Tracing
Promptfoo wraps each provider call in a GenAI span. The app-server provider also creates item-level spans for completed command, file, MCP, dynamic tool, reasoning, search, and agent-message items, plus a `gen_ai.turn N` marker span around each Codex `turn/started` -> `turn/completed` notification. Every item span is tagged with `gen_ai.turn.index` so callers can correlate items back to the protocol turn that emitted them.
To verify that an app-server protocol turn was traced, count the turn markers:
```yaml
assert:
- type: trace-span-count
value:
pattern: 'gen_ai.turn *'
min: 1
max: 1
```
An app-server `turn/start` request covers one agent turn, including any internal model
generations and tool execution. App-server notifications do not expose those internal
model-generation boundaries, so these markers cannot distinguish batched from
sequential tool calls inside a turn.
Enable deeper app-server tracing by setting `deep_tracing: true` with Promptfoo's OpenTelemetry tracing enabled. Deep tracing starts a fresh app-server process for each row so the child process can receive the active trace context. Reusable app-server process and persistent thread pooling are disabled in this mode; explicit `thread_id` resumes are still serialized so parallel rows do not overlap turns on the same Codex thread.
## Local Verification
Run from the repository root:
```bash
npm run local -- eval -c examples/openai-codex-app-server/promptfooconfig.yaml --no-cache
```
Use `--env-file .env` if your API key is stored there.
To validate the provider against your installed Codex CLI schema:
```bash
codex app-server generate-ts --out /tmp/codex-app-server-schema/ts
codex app-server generate-json-schema --out /tmp/codex-app-server-schema/json
```