Adoption Quickstart

Adoption Quickstart

Deploy GloriousFlywheel on your cluster and enroll your first repo in 5 steps.

Prerequisites

  • A Kubernetes cluster (RKE2, EKS, GKE, k3s, etc.)
  • kubectl configured for your cluster
  • OpenTofu >= 1.6.0
  • A GitHub App (for GitHub adapter) or runner registration token (GitLab/Forgejo)

Step 1: Deploy Core Substrate

Clone the repo and deploy the ARC controller:

git clone https://github.com/tinyland-inc/GloriousFlywheel.git cd GloriousFlywheel

Copy and edit the example config

cp config/organization.example.yaml config/organization.yaml

Edit with your cluster details

Deploy the ARC controller (one per cluster)

just tofu-init arc-runners just tofu-plan arc-runners just tofu-apply arc-runners

Step 2: Enroll Your Forge

Before installing forge credentials, decide where the implementation overlay lives. The core GloriousFlywheel repo should stay reusable. Your overlay owns deployment values: GitHub App installation IDs, private keys, tfvars, backend state config, cache namespaces, and private endpoint names.

GitHub (Primary)

  1. Create a GitHub App at your org level

  2. Install it on the repos or org you want to serve

  3. Store the app credentials in your implementation overlay secret path:

    GITHUB_APP_ID=… GITHUB_APP_INSTALLATION_ID=… GITHUB_APP_PRIVATE_KEY_PATH=…

  4. Configure the overlay-owned tfvars with your org URL:

    github_config_url = ”https://github.com/your-org”

For a personal GitHub account, GitHub does not provide an org-style personal-account runner group. A repo URL may be required as a private ARC registration anchor, but keep that anchor in the implementation overlay and keep workflow labels capability-shaped.

GitLab (Compatibility)

See Forge Adapter Matrix

Forgejo/Codeberg (Proof Path)

See Forge Adapter Matrix

Step 3: Choose Shared Capability Classes

Default capability classes:

Label CPU/Mem Use Case
your-org-docker 2/4Gi General CI
your-org-nix 4/8Gi Nix builds
your-org-nix-heavy 8/16Gi Rust + Nix

Configure these as shared capability classes in your tfvars. Additive classes should represent real runtime, privilege, architecture, or bounded resource differences, not repo identity.

Do not treat repo-specific labels as the normal design. If a repo cannot reach the shared lane you want, solve that as control-plane or enrollment debt underneath the shared contract.

Step 4: Attach Caches

Caches are first-class substrate components. They should be wired once and then shared by local development, CI, and runner jobs through the same variables. They are not publication authority, and they should not require repo-specific runner labels.

Attic (Nix binary cache)

just tofu-init attic just tofu-plan attic just tofu-apply attic

Nix-capable runner jobs should receive ATTIC_SERVER and ATTIC_CACHE. Credentialed write paths may also provide an Attic token, but read-side cache attachment and publication/discovery are separate concerns.

For local direnv/flake sessions, use just cache-contract-nix-strict after the shell loads. It fails unless NIX_CONFIG carries both the configured Attic substituter and the public trust key.

Bazel Remote Cache

Set BAZEL_REMOTE_CACHE through the runner/bootstrap environment so Bazel work participates in the same shared substrate as Nix and CI. Do not hard-code deployment-specific endpoints into downstream repositories.

Current internal truth for this repo:

  • self-hosted runners inject BAZEL_REMOTE_CACHE when the cache service is reachable from the runner context
  • developer machines enter shared-cache-backed mode only when an operator-provided routable BAZEL_REMOTE_CACHE is set and the strict cache-contract check passes
  • if BAZEL_REMOTE_CACHE is unset, Bazel stays in compatibility-local-only mode and is not proving the intended small-machine heavy-work story

Step 5: Use In Workflows

In your repo’s .github/workflows/*.yml:

jobs: build: runs-on: your-org-nix # or another shared capability class steps:

  • uses: actions/checkout@v6
  • uses: tinyland-inc/GloriousFlywheel/.github/actions/nix-job@main env: ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN || ” }} GF_BAZEL_REMOTE_UPLOAD: ${{ github.event_name == ‘push’ && github.ref == ‘refs/heads/main’ && ‘true’ || ‘false’ }} with: attic-public-key: ${{ vars.ATTIC_PUBLIC_KEY || ” }} command: | test -n ”${BAZEL_REMOTE_CACHE:-}” test ”${GF_BAZEL_SUBSTRATE_MODE:-}” = “shared-cache-backed” nix build .#default nix develop -c bash ./scripts/gloriousflywheel-bazel.sh build //… push-cache: ${{ github.event_name == ‘push’ && github.ref == ‘refs/heads/main’ && secrets.ATTIC_TOKEN != ” && ‘true’ || ‘false’ }}

For the shared public-read main cache, ATTIC_PUBLIC_KEY is enough to attach the Nix substituter. ATTIC_TOKEN is still required for trusted push writes and private-cache reads. The composite action maps the token into an ephemeral Nix netrc-file; do not model Attic substituter reads as Nix access-tokens. Set attic-enabled: "false" only when the cache should not be attached at all.

The current pilot shape keeps pull requests read-only and only enables Attic publication on trusted default-branch pushes when ATTIC_TOKEN is present. GloriousFlywheel’s own broad proof workflows still keep push-cache: "false" unless they are a named publication probe or an explicitly restored write path.

Prefer making the bootstrap contract explicit in workflows. Raw nix build and raw Bazel commands are only truthful if the runner image or earlier steps have already installed the required toolchain and exposed the shared cache-backed endpoint. Prefer the nix-job composite action or an equivalent bootstrap step that proves BAZEL_REMOTE_CACHE and GF_BAZEL_SUBSTRATE_MODE=shared-cache-backed before Bazel runs. Bazel rc files do not expand shell environment variables, so pass --remote_cache="$BAZEL_REMOTE_CACHE" from a repo-managed wrapper such as scripts/gloriousflywheel-bazel.sh. Package pull requests should use read-only remote-cache behavior; trusted default-branch pushes may opt into Bazel cache uploads with GF_BAZEL_REMOTE_UPLOAD=true. For local development, enter through direnv or nix develop, run just info, and only use Bazel dogfood after just cache-contract-strict passes.

Validating Enrollment

Run the enrollment check:

./scripts/benchmark/canary-enrollment-check.sh your-org/your-repo your-org-nix

The checker uses both repo runner inventory and recent successful job-label evidence, because scale-to-zero or shared runners may not appear in the repo inventory endpoint while idle.

Measuring Performance

Run the benchmark harness:

./scripts/benchmark/runner-benchmark.sh your-org-nix nix-build

GloriousFlywheel