2026-06-08 Nix Home-Manager Review and Cross-Platform Fixes

What I set out to do

A complete best-practices / nixisms review of the nix/ + Home Manager setup in .config, then work through every finding. Follows on from the 2026-05-14 Dotfiles Nix Audit Cleanup pass.

What I actually did

Reviewed ~50 nix files (flake-parts flakes, auto-discovered HM modules, custom home.mutableFile and mkUvProject abstractions, hand-built pkgs/ derivations) via four parallel review agents plus tree-wide statix/deadnix. Verdict: well above average, only one true DRY violation and a couple of real bugs. Then remediated the whole review across ~11 hm switch-verified commits, in batches:

HIGH/MEDIUM core

  • signoz-mcp-server — gated on aarch64-darwin (the prebuilt is arm64-only), tightened the derivation (dontBuild/dontConfigure, install -Dm755, Apache-2.0 license), and made the MCP entry tolerate the package’s absence.
  • Cooldown dedupe — collapsed the 3-day supply-chain cooldown duplicated across npm/yarn/bun, uv, and prek into one local.releaseCooldownDays option, re-encoded per tool.
  • Linux portability — guarded Darwin-only blocks (targets.darwin, jankyborders launchd), pkgs.ghostty (source) on Linux, chromium for the mermaid wrapper, and a lib.meta.availableOn filter so arch-unsupported packages drop out instead of breaking eval.
  • macmon launchd agent narrowed to aarch64 (package is Apple-Silicon-only).

Security / correctness / tooling

  • sillytavern whitelist CIDR typo (172.0.0.0/8 172.16.0.0/12); kept the port LAN-reachable by intent.
  • installClaude activation: download installer to a file and guard each step with $DRY_RUN_CMD (a curl | bash pipe can’t be guarded).
  • golint golangci-lint; gitleaks protect --staged git --staged.

Low nits + typing

  • commonLib.toClientServers to dedupe the MCP projection; single-source enabledPlugins; pkgs.formats.json in claude-desktop; dropped the shadowing home-manager alias; mkShell buildInputs packages.
  • Typed all 7 service ports as lib.types.port + toString at every interpolation site.

Structural refactors

  • modules/docker/lib.nix: shared desktopPath + mkComposeDeploy for the open-webui/sillytavern/sqlite-seed compose-activation pattern.
  • Extracted the ~150-line signoz OTel Python transform to a ruff-linted files/scripts/patch-otel-config.py, and 8 interpolation-free tmux scripts to files/scripts/tmux/.

What was striking

The “remaining failure” on x86_64-darwin was two stacked issues: a macmon gating bug, then an upstream wall: arrow-cpp is marked broken on x86_64-darwin in nixpkgs (genuine Hydra failure), pulled transitively by litellm -> datasets -> pyarrow -> arrow-cpp. Not fixable in-config, so I dropped x86_64-darwin from systems rather than gut the LiteLLM stack on Intel. That made the isIntelDarwin workarounds dead code, whose removal also killed the bare fetchTarball nixpkgs pin the review had flagged.

Lessons banked:

  • Dropping a platform can beat fighting an upstream-broken dependency, and often unlocks dead-code cleanup downstream.
  • Verify before “fixing”: the review claimed jupyter’s fetchNews = "false" wanted a bool, but the JupyterLab schema is a string enum (true/false/none). Checked the schema instead of trusting the finding.
  • DRY divergent code with a flag, not by forcing unification: mkComposeDeploy’s ensureRunning lets open-webui stay ensure-running and sillytavern stay manual-start, so the abstraction is behavior-preserving rather than a flag-soup compromise.
  • Footgun caught: a broad unanchored tmux/ .gitignore rule silently swallowed the new tracked source dir; anchoring to /tmux/ (matching the existing /claude-ops/ precedent) fixed it.