Sovereign CI — Build Infrastructure
How ecoPrimals builds, checksums, and distributes 30 binary artifacts across 15 primals and 2 architectures — entirely self-hosted.
Overview
Every ecoPrimals binary is built from source on sovereign infrastructure. No GitHub Actions for production builds. No cloud CI. No third-party artifact registry. The build host (sporeGate) pulls from Forgejo (git.primals.eco), cross-compiles for two target triples, computes BLAKE3 checksums, and publishes to the depot.
Build Pipeline
Forgejo (git.primals.eco)
│
│ golgi cascade timer (15-min quorum)
▼
sporeGate — Sovereign CI
│
├── cargo build --release --target x86_64-unknown-linux-musl
├── cargo build --release --target aarch64-unknown-linux-musl
│
├── BLAKE3 checksums → checksums.toml
│
└── rsync → depot (membrane.primals.eco/depot/{triple}/{binary})
│
├── Gates cascade + pull binaries
└── depot-verify validates BLAKE3 integrityBinary Inventory (Wave 133a)
? primals compiled to 30 ecobins — 15 per architecture.
| Binary | x86_64-musl | aarch64-musl | Ratio |
|---|---|---|---|
| petalTongue | 28 MB | 25 MB | 90% |
| Songbird | 23 MB | 20 MB | 90% |
| biomeOS | 20 MB | 18 MB | 92% |
| sweetGrass | 13 MB | 14 MB | 101% |
| ToadStool | 13 MB | 9.7 MB | 75% |
| BearDog | 11 MB | 8.8 MB | 80% |
| NestGate | 8.1 MB | 7.0 MB | 87% |
| coralReef | 7.7 MB | 6.8 MB | 84% |
| rhizoCrypt | 7.5 MB | 6.1 MB | 81% |
| barraCuda | 5.4 MB | 4.3 MB | 79% |
| loamSpine | 4.5 MB | 3.8 MB | 85% |
| Squirrel | 4.3 MB | 3.4 MB | 78% |
| nucleus_launcher | 4.2 MB | 3.4 MB | 81% |
| sourdough | 3.0 MB | 2.6 MB | 83% |
| skunkBat | 2.8 MB | 2.4 MB | 85% |
| Total | 153 MB | 130 MB | 85% |
All binaries are statically linked against musl libc — no runtime dependencies. The aarch64 binaries run on grapheneGate (Pixel 8a, GrapheneOS) and future ARM nodes.
Build Convention
For a primal to be CI-buildable with zero manual intervention:
- Binary discoverable from workspace root:
cargo build --release --target $TRIPLE --bin $slug - No special linker requirements beyond the global
.cargo/config.toml - Toolchain declared in
rust-toolchain.toml - Binary name = primal name lowercase with no separators
Currently 11/14 primals meet this convention. Three require workarounds:
- biomeOS: needs
--package biomeos-unibin - skunkBat: needs
--package skunk-bat-server - NestGate: requires
ld.lldlinker (project config divergence)
These are documented divergences being converged by upstream teams.
Verification
Any gate can verify its local depot against the published checksums:
spore-validate depot-verify \
--checksums /path/to/checksums.toml \
--depot /path/to/depot \
--arch x86_64-unknown-linux-musl--partial mode allows incremental verification — pass when all present binaries verify, even if the depot is incomplete. This supports staged rollouts where not all binaries have been pulled yet.
Cascade Flow
The cascade is the heartbeat of the ecosystem. Every 15 minutes:
golgi (VPS)
→ pulls all 17+ repos from Forgejo
→ writes heads/golgi.toml (its local HEADs)
→ runs unify_freshness() → regenerates freshness.toml
→ pushes wateringHole to GitHub (trailing mirror)
Each gate after cascade:
→ writes heads/<gate>.toml with its local repo HEADs
→ pushes wateringHole (FF-only pull first, no conflict)The write model is conflict-free: wave.toml is sole-writer (overwatch), each gate writes only its own heads/<gate>.toml. No merge conflicts. Ever.
Related
- Deployment Model — how binaries flow from depot to gates
- Living Systems — what’s actually running right now
- Gate Mesh — Live Topology — how gates connect