diff --git a/README.md b/README.md index 2bb582e..111a0c4 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ Flat on purpose. Two module trees, one options file each, no hidden layers. │ └── nomarchy-install/ # live-ISO installer (gum + disko + mkFlake) ├── templates/downstream/ # `nix flake init -t` starter for users ├── docs/TESTING.md # how to verify changes (incl. AI-agent rules) +├── docs/HARDWARE.md # firmware, drivers, profiles, unsupported machines ├── docs/OVERRIDES.md # how downstream users override defaults ├── docs/RECOVERY.md # runbook: broken theme/desktop/boot → undo it ├── docs/ROADMAP.md # design/decision records + shipped-fixes log @@ -112,7 +113,8 @@ Like what you see? **`nomarchy-install`** (in a terminal) walks you through installing to disk: pick a disk, LUKS2 full-disk encryption **by default** (in exchange the desktop logs in passwordless — the passphrase already gates the machine), user + hostname + timezone, hardware autodetection -(DMI → nixos-hardware profile), a hibernation-ready swapfile sized to RAM, +(DMI → nixos-hardware profile — see **[docs/HARDWARE.md](docs/HARDWARE.md)**), +a hibernation-ready swapfile sized to RAM, then disko partitions (GPT + ESP + BTRFS subvolumes incl. `@snapshots` — snapper timeline snapshots are on) and `nixos-install` runs — **without a network** when the ISO was built from a clean tree (the target's @@ -287,7 +289,9 @@ machine after 10 seconds (`panic=10 oops=panic`) rather than hanging indefinitely. **`services.fwupd.enable`** is on by default for firmware updates via LVFS — it only refreshes metadata, never flashes on its own, so run `fwupdmgr update` to apply; disable with `services.fwupd.enable = -false;` on machines without real firmware (VMs/headless). And +false;` on machines without real firmware (VMs/headless). Full hardware +story (profiles, fingerprint, NVIDIA, unsupported machines, contributing +a DMI line): **[docs/HARDWARE.md](docs/HARDWARE.md)**. And **`services.earlyoom`** is on by default so running out of memory kills the offending process (with a desktop notification) instead of freezing the desktop — process-level on purpose, since a Hyprland session is one diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 8e40bea..ac0bb27 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -517,6 +517,89 @@ flagged separately from fidelity bugs.* design) — optional README note so users know what ships and how to override. Cost: docs only. +### Hardware product (investigation 2026-07-09) + +*Full write-up: [`docs/HARDWARE.md`](../docs/HARDWARE.md). Install-time +autodetect is strong; day-2 lifecycle (firmware, biometrics, re-detect, +NVIDIA depth) is still mostly CLI. Items below are product work on top +of that doc — design notes live there (§4–§10).* + +- **System › Firmware (fwupd product surface)** + `services.fwupd.enable` is already default-on and never auto-flashes, + but users only learn about `fwupdmgr` from a README sentence. Add a + self-gated menu entry (System submenu) and/or Control Center row that: + refreshes metadata, lists updatable devices, confirms, runs + `fwupdmgr update`, then prints a reboot note when needed. Never + silent-flash (pillar 1). Optional: first-boot / MOTD one-liner when + the daemon is active. Spec: docs/HARDWARE.md §4. Cost: menu script + + optional MOTD; V2 menu, V3 on real LVFS hardware. + +- **Doctor hardware section (read-only)** + Extend `nomarchy-doctor` with the same pass/fail + one-fix-command + contract for: NetworkManager connectivity, default PipeWire sink, + optional GPU smoke (`vainfo`/`glxinfo` if present), fprintd unit when + fingerprint was enabled, fwupd active (+ warn if `get-updates` + non-empty), laptop charge-threshold sysfs when a limit is set. Spec: + docs/HARDWARE.md §10. Cost: doctor.sh sections; V1 in existing + `checks.doctor` where fakes exist, rest V2/V3. + +- **`nomarchy-detect-hw` CLI (post-install re-probe)** + The installer already has pure `nomarchy_detect_hw` stdout protocol + (MODULE / NOMARCHY / DETAIL). Ship it as a package on PATH that + prints suggested `hardwareProfile = [ … ]` and `system.nix` snippets + without reinstalling — closes the template/migration gap and “I + swapped the Wi‑Fi card.” Does not rewrite the flake unless a later + `--apply` is explicitly designed. Spec: docs/HARDWARE.md §8. Cost: + extract script + package + man/README pointer; V0–V1. + +- **Fingerprint menu: enroll / list (+ optional PAM toggle)** + Installer enables fprintd on known USB VIDs but enroll is CLI-only + (`fprintd-enroll`) and PAM is a commented rebuild. Self-gated System + row when `fprintd` is present: enroll, list, delete; optional “use + for login” that writes `settings`/system intent + rebuild note + (Control Center Bluetooth pattern). Spec: docs/HARDWARE.md §5. + Cost: menu module; V3 enroll on real reader (`[blocked:hw]` for + full path). + +- **Installer: NVIDIA commented system.nix guidance** + Detection already adds `common-gpu-nvidia`; there is no + `nomarchy.hardware.nvidia.*` and hybrid/PRIME is wiki territory. + When NVIDIA is detected, emit a **commented** block in generated + `system.nix` (same style as ROCm/NPU) pointing at PRIME / + powerManagement / open-module and docs/HARDWARE.md §6 — not a full + second stack. Cost: install script strings; V0 + doc. + +- **CI: hardware-db module names ∈ nixos-hardware** + Every `HARDWARE_DB` third field must exist in the pinned + `nixos-hardware.nixosModules` or installs break only on matching + DMI. Add a pure `checks.*` (or option-docs-style runCommand). Pairs + with existing “installer pure contracts” proposal. Cost: small + check; V0. + +- **Installer: `usbutils` on PATH for fingerprint probe** + Fingerprint path prefers `lsusb` but package wrap has `pciutils` + only; sysfs VID walk is the fallback. Add `usbutils` to + `nomarchy-install` PATH for reliable detection. Cost: one package + in wrap; V0. + +- **Document + README table: `nomarchy.hardware.i2c.*`** + `i2c.ddcci` is **mkDefault true** (external monitor brightness) but + missing from README option tables → `checks.option-docs` red (also + under docs-drift pack). Document in README + HARDWARE.md already + mentions ddcci; close option-docs. Cost: docs; V0 with option-docs. + +- **Post-install hardware hints (MOTD / first session)** + When relevant services exist, surface one line each: firmware + (`fwupdmgr get-updates`), fingerprint (`fprintd-enroll`), optional + “run nomarchy-doctor”. Avoid nagging — once or until dismissed. + Spec: HARDWARE.md §4/§5. Cost: small greeter/MOTD or notify; V2/V3. + +- **NVIDIA first-class options (larger, optional)** + Only if a maintainer commits to hybrid testing: thin + `nomarchy.hardware.nvidia.*` wrapping common PRIME/power patterns. + Prefer the commented-guidance item first; promote only with + hardware-queue coverage. Cost: high; `[big]` + `[blocked:hw]`. + ## Decisions `[human]` diff --git a/docs/HARDWARE.md b/docs/HARDWARE.md new file mode 100644 index 0000000..58579fb --- /dev/null +++ b/docs/HARDWARE.md @@ -0,0 +1,391 @@ +# Hardware support + +How Nomarchy enables CPUs, GPUs, laptops, firmware, and peripherals — and +what to do when your machine is not in the happy path. + +> **Queue:** product follow-ups live in [`agent/BACKLOG.md`](../agent/BACKLOG.md) +> (PROPOSED › Hardware product). Design history: [`ROADMAP.md`](ROADMAP.md). +> Migration without reinstall: [`MIGRATION.md`](MIGRATION.md). + +## 1. Architecture (three layers) + +Nomarchy does **not** reimplement [nixos-hardware](https://github.com/NixOS/nixos-hardware). +It stacks: + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ A. Always-on desktop floor │ +│ modules/nixos/default.nix + power.nix + audio/BT │ +│ redistributable firmware · fwupd · NM · PipeWire · PPD · ddcci │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ +┌───────────────────────────────▼─────────────────────────────────────┐ +│ B. nixos-hardware profiles (via mkFlake hardwareProfile) │ +│ common-cpu-* · common-gpu-* · common-pc(-laptop|-ssd) · model │ +│ microcode · GPU media · fstrim · vendor/model quirks │ +└───────────────────────────────┬─────────────────────────────────────┘ + │ +┌───────────────────────────────▼─────────────────────────────────────┐ +│ C. nomarchy.hardware.* (modules/nixos/hardware.nix) │ +│ gap above commons: GuC · amd-pstate · VA-API env · fprintd · │ +│ IR-webcam hide · ROCm/NPU/latestKernel · I2C/DDC/CI │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +| Layer | Who turns it on | Where it lives | +|-------|-----------------|----------------| +| **A** | Distro defaults (`mkDefault`) | Any machine importing `nomarchy.nixosModules.nomarchy` | +| **B** | Installer DMI/`lspci` → `hardwareProfile = [ … ]` | Downstream `flake.nix` (`mkFlake`) | +| **C** | Installer probes → `system.nix`, or hand-edit | Downstream `system.nix` | + +`hardware-configuration.nix` (from `nixos-generate-config`) still owns +initrd modules, filesystems, and the usual generate-config flags. The +installer writes a real one; the template ships a placeholder you must +replace. + +Unknown `hardwareProfile` names **fail at eval** with Levenshtein +suggestions (`lib.nix`) — never silently ignored. + +## 2. What works without thinking about it + +These ship on every Nomarchy system unless you override them: + +| Capability | Default | Notes | +|------------|---------|--------| +| Wi‑Fi / BT firmware blobs | `hardware.enableRedistributableFirmware` | iwlwifi, ath, rtw, brcm, SOF, … | +| NetworkManager | on | Wi‑Fi UI: System › Network | +| PipeWire + WirePlumber | on | | +| Bluetooth + blueman | on | System › Bluetooth | +| power-profiles-daemon | on | Menu + Waybar; TLP via `nomarchy.system.power.backend = "tlp"` | +| External monitor brightness | `nomarchy.hardware.i2c.ddcci` **on** | DDC/CI → backlight devices | +| Firmware updates (LVFS) | `services.fwupd.enable` | **Never auto-flashes** — see §4 | +| SMART / UPower / pcscd (FIDO) | on | | +| earlyoom | on | Process-level OOM, not cgroup kill of the whole session | + +**Not** default-on (need detect or uncomment): fprintd, GuC/HuC, +amd-pstate, ROCm, NPU, thermald, charge limit, snapper (installer enables +snapper), `latestKernel`. + +## 3. Install path (best experience) + +`nomarchy-install` sources `pkgs/nomarchy-install/hardware-db.sh` and: + +1. Probes CPU vendor, GPUs (`lspci`), battery, SSD, fingerprint USB VIDs, + RGB+IR webcam names, NPU PCI class. +2. Looks up DMI `sys_vendor` × `product_name` in a ~60-entry model table + (Framework, Dell XPS/Latitude, ThinkPad, Surface, ASUS ROG, Apple T2, + System76). +3. Emits `MODULE …` lines → `hardwareProfile` list in `flake.nix`. +4. Emits `NOMARCHY hardware.*=…` → active + commented blocks in + `system.nix`. +5. Asks you to confirm profiles (or pick manually from the full + nixos-hardware attr list baked into the ISO). Override with + `NOMARCHY_HW=auto|none|"mod1 mod2"`. + +**Live ISO** is intentionally *generic* (no model profile): broad GPU +modules as *available*, redistributable firmware on, no baked +`nomarchy.hardware.*`. Tuning happens at install time. + +Out of scope for the installer today: aarch64 (Pi, Snapdragon X), Steam +Deck (Jovian), Apple Silicon (T2 Intel Macs only in the DB). + +## 4. Firmware updates (deep dive) + +### What we ship + +```nix +# modules/nixos/default.nix +services.fwupd.enable = lib.mkDefault true; +``` + +fwupd talks to the [LVFS](https://fwupd.org/): UEFI capsule (BIOS), some +SSDs, docks, Thunderbolt controllers, peripherals. It **only refreshes +metadata** on its own. Applying an update is always an explicit user +action. + +### What you do today (CLI) + +```sh +# After first boot (and occasionally later): +fwupdmgr refresh # optional; daemon often has metadata +fwupdmgr get-devices # what LVFS can see +fwupdmgr get-updates # pending +fwupdmgr update # apply (may need reboot / battery / AC) +``` + +Disable on VMs/headless: `services.fwupd.enable = false;` in `system.nix`. + +### Why this is under-discovered + +| Present | Missing | +|---------|---------| +| Daemon + package | Menu entry / Control Center | +| README one-liner | First-boot / MOTD hint | +| | Doctor check (“updates available”) | +| | Waybar / updates panel integration | + +**Product direction (queued):** System › Firmware (or a Doctor section) +that runs refresh → list → confirm → `fwupdmgr update`, plus a short +post-install note when `fwupd` is enabled. Never auto-flash; pillar 1 +(rock-stable) forbids silent BIOS writes. + +### Thunderbolt + +Firmware for TB devices may appear via LVFS. There is **no** first-class +`services.hardware.bolt` / security-level UI in Nomarchy — use plain +NixOS options if you need bolt. + +### Microcode / kernel firmware + +- **CPU microcode:** from nixos-hardware `common-cpu-*` and + `nixos-generate-config` once redistributable firmware is on — not a + separate `nomarchy.*` toggle. +- **GPU GuC/HuC (Intel i915):** `nomarchy.hardware.intel.guc` → + `i915.enable_guc=3`. Installer turns this **off** when the bound driver + is `xe` (GuC is default there; the param is ignored). +- **`hardware.enableAllFirmware`:** not set. Oddball non-redistributable + Wi‑Fi still needs a manual NixOS fix (or a broader policy decision). + +## 5. Fingerprint (deep dive) + +### Detect → enable + +Installer scans USB vendor IDs common to libfprint (Goodix, Synaptics, +Elan, …) via `lsusb` or `/sys/bus/usb/.../idVendor`. On hit: + +```nix +nomarchy.hardware.fingerprint.enable = true; # services.fprintd +# nomarchy.hardware.fingerprint.pam = true; # login + sudo (opt-in) +``` + +### Enroll (CLI today) + +```sh +fprintd-enroll # as your user +fprintd-list "$USER" +# then, if you want login/sudo: +# uncomment fingerprint.pam in system.nix → sys-rebuild +``` + +PAM stays opt-in on purpose: password-only remains the cautious default +until a finger is enrolled. + +### Gaps + +- No System menu “Fingerprint” row (enroll / list / delete). +- No “use for login” toggle that writes state + rebuild note. +- Doctor does not check reader presence or enroll status. + +**Product direction (queued):** when `fprintd` is active, a self-gated +menu module for enroll/list; optional PAM toggle via state + rebuild +hint (same pattern as Bluetooth in Control Center). + +## 6. NVIDIA (deep dive) + +### What happens at install + +``` +lspci → NVIDIA ⇒ MODULE common-gpu-nvidia +``` + +That is the **entire** Nomarchy surface. Unfree packages are allowed +(`allowUnfree = true` in the module and in `mkFlake`), so the proprietary +path from nixos-hardware can evaluate. + +There is **no** `nomarchy.hardware.nvidia.*` for: + +- hybrid / PRIME (Intel+NVIDIA, AMD+NVIDIA) +- open vs closed kernel module +- power management / udev / suspend quirks +- CUDA / container toolkit packages + +### What a hybrid laptop user must do today + +1. Confirm `common-gpu-nvidia` (and often `common-gpu-intel` or + `common-gpu-amd`) are in `hardwareProfile`. +2. Read the relevant nixos-hardware module and [NixOS NVIDIA wiki](https://wiki.nixos.org/wiki/Nvidia). +3. Add plain NixOS options in `system.nix`, for example (illustrative — + hardware-specific): + +```nix +# Example only — verify against your generation and nixos-hardware module. +# hardware.nvidia.prime = { ... }; +# hardware.nvidia.powerManagement.enable = true; +# hardware.nvidia.open = false; # or true for open modules on newer cards +``` + +4. Rebuild the system. Home Manager does not own the driver. + +### Live ISO note + +The ISO lists `nouveau` among *available* initrd modules and does **not** +force-load every GPU driver (avoids multi-driver panics). Proprietary +NVIDIA on the live session is not the product focus; installed systems +use the profile. + +**Product direction (queued):** when detection selects +`common-gpu-nvidia`, emit a **commented** `system.nix` block with PRIME / +power / open-module pointers (same pattern as ROCm / NPU comments), not +a full second NVIDIA stack unless a maintainer commits to testing. + +## 7. Day-2: “my laptop is mostly fine, make it fully fine” + +| Goal | How | Rebuild? | +|------|-----|----------| +| Power profile (perf/balanced/saver) | System menu / Waybar | No (PPD D-Bus) | +| Charge limit 80% | Menu / `settings.power.batteryChargeLimit` | System (sysfs apply is separate backlog) | +| Thermald (Intel) | Installer on for Intel laptops; else `power.thermal.enable` | System | +| Fingerprint enroll | `fprintd-enroll` | No | +| Fingerprint login | `fingerprint.pam = true` | System | +| ROCm / Intel compute | Uncomment opt-ins in `system.nix` | System (large) | +| NPU driver | Uncomment `npu` (+ often `latestKernel`) | System; userspace BYO | +| Newer kernel for brand-new silicon | `nomarchy.hardware.latestKernel = true` | System | +| Hide IR “dark camera” | Installer or `camera.hideIrSensor` | System | +| Firmware | `fwupdmgr update` | Reboot if capsule requires | +| Model quirks missing | Set better `hardwareProfile` (see §8) | System | +| OpenRGB / printing / Steam | `nomarchy.services.*` | System | + +Theme switches never touch drivers (Home Manager only). + +## 8. Unsupported or unlisted machines + +### Still good floor + +Even with **no** DMI hit you usually get: + +- `common-cpu-{intel,amd}` +- `common-gpu-{intel,amd,nvidia}` as applicable +- `common-pc` or `common-pc-laptop` + optional `common-pc-ssd` +- `nomarchy.hardware.intel` or `.amd` when vendor matches +- Layer A (firmware, audio, BT, PPD, fwupd) + +You **lose** model-specific EC/suspend/keyboard/audio quirks that only +exist in a named nixos-hardware module. + +### Pick a profile after install + +1. List candidates: + + ```sh + nix eval github:NixOS/nixos-hardware#nixosModules \ + --apply builtins.attrNames + # or: the ISO ships hardware-modules.txt for the same list + ``` + +2. Set in your flake (installer already uses a list): + + ```nix + hardwareProfile = [ + "common-cpu-amd" + "common-gpu-amd" + "common-pc-laptop" + "common-pc-ssd" + "lenovo-thinkpad-t14-amd-gen3" # if it matches + ]; + ``` + +3. `sudo nixos-rebuild switch --flake ~/.nomarchy#default` + +### Template / migration (no installer) + +See [MIGRATION.md](MIGRATION.md): reuse `hardware-configuration.nix`, set +`hardwareProfile`, uncomment `nomarchy.hardware` / power in `system.nix`. +There is **no** post-install re-probe helper yet (queued as +`nomarchy-detect-hw`). + +### Re-detect sketch (future) + +The installer’s `nomarchy_detect_hw` is already a pure probe (stdout +lines only). Exposing it as a package on PATH that prints suggested +`hardwareProfile` + `system.nix` snippets would close the template gap +without reinstalling. + +## 9. Adding your model to the distro + +For contributors (and power users who will PR): + +1. On the machine: + + ```sh + cat /sys/class/dmi/id/sys_vendor + cat /sys/class/dmi/id/product_name + ``` + +2. Find a matching attr in + [nixos-hardware](https://github.com/NixOS/nixos-hardware) (or add one + upstream first). + +3. Append to `pkgs/nomarchy-install/hardware-db.sh` in `HARDWARE_DB`: + + ```bash + "VendorRegex|Product regex|nixos-hardware-module-name" + ``` + + First match wins — put specific lines above broad fallbacks. + +4. Verify the name exists in the **pinned** nixos-hardware input + (`mkFlake` will throw if not). A CI check that every DB name ∈ + `nixosModules` is queued so lock bumps cannot silently break installs. + +5. Optional: note on-hardware QA steps in `agent/HARDWARE-QUEUE.md`. + +## 10. Doctor and hardware health (current vs target) + +**Today** (`nomarchy-doctor`): failed units, disk space, theme-state +validity/git, generation age, snapper timer. **No** Wi‑Fi, GPU, fwupd, +or fingerprint checks. + +**Target checks** (queued, all read-only, each failure prints one fix +command — same doctor contract): + +| Check | Pass condition | Suggested fix line | +|-------|----------------|--------------------| +| NetworkManager | device connected or wifi radio on | open System › Network | +| Audio sink | default sink exists | System › Audio | +| GPU accel | `glxinfo`/`vainfo` smoke (if installed) | check `hardwareProfile` / drivers | +| Fingerprint | if USB VID matched / fprintd unit | `fprintd-enroll` or enable option | +| fwupd | daemon active; optional “updates pending” warn | `fwupdmgr get-updates` | +| Battery threshold | if laptop + limit set, sysfs writable | power docs | + +## 11. Option quick reference + +Full tables: [README § options](../README.md). Hardware-shaped surface: + +| Option | Role | +|--------|------| +| `mkFlake.hardwareProfile` | nixos-hardware name or list | +| `nomarchy.hardware.intel.enable` / `.guc` / `.computeRuntime` | Intel gap layer | +| `nomarchy.hardware.amd.enable` / `.pstate` / `.vaapi` / `.rocm.*` | AMD gap layer | +| `nomarchy.hardware.fingerprint.enable` / `.pam` | fprintd + PAM | +| `nomarchy.hardware.npu.enable` | in-kernel NPU only | +| `nomarchy.hardware.latestKernel` | `linuxPackages_latest` | +| `nomarchy.hardware.camera.hideIrSensor` / `.irMatch` | dual-sensor webcams | +| `nomarchy.hardware.i2c.enable` / `.ddcci` | I2C + external backlight | +| `nomarchy.system.power.*` | PPD/TLP, laptop, thermald, charge limit | +| `nomarchy.system.bluetooth.enable` | BT stack | +| `services.fwupd.enable` | LVFS (native NixOS, default on) | + +## 12. Ease summary + +| Situation | Effort | +|-----------|--------| +| Known model in DB (Framework, many ThinkPads, …) | Low — install and go | +| Unknown modern Intel/AMD laptop | Low–medium — commons cover a lot | +| Firmware updates | Medium — CLI only until product work lands | +| Fingerprint for login | Medium — enroll CLI + PAM uncomment | +| Hybrid NVIDIA | High — plain NixOS/wiki territory | +| ROCm / NPU userspace | High — opt-in + expert | +| Contribute a new DMI line | Medium for someone who can PR | + +## 13. Related files + +| Path | Role | +|------|------| +| `modules/nixos/hardware.nix` | `nomarchy.hardware.*` | +| `modules/nixos/power.nix` | PPD/TLP, charge limit, thermald | +| `modules/nixos/default.nix` | firmware, fwupd, ddcci default | +| `pkgs/nomarchy-install/hardware-db.sh` | DMI DB + probes | +| `pkgs/nomarchy-install/nomarchy-install.sh` | writes flake + system.nix | +| `lib.nix` | `hardwareProfile` resolution | +| `templates/downstream/system.nix` | commented opt-ins | +| `agent/HARDWARE-QUEUE.md` | on-machine V3 checks | diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index e59f8ea..c94b1d8 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -117,6 +117,8 @@ cp /etc/nixos/hosts/TuringMachine/hardware-configuration.nix ./hardware-configur # Optional nixos-hardware profile(s) for your model. For an AMD laptop: # hardwareProfile = [ "common-cpu-amd-pstate" "common-gpu-amd" "common-pc-laptop-ssd" ]; # Names: https://github.com/NixOS/nixos-hardware (verify before use) + # Full hardware story (firmware, fingerprint, unsupported machines): + # docs/HARDWARE.md in the Nomarchy repo }; } ```