Skip to content

ci: run nix-config CI on THEBATTLESHIP's own runners - #85

Merged
fts-forge[bot] merged 3 commits into
mainfrom
ci/sta-621-nix-config-runner
Nov 2, 2026
Merged

fts-forge[bot] merged 3 commits into
mainfrom
ci/sta-621-nix-config-runner

Conversation

@fts-forge

@fts-forge fts-forge Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

STA-621. The Captain asked on STA-618 for "a selfhosted runner for nix-config ... so that it was as fast as running it locally".

Why

The ubuntu-latest runners start with an empty /nix/store, so every run rebuilds or downloads the whole closure. PR #83's nix flake check failed with ENOSPC on a hosted runner.

Changes

  • hosts/THEBATTLESHIP/github-runners.nix adds a github-nix-config pool:
    • 3 instances, label nix-config, registered through the fts-forge App on Codys-Wright (the same way as github-starcommand).
    • The jobs use the host's store and daemon.
    • Each instance runs as its own user, nix-config-ci, which can't read the forge App private key held by the FTS runners' github-runner user. The unit also makes the key inaccessible.
    • The work dir and HOME are under /run/media/Development/github-runner-work-nix-config/.
  • nixConfigJobGate runs before every job (ACTIONS_RUNNER_HOOK_JOB_STARTED). The repo is public, so it only allows a push to main, workflow_dispatch, or a pull_request whose head repo is Codys-Wright/nix-config. It refuses fork PRs, pull_request_target, other events and other repos, and it refuses when the payload is unreadable.
  • ci.yml:
    • check, build-vm, build THEBATTLESHIP and nixidy now use runs-on: [self-hosted, nix-config], with an if: that skips fork PRs.
    • Those jobs no longer run the nothing-but-nix, nix-installer, magic-nix-cache or cachix steps.
    • The nix-secrets token goes in a per-job gitconfig (GIT_CONFIG_GLOBAL=$RUNNER_TEMP/gitconfig), not in the runner's long-lived HOME.
    • Adds workflow_dispatch, and PR-scoped concurrency so a newer push cancels the older run.
    • voyager stays on macos-latest.

Verified locally on THEBATTLESHIP

  • nix build .#nixosConfigurations.THEBATTLESHIP.config.system.build.toplevel exits 0 (/nix/store/c8abrgy2…-nixos-system-THEBATTLESHIP). The generated github-runner-github-nix-config-{1..3} units have User=nix-config-ci, the gate hook, the work dir in BindPaths, and the key in InaccessiblePaths.
  • I ran the gate against 10 synthetic events:
    • Allowed: push to main, dispatch, same-repo PR.
    • Refused: push to a branch, fork PR, PR whose head repo was deleted, pull_request_target, bad payload, other repo, no payload.
  • Nix 2.34's git fetcher honours GIT_CONFIG_GLOBAL insteadOf. I checked that a rewrite to example.invalid is the URL nix tries.

Deploy order

This PR's Linux jobs wait in the queue until the runners exist, so THEBATTLESHIP has to be switched to this branch first (the Captain's gate). The jobs then run here and the PR can merge.

Notes

  • Builds from these jobs are no longer pushed to fleet.cachix.org. The host's own store is the cache now.
  • Rollback: switch THEBATTLESHIP back to main, which removes the units. GitHub then shows the runners as offline.

🤖 Generated with Claude Code

Hosted runners start with an empty store and ran out of disk on PR #83's
`nix flake check`. Add a `github-nix-config` pool (3 instances, label
`nix-config`) on THEBATTLESHIP, registered through the fts-forge App on
Codys-Wright, and move check, build-vm, build THEBATTLESHIP and nixidy to
it, dropping the nothing-but-nix, installer, magic-nix-cache and cachix
steps there. voyager stays on macos-latest.

The repo is public: the jobs skip fork PRs, and a job-started gate on the
runners refuses anything but a push to main, workflow_dispatch or a
same-repo PR. The instances run as their own user, nix-config-ci, which
cannot read the forge App key. The nix-secrets token goes in a per-job
gitconfig ($RUNNER_TEMP) instead of the runner's HOME.

Refs STA-621.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fts-forge Bot and others added 2 commits November 1, 2026 20:56
k8s/ and the nixidy input went in 2d876de (cluster manifests render in
starcommand now), so `nix run .#nixidy` has no attribute to run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nixpkgs' 6.18.59 moved the i915 quirk table, so nixos-hardware's
2008-i915-4-lane-quirk-for-mbp15-1 no longer applies and nomad's and
stowaway's kernel (and `nix flake check`) fail to build. Take the copy
t2linux rebased on its 6.18 branch (166c92f, "6.18.55") alongside the
existing 3001/4001-4004 replacements; each replacement now pins its own
rev.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fts-forge
fts-forge Bot merged commit 361b1e6 into main Nov 2, 2026
4 checks passed
@fts-forge
fts-forge Bot deleted the ci/sta-621-nix-config-runner branch November 2, 2026 05:38
fts-forge Bot added a commit that referenced this pull request Nov 2, 2026
…#89)

## What

A new aspect, `fleet.ai/ollaya` (`modules/ai/ollaya.nix`), included on
THEBATTLESHIP. It serves the open Laya decision model through Ollaya,
using TypeSafe Jev's API: `POST http://127.0.0.1:11435/v1/systemone`.
The Paperclip router (STA-631) will call it.

- It uses nixpkgs' own `services.ollaya` and `pkgs.ollaya` 0.17.0, which
come from cache.nixos.org, so nothing is built from source.
- It listens on `127.0.0.1` only and opens no firewall port.
- `OLLAYA_DEVICE=cpu`, so it never touches the GPU. `OLLAYA_THREADS=8`
leaves the other cores for builds. `OLLAYA_KEEP_ALIVE=-1` keeps the
model loaded, because a cold load takes about 5 s and the TypeSafe SDK
times out after 10 s.
- Ollaya never pulls a model on request. `ollaya-model-loader.service`
pulls `laya:en` (814 MB) into `/var/lib/ollaya/models` after the daemon
starts.
- Per-host settings: `settings.ai.ollaya.models` and
`settings.ai.ollaya.threads`.

## Verified

- `nix build
.#nixosConfigurations.THEBATTLESHIP.config.system.build.toplevel` exits
0. The service environment and loader script evaluate as described
above, and 11435 is not in `allowedTCPPorts`.
- I ran the same `ollaya` store path in userspace as `agent`, on port
11439: `ollaya pull laya:en`, then a sample "which agent?" question with
3 options sent to `/v1/systemone`. It returned HTTP 200 and `DevOps`
with p=0.8164 (Librarian 0.0732, Atlas 0.1105).
- That run's cgroup had 4 CPUs at nice 10, with host load between 17 and
38, so 1.4 to 2.0 s per warm request is a starved number (cold: 4.75 s).
The service gets its own cgroup and gets measured after the switch.
- The runner's RSS was 3.2 GB, not the advertised 1 GB: on a CPU it
loads the fp32 graph.

## Deploy note

This repo's `main` doesn't match what is running on THEBATTLESHIP.
Generation 1074 was switched from open PR #87 (devenv/direnv), and #85's
`github-nix-config` runners were never activated. Switching from this
branch alone would also add those 3 runners and remove devenv, cachix
and libghostty-vt. The live switch waits for the Captain's approval
(STA-630).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: fts-forge[bot] <345159799+fts-forge[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants