« Phase 03 · Warmup · Track Overview

Core Contributor Notes — How the Real Protocols Work


Table of Contents


1. A2A's shape on the wire

A2A is JSON-RPC 2.0 over HTTP by default, with gRPC and REST bindings defined as alternatives. The core methods map one-to-one onto the lab:

MethodLab equivalent
message/sendA2AServer.message_send
message/streamA2AServer.message_stream (SSE in the real thing)
tasks/gettasks_get
tasks/canceltasks_cancel
tasks/pushNotificationConfig/set and /getset_push_config
tasks/resubscribe(not in the lab) — reattach to a stream after disconnect

tasks/resubscribe is the one worth knowing about even though the lab omits it: it exists because SSE connections die, and a long-running task must be re-attachable without re-delegating. Its existence tells you something about the design philosophy — the task, not the connection, is the durable thing. Any implementation where losing the connection loses the work has misunderstood the protocol.

The same design decision explains why Task carries history and artifacts: a client that reconnects needs to catch up from the object, not from a replayed stream.

2. Agent Card discovery in practice

Cards are conventionally served at a well-known path (/.well-known/agent-card.json), which makes discovery a plain HTTPS GET and lets an organization publish a card without any A2A-specific infrastructure.

Three refinements the spec adds that the lab does not:

Authenticated extended cards. A public card may advertise a subset; an authenticated caller can fetch a fuller one. This is the spec's own acknowledgement of the Phase 02 principle — discovery is answered relative to a principal — and it is worth using rather than reimplementing.

Signatures. Cards may be signed (JWS), so a caller can verify the card came from the claimed issuer rather than from whoever answers that URL today. For a bank consuming external agents this should be mandatory, and it is the direct answer to the "hostile card is a persistent prompt injection" risk.

Transport and interface declarations. A card can advertise several endpoints with different bindings, so a caller picks the one it supports. Which means "does this agent support A2A?" is usually the wrong question; the right one is "which binding do we share?"

3. Streaming and resumption

Real streaming is Server-Sent Events, with two event types matching the lab's: TaskStatusUpdateEvent and TaskArtifactUpdateEvent, terminated by a status update with final: true.

Artifact streaming uses append and lastChunk, which the lab declares but does not exercise. The semantics: an artifact may arrive in pieces; append: false replaces, append: true extends, and lastChunk: true closes it. A client that ignores append and concatenates everything will duplicate the first chunk of any artifact that was re-sent after a reconnect.

The practical infrastructure notes, which are the same ones that bite MCP's streamable HTTP:

  • Buffering proxies break SSE. An API gateway that buffers responses turns a stream into a single delayed blob. Configure explicitly.
  • Idle timeouts kill long tasks. A four-hour task will not hold a stream; that is what push notifications are for, and treating streaming as a substitute is a design error.
  • Reconnection needs Last-Event-ID semantics plus tasks/resubscribe, or a reconnecting client silently misses updates.

4. Push notifications, properly authenticated

The lab requires a token in the config and checks the host against an allow-list. Production adds the part that makes the callback trustworthy in the other direction:

The callee authenticates itself to the caller's webhook. The config declares an authentication scheme; the callee signs its callback (typically a JWT with the caller as audience), and the caller validates it. Without this, anyone who learns the webhook URL can drive the caller's view of a task's state.

So there are two independent authentication directions and both are needed:

DirectionPurposeLab
caller → callee (message/send)prove who is delegatingCallerContext (a stand-in for a token)
callee → caller (the webhook)prove the update is genuinetoken presence only

Plus the two hardening controls: allow-listed destination hosts, and egress control on the callee's network path. The spec is explicit that webhook URL validation is the implementer's responsibility — which is the polite way of saying this is where the SSRFs will be.

5. ACP's differences that matter

ACP is REST-shaped rather than JSON-RPC-shaped, and the differences are more than cosmetic:

A2AACP
StyleJSON-RPC (gRPC/REST bindings)REST resources
Unit of workTaskRun
Asyncstreaming + pushpolling, callbacks, and streamed responses
DiscoveryAgent Card at a well-known pathagent manifests / registry
SessioncontextId groups taskssession_id groups runs

The REST shape has one genuine advantage worth acknowledging in a design discussion: it is trivially inspectable by existing infrastructure. An API gateway, a WAF, a proxy and a logging pipeline all understand POST /runs and GET /runs/{id} without any protocol awareness. For a bank whose network controls are built around HTTP semantics, that is not nothing.

The lab's position — internal model, adapters at the edge — is what lets you take that advantage without betting on either protocol. If ACP's REST shape suits your ingress and A2A suits your counterparties, you can speak both, and the kernel never knows.

6. The hyperscaler fabrics

Each fabric hosts agents and each has its own session, invocation and identity model. What matters for interop is not the API surface but what happens to identity at the boundary:

  • Azure AI Foundry Agent Service — agents with threads and runs, integrated with Entra ID. Because Entra is likely your own identity provider, the identity story is the best of the three if the calling agent is invoked with a user context rather than a service principal. The failure mode is a fabric-hosted agent running as an app registration with broad permissions.
  • AWS Bedrock Agents / AgentCore — action groups, session isolation (microVM per session in AgentCore Runtime), and Gateway/Identity components that front tools with policy. IAM is the authority, and IAM's model is workload-shaped; carrying an end-user identity through it requires deliberate design.
  • Google ADK + Agent Engine — sessions with scoped state (user:, app:, temp:), an event-driven runner, and increasingly first-class A2A support.

The recurring integration risk in all three, stated once: the fabric's natural credential is a workload identity, and your action gateway needs a user. An adapter that papers over this is the audit finding from PRINCIPAL-DEEP-DIVE §6. The correct behaviour is a rejected task with a reason, and a conversation with the fabric team about propagating user context.

7. Sharp edges

A2A and ACP are young and moving. Versions change; protocolVersion exists for a reason. Pin what you have tested, negotiate at connect, and log the negotiated version per counterparty.

"Agent" is not a defined term across ecosystems. One vendor's agent is another's tool, and a "multi-agent system" may be a prompt chain. When integrating, ask what the counterparty actually does — judgement or execution — because the answer determines whether A2A is the right protocol at all.

Task ids are not globally unique. They are unique within a server. Correlating across organizations needs your contextId plus the counterparty's identity, or you will join two unrelated task-1s.

Cancellation is advisory. tasks/cancel asks. A callee that has already moved money cannot un-move it, and the protocol has no notion of compensation. Anything with side effects needs the saga machinery from Phase 10; treating canceled as "it did not happen" is a serious error.

Artifacts may carry data you cannot hold. Check classification on the return path. The spec has no opinion about this and your regulator does.

SSE through a corporate proxy will be buffered, chunk-rewritten, or closed. Test the real path early; a streaming implementation that works on a laptop and not in the DMZ is the default outcome.

8. What the miniature simplifies

MiniatureReality
Direct method callsJSON-RPC over HTTPS, with SSE for streaming and gRPC/REST bindings
CallerContext parametera validated token carrying identity, tenant and an act chain
AgentCard objectan HTTPS resource at a well-known path, optionally signed, with authenticated extended variants
No resubscriptiontasks/resubscribe and Last-Event-ID
pushed listauthenticated webhook POSTs with retries, backoff and receiver idempotency
append/lastChunk declared, unusedreal chunked artifact streaming
One directory, in memorya governed registry with card pinning, review and deprecation
Counter timestampswall-clock times, and clock-skew tolerance
No compensationsagas for anything with side effects
Classification checked outboundchecked in both directions

9. References

  • A2Aa2a-protocol.org: specification, Agent Card schema, task lifecycle, message/stream, tasks/resubscribe, push-notification configuration and its security guidance. Linux Foundation project since 2025.
  • ACPagentcommunicationprotocol.dev: runs, multipart messages, sync/async execution, agent manifests.
  • MCPmodelcontextprotocol.io, for the contrast in scope.
  • Server-Sent Events — the WHATWG HTML spec's EventSource section; Last-Event-ID and reconnection semantics.
  • RFC 8693 (token exchange, the act claim) and RFC 9068 (JWT access tokens) — what makes the delegation chain unforgeable; Phase 08.
  • Azure AI Foundry Agent Service, AWS Bedrock Agents / AgentCore, Google ADK / Agent Engine — read each one's session and identity documentation first; that is where interop succeeds or fails.
  • OWASP Top 10 for LLM ApplicationsExcessive Agency, which covers unbounded delegation explicitly.