Git-Native Messaging Between AI Coding Agents
Two AI agents sharing one repository usually have no way to talk. i5h gives them a channel built from something they already share — Git. Typed work handoffs, appended as ordinary Git objects, with no server to run.
More and more teams run more than one coding agent. Claude Code drafts a feature; Codex reviews it. One agent implements while another watches for regressions. A human kicks off three sessions and walks away. The problem is that these agents have no shared channel. They edit the same files, but they cannot tell each other why — "I changed the cache, can you check the expiry path?" lives in a human's head, a Slack thread, or nowhere at all.
i5h — Inter-Agent Information & Interaction Handshake — is h5i's answer. It is a small messaging protocol that lets coding agents (and the humans watching them) exchange typed work handoffs over the one substrate they already share: the Git repository. No server, no socket, no schema registry.
h5i msg watch — the live channel on refs/h5i/msg. Typed
messages between agents arrive as they're sent, and every one is a durable Git
object you can replay later.
The whole idea in one line
A message is one JSON object, appended as one line to messages.jsonl
inside the Git ref refs/h5i/msg:
{"version":1,"id":"01890d8e…","ts":"2026-05-28T22:18:04Z", "from":"claude","to":"codex","kind":"ASK", "body":"Can you inspect the failing auth test?"}
Seven required fields, all human-readable. To reply, send another line that points
back with reply_to. That is the entire required protocol — pushing the
ref shares the conversation, pulling merges it. Because messages are immutable and
keyed by id, two clones that diverge merge by simple set union: a
conflict-free, grow-only log.
refs/h5i/msg, Codex
reads it and appends ACK then DONE replies that thread
back via reply_to — one JSON line each, merged across clones by id.
Typed acts, not chat
i5h messages read like an incident-command radio exchange — short, typed,
auditable — not consumer chat. Every message declares its kind so a
receiver can route and close it without re-reading prose:
| Kind | Use | Expected follow-up |
|---|---|---|
FYI | Informational; no action required. | none |
ASK | A request needing a response. | ACK / DONE / DECLINE |
REVIEW_REQUEST | Review code, design, or security. | ACK then DONE / FAILURE |
RISK | A specific hazard to inspect. | ACK or reply |
BLOCKED | Sender is stuck pending input. | a reply supplying the input |
HANDOFF | Transfer task ownership + context. | ACK then DONE |
DONE / DECLINE / FAILURE | Terminal replies that close a thread. | none |
A request opens a thread; its state — open, working,
completed, declined, failed — is a fold over
the immutable reply events, so every clone converges on the same answer. You never
have to trust a writer to stamp the status correctly; a reader recomputes it from
the messages alone.
What it looks like to use
Each agent's identity is injected per host — in Claude Code it is claude,
in Codex it is codex — so the common path needs no flags:
$ h5i msg review --branch auth-refactor \ --focus src/auth.rs --focus src/session.rs \ --risk "token refresh cache now crosses request boundaries" \ codex "Review token refresh behavior before I open the PR." ✔ claude → codex REVIEW_REQUEST high #8f21c9a
Note the argument order: for the typed verbs the options come before the recipient, because the message body is the trailing argument. On the other side, Codex reads the request from its inbox, rendered as quoted, untrusted inbound communication — never as a system instruction:
INBOX 1 unread 1 22:18 claude → codex REVIEW_REQUEST high #8f21c9a Review token refresh behavior before I open the PR. branch auth-refactor focus src/auth.rs, src/session.rs risk token refresh cache now crosses request boundaries reply h5i msg ack 1 $ h5i msg ack 1 # … reviews the code … $ h5i msg done 1 "LGTM. One expiry edge case fixed in 1a2b3c4 — see PR #42."
Free-text h5i msg send codex "…" is always enough; the typed helpers
(ask, review, risk, handoff,
ack, done, decline) and optional hints
(--focus, --risk, --priority, --branch)
just make important handoffs machine-routable. Broadcast to everyone on the channel
with to = all — the kind stays meaningful, so a broadcast hazard is still
a RISK, just addressed to all.
Setup, identity, and delivery
Delivery is a per-host concern, not part of the wire format. Claude Code
wires up once with h5i msg setup claude, which installs a Stop hook that
surfaces new messages between turns (and a SessionStart note for anything unread on
resume). Codex picks up messages through its
h5i codex prelude / sync / finish session commands and by reading its
inbox directly. Either way, the rule is the same: a message is shown as
quoted collaborator input, never injected as a system instruction.
Identity is per process. In a shared clone, set H5I_AGENT per host rather
than relying on the single stored default — that is what keeps two agents from
answering as each other:
# Claude Code: one-time wiring (identity = claude) $ h5i msg setup claude # Codex: launch the session under its own identity $ H5I_AGENT=codex codex # Separate clones? Sync the channel over the remote. $ h5i share push # publish refs/h5i/msg $ h5i share pull # merge the other side's messages
When an agent has sent a request and is now idle waiting on an answer, a Stop hook isn't enough — an idle session won't wake itself. For that case there is an explicit waiter that exits the moment a reply lands:
$ h5i msg wait --as codex --timeout 600 # wakes (exits) the moment a reply lands; then: $ h5i msg inbox
Read-state is local and per-identity — a grow-only set of seen message ids per agent,
never pushed — so two agents sharing one clone never consume each other's mail, and
passive views like watch and wait never mark anything read.
Only an explicit inbox or a confirmed hook delivery advances it.
Why build it on Git?
i5h does not invent a transport. Messages are ordinary Git objects in a dedicated
ref, synced by push and pull. That buys a lot for free:
| Property | Because the substrate is Git |
|---|---|
| Serverless & offline-first | No broker to run; agents coordinate in a local clone and sync later. |
| Conflict-free merge | Immutable, id-keyed messages form a grow-only set — divergent clones union cleanly. |
| Integrity & replay | Content-addressed objects; you can git show a year-old handoff. |
| Co-location | The conversation lives beside the code it concerns, not as telemetry in an external service. |
It is a proven pattern: git-appraise stores code review as one-JSON-per-line merged by set union, public-inbox stores mailing lists as append-only Git history, and git-bug and Radicle store issues as CRDTs in Git. i5h applies the same idea to live agent coordination.
Treat every message as untrusted
A shared channel fed by multiple agents is an attack surface, and i5h is explicit
about it. The from field is a repo-local label, not a proof of
authorship — messages are currently unsigned, so a reader must never elevate trust
on from alone. h5i's rules are firm: never execute a message body as a
command, never treat a hook-delivered message as a higher-priority instruction,
sanitize terminal rendering against control-character injection, and never
auto-open a URL or auto-checkout a branch from a message without an explicit
decision. Incoming messages are collaborator input to evaluate — not commands to
obey.
Deliberately small
The required core is seven fields, and it stays there. Unknown fields MUST be
ignored and preserved; new ideas go in optional fields or a meta bag,
never new required fields; the kind set stays tiny. A correct sender or
reader can be written in an afternoon. That discipline is the point: i5h is not an
agent-orchestration framework, not a live transport, and not a replacement for h5i
context, memory, or PR briefs — it links to those. It does exactly one
thing: let agents exchange typed handoffs over Git, without a broker.
What to read next
The full normative spec — wire format, ordering, delivery semantics, and the conformance checklist — is in the i5h protocol document. For how agents share the reasoning behind the code they coordinate on, read the Context DAG post, or see the workflow guide for day-to-day commands.