Linux Builder and Publication Contract
Defines builder classes, cache responsibilities, derivation publication policy, and the canary validation lane for GloriousFlywheel CI.
Builder Classes
| Class | Runner | Image | Capabilities | Use Cases |
|---|---|---|---|---|
| nix-builder | gh-nix | ghcr.io/tinyland-inc/actions-runner-nix | Determinate Nix, Attic client, cache/runtime hints | Flake builds, checks, NixOS tests, OCI image builds |
| general | gh-docker | ubuntu-latest equiv | Standard CI tooling, pnpm, Node.js | Unit tests, linting, type checking, markdown validation |
| container | gh-dind | docker:dind | Docker BuildKit, multi-stage builds | OCI image builds, container integration tests |
| kernel | linux-xr-docker | rockylinux:10 | GCC toolchain, kernel headers | linux-xr kernel module builds |
Builder Responsibilities
nix-builder (gh-nix):
- Evaluate and build Nix derivations
- Push build results to Attic binary cache
- Run
nix flake checkfor formatting, linting, dead code analysis - Build OCI images via nix2container
- Publish flake to FlakeHub on release
general (gh-docker):
- Run SvelteKit app tests (vitest), type checks, linting
- Run MCP server tests
- Validate OpenTofu modules (
tofu validate) - Check documentation links and markdown formatting
container (gh-dind):
- Build and push container images with BuildKit registry cache
- Run container-based integration tests
- Produce OCI artifacts for deployment
kernel (linux-xr-docker):
- Compile linux-xr kernel modules against specific kernel versions
- Restricted to max 2 concurrent runners (resource-heavy builds)
Cache Hierarchy
Three independent cache systems serve different build ecosystems. Each has a clear authority boundary.
+-- FlakeHub (public publication)
| Authority: public flake distribution
| Content: released flake versions (tagged + main)
| Consumers: external users, downstream flake inputs
| Populated by: .github/workflows/flakehub-publish.yml
| Auth: OIDC (no secrets)
|
+-- Attic (private binary cache)
| Authority: internal Nix build artifacts
| Content: all CI-built derivations, dev shell closures
| Consumers: CI runners, dev machines
| Populated by: nix-builder post-build push
| Auth: Attic signing key per machine/runner
|
+-- Bazel Remote Cache (build action cache)
Authority: Bazel action results and CAS
Content: compiled outputs, test results, validated configs
Consumers: CI runners, local dev (via remote cache)
Populated by: any Bazel build/test invocation
Auth: mTLS or token (cluster-internal)
What Goes Where
| Artifact | Cache | Reason |
|---|---|---|
| Nix derivation (any) | Attic | Internal build cache, fast CI rebuilds |
| Released flake | FlakeHub | Public distribution, semantic versioning |
| Bazel action output | Bazel Remote Cache | Action-level caching, content-addressed |
| Container layer cache | BuildKit Registry Cache | Docker-specific layer dedup |
| Final OCI image | Container Registry (GHCR/GitLab CR) | Deployment artifact, not cache |
Cache Miss Behavior
| Cache | On Miss | Impact |
|---|---|---|
| Attic | Build from source, push result | Slow first build (~5-10 min for full closure) |
| FlakeHub | N/A (publication, not pull-through) | Consumer gets older published version |
| Bazel | Re-execute action, cache result | Moderate slowdown (~30s-2min per action) |
| BuildKit | Rebuild all layers | Slow container build (~10-30 min) |
Clean Derivation Policy
What Gets Published
A derivation is publishable (pushed to Attic or FlakeHub) when:
- It builds without
--impureflag - It passes
nix flake checkin CI - It does not reference
/nix/storepaths from the local machine - It does not embed secrets, tokens, or machine-specific paths
Publication Triggers
| Event | FlakeHub | Attic | Notes |
|---|---|---|---|
| Push to main | Yes (rolling) | Yes (all outputs) | FlakeHub gets stable channel |
| Tag (v*) | Yes (versioned) | Yes (all outputs) | FlakeHub gets semver release |
| PR CI run | No | Yes (test outputs only) | Attic caches to speed up re-runs |
| Local dev build | No | Optional (manual push) | Developer opts in with attic push |
Exposure Policy
| Consumer | Can Access FlakeHub? | Can Access Attic? | Can Access Bazel Cache? |
|---|---|---|---|
| External user | Yes (public) | No | No |
| CI runner | No (uses Attic) | Yes (direct) | Yes (cluster-internal) |
| Dev machine | Yes (as flake input) | Yes (with signing key) | Yes (with remote config) |
| Dashboard app | No | No | No |
Canary Validation Lane
A dedicated CI job validates builder health before production workloads run.
Canary Job: validate-builders
Runs on every push to main, before deployment workflows:
validate-builders:
name: Validate Builder Health
runs-on: [self-hosted, nix]
steps:
- uses: actions/checkout@v4
# Verify Nix builder can evaluate and build
- name: Nix eval smoke test
run: nix eval .#packages.x86_64-linux --json | head -c 100
# Verify Attic cache is reachable
- name: Attic connectivity check
run: attic cache info gloriousflywheel || echo "WARN: Attic unreachable"
# Verify the runner image exposes the Nix toolchain
- name: Nix toolchain health
run: |
command -v nix
nix --version
# Build a minimal derivation to verify end-to-end
- name: Canary build
run: nix build .#packages.x86_64-linux.default --no-link
Canary Failure Response
If validate-builders fails:
- Deployment workflows are blocked (GitHub Actions
needs:dependency) - Alert fires via Prometheus (
ARCRunnerColdStartSlowif it’s a timing issue) - Operator investigates via dashboard or MCP tools
- Fix the builder, re-run the canary
Downstream Consumer Guide
“How do I use GloriousFlywheel packages?”
As a Nix flake input (external consumer):
{
inputs.gloriousflywheel.url = "https://flakehub.com/f/tinyland-inc/GloriousFlywheel/*";
}
FlakeHub resolves to the latest published version. No Attic access needed.
As a CI job (internal consumer):
runs-on: [self-hosted, nix] # Routes to gh-nix runner
steps:
- run: nix build .#myPackage
# Runner image carries Nix; Attic acceleration is automatic via runtime hints
As a dev machine (internal consumer):
# One-time: configure Attic
attic login gloriousflywheel https://attic.tinyland.dev
attic use gloriousflywheel
# Then: nix builds automatically check Attic before building from source
nix build .#myPackage