How Amplifier's A2A bundle keeps agents scoped
A busy Amplifier workspace runs many specialist agents that each need their own right-sized context. Force them all through one "do everything" window and it pollutes every agent and bloats every call.
amplifier-bundle-a2a answers this by scoping context at every level — and wiring the specialists together.
amplifier-bundle-a2a is a Microsoft-org bundle: 2,328 non-test lines across two modules, with a passing suite at HEAD 14e5cc6 (2026-06-15).
So what are those two modules? That's the shape of the whole argument.
Status: Shipped · HEAD 14e5cc6The bundle ships exactly two inline modules. tool-a2a is the CLIENT — 14 operations for sending messages to remote agents. hooks-a2a-server is the SERVER — aiohttp on default port 8222, receiving messages from remote agents.
Installed globally, though, that server would try to run everywhere.
A global install could mean a server running in every directory. Instead the hook checks if not config.get("enabled", False): skip — enabled defaults to false, so no HTTP and no mDNS start until a directory sets it true.
That opt-in switch is written per directory — which is where context gets scoped.
A directory opts in by writing an override into its own .amplifier/settings.yaml. Per the README, "each directory gets its own a2a identity, port, and contacts" — and the behavior injects only its scoped context via context.include, not a monolith.
With directories scoped, the specialists inside them can start talking to each other.
.amplifier/settings.yaml per directorycontext.include: a2a:context/a2a-instructions.mdIntegration tests start the A2AServer on 127.0.0.1 with an OS-assigned port and do real aiohttp round-trips against /.well-known/agent.json and /a2a/v1/tasks. The communication is real HTTP, over localhost.
Which raises the sharp question: what is a remote agent actually allowed to touch?
8222; peers found over mDNS/.well-known/agent.json/a2a/v1/tasks on 127.0.0.1When a trusted peer asks, the server spawns a CHILD AmplifierSession with tools filtered by trust tier — and deliberately NO a2a hooks ("child doesn't need a2a server"). Context stays scoped, and no recursive server or port collision can happen.
Trust tiers bound exactly what that child may touch.
"*" (all parent tools)[tool-filesystem, tool-search] (read-only)Global install, per-directory identity, per-request child session — three nested scopes so no single context window drowns a workspace full of specialists, all covered by 308 tests.
Repository: microsoft/amplifier-bundle-a2a — git@github.com:microsoft/amplifier-bundle-a2a.git
Data as of: HEAD 14e5cc6ad9821ccd78548c10d70874e8176ead33 (2026-06-15). Clone at /tmp/a2a-src.
Feature status: Shipped as a Microsoft-org bundle; full suite green (307 passed / 1 skipped).
Commands run:
ls modules; README Architecture section sed -n '230,257p' README.mdfind modules -name '*.py' -not -path '*/tests/*' | xargs wc -l | tail -1 (2328 non-test LOC)uv run pytest --collect-only -q; uv run pytest -q (308 collected; 307 passed, 1 skipped)grep -cn 'operation ==' modules/tool-a2a/.../__init__.py (14)sed -n '29,40p' modules/hooks-a2a-server/.../__init__.py (enabled defaults false)cat behaviors/a2a.yaml (tool + server hook port 8222 + context.include)sed -n '237,254p' .../server.py; trust tiers sed -n '216,235p' .../server.pygrep -n 'port|127.0.0.1|A2AServer' tests/test_integration.py (localhost round-trip)git log --reverse --format='%ci %s'; contributors git log --format='%an' | sort | uniq -c | sort -rnGaps: The 8222/8223 pairing is documentation example, not a running pair — 8222 is the server default, 8223 appears only as an example peer URL. Integration tests use an OS-assigned port on 127.0.0.1. No gh API calls were made.
Primary contributors: Brian Krabach (25 commits), Salil Das (3 commits).