ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-04-24Intermediate

Implementing Antigravity's A2A Protocol — Practical Patterns for Agent-to-Agent Conversation

A hands-on guide to Antigravity's A2A (Agent-to-Agent) protocol. Walks through the minimal two-agent setup and three real-world patterns — fire-and-forget, bidirectional confirmation, and scatter-gather — with runnable samples.

Antigravity322A2A3multi-agent49protocol2agent design6

Any serious multi-agent discussion eventually lands on the same question: how do agents actually talk to each other? Antigravity ships an A2A (Agent-to-Agent) protocol for exactly that — a typed way for one agent to delegate work to another and receive results.

The docs cover the surface, but rarely the "when would I reach for this?" part. This article walks through three patterns I use in practice, each with working code.

A2A in One Minute

A2A treats each agent as an HTTP service that exposes a handful of structured operations. Three concepts do the heavy lifting:

  • Agent Card: a self-describing schema for what the agent can do (endpoint, supported task kinds, auth requirements)
  • Task: an object the client-side agent creates and hands off, carrying the input message and metadata
  • Message Stream: the sequence of messages exchanged while a task is in flight — progress updates, clarifying questions, the final result

In diagram form: a client agent, a remote agent, and the task that mediates between them.

Minimal Setup — Delegating One Task

Agent A hands a long article to Agent B for summarization, and Agent B returns three bullet points.

# agent_b_server.py — the summarizer
from antigravity.a2a import AgentServer, AgentCard, TaskHandler
 
card = AgentCard(
    name="summarizer",
    description="Summarize long-form text in 3 bullet points.",
    supported_tasks=["text/summarize"],
    endpoint="http://localhost:8081",
)
 
handler = TaskHandler(card=card)
 
@handler.on_task("text/summarize")
async def summarize(task):
    text = task.input["text"]
    result = await task.call_llm(
        prompt=f"Summarize this text in 3 bullet points:\n\n{text}",
    )
    return {"summary": result}
 
if __name__ == "__main__":
    AgentServer(handler).run(port=8081)
# agent_a_client.py — the caller
from antigravity.a2a import AgentClient
 
async def main():
    client = AgentClient(remote="http://localhost:8081")
    result = await client.submit_task(
        kind="text/summarize",
        input={"text": open("article.md").read()},
    )
    print(result["summary"])

Two things matter here. The Agent Card declares capabilities in a way the client can discover before connecting. The task kind (text/summarize) is the agreement between the two sides — as long as both use the same string, they're compatible, even if one side swaps its implementation later.

Pattern 1: Fire-and-Forget

The setup above. A throws a task to B, B returns a result, A moves on. This is the most common shape and where you should start.

It fits when:

  • Input and output are well-defined (summarize, translate, classify, reshape)
  • No human confirmation is needed mid-task
  • The result lets A complete its own work

This looks a lot like a REST call, and at one level it is. The real value of A2A here is that agents become replaceable components. Swap the summarizer for a different model, a language-specific variant, or a free tier — the client code doesn't change.

Pattern 2: Bidirectional Confirmation

Sometimes B wants to check in with A mid-task. Maybe B is drafting a document and wants A's approval on a proposed title. A2A's Message Stream makes that two-way conversation first-class.

@handler.on_task("doc/generate")
async def generate_doc(task):
    draft_title = await task.call_llm(prompt="Propose a title for this report: ...")
    
    # Ask A to confirm the title
    response = await task.ask(
        message=f"Is this title OK? '{draft_title}'. Reply 'yes' or a new title.",
    )
    
    final_title = draft_title if response.strip().lower() == "yes" else response.strip()
    # ... generate the body ...
    return {"title": final_title, "body": body}

The pattern suits near-autonomous flows that deliberately pause at a few important decision points. Depending on A's implementation, the confirmation prompt can escalate further — to a senior agent with approval authority, or to a human.

Pattern 3: Scatter-Gather

A fires tasks at B1, B2, B3 in parallel and aggregates the results. Useful whenever you want to saturate throughput.

import asyncio
 
async def process_articles(article_list):
    clients = [AgentClient(remote=url) for url in worker_endpoints]
    tasks = [
        clients[i % len(clients)].submit_task(
            kind="text/summarize",
            input={"text": text},
        )
        for i, text in enumerate(article_list)
    ]
    results = await asyncio.gather(*tasks)
    return [r["summary"] for r in results]

Why not just a queue and workers? Because A2A workers can specialize. A Japanese-focused summarizer, an English one, a code-specific one — route each article to the best fit when you construct the task list, and you get more than just parallelism.

Three Operational Gotchas

Auth and access control. Exposing an A2A endpoint on the open internet lets anyone submit tasks. Declare auth requirements on the Agent Card and enforce them with bearer tokens or mTLS. Even inside a private network, a minimum of token auth is worth it if anything reaches across a VPN.

Timeouts and retries. Remote agents sometimes don't respond. Set a client-side timeout. And if the task can be safely retried, tag it with an idempotency_key so double-submission doesn't double-side-effect.

Error granularity. Letting internal exceptions escape through the wire leaks your implementation. Wrap errors in a structured form — TaskError(code="llm_timeout", message="...", retry_after=30) — so the caller can make a meaningful fallback decision.

Where to Start

All the samples here run by installing Antigravity's Python SDK and starting two terminals. Get fire-and-forget working first, then layer on the bidirectional and scatter-gather patterns once the basics feel natural.

When you're ready to design larger topologies, our intro to multi-agent orchestration covers the trade-offs between A2A, shared memory, and orchestrator-worker shapes.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Agents & Manager2026-04-09
Antigravity Multi-Agent System: The Complete Implementation Guide
Master Antigravity's Manager Surface to design and implement multi-agent systems. Learn role delegation, parallel processing, and how to pair Gemma 4 with Antigravity for autonomous development workflows.
Agents & Manager2026-04-01
Antigravity × A2A Protocol: Complete Implementation Guide for Scalable Multi-Agent Systems
A complete guide to implementing Google's A2A (Agent-to-Agent) protocol with Antigravity. From agent card design to task delegation, streaming communication, and production deployment on Cloudflare Workers.
Agents & Manager2026-07-06
When Parallel Agents Ran the Same Task Twice and Quietly Doubled the Bill — Field Notes on Measuring and Stopping Duplicates
The bill for our parallel agents came in about 1.9x higher than expected — because multiple workers were running the same task twice. These are field notes on measuring the duplication, stopping it with idempotency keys, and attributing cost per task.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →