# 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:** [`agent/BACKLOG.md`](../agent/BACKLOG.md) (PROPOSED › Hardware > product). Product framing: [`VISION.md`](VISION.md) § A. Design history: > [`ROADMAP.md`](ROADMAP.md). Docs map: [`README.md`](README.md). > Migration: [`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 | Doctor check (“updates available”) | | README one-liner | Waybar / updates panel integration | | **System ▸ Firmware menu** (`nomarchy-menu firmware`) | | | MOTD + first-boot tip (#43) | | **System ▸ Firmware** (shipped): a self-gated System-submenu row (present whenever `fwupdmgr` is on PATH, i.e. `services.fwupd.enable`, default-on) that opens a terminal and runs `fwupdmgr refresh` → `get-updates` → confirm → `fwupdmgr update`. It never auto-flashes — `fwupdmgr update` confirms each device and prompts for the reboot a capsule needs; pillar 1 (rock-stable) forbids silent BIOS writes. **Hints (#43 / #73):** MOTD cheat-sheet line + `nomarchy-control-center --first-boot` tip when `fwupdmgr` is on PATH. Fingerprint / doctor tips follow the same pattern (fingerprint MOTD only when `nomarchy.hardware.fingerprint.enable`). **Still queued:** a Doctor “updates available” check, and Waybar/updates-panel integration. ### 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 (menu or CLI) **Shipped #55:** System › Fingerprint (self-gated when `fprintd-list` is on PATH) — Enroll / List / Verify / Delete all, plus **Use for login** which writes `settings.fingerprint.pam` and applies on the next `sys-rebuild` (option default follows theme-state.json). **Hints (#73):** MOTD line when `fingerprint.enable` is on; first-boot tip when `fprintd-list` is on PATH (`SUPER+M → System › Fingerprint` / `fprintd-enroll`). No permanent nag without a reader. ```sh # CLI still works: fprintd-enroll fprintd-list "$USER" # or: System › Fingerprint › Use for login (on) → sys-rebuild ``` PAM stays opt-in on purpose: password-only remains the cautious default until a finger is enrolled. Full enroll on a real reader is V3/hardware. ### Doctor `nomarchy-doctor` reports fprintd unit + enroll status when present. ## 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 (shipped #59; first-class wrappers deferred for v1):** when `common-gpu-nvidia` is in `hardwareProfile`, the installer emits a **commented** `system.nix` block with PRIME / power / open-module pointers (same pattern as ROCm / NPU comments). No `nomarchy.hardware.nvidia.*` stack for v1 — hybrid PRIME remains wiki/plain NixOS until a maintainer commits to hardware 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 / CC — live sysfs + state; boot oneshot re-applies | No rebuild for live; rebuild bakes Nix option | | 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 | ### Dual-sensor webcam / IR hide Many dual-sensor modules (e.g. ThinkPad T14s) expose colour + IR as two identically named “Integrated Camera” nodes. Picking the IR node yields a black/dark greyscale frame — the classic “my webcam is dark” symptom. `nomarchy.hardware.camera.hideIrSensor` (installer-on when RGB+IR names are detected; overridable `irMatch`) drops the IR node from **WirePlumber’s v4l2 monitor** so native PipeWire pickers only offer the colour camera. The kernel `/dev/video*` node stays open, so Howdy-style face unlock still works. Design history: [ROADMAP § Webcam](ROADMAP.md). **What it does not cover:** apps that list cameras via **libcamera** or the **xdg-desktop-portal** / **Flatpak** camera path still see both sensors — a Flatpak Zoom (or similar) user can still pick the black IR “camera”. That is intentional: a blanket libcamera disable would risk external USB cams that need the libcamera path, and surgical internal-only libcamera rules could not match early enough (only `device.api` binds before the WirePlumber monitor rule). **Workaround:** prefer the colour device in the picker (or any non-IR name). Apps that default to the first v4l2 colour source without a picker are fine. **Further engineering (needs T14s-class hardware):** (b) a WirePlumber *libcamera* monitor rule disabling GREY-only nodes; (c) a libcamera/udev quirk at the libcamera layer. Neither is implemented — the recommended path is document-only until those can be verified on real dual-sensor hardware (see `agent/HARDWARE-QUEUE.md` › T14s). 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`. Post-install re-probe (**shipped #58**): ```sh nomarchy-detect-hw # human report + suggested snippets nomarchy-detect-hw --raw # MODULE / NOMARCHY / DETAIL protocol lines ``` Prints suggested `hardwareProfile` and `system.nix` lines; **does not** rewrite the flake. Paste after review, then `sudo nixos-rebuild switch`. ## 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 (v4l2 only; §7) | | `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 |