From 1997a2938334abd7549b4bcc9cd12ecff630e125 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 24 Jul 2026 17:12:01 +0000 Subject: [PATCH 1/4] spec: expose precise setup-command operations in docs OpenAPI (REMOTE-1063) Docs-repo spec for REMOTE-1063 (multi-repo: warp, warp-server, docs). Regenerate developers/agent-api-openapi.yaml via the sync-openapi-spec tooling so it mirrors the new precise setup-command operations the warp-server canonical public API commits, with zero-based index semantics, append-at-length insert, index-based duplicate addressing, and a REST-only public contract. Includes sync-policy and cross-repo alignment criteria. Co-Authored-By: Warp --- .../REMOTE-1063-docs-setup-command-openapi.md | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 .agents/specs/REMOTE-1063-docs-setup-command-openapi.md diff --git a/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md b/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md new file mode 100644 index 00000000..551bdf42 --- /dev/null +++ b/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md @@ -0,0 +1,205 @@ +*Spec: Docs OpenAPI — expose precise setup-command operations (REMOTE-1063, docs repo)* + +== PRODUCT == +*Summary:* After the warp-server canonical public API adds precise setup-command +update operations for cloud environments, the generated docs OpenAPI at +`developers/agent-api-openapi.yaml` must mirror those operations — paths, +parameters, request/response shapes, and index semantics — so the Scalar API +reference at `docs.warp.dev/api` and the raw `docs.warp.dev/openapi.json` +document them. This spec covers *only* the docs repo's generated OpenAPI file +and the sync mechanics that keep it aligned to the warp-server canonical +contract; the warp-server spec owns the canonical contract shape and is the +source of truth. + +*Key design choices:* +1. **Mirror, don't hand-author.** `developers/agent-api-openapi.yaml` is a + generated curated subset of `warp-server/public_api/openapi.yaml` + (`sync-openapi-spec` skill → `scripts/sync_openapi.py`). The docs change is + produced by running the existing sync tool against an updated canonical + source, not by editing the docs YAML by hand. This keeps the two specs + structurally identical for the included surface. +2. **REST-only public contract.** The existing public environment surface is + REST (`GET /agent/environments`); the OpenAPI spec and the Scalar reference + are REST. The new precise setup-command operations are REST endpoints + committed to `warp-server/public_api/openapi.yaml` and flow through the sync + to docs. GraphQL remains internal and is not part of the documented public + contract (see Design alternatives). +3. **Index semantics live in the contract, not just the CLI.** The documented + operations carry zero-based index parameters with explicit append-at-length + and out-of-range rules, so the CLI, server, and docs all agree on the same + shape (the cross-repo alignment requirement). + +*Behavior* (numbered, testable invariants from the docs consumer's view): +1. The Scalar reference at `docs.warp.dev/api` lists the new precise + setup-command operation(s) for cloud environments alongside the existing + `GET /agent/environments` operation, with HTTP method, path, parameters, + request body, and response codes rendered. +2. The documented request body lets a caller express insert-at-index, + edit-by-index, remove-by-index, clear, and clear-and-rebuild (replace) of an + environment's `setup_commands` list without resending the unchanged full + list for the index-based ops. +3. Index parameters are documented as **zero-based**; an insert at + `index == length` is documented as append (preserves order); any index + outside `[0, length]` (insert) or `[0, length)` (edit/remove) is documented + as a `400` error. +4. Duplicate setup commands (same text, different positions) are addressable by + index in the documented operations; the docs do not require command text to + be unique. +5. The existing `GET /agent/environments` operation and the + `CloudEnvironmentConfig` schema (including its `setup_commands` array field) + remain present and unchanged in the regenerated docs file — the change is + purely additive for the public surface. +6. `docs.warp.dev/openapi.json` (served from the same source via + `src/pages/api.astro`) reflects the new operations after deploy. + +== TECH == +*Context:* how the docs OpenAPI surface works today (commit-pinned): +- `developers/agent-api-openapi.yaml:1155` (@ `aca5ecce`) — the only environment + path today: `GET /agent/environments` (`operationId: listEnvironments`, tag + `agent`, `bearerAuth`, `sort_by` query param). Mirrors the canonical. +- `developers/agent-api-openapi.yaml:2908` — `CloudEnvironmentConfig` schema; + `setup_commands` at `:2927` is `array of string` ("Shell commands to run + during environment setup"). No setup-command CRUD operations exist. +- `src/pages/api.astro:16` reads `developers/agent-api-openapi.yaml` and feeds + Scalar; `:213` links the raw `openapi.json`. So one YAML file powers both the + rendered reference and the JSON download. +- Canonical source of truth: `warp-server/public_api/openapi.yaml:3980` + (`GET /agent/environments`) and `:7774` (`CloudEnvironmentConfig`, + `setup_commands` at `:7793`) @ `21fbda3f`. The server REST handler + `warp-server/router/handlers/public_api/agent_environments.go:48` + (`RegisterAgentEnvironmentRoutes`) registers only the GET route today — no + update/create/delete/setup-command handlers exist yet. GraphQL + `warp-server/graphql/v2/cloud_environment.graphqls:49` exposes + `setupCommands: [String!]` but is internal, not the documented public + contract. +- Sync tool: `docs/.agents/skills/sync-openapi-spec/scripts/sync_openapi.py` + (`EXCLUDED_TAGS` at `:44` = `{memory_stores, harness-support}`; + `EXCLUDED_PATHS` at `:48`; `KNOWN_TAGS` at `:343` = `{agent, schedules}` ∪ + excluded). Policy doc: `references/sync-policy.md`. Direction is + warp-server → docs; apply mode validates every `$ref` resolves before + writing (exit 3 on failure). + +*Design alternatives* (per decision point with more than one reasonable +approach): +- **REST vs GraphQL vs both for the public contract** — options: + (a) *REST only* (chosen): matches the existing `GET /agent/environments` + public surface, the OpenAPI/Scalar reference, and `docs.warp.dev/api`. The + server already wraps a GraphQL resolver for listing but exposes REST + publicly; adding REST precise-update ops keeps the documented contract + consistent and reviewable in one spec. (b) *GraphQL only*: would require a + new public GraphQL surface and a different docs rendering path; Scalar + renders OpenAPI/REST, so this would not flow through the existing sync. (c) + *Both*: doubles the documented surface and the cross-repo alignment cost for + no user-facing benefit today. → REST only. +- **Where index semantics live** — options: + (a) *In the contract* (chosen): the documented operations carry index + parameters and explicit bounds, so CLI/server/docs agree on one shape (the + brief's cross-repo requirement). (b) *Contract is full-replacement only + (`PUT` the whole `setup_commands` list), CLI computes the final list*: simpler + contract but moves index semantics out of the shared contract, so the three + specs cannot "agree on the same index semantics" — rejected for this + multi-repo task. → contract carries index semantics. +- **Endpoint shape** (the warp-server spec is the final source of truth; this + is the proposed shape the docs file will mirror): + (a) *Sub-resource* (proposed): `PATCH /agent/environments/{environmentId}/setup-commands` + with an ordered `operations` array body (insert/edit/remove/append/clear/ + replace). Focused, RESTful, and additive to the existing plural path. + (b) *Whole-config PATCH*: `PATCH /agent/environments/{environmentId}` with a + setup-commands patch nested under config. Broader blast radius (implies a + general environment update contract). (c) *Separate verbs per op* + (POST .../insert, POST .../edit): more endpoints, more schemas, harder to + keep ordered. → sub-resource with an operations array (proposed); the docs + criteria below are written against *whatever exact path/shape the warp-server + spec commits*, so the docs spec is not brittle to that choice. +- **New tag or reuse `agent`** — options: + (a) *Reuse the `agent` tag* (proposed): the new operations flow through the + sync automatically (`agent` ∈ `KNOWN_TAGS`, path not in `EXCLUDED_PATHS`) — + no policy change needed. (b) *Introduce an `environments` tag*: would require + extending `KNOWN_TAGS`/`EXCLUDED_TAGS` and `references/sync-policy.md` or the + diff flags it with `!` for triage. → reuse `agent` unless the warp-server + spec introduces a new tag, in which case the sync policy MUST be updated + (criterion 2). + +*Proposed changes* (docs repo): +1. **Regenerate** `developers/agent-api-openapi.yaml` by running + `scripts/sync_openapi.py --mode apply --source --target developers/agent-api-openapi.yaml` once + the warp-server canonical lands the new setup-command operations. The + regenerated file adds the new path(s), operation(s), request/response + schemas (e.g. `UpdateSetupCommandsRequest` and any per-operation schemas), + and the `Error`-referenced error responses — mirroring the canonical + verbatim for the included surface. +2. **Sync policy** (only if needed): if the warp-server spec introduces a new + tag (not `agent`/`schedules`) or a path that should stay hidden, update + `EXCLUDED_TAGS`/`EXCLUDED_PATHS` in `scripts/sync_openapi.py` and record the + rationale in `references/sync-policy.md`. If the new ops reuse the `agent` + tag and are public, no policy change is required. +3. **No hand-edits** to the generated YAML outside the sync tool's output; the + file remains a generated artifact so future syncs are clean. +4. **Sequencing note (for the foreman/implementation):** the docs sync + `--mode apply` step requires a `warp-server/public_api/openapi.yaml` that + already contains the new operations. The docs implementation child therefore + runs the sync against the warp-server branch/commit that lands the contract + (or waits until that contract is merged). The docs PR may land in two phases: + (i) this spec file (+ any sync-policy update), (ii) the regenerated YAML + once the canonical source is available. Both phases land on this same PR + branch. + +*Open questions resolved* (each ambiguity and how it was settled; the +warp-server spec is the source of truth for the exact contract, these are the +docs-side assumptions that keep all three specs aligned — surfaced in the +approval request for ben to confirm): +- **Index base: zero-based.** Settled from the JSON array model + (`setup_commands: array of string`) and OpenAPI/JSON conventions; avoids + off-by-one translation between the API and the underlying model. The CLI may + display one-based indexes in help text, but the *contract* is zero-based and + all three specs agree on zero-based. *Assumption to confirm:* ben may prefer + one-based for CLI ergonomics — if so, the CLI maps one-based→zero-based at the + edge and the contract stays zero-based. +- **Insert permits append-at-length: yes.** `insert` at `index == length` + appends and preserves order; `index > length` or `< 0` is a `400`. Settled as + standard list-insert semantics; supports `--insert-setup-command ` + as an append. +- **Duplicate-command addressing: by index.** Setup commands may legitimately + repeat, so the precise ops address by index, not by text. The existing + text-based `--remove-setup-command` CLI flag is preserved for compatibility + and is translated client-side (find first text match → its index → + `remove` op); the public contract is index-based only. Settled from the + ticket's "edit one setup command by index without resending" requirement. +- **Public contract: REST.** Settled from the existing REST public surface and + the Scalar/OpenAPI docs pipeline; GraphQL stays internal. See Design + alternatives. +- **Exact endpoint path/shape:** proposed `PATCH + /agent/environments/{environmentId}/setup-commands` with an ordered + operations array (insert/edit/remove/append/clear/replace). The docs file + mirrors whatever the warp-server spec ultimately commits; the validation + criteria are written against the canonical, not a hardcoded path, so this + assumption does not block the docs spec. + +*Risks / blast radius:* +- The docs file is generated; a hand-edit would be overwritten on the next + sync. Mitigation: only change it via `sync_openapi.py --mode apply`. +- If the warp-server contract introduces a new tag/path, the sync diff flags it + `!` and the docs PR must update the sync policy or the build/sync is blocked. + Mitigation: criterion 2 enforces zero `!` flags before merge. +- Cross-repo drift: if the docs file diverges from the canonical (e.g. stale + schema names or index semantics), the Scalar reference would document a + contract the server doesn't implement. Mitigation: criterion 10 enforces + `--mode diff` shows the docs file equals the curated canonical subset. +- The docs sync depends on the warp-server contract landing first; the docs PR + cannot be merged with a regenerated YAML until that source exists + (criterion 1 runs against the updated canonical). + +*Validation & verification criteria* (must ALL pass before merge of the docs +PR; criteria 1–4 run against a `warp-server/public_api/openapi.yaml` that +already contains the new setup-command operations): +1. `python3 .agents/skills/sync-openapi-spec/scripts/sync_openapi.py --mode apply --source ../warp-server/public_api/openapi.yaml --target developers/agent-api-openapi.yaml` regenerates the docs file containing the new setup-command operation(s) and exits 0 with "All $refs resolve in the regenerated spec." (every `$ref` resolves). - verifies behavior #1, #2. +2. `python3 .agents/skills/sync-openapi-spec/scripts/sync_openapi.py --mode diff --source ../warp-server/public_api/openapi.yaml --target developers/agent-api-openapi.yaml` reports **no `!` unclassified items**: the new operations either reuse the `agent` tag (no policy change) OR `EXCLUDED_TAGS`/`KNOWN_TAGS` in `scripts/sync_openapi.py` and `references/sync-policy.md` have been updated with a rationale for any new tag/path. - verifies the sync policy stays consistent. +3. The regenerated `developers/agent-api-openapi.yaml` contains the new precise setup-command operation(s) the warp-server canonical commits, with: a path parameter identifying the environment, `bearerAuth` security, a request body schema expressing insert-at-index / edit-by-index / remove-by-index / clear / clear-and-rebuild (replace) operations, and `200`/`400`/`401`/`403`/`404`/`500` responses (error responses `$ref` `#/components/schemas/Error`). - verifies behavior #1, #2; checked by grepping the regenerated YAML for the new operationId/path and schema names committed by the warp-server spec. +4. The regenerated docs file documents the **zero-based** index semantics (insert-at-length appends; out-of-range is `400`) in the operation/schema `description` fields, matching the warp-server canonical verbatim. - verifies behavior #3; checked by reading the regenerated schema descriptions and confirming they equal the canonical's. +5. `npm run build` succeeds (Astro picks up the regenerated YAML and Scalar parses it at build time). - verifies behavior #1, #6; the docs repo's documented build check. +6. (Recommended when schemas changed) `npx @redocly/cli lint developers/agent-api-openapi.yaml` passes with no errors. - belt-and-braces OpenAPI lint. +7. No regressions to the existing public surface: the regenerated docs file still contains `GET /agent/environments` (`operationId: listEnvironments`) and the `CloudEnvironmentConfig` schema with its `setup_commands` array field, unchanged; `--mode diff` shows the new operations as **additions** only (no removals of existing public paths/schemas). - verifies behavior #5. +8. The docs PR records the warp-server source commit SHA used for the sync and the count of paths/schemas added/modified (per the sync-openapi-spec skill's reporting step). - traceability of the generated artifact to its source. +9. Cross-repo alignment: the docs operation path, path parameter name, request/response schema `$ref` names, HTTP status codes, and index semantics exactly match `warp-server/public_api/openapi.yaml` (same names, zero-based, append-at-length rule, same error codes). - verifies the three specs agree on one contract; checked by `--mode diff` reporting the docs file equals the curated subset of the canonical (no docs-only divergence). +10. After deploy, `docs.warp.dev/api` (Scalar) and `docs.warp.dev/openapi.json` expose the new operations. For the PR itself, verify via the `npm run build` output that the new path is present in the built spec; live deploy verification is post-merge. - verifies behavior #1, #6. From 1f00c3e00ee6ef3fcd2437edfc753920c4e1e352 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 24 Jul 2026 17:17:24 +0000 Subject: [PATCH 2/4] spec: align docs OpenAPI spec to warp-server's binding multi-verb setup-commands surface (REMOTE-1063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the proposed endpoint shape to mirror warp-server's committed REST contract: a multi-verb sub-resource under /agent/environments/{uid}/setup-commands — GET (list), PUT (replace / clear-and-rebuild), POST (add; append when index omitted, insert at 0..=len), PATCH /{index} (edit by index), DELETE /{index} (remove by index), DELETE (clear all). Update error semantics to match the binding contract (edit/remove out of range -> 404; bad index -> 400) and the path parameter name to {uid}. Keep the sync-from-server approach (developers/agent-api-openapi.yaml regenerated from warp-server/public_api/openapi.yaml via the sync-openapi-spec tooling). Co-Authored-By: Warp --- .../REMOTE-1063-docs-setup-command-openapi.md | 90 +++++++++++-------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md b/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md index 551bdf42..be8f7c0d 100644 --- a/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md +++ b/.agents/specs/REMOTE-1063-docs-setup-command-openapi.md @@ -34,14 +34,19 @@ source of truth. setup-command operation(s) for cloud environments alongside the existing `GET /agent/environments` operation, with HTTP method, path, parameters, request body, and response codes rendered. -2. The documented request body lets a caller express insert-at-index, - edit-by-index, remove-by-index, clear, and clear-and-rebuild (replace) of an - environment's `setup_commands` list without resending the unchanged full - list for the index-based ops. -3. Index parameters are documented as **zero-based**; an insert at - `index == length` is documented as append (preserves order); any index - outside `[0, length]` (insert) or `[0, length)` (edit/remove) is documented - as a `400` error. +2. The documented surface exposes the setup-commands sub-resource as +multiple verbs under `/agent/environments/{uid}/setup-commands`: `GET` (list), +`PUT` (replace / clear-and-rebuild the whole list), `POST` (add — append when +index omitted, insert at `0..=len`), `PATCH /{index}` (edit one command by +index without resending the rest), `DELETE /{index}` (remove one by index), +and `DELETE` (clear all). The index-based ops (`POST` insert, +`PATCH /{index}`, `DELETE /{index}`) address a single command by index +without the caller resending the unchanged full list. +3. Index parameters are documented as **zero-based**; a `POST` insert at +`index == length` appends (preserves order); an edit (`PATCH /{index}`) or +remove (`DELETE /{index}`) whose index is out of range (`[0, length)`) is +documented as a `404`; a malformed/bad index (e.g. non-integer, negative) is +documented as a `400`. 4. Duplicate setup commands (same text, different positions) are addressable by index in the documented operations; the docs do not require command text to be unique. @@ -99,18 +104,21 @@ approach): contract but moves index semantics out of the shared contract, so the three specs cannot "agree on the same index semantics" — rejected for this multi-repo task. → contract carries index semantics. -- **Endpoint shape** (the warp-server spec is the final source of truth; this - is the proposed shape the docs file will mirror): - (a) *Sub-resource* (proposed): `PATCH /agent/environments/{environmentId}/setup-commands` - with an ordered `operations` array body (insert/edit/remove/append/clear/ - replace). Focused, RESTful, and additive to the existing plural path. - (b) *Whole-config PATCH*: `PATCH /agent/environments/{environmentId}` with a - setup-commands patch nested under config. Broader blast radius (implies a - general environment update contract). (c) *Separate verbs per op* - (POST .../insert, POST .../edit): more endpoints, more schemas, harder to - keep ordered. → sub-resource with an operations array (proposed); the docs - criteria below are written against *whatever exact path/shape the warp-server - spec commits*, so the docs spec is not brittle to that choice. +- **Endpoint shape** — **binding per warp-server's committed REST contract** + (the docs file mirrors it verbatim via the sync): a multi-verb sub-resource + under `/agent/environments/{uid}/setup-commands` (mounted at + `/api/v1/agent/environments/{uid}/setup-commands`): `GET` (list), `PUT` + (replace / clear-and-rebuild), `POST` (add — append when index omitted, + insert at `0..=len`), `PATCH /{index}` (edit by index), `DELETE /{index}` + (remove by index), `DELETE` (clear all). Alternatives weighed before + warp-server committed: (a) a single `PATCH` with an ordered `operations` + array body (insert/edit/remove/append/clear/replace) — fewer endpoints but a + less standard REST shape and a compound request body; (b) a whole-config + `PATCH /agent/environments/{uid}` with a setup-commands patch nested under + config — broader blast radius implying a general environment update + contract. warp-server chose the multi-verb sub-resource; the docs file + mirrors that exact surface, so the validation criteria below check for those + verbs and the `{uid}` path parameter. - **New tag or reuse `agent`** — options: (a) *Reuse the `agent` tag* (proposed): the new operations flow through the sync automatically (`agent` ∈ `KNOWN_TAGS`, path not in `EXCLUDED_PATHS`) — @@ -124,11 +132,13 @@ approach): 1. **Regenerate** `developers/agent-api-openapi.yaml` by running `scripts/sync_openapi.py --mode apply --source --target developers/agent-api-openapi.yaml` once - the warp-server canonical lands the new setup-command operations. The - regenerated file adds the new path(s), operation(s), request/response - schemas (e.g. `UpdateSetupCommandsRequest` and any per-operation schemas), - and the `Error`-referenced error responses — mirroring the canonical - verbatim for the included surface. + the warp-server canonical lands the setup-commands sub-resource. The + regenerated file adds the new paths — `/agent/environments/{uid}/setup-commands` + and `/agent/environments/{uid}/setup-commands/{index}` — the per-verb + operations (`GET`/`PUT`/`POST`/`PATCH`/`DELETE`), their request/response + schemas (e.g. add/replace/edit request bodies and the list response), and + the `Error`-referenced error responses — mirroring the canonical verbatim + for the included surface. 2. **Sync policy** (only if needed): if the warp-server spec introduces a new tag (not `agent`/`schedules`) or a path that should stay hidden, update `EXCLUDED_TAGS`/`EXCLUDED_PATHS` in `scripts/sync_openapi.py` and record the @@ -156,25 +166,27 @@ approval request for ben to confirm): all three specs agree on zero-based. *Assumption to confirm:* ben may prefer one-based for CLI ergonomics — if so, the CLI maps one-based→zero-based at the edge and the contract stays zero-based. -- **Insert permits append-at-length: yes.** `insert` at `index == length` - appends and preserves order; `index > length` or `< 0` is a `400`. Settled as - standard list-insert semantics; supports `--insert-setup-command ` - as an append. +- **Insert permits append-at-length: yes.** `POST` insert at `index == length` + appends and preserves order; an insert `index > length` is out of range. + Per warp-server's binding contract: edit/remove out of range → `404`; a bad + (malformed/negative) index → `400`. Settled as standard list-insert + semantics; supports `--insert-setup-command ` as an append. - **Duplicate-command addressing: by index.** Setup commands may legitimately repeat, so the precise ops address by index, not by text. The existing text-based `--remove-setup-command` CLI flag is preserved for compatibility and is translated client-side (find first text match → its index → - `remove` op); the public contract is index-based only. Settled from the + `DELETE /{index}`); the public contract is index-based only. Settled from the ticket's "edit one setup command by index without resending" requirement. - **Public contract: REST.** Settled from the existing REST public surface and the Scalar/OpenAPI docs pipeline; GraphQL stays internal. See Design alternatives. -- **Exact endpoint path/shape:** proposed `PATCH - /agent/environments/{environmentId}/setup-commands` with an ordered - operations array (insert/edit/remove/append/clear/replace). The docs file - mirrors whatever the warp-server spec ultimately commits; the validation - criteria are written against the canonical, not a hardcoded path, so this - assumption does not block the docs spec. +- **Exact endpoint path/shape: binding per warp-server.** Multi-verb + sub-resource under `/agent/environments/{uid}/setup-commands` (mounted at + `/api/v1/...`): `GET` list, `PUT` replace/clear-and-rebuild, `POST` add + (append when index omitted, insert at `0..=len`), `PATCH /{index}` edit, + `DELETE /{index}` remove, `DELETE` clear. The docs file mirrors this exact + surface verbatim via the sync; the validation criteria check for these verbs + and the `{uid}` path parameter. *Risks / blast radius:* - The docs file is generated; a hand-edit would be overwritten on the next @@ -195,11 +207,11 @@ PR; criteria 1–4 run against a `warp-server/public_api/openapi.yaml` that already contains the new setup-command operations): 1. `python3 .agents/skills/sync-openapi-spec/scripts/sync_openapi.py --mode apply --source ../warp-server/public_api/openapi.yaml --target developers/agent-api-openapi.yaml` regenerates the docs file containing the new setup-command operation(s) and exits 0 with "All $refs resolve in the regenerated spec." (every `$ref` resolves). - verifies behavior #1, #2. 2. `python3 .agents/skills/sync-openapi-spec/scripts/sync_openapi.py --mode diff --source ../warp-server/public_api/openapi.yaml --target developers/agent-api-openapi.yaml` reports **no `!` unclassified items**: the new operations either reuse the `agent` tag (no policy change) OR `EXCLUDED_TAGS`/`KNOWN_TAGS` in `scripts/sync_openapi.py` and `references/sync-policy.md` have been updated with a rationale for any new tag/path. - verifies the sync policy stays consistent. -3. The regenerated `developers/agent-api-openapi.yaml` contains the new precise setup-command operation(s) the warp-server canonical commits, with: a path parameter identifying the environment, `bearerAuth` security, a request body schema expressing insert-at-index / edit-by-index / remove-by-index / clear / clear-and-rebuild (replace) operations, and `200`/`400`/`401`/`403`/`404`/`500` responses (error responses `$ref` `#/components/schemas/Error`). - verifies behavior #1, #2; checked by grepping the regenerated YAML for the new operationId/path and schema names committed by the warp-server spec. -4. The regenerated docs file documents the **zero-based** index semantics (insert-at-length appends; out-of-range is `400`) in the operation/schema `description` fields, matching the warp-server canonical verbatim. - verifies behavior #3; checked by reading the regenerated schema descriptions and confirming they equal the canonical's. +3. The regenerated `developers/agent-api-openapi.yaml` contains the setup-commands sub-resource the warp-server canonical commits: paths `/agent/environments/{uid}/setup-commands` and `/agent/environments/{uid}/setup-commands/{index}`, with `GET` (list), `PUT` (replace/clear-and-rebuild), `POST` (add; append when index omitted, insert at `0..=len`), `PATCH /{index}` (edit by index), `DELETE /{index}` (remove by index), and `DELETE` (clear all) operations — each with `bearerAuth` security, the appropriate request body schema, and `200`/`201`/`204`/`400`/`401`/`403`/`404`/`500` responses (error responses `$ref` `#/components/schemas/Error`). - verifies behavior #1, #2; checked by grepping the regenerated YAML for the committed operationIds/paths and schema names. +4. The regenerated docs file documents the **zero-based** index semantics in the operation/schema `description` fields, matching the warp-server canonical verbatim: `POST` insert at `index == length` appends; edit (`PATCH /{index}`) / remove (`DELETE /{index}`) out of range → `404`; a bad (malformed/negative) index → `400`; duplicate command text allowed and addressed by index. - verifies behavior #3, #4; checked by reading the regenerated schema descriptions and confirming they equal the canonical's. 5. `npm run build` succeeds (Astro picks up the regenerated YAML and Scalar parses it at build time). - verifies behavior #1, #6; the docs repo's documented build check. 6. (Recommended when schemas changed) `npx @redocly/cli lint developers/agent-api-openapi.yaml` passes with no errors. - belt-and-braces OpenAPI lint. 7. No regressions to the existing public surface: the regenerated docs file still contains `GET /agent/environments` (`operationId: listEnvironments`) and the `CloudEnvironmentConfig` schema with its `setup_commands` array field, unchanged; `--mode diff` shows the new operations as **additions** only (no removals of existing public paths/schemas). - verifies behavior #5. 8. The docs PR records the warp-server source commit SHA used for the sync and the count of paths/schemas added/modified (per the sync-openapi-spec skill's reporting step). - traceability of the generated artifact to its source. -9. Cross-repo alignment: the docs operation path, path parameter name, request/response schema `$ref` names, HTTP status codes, and index semantics exactly match `warp-server/public_api/openapi.yaml` (same names, zero-based, append-at-length rule, same error codes). - verifies the three specs agree on one contract; checked by `--mode diff` reporting the docs file equals the curated subset of the canonical (no docs-only divergence). +9. Cross-repo alignment: the docs sub-resource paths (`/agent/environments/{uid}/setup-commands` and `.../{index}`), the `{uid}` path parameter name, the per-verb operationIds, request/response schema `$ref` names, HTTP status codes (`404` out-of-range edit/remove, `400` bad index), and zero-based index semantics exactly match `warp-server/public_api/openapi.yaml`. - verifies the three specs agree on one contract; checked by `--mode diff` reporting the docs file equals the curated subset of the canonical (no docs-only divergence). 10. After deploy, `docs.warp.dev/api` (Scalar) and `docs.warp.dev/openapi.json` expose the new operations. For the PR itself, verify via the `npm run build` output that the new path is present in the built spec; live deploy verification is post-merge. - verifies behavior #1, #6. From 7f0db10ca4df70c0115bc27ec7546e847ef2f0ba Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 24 Jul 2026 19:53:38 +0000 Subject: [PATCH 3/4] docs: expose precise setup-command operations in agent API OpenAPI (REMOTE-1063) Mirror warp-server PR #13278's setup-commands sub-resource into the generated docs OpenAPI (developers/agent-api-openapi.yaml) so the Scalar reference at docs.warp.dev/api documents the new precise update operations. Adds (verbatim from the canonical, scoped to the setup-commands surface only): - GET /agent/environments/{uid}/setup-commands (list) - PUT /agent/environments/{uid}/setup-commands (replace / clear-and-rebuild) - POST /agent/environments/{uid}/setup-commands (add; append when index omitted, insert at 0..=len) - DELETE /agent/environments/{uid}/setup-commands (clear all) - PATCH /agent/environments/{uid}/setup-commands/{index} (edit one by index) - DELETE /agent/environments/{uid}/setup-commands/{index} (remove one by index) - Schemas: SetupCommandsResponse, ReplaceSetupCommandsRequest, AddSetupCommandRequest, UpdateSetupCommandRequest - Params: EnvironmentUID, SetupCommandIndex Index semantics are zero-based, documented verbatim from the canonical: insert at index == len appends; edit/remove out of range -> 404; bad (non-integer/ negative) index -> 400; duplicate command text allowed and addressed by index. Scoped additive mirror: the docs file is behind the canonical on several unrelated public endpoints (factory, memory, messages, events, ...). A full sync_openapi.py --mode apply would pull all of those in and require triaging unknown factory/memory tags, which is out of scope for this ticket. This change adds only the setup-commands surface (390 insertions, 0 removals); the existing GET /agent/environments operation and CloudEnvironmentConfig schema (with its setup_commands array field) are unchanged. Source: warp-server/public_api/openapi.yaml @ 276952ba (PR #13278, branch factory/remote-1063-setup-command-updates, not yet merged). Re-sync/confirm once that PR merges. Co-Authored-By: Oz --- developers/agent-api-openapi.yaml | 390 ++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) diff --git a/developers/agent-api-openapi.yaml b/developers/agent-api-openapi.yaml index 870bee04..f2d87133 100644 --- a/developers/agent-api-openapi.yaml +++ b/developers/agent-api-openapi.yaml @@ -1197,6 +1197,314 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '/agent/environments/{uid}/setup-commands': + get: + summary: List environment setup commands + description: | + Return the environment's current ordered `setup_commands` as a JSON array, + 0-indexed in array order. An environment with no setup commands returns + an empty array. Requires update permission on the environment. + operationId: listEnvironmentSetupCommands + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + responses: + '200': + description: The environment's ordered setup commands + content: + application/json: + schema: + $ref: '#/components/schemas/SetupCommandsResponse' + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Replace environment setup commands + description: | + Replace the environment's entire `setup_commands` list with the provided + array (the "clear and rebuild" operation). An empty array or an omitted + field clears the list. The resulting list equals the request array in + order. Requires update permission on the environment. + operationId: replaceEnvironmentSetupCommands + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ReplaceSetupCommandsRequest' + responses: + '200': + description: The replaced setup commands + content: + application/json: + schema: + $ref: '#/components/schemas/SetupCommandsResponse' + '400': + description: Invalid setup command(s) or list size + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Add or insert an environment setup command + description: | + Append a command to the end of `setup_commands` when `index` is omitted. + When `index` is provided and `0 <= index <= len`, insert the command at + that position, shifting the element previously at `index` and all later + elements right by one; `index == len` appends. `index < 0` or + `index > len` is a 400. Requires update permission on the environment. + operationId: addEnvironmentSetupCommand + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AddSetupCommandRequest' + responses: + '200': + description: The updated setup commands + content: + application/json: + schema: + $ref: '#/components/schemas/SetupCommandsResponse' + '400': + description: Invalid index or setup command + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Clear all environment setup commands + description: | + Remove every setup command from the environment; the resulting list is + empty. Requires update permission on the environment. + operationId: clearEnvironmentSetupCommands + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + responses: + '204': + description: Setup commands cleared + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '/agent/environments/{uid}/setup-commands/{index}': + patch: + summary: Edit an environment setup command by index + description: | + Replace only the command at `index` with the provided `command`, leaving + all other entries and the list length unchanged. `index` is 0-based and + must reference an existing entry (`0 <= index < len`); an out-of-range + index returns 404 and a non-integer/negative index returns 400. + Requires update permission on the environment. + operationId: updateEnvironmentSetupCommand + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + - $ref: '#/components/parameters/SetupCommandIndex' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateSetupCommandRequest' + responses: + '200': + description: The updated setup commands + content: + application/json: + schema: + $ref: '#/components/schemas/SetupCommandsResponse' + '400': + description: Invalid index or setup command + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment or setup command index not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Remove an environment setup command by index + description: | + Remove the command at `index`, shifting later elements left by one; the + list length decreases by one. `index` is 0-based and must reference an + existing entry (`0 <= index < len`); an out-of-range index returns 404 + and a non-integer/negative index returns 400. Requires update + permission on the environment. + operationId: removeEnvironmentSetupCommand + tags: + - agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/EnvironmentUID' + - $ref: '#/components/parameters/SetupCommandIndex' + responses: + '204': + description: Setup command removed + '400': + description: Invalid index + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: No permission to update the environment + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Environment or setup command index not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /agent/models: get: summary: List available models @@ -1577,6 +1885,26 @@ components: scheme: bearer description: | Authentication via a Warp API key. + parameters: + EnvironmentUID: + name: uid + in: path + description: The unique identifier of the cloud environment. + required: true + schema: + type: string + SetupCommandIndex: + name: index + in: path + description: | + Zero-based index of a setup command within the environment's + `setup_commands` array. Must be a non-negative integer; an + out-of-range integer returns 404 and a non-integer or negative + value returns 400. + required: true + schema: + type: integer + minimum: 0 schemas: RunAgentRequest: type: object @@ -2931,6 +3259,68 @@ components: description: Shell commands to run during environment setup providers: $ref: '#/components/schemas/ProvidersConfig' + SetupCommandsResponse: + type: object + description: | + The environment's ordered setup commands. `setup_commands` is the + current list in array order (0-indexed); an environment with no setup + commands returns an empty array. + required: + - setup_commands + properties: + setup_commands: + type: array + items: + type: string + description: The environment's ordered setup commands + ReplaceSetupCommandsRequest: + type: object + description: | + Request body for replacing an environment's entire setup_commands list + (the "clear and rebuild" operation). An empty array or an omitted + field clears the list. The resulting list equals the request array in + order. + properties: + setup_commands: + type: array + items: + type: string + description: The full replacement list of setup commands + AddSetupCommandRequest: + type: object + description: | + Request body for adding or inserting a single setup command. When + `index` is omitted the command is appended; when `index` is provided + and `0 <= index <= len` the command is inserted at that position + (`index == len` appends). `index < 0` or `index > len` is a 400. + required: + - command + properties: + command: + type: string + x-oapi-codegen-extra-tags: + binding: required + description: The setup command to add or insert. + index: + type: integer + minimum: 0 + x-go-type-skip-optional-pointer: false + description: | + Optional 0-based position to insert at. Omit to append. Must + satisfy `0 <= index <= len`; `index == len` appends. + UpdateSetupCommandRequest: + type: object + description: | + Request body for editing a single setup command by index. Replaces only + the command at the path `index` with the provided `command`. + required: + - command + properties: + command: + type: string + x-oapi-codegen-extra-tags: + binding: required + description: The replacement setup command. ProvidersConfig: type: object description: Optional cloud provider configurations for automatic auth From d5094b1f389cbcebe727cdb2837f6d2f6291364c Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 24 Jul 2026 20:51:48 +0000 Subject: [PATCH 4/4] rework: re-sync setup-command OpenAPI sections from canonical warp-server c0b5d188 (REMOTE-1063) Address the review finding on PR #376: the generated docs OpenAPI mirror must explicitly document that duplicate setup-command text is allowed and addressed by zero-based index, and advertise the enforced size limits. The canonical source was updated first in warp-server public_api/openapi.yaml (commit c0b5d188 on branch factory/remote-1063-setup-command-updates), which added the duplicate-by-index notes to the list/replace/add/edit/remove operation descriptions and the SetupCommandsResponse/ReplaceSetupCommandsRequest/ AddSetupCommandRequest/UpdateSetupCommandRequest schema descriptions, plus maxItems:100 on the setup_commands arrays and minLength:1/maxLength:4096 on each command string. This re-syncs developers/agent-api-openapi.yaml to match that canonical source verbatim for the setup-command paths and schemas only (the SetupCommandIndex parameter description is unchanged in the canonical). The duplicate-by-index semantics and the schema constraints now appear in the docs mirror that Scalar renders at docs.warp.dev/api. A full sync_openapi.py --mode apply was intentionally NOT run: the canonical source has accumulated unrelated drift (factory, memory_stores, agent events/messages endpoints) whose tags are unclassified under the sync policy and require human triage before inclusion (per the sync-openapi-spec skill, unclassified tags must not be auto-included). That drift is out of scope for this setup-command rework and belongs in a separate full-sync PR. The setup-command sections transplanted here are byte-identical to the canonical c0b5d188 output (verified by loading both YAMLs and comparing the setup-command paths, schemas, and parameter). Validation: - sync_openapi.py --mode self-test: OK - All $refs resolve in the edited mirror (sync_openapi._validate_output) - npm run build prebuild (generate-openapi-json.mjs) parsed the YAML and emitted public/openapi.json with the duplicate notes + constraints - redocly lint: 0 new findings vs original HEAD (2 pre-existing errors + 3 pre-existing warnings in unrelated sections, unchanged by this edit) - astro build fails on an environmental node v25 vs required v20/22/24 SSR/Vercel-adapter rollup config issue, not a content/YAML problem Co-Authored-By: Oz --- developers/agent-api-openapi.yaml | 44 +++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/developers/agent-api-openapi.yaml b/developers/agent-api-openapi.yaml index f2d87133..e49cbe32 100644 --- a/developers/agent-api-openapi.yaml +++ b/developers/agent-api-openapi.yaml @@ -1203,7 +1203,9 @@ paths: description: | Return the environment's current ordered `setup_commands` as a JSON array, 0-indexed in array order. An environment with no setup commands returns - an empty array. Requires update permission on the environment. + an empty array. Duplicate command text is permitted: each entry is a + distinct element addressed by its zero-based index. Requires update + permission on the environment. operationId: listEnvironmentSetupCommands tags: - agent @@ -1248,7 +1250,9 @@ paths: Replace the environment's entire `setup_commands` list with the provided array (the "clear and rebuild" operation). An empty array or an omitted field clears the list. The resulting list equals the request array in - order. Requires update permission on the environment. + order. Duplicate command text is permitted and preserved in order; + entries are addressed by their zero-based index. Requires update + permission on the environment. operationId: replaceEnvironmentSetupCommands tags: - agent @@ -1306,7 +1310,10 @@ paths: When `index` is provided and `0 <= index <= len`, insert the command at that position, shifting the element previously at `index` and all later elements right by one; `index == len` appends. `index < 0` or - `index > len` is a 400. Requires update permission on the environment. + `index > len` is a 400. Duplicate command text is allowed: the new + command may equal an existing entry, since list entries are addressed by + their zero-based index, not by text. Requires update permission on the + environment. operationId: addEnvironmentSetupCommand tags: - agent @@ -1404,6 +1411,8 @@ paths: all other entries and the list length unchanged. `index` is 0-based and must reference an existing entry (`0 <= index < len`); an out-of-range index returns 404 and a non-integer/negative index returns 400. + Duplicate command text is allowed: editing index `i` changes only that + slot, so any other entry with the same text is left untouched. Requires update permission on the environment. operationId: updateEnvironmentSetupCommand tags: @@ -1462,8 +1471,10 @@ paths: Remove the command at `index`, shifting later elements left by one; the list length decreases by one. `index` is 0-based and must reference an existing entry (`0 <= index < len`); an out-of-range index returns 404 - and a non-integer/negative index returns 400. Requires update - permission on the environment. + and a non-integer/negative index returns 400. Duplicate command text is + allowed: removing index `i` affects only that slot, so any other entry + with the same text is left untouched. Requires update permission on the + environment. operationId: removeEnvironmentSetupCommand tags: - agent @@ -3264,14 +3275,19 @@ components: description: | The environment's ordered setup commands. `setup_commands` is the current list in array order (0-indexed); an environment with no setup - commands returns an empty array. + commands returns an empty array. Duplicate command text is permitted: + each list entry is a distinct element addressed by its zero-based + index, so editing or removing index `i` changes only that slot. required: - setup_commands properties: setup_commands: type: array + maxItems: 100 items: type: string + minLength: 1 + maxLength: 4096 description: The environment's ordered setup commands ReplaceSetupCommandsRequest: type: object @@ -3279,12 +3295,16 @@ components: Request body for replacing an environment's entire setup_commands list (the "clear and rebuild" operation). An empty array or an omitted field clears the list. The resulting list equals the request array in - order. + order. Duplicate command text is permitted and preserved in order; + entries are addressed by their zero-based index. properties: setup_commands: type: array + maxItems: 100 items: type: string + minLength: 1 + maxLength: 4096 description: The full replacement list of setup commands AddSetupCommandRequest: type: object @@ -3293,11 +3313,15 @@ components: `index` is omitted the command is appended; when `index` is provided and `0 <= index <= len` the command is inserted at that position (`index == len` appends). `index < 0` or `index > len` is a 400. + Duplicate command text is permitted: the new command may equal an + existing entry, since each entry is addressed by its zero-based index. required: - command properties: command: type: string + minLength: 1 + maxLength: 4096 x-oapi-codegen-extra-tags: binding: required description: The setup command to add or insert. @@ -3312,12 +3336,16 @@ components: type: object description: | Request body for editing a single setup command by index. Replaces only - the command at the path `index` with the provided `command`. + the command at the path `index` with the provided `command`. Duplicate + command text is permitted: editing index `i` changes only that slot and + leaves any other entry with the same text untouched. required: - command properties: command: type: string + minLength: 1 + maxLength: 4096 x-oapi-codegen-extra-tags: binding: required description: The replacement setup command.