2026-05-14 Dotfiles Nix Audit Cleanup
What I set out to do
Asked Claude to audit my nix/HM config for non-standard or non-best-practice patterns. Wanted a survey, not a specific fix. Ended up working through the resulting findings in batches.
What I actually did
Seven commits, all on main:
d0bdeda— Externalized the inlinemmdcwrapper. It was usingpkgs.writeShellScriptBininline despite AGENTS.md §6 forbidding it. Migrated topkgs.replaceVarsWithwith an external template atnix/home-manager/files/scripts/mmdc.in. One snag:replaceVarsWithhas a build-time safety check that regex-matches any@identifier@in the output, including comments. Hit it because I wrote a literal@vars@in a comment.5e5caee— Collapsed 13 repeatedhome.file."bin/X"declarations into a singlelib.mapAttrs'over a name→source attrset.nullvalue means same name on both sides (10 of 13); explicit string for the 3.py-stripping cases (check-upstream-issues.py→check-upstream-issuesetc.). -38 lines, byte-identical output verified bydiff -rof thehome-manager-files/bin/derivations.4819b85— Three related PATH fixes bundled. The deep one: traced shell loading across four scenarios (Ghostty login, tmux pane, SSH-then-tmux, SSH-direct-to-tmux). Found thatssh box "tmux new -A -s main"gives the tmux server a broken PATH because only~/.zshenvruns and zshenv didn’t prepend user paths. Also added a_dedupe_pathprecmd hook becausetypeset -U pathwasn’t catching post-direnv additions (observable duplicatecoreutilsentry). Factored the PATH literal into auserPathSetuplet-binding so the three init sites (zshenv, zprofile, zshrc) share one source of truth.3e01b5f— Setxdg.enable = true(replaced four manualXDG_*exports — defaults match exactly), removedallowBroken = true(was doing nothing; nothing in closure is broken), updated thedownload-buffer-sizecomment to clarify it’s client-side only (daemon reads/etc/nix/nix.confwhich we don’t manage).2b73a43— Deleted unuseddotfilesregistry entry (rgconfirmed zero usages), deleted a danglingprograms.docker-clicomment block, migrated zsh dotfiles to XDG viaprograms.zsh.dotDir = "${config.xdg.configHome}/zsh". HM auto-generates a stub~/.zshenvthat setsZDOTDIRand chains.af8ce0a— Follow-up: the dotDir migration created untracked files in the repo root, since~/.config/IS the dotfiles repo root. Addedzsh/to.gitignorealongside other HM-managed dirs.d0d5cd5— Docs only: clarified the two-flake layout in AGENTS.md (rootflake.nixis dev-shell only, HM flake atnix/flake.nix), added a footgun note to thelistFilesRecursiveauto-import comment (renaming a module tolib.nixsilently disables it).
What was striking
- The SSH-direct-to-tmux gap was real and previously unnoticed. Tmux panes worked because
.zshrcre-fixed PATH, masking the fact that the tmux server itself (and anyrun-shellit invokes) had a broken PATH. The fix is one line inenvExtra. The reasoning to get there was the whole detective story: shell init order × macOSpath_helper× tmux non-login config × romkatv’s keep-zshenv-minimal advice. - The
replaceVarsWith@vars@paranoia check treats unreplaced@identifier@patterns as build failures. Cost me a minor comment rewrite but caught the kind of bug that would otherwise ship silently. ~/.config/being the repo root made the dotDir migration leak HM artifacts into the working tree until I gitignored. Non-obvious interaction between two unrelated choices (XDG paths + dotfiles repo location).- Three commits were pure DRY/cleanup wins with verified equivalent output — the
mapAttrs'refactor, the PATH literal factoring, thexdg.enableswap. Thediff -rcomparison of thehome-manager-filesderivation between before/after was satisfying: different store hash because builder script differs, byte-identical contents. - Sometimes the right answer is “leave it alone.” I had flagged
home.usernameas inline-instead-of-parameterized and thecompletionInit = ""workaround as worth rechecking, but on closer inspection: the first isn’t actionable without multi-host support, and HM #3965 is still open so the workaround is still needed. Knowing when a finding isn’t worth a commit is as important as the fix.
Top 3 tomorrow
- Maybe write the LiteLLM patches README — five accumulated patches in
nix/home-manager/modules/patches/deserve a status table (upstream PR vs permanent fork). - Confirm no shell-startup regressions over a few days of using the new dotDir setup.
- Open
home.usernameparameterization or revisit thecompletionInitworkaround only if pain surfaces.