Recommendations
Last reviewed: September 4, 2026
Do this now
- Run Linux tests through Apple
containerand a substitutedpackages.aarch64-linux.ci/packages.x86_64-linux.ci. That isci --host-system aarch64-linux/x86_64-linux. It matches what this laptop can actually do today: caches have the Linuxciwrapper; the gated builder cannot compile missing paths;containercan exec ELFs. - Run without
--fail-fastand watch for a stalled log: the pre-existingevent-horizonhang reproduces here in 2 of 3 runs, and a killed test binary lets the sweep continue. - Probe before you debug.
ci --linux-host-probereports Determinate (gated), Applecontainer(running or not), nix-darwin's/etc/nix/machines, andextra-platforms. - Disable
external-builderswhen substituting. A configured-but- gated helper turns a cache hit into a 400. The dispatcher passes--option external-builders '[]'for that reason. - Never evaluate
.#for a Linux output. The dirty tree is a derivation nobody built. Evaluategit+file://…?rev=at a revision CI has seen; the dispatcher does, and says which one it picked.
Do this when a builder is actually needed
Uncached Linux drvs (symlinkJoin, devShells.*.ci's nix-shell-env, a dirty packages.ci not yet in cachix):
- Prefer IOHK
nix-linux-builderover waiting on the Determinate gate: sameexternal-buildersprotocol, ungated,nix-linux-shellwhen a build fails. Pin65ecc7687e0df4b3e634e3e026f8e7822a961800. - Or enable nix-darwin
nix.linux-builderwithpackage = pkgs.darwin.linux-builder-vzandsystems = [ "aarch64-linux" "x86_64-linux" ]if a persistent NixOS guest is acceptable. - If Determinate grants the feature, raise
--cpu-countin theexternal-buildersJSON (default 1). Re-enable the helper for realize; keep Applecontainerforci --test.
Do not
- Treat
nix build .#packages.aarch64-linux.helloas evidence that tests ran. That is a substitute. - Bind-mount Darwin
SPARKLES_TS_GRAMMAR_PATHinto the guest. Grammar bundles contain native code; realize.#packages.aarch64-linux.ts-grammars. symlinkJoinLinux tools on Darwin. New drv, platform mismatch.- Use
container machine's$HOMEmount as the sparkles worktree. The repo is on/Volumes/Dev.
Dispatcher contract
apps/ci/src/linux_host.d:
--linux-host-probe— report backends, exit 0.--host-system aarch64-linux|x86_64-linux— pick the first ofHEAD,@{upstream},merge-base origin/main,origin/mainwhosepackages.<system>.cisubstitutes and whose shell inputs all arrive;nix derivation showthat revision'sdevShells.<system>.ci; substitute its inputs through the flake ref (--keep-going, since the shell drv itself cannot build here); write anenter.shthat replaysnix-shell's rc;container system startif needed;container runwith/nix/store:ro, the checkout at its own path, the script's directory; execciwith--host-system/--host-ci-revstripped so a cached Linuxci(which may not know the flags) is not fed them.--host-ci-rev REV— pin that revision instead of the chain.DCcrosses from the host only as a bare compiler name; CI's matrix sets it the same way (ldc2on aarch64,ldc2/dmdon x86_64).
The inner ci and the whole environment are the cached revision's. Library tests run from the mounted worktree. Developing apps/ci or the dev shell itself still needs a push (or a builder).
Follow-ups
- Push
.#all-desktopforaarch64-linuxin CI so more of the closure substitutes (today the aarch64 shell output is never cached; the dispatcher does not need it,nix developon an arm box would). - Optional: a
container machineimage with Nix in-guest, for the days cachix does not havepackages.ci. - Optional: IOHK as a nix-darwin module once someone wants uncached Linux builds locally.