2026-07-01 HM Bump Breaks Launchd via User-Domain Default

Context: Watching today’s update run in a tmux pane, I noticed two Failed to start agent … user/501 … I/O error (code 5) lines for atuin-daemon and tldr-update, plus hm switch exiting 1. Chased it down.

Root cause (real one, after two wrong turns)

Today’s flake update bumped home-manager (5d72a2974b38179). That release:

  1. Moved background-service launchd agents to domain = lib.mkDefault "user" inside the upstream program/service modules themselves — programs.atuin → atuin-daemon (modules/programs/atuin.nix:301), services.tldr-update → tldr-update (modules/services/tldr-update.nix:65), plus a wide sweep (ollama, syncthing, gpg-agent, ssh-agent, git-sync…). So agents I never declare got flipped to user.
  2. On macOS 26, bootstrapping a LaunchAgent into user/$UID fails with EIO code 5 (gui works). This was already in my memory note, but I’d assumed the default stayed gui.
  3. The new HM hard-exits activation on any launchd failure (activate: if [[ "$launchdStatus" -ne 0 ]]; then exit). So one EIO fails the whole hm switch and skips every entryAfter [ "setupLaunchAgents" ] block.

Only atuin-daemon/tldr-update broke because everything I declare (litellm, obsidian, macmon) defaults to gui.

The fix

Override launchd.agents.<name>.domain = "gui" (plain assignment beats upstream’s mkDefault) in atuin.nix and tealdeer.nix. One-time transition: launchctl bootout gui/$UID/<label> first (atuin respawns via KeepAlive, but the switch still succeeds once its plist matches). Verified: hm switch exits 0, both agents load in gui, no Background key, second switch idempotent. Committed 1c39c6a (bundled with nix/flake.lock, since the domain option only exists in the bumped HM). Root inputs committed separately (3c76cd2).

Wrong turns (worth remembering)

  • First diagnosis: “atuin/tldr lack the restart workaround litellm/obsidian have.” I built a shared nix/lib/launchd-gui-restart.nix helper and refactored all four modules onto it (the user had picked “extract shared helper + fix all 4”). Then hm switch still failed — because entryAfter setupLaunchAgents never runs under the new hard-exit. Reverted the entire refactor.
  • Second diagnosis: “revert/pin home-manager.” The user pushed back (“that’s not it, go deeper”), correctly — reverting dodges the real cause. Going deeper found the per-agent domain = user in the upstream modules.
  • Lesson: when a workaround “should work” but doesn’t, trace the actual generated activate script (bash -x) rather than trusting the module comment. The exit at activate:1536 was invisible until I traced it.

Latent risk (flagged, not fixed)

Because of the hard-exit, litellm/obsidian’s entryAfter setupLaunchAgents restart workarounds are now dead too. Their next plist change (version bump) could fail hm switch. General fix is an entryBefore setupLaunchAgents pre-bootout, or wait for nix-community/home-manager#9585.

Addendum: latent risk fixed generically (67cbd23)

Followed up and fixed the reload bug for all agents, not just the domain issue. Root of the reload failure: HM reloads a changed agent with launchctl bootout --wait (unsupported on macOS → old agent never unloaded → bootstrap EIO), then hard-exits, so the per-module entryAfter setupLaunchAgents restart blocks (litellm/obsidian) never ran.

New modules/launchd-reload-fix.nix: one entryBefore setupLaunchAgents activation that diffs each incoming plist ($newGenPath/LaunchAgents/<label>.plist, a global the harness exports) against the deployed copy and boots out (gui domain) any that changed, so HM’s own bootstrap lands in a free slot. Auto-discovered via home.nix’s listFilesRecursive. Deleted the now-redundant restart blocks from litellm and obsidian (net −21 lines). Verified end-to-end: appended a drift marker to a loaded agent’s deployed plist → hm switch reloaded it cleanly (exit 0, no EIO, plist restored); unchanged switch does no reload churn. Known gap: agent removal still hits the same --wait bug in HM’s removeAgent (rare here). Drop once home-manager#9585 lands.

2026-07-01 Flake Debug Warnings and Stale-Close Tag Cleanup · 2026-06-08 Nix Home-Manager Review and Cross-Platform Fixes