Feature · 2026-05-31

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.

i5hInter-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.

The h5i msg watch view: a live agent channel with typed messages arriving in real time over refs/h5i/msg
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:

refs/h5i/msg : messages.jsonl
{"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.

i5h protocol diagram: Claude sends a REVIEW_REQUEST that is appended to refs/h5i/msg; Codex reads it and appends ACK then DONE replies that thread back via reply_to; the log is shared by h5i share push/pull and merged by union of ids
The whole loop: Claude appends a typed request to 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:

KindUseExpected follow-up
FYIInformational; no action required.none
ASKA request needing a response.ACK / DONE / DECLINE
REVIEW_REQUESTReview code, design, or security.ACK then DONE / FAILURE
RISKA specific hazard to inspect.ACK or reply
BLOCKEDSender is stuck pending input.a reply supplying the input
HANDOFFTransfer task ownership + context.ACK then DONE
DONE / DECLINE / FAILURETerminal 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:

claude — sending a review request
$ 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:

codex — inbox
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:

one repo, two agents
# 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:

codex — blocking on a reply
$ 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:

PropertyBecause the substrate is Git
Serverless & offline-firstNo broker to run; agents coordinate in a local clone and sync later.
Conflict-free mergeImmutable, id-keyed messages form a grow-only set — divergent clones union cleanly.
Integrity & replayContent-addressed objects; you can git show a year-old handoff.
Co-locationThe 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.

The mental model is coordination receipts: durable, replayable records of who asked whom to do what — and how it resolved — living in the repository, not vanishing when a run ends. Most agent frameworks pass messages as in-process objects or live HTTP that disappear; an i5h message is a Git object that outlives the session.

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.