From 731f0f384a66a24c919c6474c8b4417cd4debfe6 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Fri, 6 Feb 2026 12:45:27 -0800 Subject: [PATCH] chore(app-server): update AGENTS.md for config + optional collection guidance (#10914) Based on recent app-server PRs --- AGENTS.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 77c48ddba..1506fd188 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -128,15 +128,11 @@ These guidelines apply to app-server protocol work in `codex-rs`, especially: `*Params` for request payloads, `*Response` for responses, and `*Notification` for notifications. - Expose RPC methods as `/` and keep `` singular (for example, `thread/read`, `app/list`). - Always expose fields as camelCase on the wire with `#[serde(rename_all = "camelCase")]` unless a tagged union or explicit compatibility requirement needs a targeted rename. +- Exception: config RPC payloads are expected to use snake_case to mirror config.toml keys (see the config read/write/list APIs in `app-server-protocol/src/protocol/v2.rs`). - Always set `#[ts(export_to = "v2/")]` on v2 request/response/notification types so generated TypeScript lands in the correct namespace. - Never use `#[serde(skip_serializing_if = "Option::is_none")]` for v2 API payload fields. Exception: client->server requests that intentionally have no params may use: `params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>`. -- For client->server JSON-RPC request payloads (`*Params`) only, every optional field must be annotated with `#[ts(optional = nullable)]`. Do not use `#[ts(optional = nullable)]` outside client->server request payloads (`*Params`). -- For client->server JSON-RPC request payloads only, and you want to express a boolean field where omission means `false`, use `#[serde(default, skip_serializing_if = "std::ops::Not::not")] pub field: bool` over `Option`. -- For new list methods, implement cursor pagination by default: - request fields `pub cursor: Option` and `pub limit: Option`, - response fields `pub data: Vec<...>` and `pub next_cursor: Option`. - Keep Rust and TS wire renames aligned. If a field or variant uses `#[serde(rename = "...")]`, add matching `#[ts(rename = "...")]`. - For discriminated unions, use explicit tagging in both serializers: `#[serde(tag = "type", ...)]` and `#[ts(tag = "type", ...)]`. @@ -145,6 +141,15 @@ These guidelines apply to app-server protocol work in `codex-rs`, especially: - For experimental API surface area: use `#[experimental("method/or/field")]`, derive `ExperimentalApi` when field-level gating is needed, and use `inspect_params: true` in `common.rs` when only some fields of a method are experimental. +### Client->server request payloads (`*Params`) + +- Every optional field must be annotated with `#[ts(optional = nullable)]`. Do not use `#[ts(optional = nullable)]` outside client->server request payloads (`*Params`). +- Optional collection fields (for example `Vec`, `HashMap`) must use `Option<...>` + `#[ts(optional = nullable)]`. Do not use `#[serde(default)]` to model optional collections, and do not use `skip_serializing_if` on v2 payload fields. +- When you want omission to mean `false` for boolean fields, use `#[serde(default, skip_serializing_if = "std::ops::Not::not")] pub field: bool` over `Option`. +- For new list methods, implement cursor pagination by default: + request fields `pub cursor: Option` and `pub limit: Option`, + response fields `pub data: Vec<...>` and `pub next_cursor: Option`. + ### Development Workflow - Update docs/examples when API behavior changes (at minimum `app-server/README.md`).