You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Plan: Push to soft-nix.cachix.org from aaron (Phase 2)
Status: deferred — start only after Phase 1
(#150) ships and we have data on how often the manual path
is insufficient.
Context
Phase 1 covers tower and leod via the upstream services.cachix-watch-store NixOS module. aaron is split off because
Determinate Nix already owns the post-build-hook slot, and the obvious
"just set post-build-hook" approach has three independent problems:
Single-valued setting. Nix exposes one post-build-hook. Setting it via determinateNix.customSettings.post-build-hookreplaces Determinate's
default at /nix/var/determinate/post-build-hook.sh, which feeds JSON
events into /nix/var/determinate/intake.pipe for determinate-nixd. We'd
silently break any Determinate feature that depends on those events.
Open hang bug.DeterminateSystems/nix-installer#1500 reports
Determinate's own post-build-hook hanging on macOS, unresolved as of last
check. Adding more work through that pathway is risky.
Synchronous blocking. Nix's post-build-hook blocks the build loop.
The official nix.dev guide explicitly warns this "will make Nix slow or
unusable when the network connection is slow or unreliable."
Motivation
Heavy darwin closures (e.g. stdenv-darwin regressions like compiler-rt-libc PR #147) get built locally during verification, then CI
rebuilds the same closure from scratch because soft-nix doesn't have it. If
aaron pushed locally, CI would download instead of compile.
Frequency, though, is low — this only matters when stdenv-darwin
invalidates. A few times per year, not per week.
Step 1: cachix-push-last shell script (do this first)
Add a small wrapper as a new wrapped package
(pkgs/cachix-push-last/default.nix) following the existing writeShellApplication pattern (e.g. pkgs/gen-commit-msg).
Behavior:
Resolves an out-path: $1 if provided, else ./result.
Reads the cachix auth token from ~/.config/cachix/cachix.dhall (set via cachix authtoken once on aaron — see "Token storage" below).
Calls cachix push soft-nix <out-path>.
Prints what it pushed.
Add a workflow note to CLAUDE.md (project, not global) under ### macOS specific (aaron):
When a darwin build invalidates a large closure (typically a stdenv-darwin
change), run cachix-push-last after a successful local build so CI does
not have to rebuild it.
Token storage on darwin
Two options, in preference order:
cachix authtoken (user-level): run cachix authtoken <token> once on
aaron. Cachix stores it under ~/.config/cachix/. No agenix involvement.
Simpler, no daemon needs to read the secret. The token is user-scope and
leaks only as far as the soft user's home.
agenix-darwin secret (secrets/cachix-aaron-token.age): only worth it
if Step 2 (SSE subscriber) ships, since that runs as a launchd daemon and
can't read user dotfiles.
The supported way to react to Determinate-managed builds without touching post-build-hook is the streaming HTTP API on the Unix socket at /nix/var/determinate/determinate-nixd.socket. Determinate's
"Subscribing to post-build events" guide documents this.
Architecture
launchd daemon running as root (or _nixbld-equivalent — confirm
during impl). Started via launchd.daemons.cachix-push-subscriber in modules/hosts/aaron/configuration.nix (or a darwin module under modules/).
Subscriber script (Bash or small Go/Rust binary, wrapped via writeShellApplication):
Parses each SSE message; matches v=1, c=BuiltPathResponseEventV1.
Extracts the output paths.
Calls cachix push soft-nix <paths> with the auth token from /run/agenix/cachix-aaron-token.
agenix secretcachix-aaron-token.age with mode = "0400" and an
owner the daemon can read. Add aaron to its publicKeys in secrets/secrets.nix.
Open questions to resolve at impl time
Does determinate-nixd.socket exist on every darwin install? Yes if
Determinate is installed (it is on aaron). Confirm by ls -la /nix/var/determinate/ once before starting.
Does the SSE endpoint emit events for substituted paths or only locally
built ones? Per Determinate docs the events are built-path events, so
substituted paths should not trigger them — same semantics as the standard post-build-hook. Verify by triggering a substitution and confirming no
event.
agenix-darwin secret readable by launchd daemon. agenix-darwin mounts
secrets under /run/agenix.d/<gen>/. The daemon's User must match the
secret's owner. Check the agenix.secrets.<name>.owner and .group
options on darwin.
Reconnection. The SSE connection can drop. The launchd KeepAlive
policy should restart the daemon on exit; the subscriber should use curl --retry or wrap the connection in a while true; do curl ...; sleep 1; done loop.
Test plan
Build aaron with the subscriber enabled.
nix build nixpkgs#hello --rebuild and confirm a new entry appears on the
cachix dashboard.
nix build nixpkgs#hello (no rebuild, substituted from cache) and confirm
no new push event in the daemon log.
Kill the daemon mid-build; confirm launchd restarts it and queued events
are not lost (or, if they are, document that — it's acceptable for this
use case).
Out of scope (both steps)
Migrating off Determinate Nix.
Setting post-build-hook in nix.custom.conf directly. Don't.
Caching pi builds (covered in Phase 1's out-of-scope; pi rebuilds from CI).
Plan: Push to soft-nix.cachix.org from aaron (Phase 2)
Context
Phase 1 covers tower and leod via the upstream
services.cachix-watch-storeNixOS module. aaron is split off becauseDeterminate Nix already owns the
post-build-hookslot, and the obvious"just set
post-build-hook" approach has three independent problems:post-build-hook. Setting it viadeterminateNix.customSettings.post-build-hookreplaces Determinate'sdefault at
/nix/var/determinate/post-build-hook.sh, which feeds JSONevents into
/nix/var/determinate/intake.pipefordeterminate-nixd. We'dsilently break any Determinate feature that depends on those events.
DeterminateSystems/nix-installer#1500reportsDeterminate's own post-build-hook hanging on macOS, unresolved as of last
check. Adding more work through that pathway is risky.
post-build-hookblocks the build loop.The official
nix.devguide explicitly warns this "will make Nix slow orunusable when the network connection is slow or unreliable."
Motivation
Heavy darwin closures (e.g.
stdenv-darwinregressions likecompiler-rt-libcPR #147) get built locally during verification, then CIrebuilds the same closure from scratch because soft-nix doesn't have it. If
aaron pushed locally, CI would download instead of compile.
Frequency, though, is low — this only matters when
stdenv-darwininvalidates. A few times per year, not per week.
Step 1:
cachix-push-lastshell script (do this first)Add a small wrapper as a new wrapped package
(
pkgs/cachix-push-last/default.nix) following the existingwriteShellApplicationpattern (e.g.pkgs/gen-commit-msg).Behavior:
$1if provided, else./result.~/.config/cachix/cachix.dhall(set viacachix authtokenonce on aaron — see "Token storage" below).cachix push soft-nix <out-path>.Add a workflow note to
CLAUDE.md(project, not global) under### macOS specific (aaron):Token storage on darwin
Two options, in preference order:
cachix authtoken(user-level): runcachix authtoken <token>once onaaron. Cachix stores it under
~/.config/cachix/. No agenix involvement.Simpler, no daemon needs to read the secret. The token is user-scope and
leaks only as far as the soft user's home.
secrets/cachix-aaron-token.age): only worth itif Step 2 (SSE subscriber) ships, since that runs as a launchd daemon and
can't read user dotfiles.
Start with option 1.
Why this is enough for now
a heavy build; one command after
nix buildsucceeds and CI is unblocked.Exit criteria — when to escalate to Step 2
Track instances where:
cachix-push-lastand CI subsequently rebuilt a largedarwin closure.
build (not a "heavy" one we'd think to push manually).
If either happens more than ~3 times in 6 months, do Step 2.
Step 2: Determinate SSE event subscriber (only if Step 1 proves insufficient)
The supported way to react to Determinate-managed builds without touching
post-build-hookis the streaming HTTP API on the Unix socket at/nix/var/determinate/determinate-nixd.socket. Determinate's"Subscribing to post-build events" guide documents this.
Architecture
_nixbld-equivalent — confirmduring impl). Started via
launchd.daemons.cachix-push-subscriberinmodules/hosts/aaron/configuration.nix(or a darwin module undermodules/).writeShellApplication):curl --unix-socket /nix/var/determinate/determinate-nixd.socket http://localhost/eventsv=1,c=BuiltPathResponseEventV1.cachix push soft-nix <paths>with the auth token from/run/agenix/cachix-aaron-token.cachix-aaron-token.agewithmode = "0400"and anowner the daemon can read. Add
aaronto itspublicKeysinsecrets/secrets.nix.Open questions to resolve at impl time
determinate-nixd.socketexist on every darwin install? Yes ifDeterminate is installed (it is on aaron). Confirm by
ls -la /nix/var/determinate/once before starting.built ones? Per Determinate docs the events are built-path events, so
substituted paths should not trigger them — same semantics as the standard
post-build-hook. Verify by triggering a substitution and confirming noevent.
secrets under
/run/agenix.d/<gen>/. The daemon'sUsermust match thesecret's
owner. Check theagenix.secrets.<name>.ownerand.groupoptions on darwin.
KeepAlivepolicy should restart the daemon on exit; the subscriber should use
curl --retryor wrap the connection in awhile true; do curl ...; sleep 1; doneloop.Test plan
nix build nixpkgs#hello --rebuildand confirm a new entry appears on thecachix dashboard.
nix build nixpkgs#hello(no rebuild, substituted from cache) and confirmno new push event in the daemon log.
are not lost (or, if they are, document that — it's acceptable for this
use case).
Out of scope (both steps)
post-build-hookinnix.custom.confdirectly. Don't.References
https://docs.determinate.systems/guides/post-build-events/
nix builds hang on post-build-hook DeterminateSystems/nix-installer#1500