You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ACP's spec documentation and the SDK's code-generated schema (@agentclientprotocol/sdk/dist/schema/types.gen.d.ts) are not strictly linked. New implementers building agents/clients have to choose:
Read the spec docs → may be slightly out of date relative to the SDK release.
Read types.gen.d.ts directly → up-to-date but harder to navigate / no rationale.
Read existing reference implementations (Gemini CLI, slopus/happy, OpenHands, Zed) → may have non-spec workarounds mixed in.
We hit this when building atomcode (a Rust ACP agent) and when shipping ~20 PRs against slopus/happy's ACP layer. Specific drift / discoverability gaps we tripped over:
ContentChunk.content is a ContentBlock (single), not Array<ContentBlock>. Several implementers initially wrote it as an array (mis-read from prose alone).
ToolCall.rawInput (the tool-invocation parameters) vs ToolCall.content (an Array<ToolCallContent> of output). Names easy to confuse without the type signatures in front of you; we initially read content as input in slopus/happy and shipped fixes in slopus/happy#1284.
UsageUpdate { size, used } — short field names; easy to assume inputTokens / outputTokens would also exist (they don't, that's only on Cost / per-message usage).
None of these are SDK bugs — the SDK schema is correct. They're discoverability bugs: someone reading the spec doc without also opening the SDK package is likely to write a non-conforming client/server, then debug it for a day. Once you've burned that day, the lesson is "always read types.gen.d.ts first", and the prose spec becomes secondary documentation.
Proposal
Two options, not mutually exclusive:
Option A — Designate the SDK schema as the source of truth (documentation-only)
Add a clear "Source of truth" callout near the top of the spec site that says:
The authoritative shape of every ACP message is the TypeScript / JSON Schema in @agentclientprotocol/sdk. The narrative spec on this site is for orientation and rationale. When the two disagree, the SDK schema wins; please file an issue.
Plus version-pin each spec doc page to a particular SDK release (e.g. "this page documents v0.14.x").
Option B — Auto-generate the wire-format reference from the schema
Run a build step (e.g. in the docs CI) that reads the SDK's JSON Schema (or the TS types) and generates a reference page or block per type. The narrative spec stays human-edited but always renders the canonical field list + types from the schema. This is what Stripe / OpenAI do for their API reference docs.
Why it matters for the broader ecosystem
There are already ≥4 third-party ACP implementations (slopus/happy, OpenHands, atomcode, plus several clients/agents under discussion in adjacent issues). Each independently rediscovered the same drift gaps and shipped workarounds. Without a designated source of truth, the next implementer will do the same — and every spec-adjacent agent we want to land in the ecosystem (Codex, Kimi, OpenCode, …) inherits the same friction.
Happy to draft the docs patch (Option A) if there's interest. Option B is bigger and would want input from whoever owns the SDK release pipeline.
Problem
ACP's spec documentation and the SDK's code-generated schema (
@agentclientprotocol/sdk/dist/schema/types.gen.d.ts) are not strictly linked. New implementers building agents/clients have to choose:types.gen.d.tsdirectly → up-to-date but harder to navigate / no rationale.We hit this when building atomcode (a Rust ACP agent) and when shipping ~20 PRs against slopus/happy's ACP layer. Specific drift / discoverability gaps we tripped over:
ContentChunk.contentis aContentBlock(single), notArray<ContentBlock>. Several implementers initially wrote it as an array (mis-read from prose alone).ToolCall.rawInput(the tool-invocation parameters) vsToolCall.content(anArray<ToolCallContent>of output). Names easy to confuse without the type signatures in front of you; we initially readcontentas input in slopus/happy and shipped fixes in slopus/happy#1284.UsageUpdate { size, used }— short field names; easy to assumeinputTokens/outputTokenswould also exist (they don't, that's only onCost/ per-message usage).None of these are SDK bugs — the SDK schema is correct. They're discoverability bugs: someone reading the spec doc without also opening the SDK package is likely to write a non-conforming client/server, then debug it for a day. Once you've burned that day, the lesson is "always read types.gen.d.ts first", and the prose spec becomes secondary documentation.
Proposal
Two options, not mutually exclusive:
Option A — Designate the SDK schema as the source of truth (documentation-only)
Add a clear "Source of truth" callout near the top of the spec site that says:
Plus version-pin each spec doc page to a particular SDK release (e.g. "this page documents v0.14.x").
Option B — Auto-generate the wire-format reference from the schema
Run a build step (e.g. in the docs CI) that reads the SDK's JSON Schema (or the TS types) and generates a reference page or block per type. The narrative spec stays human-edited but always renders the canonical field list + types from the schema. This is what Stripe / OpenAI do for their API reference docs.
Why it matters for the broader ecosystem
There are already ≥4 third-party ACP implementations (slopus/happy, OpenHands, atomcode, plus several clients/agents under discussion in adjacent issues). Each independently rediscovered the same drift gaps and shipped workarounds. Without a designated source of truth, the next implementer will do the same — and every spec-adjacent agent we want to land in the ecosystem (Codex, Kimi, OpenCode, …) inherits the same friction.
Happy to draft the docs patch (Option A) if there's interest. Option B is bigger and would want input from whoever owns the SDK release pipeline.
Related