diff --git a/modules/launchd/default.nix b/modules/launchd/default.nix
index 5943188e..8754daa1 100644
--- a/modules/launchd/default.nix
+++ b/modules/launchd/default.nix
@@ -43,7 +43,31 @@ let
};
};
- toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { escape = true; } config);
+ # mutateConfig calls /bin/sh with /bin/wait4path to wait for /nix/store before
+ # running the original Program and ProgramArguments. This is intentional to
+ # fix the issue where launchd starts the agent before /nix/store is ready
+ # (before the Nix store is mounted.)
+ mutateConfig =
+ cnf:
+ let
+ args =
+ lib.optional (cnf.Program != null) cnf.Program
+ ++ lib.optionals (cnf.ProgramArguments != null) cnf.ProgramArguments;
+ in
+ (removeAttrs cnf [
+ "Program"
+ "ProgramArguments"
+ ])
+ // {
+ ProgramArguments = [
+ "/bin/sh"
+ "-c"
+ "/bin/wait4path /nix/store && exec ${lib.escapeShellArgs args}"
+ ];
+ };
+
+ toAgent =
+ config: pkgs.writeText "${config.Label}.plist" (toPlist { escape = true; } (mutateConfig config));
agentPlists = lib.mapAttrs' (n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) (
lib.filterAttrs (n: v: v.enable) cfg.agents
diff --git a/modules/misc/news/2026/01/2026-01-27_21-41-51.nix b/modules/misc/news/2026/01/2026-01-27_21-41-51.nix
new file mode 100644
index 00000000..a511bf72
--- /dev/null
+++ b/modules/misc/news/2026/01/2026-01-27_21-41-51.nix
@@ -0,0 +1,13 @@
+{ config, pkgs, ... }:
+
+{
+ time = "2026-01-27T21:41:51+00:00";
+ condition = pkgs.stdenv.hostPlatform.isDarwin && config.launchd.enable;
+ message = ''
+
+ The `launchd` module now ensures that the Nix store is mounted and
+ available before starting any agents. This improves reliability on macOS
+ where `launchd` might otherwise attempt to start agents before the Nix
+ store is ready.
+ '';
+}
diff --git a/tests/modules/launchd/expected-agent.plist b/tests/modules/launchd/expected-agent.plist
index 4db6dcc1..4d5f5366 100644
--- a/tests/modules/launchd/expected-agent.plist
+++ b/tests/modules/launchd/expected-agent.plist
@@ -17,9 +17,9 @@
Background
ProgramArguments
- /some/command
- --with-arguments
- foo
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /some/command --with-arguments foo
UnrecognizedByHomeManager
should make it to the resulting plist
diff --git a/tests/modules/programs/aerospace/aerospace-service-expected.plist b/tests/modules/programs/aerospace/aerospace-service-expected.plist
index 4a44448c..d85708ff 100644
--- a/tests/modules/programs/aerospace/aerospace-service-expected.plist
+++ b/tests/modules/programs/aerospace/aerospace-service-expected.plist
@@ -6,8 +6,12 @@
Label
org.nix-community.home.aerospace
- Program
- /nix/store/00000000000000000000000000000000-aerospace/Applications/AeroSpace.app/Contents/MacOS/AeroSpace
+ ProgramArguments
+
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /nix/store/00000000000000000000000000000000-aerospace/Applications/AeroSpace.app/Contents/MacOS/AeroSpace
+
RunAtLoad
StandardErrorPath
diff --git a/tests/modules/programs/git/expected-agent-daily.plist b/tests/modules/programs/git/expected-agent-daily.plist
index d96a936a..1ea3a384 100644
--- a/tests/modules/programs/git/expected-agent-daily.plist
+++ b/tests/modules/programs/git/expected-agent-daily.plist
@@ -6,13 +6,9 @@
org.nix-community.home.git-maintenance-daily
ProgramArguments
- @git@/bin/git
- for-each-repo
- --keep-going
- --config=maintenance.repo
- maintenance
- run
- --schedule=daily
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @git@/bin/git for-each-repo --keep-going '--config=maintenance.repo' maintenance run '--schedule=daily'
StartCalendarInterval
diff --git a/tests/modules/programs/git/expected-agent-hourly.plist b/tests/modules/programs/git/expected-agent-hourly.plist
index 99ade743..90780fb8 100644
--- a/tests/modules/programs/git/expected-agent-hourly.plist
+++ b/tests/modules/programs/git/expected-agent-hourly.plist
@@ -6,13 +6,9 @@
org.nix-community.home.git-maintenance-hourly
ProgramArguments
- @git@/bin/git
- for-each-repo
- --keep-going
- --config=maintenance.repo
- maintenance
- run
- --schedule=hourly
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @git@/bin/git for-each-repo --keep-going '--config=maintenance.repo' maintenance run '--schedule=hourly'
StartCalendarInterval
diff --git a/tests/modules/programs/git/expected-agent-weekly.plist b/tests/modules/programs/git/expected-agent-weekly.plist
index dbcdac9b..e2c8a3f9 100644
--- a/tests/modules/programs/git/expected-agent-weekly.plist
+++ b/tests/modules/programs/git/expected-agent-weekly.plist
@@ -6,13 +6,9 @@
org.nix-community.home.git-maintenance-weekly
ProgramArguments
- @git@/bin/git
- for-each-repo
- --keep-going
- --config=maintenance.repo
- maintenance
- run
- --schedule=weekly
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @git@/bin/git for-each-repo --keep-going '--config=maintenance.repo' maintenance run '--schedule=weekly'
StartCalendarInterval
diff --git a/tests/modules/programs/nh/darwin/launchd.plist b/tests/modules/programs/nh/darwin/launchd.plist
index efdb65d2..987f2105 100644
--- a/tests/modules/programs/nh/darwin/launchd.plist
+++ b/tests/modules/programs/nh/darwin/launchd.plist
@@ -6,9 +6,9 @@
org.nix-community.home.nh-clean
ProgramArguments
- @nh@/bin/nh
- clean
- user
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @nh@/bin/nh clean user
StartCalendarInterval
diff --git a/tests/modules/programs/opencode/web-service.plist b/tests/modules/programs/opencode/web-service.plist
index d7247b10..698a8730 100644
--- a/tests/modules/programs/opencode/web-service.plist
+++ b/tests/modules/programs/opencode/web-service.plist
@@ -15,20 +15,9 @@
Background
ProgramArguments
- @opencode@/bin/opencode
- web
- --hostname
- 0.0.0.0
- --port
- 4096
- --mdns
- --cors
- https://example.com
- --cors
- http://localhost:3000
- --print-logs
- --log-level
- DEBUG
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @opencode@/bin/opencode web --hostname 0.0.0.0 --port 4096 --mdns --cors https://example.com --cors http://localhost:3000 --print-logs --log-level DEBUG
RunAtLoad
diff --git a/tests/modules/programs/sketchybar/sketchybar-service-expected.plist b/tests/modules/programs/sketchybar/sketchybar-service-expected.plist
index e2e3be34..e620aa76 100644
--- a/tests/modules/programs/sketchybar/sketchybar-service-expected.plist
+++ b/tests/modules/programs/sketchybar/sketchybar-service-expected.plist
@@ -8,8 +8,12 @@
org.nix-community.home.sketchybar
ProcessType
Interactive
- Program
- /nix/store/00000000000000000000000000000000-sketchybar/bin/sketchybar
+ ProgramArguments
+
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /nix/store/00000000000000000000000000000000-sketchybar/bin/sketchybar
+
RunAtLoad
StandardErrorPath
diff --git a/tests/modules/services/borgmatic/darwin/expected-agent.plist b/tests/modules/services/borgmatic/darwin/expected-agent.plist
index 24cbe4dd..53436923 100644
--- a/tests/modules/services/borgmatic/darwin/expected-agent.plist
+++ b/tests/modules/services/borgmatic/darwin/expected-agent.plist
@@ -8,9 +8,9 @@
Background
ProgramArguments
- @borgmatic@/bin/borgmatic
- --stats
- --list
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @borgmatic@/bin/borgmatic --stats --list
StandardErrorPath
/home/hm-user/Library/Logs/borgmatic/launchd-stderr.log
diff --git a/tests/modules/services/colima/darwin/expected-agent.plist b/tests/modules/services/colima/darwin/expected-agent.plist
index e4e43477..6a73e56c 100644
--- a/tests/modules/services/colima/darwin/expected-agent.plist
+++ b/tests/modules/services/colima/darwin/expected-agent.plist
@@ -13,12 +13,9 @@
org.nix-community.home.colima-default
ProgramArguments
- @colima@/bin/colima
- start
- default
- -f
- --activate=true
- --save-config=false
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @colima@/bin/colima start default -f '--activate=true' '--save-config=false'
RunAtLoad
diff --git a/tests/modules/services/emacs/darwin/expected-agent.plist b/tests/modules/services/emacs/darwin/expected-agent.plist
index 81945758..cc9b7682 100644
--- a/tests/modules/services/emacs/darwin/expected-agent.plist
+++ b/tests/modules/services/emacs/darwin/expected-agent.plist
@@ -13,8 +13,9 @@
org.nix-community.home.emacs
ProgramArguments
- @emacs@/bin/emacs
- --fg-daemon
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @emacs@/bin/emacs --fg-daemon
RunAtLoad
diff --git a/tests/modules/services/espanso/darwin/launchd.plist b/tests/modules/services/espanso/darwin/launchd.plist
index a38c6f2c..c2b65479 100644
--- a/tests/modules/services/espanso/darwin/launchd.plist
+++ b/tests/modules/services/espanso/darwin/launchd.plist
@@ -18,8 +18,9 @@
org.nix-community.home.espanso
ProgramArguments
- @espanso@/Applications/Espanso.app/Contents/MacOS/espanso
- launcher
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @espanso@/Applications/Espanso.app/Contents/MacOS/espanso launcher
RunAtLoad
diff --git a/tests/modules/services/git-sync/darwin/expected-agent.plist b/tests/modules/services/git-sync/darwin/expected-agent.plist
index 2699a996..53d8156e 100644
--- a/tests/modules/services/git-sync/darwin/expected-agent.plist
+++ b/tests/modules/services/git-sync/darwin/expected-agent.plist
@@ -8,7 +8,9 @@
Background
ProgramArguments
- @git-sync@/bin/git-sync
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @git-sync@/bin/git-sync
StartInterval
500
diff --git a/tests/modules/services/gpg-agent/expected-agent.plist b/tests/modules/services/gpg-agent/expected-agent.plist
index 5843ff44..093e3137 100644
--- a/tests/modules/services/gpg-agent/expected-agent.plist
+++ b/tests/modules/services/gpg-agent/expected-agent.plist
@@ -20,8 +20,9 @@
Background
ProgramArguments
- @gpg@/bin/gpg-agent
- --supervised
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @gpg@/bin/gpg-agent --supervised
RunAtLoad
diff --git a/tests/modules/services/home-manager-auto-expire/darwin/expected-agent.plist b/tests/modules/services/home-manager-auto-expire/darwin/expected-agent.plist
index fb3878d1..5d974246 100644
--- a/tests/modules/services/home-manager-auto-expire/darwin/expected-agent.plist
+++ b/tests/modules/services/home-manager-auto-expire/darwin/expected-agent.plist
@@ -8,7 +8,9 @@
Background
ProgramArguments
- /nix/store/00000000000000000000000000000000-home-manager-auto-expire
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /nix/store/00000000000000000000000000000000-home-manager-auto-expire
StandardErrorPath
/home/hm-user/Library/Logs/home-manager-auto-expire/launchd-stderr.log
diff --git a/tests/modules/services/imapnotify/darwin/launchd.plist b/tests/modules/services/imapnotify/darwin/launchd.plist
index 75009bb6..4fb9555c 100644
--- a/tests/modules/services/imapnotify/darwin/launchd.plist
+++ b/tests/modules/services/imapnotify/darwin/launchd.plist
@@ -17,9 +17,9 @@
Background
ProgramArguments
- @goimapnotify@/bin/goimapnotify
- -conf
- /nix/store/00000000000000000000000000000000-imapnotify-hm-example.com-config.json
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @goimapnotify@/bin/goimapnotify -conf /nix/store/00000000000000000000000000000000-imapnotify-hm-example.com-config.json
RunAtLoad
diff --git a/tests/modules/services/macos-remap-keys/basic-agent.plist b/tests/modules/services/macos-remap-keys/basic-agent.plist
index fa3da3cb..f223bf31 100644
--- a/tests/modules/services/macos-remap-keys/basic-agent.plist
+++ b/tests/modules/services/macos-remap-keys/basic-agent.plist
@@ -11,10 +11,9 @@
org.nix-community.home.remap-keys
ProgramArguments
- /usr/bin/hidutil
- property
- --set
- { "UserKeyMapping": [ { "HIDKeyboardModifierMappingSrc": 0x700000039, "HIDKeyboardModifierMappingDst": 0x70000002A } ] }
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /usr/bin/hidutil property --set '{ "UserKeyMapping": [ { "HIDKeyboardModifierMappingSrc": 0x700000039, "HIDKeyboardModifierMappingDst": 0x70000002A } ] }'
RunAtLoad
diff --git a/tests/modules/services/nix-gc/darwin/expected-agent.plist b/tests/modules/services/nix-gc/darwin/expected-agent.plist
index 13b16c16..4691c2e4 100644
--- a/tests/modules/services/nix-gc/darwin/expected-agent.plist
+++ b/tests/modules/services/nix-gc/darwin/expected-agent.plist
@@ -6,8 +6,9 @@
org.nix-community.home.nix-gc
ProgramArguments
- @nix@/bin/nix-collect-garbage
- --delete-older-than 30d
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @nix@/bin/nix-collect-garbage '--delete-older-than 30d'
StartCalendarInterval
diff --git a/tests/modules/services/ollama/darwin/expected-agent.plist b/tests/modules/services/ollama/darwin/expected-agent.plist
index 97ed3c8a..daeccc78 100644
--- a/tests/modules/services/ollama/darwin/expected-agent.plist
+++ b/tests/modules/services/ollama/darwin/expected-agent.plist
@@ -24,8 +24,9 @@
Background
ProgramArguments
- @ollama@/bin/ollama
- serve
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @ollama@/bin/ollama serve
\ No newline at end of file
diff --git a/tests/modules/services/podman/darwin/basic-expected-agent.plist b/tests/modules/services/podman/darwin/basic-expected-agent.plist
index 146a1827..341a43b3 100644
--- a/tests/modules/services/podman/darwin/basic-expected-agent.plist
+++ b/tests/modules/services/podman/darwin/basic-expected-agent.plist
@@ -15,7 +15,9 @@
Background
ProgramArguments
- /nix/store/00000000000000000000000000000000-podman-machine-watchdog-podman-machine-default
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /nix/store/00000000000000000000000000000000-podman-machine-watchdog-podman-machine-default
RunAtLoad
diff --git a/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist b/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist
index 056846e0..3668a1fc 100644
--- a/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist
+++ b/tests/modules/services/podman/darwin/custom-machines-dev-expected-agent.plist
@@ -15,7 +15,9 @@
Background
ProgramArguments
- /nix/store/00000000000000000000000000000000-podman-machine-watchdog-dev-machine
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec /nix/store/00000000000000000000000000000000-podman-machine-watchdog-dev-machine
RunAtLoad
diff --git a/tests/modules/services/proton-pass-agent/basic-service-expected.plist b/tests/modules/services/proton-pass-agent/basic-service-expected.plist
index a4380df5..e8f71a8c 100644
--- a/tests/modules/services/proton-pass-agent/basic-service-expected.plist
+++ b/tests/modules/services/proton-pass-agent/basic-service-expected.plist
@@ -15,9 +15,9 @@
Background
ProgramArguments
- @bash-interactive@/bin/bash
+ /bin/sh
-c
- @proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket
+ /bin/wait4path /nix/store && exec @bash-interactive@/bin/bash -c '@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket'
RunAtLoad
diff --git a/tests/modules/services/proton-pass-agent/full-service-expected.plist b/tests/modules/services/proton-pass-agent/full-service-expected.plist
index 9d0e9690..aa462e83 100644
--- a/tests/modules/services/proton-pass-agent/full-service-expected.plist
+++ b/tests/modules/services/proton-pass-agent/full-service-expected.plist
@@ -15,9 +15,9 @@
Background
ProgramArguments
- @bash-interactive@/bin/bash
+ /bin/sh
-c
- @proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket --share-id 123456789 --vault-name MySshKeyVault --refresh-interval 7200 --create-new-identities MySshKeyVault
+ /bin/wait4path /nix/store && exec @bash-interactive@/bin/bash -c '@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket --share-id 123456789 --vault-name MySshKeyVault --refresh-interval 7200 --create-new-identities MySshKeyVault'
RunAtLoad
diff --git a/tests/modules/services/ssh-agent/darwin/basic-service-expected.plist b/tests/modules/services/ssh-agent/darwin/basic-service-expected.plist
index 1a939f6a..6c8d8d2c 100644
--- a/tests/modules/services/ssh-agent/darwin/basic-service-expected.plist
+++ b/tests/modules/services/ssh-agent/darwin/basic-service-expected.plist
@@ -15,9 +15,9 @@
Background
ProgramArguments
- @bash-interactive@/bin/bash
+ /bin/sh
-c
- @openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent"
+ /bin/wait4path /nix/store && exec @bash-interactive@/bin/bash -c '@openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent"'
RunAtLoad
diff --git a/tests/modules/services/ssh-agent/darwin/pkcs11-service-expected.plist b/tests/modules/services/ssh-agent/darwin/pkcs11-service-expected.plist
index d6b5d8fb..72139397 100644
--- a/tests/modules/services/ssh-agent/darwin/pkcs11-service-expected.plist
+++ b/tests/modules/services/ssh-agent/darwin/pkcs11-service-expected.plist
@@ -15,9 +15,9 @@
Background
ProgramArguments
- @bash-interactive@/bin/bash
+ /bin/sh
-c
- @openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent" -P '/usr/lib/libpkcs11.so,/usr/lib/other.so'
+ /bin/wait4path /nix/store && exec @bash-interactive@/bin/bash -c '@openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent" -P '\''/usr/lib/libpkcs11.so,/usr/lib/other.so'\'''
RunAtLoad
diff --git a/tests/modules/services/ssh-agent/darwin/timeout-service-expected.plist b/tests/modules/services/ssh-agent/darwin/timeout-service-expected.plist
index 0a49f024..6facee27 100644
--- a/tests/modules/services/ssh-agent/darwin/timeout-service-expected.plist
+++ b/tests/modules/services/ssh-agent/darwin/timeout-service-expected.plist
@@ -15,9 +15,9 @@
Background
ProgramArguments
- @bash-interactive@/bin/bash
+ /bin/sh
-c
- @openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent" -t 1337
+ /bin/wait4path /nix/store && exec @bash-interactive@/bin/bash -c '@openssh@/bin/ssh-agent -D -a "$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/ssh-agent" -t 1337'
RunAtLoad
diff --git a/tests/modules/services/syncthing/expected-agent.plist b/tests/modules/services/syncthing/expected-agent.plist
index 72ec9d0d..72cf9870 100644
--- a/tests/modules/services/syncthing/expected-agent.plist
+++ b/tests/modules/services/syncthing/expected-agent.plist
@@ -15,7 +15,9 @@
Background
ProgramArguments
- @syncthing-wrapper@
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @syncthing-wrapper@
\ No newline at end of file
diff --git a/tests/modules/services/yubikey-agent/darwin/service.nix b/tests/modules/services/yubikey-agent/darwin/service.nix
index 8d707450..c8bd674f 100644
--- a/tests/modules/services/yubikey-agent/darwin/service.nix
+++ b/tests/modules/services/yubikey-agent/darwin/service.nix
@@ -27,9 +27,9 @@
Background
ProgramArguments
- @yubikey-agent@/bin/yubikey-agent
- -l
- /tmp/yubikey-agent.sock
+ /bin/sh
+ -c
+ /bin/wait4path /nix/store && exec @yubikey-agent@/bin/yubikey-agent -l /tmp/yubikey-agent.sock
Sockets