Files
Nomarchy/agent/BACKLOG.md
Bernardo Magri fb75c3dedf
All checks were successful
Check / eval (push) Successful in 3m2s
feat(tools): 1080p themed-desktop capture harness + first polish findings (item 28c)
tools/theme-shot.nix: boots the full themed desktop headlessly
(software-GL Hyprland, THEME env picks the slug) at 1920x1080 and
QMP-dumps desktop.png + menu.png (rofi root open) — the review
artifact for slice (c). Two fixes over the 2026-06-19 spike:
home-manager.useGlobalPkgs (the HM submodule otherwise misses the
overlay) and the menu shot via hyprctl dispatch exec. Maintainer tool,
deliberately not a checks.* gate. Known gap in the header: the
wallpaper needs ~/.nomarchy seeded in the guest.

First full-res review (tokyo-night) added to the item-28 punch list:
rofi root menu is ~760px of mostly empty row space (candidate:
right-aligned SUPER+CTRL hints from keybinds.nix), full-color Papirus
menu icons vs the all-monochrome bar glyphs is a [human] identity
call, bar right-cluster group margins confirmed at full res, and the
bar's alpha(text,.5) dim states should become the @muted role now
that 28b floors guarantee its legibility. Whole-swap bar module
parity verified textually — no drift.

Verified: harness end-to-end green (screenshots read back); evals
from tools/ via the relative flake path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:00:28 +01:00

299 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backlog — the prioritized task queue
The forward-looking half of the old docs/ROADMAP.md, reworked as a queue
agents can execute. Detailed design notes and decision records stay in
`docs/ROADMAP.md` (referenced as "ROADMAP § <item>"); this file is *what's
next, in what order*.
**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 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; only
Bernardo moves items *out* of PROPOSED into the tiers.
---
## NOW
*(empty — NEXT's top item is the queue head)*
## NEXT
### 28. Theme UI review — make every surface stunning `[big]`
(Raised by Bernardo, 2026-07-05 — placed at the head of NEXT; reorder
freely.) A thorough visual pass over the whole themed UI — Waybar (the
generated bar AND the summer whole-swaps), rofi menus, swaync,
hyprlock, the cheatsheet, ghostty/btop, GTK/Qt, boot splash, greeter —
with the bar set at *stunning*, not merely consistent (pillar 4).
Grounded in design theory, not taste alone:
- **Color:** palette-role relationships that demonstrably work
together — harmony models (analogous/complementary accents),
perceptual lightness ordering of base→surface→overlay→text (check in
OKLCH, not raw hex), accent/warn/bad distinguishable for color-blind
users; extend tools/check-theme-contrast.py to encode the adopted
rules (it currently guards legibility pairs only).
- **Typography & rhythm:** a consistent type scale across bar/menus/
OSD, spacing on the ui.gapsIn/gapsOut grid, aligned paddings (the
bar's per-module padding vs rofi rows vs swaync toasts).
- **Hierarchy:** what reads first — bar module ordering/weights, menu
title vs rows, toast title vs body; icon weights consistent with the
adjacent text.
Bernardo has offered image-expert models for designed graphics
(wallpapers, logos, glyphs, preview/branding art): an agent slice that
needs artwork must STOP and ask ("say the word") instead of shipping
programmer-art.
Slices: (a) ✓ the audit (2026-07-05, iteration #31 — findings below);
(b) palette-level fixes + the extended contrast/harmony checker —
P1s ✓ shipped 2026-07-05 (iteration #32): summer-day + flexoki-light
subtext/surface/overlay/muted retuned (flexoki to its canonical
upstream tones), miasma + kanagawa surfaces raised (kanagawa to
sumiInk4); `subtext/base ≥ 3` now GATED in check-theme-contrast.py
(all 21 pass). P2s ✓ shipped 2026-07-05 (iteration #33): 18 hex
retunes across 9 themes (OKLCH hue-preserving minimal raises;
canonical where upstream defines one — gruvbox bg4, nord #616e88,
latte overlay1, flexoki 600-series statuses for light mode) and the
four floors GATED: muted ≥ 2, text/surface ≥ 4.5, accentAlt ≥ 3,
warn ≥ 2.5 (21×7 pairings green; audit contrast findings 20 → 1 —
miasma's earthy `bad` stays as identity, good/bad floors stay
audit-only so no exemption list was needed). Remaining (b): nothing —
further palette work graduates from slices (c)/(d) findings;
(c) per-surface polish slices — capture harness ✓ shipped 2026-07-05
(iteration #34): `tools/theme-shot.nix` boots the themed desktop
headlessly at 1080p and screenshots desktop + open root menu (proven
on tokyo-night); per-surface punch items from the first full-res
review:
- **rofi root menu width:** ~760px for six short left-hugging rows —
either tighten, or use the space: right-aligned `SUPER+CTRL+<key>`
hint per row (keybinds.nix already knows them; discoverability
win).
- **Icon weight mix `[human]`:** full-color Papirus icons in the
menus vs all-monochrome bar glyphs — pick: symbolic/monochrome
menu icons for one system, or color as the menu's identity.
- **Bar right-cluster rhythm:** confirmed at 1080p — add group
margins (tray/net · stats · toggles · battery/notify) on the
gaps grid.
- **Semantic dim:** bar dim states are `alpha(@text, 0.5)` tints;
the palette's `muted` role is now floor-guaranteed (28b) — one
semantic source, use `@muted`.
- Harness gap: wallpaper needs `~/.nomarchy` seeded in the guest
(theme-sync reads runtime state there) — add before vibe-review
captures; whole-swap captures (summer-day/night) still pending;
(d) the whole-swap themes brought to the same bar (module parity
verified textually 2026-07-05: whole-swaps carry every functional
module; omitting cpu/memory is identity). Visual work is
V3-bound by nature — screenshots are the review artifact, hardware
confirms.
**Audit findings (slice a — `tools/audit-theme-design.py` over all 21
palettes + visual pass over previews; identity-aware curation):**
- ~~P1 · invisible-secondary-text palettes~~ ✓ fixed iteration #32
(summer-day subtext #6e828a, surface #efe7d0; flexoki-light to
canonical Flexoki: surface #E6E4D9, overlay #B7B5AC, subtext
#6F6E69, muted #878580). Gate added.
- ~~P1 · inverted bg stacks~~ ✓ fixed iteration #32 (miasma surface
#2e2e2e; kanagawa surface #2a2a37 = upstream sumiInk4). Note
learned: in this palette model `overlay` is a MID-TONE
(borders/dim, catppuccin semantics), not a third bg tier — the
dark-theme overlay==muted pattern is intentional.
- **P2 · muted floor:** muted-on-base < 2.0 on gruvbox (1.27),
everforest (1.55), lumon (1.68), nord (1.69), white (1.82), latte
(1.91), retro-82 (1.93) — dimmed workspaces/inactive items barely
render (visible on the lumon preview). Adopt ≥ 2.0 and retune.
- **P2 · warn barely reads:** warn-on-base ≈ 2.02.3 on rose-pine,
summer-day, latte, flexoki-light — this is the bar's 25%-battery
color. Floor 2.5 (or see the color-only rule below).
- **P2 · text-on-surface < 4.5:** ristretto 3.88, latte 4.39 (menus
and chips draw text on surface).
- **P3 · accentAlt-on-base < 3:** latte 2.34, summer-day 2.83.
- **Design rule (systemic, beats palette surgery): status is never
color-only.** good/warn collapse under protanopia on ~half the
themes and good/bad under deuteranopia (59 pair-findings) — that's
inherent to red/green/yellow, not fixable per-palette. Battery and
recording already carry glyph changes; sweep the remaining
color-only indicators (updates count, notification dot, VPN shield
states) for shape/glyph redundancy.
- **Identity exemptions, made explicit:** vantablack + white
(deliberately hueless statuses), lumon (all-blue), hackerman
(matrix green statuses), matte-black/retro-82 (off-family hues) are
identity, not defects — slice (b)'s checker gets a per-theme
exemption list instead of silently lowered floors.
- **ANSI / greeter notes:** latte, rose-pine and white ship
`ansi[0]` LIGHTER than `ansi[15]` — decide the light-theme ANSI
convention (terminals conventionally keep black dark) before the
greeter/tty theming ships to them. tokyo-night/summer-night
`ansi[7]-on-ansi[0]` ≈ 2.83.0 = the greeter's muted text; fine as
muted, watch on hardware.
- **Visual pass (480×270 previews — too small for type/spacing; the
deep per-surface pass needs 1080p captures):** the generated bar's
right cluster runs ~9 modules with uniform spacing — no grouping
rhythm (consider micro-gaps between tray/net · stats · toggles ·
battery/notify groups); latte's preview shows a DARK terminal on
the light desktop — verify ghostty consumes the latte palette (or
the preview is stale); summer-day's island-pill whole-swap bar and
lumon's globe identity are strong — preserve through any polish.
### 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
(also upgrades item 14's bump gate from eval-only to the full suite).
### 15. Display profiles — docked/undocked switching
ROADMAP § Display / monitor management, remaining: profile switching of
the *same* outputs. **Plan (designed 2026-07-05, iteration #27):**
- **Option:** `nomarchy.displayProfiles` (HM) = `attrsOf (listOf
monitorType)` — each profile is a named list reusing the existing
monitor submodule verbatim (no second schema). Example: `docked =
[ { name="eDP-1"; resolution="disable"; } { name="DP-3"; … } ]`.
- **State:** `settings.displayProfile = "<name>"` (absent = base
config), menu-written with `--no-switch` — the night-light pattern:
instant now, baked at the next rebuild. Add the key to
nomarchy-theme-sync's known-settings list (item 11's validator warns
on unknowns).
- **Rebuild overlay** (hyprland.nix): active profile's entries replace
base `nomarchy.monitors` entries whole, by name; the existing
`settings.monitors` resolution overlay then applies field-level on
top, EXCEPT onto entries whose profile resolution = "disable" (a
stale resolution pick must not resurrect a disabled panel).
- **Instant apply** (menu): System Display gains a self-gated
"Profile: <active>" row (only when profiles are declared) → pick →
`hyprctl keyword monitor <rule>` per entry (rules baked into the
dispatcher at build, like everything else in rofi.nix) + state write
+ toast. Outputs the profile doesn't name keep their base rules.
- **Slices:** (a) ✓ shipped 2026-07-05 (iteration #28): option +
overlay (pure `modules/home/monitor-rules.nix`, unit-tested by
checks.display-profiles) + `nomarchy-display-profile` applier + menu
Profiles row + template example — V3 (real dock) queued; (b) ✓
shipped 2026-07-05 (iteration #29): hotplug auto-switch — `match`
subcommand (exact set, else unambiguous largest subset, ties =
none) + a poll watcher (exec-once, the keyboard-watcher pattern)
gated live on `settings.displayProfileAuto` (a separate boolean,
NOT an "auto" pseudo-profile, so auto-picks persist concrete
profiles that rebuilds bake) + menu Auto-switch row — V3 rides the
slice-a dock test; (c) optional per-profile
`workspaces = { "1" = "DP-3"; }` → Hyprland `workspace` keywords.
- **Non-goals:** no kanshi (fights Hyprland's output management —
decided in ROADMAP), nwg-displays stays a find-the-values helper.
### 17. Launch-or-focus UX scripts
ROADMAP § launch-or-focus. Hyprland dispatch scripts: a bind launches an
app or focuses its existing window. Curate which apps get binds;
cheatsheet entries via keybinds.nix.
### 18. "nomarchy" control center + first-boot welcome `[big]`
ROADMAP § control center. A single front-end over the common toggles on
the same `nomarchy-theme-sync` surface, + a first-boot guided
"pick your theme / essentials" flow. Needs a design pass (TUI vs GUI)
→ write options into Decisions before implementing. Note: items 911
(rollback menu, doctor, validation) are natural panels of it — design
them as composable commands, not dead ends.
### 19. Look & Feel menu category
ROADMAP § Menu system, remaining: group Theme + night-light (+ wallpaper
cycle, future appearance toggles) under a Look & Feel submenu once it
earns ≥3 entries — keep the root at six.
## 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).
- **OCR screenshot-to-text**: a Capture entry (grim region → tesseract
→ clipboard) — recording (#12, shipped 2026-07-04) already reshaped
the submenu, so this is now a two-row addition.
- **Doctor Waybar warning**: a self-gating bar indicator fed by
`nomarchy-doctor` (shipped 2026-07-04) — appears only when the sheet
has a ✖; click opens the sheet.
- **Auto-timezone Waybar tooltip** showing the detected zone (optional).
- **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.*
- **Menu parity for downstream-flake options** (raised by Bernardo,
2026-07-04, from the hardware sweep): anything the docs or the
hardware queue ask a user to *hand-edit into the downstream flake*
(`keyboard.layout` multi-layout, `power.batteryChargeLimit`,
`updates.enable`, `services.printing`, …) should have a menu toggle
instead — the in-flake-state philosophy already gives the menu a
write-into-the-flake path, and night-light / auto-timezone /
auto-commit prove the pattern (incl. rebuild-on-first-enable).
Pitch: (a) an audit listing every user-facing `nomarchy.*` option vs
its menu surface; (b) menu writers for the gaps, respecting the
toggle-vs-package discipline (bare template packages stay hand-edits)
and menu-placement convention (right submenu, root stays short).
Values beyond booleans (layout lists, charge thresholds) need a small
input UI per option. Cost: audit is one iteration; the writers a few
more, sliceable per option.
- **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.
## 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).
- **Control center form factor:** TUI (gum/ratatui-style) vs GUI vs
"the rofi menu *is* the control center, just add a first-boot flow".
- **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?