Skip to content

docs: reconcile v1.15 spec text, unstable RFDs and the proxy-chains RFD - #2743

Merged
benbrandt merged 6 commits into
mainfrom
docs/v1.15-spec-cleanups
Nov 2, 2026
Merged

benbrandt merged 6 commits into
mainfrom
docs/v1.15-spec-cleanups

Conversation

@benbrandt

@benbrandt benbrandt commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Fixes the spec, schema-description and RFD issues found while syncing the SDKs to v1.15.0. All changes are text only. The regenerated schema/*.json and schema.mdx files are committed with their sources.

Fixes by issue

I1: v1 Implementation.title (stable v1 requirement drift from #2730)

  • docs(schema): plain-language pass over spec pages and schema descriptions #2730 changed "optimized to be human-readable and easily understood" to "so it should be readable by people", which adds a should-statement to stable v1. This PR restores the v1.14.0 wording, minus the em dash, in src/v1/agent.rs (field and builder), docs/protocol/v1/initialization.mdx and the v1 draft. The v2 copies use the same text.

I2: v1 tool-calls intro

  • "Agents may use Client capabilities ... while running a tool call" can be read as a new timing limit. The new text is "Agents run tool calls themselves. They may use Client capabilities such as permission requests or file system access." It changes v1 stable and the v1 draft.
  • I re-scanned the docs(schema): plain-language pass over spec pages and schema descriptions #2730 v1 diff (docs and .rs). No other v1 requirement changes.

I4: missing "or" (stable v2 background work)

  • prompt-lifecycle.mdx: "a terminal_update for a terminal or a tool_call_update for a tool call". The draft copy already had the "or".

v2 session/cancel and pending permission requests

  • The Agent now cancels permission requests, as it already did for elicitations. On session/cancel it MUST stop waiting for the cancelled foreground work's session/request_permission requests and treat them as not approved. It SHOULD cancel each one with $/cancel_request. The Client MAY answer a request it knows belongs to the cancelled work with cancelled without waiting. Requests for work in the background list are not affected.
  • This removes the Client-side rules that used subject to pick which requests to answer: requests without a subject, unrecognized custom subjects, and the old I8 question. subject is now display information only.
  • session/close: before responding, the Agent MUST cancel every pending permission request and elicitation in the session with $/cancel_request. The Client-side "MUST answer pending permission requests for listed work" is removed.
  • Updated in prompt-lifecycle, cancellation (rule and cascading example, which now shows $/cancel_request), tool-calls and session-setup (stable and draft v2), migration.mdx, the schema descriptions (RequestPermissionOutcome::Cancelled, the session/request_permission variant, the session/cancel notification), and the background-work RFD, with a revision-history entry. v1 is unchanged: the Client still answers every pending permission request there.
  • prompt-lifecycle.mdx (stable and draft): "SHOULD stop all language model requests and all tool call invocations" now says "of the cancelled foreground work", to match "listed work keeps running". The -32800 sentence now comes before the sentence about prompts received after session/cancel, so "those prompts" no longer reads as the later ones. The session/cancel schema description no longer says "Background work is not covered, but the Agent MAY stop it too".

I6: auth/status vs auth_required

  • auth/status is added to the draft v2 exception list in authentication.mdx. The RFD's MUST NOT is added to the AuthStatusRequest schema descriptions (v1 and v2).

I3: proxy-chains RFD and proxy schema descriptions

  • (a) New "Errors the conductor returns" section. It covers requests before initialization, a chain that fails to start, proxy/initialize from outside, misplaced proxy/successor, malformed envelopes, and a component that exited or a routing failure.
  • (b) New "Cancellation" section: cancellation is hop-local, never forwarded, and re-issued per hop. Includes an example.
  • (c) Envelope _meta is hop-local. The conductor does not copy it into the unwrapped message.
  • (d) The conductor selects the version like an Agent and rewrites protocolVersion only when it lowers it. Each proxy negotiates the same way, so the version only goes down along the chain. A proxy MUST forward initialize before answering successfully, builds its result from its successor's, and MUST NOT change protocolVersion. "Expects a standard InitializeResponse" is replaced by the version's InitializeRequest/InitializeResponse shapes, describing the chain from the proxy onward. Repeated proxy/initialize follows the repeated-initialize rules.
  • (e) Version negotiation links to both v1 and v2.
  • (f) sacp-conductor is now agent-client-protocol-conductor, and "SACP proxies" is now "ACP proxies".
  • (g) Wrapped params is a JSON object, an array, or null. An envelope without a string method, or with other params, gets -32602. Omitted or null params unwraps to a message without params.
  • (h) New "Forwarding" section. Proxies forward requests and notifications they don't handle, in both directions. -32601 comes from the end of the chain and passes back unchanged. A proxy answers -32601 itself only for a request it decides not to forward. $/cancel_request is never forwarded.
  • Pass-through: "unchanged" means the same JSON value, not the same bytes. Error members other than code/message/data may be dropped.
  • The crash-handling FAQ claimed the reference conductor restarts or bypasses failed components. It doesn't, so that text is replaced.
  • Added a revision-history entry.

Decisions to review

  • I6: Exempt auth/status from auth_required in the docs and schema. Alternative: leave the MUST NOT only in the RFD.
  • Permission cancellation: the Agent cancels permission requests on session/cancel (MUST stop waiting, SHOULD send $/cancel_request), and the Client MAY answer early. Alternative: keep the Client MUST and the subject-based rules.
  • I3(a): The conductor's own errors use -32600 for protocol misuse (matching the reference's proxy/initialize errors), -32602 for malformed envelopes or an invalid protocolVersion, and -32603 for a missing or exited component. A conductor MAY instead close the connection when a component fails.
  • I3(b): Plain hop-local $/cancel_request (SHOULD), with the wrapped form accepted and treated the same (MUST). Alternative: require the wrapped form on proxy-to-conductor hops.
  • I3(c): Envelope _meta is hop-local. Alternative: carry it end to end. Nothing in the reference does that, and it would mix envelope and message metadata.
  • I3(d): The version only goes down along the chain, and proxies keep their successor's protocolVersion. A proxy must forward initialize before a successful answer. Alternative: let a proxy answer without its successor, which leaves the successor uninitialized.
  • I3(g): Documented only. The schema type stays Option<RawValue>, with no validation added in the schema crate.
  • I3(h): Forward unknown requests and notifications. -32601 comes from the end of the chain.
  • Proxy rules 1-8 (pass-through as the same JSON value, conductor-originated errors, hop-local _meta, hop-local cancellation, repeated proxy/initialize, version wording, params shape, envelope without params or method) follow the proposals from the Rust SDK's schema 1.15.0 adoption, rust-sdk chore(deps): bump the minor group with 4 updates #480. Its byte-level wire tests check the reference conductor against them, and the reference in chore(deps): bump the minor group with 4 updates #480 already follows them, except for the two differences below.

Reference implementation differs

Checked against rust-sdk main and #480:

  • proxy/successor from a non-proxy. The spec now says the conductor answers a proxy/successor request from the agent, or from the client of a terminal-mode conductor, with -32600 and drops such notifications. The reference conductor forwards these as ordinary messages. A client's proxy/successor reaches the first proxy, which reads it as a message from its successor. An agent's arrives double-wrapped at the last proxy. I think forwarding is wrong because it lets the client inject messages that look like they came from the agent side.
  • Wrapped cancellation. The spec says senders SHOULD send $/cancel_request plain. Rust SDK proxies wrap the cancellation of a request they sent to their successor in proxy/successor. Its requestId is still the outer request's ID, so this is allowed but not the recommended form. The reference conductor accepts both forms and never forwards either, which matches the MUST rules.

Checks

  • npm run generate and npm run check pass.

benbrandt and others added 4 commits November 1, 2026 23:05
…tool-call intro

The plain-language pass (#2730) changed two v1 passages beyond wording:

- `Implementation.title` said it "should be readable by people", which adds
  a should-statement to the stable v1 spec and schema. Restore the v1.14.0
  meaning ("optimized to be human-readable and easily understood") without
  the em dash. The v2 copy uses the same text.
- The v1 tool-calls intro said Agents may use Client capabilities "while
  running a tool call", which reads as a new timing limit. Drop the temporal
  clause and keep the original "or".

Co-Authored-By: Claude <noreply@anthropic.com>
… rules

#2738 narrowed `session/cancel` so listed background work keeps running and
its permission requests stay open, but several v2 passages still stated the
old rule. Update them in the stable and draft pages and the v2 schema:

- prompt-lifecycle: add the missing "or" in the announce-before-listing
  rule (stable only, the draft already had it), scope "stop all tool call
  invocations" to the cancelled foreground work, put the `-32800` rule next
  to the prompts it covers, and state that a `subject` the Client does not
  recognize, such as a custom subject type, is answered with `cancelled`.
- tool-calls, cancellation, migration: answer pending permission requests
  for the cancelled foreground work, not every request in the session.
- Schema: `RequestPermissionOutcome::Cancelled`, the
  `session/request_permission` request and the `session/cancel`
  notification descriptions now state the narrowed rule and the custom
  subject case.

Co-Authored-By: Claude <noreply@anthropic.com>
…_title with their RFDs

- session/status: keep `-32002` for sessions the Agent does not know, and
  state the RFD's exception in the schema, the draft error pages and the
  RFD's own error rule: an Agent that cannot cheaply tell a saved session
  from an unknown one may return `saved`, and the later resume or load gets
  `-32002`.
- auth/status: add it to the draft v2 list of requests that do not fail
  with `auth_required`, and put the RFD's MUST NOT in the schema.
- session/set_title: refusing a session the Agent cannot safely update
  returns `-32602`, as an explicit exception to retitling any listed
  session, in the schema, the draft error pages and the RFD.

Co-Authored-By: Claude <noreply@anthropic.com>
…onductor

Define, in the proxy-chains RFD and the proxy schema descriptions:

- Errors the conductor returns itself (before initialization, failed
  chain start, `proxy/initialize` from outside, misplaced `proxy/successor`,
  malformed envelopes, a component that exited), separate from the
  pass-through rule for wrapped results.
- Hop-local cancellation: `$/cancel_request` names a request on its own
  connection, is never forwarded, and each hop re-issues it.
- Envelope `_meta` is hop-local and not copied into the unwrapped message.
- Version selection along the chain, the proxy's obligation to forward
  `initialize` before answering, the proxy/initialize result built from the
  successor's (same `protocolVersion`), and repeated `proxy/initialize`.
- "Unchanged" results and errors mean the same JSON value.
- Wrapped `params` is an object, an array, or `null`.
- Forwarding of unknown requests and notifications and where `-32601`
  comes from.

Also link version negotiation for v1 and v2, replace the old
`sacp-conductor` name, drop crash-handling claims the reference conductor
does not implement, and add a revision-history entry.

Co-Authored-By: Claude <noreply@anthropic.com>
benbrandt and others added 2 commits November 2, 2026 11:01
…ions

Co-Authored-By: Claude <noreply@anthropic.com>
…ancel in v2

The Agent knows which work each permission request belongs to, so on
session/cancel it stops waiting for the cancelled work's requests and
cancels them with $/cancel_request, as it already does for elicitations.
Clients MAY answer them early. session/close cancels every pending
permission request the same way. This removes the subject-based rules
for which requests the Client answers.

Co-Authored-By: Claude <noreply@anthropic.com>
@benbrandt
benbrandt merged commit bf35ca1 into main Nov 2, 2026
14 checks passed
@benbrandt
benbrandt deleted the docs/v1.15-spec-cleanups branch November 2, 2026 10:45
@acp-release-bot acp-release-bot Bot mentioned this pull request Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant