Skip to main content
Complete API reference for the ACP Java SDK, covering client, agent (all three styles), protocol types, transports, errors, and test utilities.

Installation

Maven (0.80.0 β€” stable)

Core SDK (client + sync/async agent APIs). From 0.18.0, acp-core contains no JSON implementation; add one JSON module next to it:
Or, for Jackson 3 (tools.jackson.databind, for example alongside Spring Boot 4), use acp-json-jackson3 in place of acp-json-jackson2. Without either, AcpJsonMapper.createDefault() fails with No AcpJsonMapperSupplier found on the classpath. AcpJsonMapper.createDefault() picks the supplier with the highest AcpJsonMapperSupplier.priority(): with both modules present Jackson 3 wins, and an application’s own supplier wins over both. The system property acp.json.mapper.supplier names a supplier class explicitly. Annotation-based agent support (includes acp-core and acp-json-jackson2 transitively):
Test utilities:
Streamable HTTP and WebSocket server transport for remote agents:
acp-websocket-jetty (single-client WebSocketAcpAgentTransport) was deprecated for removal in 0.18.0 and is removed in 0.80.0; use acp-streamable-http-jetty. See the 0.80.0 migration guide.

Gradle

Snapshot (0.81.0-SNAPSHOT)

For unreleased features, add the snapshot repository and use the snapshot version:
Then use 0.81.0-SNAPSHOT in place of 0.80.0 in your dependencies.

Three Agent API Styles

Quick Comparison

All three produce identical protocol behavior and support the same capabilities.

When to Use Each

  • Annotation-based β€” default choice. Least boilerplate, auto-converts return types, supports interceptors and custom argument resolvers.
  • Sync β€” when you want explicit control over every handler without annotations. Blocking void methods for sending updates.
  • Async β€” when your agent needs non-blocking I/O. Uses Project Reactor Mono for composable async chains.

Client API

AcpClient β€” Factory

AcpSyncClient β€” Blocking Client

Builder Configuration

Example β€” Complete client lifecycle

This launches the Grok CLI as an ACP agent subprocess and sends it a prompt. AgentParameters builds the command line; StdioAcpClientTransport spawns the process and handles JSON-RPC framing over stdin/stdout.

Agent API β€” Annotation-Based

The acp-agent-support module provides a declarative programming model using annotations.

Annotations

Class-Level

Handler Methods

Removed in 0.80.0: the session-model API. session/set_model and the related types (@SetSessionModel, SetSessionModelRequestResolver, SetSessionModelRequest/Response, SessionModelState, ModelInfo, and the models field on session responses) were deprecated for removal in 0.14.0 and are gone in 0.80.0. An agent built on 0.80.0 no longer answers session/set_model; a peer that sends it gets β€œmethod not found”. Expose model selection through session/set_config_option instead: advertise a select config option whose category is "model", and switch models with setSessionConfigOption(...). This is the same mechanism used for session modes (category: "mode") and reasoning level (category: "thought_level"). See the 0.80.0 migration guide.

Parameter Annotations

Connection-Level Parameters (0.80.0)

Any handler method, not only @Prompt, may also declare a parameter of type AcpSyncAgent/ AcpAsyncAgent (the connection’s own agent facade, to call back into the client) or NegotiatedCapabilities (what the connected client advertised). Resolution is by parameter type, so order and presence are both optional:
Previously, a handler needing to call back into the client had to capture the agent from an enclosing scope; as of 0.80.0 it’s an ordinary parameter like any other.

Flexible Method Signatures

Handler methods support flexible parameter resolution:

Return Value Handling

SyncPromptContext

Available in @Prompt handlers. Provides blocking methods for agent-client interaction:
ctx.async() (0.80.0) returns the same turn’s PromptContext (the async, Reactor-based view), for the rare case where a sync handler needs to compose one of the async-only APIs. If you implement SyncPromptContext yourself, for a test double, async() is an abstract method you must provide too; it’s not a default method.

AcpAgentSupport β€” Bootstrap

For a single stdio agent, .run() blocks until the client disconnects:
For Streamable HTTP or WebSocket, where one JVM serves many remote connections, buildFactory() (0.80.0) hands back an AcpAgentFactory instead of running one agent directly; the server creates a fresh agent per connection from it, sharing the same handler bean (which must be thread-safe) across all of them:
The builder is safely reusable across multiple buildFactory() calls, if you need more than one listener sharing the same configuration. See Transports for the full connection lifecycle.

Interceptors

Cross-cutting concerns like logging, metrics, or error handling:

Example β€” Complete annotation-based agent


Agent API β€” Sync (Builder)

Blocking handlers with plain return values. No annotations.

Builder Methods

Example

Prompt Handler Context

The context parameter in promptHandler provides:

Agent API β€” Async (Builder)

Reactive handlers returning Mono. Uses Project Reactor.

Example

The async context’s sendMessage(), sendSessionUpdate(), etc. return Mono<Void>, composable with .then() and .flatMap().

Convenience Methods vs Full API

The SDK provides convenience methods that cover the most common operations. Use these by default β€” they produce cleaner code and handle the protocol details for you.

When convenience methods are enough (~80% of cases)

When to use the full API (~20% of cases)

Drop to the full API when you need control that convenience methods don’t expose:
The convenience methods are wrappers around the full API β€” they call the same underlying protocol methods. You can mix and match freely within a single handler.

Protocol Types

All protocol types are defined in AcpSchema as Java records.

Request/Response Types

Session Types (0.12.0)

Config Option Types (0.12.0)

session/set_config_option is stable. The select variant is the stable shape; boolean is an SDK extension.

Provider Types (0.14.0, unstable)

Model/backend routing configuration. The agent advertises support with a providers capability; the client manages providers via listProviders / setProvider / disableProvider. apiType / supported use well-known LlmProtocol ids (anthropic, openai, azure, vertex, bedrock) or a custom string, modeled as String in the SDK.

Elicitation Types (0.12.0, unstable)

Content Types

Session Update Types

Content chunks (UserMessageChunk, AgentMessageChunk, AgentThoughtChunk) carry an optional messageId: chunks sharing the same id belong to one logical message, and a change in id starts a new message (0.14.0).

Stop Reasons

Convenience Methods


Capabilities

Client Capabilities

Advertised on the client builder, before initialize() is called. As of 0.80.0, initialize(InitializeRequest) is removed; capabilities are set only this way. See the 0.80.0 migration guide. A client built with the matching handlers (readTextFileHandler, writeTextFileHandler, the five terminal handlers) advertises these capabilities automatically as of 0.80.0; setting clientCapabilities(..) explicitly, as below, always wins over what the handlers would derive. See Client builders derive capabilities from handlers.
For session, auth, and elicitation support too, add their builder calls; these aren’t derived from handlers, so set them explicitly whenever you need them:
The setters that take the nested records directly (.fs(new FileSystemCapability(true, true)), .terminal(true)) still work, for a capability shape the one-flag setters don’t cover. initialize(int protocolVersion, Map<String, Object> meta) is still available for the rare case of pinning a specific protocol version or attaching _meta to the handshake; plain initialize() is what nearly every client should call.

NegotiatedCapabilities

Check capabilities before using them:
Or use require methods that throw AcpCapabilityException if unsupported:

Session Capabilities (0.12.0)

Agents advertise session management support via SessionCapabilities. The NegotiatedCapabilities accessors are: supportsListSessions(), supportsCloseSession(), supportsResumeSession(), supportsDeleteSession() (0.14.0), supportsAdditionalDirectories() (0.14.0), and supportsForkSession() (unstable) β€” each with a matching require*() that throws AcpCapabilityException.

Elicitation Capabilities (stable since 0.80.0; added 0.12.0 as unstable)

Clients advertise elicitation support during initialization. The capability’s modes are typed (ElicitationFormCapabilities, ElicitationUrlCapabilities); the no-argument ElicitationCapabilities() constructor is removed in 0.80.0 in favor of formOnly(), urlOnly(), and formAndUrl(). A client built with a createElicitationHandler and no explicit clientCapabilities(..) advertises form-mode elicitation automatically (0.80.0):
Set it explicitly with the capability builder to advertise without a handler, or to combine with other capabilities:

@UnstableAcpApi

APIs marked @UnstableAcpApi correspond to protocol elements in schema.unstable.json. They are public and functional but may change in any minor release. When the protocol element stabilizes, the annotation is removed (compatible change). See Stable vs Unstable for the full policy. IntelliJ users can configure the Unstable API Usage inspection (Settings > Inspections > JVM languages) to flag usages.

Transports

Stdio Transport

The default transport. The client launches the agent as a subprocess and communicates via JSON-RPC over stdin/stdout. This is the same mechanism Zed, JetBrains, and VS Code use to talk to agents. Client side β€” AgentParameters specifies the command to launch. Any executable that speaks ACP over stdin/stdout works (Grok CLI, your own agent JAR, etc.):
Agent side β€” reads JSON-RPC from stdin, writes responses to stdout. The agent doesn’t need to know what launched it:

Streamable HTTP and WebSocket Transport

For remote agents, per the ACP Streamable HTTP and WebSocket transport RFD. One endpoint serves HTTP POST with Server-Sent Event streams and a WebSocket upgrade on the same path. Plain http:// is supported: against a server that speaks h2c, every request runs on HTTP/2. Agent (requires acp-streamable-http-jetty): StreamableHttpAcpAgentTransport is a listener, not a per-session transport. It creates one fresh agent per remote connection through an AcpAgentFactory:
Use AcpAgentFactory.async(...) for an AcpAgent.async(...) agent. Other constructors take a custom path and StreamableHttpAcpAgentTransportOptions (POST body cap, SSE mailbox and backpressure limits, keep-alive, HTTP/2 stream limit). Agent in your own Servlet 6 container: StreamableHttpAcpServlet(jsonMapper, agentFactory) serves the HTTP/SSE profile at a path you choose; register it with async support. It does not serve the WebSocket upgrade. See Remote agents for a Spring Boot registration. Client, Streamable HTTP (in acp-core):
Client, WebSocket (JDK-native, in acp-core):
WebSocketAcpAgentTransport (acp-websocket-jetty) was deprecated for removal in 0.18.0 and is removed in 0.80.0. It served a single WebSocket client. WebSocketAcpClientTransport clients connect to StreamableHttpAcpAgentTransport unchanged.

In-Memory Transport

For testing. No subprocess or network I/O.

Errors

Exception Hierarchy

Error Codes

isConcurrentPrompt() is removed in 0.80.0: a prompt sent while one is already running on the session is now a generic INVALID_REQUEST (-32600), not its own code. isAuthenticationRequired() is new. See the 0.80.0 migration guide.

Agent-Side Error Handling

Throw AcpProtocolException from handlers to send structured errors to clients:

Test Utilities

The acp-test module provides utilities for testing without subprocesses.

InMemoryTransportPair


Packages

Maven Artifacts

acp-websocket-jetty (single-client WebSocket agent transport) is removed in 0.80.0; it is not a dependable artifact as of this release. See the 0.80.0 migration guide.

See Also