Google A2A over Git: production-ready agent transport across organizations
An implementation of the open Google Agent-to-Agent standard over a shared git repository: humans and agents from different companies send tasks to each other and receive responses — no HTTP server, no broker, full audit trail out of the box.
Problem
Google A2A (Agent-to-Agent) is an open interoperability standard for agents:
JSON-RPC 2.0 as the message format,
.well-known/agent.json as the manifest,
tasks with a lifecycle, delegation between agents from different vendors.
The standard specifies what is sent, but leaves the transport open —
HTTP(S) is the usual assumption.
HTTP transport works well within a single network. But once agents live with different people at different companies, questions arise that HTTP doesn't solve out of the box:
- • How does Alice's agent reach Bob's agent when Bob has no public endpoint and no SLA?
- • How does Alice the human assign a task to Bob's agent when all they share is a common working context?
- • Who keeps the history of all interactions — and can it be replayed six months later when Bob's server is gone?
- • Who pays for infrastructure when ten people want to orchestrate agents in a shared experiment and nobody wants to run a broker?
Also worth noting: the contrast with breakdown #2 "Cross-org agent negotiation", where two agents agree on a contract through a firewall. That's an exploratory dialogue between two processes about one artifact. This is shared infrastructure where any number of humans and agents operate as a multi-tenant system. Detailed comparison at the end of the Methodology section.
Methodology
Implement Google A2A over a shared git repository, using the filesystem as a queue and git as the transport.
The architectural move
Message and manifest contracts are the same as in Google A2A. Only the transport changes: instead of "agent runs an HTTP server" — "agent works with a local clone of the repository."
| HTTP-A2A | File-bus A2A |
|---|---|
Endpoint POST /tasks |
File inbox/{id}.json |
| Server-Sent Events / polling | outbox/res_{id}.{ext} + git pull |
.well-known/agent.json |
.well-known/agents/{agent_id}.json |
| TLS + API keys | Git repository permissions (SSH / deploy key) |
| Server request log | git log (full history, every clone) |
Idempotency by id |
Atomic rename as capture lock |
Multi-tenant model
-
1. Human → another person's agent.
Alice adds
inbox/{uuid}.jsonviagit push. Bob's agent (his cron/CI) doesgit pull, sees the new request, claims it with an atomicrenameintoprocessing/, executes, publishes the response inoutbox/res_{uuid}.json, commitsProcessed {uuid}. Alice doesgit pulland reads the answer. No servers running at Bob's end — the agent starts on schedule or on a push trigger. -
2. Agent → another person's agent.
Same path, but the request is generated by Alice's autonomous agent. Delegation
chains (agent X spawned a subtask for agent Y) are expressed via
parent_idin a new JSON-RPC message — an iteration tree that's visible to everyone throughgit log. -
3. Multiple roles, one owner.
Manifests in
.well-known/agents/declare roles with their owncapabilities. An agent checks whether it can take a task before attempting the capture. -
4. Audit and compliance for free.
git logis the complete history: who sent what, who processed it, when. A distributed history that can't be rewritten unnoticed — every clone carries its own copy. For regulated industries, this is a level of audit trail that HTTP transport doesn't provide without a separate logging layer.
Production-ready mechanics
-
1. Atomic capture via
rename. When two agents race for the same task —rename(inbox/{id}.json → processing/{id}.json)on a single POSIX mount point is atomic: exactly one winner (CLAIMED), the rest getENOENT(LOST_RACE) orEEXIST(CONFLICT_EXISTS, escalate to human). Formalized indocs/ATOMIC_CAPTURE.mdwith an outcome table — not "we'll add a mutex somehow." -
2. JSON-RPC 2.0 as a contract.
Request and response fields are specified with explicit invariants (e.g., when
erroris set,resultmust benull). Any A2A-compliant agent from any vendor joins the bus without modification — the format is the same. -
3. Iteration Policy via
parent_id. A revision is a new task with a newidand aparent_idfield. The executor must load the base context fromoutbox/{parent_id}/before doing any work; if context can't be restored — stop and ask a human. Prior iteration files are never overwritten: you get a tree where two parallel revision branches coexist naturally. This resolves the old "where do I write v2" question in agent pipelines. -
4. Envelope pattern for heavy artifacts.
The machine response always goes into
outbox/res_{id}.json. If there are additional files (PDF, CSV, images) — a sibling directoryoutbox/{id}/withmetadata.jsonas inventory. Staging happens outsideoutbox/, with a single atomicrenameat the end. No half-assembled states ever appear inoutbox/. -
5. Separate roles for
renameand git.renameprotects against races locally;git pull/pushpropagates already-committed mutations between participants. Git is not responsible for capture atomicity — only for propagation and history. This separation of concerns makes the system predictable.
Comparison with breakdown #2 (bots-discuss-spec)
| #2 bots-discuss-spec | #14 a2a-file-bus | |
|---|---|---|
| Nature | Exploratory dialogue | Production-ready infrastructure |
| Participants | Exactly 2 agents | Any number of humans and agents |
| Artifact | One OpenAPI contract | Stream of tasks and responses of any kind |
| Standard | Custom chat protocol | Google A2A (JSON-RPC + agent manifest) |
| Audit | chat-history.txt |
Full git log across all participants |
| Why read it | Proof of paradigm | Ready environment for shared work |
If #2 answers "is this even possible," #14 answers "how to deploy it to a shared repo and use it with ten people." Read #2 →
Artifact
github.com/dobryakov/a2a-example — reference implementation of Google A2A on a file bus.
-
Specification:
PROTOCOL.md,docs/SYSTEM_INSTRUCTIONS.md(what the agent must and must not do),docs/ATOMIC_CAPTURE.md(capture model with outcome table),docs/VERSIONING.md(git as snapshot journal). -
Role manifests in
.well-known/agents/: Data Analyst, Product Manager — templates to extend with your owncapabilities. -
Ready Cursor and Claude integration:
.cursor/rules/a2a-file-bus.mdcand Claude skills for "text →inbox/" and "inbox/→ response." The bus works as a live operating environment for LLM agents out of the box. -
Request examples including a revision with
parent_id(docs/examples/).
To connect a partner's agent — grant them repository access (deploy key or org member),
place their manifest in
.well-known/agents/{agent_id}.json,
and lock in their inbox/ sort
strategy in their journal. No VPN, no API key exchange, no URL negotiation.
Where it breaks
-
Cross-mount.
renameis atomic only within a single mount point. Deployment contract: all bus directories on the same FS. -
Network filesystems.
On NFS,
renameguarantees are weaker than POSIX-local; double-success is possible in bad configurations. The bus is designed for each participant's local FS, with git as the transport between them. -
Concurrent git push.
If two participants commit simultaneously — conflict on remote, resolved via
pull --rebaseand retry. No data loss, but at high frequency you need a dedicated git-writer or serialization on the remote side (GitHub branch protection with a single merger). - Not for real-time. The bus is designed for passes triggered externally (cron, systemd.timer, webhook). Latency is seconds to minutes. For millisecond latency — use HTTP-transport A2A.
- Throughput capped by git. Tens to hundreds of messages per hour — fine. Thousands per second — no, you need a broker (Kafka/Redis Streams).
-
Artifact size.
Heavy binaries → Git LFS or reference in
metadata.json. A 2GB video inoutbox/kills participants ongit pull. -
Privacy.
All participants see the entire repository. For confidential tasks — a separate private
repo or egress redaction
(see breakdown #13)
before writing to
outbox/. -
Fairness not guaranteed.
The
inbox/sort strategy is each agent's choice — but it must be fixed permanently in its journal. -
Escalation over retries.
On
EEXIST/EIOthe agent stops and notifies a human rather than silently retrying. Slower on the happy path; eliminates a class of duplicate-processing bugs.
For whom and why
This is not a replacement for HTTP-A2A in a high-throughput production system. The use case is different: agents live with different people, teams, or organizations; nobody wants to run public endpoints with SLAs; audit trail and reproducibility matter more than throughput; you want humans to be able to assign tasks to each other's agents — using the same contract, without a separate UI layer on top.
The artifact's strength is in the contracts, not the code:
SYSTEM_INSTRUCTIONS.md
formalizes agent behavior to the level of "a violation is an execution error";
ATOMIC_CAPTURE.md
names races explicitly; Iteration Policy solves agent response versioning
architecturally, not with a naming convention.
For a CTO or architect, this is about the fact that Google A2A is a format, not a transport. And about how an open standard plus two POSIX primitives assemble a multi-tenant agent environment — without a broker and without vendor lock-in.
Designing multi-agent infrastructure across teams?
Transport, contracts, iterations, audit trail — architectural decisions to make before agents from three different organizations are all writing to the same inbox.
Email meOther breakdowns
An engineering breakdown series: real task → methodology → working artifact → honest breakdown of where it fails.
Back to series →