An open protocol - jointly governed by Zed Industries and JetBrains under a BDFL model, with a stated aim of transitioning to an independent foundation - that standardizes how a code editor or IDE (the "Client") talks to a coding agent (the "Agent"). ACP is the mirror image of MCP: MCP standardizes how an agent talks to tools and data, while ACP standardizes how a host editor exposes and drives an agent. It is carried over JSON-RPC 2.0, runs on stdio for local transports and on HTTP or WebSocket for remote transports (remote is noted as work in progress), and explicitly reuses MCP JSON shapes where possible so a single editor can speak both protocols without maintaining two serializers.
All ACP messages MUST be framed as JSON-RPC 2.0 requests, responses, or notifications with the 'jsonrpc' field set to the string '2.0'
Reusing JSON-RPC 2.0 gives ACP a battle-tested message envelope, a standard error shape, and free library support in every language an editor or agent is likely to be implemented in
The Client MUST send the 'initialize' request as its first message to the Agent and MUST NOT issue any session or authentication methods until it has received the initialize response
A fixed handshake prevents the Agent from having to guess which Client capabilities are available when answering early requests, and gives both peers one deterministic place to negotiate protocol version and feature flags
A well-formed JSON-RPC 2.0 initialize request declaring the Client's supported protocol version and advertising its file-system and terminal capabilities
If the Agent's advertised capabilities indicate authentication is required, the Client MUST call 'authenticate' after receiving the initialize response and before issuing any method that depends on the authenticated identity
Ordering authentication after initialize keeps the capability handshake and the credential exchange on the same deterministic path, so Agents never have to accept or reject session methods based on an ambiguous auth state
All agentic work happens inside a named session created by session/new or restored by session/load, with every session addressable by the ID returned from session/new
The Client MUST call 'session/new' to obtain a session ID before issuing any session-scoped method (session/prompt, session/cancel, session/set_mode, session/update, session/request_permission)
A session ID is the only unambiguous way the Client and Agent can correlate a prompt turn with its streaming updates, permission requests, and cancellation signals; without it, multi-session Agents cannot route messages correctly
The Client MUST NOT call 'session/load' unless the Agent advertised the loadSession capability in its initialize response
session/load is optional and some Agents do not persist sessions across connections; calling it unconditionally produces a cryptic error instead of the capability-gated failure the handshake is designed to prevent
A prompt turn drives the Agent's work with session/prompt, streams progress back over session/update notifications, and can be stopped with session/cancel
Recipients MUST NOT send any response - successful or error - to a session/update notification, because session/update is a JSON-RPC notification, not a request
Notifications are fire-and-forget by design in JSON-RPC 2.0; responding to them breaks the protocol contract and can leave the transport in an inconsistent state where each peer disagrees about the count of outstanding requests
Agents SHOULD emit session/update notifications as work progresses for any prompt that runs longer than a few hundred milliseconds, rather than waiting to deliver all output in the final session/prompt response
Streaming updates let the editor show real-time progress and cancel early if the user changes direction; batching everything into the final response makes the editor feel unresponsive
When the Agent wants to run a tool that affects the user's environment, it asks the Client for permission via session/request_permission before proceeding
The Client MUST surface session/request_permission to the end user and return only the user's decision; it MUST NOT auto-approve the request on the user's behalf
The whole point of the permission handshake is human-in-the-loop control over Agent actions - a Client that auto-approves defeats the security model and turns ACP into a trust-me back channel
Agents read and write text files in the Client's workspace through fs/read_text_file and fs/write_text_file, gated by the fs capability the Client declared at initialize time
All file paths passed to fs/read_text_file and fs/write_text_file MUST be absolute, not relative to any working directory
The Agent and the Client may have different working directories - or the Agent may have none at all when running remotely - so absolute paths are the only unambiguous way to identify a file
Any line-number fields in fs/read_text_file and fs/write_text_file requests or responses MUST be 1-based, not 0-based
Editor tooling and error messages are universally 1-based; using 0-based line numbers would force every Client to translate them at the boundary and is a common source of off-by-one bugs
The Client MUST advertise the fs capability in its initialize response before the Agent issues any fs/read_text_file or fs/write_text_file request
File system methods are optional; Clients that do not expose the user's workspace (for example, a browser-based host) cannot support them, and capability gating prevents the Agent from issuing requests that will always fail
Agents can create, interact with, and reap long-running terminal processes in the Client's workspace through the terminal/* method family, gated by the terminal capability
The Agent MUST NOT issue any terminal/create, terminal/output, terminal/release, terminal/wait_for_exit, or terminal/kill request unless the Client declared the terminal capability in its initialize response
Terminals give the Agent a direct path to execute arbitrary commands in the user's environment, so the Client is the only party that can decide whether to expose that capability at all
A terminal/create request launching a test runner in the project directory and receiving a terminal ID the Agent can use for output and lifecycle calls
Agents that accept session/set_mode SHOULD declare the set of supported mode names through their initialize response so the Client does not have to guess
Modes are Agent-defined and arbitrary; advertising the supported set during the handshake lets the Client render a picker, reject unsupported modes up front, and surface a clear error path
A session/set_mode request switching the Agent from its current mode into the "plan" mode for the rest of the session or until another set_mode is issued
Clients and Agents MUST ignore unknown _meta fields on any message rather than erroring out, so extensions added by peers at a newer protocol version remain forward-compatible
Without ignore-unknown-meta semantics, every future extension would break every older Client and Agent; forward compatibility is the whole reason _meta exists in the first place
Vendor-specific extension methods SHOULD be prefixed with an underscore (for example, _zed/custom_operation) so they are clearly distinguishable from core ACP methods
The underscore prefix makes the core-versus-extension boundary visible at the wire level, which helps debugging and prevents accidental collisions with future core method names