A2A defines a data model, a set of operations, and three bindings for agents that cannot see inside each other, and leaves everything inside an agent to the implementation.
Your planner needs the unit tests of payments-api run at commit 9f3c2e1. The test-runner agent does that job on port 41241, in a container the platform team owns. You cannot import it as a function. You can only send it a request and read what comes back.
The specification describes such agents as independent AI agent systems whose insides can be hidden {{spec §1}}. When you finish this section, you can name the three layers, state the core rules, and say where A2A stops.
Three layers in the specification
The specification has three separate layers {{spec §1.3}}.
Data model: what the records are. Layer 1 defines them as Protocol Buffer messages {{spec §1.3}}, and the proto file is normative {{spec §1.4}}.
Operations: what a client can ask for. Layer 2 describes the eleven RPCs of A2AService {{proto A2AService}}, apart from the protocol that carries them {{spec §1.3}}.
Bindings: how the bytes travel. Layer 3 maps the operations onto JSON-RPC, gRPC, and HTTP+JSON {{spec §1.3}}.
A client first reads the AgentCard, usually at /.well-known/agent-card.json {{spec §8.2}}, with a plain GET that is none of the eleven operations. The card of test-runner lists /a2a/jsonrpc and /a2a/rest, and figure stacks the layers behind them.
Below the dashed line, test-runner builds what the protocol leaves open: an HTTP router, a request handler, a task store, and an event broadcast. The §1.3 diagram lists a Get Agent Card operation that §3.1 never defines (conflict D25), and §1.4 misnames the proto path (conflict D15).
Original source
id: fig-spec-layers
kind: layers
title: the A2A stack for test-runner
claim: A2A defines the card, the bindings, the operations, and the objects, while test-runner's server parts and agent logic below the dashed line belong to its owner.
caption: Read from the planner down. Above the dashed line sit the three layers of spec §1.3 with test-runner's real paths from the captured agent cards. Below it are the kit's own parts, and dashed boxes mark what a production agent adds.The core rules
An agent is opaque: agents work together without sharing their internal reasoning, plans, or tool code {{spec §1.2}}, so a client sees only what comes back.
The server chooses the reply: a message gets either a new Task or a direct Message in reply {{spec §3.1.1}}. The direct reply suits a simple exchange, and SendMessage shows both.
The server owns the task: a client cannot supply the taskId of a new task {{spec §3.4.2}}, and the client mints only the messageId {{proto Message}}.
A task is in one of nine states: status.state holds one TaskState value {{proto TaskState}}, four of them terminal and two interrupted. Task, TaskStatus, and TaskState lists all nine.
A terminal task does not change: no message moves it again, as CancelTask and terminal states shows.
Original source
label: the end of a task
source: spec §3.1.1
---
A task in a terminal state takes no more messages. The terminal states are `TASK_STATE_COMPLETED`, `TASK_STATE_FAILED`, `TASK_STATE_CANCELED`, and `TASK_STATE_REJECTED`.Artifacts carry results: a message should not carry the output of a task {{spec §3.7}}, so the planner reads the test count from summary.json.
Events arrive in order: every implementation must deliver events in the order it created them {{spec §3.5.2}}. A client that reconnects confirms the state with GetTask {{spec §3.7}}.
Credentials travel in HTTP headers: the client puts the credentials in the headers or metadata of the transport on every A2A request {{spec §7.3}}. So the planner sends Authorization: Bearer to deployer with every request.
The boundary with MCP
MCP connects an agent to its tools and resources, and A2A connects agents to each other {{docs a2a-and-mcp}}. The 1.0 announcement puts it in short form: MCP works inside an agent, and A2A works between agents {{docs announcing-1.0}}. No card names a tool: the run-tests skill on the test-runner card describes the work and stops there. MCP fundamentals covers the other protocol.
What A2A leaves to the host
A2A defines no registry: the specification sets no standard API for curated registries {{docs agent-discovery}}. It issues no credentials, because the transport handles identity, not A2A itself {{spec §7}}. It sets no retention period, so a task id can be invalid, expired, or already completed and deleted {{spec §3.3.2}}. It promises no exactly-once effect, because Send Message operations are allowed to be idempotent but do not have to be {{spec §3.3.1}}. Also, a webhook gets at least one attempt {{spec §4.3.3}}. Figure pairs each guarantee with the host's job.
Original source
id: fig-guarantees
kind: comparison
title: what A2A guarantees and what the host builds
claim: A2A fixes the messages, states, and events between agents, while trust, discovery, retention, and exactly-once effects stay with the host.
caption: Read across each row, one row per step. The left box is what the specification guarantees, and the grey box beside it is what you build. No capture: the rows come from spec §1, §3.3.1, §3.4.1, §3.7, §4.3.3, §7, §8.2, and §13.1.The specification also contradicts itself in ten places that change your code, listed below and settled in the sources reference.
| Conflict | What disagrees |
|---|---|
| D1 | the HTTP verb for SubscribeToTask |
| D2 | whether a plain SendMessage waits |
| D3 | whether a stream closes at an interrupted state |
| D4 and D5 | the names of the push configuration objects |
| D6 | the name of the card's security field |
| D11 | deprecated OAuth flows |
| D12 | the page field names of ListTasks |
| D13 | the HTTP+JSON error body |
| D36 | the error for another client's task |
Original source
- Build your client against the operations and objects, and keep each binding in one module.
- Treat everything behind a remote agent's endpoint as private.
- Mint a fresh `messageId` for every message, read results from artifacts, and send credentials in HTTP headers.Sources: spec §1, §1.2, §1.3, §1.4, §3.1.1, §3.3.1, §3.3.2, §3.4.1, §3.4.2, §3.5.2, §3.7, §4.3.3, §7, §7.3, §8.2, §13.1 (research/sources/specification.md); proto A2AService, Message, TaskState (research/sources/a2a.proto); docs a2a-and-mcp, announcing-1.0, agent-discovery (research/sources/docs.md); capture/a2a_ref.py, capture/planner.py; capture/out/01-agent-cards.http, 03-blocking-task.http, 10-cancel.http, 19-planner.http