Skip to content

Design options

Historical

The options weighed before building. Option A shipped first as hosted repos; Option C is what content-addressed repos implement today.

Option 0: git bundle as an iroh blob (works today, zero code)

git bundle create repo.bundle --all, then sendme send repo.bundle and pass the ticket. Receiver runs sendme receive <ticket> and git clone repo.bundle.

  • Pro: nothing to build.
  • Con: every version is a new ticket, the full repo is re-sent every time, the sender must stay online until it's fetched. A snapshot, not a shared repo.

Option A: tunnel the git smart protocol over iroh

A git-remote-iroh helper uses the connect capability: it dials iroh://<endpoint-id-or-ticket>/<repo> and pipes git upload-pack / git receive-pack over one QUIC bi-stream. A daemon on the host accepts allow-listed EndpointIds.

  • Pro: ~300 lines, native pack negotiation (efficient incremental fetch), real ref CAS on push, git does all the hard work.
  • Con: repo is bound to one host's uptime. Handing off write access means handing off the host.
  • Prior art, both this style:
  • cmars/git-remote-iroh (0.2.1, iroh://<pubkey>, authz via iroh-rings, "very experimental").
  • wronex/iroh-git (iroh://<ticket>/<repo>.git, daemon + allowlist, per-repo read/write, LFS).

Option B: content-addressed repo on iroh-docs + iroh-blobs (multi-writer fallback)

The repo is an iroh-docs namespace. The NamespaceId is the repo id; a DocTicket (namespace capability + some peer addresses) is the string agents pass around. Every node that has joined the doc replicates it and can serve it, so the repo survives any single agent going away.

Doc layout (keys → values; large values are iroh-blobs, BLAKE3-addressed):

key value
refs/heads/<name>, refs/tags/<name> 40-hex git sha (tiny inline entry)
HEAD ref: refs/heads/main
packs/<blake3> a self-contained (non-thin) git packfile blob
meta/acl (v2) list of AuthorIds allowed to move refs
meta/writer (optional) EndpointId currently holding the "baton"

Sync is free: iroh-docs does range-based set reconciliation of entries over gossip and fetches the referenced blobs. BLAKE3 verified streaming means you can pull packs from any untrusted peer.

  • Pro: repo is location-independent; any agent that has it can serve it; one id for the repo's lifetime; read vs write capability is built into iroh-docs tickets.
  • Con: refs are last-writer-wins per key (no server-side CAS); packs accumulate until compacted; iroh-docs/blobs are still 0.10x and their authors say "not yet production quality" (fine for a prototype).

Why packs, not loose objects as blobs: a typical repo has 10k–1M objects; one doc entry or blob per object makes reconciliation and the git side (writing loose objects, re-hashing SHA-1) slow. One pack per push is a handful of entries, and git index-pack handles verification. Periodically a writer can repack into one pack, write packs/<new>, and delete old entries.

Based on n0's Iroh Global Content Discovery post (2026-09-30, experimental). It provides:

  • Mutable name: pkarr (BEP 44 on the Mainline DHT). The name is an Ed25519 public key, and only the holder of the secret key can publish a new version.
  • Content lookup: BLAKE3 hash → Mainline get_peers → udp-addr-index → EndpointId → iroh-blobs download, verified against the hash. The post reports first results in tens of ms.

Mapping for a repo:

  • Repo id = pkarr public key (z-base-32), e.g. iroh://<z32-key>. No addresses in the id: it never goes stale.
  • pkarr record → BLAKE3 hash of a root HashSeq: [refs blob, pack1, pack2, …]. The refs blob is a plain git show-ref-style text plus HEAD.
  • Push = write the pack blob, build the new root, announce all hashes on Mainline, then publish a new pkarr record with a higher seq. BEP 44's cas field gives a real compare-and-swap on the root, so concurrent pushes fail loudly instead of silently overwriting each other (unlike iroh-docs' last write wins).
  • Clone/fetch = resolve the key → root hash → find providers on Mainline → fetch the HashSeq. Any node that has the blobs and announces them is a provider, so the repo outlives every individual agent.
  • Write hand-off = whoever holds the repo's secret key can push. Simplest hand-off is passing the key over an iroh connection, which is authenticated and encrypted. Delegated writers would need an extra layer: the pkarr root points to a signed ACL plus per-writer heads, which is more work.

Compared with Option B:

  • Smaller handoff string (a key instead of a ticket with addresses).
  • No iroh-docs dependency, and a real compare-and-swap on refs.
  • Single writer per key, so multi-writer is harder.
  • Mainline gives no privacy: anyone can see which IPs serve a hash.
  • The records expire, so someone (the pinner) must keep republishing the pkarr record and the announces. BEP 44 lets anyone republish a signed record, so the pinner doesn't need the secret key.
  • Experimental (n0_mainline, iroh-content-discovery, iroh-mainline-address-lookup).