Blog
Post · 2026-06-16

The Fabric Is One Binary

A small kernel is necessary but not sufficient. The Minimal Genome settled what the kernel must hold — one irreducible primitive, everything else a projection. This is the next question: what must the kernel be, as a thing you ship? A federation is a distribution problem before it is anything else — a node cannot govern, mint, or join until the fabric is running on it — so the governing constraint is not the kernel's logic but its delivery: the fabric must land on any machine, of any architecture, with nothing else present, and run. Hold that one constraint and it selects the implementation for you. Not a language preference — a forcing function. The fabric must be a single, dependency-free, statically-linked binary. That is Go. Here is why we had to go, with every reason on the table.


The bottleneck was never the logic — it was the interpreter

For months the kernel was a Python daemon baked into a ~350 MB image, and for months the thing that fought us was not the code. It was getting the code onto a node. The symptoms were all distribution symptoms: a multi-arch build that silently emulated arm64 on amd64 under QEMU and ran the compile on the host instead of in-container; a Docker credential subsystem on the Apple-Silicon builder that demanded a keychain that headless builds do not have; a disk that filled because the image VM carried 14 GB that had nothing to do with the work; a CI runner that zombied trying to cross-build a 4 GB image under emulation. We solved each one — colima for the keychain, native per-arch runners, a disk reclaim. But solving them one at a time was the tell. Every fix was a patch on the same wound: an interpreter and a fat image do not distribute. A Python kernel is not one artifact you can hand a node; it is an interpreter of a specific minor version, plus a virtual environment, plus C-extension wheels matched to that node's libc and architecture, plus an image to carry them. The federation's real cost was paid every time a node tried to come up.

The insight that shrank the problem

The unlock was noticing what the kernel actually does. Its one mandate is to prove that work happened and mint its value: take a unit of work, hash-chain it into a signed attestation, and mint a conserved split to the authors. Written out, that is four primitives — sha256 for the chain, ed25519 for the signature that is the proof, json for the ledger row, and an HTTP surface to serve the shop of work-contracts. None of that is 4 GB. None of it is even 4 MB of dependencies. The scientific stack, the headless browser, the node toolchain — all the weight — were peripheral artifact generation that had been allowed to sit in the kernel because the kernel was an image and images accrete. Once you see that minting is kernel-level arithmetic and signatures, the fabric collapses to something tiny, and the only remaining question is how to ship something tiny to everyone.

Why Go — every reason

Distribution. A CGO_ENABLED=0 Go program compiles to a single statically-linked binary with no interpreter, no shared objects, no libc dependency. You curl it onto a node and it runs. There is no environment to reproduce. The colima/keychain/QEMU/disk saga does not get solved — it ceases to exist, because there is no image and no interpreter to fight.

Portability — in both senses. Build portability: GOOS=linux GOARCH=arm64 go build — one environment variable, any of ~45 OS/arch targets, from a single host, in seconds, with no cross-toolchain or sysroot. Runtime portability: the same static binary runs identically on scratch, Alpine's musl, a glibc distro, a Synology, a Raspberry Pi, or a rented cloud BOX. The CANONIC BOX pitch — "flash it onto anything you already own" — stops being marketing and becomes literally one binary per machine class from a single cross-compile.

Performance, measured — not just size. On the COIN=WORK hot path (Apple M4), the Go kernel beats the Python path ~4.9× on prove, ~5.2× on verify, and ~4–9× on cold start (4.7 ms versus 18–44 ms). Cold start is the one that compounds: it is paid on every node bring-up and every CI invocation, forever. Speed here is not vanity; it is the tax rate on joining the federation.

The standard library tells the truth. The sharpest fact: ed25519 — the signature that constitutes the proof — is not in the Python standard library. The "stdlib kernel" we claimed never was; it pulled a cryptography C-extension just to sign. Go's crypto/ed25519, crypto/sha256, encoding/json, and net/http are all stdlib, so the entire fabric is genuinely dependency-free. The thing that makes it distribute and the thing that makes it honest are the same thing.

Size. 8.5 MB unstripped, ~6 MB stripped, versus a 350 MB image. Forty to fifty times smaller — which is forty to fifty times less to move to every node, every time.

Memory safety where it is load-bearing. The fabric is network-facing and value-bearing: it parses untrusted peer JSON and signatures over HTTP, and it signs mints. A memory-safety bug on that boundary is a forged mint or a node takeover. Go is memory-safe by construction. For a daemon that signs money over a wire, that is not a nicety — it is the security model.

Why not C — and why C still scores

The honest challenger to Go here is not Python; it is C. C compiles to a smaller, faster binary with no runtime. So we measured instead of assuming: a tight bitmask loop, Clang -O2 versus Go — 826 versus 818 million operations per second. A one-percent difference, inside the noise. For the fabric's workload, Go is not slower than C; the gap people remember is C versus interpreters, not C versus a modern compiled language whose crypto routines are hand-written assembly. And against that ~1% you weigh what C costs the fabric: no standard-library crypto, JSON, or HTTP (you re-vendor OpenSSL, cJSON, libmicrohttpd — each a per-arch cross-compile, which puts the QEMU saga back); and memory-unsafety on the exact value-signing network boundary where it is most dangerous.

So the kernel is Go. But the MAGIC-255 scorer — the bitmask that measures a contribution's worth — stays C, and that is not a contradiction. It is the right factoring. The scorer is pure, hot, deterministic compute over fixed input, with no network and no untrusted I/O: the one place C's lack of a safety net costs nothing and its tightness is welcome. The OS invokes the scorer across a process boundary as a registered closure rather than inlining it — and that boundary does double duty, because the scorer is a trade secret and the process line is also the IP line. C measures work; Go mints it. Two languages because two jobs, joined by one seam.

The principle

A federation's kernel must be small — that was the genome. It must also be one thing you can hand to a node — that is the fabric. Those two constraints, taken together, do not leave much room: an irreducible primitive, shipped as a single dependency-free static binary that cross-compiles to every architecture and runs with nothing else present. Distribution stops being an operations problem and becomes a compile flag. That is the whole reason we had to go to Go — and it is why the fabric, now, is one binary.