The Agent Client Protocol inverts who owns the filesystem — the agent asks the editor to read and write files, and that single inversion is what makes it a protocol rather than a plugin API.
Zed's ACP is why Claude Code, Codex CLI and Gemini CLI can all run inside the same editor window. The interesting part is not the JSON-RPC framing, it is that an ACP agent is forbidden from touching the disk directly: it calls fs/read_text_file and asks the client to do it. The stated reason is unsaved editor buffers. The consequence is that permission, change-tracking and sandboxing all become client-side and therefore uniform across every agent that speaks the protocol. Read the capability handshake and the filesystem inversion and the rest of ACP follows; read it as "LSP for agents" and you will miss both.
Two protocols, one acronym — and this is the live one.
Before anything technical: there have been two protocols called ACP, and search results still mix them freely. The one this essay covers is the Agent Client Protocol, created by Zed Industries in August 2025, which connects code editors to coding agents. The other was the Agent Communication Protocol, a REST-native agent-to-agent protocol contributed to the Linux Foundation in July 2025 and subsequently folded into A2A; this site covers its short life in ACP: What Happened. If a page you are reading describes ACP as an alternative to A2A, it means the dead one. If it describes ACP as something your editor speaks, it means this one.
The confusion is not merely lexical, because the two protocols sit on different seams. The Agent Communication Protocol was trying to standardise agent-to-agent delegation, which is the seam A2A now owns. The Agent Client Protocol standardises client-to-agent control: one editor, many interchangeable agents. Those are orthogonal problems, and a system can reasonably speak both — ACP to its editor, A2A to a peer, MCP to its tools. Treating them as competitors is the single most common error in secondary coverage of this area.
Adoption is the reason to care. JetBrains joined the effort after Zed, the two co-launched an agent registry in January 2026, and 40-plus agents are listed as of 2026. Crucially the three CLIs most people actually run are all reachable: Gemini CLI implements ACP natively, while Claude Code and Codex CLI connect through Zed-built adapters rather than first-party support. That adapter distinction matters for expectations — an adapter wraps a CLI that was designed around its own harness, so capability coverage is whatever the adapter chose to map, not whatever the agent can do.
The shape: JSON-RPC 2.0 over stdio, and where the LSP analogy stops.
ACP is JSON-RPC 2.0 spoken over stdin and stdout between a client and an agent it spawns as a subprocess. There are exactly two message shapes: methods, which are request/response pairs, and notifications, which are one-way and — the spec is explicit — "never receive responses (success or error)." That split is what lets a single prompt turn be synchronous at the outer boundary (you called session/prompt, you will get a response) while streaming an unbounded number of intermediate events without blocking.
The obvious analogy is the Language Server Protocol, and it is a good one as far as it goes: both turn an N-editors × M-implementations integration matrix into N + M, which is the structural argument the interop problem essay makes in general. Adopt the analogy for the economics and drop it for the semantics. A language server answers questions about a buffer and is fundamentally stateless per request; an ACP agent holds a long-lived, expensive, non-deterministic conversation, asks for permission mid-turn, spends money per token, and can be interrupted halfway through an edit. LSP has no concept that maps onto "the server may ask the editor for authorisation before continuing," and that concept is where most of ACP's design pressure lives.
The subprocess model is a deliberate constraint rather than an implementation convenience. Because the client spawns the agent, the client already owns the process boundary — it can set the working directory, control the environment, kill the process, and (in principle) sandbox it. A protocol over HTTP to a remote agent would have had to invent all of that. ACP instead assumes the client is the privileged party and builds every other decision on top of that assumption, which is what the next three steps are really about.
initialize: version negotiation, then capability gating.
Every connection opens with initialize, which does two jobs at once: negotiate a protocol version and exchange capabilities. Version negotiation is deliberately crude — the protocolVersion is "a single integer that identifies a MAJOR protocol version" and only increments on breaking changes. The client sends the latest version it supports; if the agent supports it, the agent MUST echo the same version back, otherwise it MUST respond with the latest version it supports. On a mismatch the client SHOULD close the connection and tell the user. There is no minor version and no feature-flag-by-version — everything finer-grained is a capability.
Capabilities are declared in two directions and the gating rule is the important part. The client advertises clientCapabilities: an fs object with readTextFile and writeTextFile booleans, a terminal boolean covering all terminal/* methods, and an auth.terminal flag for whether it can reproduce the agent invocation in an interactive terminal. The agent advertises agentCapabilities: loadSession for whether session/load exists, a promptCapabilities object with image, audio and embeddedContext booleans for content types beyond baseline text and resource links, and mcpCapabilities with http and sse transport flags.
The rule that makes this safe to implement against: "Clients and Agents MUST treat all capabilities omitted in the initialize request as UNSUPPORTED." Absence is a hard no, not a maybe — which means a correct agent degrades by default rather than probing, and an older client talking to a newer agent simply never sees the new surface. This is the same discipline the capability discovery essay describes for Agent Cards, applied at process start instead of over the network. If you implement one thing from ACP correctly, implement this: an agent that calls a method whose capability was not advertised is a bug, not a graceful fallback.
The prompt turn, and what streams during it.
Work happens inside a session. session/new creates one, anchored to a primary working directory and optionally additional filesystem roots, and carrying its own isolated context — conversation history, state, and its own MCP server connections. That last detail is where ACP and MCP compose: the client hands MCP server configuration into the session, the agent connects to those servers, and the two protocols occupy different seams without overlapping. See MCP: hosts, clients, servers for the other half.
A turn is then: the client calls session/prompt with the user's message; the agent streams session/update notifications while it works; the agent may interrupt itself to call session/request_permission or a filesystem method; the client may abort with a session/cancel notification; and finally the session/prompt request returns with a stop reason. The stop reason is the part worth designing around — it is how the client learns whether the turn ended because the agent finished, because it hit a limit, or because the user cancelled, and those three need different UI.
The session/update stream is richer than a token feed. It carries message chunks tagged by role — agent, user, and thought, which is how reasoning surfaces separately from output — plus tool calls and their subsequent updates, plans, changes to the available command set, and mode changes. Two design notes fall out. First, because tool calls arrive as updates rather than as opaque text, the client can render a real tool-call UI for any agent without knowing that agent's tool vocabulary. Second, because thought is a distinct chunk type, a client can show or hide reasoning as a display decision — and should treat it as display only, for the reasons in chain-of-thought faithfulness.
The inversion: the client owns the filesystem, and the agent has to ask.
Here is the design decision that distinguishes ACP from every "run the agent in a terminal" arrangement. An ACP agent does not read and write project files itself. It calls fs/read_text_file and fs/write_text_file and the client performs the operation. The gating is strict: if readTextFile or writeTextFile is false or absent, the agent "MUST NOT attempt to call the corresponding filesystem method."
The stated motivation is mundane and completely convincing: unsaved editor state. A developer's buffer routinely differs from what is on disk, and an agent that reads the file gets a stale copy of the thing the human is looking at — then edits it, and silently destroys the unsaved work on write. Routing through the client means the agent sees the live buffer. That alone justifies the design. But the second stated reason is the one with architectural consequences: it "allow[s] Clients to track file modifications made during agent execution." The client is not merely a proxy, it is the ledger.
Follow that through and the payoff is large. Because every mutation goes through the client, undo/redo integration, change previews, per-file diffs and selective application are all implementable once, in the editor, and they then work identically for every ACP agent — including agents whose internals you cannot see, reached through an adapter. The same inversion covers execution: terminal/* methods are gated behind a single terminal capability, so an agent that wants to run a command asks rather than spawning. And session/request_permission generalises the pattern to arbitrary tool calls — the agent cannot reach client resources unilaterally, it requests and the client decides.
This is the right place to be precise about what that does and does not buy you. It gives you a uniform, client-side policy surface, which is genuinely valuable and is the reason an editor can offer one consistent approval UX across heterogeneous agents. It does not give you containment: the agent is still a subprocess on your machine with whatever ambient authority the OS granted it, and nothing in ACP stops a determined or compromised agent from opening a file directly with ordinary syscalls. ACP's filesystem methods are a cooperative contract, not a sandbox. For actual isolation you need the mechanisms in sandboxing and code execution; ACP composes with them but does not replace them.
Where ACP stops — and the three seams it shares the stack with.
ACP has three session methods and the differences between them are easy to over-read. session/new opens a fresh context. session/load, available only when the agent advertised loadSession, reconnects to a stored session — and loading means the agent replays the entire conversation to the client as a stream of session/update notifications, responding to the original request only once every entry has been streamed. session/resume reconnects without that replay.
Read the direction of that replay carefully, because it is the most commonly misunderstood thing about ACP. The replay flows agent → client, and its purpose is to let the editor repaint a thread it does not store. The conversation belongs to the agent that produced it; the session id was minted by that agent. So ACP does not let your editor hand a Claude Code session to Codex — running both in one window gives you two agents in two threads, not one shared session. ACP standardises the socket, not the state, which is the argument developed at length in every handoff that works throws the transcript away.
Which leaves a clean three-seam picture, and it is worth holding all three at once. ACP is client-to-agent: one editor drives many interchangeable agents, and the client holds the filesystem, the terminal and the permission decisions. MCP is agent-to-tools: the agent reaches capabilities and data, configured per session by the client. A2A is agent-to-agent: delegation across an organisational boundary where the peer is deliberately opaque and returns artifacts rather than history — see A2A v1.0. They are complements, not alternatives, and a serious agent product will speak all three. The practical test for which one a problem belongs to: ask who is allowed to see the conversation. If the answer is "the thing rendering it," that is ACP. If it is "nobody outside the agent," that is A2A. If the question does not involve a conversation at all, it is MCP.