From 053c4de5295c312f710a5f6d3dcbddd945c0bc29 Mon Sep 17 00:00:00 2001 From: alexion Date: Sat, 18 Jul 2026 15:28:39 -0400 Subject: [PATCH] feat(neogaia): add the CachyOS kernel and hardware enablement Select the CachyOS kernel per-Host via boot.kernelPackages, enable Intel microcode and redistributable firmware (ath10k for the QCA6174 wifi), and move zram behind a toggle Module. Declare the chaotic binary cache in the base Nix settings (extra-substituters/keys) so the built system fetches the kernel from nyx-cache rather than compiling it. --- .claude/tasks/0003-kernel-and-hardware.md | 27 +++++++++++++++++++++++ CLAUDE.md | 4 ++++ hosts/neogaia/default.nix | 19 +++++++++++++--- modules/zram.nix | 14 ++++++++++++ system/default.nix | 12 ++++++++++ 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 .claude/tasks/0003-kernel-and-hardware.md create mode 100644 modules/zram.nix diff --git a/.claude/tasks/0003-kernel-and-hardware.md b/.claude/tasks/0003-kernel-and-hardware.md new file mode 100644 index 0000000..18b1e1e --- /dev/null +++ b/.claude/tasks/0003-kernel-and-hardware.md @@ -0,0 +1,27 @@ +--- +spec: laptop-mvi +blocked-by: 0001-skeleton-and-building-host +--- + +## What to build + +Give `neogaia` the kernel and hardware enablement it needs to run well on the Dell XPS 13 9380: the CachyOS kernel pulled as a binary from chaotic-nyx (not compiled from source), Intel microcode, and the redistributable firmware for the QCA6174 wifi. Add a zram toggle `Module` and enable it here. + +The kernel is selected through a small per-`Host` kernel mechanism so other `Host`s can choose different kernels. The chaotic substituter and its trusted public key are added to the Nix settings so the kernel is fetched from the binary cache from the first build. + +## Acceptance criteria + +- [x] `neogaia` runs the CachyOS kernel selected via a per-`Host` kernel mechanism, sourced from chaotic-nyx. +- [x] The chaotic substituter and trusted public key are in the Nix settings, so the kernel is fetched from cache rather than compiled. +- [x] Intel microcode is enabled. +- [x] Redistributable firmware is enabled so the QCA6174 wifi hardware is available. +- [x] A zram toggle `Module` exists (following the `Enable convention`) and is enabled on `neogaia`. +- [x] The `neogaia` toplevel still builds with all of the above. + +## Implementation Notes + +- **Per-`Host` kernel mechanism = native `boot.kernelPackages`.** neogaia sets `boot.kernelPackages = pkgs.linuxPackages_cachyos` directly in its Host directory (`hosts/neogaia/default.nix`). No custom wrapper option was added: `boot.kernelPackages` is already a per-`Host` setting, so other `Host`s pick their own kernel the same way. A string→package wrapper would have been premature abstraction with one `Host` and one kernel, so it was deliberately left out; the "mechanism" is the per-`Host` placement of the native option. +- **Substituter/key live in the shared base, via the `extra-` options.** They were added to `system/default.nix` (shared by every `Host`), not just neogaia, because the chaotic module is wired for all `Host`s and the cache is general plumbing. `nix.settings.extra-substituters` / `extra-trusted-public-keys` are used rather than the replacing `substituters` / `trusted-public-keys`, so `cache.nixos.org` (and any other substituter) is only appended to, never dropped. chaotic's own module also provides these entries; the explicit declaration is belt-and-suspenders and keeps the built system's cache config visible and independent of that module. +- **Dev-host build needed a daemon-level cache.** Building the toplevel here first compiled the CachyOS kernel (and rustc bootstrap) from source, because the build daemon's `/etc/nix/nix.conf` had no `nyx-cache` substituter — the built system's `nix.settings` do not govern the daemon doing the build, and the dev user is a non-trusted client that cannot add substituters from the CLI. Adding `extra-substituters`/`extra-trusted-public-keys` for `nyx-cache` to `/etc/nix/nix.conf` (sudo) and restarting `nix-daemon` fixed it; the build then fetched the kernel (7.1.3) from the cache. Recorded as a gotcha in `CLAUDE.md`. +- **zram `Module` kept minimal.** `modules/zram.nix` is a pure toggle (`zramSwap.enable = true` under `mkIf`), following the `modules/example.nix` reference shape. This preserves task 0002's exact behaviour while moving the switch behind the `Enable convention`; the direct `zramSwap.enable = true` previously inline in the `Host` was removed in favour of `modules.zram.enable = true`. +- **Why zram graduated to a `Module` but kernel/microcode/firmware stayed inline.** zram is a reusable, cross-`Host` feature toggle (the spec calls for it as a `Module`), whereas the kernel choice, Intel microcode, and firmware are neogaia-specific hardware facts that belong to the `Host` itself. diff --git a/CLAUDE.md b/CLAUDE.md index a4ab215..ce804ea 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,6 +10,10 @@ The domain model (Host, Module, Skeleton, Auto-loader, Enable convention, overla The system `/etc/nix/nix.conf` does not enable flakes, so export `NIX_CONFIG="experimental-features = nix-command flakes"` (or pass `--extra-experimental-features 'nix-command flakes'`) for every command. - The dev user is a non-trusted daemon client (`nix store info` reports `Trusted: 0`). You cannot add substituters from the CLI, so rely on what the flake/config declares (e.g. the chaotic cache is wired by the chaotic module, not a CLI flag). + Caveat that bites when a Host actually selects the CachyOS kernel: the substituters a `nix build` fetches from are the **daemon's** (`/etc/nix/nix.conf`), *not* the `nix.settings` of the config being built — those only govern the built system. + This dev host's `/etc/nix/nix.conf` has no `substituters`/`trusted-substituters` lines, so building a toplevel whose `boot.kernelPackages` is `linuxPackages_cachyos` compiles the kernel (and rustc bootstrap, etc.) from source instead of hitting `nyx-cache`. + To build such a Host here, first add `extra-substituters = https://nyx-cache.chaotic.cx/` and `extra-trusted-public-keys = nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk=` to `/etc/nix/nix.conf` (sudo) and `sudo systemctl restart nix-daemon`. + `nix eval` of the kernel version does *not* trigger this — only a real build does. - If `/nix/store` is missing or `nix-daemon` is inactive after a fresh Nix install, initialise it with `sudo systemd-tmpfiles --create nix-daemon.conf && sudo systemctl enable --now nix-daemon.socket`. - The primary build/verify seam for any Host is `nix flake check`, which builds `checks.x86_64-linux.` (the system toplevel); cheap targeted checks use `nix eval .#nixosConfigurations..config...`. - chaotic-nyx must **not** follow our `nixpkgs`, and its packages are built against chaotic's own pinned nixpkgs (its overlay defaults to `onTopOf = "flake-nixpkgs"`, the cache-friendly path). diff --git a/hosts/neogaia/default.nix b/hosts/neogaia/default.nix index 7547a35..753d370 100644 --- a/hosts/neogaia/default.nix +++ b/hosts/neogaia/default.nix @@ -1,4 +1,4 @@ -{ ... }: +{ pkgs, ... }: # neogaia — Dell XPS 13 9380 laptop. # # The disk layout lives in ./disk.nix (disko); the resulting `fileSystems` are @@ -17,6 +17,19 @@ boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - # Swap is RAM-backed zram rather than an on-disk partition. - zramSwap.enable = true; + # Kernel is a per-Host choice, expressed through boot.kernelPackages: neogaia + # runs the CachyOS kernel from chaotic-nyx (fetched from the chaotic binary + # cache wired in system/, not compiled from source). Other Hosts pick their + # own kernel the same way, so the choice never leaves the Host. + boot.kernelPackages = pkgs.linuxPackages_cachyos; + + # Intel CPU microcode updates for the XPS 13's Core i7-8565U. + hardware.cpu.intel.updateMicrocode = true; + + # Redistributable firmware — carries the ath10k blobs the QCA6174 wifi needs. + hardware.enableRedistributableFirmware = true; + + # Swap is RAM-backed zram (the zram Module) rather than an on-disk partition, + # matching the disko layout, which declares no swap partition. + modules.zram.enable = true; } diff --git a/modules/zram.nix b/modules/zram.nix new file mode 100644 index 0000000..432544a --- /dev/null +++ b/modules/zram.nix @@ -0,0 +1,14 @@ +{ config, lib, ... }: +# A toggle for RAM-backed swap. A Host that has no on-disk swap partition (like +# neogaia, whose disko layout deliberately omits one) enables this to get a +# compressed zram device instead. +let + cfg = config.modules.zram; +in +{ + options.modules.zram.enable = lib.mkEnableOption "zram-backed compressed swap"; + + config = lib.mkIf cfg.enable { + zramSwap.enable = true; + }; +} diff --git a/system/default.nix b/system/default.nix index 57f42b8..1e828ce 100644 --- a/system/default.nix +++ b/system/default.nix @@ -51,6 +51,18 @@ in "nix-command" "flakes" ]; + + # The chaotic binary cache, declared explicitly on the built system so the + # CachyOS kernel is substituted rather than compiled. chaotic's own module + # also provides these, but stating them here keeps the built system's cache + # config visible and independent of that module. Added via the `extra-` + # options so they only append — cache.nixos.org and any other substituter + # are never dropped. (Fetching at install time depends on the installing + # daemon's substituters, not this — see the chaotic gotcha in CLAUDE.md.) + nix.settings.extra-substituters = [ "https://nyx-cache.chaotic.cx/" ]; + nix.settings.extra-trusted-public-keys = [ + "nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk=" + ]; environment.systemPackages = [ pkgs.git ]; # Primary user, in wheel. No password is set here.