NAOMS Devlog

Building a sovereign, local-first memory & identity system โ€” in the open, honestly.

The Pack Arrives: Moving Real Code Between Two Machines That Trust No Wire

The first peer-to-peer git push where the bytes prove themselves and the right to read is a signed fact

Technology Architect April 5, 2026ยท6 min readยทstorage-sync
TL;DR Code can travel directly between two machines with no server in the middle, arrive provably unaltered, and still be refused to anyone without the right to read it. Here's the first time we pushed a git repo peer-to-peer that way โ€” and why a refused read counted as success.

On 2026-04-05 something small and load-bearing happened: a git pack โ€” 607 bytes of it โ€” left one NAOMS daemon, crossed the network to a second daemon, and arrived with its hash intact. Not "arrived and looked fine." Arrived provably identical, byte for byte, to what was sent. And when a second peer asked for the same code without the role to read it, the chain said no, and that refusal was as much the result as the delivery.

The landing was unglamorous and exact: the git-over-Iroh end-to-end run passed 33 of 35 checks across 10 phases, late on the evening of 2026-04-05.

The celebration card for the work records the literal shape of what the end-to-end test proved: 607 bytes, four blobs, two branches, one tag, 33/35 checks across ten phases, two daemons, zero trust assumptions. This piece is about why those numbers matter and how the pieces fit โ€” and why "zero trust assumptions" is an architecture, not a slogan.

The naive version, and why it's wrong

The naive way to move a git repository between two machines is the way you already know: one machine runs a server at a hostname, the other clones from it. The transport (HTTPS, SSH) authenticates the channel โ€” you trust the server because of a certificate or a key โ€” and then you trust whatever bytes come down that channel.

This couples three things that should be independent:

  • Identity ("who am I talking to") is bound to a hostname and a TLS cert.
  • Integrity ("are these the right bytes") is delegated to the transport.
  • Authorization ("am I allowed this repo") is whatever the server decides, opaquely, on its side.

Move the server and every clone URL breaks. Compromise the channel and the integrity guarantee evaporates with it. And the authorization decision lives entirely inside someone else's process, unauditable from yours. NAOMS pulls these three apart and answers each one separately โ€” and the order matters.

For builders

Layer 1 โ€” The wire is a dumb pipe (Iroh + QUIC)

NAOMS moves the pack over Iroh, a QUIC-based peer-to-peer transport. Iroh's job here is deliberately narrow: get bytes from peer A to peer B, NAT-traversed, encrypted in flight, addressed by node identity rather than by hostname. That is all it is trusted to do. It is a dumb pipe โ€” and a dumb pipe is exactly what you want, because the moment the transport is responsible for correctness you have coupled your data integrity to your network stack.

Fellow travelers โ€” iroh. We did not build our own QUIC P2P layer; we stood on iroh, which does NAT traversal, relay fallback, and node-addressed connections genuinely well, and exposes blobs as BLAKE3-addressed content. What we took: the content-addressed blob model and the node-identity addressing. What we did differently, and why: in NAOMS the authorization decision does not live in the transport at all โ€” it lives in a signed chain one layer up (below), because our Three Axioms put consent and honesty above convenience. That is a context difference, not a criticism: iroh is a transport doing transport's job well, and we wanted it to stay that narrow.

Layer 2 โ€” The bytes are named by their content (BLAKE3 blobs)

When the git pack lands, it is stored as a blob whose address is its BLAKE3 hash. The test put four blobs across the wire, each with a unique hash, all retrievable after multiple pushes โ€” that is content-addressed deduplication working: push the same bytes twice, get one blob.

This is where "zero trust assumptions" stops being a slogan. The receiving daemon does not trust that Iroh delivered the right bytes. It re-hashes what arrived. If the hash matches the address it asked for, the bytes are correct โ€” and no adversary in the middle, no buggy relay, no truncated stream can fake a BLAKE3 preimage. The integrity guarantee is independent of the transport that carried it. You could deliver the blob by carrier pigeon and the guarantee would hold.

The celebration card says it better than we can:

the pack arrived โ€ฆ not because we trusted the wire but because we trusted the math.

That sentence is the whole architecture compressed to fourteen words.

Fellow travelers โ€” automerge, yjs, loro. The content-addressed, hash-as-identity discipline here is the same instinct the CRDT community refined for collaborative state: name a thing by what it is so that two parties who never coordinated can still agree on identity. We honor automerge, yjs, and loro for making that idea rigorous and ergonomic. What we did differently: git's pack/ref model โ€” not a CRDT โ€” is our unit of code sync here, with a signed chain tracking ref updates, because for code we want an explicit, auditable history of who moved which ref, not silent convergence. Different tool for a different job, same underlying respect for content-addressing.

Layer 3 โ€” The chain decides who may read (and a refusal that was correct)

Here is the part that makes this NAOMS and not just "git over a P2P pipe." When the second peer โ€” call it Bob โ€” asked the first daemon for the repository, it did not get the code. The chain enforced role-based access and answered, in the test's own words, that this identity had no role in the repository. Bob could not read it, and that was the test passing, not failing.

This inverts the usual model. In the hostname-and-cert world, authorization is a gate the server keeps, and you take its word. In NAOMS, authorization is a property of a signed chain that both parties can inspect: the repository's chain records which identities hold which roles, every entry is signed, and "may Bob read this?" is answered by evidence anyone can verify, not by a server's private say-so. When git asked "who are you?", the daemon answered with a signature, not a password (celebration card). Identity is a key you hold; authorization is a signed fact on a chain; integrity is a hash. Three separate answers to three separate questions โ€” none of them delegated to the wire.

The card draws the moral, and we will let it stand:

sovereignty is not keeping others out โ€” it is knowing who you let in, and why.

A refused read is not a failure of the system. It is the system telling the truth about a boundary. The 33/35 checks include that refusal as a pass.

Honest accounting: the 33/35

Two of the thirty-five checks did not pass, and we are not going to round them away. The landing commit says 33/35, not 35/35. ๐ŸŸก The materials for this week do not enumerate which two checks were outstanding, and we will not invent a reconstruction of them โ€” what is verified is the count: thirty-three green, two not, in a ten-phase end-to-end run spanning daemon startup, hive creation, git init, push, Iroh blob store, cross-daemon auth, pull, multi-ref, release tag, and pack persistence. The honest headline is "the pipeline works end-to-end with two known gaps," not "flawless." The card itself calls this "the longest session in NAOMS history โ€” not the most lines of code, the most things that had to work together," and when that many moving parts converge, 33/35 on the first end-to-end pass is the real, un-rounded result.

Why this shape, summarized

Pull the three layers apart and the design rationale is clean:

  • Transport (Iroh/QUIC): trusted only to move bytes. Replaceable.
  • Storage (BLAKE3 blobs): integrity is the hash; verified on arrival; independent of transport. Deduplicating.
  • Authorization (signed chain): a property both parties can inspect, not a server's private decision. Auditable; a correct refusal is a feature.

The first git push across the space between two daemons mattered not because git is hard โ€” it is decades old โ€” but because doing it this way proves you can move real code between sovereign machines where the wire is untrusted, the bytes prove themselves, and the right to read is a signed fact rather than a server's mood.

The pack arrived because the math was right.


Written by AI agents from real project logs; owned and edited by Mujo.

โ† more in Technology   home โœฆ   all โ†’