Learn A2A - Policy-as-Code & Automation
Series/Learn A2A/Episode 20
Episode 20 of 23

Learn A2A - Policy-as-Code & Automation

This episode discusses automating the agent service lifecycle: CI/CD for Docker and Cloud Run, multi-agent testing in the pipeline, agent card contract testing, and version governance, deprecation policy, and per-agent SLAs.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Introduction

Episode 19 showed the commercial side of the A2A ecosystem: agents can request payment via x402, governed by mandate and approval, then settled through trust rails. But behind the scenes, all that capability is only useful if the service can be managed with discipline. Episode 20 brings A2A into the operational realm: automation and policy-as-code. We'll build a CI/CD pipeline that deploys an agent service to Docker and Cloud Run, write multi-agent tests that actually execute tasks in the pipeline, apply contract testing to the agent card, then arrange governance — agent versioning, deprecation policy, and measurable per-agent SLAs.

Deploy an Agent Service with CI/CD

An agent service is no different from an ordinary web service: it needs an image, a pipeline, and a deployment target. Docker is the most neutral starting point — the same image can run locally, on staging, or in production.

Dockerfile
FROM node:22-slim AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
 
FROM node:22-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/agent-card.json ./agent-card.json
EXPOSE 3000
CMD ["node", "dist/server.js"]

The agent card is copied into the image because it's a release artifact, not a configuration file. When the card changes, the image version changes too — and clients caching the card get the signal via version metadata. For serverless platforms like Cloud Run, deployment happens after the build and tests are green, just one line in the pipeline:

deploy-cloud-run.yaml
deploy:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Build image
      run: docker build -t a2a-agent:${{ github.sha }} .
    - name: Deploy to Cloud Run
      run: |
        gcloud run deploy a2a-agent --image gcr.io/my-project/a2a-agent:${{ github.sha }} \
          --region asia-southeast1 --allow-unauthenticated

The commit-SHA tag pattern guarantees every deploy can be traced back to its exact commit. For a quick local verification before pushing to the pipeline, run docker build -t a2a-agent:dev .. The principle is the same for Cloud Run, ECS, or Kubernetes — only the target changes.

Multi-Agent Testing in the Pipeline

A pipeline that only builds without running agents is false confidence. A valuable test for A2A must run two real agents and send real tasks between them — not mocks.

Pythontest-multi-agent.py
import pytest
 
@pytest.mark.asyncio
async def test_agent_ke_agent():
    async with run_server(agent_analisa) as url_a, run_server(agent_ringkas) as url_b:
        client = A2AClient(httpx.AsyncClient())
 
        task = await client.send_task(url_a, {
            "parts": [{"type": "text", "text": "Ringkas laporan ini"}],
        })
        assert task.status == "completed"
 
        hasil = task.artifact.parts[0].text
        assert len(hasil) > 0
 
        task_b = await client.send_task(url_b, {
            "parts": [{"type": "text", "text": f"Terjemahkan: {hasil}"}],
        })
        assert task_b.status == "completed"

Several things that must be tested besides the happy path:

  • State machine: every task moves from submitted to working, then to a terminal state — nothing hangs in working.
  • Error path: send an invalid payload, make sure the agent replies failed with a message the client can read.
  • Streaming: if the agent supports SSE, make sure the event stream closes properly when the task finishes.
  • Auth: run once with valid credentials and once without — both must behave according to policy.

These tests run on every pull request, so regressions between agents are caught before production — the difference between a pile of code and a system that genuinely collaborates.

Contract Testing: The Agent Card as a Contract

When many clients rely on your agent card, a small change to the card can break all of them. Contract testing treats the agent card as a public contract that is explicitly tested.

Pythontest-contract-card.py
import jsonschema
import pytest
 
SCHEMA = load_json("agent-card-schema.json")
 
def test_agent_card_valid():
    card = load_json("agent-card.json")
    jsonschema.validate(card, SCHEMA)
 
def test_skill_id_stabil():
    card = load_json("agent-card.json")
    for skill in card["skills"]:
        assert skill["id"].startswith("a2a-agent:")
 
def test_breaking_change_terdeteksi():
    lama = load_json("agent-card.v1.json")
    baru = load_json("agent-card.json")
    for skill in lama["skills"]:
        if skill["id"] not in [s["id"] for s in baru["skills"]]:
            pytest.fail("skill yang dideprekasi belum lewat masa transisi")

Schema validation catches broken cards; id assertions catch silently missing skills. The most important is the third test: breaking changes must be deliberate and scheduled, not an accidental refactor that happens to remove a skill.

Agent Versioning and Deprecation Policy

Versioning is the agreed language between an agent's owner and its clients. For A2A there are two things to version: the protocol version (handled by version negotiation, discussed in episodes 10 and 21) and the agent's capability version — the agent card version.

Healthy practices:

  • Semantic versioning on the agent card: major when a skill is removed or a parameter changes in a breaking way; minor when there's a new additive skill; patch for descriptions and metadata.
  • Field deprecation: mark skills heading toward retirement with a deprecated flag and a sunset date, rather than deleting them outright.
  • Transition period: support at least two major versions simultaneously — for example v2 is active while v1 still accepts tasks and replies with a sunset header.
deprecated-skill.json
{
  "agentName": "a2a-agent",
  "cardVersion": "3.2.0",
  "protocolVersion": "1.0",
  "skills": [
    {
      "id": "a2a-agent:analisa-kredit",
      "name": "Analisa Kredit",
      "deprecated": true,
      "sunset": "2026-12-31"
    },
    {
      "id": "a2a-agent:analisa-kredit-v2",
      "name": "Analisa Kredit v2",
      "inputs": ["skor_kredit", "riwayat"]
    }
  ]
}

Smart clients read the deprecated and sunset markers and migrate before the deadline. A written deprecation policy is an agreement — not a sudden command.

Per-Agent SLA

Finally, agents need a measurable SLA. Without numbers, clients can't trust an agent with critical tasks. Four common metrics:

  • Availability: the percentage of time the agent can accept tasks — a common target is 99.5 percent or higher.
  • Task latency: p50, p95, and p99 of task duration — not just an average, which can deceive.
  • Error rate: the proportion of tasks ending in the failed status — signaling quality problems, not just uptime problems.
  • Throughput: task capacity per second before load shedding kicks in.
sla-agent.yaml
agent: a2a-agent
version: "3.2.0"
slo:
  availability: "99.5%"
  latency_p95: "4s"
  error_rate: "0.5%"
  throughput_per_sec: 500
windows:
  - "1m"
  - "7d"

Publishing SLOs alongside the agent card lets clients read the promised capacity before sending a task. Because these SLOs are version-sensitive, performance improvements in a major release show up as improved numbers.

Conclusion

Episode 20 closes the gap between "an agent works on my laptop" and "an agent runs in production". CI/CD makes deploys repeatable and traceable, multi-agent tests prove real collaboration in the pipeline, contract testing protects the agent card as a public contract, and governance — versioning, deprecation, and SLAs — provides an agreed language between agent owners and consumers.

Here's the core takeaway:

  • The agent card is a release artifact: shipped with the image, versioned, and tested as a contract.
  • Multi-agent tests must execute real tasks between agents, not mocks.
  • Contract testing catches breaking changes before partners are affected.
  • Versioning plus a deprecation policy makes migration planned, not surprising.
  • Measurable SLAs give clients a reason to trust your agents.

In episode 21 we look to the horizon: modern features and the A2A roadmap — from the stable v1.0 with signed agent cards, multi-tenancy, and version negotiation, to the development direction of discovery and security. See you there!

Learn A2A - Policy-as-Code & Automation | Learn A2A