15 min read

What Is a Local Agent Bridge? Transport and Auth Rules

A local agent bridge lets a browser extension, Slack bot or CI runner call a coding agent on your machine. Here is what decides the transport.

I spent an afternoon trying to get a Chrome extension to talk to Claude Code running on my own laptop. Not a hosted API. The actual agent, with my repository and my notes in scope. The problem turned out to be more interesting than the solution, because the answer was never really about HTTP.

A local agent bridge is a small HTTP service that lets a sandboxed client invoke a coding agent running on the same machine, with that machine's files and memory in scope. It matters because the clients people actually work in, browsers and chat apps and CI runners, cannot reach local context on their own. It differs from calling a hosted model API in that the context never leaves the machine.

One local agent bridge at the centre of the frame, joined by connecting lines to six spokes: a browser extension, a Slack bot, a CI check, a phone shortcut, a Raycast command, and a sixth spoke drawn with a dashed border and labelled whatever you build next, which adds that the bridge does not care what calls it, showing that a single bridge serves every client you already work in while the agent and its context stay on your machine
One local agent bridge at the centre of the frame, joined by connecting lines to six spokes: a browser extension, a Slack bot, a CI check, a phone shortcut, a Raycast command, and a sixth spoke drawn with a dashed border and labelled whatever you build next, which adds that the bridge does not care what calls it, showing that a single bridge serves every client you already work in while the agent and its context stay on your machine

Table of Contents#

What is a local agent bridge?#

A local agent bridge needs exactly three pieces to do its job. A loopback HTTP listener that answers only requests originating from the machine it runs on. A way to invoke the coding agent headless, meaning without a terminal attached, so a single request can start it, wait on it, and collect whatever it produces. And a way to hand that invocation context the agent would not otherwise have: the repository on disk, the conventions a team has settled into without writing them down, whatever memory the agent has been keeping between sessions.

None of those three pieces is exotic by itself. A loopback listener is a handful of lines in any HTTP framework. Headless invocation is exactly what a CI runner already does to a CLI tool it never opens a terminal for. Handing over context is mostly reading files off disk and writing them into a prompt. I built a version of this scaffolding once for a project that needed to survive across sessions rather than start over each time, and the harness that carries state between runs turned out to be more of the actual engineering than the agent itself, a lesson I wrote up in more detail in a piece about giving an agent a scaffold that outlives any single session. That lines up with a pattern I keep running into: the harness wrapped around the model tends to matter more than the model does, and a local agent bridge is a harness decision before it is anything else.

I built one of these so a Chrome extension could draft LinkedIn replies in my own voice, reading from notes that live only on my laptop. That extension is the worked example for the rest of this post, and it is the least interesting part of it. What matters is that the bridge does not know or care whether a request came from a browser extension, a Slack bot, a CI job reviewing a pull request, or a phone shortcut typed on a train. It answers the same way regardless. The client is disposable. The bridge, the local files, and the memory sitting on your machine are not.

Why can a browser extension not just call the agent directly?#

A browser extension cannot spawn a child process. That is not a limitation someone chose for the sake of caution, it is what the sandbox is for. Browser extensions run inside a process boundary designed explicitly to stop arbitrary code from reaching the filesystem, the network stack, or another process on the machine, because the entire threat model of a browser is that it will load code from strangers on the internet and run it. Loosening that boundary so an extension could fork a subprocess would undo the one guarantee that makes browsing safe in the first place.

So the sandbox is not a network problem, even though it looks like one. The symptom is "my extension cannot reach my agent," and the instinct is to reach for a port and a fetch call. But the actual boundary is a permission problem enforced by the browser's process model, not a routing problem enforced by a firewall. A Slack bot hits the identical wall for a different reason: it runs on Slack's infrastructure, not yours, so it has no filesystem to spawn a process into even if its runtime allowed it. A CI runner hits the wall in yet another shape: it runs on a machine, but not the machine that has your repository and your notes on it. A phone hits the wall for the most basic reason of all, it never had a process to spawn from.

A coding agent boxed on your machine holding your repository, project memory, conventions and unfinished work, with a broken red barrier separating it from a browser extension, Slack bot, CI runner and phone that are all marked blocked, illustrating that a sandbox is a permission problem rather than a network problem
A coding agent boxed on your machine holding your repository, project memory, conventions and unfinished work, with a broken red barrier separating it from a browser extension, Slack bot, CI runner and phone that are all marked blocked, illustrating that a sandbox is a permission problem rather than a network problem

A hosted model API has none of your local context, and shipping that context to a hosted API is the thing you were trying to avoid in the first place. The repository on disk, the conventions nobody wrote down but everyone follows, none of it exists anywhere a hosted endpoint can read unless you upload it on every single call. That upload costs twice: once in the tokens spent reconstructing context a local agent already keeps in memory, and once in the fact that the data just left the machine you built the bridge to keep it on. A context card compiled once and reused rather than rebuilt on every call is cheaper and safer than a fresh payload sent to a server you do not control. A local agent bridge exists because the agent, the files, and the memory were already on your machine before you asked the question, and routing through a hosted API throws that advantage away.

What decides whether you need authentication?#

The rule is not really a choice you make. The trust boundary between your client and the agent's process picks the transport for you, and you do not get to decide which side of that boundary your client lands on, because that decision was already made by whoever built the client. A CLI tool that spawns the agent as a subprocess inherits the operating system's process boundary as its authentication, for free, before anyone writes a line of bridge code. A browser extension, a Slack bot, or anything else that cannot spawn a child process has to cross a real network boundary instead, and a network boundary needs something to authenticate it, because unlike a process boundary, nothing about an open socket tells you who opened it.

Where the client sitsTransportWhat authenticates itExamples
Same sandbox as the agentChild process, JSON-RPC over stdioNothing. The operating system process boundary is the authenticationZed ACP, MCP over stdio
Different sandbox, same machinelocalhost HTTPWhatever the project invents, and the defaults disagreeMCP Streamable HTTP, LM Studio, a browser extension bridge
Different machineHTTPSReal credentials, revocation, transport securityAny hosted agent API

That table is the whole decision tree collapsed into three rows. Drawn out as a branch, the same rule looks like this:

A branch diagram asking one question, can your client launch a child process, annotated with the note that you do not answer this because your client already did, splitting down two drawn paths into determined outcomes: yes it can leads to a child process over stdio with JSON-RPC, no token, no port and no CORS because the process boundary is the authentication, while no it cannot leads to localhost HTTP where you bind loopback only, invent your own token and check the Origin header yourself
A branch diagram asking one question, can your client launch a child process, annotated with the note that you do not answer this because your client already did, splitting down two drawn paths into determined outcomes: yes it can leads to a child process over stdio with JSON-RPC, no token, no port and no CORS because the process boundary is the authentication, while no it cannot leads to localhost HTTP where you bind loopback only, invent your own token and check the Origin header yourself

How does Zed's Agent Client Protocol avoid authentication entirely?#

Zed's Agent Client Protocol sidesteps the authentication question by refusing to ever cross the network boundary that would require it. ACP defines a wire format for editor and agent to talk to each other over stdio, the same pipe a parent process already shares with a child process it spawned, so the identity check already happened before the first message was sent. According to the Agent Client Protocol transport specification, messages "are delimited by newlines (\n), and MUST NOT contain embedded newlines." That is a small, almost boring detail, and that is the point: when the transport is a pipe between a process and the child it spawned, the protocol only has to worry about framing messages correctly, not about who is allowed to send one.

The project has a specific timeline worth being precise about, because it is easy to compress into one date. The agent-client-protocol repository was created on 23 June 2025. The agentclientprotocol GitHub organization that now hosts it followed more than three months later, on 30 September 2025. Those are two different milestones, a repository existing and an organization forming around it, and treating them as the same date erases the three months between the protocol existing and the protocol getting an organisation of its own.

The tradeoff is that ACP only works when your client can spawn that child process in the first place. An editor like Zed can. A browser extension cannot, which is exactly the wall from earlier in this post. ACP is the "yes it can" branch of the fork diagram above, not a way around the fork itself.

Why do the local agent servers disagree about defaults?#

Landing on the network side of the boundary settles the transport, not the defaults. What is still undecided is what the projects sitting on that side actually do once a client shows up, and that is a coordination failure across projects, not the boundary mechanism itself. The disagreement between them is real, not a matter of one project being wrong and the other being careless. The Model Context Protocol transport specification is explicit. Servers must validate the Origin header on every incoming connection to prevent DNS rebinding, should bind only to localhost rather than all interfaces, and should authenticate every connection. That is a specification written by people who assumed a hostile network from the start and built the default posture around refusing anything unverified.

LM Studio's documentation takes the other position: "By default, LM Studio does not require authentication for API requests." Authentication is a toggle in Server Settings, and it is off until you find it. That is documentation written by people who assumed a trusted local machine and built the default posture around not making a developer do anything extra just to get a request answered.

Neither position is wrong, and that is the actual problem. There is no single standard that every local agent server implements, so each project decided independently, weighing convenience against caution in whatever proportion its authors found reasonable. A reader building a bridge on top of any one of them inherits that project's decision, not some industry default, because no such default exists across the category. The fix is not memorizing which project picked which posture. It is reading the actual documentation for whichever server a bridge is pointed at, every time, because the last project checked tells you nothing about the next one.

What can you actually build on this?#

A local agent bridge turns whatever sandboxed client is at hand into something that can act on the actual state of a repository, not a stale copy of it. A Slack bot can answer from the repository itself rather than a vector store nobody remembered to refresh. A CI check can review a diff against a team's real conventions, the ones written down nowhere except in the codebase. Someone standing in a grocery line, nowhere near a laptop, can trigger a phone shortcut that drafts a reply from the machine's own context. A two-keystroke Raycast command can carry a project's memory into its answer the same way a terminal session would. Four possible clients, four sandboxes, one bridge behind all of them, indifferent to which one is asking. Build the bridge once, and every new client that shows up gets the same repository, the same conventions, and the same memory, without a single line changed on the agent's side.

The Slack bot and the CI check in that list are not exempt from the constraint that opened this post. Slack hosts the bot's code, not you, so whatever actually talks to the bridge cannot live inside Slack's infrastructure. What gets deployed to Slack has to be a thin relay that forwards the request to a listener running on the same machine as the bridge, or the bridge has to be exposed through a tunnel, and the moment it is reachable through a tunnel it has left the localhost row of the earlier table and needs the credentials and transport security the different-machine row demands. Either way, the boundary decided this too.

That is the actual shape of the pattern this post has been circling. Not a Chrome extension that drafts LinkedIn replies, that is one client among many and it happens to be the one built first here. The pattern is a coding agent that already knows a repository, sitting on a machine someone controls, reachable by whatever sandboxed thing they decide should be able to ask it a question next. How one actually gets built is the next question, and what broke the first time it met a real caller is the one after that.

FAQ#

Is a local agent bridge a security risk?#

It is a network service listening on a machine, so it carries the same risk any local server carries: bind to loopback only, validate the Origin header rather than trusting a request because it looks local, and add real authentication rather than assuming the localhost address is protection enough on its own. The risk is not unique to this pattern. It is the standard local server risk, and the fix is the standard local server fix.

Does the Model Context Protocol already solve this?#

MCP solves a related but different problem. It standardizes how an agent calls tools and reads resources, not how an outside client reaches the agent itself. A local agent bridge sits one layer up from MCP. MCP operates on the agent's side of the boundary, deciding what the agent can do once it is already running, while the bridge is what lets something outside that process ask the agent to run at all.

Does this pattern require Claude Code specifically?#

No. The three pieces, a loopback listener, headless invocation, and context handoff, describe the shape of the bridge, not a specific vendor. Any coding agent that can be invoked without a terminal attached and can be pointed at a working directory can sit behind the same kind of bridge.

What happens if the agent is not running when a request comes in?#

The bridge has to decide that for itself, because nothing about the pattern guarantees the agent is already warm. The two honest options are to fail fast with a clear error the client can surface to a user, or to spawn the agent on demand and accept the latency of a cold start. Silently queueing a request against an agent that may never start is the option worth avoiding.

Does the context ever leave the machine?#

Not in the pattern described here. The entire argument for building a bridge instead of calling a hosted API is that the repository, the notes, and the memory stay exactly where they already are. If a request eventually needs to leave the machine, for a hosted model call the local agent itself decides to make, that crosses a different boundary than the one this post is about, and it deserves its own separate scrutiny.

Do I need an editor like Zed to use the Agent Client Protocol?#

Something that can spawn the agent as a child process is required, which is what ACP assumes throughout. Zed does this because it is an editor with that capability built in already. Anything else with the same capability, a custom CLI tool, a different editor, a script that forks a subprocess, could use the same transport for the same reason.

Share:

Stay in the loop

New posts on AI engineering, Claude Code, and building with agents.