# 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 § "); 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 keybind hints** (shipped iteration #37): dimmed pango hints on root/Tools/System rows, generated from keybinds.nix via the cheatsheet's prettyKeys (single source, can't drift) — capture-verified on tokyo-night. - **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** (shipped iteration #36): group margins before pulseaudio/powerprofile/battery — heads that self-hide degrade to the uniform spacing. - ✓ **Semantic dim** (shipped iteration #36): workspaces + dnd + muted-volume now use `@muted` (floor-guaranteed by 28b) instead of `alpha(@text, 0.5)` tints; the CSS comment now documents the new invariant. - ✓ **compositor backdrop** (shipped iteration #35): Hyprland `misc:background_color` now the theme's base — no more black flash behind a missing/slow wallpaper (glaring on light themes in the summer-day capture). - summer-day whole-swap capture reviewed (iteration #35): the authored slate menu + island-pill bar survive the 28b retunes and read as one coherent identity — keep. ✓ placeholder-dim nit fixed (iteration #38: both summer rasi, bg0 at 60% alpha). - latte capture reviewed (iteration #38): the generated menu is fully coherent on light themes (zebra rows, retuned surface, blue selected, dimmed hints) — the audit's "dark terminal on latte" preview concern was a stale preview, not a defect. Backdrop probe: misc:background_color IS applied (hyprctl getoption = 0xFFEFF1F5); captures show dark because awww's empty-state layer paints over it in the wallpaper-less VM — on hardware the fix covers its intended window (the pre-awww startup gap). - Harness gap: wallpaper needs `~/.nomarchy` seeded in the guest (theme-sync reads runtime state there) — add before vibe-review captures; latte + an identity theme (lumon/retro-82) captures 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.0–2.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.8–3.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 = ""` (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: " row (only when profiles are declared) → pick → `hyprctl keyword monitor ` 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. ### 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 9–11 (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?