fix(installer): wire HM as a NixOS module, move env-update to system layer

The post-install standalone HM activation kept failing in new ways
(daemon access, git ownership, missing PATH on first boot). Wire HM as
a NixOS module in the generated flake instead, so first-boot dotfiles
are activated by `nixos-install` itself with proper system context. The
standalone `homeConfigurations.<user>` is kept alongside for fast
iteration via `nomarchy-env-update`. Also:

- Drop the chroot HM activation block from the installer entirely.
- Move `nomarchy-env-update` from `features/scripts/utils/` to
  `core/system/scripts/` so it ships in `nomarchy-system-scripts` and
  exists on a freshly-installed system regardless of HM state.
- Set system-wide git `safe.directory` for /etc/nixos and the
  impermanence-relocated /persist/etc/nixos so the user-mode HM run
  doesn't trip on the root-owned flake repo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-05-02 12:24:12 +01:00
parent d4f50afc62
commit bef7be01b8
3 changed files with 43 additions and 57 deletions

View File

@@ -2,4 +2,13 @@
{
environment.systemPackages = [ pkgs.nomarchy-system-scripts ];
# /etc/nixos is owned by root, but `nomarchy-env-update` (and `nix
# flake` invocations) run as the user and shell out to git. Without
# this, git refuses with "dubious ownership in repository" and HM
# evaluation fails. Mark both the standard and impermanence-relocated
# paths as safe at the system level so every user is covered.
programs.git.config = {
safe.directory = [ "/etc/nixos" "/persist/etc/nixos" ];
};
}

View File

@@ -1,12 +1,13 @@
#!/usr/bin/env bash
# Nomarchy Environment Update Script
# 1. Runs the pre-flight state migration
# 2. Applies user-level Home Manager changes (Standalone)
# Standalone Home Manager iteration path. Use this for fast dotfile and
# theme changes that don't need a full system rebuild. For first-boot
# dotfiles and any system-level change, the NixOS module activation
# from `sudo nixos-rebuild switch` is the source of truth.
set -e
# Detect the repository location
if [ -f "/etc/nixos/flake.nix" ]; then
REPO_DIR="/etc/nixos"
elif [ -f "/etc/nomarchy/flake.nix" ]; then
@@ -16,19 +17,16 @@ else
exit 1
fi
# Use the pre-flight migration script to ensure the state is synced before evaluation
if command -v nomarchy-preflight-migration >/dev/null 2>&1; then
nomarchy-preflight-migration
fi
# Apply Home Manager changes from the local flake (Standalone).
# On a freshly-installed system where the installer's HM activation failed,
# `home-manager` won't be on PATH yet — fall back to `nix run` so this
# script can recover the install instead of erroring on a missing binary.
echo "Applying user-level changes from $REPO_DIR#$USER..."
if command -v home-manager >/dev/null 2>&1; then
home-manager switch --flake "$REPO_DIR#$USER" --impure
else
# Bootstrap path: HM hasn't put `home-manager` on PATH yet (e.g. running
# straight after a partial install). Pull it from the flake registry.
nix --extra-experimental-features 'nix-command flakes' \
run 'home-manager/release-25.11' \
-- switch --flake "$REPO_DIR#$USER" --impure

View File

@@ -1256,47 +1256,10 @@ execute_installation() {
nixos-install --flake "/mnt/etc/nixos#$HOSTNAME" --no-root-passwd
success "Nomarchy installed"
# 9.8 Activate Home Manager for $USERNAME inside the new system so the
# user's first login already has Nomarchy's dotfiles. `home-manager
# switch` must run as the target user with a real \$HOME *and* a
# \$USER env var pointing at them — home-manager's activation script
# bails with "running as root" if \$USER is still root, even when the
# uid has been switched. `runuser -l` runs a login shell, which sets
# HOME, USER, LOGNAME, and SHELL from the user database; plain
# `runuser -u … -- env HOME=…` switches uid only and leaves \$USER
# as root, which is what landed the dotfiles in /root previously.
info "Activating Home Manager for $USERNAME..."
# `nixos-enter` chroots without starting systemd, so nix-daemon isn't
# running. A user-level `nix run` would then fall back to single-user
# mode and try to write /nix/var/nix/db directly — which root owns in
# the multi-user store, so it fails with "big.lock: Permission denied".
# Launch the daemon manually for the duration of the activation.
if nixos-enter --root /mnt -- bash -c "
set -e
install -d -o '$USERNAME' -g users -m 0755 '/home/$USERNAME'
# /etc/nixos is a git repo owned by root (we init it as root above).
# When HM runs as the user, nix invokes git, which refuses with
# 'dubious ownership' unless the path is marked safe system-wide.
git config --system --add safe.directory /etc/nixos || true
git config --system --add safe.directory /persist/etc/nixos || true
/run/current-system/sw/bin/nix-daemon --daemon &
DAEMON_PID=\$!
trap 'kill \$DAEMON_PID 2>/dev/null || true' EXIT
for _ in \$(seq 1 50); do
[ -S /nix/var/nix/daemon-socket/socket ] && break
sleep 0.1
done
runuser -l '$USERNAME' -c \"NIX_REMOTE=daemon nix --extra-experimental-features 'nix-command flakes' run 'home-manager/release-25.11' -- switch --flake '/etc/nixos#$USERNAME' --impure\"
"; then
success "Home Manager activated"
else
error "Home Manager activation failed (non-fatal)."
info "Run \`nomarchy-env-update\` after the first login to retry."
fi
# 9.8 (Removed) Standalone Home Manager activation in a chroot.
# HM is now wired as a NixOS module in the generated flake, so
# `nixos-install` above already activated the user's dotfiles as part
# of system activation. No chroot dance required.
# 9.9 Pre-flight: catch evaluation errors in the freshly-installed
# configuration *now*, while we can still fix them with `vi`, instead of
@@ -1432,11 +1395,15 @@ generate_flake_config() {
};
# Two-track Nomarchy workflow:
# * System changes → sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME
# * Dotfiles/themes → nomarchy-env-update (home-manager switch, no rebuild)
# * System + dotfiles (full) → sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME
# * Dotfiles only (fast iter) → nomarchy-env-update (standalone home-manager switch)
#
# Both consume the same \`pkgs\` below so overlays and allowUnfree stay in
# sync across the two paths.
# Home Manager is wired both ways:
# - As a NixOS module under \`nixosConfigurations.$HOSTNAME\` so first boot
# after install already has dotfiles in place and every nixos-rebuild
# reconciles them. This is what makes the install actually usable.
# - As a standalone \`homeConfigurations.$USERNAME\` so theme switches and
# dotfile iteration don't require a full system rebuild.
outputs = { self, nomarchy, ... }@inputs:
let
inherit (nomarchy.inputs) nixpkgs home-manager;
@@ -1459,12 +1426,24 @@ generate_flake_config() {
./hardware-selection.nix
nomarchy.nixosModules.system
./system.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.backupFileExtension = "hm-bak";
home-manager.extraSpecialArgs = { inputs = nomarchy.inputs; };
home-manager.users.$USERNAME = {
imports = [ nomarchy.nixosModules.home ./home.nix ];
home.stateVersion = "25.11";
};
}
];
};
# Standalone Home Manager — \`home-manager switch --flake /etc/nixos#$USERNAME\`
# (which is what \`nomarchy-env-update\` runs). Kept separate from the
# NixOS config so dotfile/theme iterations don't rebuild the system.
# (which is what \`nomarchy-env-update\` runs). Kept alongside the NixOS
# module above so dotfile/theme iterations can skip a full system rebuild.
homeConfigurations.$USERNAME = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = { inputs = nomarchy.inputs; };
@@ -1721,8 +1700,8 @@ finish() {
echo " 4. Your configuration lives at /etc/nixos/"
echo ""
echo "Rebuild commands:"
echo " • System: sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME"
echo " • Dotfiles: nomarchy-env-update (runs home-manager switch)"
echo " • System + dotfiles: sudo nixos-rebuild switch --flake /etc/nixos#$HOSTNAME"
echo " • Dotfiles only: nomarchy-env-update (fast standalone home-manager switch)"
echo ""
echo "Tip: run 'nomarchy-themes-prebuild' once to pre-cache every theme"
echo " variant. Theme switches after that are instant (no rebuild)."