Pillar · Multi-agent collaboration

Git as the Communication Layer for AI Agents

Multi-agent systems need a coordination channel that outlives the chat window. A Git ref with compare-and-swap writes and union-merge-by-id is a lossless multi-writer mailbox — durable, auditable, and broker-free. Here is the mechanics, the honest tradeoffs, and where it loses to a message bus.

Key takeaways
  • Agent coordination should live next to the artifact (branch and commit) and survive the chat window that produced it.
  • Compare-and-swap on send plus union-merge-by-id on pull turn a plain Git ref into a lossless multi-writer mailbox with no broker.
  • Git-native messaging trades latency and presence for durability, auditability, and zero infrastructure — right for handoffs, wrong for live chat.

A year ago "multi-agent" meant one model in a loop. Now it means a Claude Code session writing a branch while Codex reviews it, a third agent runs the long task, and a human steps in to redirect — often on different machines, rarely all awake at the same second. The hard part is no longer making one agent competent. It is getting several of them to coordinate without losing the thread: who asked for what, which risk was already flagged, who owns the next step, what counts as done.

Most teams answer this with the chat window. That works until the session ends. The ask, the review note, the "I already handled that" — all of it lives in a transcript that is not attached to the branch it was about, and is gone the moment the context resets. Coordination state that does not survive the session is not coordination state; it is a conversation you have to reconstruct.

This article makes a narrower claim than "use Git for everything." It is that the coordination channel for asks, reviews, risks, and handoffs should live next to the artifact — the branch, the commit, the file — and that a single Git ref, written with compare-and-swap and reconciled with union-merge, gives you a lossless multi-writer mailbox with no server to run. You already know Git's basics; the part worth your attention is why those two mechanics turn an append-only ref into a mailbox, and where that trade is wrong. Git-native handoffs are also one of the coordination pillars inside an auditable workspace: every ask, review, risk, and handoff recorded in the repo, provable after the fact.

Why a ref is the substrate, not a server

Strip the messaging idea down and you are choosing where coordination state lives. The candidate properties you want: it travels with the code, it survives a machine or a session, it cannot be silently rewritten, and it needs no always-on service. A Git ref has all four, and you did not have to build any of it.

h5i builds on this directly: cross-agent messages live in refs/h5i/msg as an append-only messages.jsonl (one JSON message per line) plus an agents.json roster. They move with h5i share push and h5i share pull — they are not carried by a plain git push, which only moves refs/heads/*. (For the on-the-wire field layout — version, kind, reply_to, thread_id, priority, focus, risk, links — see the i5h protocol deep dive; this post stays at the substrate altitude.)

A Git ref as a lossless multi-writer mailbox

Here is the part that is not obvious. A single ref looks like a single-writer thing — it points at one commit, and a naive "read tip, write new commit, move ref" loses data the moment two agents do it at once. The trick is two mechanics working together: compare-and-swap on write, union-merge-by-id on reconcile.

Compare-and-swap on send

A send does not blindly move the ref. It reads the current tip, builds a new commit that appends one line to messages.jsonl off that tip, and then moves the ref only if it still points where it was read. If a concurrent writer in the same clone moved the tip first, the swap fails; the sender re-reads the new tip and retries. h5i's append_message_cas loops this up to 64 times — a writer would have to lose that many consecutive races to error — so bursty concurrency (several agents sending into one clone at once) never silently drops an append. This is the standard optimistic-concurrency pattern, applied to a ref instead of a database row: no locks, no broker, and no lost write under contention within a clone.

Union-merge-by-id on pull

Compare-and-swap solves contention inside one clone. It does nothing for two agents on two machines who both committed off the same tip and pushed — that is a genuine divergence, and a fast-forward-only push would reject one of them. Here the append-only discipline pays off. Because no message is ever edited, the two messages.jsonl blobs are two sets of immutable lines, and reconciliation is set union keyed by message id. h5i's union_merge_commits takes the union of both message sets (de-duplicating by id), then sorts the result into a stable (timestamp, id) order; the two rosters merge by keeping the latest last-seen per agent. Neither side's messages are clobbered — you end up with both.

Why this is lossless: a message is identified by its id, and union never discards a line that exists on either side. Two agents can write blind to each other and, after a pull, both messages are present. What it costs is precise, and worth stating plainly:

In practice the command surface hides all of this. You send typed messages — ask, review, risk, handoff, and the typed replies reply, ack, done, decline — addressed to one agent or broadcast to all. Identity comes from $H5I_AGENT (Claude Code sets it to claude), so no --from is needed in the common case.

~/repo
$ h5i msg review --branch auth --focus src/auth.rs codex "review token refresh edge cases"
$ h5i msg risk --priority high all "billing cache crosses tenants"
$ h5i msg done 1 "fixed in 8f21c3a"
$ h5i share push   # refs/h5i/msg does not ride a plain git push

How it fails, and why those failures are acceptable

A substrate is only as good as its failure modes are understood. The Git-native ones are real and bounded.

None of these is fatal for the use case the substrate is chosen for: durable, low-frequency coordination events. They would be disqualifying for live chat. That is the whole point — pick the substrate to match the traffic.

Git-native versus the alternatives

The honest way to argue for a substrate is to say what it gives up. Here is where a Git ref wins and where it does not.

The pattern across the comparison: every alternative that beats Git on latency or presence loses to it on durability, code-adjacency, or zero-infra — and vice versa. There is no free lunch, only a fit. For asks, reviews, risks, and handoffs, the Git-native trade is the right one. For a live operator chat or a high-rate event stream, it is not.

What goes in a message versus a context trace

Choosing the substrate is half the discipline; the other half is what you put on it. The failure mode of any durable channel is that it becomes a dump of everything, at which point it is as useless as no channel. The line h5i draws: messages are coordination events; routine observation is a context trace.

A trace records what an agent did and saw — the work. A message records a decision that requires another party: an ask that expects a response, a risk that the next agent must inspect, a review request scoped to a file, a handoff that transfers ownership, an acknowledgement that closes a loop. If a line does not change what someone else should do, it is a trace, not a message.

That keeps the channel both readable and searchable after the session is gone. A good message is self-contained: it names the branch, the file or behavior at issue, the response expected, and the evidence already known. "Review auth retry behavior in src/auth.rs; concern is duplicate refresh after timeout" survives the loss of its chat window. "Look at this" does not.

The handoff case is where this earns its keep. Multi-agent work fails most often not from a bad change but from ambiguous ownership — two agents redoing the same task, or both assuming the other handled a risk. A handoff message makes ownership explicit: who owns the next step, what result counts as done, whether a reply, review, or fix is expected. That small structure, recorded durably next to the branch, is the difference between coordination and two monologues.

Conclusion: pick the substrate for the traffic

There is no universal coordination layer for AI agents, and the useful question is not "real-time or durable" in the abstract — it is which trade matches the traffic in front of you. Asks, reviews, risks, and handoffs are low-frequency, high-consequence, and inherently tied to a branch or commit. For that traffic, a Git ref written with compare-and-swap and reconciled with union-merge-by-id is a lossless multi-writer mailbox you already have the infrastructure for: it travels with the code, it cannot be silently rewritten, it works offline and across clones, and it costs you a server you never have to run. The price — eventual delivery, poll-or-wake instead of push, no global causal clock — is real, well understood, and acceptable exactly where this channel is used.

Where it is the wrong tool — live operator chat, sub-second streams, synchronous RPC between two agents that are both awake — reach for a bus or an A2A-style protocol and let them complement the durable log rather than replace it. Use the chat window for the conversation with the human; use the ref for the coordination that has to outlive it.

FAQ

Is Git fast enough for AI agent messages?

For durable task handoffs, reviews, and risk notes, yes. A Git ref trades sub-second latency for durability and auditability: an agent must pull to see new mail, so delivery is eventual, not real-time. h5i bridges the gap with a Stop-hook that surfaces new messages between turns and an h5i msg wait background waiter that wakes on arrival. It is the wrong substrate for live, sub-second chat and the right one for asks, reviews, risks, and handoffs.

How does a plain Git ref avoid lost messages with many writers?

Two mechanisms. A send is a compare-and-swap against the ref tip: build a commit off the tip you read, then move the ref only if it still points there; retry on contention. Across clones, pulls union-merge the append-only messages.jsonl by message id, so two agents pushing from different machines reconcile into the union of both message sets instead of one clobbering the other. The cost is eventual consistency: ordering is a per-id merge, not a global clock, so causal order rides on thread_id and reply_to.

Should every agent thought become a message?

No. Routine observation belongs in context traces. The message channel is reserved for coordination events — asks, reviews, risks, handoffs, acknowledgements, and completion — so it stays readable and searchable after the session ends.

How does Git-native messaging compare to a message bus like Kafka or to MCP?

A message bus gives real-time, ordered delivery but is a server to run and is not code-adjacent or auditable by default. MCP is a tool/transport protocol for one agent's tools, not a durable multi-agent log. Live agent-to-agent RPC protocols such as Google's A2A need both endpoints up at once. A Git ref is complementary: it works async and offline, travels with the code, and is auditable by construction — at the cost of presence and server-push.

Can humans read the messages?

Yes. The ref is plain text under refs/h5i/msg, and the point is an auditable channel that both agents and humans can inspect — including in a PR body, where relevant message history can be surfaced for human review.

Sources and verification

This article avoids vendor-specific claims that were not checked against primary docs or local h5i CLI behavior.

Try h5i on your next AI-assisted branch

Create a sandboxed workspace, capture the run, and post a review-ready PR brief. h5i records prompts, context, test evidence, review signals, and agent messages alongside normal Git history.

Star on GitHub Read the guides