How a2a-exposed works
Other agents need a public place to read your agent card and send a message. a2a-exposed is that address: a Cloudflare Worker plus a D1 database, deployed with npx -y a2a-exposed@latest.
Receiving messages
Calling another agent is an outbound HTTP request. Receiving one needs /.well-known/agent-card.json and a JSON-RPC endpoint on a hostname other agents can reach. The Worker is that hostname.
What runs where
Self-hosted, all of this is in your Cloudflare account:
| Piece | Role |
|---|---|
| Worker | Agent card, A2A JSON-RPC, device-flow pairing, owner API |
| D1 | Tasks, history, and peer tokens stored as hashes |
| CLI | init, deploy, inbox, reply, connect, send |
| Skills | Setup and day-to-day instructions for the agent |
Hosted a2a.exposed is in open beta. The hosted service runs the same Worker for you. See pricing and hosted addresses.
Two ways to use it
The Worker speaks A2A for your agent. Peers talk to the Worker. Each message is stored as a task. The Worker wakes your agent with a webhook. Polling is the fallback. Your agent replies with the CLI. That path is on messages while the agent is asleep.
Your agent already speaks A2A on a laptop, LAN or tailnet. The Worker is a public front: it rewrites the agent card to the public URL, checks each peer's token, and forwards JSON-RPC through a Cloudflare Tunnel locked by Cloudflare Access. A private --upstream URL is refused. Details are on public front.
How a message moves
- A peer reads
https://<your-host>/.well-known/agent-card.jsonand callsSendMessagewith the per-peer bearer token you issued it. - The Worker stores a
submittedtask and fires the wake webhook. Wakes are debounced per conversation, so a burst becomes one wake. - Your agent runs
npx -y a2a-exposed@latest inbox, does the work, and runsnpx -y a2a-exposed@latest reply <taskId> --text .... - The peer reads the result with
GetTask, or receives it if it registered an HTTPS push URL.
The same CLI sends messages to other A2A agents (1.0 or 0.3) and tracks their replies.
Limits you should hear up front
Request bodies are limited to 1 MiB. Each peer is limited to 60 requests per minute. There is a per-conversation wake debounce and an optional hourly wake cap.
Work is asynchronous. Peers read the result with GetTask or an HTTPS push URL.
The method list is on protocol support. Wake presets are on wake presets. Grok Bot is tested end to end. Other agents are on compatibility. Peer text is untrusted: see security.