Introduction0:00
I'm Bennet, I work at Zed, and we built like an AI code editor, all written in Rust. And last year was kind of, as you probably all know, the rise of the AI coding agent terminal user interfaces, with every major model provider like building Claude Code, Codex, Gemini, CLI, and so on.
And so at Zed we asked ourselves, like, how can we let users bring their agent of choice to our tool and enjoy, like, a nice interface that is unified across all of them? And so that's why we decided we need some type of protocol called Agent-Client Protocol, which is similar to, like, MCP or LSP.
It's a JSON-RPC-based protocol, and the idea is basically that agents and clients can talk to each other through a unified interface. And, yeah, the it's, yeah, online, it's open source, you can contribute if you want. At this point we have a wide variety of agents already supporting this, either by, like, an adapter that kind of, like, translates the agent's native language to the ACP one, and then we have, like, for example, OpenCode and Cursor having, like, ACP mode built into their, like, CLI agents.
And we also have a bunch of clients, at this point up to 40, that implement this, including OpenClaw, for example. Like, OpenClaw itself is a client and a server, actually, like a client and an agent. And JetBrains, and Obsidian, and other people are supporting this.
Great. So I'm going to do a live coding session. Let's see how well that goes. So.
Live Coding1:55
Really courageous.
Right. Basically, we have some pre-existing code. So this is Zed. Here I have some TypeScript code. Also, bear with me, I'm a Rust developer. I have basically zero clue about TypeScript, so if you see anything that you don't do in TypeScript, tell me afterwards.
But yeah, like, here's a very minimal coding agent that just doesn't support ACP, but it's kind of the bare minimum you need to, like, build a coding agent. So all it has is really like two tools: one to read a file, and one to edit an existing file.
Yeah, this is, like, pretty basic. It provides the model has to provide a path, then it has to provide an old text that is, like, then just replaced with new text, and that's kind of everything. And then we have, in this case, like, I'm using Anthropic.
There's a way to prompt the agent
with, yeah, the user can prompt the agent, which is the function that we're going to call here. And then we enter the agent loop, and this is kind of like the way all agents basically work, is the model APIs are stateless, so you just attach some, like, conversation up to this point.
You call the endpoint, in this case it's like the Anthropic API. And then we, yeah, we get, like, a message from the model, and either it can be, like, an end turn, that means, like, the model decided to, yeah, just output some text and do nothing, or it can call a tool.
And in this case it would be, like, a read or a write tool call. And then in the case of a tool call, we, like, run the, for example, the edit file tool call locally, collect a result, and then send it up to the model again.
That's where this loop. And then we call the API again with the conversation up to that point, and that's kind of everything. And then we have, like, these, this, like, handle tool call function here, which, yeah, handles, like, read and write tool calls, which does what you expect.
We get the path, we read it from the file system, and we return some, some result. Right. So now the question is, how do we make this thing ACP compatible? And hopefully we can do it in 10 minutes.
ACP Integration4:13
So let's see. So, yeah, I have some boilerplate here. In this case I'm using the TypeScript SDK, as I said. And the way this works, you implement the agent interface provided by this library, and then you have to, at minimum, implement these three, four functions.
So the first one that we're looking at is kind of this initialize here. All we really have to do here is, like, respond with the protocol version we support, which in this case is just the latest. There's also, like, some capabilities, like client, and the agent can itself advertise capabilities of stuff it supports.
But we're building a very minimal coding agent, so we don't support anything outside that's necessary, I guess. And then for us, like, authentication is irrelevant since it's just using my API key from an env var. And then there's this concept of sessions in ACP.
So basically every time you start to write in Zed or in a different editor or client, you call a new session. And in a session you can prompt, and then, yeah, from there on you can, like, get your output.
So all we really do here is, like, we generate a random ID,
then we instantiate this coding agent with the current working directory, which we get from the client. We store it in our internal map, and then just return the ID to the client so that the client knows, yeah, knows the ID.
And that is kind of then used inside prompt, because what prompt does in this case, it, like, prompt, the prompt request, if we go to the definition here, all this is kind of doing is, it provides a prompt, which is an array of content blocks that can be, like, text, images, whatever, the session ID for reference.
And so all we kind of have to do here is, yeah, we look it up in our internal state, we get the relevant agent for that current session. And then I have a helper function here, which just, in this case, ignores everything that's not a text because we don't support images and stuff like this.
And then we call this, like, prompt function I showed earlier, which then runs the tool calling loop. And so then just, like, as a nice-to-have feature, we also support cancellation. That's also pretty, pretty simple. So these are kind of, like, the four minimal things we have to implement.
And I have this hooked up in Zed just by, there's no special code. All I have is kind of, like, I tell Zed there's some ACP compatible agent and you can run it with Node and then my path to that agent JS file.
So when I, let's do that in here as well. So when I run, I'm going to build, I'm going to build,right, and then I'm going to restart, yeah, launch a new ACP demo agent. And you can see if I ask it for something, you can see wait indicator, and now it's done.
So nothing.
Okay.
Which is what we expect,right? Because, like, what we can see here, if I go over, oops,
if I go over here, we have some kind of, like, ACP debug view in Zed, so to make it easier for us to develop. And you can see, like, Zed sends a session new request. We respond with a session ID.
And as soon as I type in something,
we get prompt. And now we got a stop reason,right? So these red arrows come from the, from the adapter that we are building from the agent, but it's not outputting tokens,right? Like, behind the scenes it's obviously, like, Anthropic is giving us tokens, but how do we make them show up in Zed?
Streaming Output7:54
So that's the next thing that we, yeah, want to focus on. So the first thing that we kind of need to do, like, our coding agent itself needs to have a way to
send something over to the connection. So what we're going to do here is, like, the coding agent is going to take the ACP connection and then also the session ID. And then inside here we have to provide this connection and the ID.
And then if we go, okay, I'm just going to close this. Right. If we go back here, now inside of prompt, Anthropic, like, this is the Anthropic SDK. So in this case, like, in, oops, you can just use this, like, stream on, yeah, that's like an Anthropic SDK.
Like, you can react to a text event. So every time we basically get a chunk, we send this kind of what ACP calls a session update. As I said, a session is like a single thread or a conversation, and then you can send updates, kind of like notifications to the client that are not, like, a usual request response,right?
It can happen at any time and the client reacts to it. And so here we are associating with the session update with a session ID. And then this, like, there's a type of session updates. There are multiple. We will see more in a second.
But this agent message chunk is just like, okay, hey, here's some new output from the model. And so if we build again, we go back to Zed. I'm going to have to restart the agent. I go here and I say, hello.
Hello, hello. Well, here's Opus talking,right? You can see, like, we're streaming in these individual
chunks,right,right, that we got from Anthropic. So, so far, so good. Let's hope the demo gods stay with us. Right. So that's one piece. The next thing, though, is, like, I want to, like, it's a coding agent,right? It's supposed to edit code.
So I can actually tell it already, because we have tool support,right? I can tell it to read, for example, this, like, helpers.ts file, and it's going to give me, if the Wi-Fi isn't too slow, it's giving me a description of what this file actually contains.
File Operations10:24
Like, if you look here, that's basically the description of the file. But again, you don't see it in the UI,right? So now we need to emit more session updates, similar to, like, what we did for text. So if we actually go towards the read file, kind of what we need to do here is, like, the way it works usually in ACP, like, you emit an initial tool call update, which I'm going to paste in here.
So, yeah, again we're emitting a session update. In this case, it's a type of tool call. And then there are multiple properties we can specify. For example, like, the title, kind of some kind of metadata that Zed uses, for example, for, like, yeah, using some icons and stuff like this.
And then we indicate that the status is in progress. And you can also, like, associate tool calls with, like, actual
locations. And so now we're signaling over ACP that something is in progress,right, this tool call. But then we also want to, at the end, like, once the tool call has finished, like, at the bottom here, we kind of want to send another update.
And in this case it's not tool call itself, but it's a tool call update. So you have to emit on the agent, you have to emit, like, a tool call, like, session update of type tool call. And then once, once the client knows about it, you can emit updates for that.
And this is the way that we set the status. And we can also return the content.
And then one additional thing that I'm going to do here is the, instead of, like, you can see here we're calling, I guess it's a bit hard to see, but, like, here we're calling FS read file,right? So we're just using the native file system APIs.
But ACP actually proxies the file system too. Like, the client can provide a file system capability, and if it does, we can, like, proxy those file system tool calls over ACP. And it kind of makes sense, for example, for an editor,right?
You want to, if I have unsafe chains in my buffer, they're not actually on the file system, but the agent should still see them. So that's why we call this, like, read text file over ACP. And so now if we go back here
and hit npm run build, and then go back here,
restart, and say read
this file. Oops, not Rust.
Then we should be seeing,
yeah, so now we see read tool calls,right? Okay, something is going wrong because everything is duplicated.
Yeah, but, like, here you can see the output of the actual file. And because I think I'm low on time, we're going to basically going to do the same for edit file.
And I'm going to compile again.
And if I again restart
and say add a comment at the top of
agent source agent.typescript, then you're going to see,
hello world is good.
Hopefully Opus is going to decide to add hello world at the top of the file. And we actually get a diff here because over ACP we send, like, a diff of the file. Okay.
Is it mitigating the first few tokens?
Yeah, I think there's something going wrong with the connection. I'm, yeah, yeah, no time to debugright now. Sorry. Am I out of time or do I still have?
Um,
let's have a look.
Scratch on.
Okay, maybe, like, we can see. So now that, okay, just another minute. Now that the coding agent supports reading and writing files, we can actually.
Agent Bootstrapping15:01
About five minutes.
Oh, great. Okay, then I don't need to rush. Now we can kind of bootstrap the agent itself,right? Like, the coding agent supports reading and writing files. I can just ask it, I prepared a prompt here, to add a terminal tool to itself,right?
Let's see how this works out with, like, the duplication we're seeing. But basically I'm telling it something about the ACP APIs. And there's some, there's some APIs in ACP which also, that's another, like, capability of the client where the client can
advertise that it supports creating terminal and managing terminals for the agent. Like, the agent can also do it itself, of course. But it's a nice way for us to add some more interactivity. And so the agent here decided to add a new tool description.
Now it, yeah, I'm vibe coding basically this terminal tool. And let's see if it actually builds. It does. Well, that's good. And then again, I'm going to restart the agent. I'm going to run our demo agent. And I'm going to ask it to run sleep 5 ls.
Let's see. There you go. You can see a terminal running. Sleeping five seconds. There's the output. And there's, yeah, and that's it basically.
Thank you.
Yeah, so that's how you kind of build an ACP compatible coding agent in 15 minutes or so. Yeah, if you want to check it out, just go to agentclientprotocol.com. In case anyone wants the demo code, but please don't use it in production.
Wrap-up & Q&A16:45
It's all agent generated. It's not uploaded yet, but it's an empty repository. I'm going to upload it in a second. Yeah, thank you for listening. Happy to answer questions.
That's it. Yeah.
How does it handle the diffs? Is it only on the client side or?
The diffs, yeah, we have, like, in, in ACP there are multiple content types and one content type is diff. And so the agent sends old text, new text, and then Zed does the diffing for you. Yeah. Yeah. Cool.
Do I need to go or can I?
One more.
Okay, one more question. Yes.
So the connection, is it all local host between?
Yeah, the connection works over standard IO. There are some folks, I think from the JetBrains people, are working on, like, remote transport, which we're going to have soon, I think. So, yeah. Butright now it works over standard IO.
Yeah.





