Technology · Protocol

Agent Client Protocol (ACP)

I built agents that speak the Agent Client Protocol so coding assistants can be driven as governed workers rather than chat windows.

AgentOS · Agent SwarmCross-vendor agent wireJSON-RPC 2.0, signed extension
One envelope · a standard body · a signed extension
ACP body · JSON-RPC 2.0any ACP peer can still parse it
Extensioncanonical hash · RS256 JWT in the sender's own key
Delegation depth · one cell per hop
a chain in flight
up to the default limit
up to the hard ceiling
  • 25hard ceiling on delegation depth; a persona configured deeper is refused
  • 4checks on every receipt: audience, issuer, hash and call chain
  • 2transports for the same envelopes: stdio and Redis streams
  • 7typed endings in the delivery adapter besides acceptance

ACP is the seam between my governance platform and the vendors' own tools.

A signed wire for agents that delegate to agents

Agent Swarm lets agents delegate to one another, and a receiving agent has to know who really sent a request, on whose behalf, and that the chain of delegation is not looping or growing without end. I did not want a home-grown protocol for that. I adopted the Agent Client Protocol, which is JSON-RPC 2.0, as the cross-vendor agent protocol and locked the choice into the runtime's master plan; I did not author ACP, I use it and extend it.

ACP runs over stdio for agents started as subprocesses; between long-lived agents the same envelopes travel on Redis streams, and synchronous calls go through the orchestrator over HTTP.

stdioparent to subprocess
Redis streamslong-lived peers
HTTPsynchronous
orchestrator
Each block is one envelope; the same envelope travels all three. Spacing is illustrative.

On top of the standard body I added an extension: each envelope is canonicalised and hashed, signed as an RS256 JWT with the sending agent's own key, and checked on arrival.

A clean envelope
audienceissuerhashcall chain
A body altered in transit
audienceissuerhashcall chain

The extension keeps the base protocol standard, and the wire contract is a small crate with no I/O and no business logic, with signing in a separate crate, so the protocol stack can leave the estate on its own.

Delegation bounded on every receipt

The chain check enforces a depth limit for each persona, ten unless the persona sets its own, under a hard ceiling of 25 that no persona can raise; a limit of zero forbids peer calls entirely. It also rejects any chain in which the same job and action appear twice.

A chain within its persona's depth
Ajob 7 · plan
Bjob 7 · search
Cjob 7 · summarise
A chain that loops, refused
Ajob 7 · plan
Bjob 7 · search
Ajob 7 · plan
default depthhard ceiling
Job numbers and agent letters are illustrative.

Confused-deputy calls and runaway delegation are the failure modes that matter when language models call each other, so bounded delegation is a protocol rule rather than a convention, checked by every receiver.

I put identity and delegation limits into the wire itself.

Journalled before it is streamed

Messages whose loss would corrupt agent state are written to PostgreSQL before they go on the stream.

On the stream alone
Heartbeatsfire and forget; losing one costs nothing
Journalled first, then streamed
  • Approvalsjournal
  • Gatekeeper decisionsjournal
  • Sub-agent resultsjournal
Trimming a stream cannot lose anything that carries state.

A trace id in every envelope lets an operator join the journal with the audit log and find the first message that was never acknowledged, across hosts.

Typed endings for a vendor's coding tool

AgentOS drives vendors' own coding tools as governed seats, and ACP is one way it hands them work. For a third frontier family I built a bounded delivery adapter. It reports acceptance only when the vendor's own queue notification comes back carrying the prompt id the adapter chose, because a prompt that was written to a pipe has not yet been accepted by anything.

launch
spawn failure
negotiate
unsupported version · initialise rejected
load session
session load rejected
write prompt
prompt rejected
my prompt id returns
output limit · process ended

The adapter leaves the vendor's own session socket alone and talks only through the supported bridge. Adding a vendor follows a runbook that keeps provider names out of central code and needs no schema migration.

A gatekeeper for sensitive operations

The same signed messaging carries the gatekeeper pattern, in which a worker asks a trusted agent to perform a sensitive operation instead of holding the credentials itself.

worker
a coding agent with no repository credentialsthe git gatekeeper holds the keysthe repository

The git gatekeeper that opens merge requests for coding agents is the example in use, told in A coding agent that never holds the keys.