Skip to content

A2A Protocol

A2A (Agent-to-Agent) is an open protocol for agent interoperability — think of it as HTTP for AI agents. When enabled, AI Butler exposes an HTTP endpoint that other agents can call to discover its capabilities and delegate work, AND AI Butler can call external A2A peers when it decides a task is better handled by another agent.

The three things A2A enables:

  1. Delegation — an external agent hands a subtask to AI Butler, gets back a result. Or vice versa.
  2. Capability discovery — AI Butler publishes an agent card describing its tools, skills, and interfaces. Other agents query it to decide what to route.
  3. Distributed swarms — multiple Butler instances (or different A2A-compliant agents) collaborate on one task, bounded by shared safety controls.
Your AI Butler External A2A-compliant agent
────────────── ─────────────────────────────
1. User asks for something complex
2. Agent decides this would be
better handled by an external
specialist — calls a2a.delegate
3. A2A client sends POST /v2/tasks
with { task, capabilities_needed,
caller_chain, budget,
auth: Bearer <token> }
──────────► 4. Peer's A2A handler
receives the request,
checks the token,
validates depth/loop
headers, runs the task
◄────────── 5. Peer returns result +
updated budget + trace
6. Your agent receives result, merges
with its own context, returns to
user in the original chat

Every hop updates three pieces of shared state:

  • Caller chain — an append-only list of agent IDs along the delegation path. Used for loop detection.
  • Budget remaining — total USD cost across all hops, decremented at each step.
  • Distributed trace ID — OpenTelemetry-compatible trace context so you can correlate the whole chain.

A2A is off by default and binds to 127.0.0.1 (localhost only) when enabled. That’s the secure default — if you want remote peers, you bind to an external interface and put a reverse proxy with TLS in front.

configurations:
a2a:
enabled: true
port: 8081 # default
bind_address: 127.0.0.1 # default; use 0.0.0.0 for remote peers
token_hashes:
- "a1b2c3d4e5f6..." # SHA-256 hex hashes of allowed bearer tokens

Requests must include an Authorization: Bearer <token> header. The handler SHA-256s the token on every request and compares it (constant-time) against the configured hash list. Tokens themselves are never stored — only their hashes, in your config file. If an attacker reads your config.yaml, they can’t forge a valid token from the hash.

Terminal window
# Generate a 32-byte random token, compute its SHA-256, keep the hash in config
TOKEN=$(openssl rand -hex 32)
HASH=$(echo -n "$TOKEN" | shasum -a 256 | awk '{print $1}')
echo "Give this to your peer: $TOKEN"
echo "Paste this into config: $HASH"

Restart AI Butler — the new hash takes effect. You can rotate tokens by replacing the hash list and restarting.

Agent card — what A2A peers see when they look at you

Section titled “Agent card — what A2A peers see when they look at you”

Every A2A agent publishes a card describing itself. AI Butler’s card is generated at runtime and reflects the actual current state of the instance:

{
"name": "Butler (Sam's desk)",
"description": "Personal AI assistant — self-hosted AI Butler v0.1",
"url": "https://butler.example.com/a2a/v2",
"version": "0.1.0",
"capabilities": [
"memory.read",
"memory.write",
"schedule.manage",
"iot.sensor.read",
"channel.send"
],
"skills": [
{ "name": "morning-briefing", "description": "Generate a daily briefing" },
{ "name": "weekly-report", "description": "Summarize the week from memory" }
],
"auth_schemes": ["bearer"],
"streaming": true,
"updated_at": "2026-04-11T14:00:00Z"
}

The card respects the MCP server exposure allow-list (configurations.mcp_server.allowed_capabilities). If you restrict MCP to memory.read and data.read, those are the only capabilities advertised on the A2A card. Peers can’t discover tools you’ve chosen not to expose.

Fetch your own card to verify:

Terminal window
curl http://localhost:8081/a2a/v2/card \
-H "Authorization: Bearer $TOKEN"

Swarm safety controls (shared with local swarm)

Section titled “Swarm safety controls (shared with local swarm)”

A2A delegation is bounded by the same safety controls as local swarm — see the Swarm page for the full list. Short version:

configurations:
swarm:
enabled: true
max_depth: 4 # max delegation hops
budget_usd: 5.0 # total cost cap across all peers
workspace_ttl_hours: 24
ControlHow it helps with A2A specifically
Depth limitPrevents unbounded A→B→C→D→E chains across peers — you can’t end up in a 50-hop delegation graph with runaway cost
Loop detectionThe caller-chain header lets the handler detect when a peer tries to delegate back to an agent already in the chain (A→B→A). The request is refused with HTTP 409.
Budget capTotal USD cost across all peers, not per-peer — a single budget that spans the entire delegation chain
Trace propagationEvery hop carries a trace ID so you can correlate logs across peers post-hoc

When configurations.registry.self_register: true, AI Butler publishes itself to a central A2A registry at startup and refreshes its health status every health_ttl_minutes:

configurations:
registry:
self_register: true
health_ttl_minutes: 5

Other agents in the same registry can discover AI Butler by capability — e.g. “find me an agent that provides memory.search. The registry itself is just an HTTP service that speaks a simple discovery protocol; you can run your own or use a community one.

The registry is beta-within-beta for v0.1 — the client code is there, the discovery API is defined, but we haven’t validated it against a running registry with multiple peers. If you operate an A2A registry, reach out.

AI Butler’s A2A implementation is designed for compatibility with Google’s A2A v2 spec. The handler covers:

  • POST /v2/tasks — inbound task delegation
  • GET /v2/card — agent card discovery
  • GET /v2/tasks/{id} — task status polling
  • POST /v2/tasks/{id}/cancel — task cancellation
  • Bearer token auth with SHA-256 hash comparison
  • Caller-chain header propagation
  • Loop detection on inbound requests
  • Budget-aware task execution

What’s not yet validated:

  • Formal conformance suite run against the Google A2A reference implementation
  • Interop with at least 3 external A2A-compliant agents
  • Streaming response support for long-running tasks (handler accepts streaming requests but returns non-streaming responses)

All of these are on the v0.2 milestone. If you’re building an A2A peer and want to run interop tests, open an issue — we’ll fast-track it.

Practical setup — two Butlers talking to each other

Section titled “Practical setup — two Butlers talking to each other”

The easiest way to test A2A end-to-end today is two AI Butler instances on the same LAN:

Instance 1 — butler-home.local:8081

configurations:
a2a:
enabled: true
port: 8081
bind_address: 0.0.0.0
token_hashes:
- "<sha256 of butler-home's own token>"
- "<sha256 of the token butler-office gave you>"
registry:
self_register: true

Instance 2 — butler-office.local:8081

configurations:
a2a:
enabled: true
port: 8081
bind_address: 0.0.0.0
token_hashes:
- "<sha256 of butler-office's own token>"
- "<sha256 of the token butler-home gave you>"
registry:
self_register: true

Once both are running, ask butler-home something that references work-context: “check with my office Butler for any pending action items”. The home Butler will call a2a.delegate to butler-office, which runs the task and returns a result. Both audit trails record the delegation for accountability.

  • Formal conformance testing against the Google A2A reference suite
  • Live interop validation with published partners + screenshots on this page
  • Streaming response support end-to-end
  • Registry federation — multiple registries, peer gossip, trust levels
  • Signed agent cards — cryptographic verification of peer identity beyond bearer tokens

The single highest-impact contribution is interop validation with a non-Butler A2A peer. If you’re building an A2A-compliant agent (or know someone who is), run a bidirectional delegation test:

  1. Generate a token pair and exchange hashes
  2. Delegate a simple task from your agent to AI Butler (e.g. “save this fact to memory”)
  3. Delegate a simple task from AI Butler to your agent
  4. File an issue with what worked, what didn’t, and any spec deviations you spotted

A dozen interop reports across different implementations is the fastest path from beta to ready for v0.2.