All checks were successful
Check / eval (push) Successful in 3m3s
Add a self-gated Firmware row to the System submenu (present whenever fwupdmgr is on PATH, i.e. services.fwupd.enable — default-on), its dispatch, and a `firmware` handler that opens a terminal and runs fwupdmgr refresh → get-updates → y/N confirm → fwupdmgr update. Never auto-flashes: fwupdmgr update confirms each device and prompts for the reboot a capsule needs (pillar 1 — no silent BIOS writes). HARDWARE.md §4 updated to "shipped". Verified V0 (nix flake check --no-build) + V1 (HM generation builds; generated nomarchy-menu passes bash -n; firmware handler emitted correctly). V2 (menu render in a session) queued in #43 and V3 (real LVFS flash) in HARDWARE-QUEUE — the VM was held by the #46 install test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
397 lines
16 KiB
Markdown
397 lines
16 KiB
Markdown
# 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 | First-boot / MOTD hint |
|
||
| README one-liner | Doctor check (“updates available”) |
|
||
| **System ▸ Firmware menu** (`nomarchy-menu firmware`) | Waybar / updates panel integration |
|
||
|
||
**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.
|
||
|
||
**Still queued:** a post-install / MOTD one-liner when `fwupd` is active,
|
||
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 (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 |
|