# Schema generation

> `codex app-server generate-ts` and `generate-json-schema`, stable vs `--experimental` output, version pinning to the running binary, and when to regenerate fixtures after protocol changes.

- 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/main.rs`
- `src/models.rs`
- `src/request_serialization.rs`
- `tests/suite/strict_config.rs`

---

---
title: "Schema generation"
description: "`codex app-server generate-ts` and `generate-json-schema`, stable vs `--experimental` output, version pinning to the running binary, and when to regenerate fixtures after protocol changes."
---

The `codex app-server` CLI exposes schema generators that materialize the app-server JSON-RPC protocol from Rust types in `codex-app-server-protocol`. Generated TypeScript and JSON Schema artifacts reflect the exact `codex` binary you invoke—use them for client bindings, validation, and CI fixtures after protocol changes.

## Commands and entry points

Integrators and maintainers use different surfaces for the same underlying generators.

| Surface | Command | Typical use |
| --- | --- | --- |
| Installed CLI | `codex app-server generate-ts` | Ship TypeScript types to an app or extension |
| Installed CLI | `codex app-server generate-json-schema` | Ship JSON Schema for validation or codegen |
| Repo maintainer | `just write-app-server-schema` | Refresh vendored fixtures under `codex-rs/app-server-protocol/schema/` |
| Cargo (direct) | `cargo run -p codex-app-server-protocol --bin write_schema_fixtures` | Same as `just write-app-server-schema` |
| Hidden internal | `codex app-server generate-internal-json-schema` | Internal `RolloutLine` JSON Schema only |

Both public CLI subcommands are marked `[experimental]` in the `codex` CLI help. They delegate to `codex_app_server_protocol::generate_ts_with_options` and `generate_json_with_experimental`.

### `generate-ts`

```bash
codex app-server generate-ts --out DIR
codex app-server generate-ts --out DIR --experimental
codex app-server generate-ts --out DIR --prettier /path/to/prettier
```

<ParamField body="--out" type="path" required>
Output directory. TypeScript files are written here, with v2 types under `DIR/v2/`.
</ParamField>

<ParamField body="--prettier" type="path">
Optional Prettier executable. When set, all generated `.ts` files are formatted in place after generation.
</ParamField>

<ParamField body="--experimental" type="boolean" default="false">
Include experimental RPC methods and fields. Default output is stable-only.
</ParamField>

Generation uses `ts-rs` exports from protocol types (`ClientRequest`, `ServerNotification`, v2 param/response types, and dependencies). Each file is prefixed with `// GENERATED CODE! DO NOT MODIFY BY HAND!`. Root and `v2/` each get an `index.ts` that re-exports types; the root index also exposes `export * as v2 from "./v2"`.

### `generate-json-schema`

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

<ParamField body="--out" type="path" required>
Output directory for per-type JSON Schema files and bundle files.
</ParamField>

<ParamField body="--experimental" type="boolean" default="false">
Include experimental methods and fields in bundles and per-type schemas.
</ParamField>

JSON output is produced with `schemars`. Two bundle files are always written:

| File | Role |
| --- | --- |
| `codex_app_server_protocol.schemas.json` | Full definitions graph (v1 + v2 namespaces) |
| `codex_app_server_protocol.v2.schemas.json` | Flattened v2-focused bundle for consumers that want a smaller surface |

Individual schema files are also emitted under `v1/`, `v2/`, and the output root (envelopes like `ClientRequest`, `JSONRPCMessage`, server-initiated approval types, and so on).

## Stable vs experimental output

Schema generation defaults to the **stable** API surface—the same surface clients see without opting in at runtime. Experimental methods and fields are stripped unless you pass `--experimental`.

```mermaid
flowchart LR
  subgraph sources [Protocol sources]
    RS[Rust types in codex-app-server-protocol]
    EXP["#[experimental(...)] annotations"]
  end
  subgraph gen [Generators]
    TS[ts-rs TypeScript export]
    JS[schemars JSON Schema]
  end
  subgraph filter [Post-processing when stable]
    FM[Filter ClientRequest methods]
    FF[Remove experimental fields]
    FR[Drop experimental-only type files]
  end
  subgraph out [Output]
    STABLE[Stable DIR]
    FULL["--experimental DIR"]
  end
  RS --> TS
  RS --> JS
  EXP --> filter
  TS --> filter
  JS --> filter
  filter --> STABLE
  TS --> FULL
  JS --> FULL
```

Stable filtering removes:

- Experimental client methods from `ClientRequest` unions (driven by `EXPERIMENTAL_CLIENT_METHODS` in protocol `common.rs`).
- Fields registered via `#[experimental("method/field")]` on protocol types.
- Generated type files that exist only for experimental-only RPCs.

<Note>
**Runtime opt-in is separate.** Even with `--experimental` schemas, a client must still send `initialize` with `capabilities.experimentalApi: true` to call experimental methods or set experimental fields. Without opt-in, the server rejects those requests with `<descriptor> requires experimentalApi capability`. See the experimental API page for descriptor examples (`thread/start.mockExperimentalField`, `mock/experimentalMethod`, and similar).
</Note>

### Vendored repo fixtures are stable-only

Committed fixtures live at `codex-rs/app-server-protocol/schema/typescript/` and `schema/json/`. CI compares them to freshly generated **stable** output (`experimental_api: false`). They do not include experimental-only wire methods such as `mock/experimentalMethod` or `thread/turns/list`.

When you change experimental protocol surface area, run `just write-app-server-schema --experimental` locally if you need a full-surface snapshot for review or downstream tooling—but the checked-in fixtures and `schema_fixtures` tests expect the stable tree unless the project explicitly expands that policy.

## Version pinning

Generated artifacts are tied to the **binary that runs the command**, not to a separate schema version string.

From the app-server README: each output is specific to the version of Codex used to run the command, so generated artifacts are guaranteed to match that build.

Practical guidance:

- **Extension or app clients** — Run `codex app-server generate-ts` or `generate-json-schema` with the same `codex` release you target in production, then commit or vendor the output.
- **In-repo development** — Prefer `just write-app-server-schema` so fixtures stay aligned with the workspace protocol crate you are editing.
- **Downstream SDKs** — The Python SDK invokes a pinned installed `codex` binary (`codex app-server generate-json-schema --out …`) so published models match a known runtime.

If you generate from `cargo run` against a local workspace build, you get the workspace protocol definitions. If you generate from a globally installed `codex`, you get whatever protocol that release shipped.

## Output layout

:::files
codex-rs/app-server-protocol/schema/
├── typescript/
│   ├── index.ts              # barrel re-exports + `export * as v2`
│   ├── ClientRequest.ts
│   ├── …                     # shared / v1-adjacent types
│   └── v2/
│       ├── index.ts
│       └── ThreadStartParams.ts, …
└── json/
    ├── codex_app_server_protocol.schemas.json
    ├── codex_app_server_protocol.v2.schemas.json
    ├── ClientRequest.json
    ├── v1/InitializeParams.json
    └── v2/ThreadStartParams.json, …
:::

`write_schema_fixtures` (used by `just write-app-server-schema`) **deletes** existing `typescript/` and `json/` subtrees before regenerating so removed types do not leave stale files.

## Maintainer workflow: when to regenerate

Regenerate fixtures whenever app-server **v2 protocol shapes** change—new RPCs, renamed fields, notification variants, or experimental annotations that affect stable output.

<Steps>
<Step title="Change protocol types">
Edit request/response/notification types in `codex-app-server-protocol` (for example `src/protocol/v2/`, `src/protocol/common.rs`). Follow v2 API conventions: camelCase on the wire, `#[ts(export_to = "v2/")]` on v2 types, and `#[experimental("resource/method")]` or field-level gates where needed.
</Step>

<Step title="Regenerate fixtures">
From the repo root:

```bash
just write-app-server-schema
```

If your change only affects experimental methods or fields (and you need a local full snapshot):

```bash
just write-app-server-schema --experimental
```

Optional Prettier for TypeScript fixtures:

```bash
cargo run -p codex-app-server-protocol --bin write_schema_fixtures -- -p /path/to/prettier
```
</Step>

<Step title="Verify">
```bash
just test -p codex-app-server-protocol
```

Fixture tests fail with a diff and instruct you to run `just write-app-server-schema` when vendored files drift from generated output.
</Step>

<Step title="Update app-server docs when behavior changes">
If RPC behavior or examples in `app-server/README.md` change, update that README in the same change. Regenerate schema fixtures in the same PR when API shapes change.
</Step>
</Steps>

### What triggers regeneration

| Change | Regenerate stable fixtures? | Notes |
| --- | --- | --- |
| New or renamed v2 `*Params` / `*Response` / `*Notification` | Yes | TS + JSON fixtures and bundles |
| New stable client method on `ClientRequest` | Yes | Updates unions and per-type files |
| New `#[experimental(...)]` method only | Stable fixtures unchanged | Use `--experimental` locally if you need full schema |
| Experimental field on otherwise stable method | Yes if field appears in stable schema paths | Stable generation strips the field; shape of surrounding types may still change |
| Server-only notification excluded from JSON | Maybe | Some notifications are excluded from JSON export (for example `rawResponseItem/completed`) by design |

Also run `just write-app-server-schema --experimental` when experimental API fixtures are explicitly part of your workflow (per repository `AGENTS.md` app-server guidance).

### Experimental gating checklist (maintainers)

When adding experimental API surface:

1. Annotate fields with `#[experimental("thread/start.myField")]` on protocol types and derive `ExperimentalApi` on params types.
2. For partial experimental fields on a stable method, use `inspect_params: true` on the method in `common.rs`; for fully experimental methods, annotate the request variant.
3. Regenerate fixtures (`just write-app-server-schema`, plus `--experimental` when needed).
4. Run `just test -p codex-app-server-protocol`.

## Consumer workflow (outside the repo)

For TypeScript or JSON Schema in your own project—not the vendored `schema/` tree:

```bash
# Match your production Codex version
codex app-server generate-ts --out ./types/codex-app-server
codex app-server generate-json-schema --out ./schemas/codex-app-server
```

Add `--experimental` only if your client sets `capabilities.experimentalApi: true` at `initialize` and you intentionally depend on unstable API.

<Warning>
Do not hand-edit generated files. Regenerate from the protocol sources. The standard TypeScript banner marks generated output; fixture tests strip it when comparing vendored trees.
</Warning>

## Internal JSON Schema

`codex app-server generate-internal-json-schema` is a hidden CLI subcommand that writes internal artifacts (for example `RolloutLine`) via `generate_internal_json_schema`. It is not part of the public app-server RPC surface documented for integrators.

## Relationship to the running server

Schema generation is **offline**. It does not require a listening app-server process (`--listen off` is irrelevant). The live server enforces experimental gating and notification filtering at runtime in `message_processor` and transport layers; generated stable schemas describe what clients can rely on without `experimentalApi`, not what the server will accept if experimental fields are sent without opt-in.

## Related pages

<CardGroup>
<Card title="Experimental API" href="/experimental-api">
Runtime `experimentalApi` capability, rejection messages, and maintainer gating patterns aligned with schema filtering.
</Card>
<Card title="Protocol and transport" href="/protocol-and-transport">
JSON-RPC wire format and transports the generated types describe.
</Card>
<Card title="RPC methods reference" href="/rpc-methods">
Catalog of v2 `<resource>/<method>` RPCs and stable vs experimental markers.
</Card>
<Card title="Development and testing" href="/development-and-testing">
Integration tests and `just test -p codex-app-server` expectations alongside protocol crate tests.
</Card>
</CardGroup>
