Files
Nomarchy/agent/BACKLOG.md
Bernardo Magri a504f35b41
Some checks failed
Check / eval (push) Has been cancelled
feat(waybar): #63 generated bar logo + powermenu
Add custom/nomarchy (left, Nomarchy monogram → nomarchy-menu) and
custom/powermenu (right → nomarchy-menu power) to the generated bar so
default-theme users match whole-swap affordances. Pin font-family:
Nomarchy; use literal UTF-8 glyphs (Nix has no \u escapes).

Verified: V2 (THEME=tokyo-night theme-shot — monogram + power glyph).
Close #63.
2026-07-10 08:38:45 +01:00

29 KiB
Raw Blame History

Backlog — the prioritized task queue

This is the only executable work list for agents. Product themes and v1.0 intent live in docs/VISION.md; design history in docs/ROADMAP.md; map in docs/README.md and agent/README.md.

Rules:

  • Agents take the topmost actionable item (see LOOP.md). Finished items are deleted here — the journal + git log are the record; durable design notes get a ✓-entry in docs/ROADMAP.md (and/or a note in VISION) if worth keeping.
  • Item numbers are stable IDs — never renumbered or reused. A gap in the sequence means shipped (or dropped) work; new items take the next free number regardless of tier.
  • Tags: [blocked:hw] needs real hardware (see HARDWARE-QUEUE.md) · [human] needs Bernardo · [stuck] two failed attempts, needs help · [big] must be split before starting.
  • Agents may append to PROPOSED and Decisions freely (include VISION § … or ROADMAP § … when relevant); only Bernardo moves items out of PROPOSED into the tiers.

NOW

(empty — NEXT's top item is the queue head)

NEXT

14. Automated lock bumps — confirm the first real run

Slices b+c shipped 2026-07-05 (.gitea/workflows/bump.yml): weekly schedule (Mon 05:17 UTC) + workflow_dispatch as the security fast-lane; nix flake update → eval gate → pathspec-limited lock commit pushed to main on green (that push triggers check.yml as the second net). Update/commit/push logic simulated locally end-to-end in a scratch clone, incl. a real update; today's bumped lock evals green. Remaining (not confirmable from a session): the first scheduled or dispatched run must land — watch that the runner picks up the cron and that the Actions token can push. Then delete this item. Item 20's KVM runner later upgrades the gate from eval-only to the VM suite.

20. KVM runner → VM suite in CI [human]

The remaining stretch of the CI item — checks-on-push is live and green (run #58; runner = gitea/act_runner docker, eval tier). Register a second runner on a host with /dev/kvm + nix (host-mode label nix-kvm), then an agent uncomments the workflow's vm-checks job: the checks.* VM suite + real toplevel/HM builds on every push that later upgrades item 14's bump gate from eval-only to the full suite.

41. Floating-window audit — remaining (needs hardware class checks)

(Raised by Bernardo, 2026-07-07 — item 11.) Broaden the windowrule float set beyond the conservative first cut. Conservative cut shipped 2026-07-07 (iteration #63, on Bernardo's "take a conservative approach"): float + center the mixer (item 35), blueman (manager/adapters) and system-config-printer — the only shipped, unambiguous config dialogs whose classes are confident. Remaining candidates, deliberately deferred because their window class can't be verified headlessly (a guessed class = dead rule): the polkit auth prompt (hyprpolkitagent — no discoverable class in the package), GTK file-chooser portals (xdg-desktop-portal-gtk), and any pinentry dialog. Next slice: on hardware, run hyprctl clients while each is open, read the real class, then append rules. Also revisit whether blueman/s-c-p actually float once seen (regex tolerance for the .…-wrapped form).

55. Fingerprint menu: enroll / list (+ optional PAM toggle)

VISION § A / HARDWARE.md §5. 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). Full enroll path is [blocked:hw] / V3; menu surface + self-gate + dry paths are V1V2.

56. Human rebuild errors

VISION § A. On failed sys-rebuild / HM switch, point the user at the last log lines + nomarchy-doctor instead of a raw Nix wall. Likely home: menu rebuild wrapper and/or control-center path. Cost: medium pkgs/menu; V1 + V2 smoke of the failure path (can force a bad eval).

57. Live: one always-visible “Install Nomarchy” action

Install is only in: 3s notify-send toast, getty helpLine, and tribal knowledge of nomarchy-install. One durable surface on the live host only: e.g. xdg.desktopEntries (Terminal=true) or a single Tools/System menu item that opens a terminal into nomarchy-install. Prefer that over more install-time questions. Also fix stale hosts/live.nix header (“No installer yet”) if still present. Cost: live.nix only; V1 ISO rebuild + V2 smoke.

58. nomarchy-detect-hw CLI (post-install re-probe)

HARDWARE.md §8. 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 WiFi card.” Does not rewrite the flake unless a later --apply is explicitly designed. Cost: extract script + package + man/README pointer; V0V1.

LATER

  • Wallpapers artifact split (ROADMAP § Faster switches — decided, deferred): pinned Nomarchy-wallpapers input so a state write stops re-copying 86 MB. Follow-on: pre-built theme variants if switches are still slow after.
  • Installer round 2 (ROADMAP § Installer): multi-disk BTRFS RAID, impermanence, BIOS/legacy boot.
  • Boot-from-snapshot: a systemd-boot equivalent of grub-btrfs.
  • Night-light geo mode: lat/long auto sunset/sunrise (means wlsunset).
  • Per-theme icon overrides / more icon packs (ROADMAP § Icon themes).
  • MIPI/IPU software-ISP camera support (no-UVC machines).
  • VPN exit-node richer display (country/city) (optional).
  • NixOS release bump → v2 [human]: deliberate, hand-edited, never automated; the previous attempt was discarded (2026-06-22) over a Hyprland OOM blocker — see MEMORY.md before retrying (NOW#3 should also soften that blocker class).

PROPOSED (agent suggestions — await human triage)

Agents: append here with a one-paragraph pitch (what/why/cost). Do not implement. Bernardo moves accepted items into a tier.

v1.0 track — see docs/VISION.md

Product themes and the release bar live in VISION. Shipped 2026-07-09: #42 boreal default · #43 Firmware menu · #44 doctor hardware · neon-glass quarantine (#53). Promoted 2026-07-10 → NEXT #55#63 (A fingerprint / human rebuild / live install · B detect-hw / NVIDIA comments / BAT* · C review source line / whole-swap CSS CI / generated bar affordances). Still PROPOSED for later triage: first-boot tips (partially shipped via #43 MOTD), charge-limit instant apply, theme taste polish.

Pre-existing

  • Battery charge-limit — make the toggle instant [blocked:hw] (follow-up to the preset toggle shipped 2026-07-07, iteration #55). The control-center now has a proper toggle (Off / 80% / 90% / 60% / Custom…) writing settings.power.batteryChargeLimit — but that's a baked NixOS option, so it only lands on the next sys-rebuild. To make it instant (no rebuild): add a udev rule making system-battery charge_control_end_threshold nodes group-writable (MODE/GROUP) so the menu can echo N > it live alongside persisting state (the sysfs oneshot in power.nix still owns boot + AC-replug re-apply), and/or surface a rofi-menu quick row or a Waybar action. [blocked:hw]: the sysfs write + no-rebuild effect can only be confirmed on a laptop exposing the threshold. Decide first whether the small privilege grant (a local user can set the charge cap) is acceptable.

  • Portal/Flatpak camera picker still lists the internal IR sensor (ROADMAP § Webcam follow-up). The shipped IR-hide is a WirePlumber v4l2 rule, but Flatpak/portal apps consume cameras via the libcamera path, where both sensors remain visible — a Flatpak Zoom user can still pick the black IR "camera". Options, roughly ascending cost: (a) do nothing — document it (portal camera support is still rare in practice); (b) a WirePlumber libcamera monitor rule disabling GREY-only nodes — needs verifying that libcamera monitor rules can match early enough (the v4l2 investigation found only device.api binds pre-rule, which is why surgical scoping failed before — same wall likely applies); (c) a libcamera configuration/udev quirk hiding the IR sensor at the libcamera layer itself. Cost: (b)/(c) need a T14s-style RGB+IR machine to verify → pairs with a hardware-queue session. Recommend (a) now, (b) investigated when the T14s is next available.

Bugs / broken behavior (codebase exam 2026-07-09)

(Waybar doctor indicator, Control Center appearance no-ops, summer-day scroll → #51; neon-glass broken waybar → fixed 2026-07-09 by quarantine (removed waybar.css → generated bar; render-confirmed).) (Battery charge-limit / powerprofile BAT*-only → #60 ✓ 2026-07-10; V3 pending on non-BAT* hardware.)

Docs / option-surface drift (codebase exam 2026-07-09)

(i2c option-docs → #48; README/docs drift pack, keybind nmtui label, nomarchy-menu usage string, secondary docs, always-on pieces → #47.)

  • Template / seed state drift (residual after SoT work) (1) templates/downstream/theme-state.json lacks border and settings keys present in repo root state (eval merges defaults); (2) no commented nomarchy.system.snapper.enable or hardware.i2c.* in template system.nix despite opt-in convention. Main home/system sync is Installer consumes template as SoT below — do that first, then close these residual gaps on the template itself. Cost: small template polish.

  • Installer ↔ template SoT — follow-ups (shipped 2026-07-09: copy + patch-template.py). Remaining: (1) optional CI that the install share ships the same template files; (2) V2 test-install.sh after ISO rebuild (HM pre-activate now pulls starter packages — larger closure); (3) residual theme-state / i2c comment polish on template (see residual seed drift item).

Theme polish / completeness (codebase exam 2026-07-09)

  • theme preview recapture nicety (all 24 themes now have preview.png as of 2026-07-09 — executive-slate + neon-glass captured via theme-shot). These headless captures are a clean bare desktop+bar, not the theme-shot capture — a clean bare desktop+bar, not the floating-terminal (fastfetch+btop) composition the other 21 use; a real-hardware recapture to match the grid would be nicer (VM is the documented fallback). Optional hand btop.theme for the three identity themes still open. Cost: asset capture; V3 visual.

(Generated Waybar missing identity-bar affordances → #63.)

  • summer- CSS under-styles status module states* summer-day/night include modules in selectors but largely lack .on / .available / .recording polish that boreal, executive-slate, and the generated style have. Functional OK; visual hierarchy weak. Cost: CSS pass; V3.

(Optional CI: whole-swap CSS self-containment → #62 ✓ 2026-07-10.)

Per-theme design audit (2026-07-09)

Method: checks.theme-contrast (all 24×7 pairings pass) + tools/audit-theme-design.py + per-theme agent review of JSON roles, ANSI, assets, whole-swaps, and fidelity to canonical sources. Gated WCAG floors are green; items below are fidelity, hierarchy, btop drift, identity semantics, and polish. Identity themes (white, vantablack, lumon, hackerman, matte-black, miasma, neon-glass) are flagged separately from fidelity bugs.

Broken / high-ROI fixes

→ promoted as NEXT #52 (2026-07-09); the six bullets below are its spec (exact hexes). The rest of the per-theme audit stays PROPOSED.

Residual ANSI drift exposed by the #52 fixes (not yet touched — small follow-up): vantablack ansi[8] (bright-black) still #fdfdfd, now diverging from the new muted #666666; osaka-jade ansi[3] (normal-yellow) still the old warn-green #459451 while warn/ansi[11] are now #E5C736. Decide per theme whether these are identity or bugs.

  • rose-pine btop is Main-on-Dawn (near-invisible hi_fg) JSON is Rosé Pine Dawn (mode: light, base #faf4ed, text #575279) but themes/rose-pine/btop.theme mixes Dawn main_bg/main_fg with Main accents: hi_fg=#e0def4 on #faf4ed ≈ invisible, selected_bg=#524f67, love #eb6f92, foam/iris Main hexes. Fix: rewrite btop entirely to Dawn roles (foam #56949f, iris #907aa9, love #b4637a, gold #ea9d34/#d68a16, pine #286983). Also rename display name to "Rosé Pine Dawn" (or ship a dark Main preset as a separate slug). Cost: one btop rewrite + optional rename; V1 + visual V2.

  • everforest + summer-night btop: inactive_fg == main_bg themes/everforest/btop.theme and themes/summer-night/btop.theme set inactive_fg to #2d353b (= main_bg) → inactive/disabled labels invisible. Fix: inactive_fg → grey1/muted range (#859289 / #7a8478 / JSON muted). Cost: two lines; V1.

  • vantablack role inversion breaks selection / muted overlay and muted are near-white #fdfdfd while base is #0d0d0d. Generated consumers use overlay as selected_bg; hand btop has selected_bg=#fdfdfd + selected_fg=#ffffff (white-on-white) and inactive_fg=#fdfdfd (inactive rows scream). Status greys are intentional monochrome identity. Fix (keep void identity): surface #1a1a1a, overlay #2a2a2a, muted #666666; btop selected_bg #333 / selected_fg #fff / inactive_fg ≈ muted. Cost: JSON + btop; re-run contrast; V1V2.

  • osaka-jade: warn≈good and text/subtext inverted warn #459451 is green (same family as good #549e6a) → battery warning reads as "ok". subtext #F6F5DD is brighter than text #C1C497 (secondary louder than primary). Fix: swap text↔subtext; set warn #E5C736 (from bright yellow ANSI, already in palette). Keep jade accent + blossom accentAlt. Cost: small JSON retune; contrast re-check; V1.

  • catppuccin-latte: ANSI black/white axis inverted + mantle sludge Latte UI roles mostly match (base/text/accent/good/bad exact), but ansi[0]=#bcc0cc (light) and ansi[7]/[15] are darkish → terminal "black"/"white" slots misbehave; design-audit flags inverted slots. mantle #cbcdd0 is import-darken of light base (should be Latte mantle #e6e9ef); accentAlt #d260b5 is not Latte pink/mauve. Fix:

    mantle #e6e9ef; accentAlt #ea76cb (pink);
    ansi[0] #5c5f77; ansi[7] #acb0be; ansi[8] #6c6f85; ansi[15] #bcc0cc
    

    warn keep #d6860a if contrast requires, else #df8e1d. Cost: JSON only; btop already Latte-correct. V0 contrast + V1.

  • catppuccin (Mocha) btop is Frappé-on-Mocha JSON is exact Mocha; btop.theme uses Mocha main_bg but Frappé fgs/boxes (main_fg #c6d0f5, hi_fg #8caaee, mauve/green/maroon Frappé hexes). Fix: replace with official Mocha btop hexes (#cdd6f4, #89b4fa, …). Optional: rename to "Catppuccin Mocha". Cost: btop rewrite; V1.

Whole-swap / identity themes

  • neon-glass — already queued above (broken waybar.css). JSON palette itself is fine (high-chroma cyber). Finish or quarantine.

  • summer-day / summer-night pair polish Structurally paired (inverted Everforest bar language) but: (1) waybar CSS hexes drift from JSON (day warn/accentAlt; night red/blue/yellow/purple vs JSON); bar follows legacy EF source, Stylix/swaync follow JSON — dual sources of truth; (2) night JSON collapses subtext=muted=overlay #868d80 (no secondary ladder for generated surfaces); (3) day font 16px vs night 13px; day battery thresholds 30/15 vs night 25/10; day missing #custom-vpn in pill selectors; (4) day scroll e±1 already queued. Fix: pick JSON as source of truth and map waybar tokens to it (or document intentional EF split); split night muted darker / subtext lighter; align font + battery thresholds + VPN pill. Cost: CSS/JSON polish pass; V3.

  • boreal / executive-slate — whole-swaps self-define colors and match JSON; best-in-class. Only gaps: preview.png + optional btop.theme (already queued).

  • white (monochrome light) — identity-ok. Status good/warn/bad are greys by design (audit hue/CVD noise expected). Optional: widen L steps (good #555, warn #777, bad #222), raise surface #f0f0f0, split subtext #404040 while staying hueless. Do not inject traffic-light hues. Cost: optional taste retune.

  • lumon (Severance blue mono-status) — identity-ok. good/warn/bad all blue family by design; CVD collapse expected — rely on glyph/shape (item 28). Optional: dim subtext one step (#9bb0c0); increase L separation only among blues. Cost: optional; document as identity exemption in audit tooling.

  • hackerman — matrix identity: warn cyan, bad green, ANSI reds are greens. CVD collapse expected. Keep identity or optional cyber-semantic UI only: warn #e8d44f, bad #ff5a7a while leaving ANSI matrix. Raise surface #1a1c2e (flat base=surface). Cost: product call + small JSON.

  • matte-black — identity: good=#FFC107 amber, warn=#b91c1c red (inverted traffic-light). Matches Omarchy matte-black. Minimal fix: subtext #9a9a9d (text==subtext today). Full semantic remap only if product wants conventional battery colors on this theme. Cost: one-line hierarchy or deliberate status retune.

  • miasma — earthy bad #685742 (brown, contrast ~2.3 audit-only) is JOURNAL-exempt identity. Optional more readable brown-red #8b5a4a / #a65d4e without leaving the forest. Cost: optional.

  • gruvbox is Material medium, not classic — name + btop split JSON hexes are Gruvbox Material (text #d4be98, material green/yellow/red) while name says "Gruvbox" and btop.theme is classic (#ebdbb2, #d79921, …). surface=overlay, text=subtext. Fix: rename to "Gruvbox Material" or retune JSON to classic; sync btop to the chosen lineage; overlay #504945, subtext #a89984. Cost: naming + assets.

  • nord — clean Polar Night. Only nit: subtext #e5e9f0 is brighter than text #d8dee9 (hierarchy inverted). Fix: subtext → nord4-dim or bump text to nord6 #eceff4. Cost: one hex.

  • tokyo-night — Night (not Storm), JSON solid. btop main_fg/title use warm #cfc9c2 instead of Night #c0caf5/#a9b1d6. Optional: text #c0caf5, accentAlt #bb9af7 (modern purple). Cost: btop + optional JSON.

  • kanagawa — Wave, clean. No action required; optional rename "Kanagawa Wave"; optional brighter good springGreen #98bb6c.

  • ethereal — vibe solid; surface=base, muted=overlay. Fix: surface #1a2340 (or Omarchy color0 #3C486D); split muted darker than overlay; optional richer good. Cost: small JSON.

  • retro-82 — strong synthwave + excellent rofi whole-swap. surface #00172e darker than base #05182e (inverted raise); good #028391 teal (reads info not ok). Fix: surface #0a2844; optional good #3f8f8a or phosphor green. Cost: small JSON; keep rofi.

  • ristretto — Monokai Pro Ristretto, ship-quality. Only subtext=text; btop main_bg 1-step drift (#2c2421 vs #2c2525). Fix: subtext #b5a9aa; align btop bg. Cost: tiny.

  • flexoki-light — best of the Flexoki/import set post item-28. Optional: distinct ANSI bright-black #575653; recapture preview if terminal chrome still looks dark-on-paper. Cost: polish only.

Systemic theme tooling

  • Import pipeline collapses hierarchy when ANSI 0==8 tools/import-palettes.py maps surface←color0, overlay←color8, good/warn/bad←color2/3/1, mantle←darken(base). When color0==8 (gruvbox, everforest) surface=overlay; light themes get sludge mantle. Long-term: allow explicit role overrides independent of ANSI for identity themes; don't re-import without a hierarchy pass. Cost: tool + convention doc.

  • audit-theme-design identity exemptions Document expected noise for white/vantablack/lumon/hackerman/ matte-black/miasma (hue-family + CVD) so future audits don't "fix" identity into traffic lights. Optional: special-case in the report script. Cost: docs or small script tweak.

Tooling / CI / installer hardening (codebase exam 2026-07-09)

(py_compile expand, installer pure contracts, hardware-db ∈ nixos-hardware, windowrule dead-syntax guard → #49.)

  • Installer soft gaps (1) fingerprint path prefers lsusb but package PATH has pciutils not usbutils (sysfs fallback usually OK); (2) chown -R 1000:100 on the flake dir assumes first-user UID/GID; (3) flake packages exports only theme-sync + install, not doctor / control-center / battery-notify (runtime via overlay is fine — discoverability only). Cost: small each.

(Control Center /tmp/nomarchy-gens → mktemp → #50.)

Distro improvement ideas (codebase exam 2026-07-09)

  • Fail-closed / friendlier theme-state errors in mkFlake Missing theme-state.json fails later at readFile; invalid JSON fails at fromJSON before theme.nix's field-level validator. A friendly "add theme-state.json" / schema pointer would help downstream authors. Related: settings.displayProfile* not in defaults block (consumers use or); unknown border role falls through to raw string. Cost: medium lib/theme.nix UX.

  • Look & Feel submenu (ROADMAP optional) Night-light, wallpaper cycle, blur/gaps (once CC appearance is fixed) grouped with Theme once the root stays six entries. Cost: menu structure only; product call.

(Export overlay tools as flake packages → #50.)

  • Unattended-install test matrix test-install.sh always LUKS+swap; add (or document) no-swap and no-LUKS paths once those contracts are fixed, so swap/LUKS-class bugs cannot recur. Cost: script flags + time on KVM host.

(Document always-on home pieces (easyeffects/udiskie/cliphist) → #47.)

Hardware product (investigation 2026-07-09)

Full write-up: 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).

(nomarchy-detect-hw CLI → #58; Fingerprint menu → #55; Installer NVIDIA commented guidance → #59 ✓ 2026-07-10.)

(hardware-db ∈ nixos-hardware → #49; usbutils on install PATH → #50; i2c README table → #48.)

  • 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. (Partial: #43 shipped Firmware MOTD/tip 2026-07-09; fingerprint + doctor lines still open.)

  • NVIDIA first-class options (larger, optional) Only if a maintainer commits to hybrid testing: thin nomarchy.hardware.nvidia.* wrapping common PRIME/power patterns. Prefer NEXT #59 (commented guidance) first; promote only with hardware-queue coverage. Cost: high; [big] + [blocked:hw].

Installer process (audit 2026-07-09)

Full-path review of live ISO → nomarchy-install → disko → config generation → offline/online nixos-install → HM pre-activate → first boot. Philosophy applied: opinionated, stability-first — prefer safer defaults and fewer install questions over option sprawl. Day-2 firmware / fingerprint / re-detect stay in Hardware product above, not in the installer questionnaire.

Already strong (do not “fix” with more choices)

  • Single whole-disk GPT, UEFI + systemd-boot only; multi-disk RAID / dual-boot / BIOS deferred (ROADMAP LATER).
  • LUKS2 default + greeter auto-login (one gate); type-to-confirm wipe; live medium excluded from disk list; careful pre-wipe.
  • BTRFS subvols + snapper on by default; hibernation swap default = RAM; hardware autodetection with safe defaults on, heavy bits commented.
  • Offline-capable install (compose-lock, ISO store pin, daemon substituter); HM pre-activate so first boot is themed.
  • No Secure Boot theater; no install-time app-suite wizard / custom partitioner / pbkdf knobs. (Starter apps come from the template home.packages once the installer consumes the template as SoT — see above; not a separate install questionnaire.)
  • Live: no idle suspend (avoids mid-install sleep); WiFi via normal desktop NM path.

Bugs (stability contracts — fix, dont optionalize)

  • Installer swap=0 + unattended LUKS fail-closed — ✓ shipped (workflow test run 2026-07-09): pass bare "0"; disko accepts "0"/"0G"; unattended needs passphrase or NOMARCHY_NO_LUKS=1.

(Offline fail-closed → #54.)

Safety / clarity (one line each — no new install menus)

(Review-panel destructive-data warning → #54.)

(Review panel: offline vs online source line → #61 ✓ 2026-07-10.)

(User password minimum length = 8 → #54.)

Live ISO discoverability (one durable cue)

(Live: one always-visible “Install Nomarchy” action → #57.)

Generated config / post-install polish

(HM pre-activate failure → durable recovery hint → #54.)

  • MIGRATION.md: installer snapshot layout vs @home-snapshots Installer creates disko @snapshots/.snapshots and a first-boot oneshot for nested /home/.snapshots. MIGRATION still speaks of top-level @home-snapshots (TuringMachine vocabulary). One paragraph clarifying installer layout vs migration machines prevents wrong expectations. Cost: docs only.

Test / pure contracts (after P0 bugs)

  • Installer pure checks + expanded unattended matrix — overlaps existing Tooling items (disko swapSize contract, compose-lock py_compile, hardware-db ∈ nixos-hardware). After swap/LUKS fixes: document or script unattended no-swap and explicit no-LUKS paths in test-install.sh (env flags only — no interactive options). Do not grow the interactive installer questionnaire.

Explicit non-goals for the installer (defer)

Do not add install-time: dual-boot / preserve partitions, multi-disk RAID, Secure Boot/lanzaboote, recovery-key wizard (optional silent recovery print is the only recovery-key idea worth considering later), custom partitioner, online/offline user toggle, app suite selection, pbkdf/TRIM knobs, or a second installer frontend. Stability and the single golden path win.

Decisions [human]

Open calls only Bernardo can make; agents add options/evidence but never decide.

  • Formatter adoption: repo deliberately has none; nixfmt-rfc-style would flatten the aligned hand-formatting of ~33 files. Adopt or declare never?

  • Docs site vs Markdown-in-repo (from the docs-review item).

  • zram swap: faster under pressure and pairs with NOW#3, but it interacts with the hibernation-swapfile story (resume device/priority ordering) — adopt, adopt-with-hibernation-guard, or skip?

  • Default browser: the template comments Firefox out. The shipped mime defaults (item 8, done) point text/html/http(s) at firefox.desktop as inert entries — they activate the moment Firefox is installed and are skipped otherwise, so the remaining call is only: ship a browser active in the suite, or stay browserless-by-default?

  • Default power backend — PPD vs TLP: (raised by Bernardo 2026-07-08: would TLP be more power-efficient, and should it be the default?) TLP does get more idle battery life, but only from device-level knobs PPD deliberately omits — PCIe ASPM, disk/NVMe link PM, USB autosuspend, runtime PM — which are the same knobs behind NVMe/USB flakiness that pillar 1 (rock-stable, never fight your machine) guards against. Evidence (2026-07-08): no credible hard-watt benchmarks exist — TLP's own maintainer declines to quote any ("measure on your hardware") and says PPD's power-saver gives similar savings under load; TLP's edge is idle-only (linrunner.de/tlp/faq/ppd.html — PPD covers a subset of TLP, "no settings to reduce consumption when the CPU is idle"). Our sibling distro Omarchy ran this exact experiment — a "replace Power Profiles with TLP for battery" guide — and the author reverted to PPD ("more headaches and weird issues"); Omarchy shipped PPD auto-switching instead (basecamp/omarchy#3907). PPD 3.4.0 now does AC/battery auto-switching, closing part of TLP's UX gap. Cost of TLP-default: TLP has no live D-Bus profile API, so the powermgmt menu + Waybar profile indicator + low-battery auto power-saver (all powerprofilesctl) would need a rework — it's not a one-line backend swap. Agent rec (evidence, not a decision): keep PPD default; chase battery via targeted low-risk tweaks (PCIe ASPM policy, battery-side EPP, the charge start threshold, PPD auto-switching) and keep TLP the documented one-line opt-in it already is (nomarchy.system.power.backend = "tlp"). Options: (i) status quo + targeted tweaks [rec]; (ii) TLP default (reworks the profile UX); (iii) nothing.