This guide applies to the breaking entrypoint split: the default SDK import uses the stable ACP v1 schema, and unstable v1 features require an explicit opt-in. The v2 experimental entrypoint follows the same schema-selection rule, but all of v2 remains a draft. Earlier SDK releases included unstable features in both the default v1 import and the experimental v2 import. Consult the versioned changelog for release availability.
This upgrade also removes the deprecated v1 connection classes and implementation
interfaces. Both v1 entrypoints now use the app API. Opting into /unstable does
not restore the legacy API.
| Import | Protocol surface |
|---|---|
@agentclientprotocol/sdk |
Stable v1 |
@agentclientprotocol/sdk/unstable |
Full v1, including unstable features |
@agentclientprotocol/sdk/experimental/v2 |
Stable features of the v2 draft |
@agentclientprotocol/sdk/experimental/v2/unstable |
Full v2 draft, including unstable features |
SDK package versions and ACP protocol versions are independent. This upgrade does not switch your integration to ACP v2: the default import still speaks ACP v1.
unstable_*. A successful TypeScript build is not enough
to establish that an existing integration is stable-only.createLegacyAgent server options with the app APIs below.
This applies to stable-only integrations too.// Stable ACP v1 types, methods, and handler validation.
import * as acp from "@agentclientprotocol/sdk";
// Stable ACP v1 plus the current unstable protocol features.
import * as acp from "@agentclientprotocol/sdk/unstable";
Stable-only v1 applications already using the app API can keep their imports
unchanged. Legacy applications must migrate their API usage regardless of which
feature set they select.
Applications using unstable v1 features must move their protocol imports to
/unstable, including types, apps, peer contexts, method constants, and
narrowing helpers.
Before:
import { client, methods, type SystemPrompt } from "@agentclientprotocol/sdk";
After:
import {
client,
methods,
type SystemPrompt,
} from "@agentclientprotocol/sdk/unstable";
Use the selected entrypoint consistently throughout an app and its directly
connected in-process peer. Mixing stable and unstable app classes in a direct
connect(...) or connectWith(...) call is not supported. Peers communicating
over a transport can select their SDK entrypoints independently, provided they
honor the negotiated protocol capabilities.
Each unstable entrypoint is a complete API for its protocol version, not an
add-on to the stable-feature import. Importing it does not change other modules'
stable imports. Protocol wire method names are unchanged. The deprecated
unstable_* connection methods are removed with the rest of the legacy API.
Applications using only the stable-feature set of draft v2 can keep importing from
@agentclientprotocol/sdk/experimental/v2. Applications using additional unstable
v2 features must move their protocol imports to
@agentclientprotocol/sdk/experimental/v2/unstable:
import * as acp from "@agentclientprotocol/sdk/experimental/v2/unstable";
Both v2 entrypoints remain experimental: their wire protocol and SDK APIs can change incompatibly in any release. Here, "stable" describes the selected schema features, not a stability guarantee for v2 itself. Both v2 surfaces retain batch support and branded unknown variants.
The split also affects fields and variants on otherwise stable types. Examples
of APIs that require /unstable include:
systemPrompt on session lifecycle requests and its advertised capabilities.usage on v1 prompt responses and usage on v2 idle state updates.plan_removed updates. V1's existing
stable plan update and v2's stable item-based plan_update remain available
from their stable-feature entrypoints. V1's ID-based plan_update, and v2's
file and markdown plan representations, require the corresponding unstable
entrypoint.For each protocol version, the stable entrypoint's generated types and validators
come from upstream's schema.json and meta.json. Its unstable entrypoint uses
schema.unstable.json and meta.unstable.json, including their unstable additions
to shared types.
TypeScript can accept inferred capability objects containing extra fields, and JavaScript has no compile-time check. Review capability advertisements alongside explicit handler registrations so that an integration does not advertise a feature its selected entrypoint will not handle.
Passing unstable fields through untyped code is not a substitute for opting in: stable-feature request parsing can strip those fields, and stable built-in handlers do not include unstable methods. Explicit custom-method APIs remain available.
In the repository, schema inputs are organized by protocol version under
schema/v1/ and schema/v2/. Each directory uses the same upstream filenames:
schema.json, schema.unstable.json, meta.json, and meta.unstable.json.
The JSON schemas are public package exports; metadata files are generation
inputs, not additional public imports.
The canonical stable v1 JSON schema import is:
@agentclientprotocol/sdk/schema/v1/schema.json
The previous unversioned @agentclientprotocol/sdk/schema/schema.json export has
been removed. JSON schema consumers must update their imports to a versioned
path, even when using only stable definitions.
Tools that need the full v1 schema must switch to:
@agentclientprotocol/sdk/schema/v1/schema.unstable.json
V2 schema consumers can choose the stable-feature schema for the v2 draft:
@agentclientprotocol/sdk/schema/v2/schema.json
The existing full v2 schema export remains available and unchanged:
@agentclientprotocol/sdk/schema/v2/schema.unstable.json
The following APIs are removed from both v1 entrypoints and the NES re-exports:
| Removed API | Replacement |
|---|---|
AgentSideConnection |
agent().onRequest(...).onNotification(...).connect(...) |
ClientSideConnection |
client().onRequest(...).onNotification(...).connect(...) or connectWith(...) |
Agent / Client implementation interfaces |
Typed app callbacks; handler maps are available as AgentRequestHandlersByMethod and ClientRequestHandlersByMethod |
Named outbound methods such as newSession(...) and sessionUpdate(...) |
Peer-context request(methods.agent.session.new, params) and notify(methods.client.session.update, params) |
Outbound extMethod(...) / extNotification(...) |
Peer-context request(...) / notify(...) |
Incoming extMethod / extNotification callbacks |
Explicit custom-method handlers or the raw fallback hooks below |
AgentSideConnection.connector(...) / LegacyAgentFactory / createLegacyAgent |
An app or router supplied through agent or createAgent |
connect(...) returns a lifecycle handle with signal and closed. Use its
.client context on the agent side, or .agent context on the client side, to
call the peer. connectWith(...) passes that peer context directly and closes
the connection when the callback finishes. Handler contexts expose the actual
method as ctx.method, including in custom and fallback handlers.
Use explicit method handlers when the method names are known. If an existing extension dispatcher needs a catch-all, both agent and client apps support:
import * as acp from "@agentclientprotocol/sdk";
const app = acp
.agent()
.onRequest("*", ({ method, params }) => {
if (method === "_example/echo") return { echoed: params };
throw acp.RequestError.methodNotFound(method);
})
.onNotification("*", ({ method }) => {
console.error("Ignoring unregistered notification:", method);
});
Exact handlers take precedence regardless of registration order. Fallbacks run
after normal dispatch, including dynamically registered handlers and protocol
guards. They receive raw unknown params, without a parser argument; validate
untrusted input before using it. Register at most one fallback per kind per app.
Without a fallback, unhandled requests still receive Method Not Found and
unhandled notifications are ignored. A fallback does not bypass v2 initialization:
v2 agents still need an explicit initialize handler.
For v1 client-managed terminals, use AgentContext.createTerminal(...) to retain
the handle and disposal ergonomics of the old connection helper:
import * as acp from "@agentclientprotocol/sdk";
async function runCommand(client: acp.AgentContext, sessionId: string) {
await using terminal = await client.createTerminal({
sessionId,
command: "echo",
args: ["hello"],
});
await terminal.waitForExit();
return await terminal.currentOutput();
}
Check the peer's advertised terminal capability before calling it. The handle
retains currentOutput(), waitForExit(), kill(), release(), and async disposal.
For raw responses or per-operation request options, use the corresponding
request(methods.client.terminal.*, ...) calls.
The experimental HTTP, WebSocket, server, and Node transport import paths are unchanged. They can carry stable-feature or unstable apps for either protocol version; select the app from the appropriate protocol entrypoint. Selecting stable protocol features does not make these experimental transport APIs stable.
Replace createLegacyAgent with a factory returning an app, not an object
implementing the old Agent interface. Register each supported method explicitly.
This minimal example uses stable v1; select /unstable if the app needs it:
import * as acp from "@agentclientprotocol/sdk";
import { AcpServer } from "@agentclientprotocol/sdk/experimental/server";
const server = new AcpServer({
createAgent: () =>
acp.agent().onRequest(acp.methods.agent.initialize, () => ({
protocolVersion: acp.PROTOCOL_VERSION,
agentCapabilities: {},
})),
});
Use agent: app when intentionally sharing an app across connections, or a
createAgent factory that constructs a new app for each connection. Replace per-request and
per-WebSocket-upgrade createLegacyAgent overrides too; they are rejected rather
than silently falling back to the default app.
npm run typecheck checks production code, tests, fixtures, and examples without
emitting files. npm run build cleans dist and emits production code only.
npm test runs source tests once rather than discovering compiled duplicates.
Examples remain in src/examples and can be run with tsx from a repository
checkout; compiled examples and test helpers are no longer shipped in npm.
npm run package:check verifies the packed file allowlist, public exports, and
relative runtime and declaration dependencies. CI runs this check.
The supported Zod versions are ^3.25.76 || ^4.0.0. Zod 3 users should upgrade
to at least 3.25.76 before installing this SDK. Earlier 3.25.x versions are not
part of the supported range; in particular, 3.25.0 advertises a zod/v4 export
whose compiled entrypoint is missing.
This is an SDK API boundary, not a new wire protocol version. Both v1 entrypoints speak ACP v1, and both v2 entrypoints speak the v2 draft. Selecting an unstable entrypoint does not automatically advertise support or establish peer support: advertise and check capabilities before using features that require them.
The default v1 entrypoint follows the SDK's normal versioning guarantees. Unstable features can change or be removed in any SDK release, including non-major releases.
The existing @agentclientprotocol/sdk/experimental/nes entrypoint remains
separate. Importing /unstable does not opt into draft v2 or the frozen NES
compatibility APIs.
Breaking change: The default SDK entrypoint now contains only stable ACP v1
definitions. Applications using unstable protocol methods, fields, or variants
must import their protocol API from @agentclientprotocol/sdk/unstable.
Stable-only v1 applications already using the app API can keep their imports.
The deprecated AgentSideConnection, ClientSideConnection, Agent, and
Client APIs have been removed from both v1 profiles. Use app builders, typed
handlers, and peer-context calls instead. Raw extension fallbacks and v1
terminal-handle helpers are available without the compatibility layer.
The unversioned JSON schema export
@agentclientprotocol/sdk/schema/schema.json has been removed. JSON schema
consumers must choose @agentclientprotocol/sdk/schema/v1/schema.json for stable
v1 definitions or @agentclientprotocol/sdk/schema/v1/schema.unstable.json for
the full v1 schema. Server integrations must replace createLegacyAgent and its
connector helper with an app or router through agent or createAgent.
The experimental v2 entrypoint now uses the stable-feature set of the v2 draft.
Existing v2 applications using additional unstable features must switch their
protocol imports to @agentclientprotocol/sdk/experimental/v2/unstable. Both v2
entrypoints remain experimental; this split does not stabilize v2.