All checks were successful
Check / eval (push) Successful in 3m44s
Acer M5-481T fails Ghostty because Ivy Bridge HD 4000 tops out at OpenGL 4.2 in Mesa; Ghostty needs 4.3 — a generation ceiling, not a missing driver. Document that plus UEFI/x86_64, RAM, and storage floors (Nix store generations + BTRFS snapper + hibernate swap≈RAM). Linked from README, docs map, HARDWARE.md; #95 points here.
639 lines
34 KiB
Markdown
639 lines
34 KiB
Markdown
# 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`](../docs/VISION.md); design history
|
||
in [`docs/ROADMAP.md`](../docs/ROADMAP.md); map in
|
||
[`docs/README.md`](../docs/README.md) and [`agent/README.md`](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
|
||
|
||
### Live ISO / install hardware findings — Acer Aspire M5-481T + Dell XPS 9350
|
||
|
||
Bernardo, real installs 2026-07-13–14 (photos of the install end screens and
|
||
post-boot sessions). Preserve separation: the installer bake failure, the
|
||
flake pin, and the Ghostty GL floor are different root causes even when they
|
||
show up on the same machine.
|
||
|
||
### 123. Installer HM pre-activate aborts on dconf / missing XDG_RUNTIME_DIR
|
||
|
||
**Seen on both machines** (Dell XPS 9350 and Acer M5-481T), same log shape at
|
||
the end of `nomarchy-install` after "✓ System installed":
|
||
|
||
```
|
||
— Baking the desktop —
|
||
Building the desktop generation...
|
||
▲ Desktop pre-activation failed (see /var/log/nomarchy-hm-preactivate.log
|
||
on the installed system); after first login run:
|
||
home-manager switch --flake ~/.nomarchy -b bak
|
||
Activating dconfSettings
|
||
dconf-CRITICAL **: Unable to create directory '/run/user/1001/dconf':
|
||
Permission denied. dconf will not work properly.
|
||
error: Could not connect: No such file or directory
|
||
```
|
||
|
||
Install still reports success and offers reboot — so first boot lands on a
|
||
**partial** Home Manager activation. That matches the post-boot pain Bernardo
|
||
had to fix by hand on both boxes: **GTK theme looking wrong** (Stylix/dconf
|
||
color-scheme never landed) and **missing nm-applet tray icon**
|
||
(`services.network-manager-applet` is on in `modules/home/default.nix`, but
|
||
only after a complete HM generation/activation). Do **not** file those as
|
||
separate product bugs until this bake succeeds; re-check them as acceptance
|
||
criteria of the fix.
|
||
|
||
**Root cause (code path):** `pkgs/nomarchy-install/nomarchy-install.sh`
|
||
"Baking the desktop" runs `$out/activate` via `runuser` inside `nixos-enter`.
|
||
There is no user session: `/run/user/$UID` is missing or unwritable, so the
|
||
dconf activation step dies and the scripted activate aborts mid-way. #83
|
||
already surfaces the recovery one-liner; the *bake itself* is what is broken.
|
||
|
||
**Fix direction:** before `runuser … activate`, create a private runtime dir
|
||
the target user owns (`mkdir -p /run/user/$UID && chown`, export
|
||
`XDG_RUNTIME_DIR`), and/or give activate a session bus if dconf still needs
|
||
one. Prefer making pre-activate succeed over papering over dconf. Keep the
|
||
existing failure hint for genuine failures.
|
||
|
||
**Pass:** a `tools/test-install.sh` (or equivalent) run ends with
|
||
"Desktop pre-activated — first boot is fully themed", **not** the dconf
|
||
CRITICAL; `/var/log/nomarchy-hm-preactivate.log` is absent or clean; first
|
||
graphical login has Stylix GTK theming + nm-applet in the tray **without** a
|
||
manual `home-manager switch`. V3: same on at least one of the two boxes that
|
||
regressed (HARDWARE-QUEUE).
|
||
|
||
### 124. Install seeds `?ref=v1` while writing main-era config (and v1 lags hard)
|
||
|
||
**Seen on Acer after install** (and inherent in every current install):
|
||
|
||
- ISO was built from **main**.
|
||
- Generated `~/.nomarchy/flake.nix` still has
|
||
`inputs.nomarchy.url = "…?ref=v1"` (`templates/downstream/flake.nix` +
|
||
`flake.nix` `flakeUrl` / `originalNode.ref = "v1"`).
|
||
- Installer **also** writes live `nomarchy.hardware.*` lines into
|
||
`system.nix` (`patch-template.py` — e.g. `nomarchy.hardware.intel.enable`).
|
||
- `v1` is far behind main (hundreds of commits; currently lacks the modern
|
||
`nomarchy.hardware` surface). After a pull / lock re-resolve to the forge,
|
||
rebuild dies with:
|
||
|
||
```
|
||
error: The option 'nomarchy.hardware' does not exist.
|
||
… intel = { enable = true; };
|
||
Did you mean 'nomarchy.services' or 'nomarchy.system'?
|
||
```
|
||
|
||
So a main-built ISO writes config that **only main understands**, then points
|
||
the machine at a release branch that does not have those options. Offline
|
||
compose-lock papers over first boot (path-locked to the ISO store), but the
|
||
first intentional update re-resolves to ancient v1 and the machine breaks.
|
||
|
||
**Product tension:** the standing branch model is "downstreams pin `v1`"
|
||
(ROADMAP / CONVENTIONS) — correct once `v1` is a real release pointer. While
|
||
`v1` lags development this hard, **installs from a main ISO must not leave
|
||
users on that lagging ref**.
|
||
|
||
**Fix direction (pick one and document):** (a) ISO build injects the ref the
|
||
image was built from (`main` or `v1`) into the template + `flakeUrl`; (b) pin
|
||
`original` to the exact ISO `rev` and only advance on explicit
|
||
`nomarchy-pull`; (c) stop writing options that do not exist on the pinned
|
||
ref (worse — loses hardware enablement). Prefer (a) or (b).
|
||
|
||
**Pass:** a machine installed from a main-built ISO has a flake whose nomarchy
|
||
input evaluates the same option surface the installer wrote (no
|
||
`nomarchy.hardware does not exist` on `nomarchy-rebuild` / first pull policy
|
||
as documented); a release ISO built from `v1` still pins `v1`. Guard: install
|
||
safety / template check that written options ⊆ pinned module surface, or that
|
||
the seeded ref matches the ISO source ref.
|
||
|
||
### 94. Live ISO/install: no default browser observed
|
||
|
||
**Progress 2026-07-13:** installed path VERIFIED at V1 — the exact HM
|
||
generation the ISO pins for offline installs contains the chromium binary,
|
||
`chromium-browser.desktop`, and all three HTTP/HTML handlers
|
||
(mime.nix sets them; template ships the package). The Acer sighting is the
|
||
LIVE session, which shipped NO browser by design (mime defaults name chromium,
|
||
GIO skips it while absent).
|
||
|
||
**Update 2026-07-14:** the live half is **gone** — #103 shipped, so the live
|
||
session now carries chromium (plus office/editor/music/camera) on PATH and in
|
||
the launcher, and `checks.live-baseline-apps` asserts HTTPS still resolves to
|
||
`chromium-browser.desktop` *and* that the entry it names is actually present —
|
||
the exact "mime names a package nothing ships" trap this item found. What
|
||
remains here is only the **installed** path: a test-install VM run proving
|
||
chromium launches post-install (chain #97's Bluetooth-click V2 into the same
|
||
run).
|
||
|
||
Chromium is the resolved default-browser decision and is present in the
|
||
downstream template, but this hardware pass found no usable default browser.
|
||
Trace the live-to-installed Home Manager path rather than merely checking the
|
||
template source. Pass = Chromium launches after installation and HTTP/HTTPS
|
||
mime defaults resolve to `chromium-browser.desktop` (and the intended live-ISO
|
||
browser posture is explicit).
|
||
|
||
### 95. Live ISO/install: Ghostty does not open on Acer (old GL + two log shapes)
|
||
|
||
**Machine:** Acer Aspire M5-481T only. **Dell XPS 9350 starts Ghostty fine**
|
||
(Bernardo clarified 2026-07-15 — do not treat XPS as a Ghostty failure).
|
||
|
||
**Why this hardware fails:** the Aspire is Ivy Bridge–class (**Intel HD
|
||
4000**, ~2012). Mesa’s max for that GPU is **OpenGL 4.2**; Ghostty requires
|
||
**4.3**. That is a **generation ceiling**, not a missing package — no
|
||
Nomarchy or Mesa tweak can make HD 4000 report 4.3 honestly. Documented in
|
||
`docs/REQUIREMENTS.md`. The product response is a fallback terminal (or
|
||
probe), not “fix Intel drivers.”
|
||
|
||
On the Acer, Bernardo installed **kitty** by hand (worked) and launched
|
||
Ghostty from that shell twice — **same box, two lifecycle points, two log
|
||
shapes**:
|
||
|
||
**1 — Before Home Manager was properly built** (partial first boot after
|
||
#123 bake failure). Explicit GPU floor:
|
||
|
||
```
|
||
info(opengl): loaded OpenGL 4.2
|
||
warning(opengl): OpenGL version is too old. Ghostty requires OpenGL 4.3
|
||
warning(gtk_ghostty_surface): failed to initialize surface
|
||
err=error.OpenGLOutdated
|
||
warning(gtk_ghostty_surface): surface failed to initialize
|
||
err=error.SurfaceError
|
||
```
|
||
|
||
**2 — After home was built** (full HM generation). Silent-ish exit:
|
||
|
||
```
|
||
warning(gtk_ghostty_application): setting GDK_DEBUG=
|
||
warning(gtk_ghostty_application): setting GDK_DISABLE=gles-api,vulkan
|
||
~ 9s )
|
||
```
|
||
|
||
No `info(opengl):` line, no `OpenGLOutdated`, no `SurfaceError` — process
|
||
ends after ~9s with only the two `GDK_*` warnings. Same Ghostty 1.3.1, same
|
||
machine; the difference is **session/config state after HM**, not a second
|
||
GPU. Likely still the GL 4.2 floor (or the same surface path) with different
|
||
verbosity once the full Ghostty/GTK/Stylix config is in place — confirm
|
||
before inventing a second root cause. Re-run post-HM with extra logging
|
||
(`GDK_DEBUG`, Ghostty verbosity, `WAYLAND_DEBUG=1`) if the quiet path is
|
||
still opaque.
|
||
|
||
**Product impact:** default terminal is Ghostty (`nomarchy.terminal`), so on
|
||
this class of GPU SUPER+Return and the launcher entry are dead. Kitty as a
|
||
manual workaround proved the session/Wayland path is fine.
|
||
|
||
**Fix direction:** treat the **GL ≥ 4.3 requirement** as the primary Acer
|
||
blocker (soft-fallback, alternate default terminal when GL < 4.3, or
|
||
installer/hardware probe that swaps the default). Do not leave SUPER+Return
|
||
bound to a terminal that cannot map a surface. Optionally make the post-HM
|
||
failure mode print the OpenGL reason again so the quiet log is not a
|
||
support trap.
|
||
|
||
**Pass:** on the Acer (or a GL 4.2 / softGL stand-in), SUPER+Return opens a
|
||
usable terminal without hand-editing `home.packages`; modern-GL machines
|
||
(including the XPS) still get themed Ghostty by default. V2 softGL may cover
|
||
the floor; V3 on the Acer is the real check.
|
||
|
||
### 98. Boreal: button text renders black and is difficult to read
|
||
|
||
Audit GTK button foreground/background contrast under Boreal, including the
|
||
installer surface where it was observed. Follow THEME-DESIGN's two-theme
|
||
visual protocol. Pass = normal, hover, focused, and disabled button labels
|
||
remain legible and palette-consistent.
|
||
|
||
**Progress 2026-07-13:** scripted checks pass all 24 themes — not
|
||
palette-level. Stylix gtk.css for Boreal audited: fg roles are light
|
||
(#d3dae0); the near-black values are `accent/warning/error_fg_color`
|
||
(#21272f) on their pastel bgs (deliberate, ~4.4:1). Candidate surfaces:
|
||
adw-gtk3 (light base) + dark recolor edge cases, or gum's TUI confirm
|
||
buttons in the installer (VM gum screens under Boreal look legible —
|
||
artifacts in `/tmp/nomarchy-v2-swap-93/`). Needs Bernardo's screenshot or
|
||
an Acer repro to pin the actual widget before fixing.
|
||
|
||
### 113. Live session: offline theme switch rebuilds the world from source
|
||
|
||
Surfaced by #99's evidence run (2026-07-13, `/tmp/nomarchy-v2-theme-99/`):
|
||
in the **live ISO** session, offline `nomarchy-theme-sync apply gruvbox`
|
||
fails — its `home-manager switch` tries to build **1176 derivations** from
|
||
the `stage0`/`hex0` bootstrap up, then dies on offline source fetches
|
||
(`vala`, `yasm`, `config.jsonc`, `ghostty-config`, `easyeffects.svg`,
|
||
`typogrify`…), ending `error: Build failed due to failed dependency`. This
|
||
contradicts docs/TESTING.md item 6 ("apply gruvbox → switch runs offline").
|
||
The failing generation is `bvl30ggn…-home-manager-generation.drv`; it is
|
||
**not** the drv the ISO pins (the pin is the *default*-theme
|
||
`homeConfigurations.${username}.activationPackage`, i.e. Boreal — confirmed
|
||
drv-identical to the failing one only for gruvbox state, so a non-default
|
||
theme's generation is unpinned). NOT caused by #99's git-seed: the drv is
|
||
byte-identical path-seeded vs git-seeded. **Decide the contract:** either
|
||
pin every baked theme's live activationPackage into the ISO (size cost) or
|
||
scope the offline-switch promise to the shipped theme + correct
|
||
TESTING.md/MEMORY. Pass = a fresh live ISO either switches to any baked
|
||
theme offline, or fails with a clear "needs network for this theme" message
|
||
and accurate docs. **Not caused by anything in today's batch** — separate
|
||
pre-existing ISO-pinning gap.
|
||
|
||
## NEXT
|
||
|
||
### 122. A crisper Nomarchy logo in fastfetch
|
||
|
||
Bernardo 2026-07-14: the ASCII/block logo fastfetch prints should be **crisper,
|
||
with straight lines** — a "high resolution" ASCII logo rather than the chunky
|
||
mark it renders today.
|
||
|
||
Where it comes from (`modules/home/fastfetch.nix:12-17`): the vendored vector
|
||
mark is rasterised at 220px (`rsvg-convert`), recoloured to `theme.colors.accent`
|
||
with `magick`, and converted at build time by
|
||
`chafa --format symbols --symbols block --size 20x10 --colors full`. **That
|
||
`--symbols block` is the cause**: it restricts chafa to full/half blocks, so a
|
||
20×10 grid carries roughly 20×20 pixels of detail and every diagonal turns into
|
||
a staircase.
|
||
|
||
**`--symbols sextant` is the lever, and it is available — verified 2026-07-14 on
|
||
a real Nomarchy machine.** Chase the *fallback*, not one font's charset; this
|
||
was got wrong twice while filing, both times by checking a single font:
|
||
|
||
- The mono face is **per theme** (`ghostty.nix:22` → `t.fonts.mono` from the
|
||
theme JSON), not stylix's default. **Boreal — the default theme and the base
|
||
state — is `GeistMono Nerd Font`**; the other 23 themes are `JetBrainsMono
|
||
Nerd Font`. Any answer must hold for both.
|
||
- Neither of those two faces covers U+1FBxx (sextants), U+2800 (braille) — **and
|
||
GeistMono covers no block elements (U+2580–259F) or box drawing either**. So
|
||
**the logo already renders through fontconfig fallback on the default theme
|
||
today**, and has all along. Fallback is the normal case here, not the risk.
|
||
- Fallback resolves it: `fc-list :charset=1fb00` → **37 families** on a real
|
||
box, including the shipped `nerd-fonts.caskaydia-cove` plus
|
||
`noto-fonts`' Noto Sans Symbols 2; `fc-match "GeistMono Nerd Font:charset=1fb00"`
|
||
picks CaskaydiaCove. Braille: 59 families. **No tofu.**
|
||
|
||
So the change itself is roughly a one-flag edit (`--symbols block` →
|
||
`sextant`, 2×3 subcells = 6× the detail, likely with a larger `--size` and a
|
||
matching `rsvg-convert -w`). **The work is the verification, not the edit.**
|
||
Two things can still make it look worse, and only a real terminal can say:
|
||
**(1) fallback metrics** — CaskaydiaCove's sextants drawn in GeistMono's cell
|
||
may not align or may differ in stroke weight, and this is precisely the kind of
|
||
seam that looks fine in a VM and wrong on a laptop; **(2)** the mark is
|
||
**diagonal-heavy** (an N-monogram of angled strokes), and diagonals staircase
|
||
under *any* cell symbol — more resolution makes a finer staircase, not a
|
||
straight line. If "straight lines" means the mark itself should be redrawn with
|
||
straight strokes, that is a **logo design change** to `logo.svg` — not a
|
||
renderer tweak — and it hits all three surfaces below. Settle which is wanted
|
||
before touching chafa flags.
|
||
|
||
**Note the mark is diagonal-heavy** (an N-monogram of angled strokes), which is
|
||
the underlying tension: diagonals staircase under block symbols at *any* size.
|
||
If "straight lines" means the logo itself should be redrawn with straight
|
||
strokes, that is a **logo design change** to `logo.svg`, not a renderer tweak —
|
||
and it would hit all three surfaces below. Settle which is wanted first.
|
||
|
||
Do **not** conflate the three logo surfaces — they are different renderers and
|
||
a change here touches only the first: fastfetch (this item), the ISO boot splash
|
||
(`hosts/live.nix` `isoSplash`, rsvg→magick), and the Waybar menu glyph
|
||
(`Nomarchy.ttf` U+F000, `modules/nixos/branding/`). The vector source
|
||
(`modules/nixos/branding/logo.svg`) is shared, so a change to *it* hits all
|
||
three — if the SVG is what needs work, say so and split the item.
|
||
|
||
This is a **visual change**, so `agent/THEME-DESIGN.md` and the honesty rule
|
||
apply: no "it probably looks fine". Pass = the logo reads crisply in a real
|
||
terminal at the shipped font, **screenshots captured and viewed under at least
|
||
two themes** (one generated palette, one whole-swap), no tofu, it still tracks
|
||
the accent on a theme switch, and the fastfetch layout still lines up (the logo
|
||
column and the module list share a row grid — changing `--size` moves it).
|
||
|
||
### 120. A netinstall ISO, next to the fat offline one
|
||
|
||
Bernardo 2026-07-14, after seeing the measured size: **keep the current ISO
|
||
exactly as it is** — the guaranteed offline install is the feature it buys —
|
||
and ship a **much lighter netinstall variant alongside it**. Two products, one
|
||
distro: "works on a plane" and "8 GiB is absurd to download" are both true, and
|
||
a second target settles them without compromising either.
|
||
|
||
**Measured facts (2026-07-14), so this starts from numbers, not vibes.**
|
||
*(These stand as measured: #121 would have cut ~0.67 GiB of duplicate chromium
|
||
from them, but it was **reverted** — decided against, ROADMAP § one chromium,
|
||
not two. If a netinstall ships, revisit it: the duplicate is worth ~195 MiB of
|
||
**download**, which is this item's whole currency, even though it is worth
|
||
almost nothing on disk or on the ISO.)*
|
||
|
||
> **Read this before using the numbers below.** They are **closure arithmetic**,
|
||
> and #121 proved the hard way that closure size is neither disk size nor image
|
||
> size: removing a 687 MiB path shrank the ISO by **8 KiB**, because
|
||
> **mksquashfs dedupes duplicate files** and **`auto-optimise-store` hardlinks**
|
||
> them on disk. So a change that looks like it sheds gigabytes of closure can
|
||
> shed nothing off the actual image. **Measure the artifact — build the ISO and
|
||
> `stat` it.** The corollary cuts the other way and is the good news for this
|
||
> item: what dedupe cannot help is the **wire**, so a netinstall's download is
|
||
> the one figure closure/NAR size predicts honestly (`nix path-info --store
|
||
> https://cache.nixos.org --json` gives the real `downloadSize`).
|
||
- Current ISO **8.078 GiB** compressed; **18.03 GiB** of store uncompressed
|
||
(`zstd -19`, 2.23:1 — compression is already near-max, not the lever).
|
||
- The offline pin (`system.extraDependencies`, 60 roots: a representative
|
||
installed system + the template HM closure + all flake inputs) is **4.02 GiB
|
||
uncompressed of that — only ~22%**. Dropping it entirely still leaves a
|
||
**~13.3 GiB** desktop → roughly **6 GiB** compressed at the same ratio.
|
||
**So "no pin" alone is NOT the lighter ISO** — this is the trap to avoid.
|
||
- The desktop's own top weights: libreoffice 1457 MiB, initrd 1369,
|
||
linux-firmware 770, chromium 1391 (two builds — #121, left in), llvm-lib 540,
|
||
bibata-cursors 322, mesa 264, mbrola-voices 259, nerd-fonts ~420 combined.
|
||
Note what that list implies: no single lever gets a desktop ISO under ~4 GB —
|
||
which is the case for (b) below.
|
||
|
||
**So the real decision is what a netinstall ISO IS**, and it should be settled
|
||
first (`[human]`): (a) the full try-before-install desktop minus the pin
|
||
(~6.3 GiB — barely lighter, probably not worth a second target); (b) a **TUI
|
||
installer only, no desktop** (~1 GiB, the actual "netinstall" in the Debian
|
||
sense) which drops "try before install" from that medium — the fat ISO still
|
||
offers it; (c) a middle desktop (no libreoffice/chromium — but note #103 just
|
||
put those there deliberately, and a *demo* desktop that can't browse is the
|
||
bug #103 fixed).
|
||
|
||
**The gotcha that decides feasibility:** without the pin, a netinstall target
|
||
fetches from `cache.nixos.org` for stock nixpkgs paths — but **Nomarchy's own
|
||
derivations are in no binary cache**, so they would build *from source on the
|
||
user's machine* during install. That is the same failure `tools/vm/gap-analysis.py`
|
||
exists to diagnose (and #113 is a live instance of). So this item probably
|
||
depends on a public binary cache (cachix) for the flake's own outputs, or it
|
||
trades an 8 GiB download for a 40-minute install. Establish that before
|
||
building the target.
|
||
|
||
Pass = a second, documented ISO target that is *substantially* smaller (state
|
||
the measured number, both ISOs built from one tree), installs successfully with
|
||
a network in a QEMU run, says clearly at boot that it needs one, and leaves the
|
||
offline ISO's behaviour untouched (`checks.*` for the offline path stay green).
|
||
|
||
### 115. Suspend-then-hibernate, with a way to set it up
|
||
|
||
Bernardo, 2026-07-14: a suspended laptop should be able to fall through to
|
||
hibernate after a while, so a bag-carried machine stops draining, and setting
|
||
that up must be easy — not a systemd-sleep man-page trip.
|
||
|
||
The mechanism is `systemd`'s `suspend-then-hibernate` plus
|
||
`HibernateDelaySec`; the work is the surfacing, and the constraints are
|
||
already in the tree. Hibernate needs the resume offset + swap the installer
|
||
detects (`resumeOffset`/`rootUuid` in patch-template.py) — on a machine
|
||
without them this must self-gate, not fail at suspend time, the way Battery
|
||
limit gates on a battery. `modules/nixos/default.nix` already declines to
|
||
hyprlock before an encrypted hibernate (the LUKS resume gates it); check that
|
||
reasoning still holds when the suspend leads to hibernate. Menu placement: it
|
||
belongs with the power settings, not the root (§ menu placement convention).
|
||
|
||
Settle first (`[human]`): whether the delay is a preset list (30 min / 1 h /
|
||
2 h / never) or a free-form entry, and whether it applies on battery only or
|
||
always — the same on-AC question `modules/home/idle.nix`'s suspend listener
|
||
already answers with `${onAc} ||`.
|
||
|
||
In-flake state like the rest (`settings.*`), menu-writable, and read via
|
||
`theme-state-read.nix` on the NixOS side — NOT `config.nomarchy.settings`,
|
||
which does not exist there (ROADMAP § *NixOS-side state bridges (#116)*; copy
|
||
the `bluetooth.enable` shape in `modules/nixos/default.nix` and add a case to
|
||
`checks.state-bridges`). Pass = the toggle survives a rebuild,
|
||
a suspended machine hibernates after the configured delay and resumes, and a
|
||
machine without hibernate support hides the row instead of offering a
|
||
suspend that never wakes.
|
||
|
||
### 107. Rename `theme.json` to reflect that it is the system state
|
||
|
||
The state file long ago stopped being about themes: it carries night-light,
|
||
keyboard memory, display resolution and profiles, auto-commit, services and
|
||
more, so `theme.json` now misnames its own contents and misleads anyone
|
||
reading the flake. Rename it to `state.json` (Bernardo's call, 2026-07-14 —
|
||
settled, do not revisit), and carry the `nomarchy-theme-sync` tool name along
|
||
with it.
|
||
|
||
Standalone task — do not fold it into a feature. Ships with a compatibility
|
||
shim that keeps reading an existing `theme.json` so downstream checkouts do
|
||
not break on a pull, plus a migration note. Pass = a fresh install and an
|
||
existing downstream checkout both work, every in-repo reference (modules,
|
||
tools, template, docs) uses the new name, and the shim is documented with the
|
||
release it can be dropped in.
|
||
|
||
### 104. Runtime Airplane mode
|
||
|
||
Add Airplane mode under System connectivity controls. It must disable Wi-Fi
|
||
and Bluetooth together, remember their prior states, and restore those states
|
||
when disengaged. Pass = the runtime round trip works, and a Waybar indicator is
|
||
visible only while engaged with parity across every whole-bar swap.
|
||
|
||
### 105. `[big]` System-menu information architecture
|
||
|
||
Keep exactly six root menu entries while reorganizing System into
|
||
Connectivity, Devices, Recovery, and Preferences. This item must be split into
|
||
scoped implementation/verification tasks before work starts. Pass = every
|
||
current route has one deliberate home, navigation remains shallow, and no
|
||
root-level entry is added or lost.
|
||
|
||
### 106. Internal menu Back/Left navigation contract
|
||
|
||
Reproduce the reported internal leaf with neither Back nor Left behavior, then
|
||
fix any breach of the already-intended navigation contract. Add a permanent
|
||
guard covering every internal leaf; external GUIs and free-text prompts retain
|
||
their explicit Esc exceptions. Pass = no internal leaf can strand the user and
|
||
the guard fails on a regression.
|
||
|
||
### 108. Keybindings menu presentation and completeness audit
|
||
|
||
Group the menu as Window, Workspace, Menu, and Media, then prove every live
|
||
Hyprland binding appears from the canonical source. Do not repeat the obsolete
|
||
claim that float/move bindings are absent. Pass = presentation is scannable and
|
||
an automated comparison detects omissions or stale displayed bindings.
|
||
|
||
### 110. `[big]` Retire Control Center safely
|
||
|
||
Split this into two phases before implementation: first build a migration/drop
|
||
matrix for every unique setting, then remove the package and all references.
|
||
Keyboard and terminal replacements must reject unsafe free-text values. Pass =
|
||
no supported setting silently disappears and the second phase leaves no stale
|
||
launcher, menu, package, documentation, or generated-artifact reference.
|
||
|
||
**Facts for the matrix, from #116 (2026-07-14):** its Bluetooth and Printing
|
||
rows write `settings.{bluetooth,printing}.enable`, and those keys became live
|
||
bridges to the NixOS config in a9f3a64 — until then they wrote JSON nothing
|
||
read, so *these two toggles have never actually worked for any user*. That
|
||
cuts both ways: "preserve existing behavior" is not a reason to keep them
|
||
(there is no behavior to preserve), but the state keys and their bridges are
|
||
real now and outlive the TUI — dropping the rows must not drop the keys, or a
|
||
machine whose theme-state.json already says `bluetooth.enable = false` will
|
||
silently flip back on at the next rebuild. `checks.state-bridges` covers those
|
||
two keys and will fail loudly if the bridges go with the tool; keep it green,
|
||
and if a key is deliberately retired, remove its case in the same commit.
|
||
Whatever inherits the rows should rebuild on toggle rather than print
|
||
"requires rebuild" (#117). Updates (`settings.updates.enable`) is HM-side,
|
||
where `nomarchy.settings` genuinely exists, and needs none of this.
|
||
|
||
### 111. Scope-first Recovery menu
|
||
|
||
Replace confusing Rollback/Snapshots duplication with explicit Desktop
|
||
generation, System boot generation, and Files/root BTRFS scopes. Pass = labels
|
||
state what is restored and from where before action, with destructive or reboot
|
||
effects made clear and each existing recovery path represented once.
|
||
|
||
### 112. Installer disk-picker safety
|
||
|
||
Exclude floppy, pseudo, tiny, and otherwise non-installable devices such as
|
||
`/dev/fd0`; never select them by default. **Reproduced in QEMU 2026-07-13**
|
||
(#93's V2 run): with OVMF the guest exposes `/dev/fd0` and the picker listed
|
||
it FIRST — a blind Enter selected it (artifacts:
|
||
`/tmp/nomarchy-v2-swap-93/20-review.png`, `Disk: /dev/fd0 (WILL BE ERASED)`). Pass = the real install disk is clear,
|
||
invalid devices cannot reach destructive setup, a permanent guard covers the
|
||
filter/default logic, and a pre-destructive KVM run proves the picker behavior.
|
||
|
||
## 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.
|
||
- **MIPI/IPU software-ISP camera** support (no-UVC machines).
|
||
- **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).
|
||
|
||
## FUTURE (decided deferred — not the agent queue head)
|
||
|
||
Work we **intend** someday but explicitly **not** NEXT. Agents do not
|
||
pick these unless Bernardo promotes one into NEXT/NOW.
|
||
|
||
### 20. KVM runner → VM suite in CI `[human]`
|
||
**Status (2026-07-10):** keep **eval-only** CI on the current Gitea
|
||
stack (act_runner in docker-compose on the 4c/4 GB IONOS VPS). Nested
|
||
KVM + RAM headroom on that host are a poor fit next to Gitea; full
|
||
`checks.*` VMs stay local / promotion-time until a **separate**
|
||
KVM-capable machine exists.
|
||
|
||
**When ready:** register a second runner (host-mode nix + `/dev/kvm`,
|
||
label `nix-kvm` — not the existing docker eval runner), then uncomment
|
||
the `vm-checks` job in `.gitea/workflows/check.yml` (`runs-on: nix-kvm`,
|
||
`nix flake check` + toplevel/HM builds). Do not enable the job until
|
||
that label is online (Gitea queues forever otherwise).
|
||
|
||
### Formatter — adopt later `[human]`
|
||
**Intent:** add a Nix formatter (likely `nixfmt-rfc-style`) in a dedicated
|
||
pass: reformat the tree once, document in CONVENTIONS, optional CI
|
||
check. **Not** the queue head — no drive-by reformats until that pass.
|
||
|
||
## 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.*
|
||
|
||
*Open work only. Shipped exam/A–C items (#47–#63, #14, #52 theme
|
||
high-ROI, etc.) live in the journal + ROADMAP — not here.*
|
||
|
||
### Product / day-2
|
||
|
||
### 117. Control Center says "requires rebuild" and leaves the user to do it
|
||
|
||
**Filed as an input to #110 (Retire Control Center safely), not as standalone
|
||
work** — Bernardo 2026-07-14: the Control Center is going away, so fixing its
|
||
toggles would be building on a condemned surface. Recorded because the
|
||
observation outlives the tool: it is a fact the #110 migration matrix needs,
|
||
and whatever menu inherits these settings must not repeat it.
|
||
|
||
Noticed while fixing #116 (2026-07-14). `nomarchy-control-center.sh`'s
|
||
Bluetooth, Printing and Updates toggles set the state and print "… (requires
|
||
rebuild)", so the setting only lands whenever the user next thinks to run
|
||
`nomarchy-rebuild`. Every menu toggle written since does the rebuild itself
|
||
and toasts the outcome (`nomarchy-autologin`, `nomarchy-fingerprint`,
|
||
`nomarchy-autotimezone`) — the state-write-then-rebuild shape. A user who
|
||
toggles Bluetooth off and sees Bluetooth still running cannot tell "needs a
|
||
rebuild" from "the toggle is broken again", which is exactly the symptom #116
|
||
removed. Migrating these rows into the rofi menu resolves it for free, since
|
||
that shape is the convention there.
|
||
|
||
### 114. Greeter ignores per-device keyboard layouts
|
||
|
||
Found by Bernardo 2026-07-14: logging out while docked lands on tuigreet,
|
||
where his external keyboard (remembered as `us` via
|
||
`settings.keyboard.devices`) types the session layout `gb` — so the password
|
||
prompt fights him. Not a regression and not docking-related: per-device
|
||
layouts are applied with `hyprctl keyword device[<name>]:kb_layout`, which
|
||
only exists inside a running Hyprland session, while tuigreet draws on a
|
||
kernel VT whose single keymap comes from `console.useXkbConfig` ←
|
||
`services.xserver.xkb.layout`. A VT structurally cannot do per-device
|
||
layouts, so this is a design gap, not a bug to patch. Options, cheapest
|
||
first: (a) document it and stop there; (b) a greeter layout-cycle key
|
||
(tuigreet has no such feature — would need the keymap swapped under it);
|
||
(c) host tuigreet inside a small Wayland compositor (cage/labwc), which
|
||
*does* get per-device XKB and would let the greeter honour the same
|
||
in-flake state the session uses — real work, and it changes the greeter's
|
||
whole rendering path (`modules/nixos/greeter.nix` themes tuigreet through
|
||
the 16 ANSI console slots, so (c) is not a drop-in). Worth deciding whether
|
||
the greeter is meant to be layout-aware at all before costing it.
|
||
|
||
- **NVIDIA first-class options** — **deferred past v1** (Bernardo
|
||
2026-07-10). Keep #59 commented install guidance; no
|
||
`nomarchy.hardware.nvidia.*` until a hybrid maintainer + queue.
|
||
|
||
- **Post-install hardware hints** (`VISION § B`) — After the general
|
||
“you're set” card (#81), optionally fire **one** additional
|
||
self-gated notify when the machine actually has the hardware:
|
||
(a) `fwupdmgr` on PATH → “System › Firmware to check LVFS updates”;
|
||
(b) `fprintd-list` on PATH → “System › Fingerprint to enroll”.
|
||
One-shot markers in `settings.*` (same in-checkout discipline as
|
||
`firstBootShown`); never a permanent MOTD nag. Cost: small — extend
|
||
`nomarchy-first-boot` or a sibling oneshot + `checks.first-boot`
|
||
fixture. Control-center / MOTD already mention these; the gap is the
|
||
silent first *graphical* session for people who never open those.
|
||
|
||
_(#80–#83 + #85–#88 shipped 2026-07-11. Theme A day-2 + neon-glass finish
|
||
shipped — VISION ✓. Dock/hibernate V3 → HARDWARE-QUEUE. Parallel
|
||
fingerprint-or-password shipped 2026-07-12 (Bernardo promoted it live;
|
||
`fingerprint.parallel`, pam-fprint-grosshack) — reader V3 →
|
||
HARDWARE-QUEUE.)_
|
||
|
||
### v1.0 pointer
|
||
|
||
See **VISION**. Open PROPOSED: post-install hardware hints; NVIDIA
|
||
deferred past v1; IR portal (b)/(c) need T14s (HARDWARE-QUEUE § T14s).
|
||
Standing calls: browser = Chromium; power = PPD.
|
||
|
||
|
||
## Decisions `[human]`
|
||
|
||
Open calls only Bernardo can make; agents add options/evidence but never
|
||
decide. **Resolved** entries stay for history; agents treat them as closed.
|
||
|
||
### Resolved (2026-07-10)
|
||
|
||
- **Docs site vs Markdown-in-repo** — **markdown in-repo for now**
|
||
(`docs/`, README). A rendered docs site is FUTURE if wanted.
|
||
- **Default browser** — **ship Chromium** in
|
||
`templates/downstream/home.nix`; mime → `chromium-browser.desktop`.
|
||
Opt out: delete the line / override mime.
|
||
- **Default power backend** — **keep PPD** (`nomarchy.system.power.backend`
|
||
default). TLP remains the one-line opt-in. Rationale: stability + live
|
||
profile API for menu/Waybar; Omarchy’s TLP experiment reverted.
|
||
|
||
### Resolved (2026-07-10, more)
|
||
|
||
- **Formatter adoption** — **yes, but not now.** Tracked as FUTURE
|
||
(below). Nix-source style only (`nixfmt-rfc-style` or similar); one
|
||
bulk reformat + CI/check when promoted. Until then: hand-aligned
|
||
style per CONVENTIONS.
|
||
|
||
- **Hibernation** — **want by default** (product intent). Needs a
|
||
disk-backed swap (file or partition) sized for resume; not zram alone.
|
||
**Shipped as #76**; V3 power-cycle PASSED on TuringMachine 2026-07-12
|
||
(ROADMAP § Hibernation + zram by default).
|
||
|
||
### Resolved (2026-07-10, #76 design)
|
||
|
||
- **Swap sizing** — **exactly RAM** (installer default, unchanged). Hibernate
|
||
image ≤ RAM; zram takes day-to-day paging. **`swapSize=0`** stays no-swap.
|
||
- **Migration** — **docs runbook** (`docs/MIGRATION.md`), not a tool.
|
||
- **No-swap Hibernate** — keep the menu row; **notify on failure**.
|