Observed since 20 Oct, 16:30 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A polyglot, JSON-driven, multi-agent A2A network simulator with scenario runner, conformance contracts, Agent Control Specification (ACS) runtime governance, observer agents, time control, and failure injection.
Live at a2a-testbed.com · CLI on GitHub · Apache 2.0
A polyglot, JSON-driven, multi-agent A2A network simulator with scenario runner, observer agents, virtual time control, failure injection, and an in-browser playground for live AgentCard validation.
You drop your A2A AgentCard JSON files in a directory, write a YAML
scenario that names the agents and the messages flowing between them,
and the testbed boots a real multi-agent network for the duration of
the run, drives the scenario, and reports pass/fail per step plus a
JSON / Markdown / SVG-badge artefact. Agents are polyglot: each agent
in a scenario picks its runtime independently, so a Python principal
can interoperate with a Go service provider and a Node.js guardian
inside the same scenario. The result is a focused test environment
for multi-agent A2A protocol extensions and cross-runtime
interoperability.
The testbed also ships an extension-validation layer that follows a
small convention: each extension publishes a JSON Schema manifest at
its URI, and a generic validator checks any AgentCard payload against
that schema with zero protocol-specific code. See manifest/ and
extensions/ for the convention's reference types and the manifest
generator.
a2a-testbed is built around a specific set of multi-agent testing
capabilities:
capabilities.extensions[] payloads against published
JSON-Schema manifests.git clone https://github.com/ravikiran438/a2a-testbed.git
cd a2a-testbed
python3 -m venv .venv
. .venv/bin/activate
pip install -e ".[test]"
# 1. Run the bundled three-party guardian-mediated consent scenario
a2a-testbed run examples/scenarios/three_party_consent.yaml
# 2. Run a live A2A transport-contract sweep against any deployed
# agent. 62 spec-derived contracts; cites the spec section for
# each row. Use for your own Cloudflare/Lambda/GKE deployments.
# Probes in the version the agent's card advertises (1.0, or 0.3
# for legacy cards); --protocol-version 0.3 sweeps the legacy
# surface of an agent that serves both.
a2a-testbed conformance https://my-agent.example.com
# 3. Run a multi-agent scenario AND probe its `runtime: external`
# agents with the contract sweep in the same pass.
a2a-testbed run --probe-external examples/scenarios/my_scenario.yaml
# 4. Validate a live agent's AgentCard + every declared extension
# against its published manifest
a2a-testbed card https://my-agent.example.com
# 5. Statically validate an AgentCard JSON file (offline; no network)
a2a-testbed validate path/to/agent-card.json --manifest-dir ./manifests
# 6. Static AgentCard compatibility check against A2A 1.0 (built-in)
# or against a user-supplied dialect file (-f some-dialect.json)
a2a-testbed compat path/to/card.json
# 7. Show contract coverage with the spec pin (which A2A commit, last
# review date, % of clauses covered)
a2a-testbed coverage
# 8. Generate an ExtensionManifest from a pydantic model
a2a-testbed manifest generate \
--extension-uri https://example.org/my-protocol/v1 \
--name "My Protocol" \
--version 1.0.0 \
--ref-class my_protocol.types:MyServiceRef \
--output ./manifest.json
# 9. Author + validate an Agent Control Specification (ACS) manifest.
# `init` scaffolds, `validate` checks (--strict for CI), `spec`
# renders a human-readable governance summary. See docs/ACS.md.
a2a-testbed acs init --name my-agent -o my-agent.acs.yaml
a2a-testbed acs validate examples/acs/email-agent.acs.yaml
a2a-testbed acs spec examples/acs/three-party-governance.acs.yaml
# 10. Apply ACS runtime governance to a scenario. Evaluates every
# handoff against the manifest and prints per-step verdicts
# (allow/warn/deny). Use the scenario's `acs:` field or --acs.
a2a-testbed run examples/scenarios/three_party_governed.yaml
a2a-testbed run --acs examples/acs/three-party-governance.acs.yaml \
examples/scenarios/three_party_consent.yaml
# 11. Enforce ACS: a deny/escalate blocks the handoff before dispatch
# and halts the flow (instead of just recording the verdict).
a2a-testbed run --acs-enforce \
--acs examples/acs/three-party-governance.acs.yaml \
examples/scenarios/three_party_consent.yaml
The bundled three-party scenario produces a colored step table and
written reports under examples/scenarios/reports/.
Gate an agent on A2A conformance in any pipeline. The GitHub Action sweeps a live URL and/or lints an AgentCard file, writes a job summary, uploads SARIF to code scanning and fails the check on contract violations:
- uses: ravikiran438/a2a-testbed@v0
with:
url: ${{ steps.deploy.outputs.preview_url }} # a running agent
card: agent-card.json # and/or a card file
Elsewhere, call the CLI directly:
uvx a2a-testbed lint-card agent-card.json # no server needed
uvx a2a-testbed conformance https://agent.example \
-o results.sarif -o results.xml -o results.json
Exit codes: 0 conformant, 1 a contract failed, 3 the agent did not
answer some checks (retried once), 2 usage error or agent unreachable.
Known failures go in a .a2a-conformance.yaml baseline with a reason
each. Details in docs/ci.md.
The repo ships a Justfile that orchestrates work across
all the apps (Python testbed, in-browser playground, hosted demo
agents). Install Just once
(brew install just on macOS, or see the install page for other
platforms), then:
just # list every recipe
just install # install Python + JS deps for every app
just doctor # report which toolchains are on PATH
just test # run every test (Python + playground typecheck)
just build # build production artifacts for every JS app
just dev # start the playground at http://localhost:5173
just math-deploy # deploy the Cloudflare math agent
just clean # wipe every build artefact + node_modules / cache
Recipes are thin wrappers — every app stays independently buildable
with its native toolchain (pip, npm, wrangler). The Justfile
just removes the need to remember each one.
The playground/ directory is a Vite + React + TypeScript app with
two modes:
@xyflow/react), animate
message edges as the scenario runs, click any node or edge to
inspect its AgentCard / message payload. Pick a built-in scenario
from the dropdown (including the live LLM agent validator —
see below) or paste your own CLI-format YAML.When a scenario declares an agent with runtime: external and a
url:, the playground makes real HTTP calls to that deployment
and enforces each step's expect block (response_status,
response_contains) against the actual response — same checks the
CLI runs. The bundled cloudflare_math_demo scenario drives a live
LLM-backed A2A agent on Cloudflare Workers (Llama 3.3 via Groq, JSON
mode) end-to-end. See
playground/README.md
for the full execution model and how to add your own live scenario.
Run it locally:
cd playground
corepack enable # activates the pinned pnpm
pnpm install
pnpm dev
a2a-testbed/
├── pyproject.toml
├── README.md (this file)
├── ARCHITECTURE.md (the design)
├── CONTRIBUTING.md (how to contribute)
├── LICENSE (Apache 2.0)
├── src/a2a_testbed/
│ ├── core/ (types, loader, time controller, faults, observer)
│ ├── runtimes/ (python_inproc, python_subproc, go, nodejs, java, external)
│ ├── network/ (multitenant — sim mode; perprocess — realistic mode)
│ ├── transport/ (Transport protocol abstraction + A2ATransport)
│ ├── contracts/ (65 spec-derived A2A conformance contracts: 62 transport + 3 network + runner)
│ ├── manifest/ (ExtensionManifest types, generator, store, validator)
│ ├── extensions/ (MCP delegation glue for richer semantic validation)
│ ├── vendors/ (AgentCard dialect framework + A2A native checker)
│ ├── scenario.py (orchestrator: sim and realistic modes)
│ ├── reporter.py (JSON, Markdown, SVG output)
│ ├── spec_meta.py (A2A spec pin + coverage metadata)
│ └── cli/ (typer CLI)
├── agents/
│ ├── python-template/ (subprocess Python reference agent)
│ ├── go-template/ (subprocess Go reference agent)
│ ├── nodejs-template/ (subprocess Node.js reference agent)
│ └── java-template/ (placeholder; contract documented)
├── examples/
│ ├── agent-cards/three-party/ (3 example AgentCards)
│ └── scenarios/ (bundled YAML scenarios)
├── playground/ (Vite + React in-browser playground)
└── tests/
├── unit/ (loader, types, time, observer, faults, manifest)
├── integration/ (end-to-end scenario, MCP delegation)
└── polyglot/ (cross-SDK; requires language toolchains)
Scenario. A YAML file that names agents and a flow of message steps. Optional fault injection per step, virtual time advance, and observer agents.
Agent. Identified by id, declared with an AgentCard JSON file
and a runtime kind. Default runtime is python_inproc (in the
orchestrator process); cross-SDK scenarios pick go, nodejs, or
external. (java is reserved — adapter exists but no reference
jar ships yet; see agents/java-template/.)
Mode. A scenario picks one. sim (default) runs all agents in a
single Starlette server with path-prefix routing — fast, dev-friendly.
realistic spawns one process per agent — used for cross-SDK
conformance and production-topology validation.
Runtime. A polyglot adapter: python_inproc, python_subproc,
go, nodejs, external. Each adapter knows how to bring its
language's agent up, route the AgentCard JSON in, capture the ready
handshake, and tear down on scenario exit. (A java adapter is
scaffolded but inactive until a reference jar ships.)
Fault. Declared on a step. drop, delay <ms>, corrupt,
http_error <status>. Injected client-side so the agent under test
can't tell it's being faulted from the wire.
Time controller. Per-scenario virtual clock with explicit
advance(seconds). Required for testing protocol TTLs and refresh
cadences without sleeping in the test.
Protocol version. The testbed speaks A2A 1.0 (SendMessage,
A2A-Version: 1.0, ProtoJSON payloads) and stays backward compatible
with A2A 0.3. As a client it negotiates per agent from the AgentCard —
1.0 unless the card is a 0.3 card or lists only 0.x JSONRPC interfaces
— and normalizes 0.3 payloads to the 1.0 shape before any contract
runs, skipping only rules that 1.0 introduced. As a server, every
testbed-hosted agent (in-process agents and the Python / Go / Node /
Java templates) answers 1.0 and 0.3 callers in their own wire format,
like the a2a-sdk's enable_v0_3_compat; an agent declared with a 0.3
card behaves like a pre-1.0 deployment (0.3 card layout, 0.3 methods
only). examples/scenarios/mixed_versions.yaml runs both side by side.
The contract suite is validated against agents built on the official
a2a-sdk in both versions (tests/oracles/).
Observer. An agent declared with role: observer. The runner
records every step against the observer's history; a semantic
validator can be plugged in for invariants like "audit trail is
complete" or "no behavioral drift detected across this scenario."
A2A 1.0 specifies capabilities.extensions[] with a uri, but does
not yet specify how a third-party validator should understand the
entry's payload. This testbed proposes a small convention: each
extension publishes a self-describing manifest at its URI.
GET <extension_uri>/manifest.json → ExtensionManifest (JSON Schema for the payload)
A generic validator can:
capabilities.extensions[].uri from the AgentCard<uri>/manifest.jsonparams against the manifest's JSON SchemaThe manifest/ package contains the typed envelope, a generator that
builds a manifest from any pydantic model, a store abstraction
(in-memory / filesystem / HTTP / composite), a JSON-Schema validator,
and a markdown spec generator. The playground/ app demonstrates the
same flow in pure browser JS via ajv.
The convention is experimental; it is not part of the A2A 1.0 specification.
name: "polyglot interop"
mode: realistic
agents:
- id: principal
card: ./cards/alice.json
runtime: python_inproc # in the testbed
- id: guardian
card: ./cards/bob.json
runtime: nodejs # subprocess
source: ./agents/nodejs-template/
- id: provider
card: ./cards/carol.json
runtime: go # subprocess
source: ./agents/go-template/
flow:
- from: provider
to: principal
action: request_consent
- from: principal
to: guardian
action: forward_consent
- from: guardian
to: provider
action: grant_consent
Runs three agents in three different languages talking via real
HTTP+JSON-RPC. The Python subprocess path is validated end-to-end
in tests/polyglot/; Go and Node.js work the same way given their
toolchain on PATH.
Bundled under examples/scenarios/:
| Scenario | Demonstrates |
|---|---|
three_party_consent.yaml | 5-step three-party guardian-mediated flow across 3 in-process agents |
extension_checks.yaml | Extension semantics checked on the protocol's own MCP server (expect.extensions, here PACE time windows and language match); needs pace-mcp, see docs/scenarios.md |
fault_injection.yaml | Drop / delay / corrupt / synthetic HTTP error at the orchestrator's wire seam |
time_advance.yaml | Virtual clock advanced explicitly between message steps for TTL / refresh testing |
observer_audit.yaml | Observer agent receives every wire exchange via traffic taps |
polyglot_smoke.yaml | Polyglot architecture demo (in-process Python; subprocess scenarios in tests/polyglot/) |
cloudflare_math_demo.yaml | Live LLM-backed math agent on Cloudflare Workers (Llama 3.3 via Groq, JSON mode); semantic field-level assertions |
task_runner_demo.yaml | Live task-runner agent at tasks.a2a-testbed.com (A2A 1.0 + 0.3); full Tasks / SSE / push lifecycle, pairs with --probe-external for the contract sweep |
mixed_versions.yaml | An A2A 1.0 agent and an A2A 0.3 agent exchanging requests both ways; the testbed speaks each receiver's own version |
three_party_governed.yaml | The three-party flow with an ACS manifest attached (acs: field); per-step governance verdicts |
cloudflare_math_governed.yaml | ACS runtime governance against the live Cloudflare math agent: DLP on the real request, error-check on the real response |
ACS manifests under examples/acs/: email-agent.acs.yaml (builtin),
email-agent-rego.acs.yaml (OPA/Rego), dlp-evidence.acs.yaml (evidence
provider), three-party-governance.acs.yaml, and
cloudflare-math-governance.acs.yaml. See docs/ACS.md.
Alpha. The CLI surface, scenario format, and manifest envelope may
change while the convention is being explored. Tests cover the core
runtime, the manifest layer, and one end-to-end scenario; cross-SDK
toolchains are exercised in tests/polyglot/.
| Project | What it does |
|---|---|
| a2aproject/a2a-tck | Single-agent compliance validator. Local CLI, targets A2A v0.3.0. |
| a2aproject/a2a-inspector | Interactive debugger UI for one agent at a time. Local launch. |
| a2aproject/a2a-samples | Reference sample agents in Python, JavaScript, Go, Java. |
| A2A-StoryLab | Educational multi-agent demo (Orchestrator + Creator + Critic). |
a2a-testbed targets A2A 1.0 (pinned to the v1.0.1 spec release), stays compatible with A2A 0.3 agents, and adds: multi-agent scenarios, network fault injection, virtual time, the extension manifest convention, and a hosted browser playground at https://a2a-testbed.com.
The reference task-runner at
examples/hosted-agents/cloudflare-task-runner/,
deployed at https://tasks.a2a-testbed.com, can also serve as the
SUT for an a2a-tck run:
git clone https://github.com/a2aproject/a2a-tck.git
cd a2a-tck
uv venv && source .venv/bin/activate && uv pip install -e .
./run_tck.py --sut-url https://tasks.a2a-testbed.com --category all
Some tests will fail because TCK enforces A2A v0.3.0 mandatory surfaces (notably multi-transport equivalence) that this JSON-RPC-only agent does not implement.
See CONTRIBUTING.md. Issues and pull requests
welcome.
Apache 2.0. See LICENSE. Hosted playground:
a2a-testbed.com.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.0a3 | 11 Oct 2026 | 15 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 16:30 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:afac09811efcfa3c1a8ef4496e8c82cbf0e0915644cc3f88fbe8bc7c15fd91f7