# Session Log ## Current Repo State - The git worktree is dirty. Many files were already modified before or during this session. Do not revert unrelated changes. - New main host/user additions are already in place: - hosts: `polaris`, `zenith`, `orion` - users: `kiri`, `ergon` - `zenith` is the Lenovo Yoga Slim 7 ProX 14ARH7 laptop. - `ergon` is the work user and is present on `polaris` and `zenith`, not `orion`. ## Naming Decisions - Host names chosen: - `polaris` = main machine - `zenith` = laptop - `orion` = VPS - Work user chosen: - `ergon` ## Den / Architecture Decisions - `kiri` stays on `den._.primary-user`. - `ergon` is explicit and should not use `den._.primary-user`. - Do not introduce a local `admin-user` battery yet. Keep repeated patterns explicit until they stabilize. - Prefer host files thin and move reusable behavior into `modules/features/` or `modules/profiles/`. ## Den Helper Mental Model - `perHost` / `perUser` are stage gates, not just readability helpers. - `perUser` is not the same as `parametric.exactly`. - Actual behavior: - `perUser` gates entry at exact `{ host, user }`, then evaluates the wrapped aspect under fixed `{ host, user }` with normal `atLeast` matching inside. - `parametric.exactly` is an inner include matcher based on exact context shape. - Practical rule used in this repo: - use `perHost` for host-owned NixOS config that must apply once per host - use `perUser` for host-user-pair HM or NixOS config - avoid `take.*` unless doing low-level Den plumbing ## Niri / Display Model - `lux.niri` was intentionally collapsed back into one conceptual aspect in `modules/features/niri.nix`. - It now uses: - `den.lib.perHost` for NixOS-side Niri setup - `den.lib.perUser` for HM-side Niri settings - Host monitor layout is a host fact, not a user fact. - `den.schema.host.displays` exists and is the source of truth for monitor facts. - Current `polaris` display layout lives in `modules/infra.nix`. - `programs.niri.settings.outputs` is derived from `host.displays`, so both `kiri` and `ergon` on `polaris` get the same output configuration. - `displays` intentionally has no `enabled` flag; omission means absent. ## SOPS / SSH / GPG Decisions - Repo-managed GPG was removed from `modules/features/ssh.nix`. - If commit signing is added later, prefer SSH signing rather than restoring repo-managed GPG. - Secret recipient policy currently is: - one admin age recipient - `orion` SSH host key recipient - `.sops.yaml` and `modules/secrets/secrets.yaml` were rekeyed to that policy. ## Current SOPS Model - SOPS is now host-owned conceptually. - Current host schema fields: - `sopsHostSshKeyPath` - `sopsAdminKeyPath` - `sopsAdminKeyUsers` - Current policy: - `orion` uses `sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]` for host-level NixOS decryption. - local hosts (`polaris`, `zenith`) use `/var/lib/sops-nix/admin-key.txt` for host-level NixOS decryption. - HM SOPS also uses the host-provisioned `/var/lib/sops-nix/admin-key.txt`, but only for users listed in `host.sopsAdminKeyUsers`. - Shared reader group: - `sops-users` - Current host metadata in `modules/infra.nix`: - `polaris.sopsAdminKeyPath = "/var/lib/sops-nix/admin-key.txt"` - `polaris.sopsAdminKeyUsers = [ "kiri" "ergon" ]` - `zenith.sopsAdminKeyPath = "/var/lib/sops-nix/admin-key.txt"` - `zenith.sopsAdminKeyUsers = [ "kiri" "ergon" ]` - `orion.sopsAdminKeyPath = "/var/lib/sops-nix/admin-key.txt"` - `orion.sopsAdminKeyUsers = [ "kiri" ]` - `orion.sopsHostSshKeyPath = "/etc/ssh/ssh_host_ed25519_key"` - Important operational caveat: - the admin key file is expected to be provisioned out-of-band on hosts - config creates `/var/lib/sops-nix` via tmpfiles and adds listed users to `sops-users`, but does not create the private key itself ## SSH Recovery Policy - `orion` is treated as the remote recovery-critical host. - `modules/features/services/openssh.nix` now owns both: - OpenSSH base config - user `authorizedKeys` - Recovery assertions now enforce for `requiresSshRecovery = true`: - OpenSSH enabled - password auth disabled - root login disabled - `sshRecoveryUsers` non-empty - every recovery user exists - every recovery user has plain `authorizedSshKeys` - `sopsHostSshKeyPath` non-null - SSH exposed through firewall - `AllowUsers = lib.attrNames host.users` is still the intended model. ## Recent Validation Results - Successfully built after the Niri / SOPS / SSH refactors: - `nix build .#nixosConfigurations.polaris.config.system.build.toplevel --show-trace` - `nix build .#nixosConfigurations.orion.config.system.build.toplevel --show-trace` - `nix build .#nixosConfigurations.zenith.config.system.build.toplevel --show-trace` - Verified by evaluation: - `polaris` Niri outputs for `kiri` and `ergon` match - local hosts resolve `config.sops.age.keyFile = "/var/lib/sops-nix/admin-key.txt"` - `orion` resolves `config.sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]` - HM SOPS for allowed users resolves `"/var/lib/sops-nix/admin-key.txt"` - `ergon@polaris` has `["sops-users", "wheel", "networkmanager"]` - tmpfiles includes `d /var/lib/sops-nix 0750 root sops-users -` ## Remaining Warnings / Caveats - Builds still emit pre-existing Home Manager default-change warnings: - `gtk.gtk4.theme` - `xdg.userDirs.setSessionVariables` - `programs.git.signing.format` - These warnings were not addressed in this session. - There is no deployment wrapper or automated bootstrap tooling yet. - `nixos-anywhere --copy-host-keys` remains the intended `orion` install approach when preserving the SSH host key for first-boot SOPS decryption. ## Architecture Contract - Added `ARCHITECTURE.md` as the single durable reference for the repo's intended 1.0 structure. - The contract is grounded in the current codebase: - `schema` and `infra` own facts - `users` own cross-host user baselines - `features` own reusable behavior - `profiles` and `environments` own bundling - `hosts` stay thin and compose the final machine shape - Kept the existing Den helper convention explicit: - `perHost` and `perUser` are stage gates - `parametric.exactly` is only for exact inner matching - avoid new local batteries until the pattern is stable - No repo redesign was done; this was documentation only. - Validation: - doc-only change - no `nix build` run in this session - Small open question for later: - whether `ARCHITECTURE.md` should stay standalone or also be linked from `AGENTS.md` / future README if a contributor-facing index is added ## Architecture Simplification - Collapsed `environments` into `profiles`. - Current rule is now simpler: - `features` are the smallest reusable behavior units - `profiles` are all named bundles larger than a single feature - `hosts` still own final composition and explicit host-specific exceptions - `modules/environments.nix` was removed. - `graphical` and `development` now live under `lux.profiles._`. - Kept the repeated `provides.kiri` / `provides.ergon` host wiring explicit for now. The duplication is intentional until a shared host-composition pattern is clearly stable enough to justify extraction. - Validation: - `nix build .#nixosConfigurations.polaris.config.system.build.toplevel --show-trace` - `nix build .#nixosConfigurations.orion.config.system.build.toplevel --show-trace` - `nix build .#nixosConfigurations.zenith.config.system.build.toplevel --show-trace` ## MANUAL INTERVENTION NOTE BY HUMAN USER, NOT AI AGENT Removed `ARCHITECTURE.md`. Pinning down the architecture this explicitly feels too rigid and unnecessary. Perhaps a more generally applicable Design Philsophy would be more helpful and allow for more flexibility.