Six self-gating hardware checks in nomarchy-doctor, same ok/bad/warn/skip
+ one-fix-command contract: NetworkManager connectivity, default PipeWire
sink, VA-API/OpenGL smoke (only if vainfo/glxinfo present), fprintd unit +
enroll nudge, fwupd daemon + a soft warn when get-updates is non-empty,
and the laptop charge_control_end_threshold when a limit is set. Each
skips cleanly when its tool/service/device is absent, so the section
shrinks to the machine and never hard-fails on a missing feature.
Implemented by a worktree-isolated agent in parallel with the #46 install
VM; diff reviewed and cherry-picked here. Verified V0 (flake check) + V1
(nix build .#…pkgs.nomarchy-doctor — build-time bash -n + shellcheck),
re-run on main after cherry-pick; plus a read-only run on real hardware
(all six checks fired + self-gated). V2 (checks.doctor fakes) pending.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a self-gated Firmware row to the System submenu (present whenever
fwupdmgr is on PATH, i.e. services.fwupd.enable — default-on), its
dispatch, and a `firmware` handler that opens a terminal and runs
fwupdmgr refresh → get-updates → y/N confirm → fwupdmgr update. Never
auto-flashes: fwupdmgr update confirms each device and prompts for the
reboot a capsule needs (pillar 1 — no silent BIOS writes). HARDWARE.md
§4 updated to "shipped".
Verified V0 (nix flake check --no-build) + V1 (HM generation builds;
generated nomarchy-menu passes bash -n; firmware handler emitted
correctly). V2 (menu render in a session) queued in #43 and V3 (real
LVFS flash) in HARDWARE-QUEUE — the VM was held by the #46 install test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Close the honesty gap on #45. Rendered the full Boreal desktop
headlessly (tools/theme-shot.nix, softGL 1920x1080) and confirmed the
session reads as Boreal — aurora wallpaper, Waybar violet accent
(#B79BE8) workspace pill, GeistMono clock, rofi launcher violet
prompt/selection — not Tokyo Night. Added themes/boreal/preview.png
(480x270, matches the existing 21) so the picker row is no longer
plain-name.
theme-shot: park the cursor bottom-right before the desktop shot so the
frame (which doubles as the preview source) is clean; reusable for the
other two missing previews.
Verified: V0 flake check; V2 theme-shot desktop/menu shots viewed;
contrast 24x7 pass. Preview is a headless bare-desktop capture (not the
floating-terminal composition of the others) — hardware recapture noted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The default desktop showed a red Hyprland config-error banner on every
boot, occluding the Waybar. Root cause: Hyprland 0.53 rewrote window
rules — the `windowrulev2` keyword is a hard error and the old
rule-first order (`float, class:^…$`) no longer parses, so the float
rules were not applying either. Confirmed against the Hyprland 0.55.4
source (`handleWindowrule`): each comma field is now `<keyword> <value>`,
so effects carry a value and matchers take a `match:` prefix.
Migrated the 7-rule block to `float 1, match:class ^…$` form.
Verified: V0 nix flake check --no-build; built the generated
hyprland.conf; V2 theme-shot re-render — banner gone, themed Waybar
renders. Journal + MEMORY gotcha added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Seed theme-state.json and the downstream template from themes/boreal.json
(including border + empty settings). Point eval/schema fallbacks at Boreal
(theme.nix preset, plymouth and live-ISO splash colors, theme-shot, sync
error examples). Docs/TESTING and RECOVERY follow the new default.
Verified: state matches boreal palette; theme-contrast all pass.
preview.png for boreal still missing (picker plain-name; V3 capture).
Pass bare swapSize "0" when the user wants no swap (was "0G", which
still created @swap). Accept "0"/"0G" in disko-config. Unattended
installs require NOMARCHY_LUKS_PASSPHRASE or explicit NOMARCHY_NO_LUKS=1
instead of silently installing cleartext.
Verified: bash -n; nix-instantiate subvolume sets for 0/0G/16G.
VISION § v1.0 install golden path (workflow test iteration).
- Fixed invalid `windowrule` syntax when matching by class regex
which caused Hyprland parse errors.
- Documented IPC socket watcher for display profiles in README.
- Updated agent/JOURNAL.md.
Added satty (Wayland-native screenshot annotation tool) and integrated it with the Capture flow.
Wired `$mod SHIFT, Print` to slurp a region and open satty.
Added "Annotate region" to the rofi Capture menu (Tools > Capture).
Added satty's configuration via home-manager to inject the active theme's palette colors into its UI.
Verified: V1 (flake check --no-build, home activation package build).
Pending: V3 hardware/visual check for the satty UI (queued in HARDWARE-QUEUE.md).
Changed home.stateVersion assignment to use lib.mkDefault instead of a plain assignment.
This fixes downstream flakes that need to migrate existing NixOS installations without bumping their state version.
Verified: V1 (flake check --no-build, home activation package build).
Pending: nothing.
Research iteration (LOOP §1). Findings: the state-file path is robust;
the real stability hole is the eval-only automated lock-bump gate (#14)
with no binary cache, whose true fix is the KVM-blocked #20. Usefulness:
the capture suite lacks a screenshot annotate step. Filed 2 PROPOSED —
an interim build-tier lock gate (no KVM) and a satty annotate step.
V0 (docs-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Headless-actionable backlog is empty (NEXT is all human/hw/V3-visual).
Ran the full scripted suite: flake check green; option-docs and
theme-contrast checks built+passed; theme-design audit shows only
pre-curated identity findings; templates in sync with the live surface.
No churn manufactured. V0-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Item 28 color-only accessibility sweep. Swept every Waybar status
indicator for shape/glyph redundancy: all already carry non-color
distinction (updates shows a count + self-hides; vpn/doctor/nightlight/
recording self-gate; battery/idle/muted are glyph-distinct) except the
swaync notification module — its `inhibited-*` states reused the normal
bells (/), so an app-inhibited (suppressed) state was distinguished
from a normal one by color alone.
Route every suppressed state (DND + inhibited) to the bell-off glyph
+ @muted, so "notifications are off right now" reads by SHAPE. Applied
to the generated bar and all four whole-swaps (summer-day/night use
their own bell-off glyph; executive-slate/boreal use ) — parity rule.
Reuses the glyph DND already ships, so no new codepoint / tofu risk.
Verified: V0 (flake check --no-build; 4 jsoncs valid JSON) + V1 (built
homeConfigurations.nomarchy.activationPackage — the built config has
inhibited-* = U+F009B and style.css routes .inhibited-* → @muted).
V3 pending: live inhibited-state render with an app holding an inhibitor
(HARDWARE-QUEUE). MEMORY gains the "status is never color-only" invariant.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bernardo asked whether TuringMachine (NixOS 25.11) could adopt Nomarchy
without a reinstall, keeping all files. It can — it's a config switch that
reuses the existing hardware-configuration.nix, not a reformat. Adds
docs/MIGRATION.md: a generic "existing NixOS → Nomarchy" walkthrough with
TuringMachine as the worked example — candidacy checklist, the two
data-safety rules (never bump system.stateVersion; /home untouched), a
reversible Phase 0→4 (btrfs snapshot → build-only gate → nixos-rebuild
test → reconcile → cutover) and a triple rollback net. Bakes his decisions:
Nomarchy PPD (drop all ryzenadj), no Secure Boot (drop lanzaboote), full
cutover. Flake/system/home examples verified against lib.nix mkFlake +
templates/downstream, not guessed.
Also files a PROPOSED note: home.stateVersion should be mkDefault so
migrating users don't need mkForce.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Item 42, de-scoped by Bernardo to app-only — no account sync (the user
configures that themselves locally). Clicking the Waybar date/clock now
runs nomarchy-calendar → calcurse in a floating, centered ghostty window
tagged --class=com.nomarchy.calendar (+ --gtk-single-instance=false for a
fresh standalone window), matched by a float+size+center windowrule. The
launcher self-gates on calcurse. Dropped the clock's format-alt date
toggle (conflicts with on-click) and moved the long date into the tooltip.
Parity: on-click added to all four whole-swap jsoncs.
Ships calcurse + pwvucontrol uncommented in the downstream template
(opt-out). Enforces ghostty always installed (ghostty.nix: enable = true
unconditional; nomarchy.ghostty.enable now gates only the theming/config)
so the --class launcher can rely on it.
Verified: V0 green; four jsoncs valid JSON; V1 HM built — launcher ships,
generated clock renders on-click=nomarchy-calendar (format-alt gone, date
in tooltip), hyprland has the 3 calendar windowrules, ghostty in the HM
profile. Click→float→calcurse month view is V3 (queued). Sync is
deliberately the user's own config, not a distro feature.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Item 36(b). Adds `nomarchy-menu powermgmt` — one flat rofi menu of power
Profile rows (→ powerprofilesctl set) + Charge limit rows (→ the same
theme-sync writer batterylimit uses), each half self-gating on its
hardware. No backend duplication; Custom charge stays in the dedicated
batterylimit picker.
Opened two ways (Bernardo's call): the Waybar battery icon AND the
power-profile icon — the profile icon's click flips from cycle → menu.
Wired in waybar.nix and all four whole-swaps (parity). Named `powermgmt`
to avoid the whole-swaps' existing `custom/powermenu` shutdown button
(→ nomarchy-menu power), which is left untouched. The granular System ▸
Power profile / Battery limit rows stay ("keep both").
nomarchy-powerprofile-cycle kept as a standalone bin, now unbound by
default.
Verified: V0 green; V1 HM built (bash -n) — powermgmt case ships, the
generated waybar-config.json wires both icons (2 hits), all four jsoncs
re-wired and still parse, shutdown buttons intact. Click→menu→apply is
V3 (queued).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Iteration #66 (direct request: "make sure menu items that have a keybind
display it"). Audit found every SUPER(+CTRL) module-opening row already
hinted (item 28c); the one gap was Tools ▸ Capture — its Region/Full
screen rows run the exact grim commands of the Print / SHIFT+Print /
CTRL+Print binds but showed nothing. Adds `hintForBind mods key` (matches
keybinds.nix by mods+key, so no drift and no brittle full-action compare)
and `-markup-rows` on the Capture menu so the spans render.
Verified: V0 green; V1 HM built — shipped nomarchy-menu shows
`Region → clipboard {{Print}}`, `Region → file {{SHIFT + Print}}`,
`Full screen → file {{CTRL + Print}}`. Substring case-matches precede the
appended span, so dispatch is unchanged. V3 (pango dim render) queued.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Item 32. Item 26 added SHIFT to the modmask but kept the shifted keysym
`question`, so the bind stayed dead. Hyprland 0.55 resolves a bind's
keysym with SHIFT consumed (issue #7750, behaviour since 0.43): with
Shift held, `$mod SHIFT, question` is matched against `slash` and never
fires. The base keysym is what works — same pattern as this file's own
`$mod SHIFT, 1` workspace binds. Also updates rofi.nix prettyKeys to
collapse "SHIFT + /" → "?" so the cheatsheet row still reads "SUPER + ?".
Verified: V0 `nix flake check --no-build` green; V1 HM activation built,
built hyprland.conf carries `bind=$mod SHIFT, slash, exec, nomarchy-menu
keybinds` (kb_layout=us → slash is `?`). The keypress opening the menu is
V3 — queued (HARDWARE-QUEUE, existing SUPER+? entry updated).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a `batterylimit` nomarchy-menu subcommand — a preset picker
(80/90/60/Off/Custom…) that writes settings.power.batteryChargeLimit via
theme-sync (--no-switch; lands on the next sys-rebuild, power.nix's oneshot
applies it). Surfaced as a first-class System row, self-gated on the
charge_control_end_threshold sysfs node like Power profile.
Moved out of the gum control-center (removed its Battery Limit case +
choose entry) so the toggle lives in one place — the rofi menu Bernardo
actually uses, per his request.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conservative first cut of the floating-window audit (item 41): float and
center the two shipped, unambiguous config dialogs — blueman
(manager/adapters) and system-config-printer — alongside the mixer. Uses
(?i) class regexes tolerant of the XWayland `.…-wrapped` form, consistent
with the existing (?i) usage in this file.
Deliberately conservative: network is dmenu/nmtui (no GUI editor), and the
polkit prompt + GTK file portals are deferred because their window class
can't be verified headlessly — a guessed class is a dead rule. Those wait
for a hardware `hyprctl clients` read (queued).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Right-clicking the Waybar volume module now opens pwvucontrol (per-app
mixer); left-click still mutes. Adds:
- on-click-right in waybar.nix + all four whole-swap jsoncs (parity)
- hyprland.nix: the config's first windowrule block — float + center the
mixer (pwvucontrol, with pavucontrol as a fallback class); normal-
priority list so a downstream windowrule concatenates
- pwvucontrol in the template home.packages
pwvucontrol is PipeWire-native + GTK4/libadwaita, so it themes via the
portal color-scheme like Amberol. app-id verified from the built package.
This settles the windowrule pattern/placement; item 41 is now just
broadening the float set. Right-click→float→center is a V3 session check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swap the vim-style SUPER+H/J/K/L focus binds for SUPER+arrow keys
(movefocus l/r/u/d). SUPER+arrows were unbound and there are no vim
move-window binds, so no collision. prettyKeys renders the arrow keysyms
as glyphs so the SUPER+? cheatsheet shows "SUPER + <-" not "SUPER + left".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mpv (video) and amberol (audio) are both already in the template suite;
the gap was mime wiring — audio/* still resolved to mpv.desktop. Repoint
the audio types to io.bassi.Amberol.desktop (id verified against the
built package) and broaden coverage to mp3/flac/ogg/opus/wav/m4a/aac,
both canonical and x- names. Video stays on mpv. Degrades to mpv if a
downstream drops Amberol from the suite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add SHIFT+Print (region → file) and CTRL+Print (screen → file) next to
the existing bare Print (region → clipboard). Each saves a timestamped
PNG under ~/Pictures/Screenshots and toasts the path — the same grim/slurp
plumbing and directory the Capture menu's "→ file" rows already use.
Single-source keybinds.nix, so the SUPER+? cheatsheet lists both new rows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two rofi fixes:
- Search (item 31): rofi 2.0.0's fzf sorter mis-ranks fuzzy matches —
typing "steam" left ghostty selected instead of Steam. Bernardo's live
A/B confirmed `-sorting-method normal` and `-matching normal` both fix
it while `-no-sort` does not. Switch sorting-method fzf → normal, keep
matching=fuzzy + case-sensitive=false.
- Power profile menu (item 39): list profiles with per-profile icons from
Papirus' colored battery-profile-{performance,balanced,powersave} family
(the -symbolic variants are #444 grey, invisible on dark). Row text
stays the bare profile name so `powerprofilesctl set` is unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mode picker's Back did `exec "$0" display`. On a single-monitor
machine with no display profiles the output chooser is skipped, so
re-running `display` dropped straight back into the same mode picker — an
apparent no-op. Track modeBack (display when the chooser was shown, else
system) and dispatch Back to it, so single-monitor Back leaves Display.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every submenu's "↩ Back" row rendered two arrows: the ↩ glyph in the
label plus a themed go-previous icon. back() now emits the plain label
only — identical to what pick-lists already append — so Back shows a
single glyph everywhere. BACK="↩ Back" stays the universal label/match,
so no case-branch comparison changes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "Battery Limit" entry was a raw number prompt; make it a proper
toggle picker — Off / 80% (recommended) / 90% / 60% / Custom… — writing
settings.power.batteryChargeLimit. Kept in the control-center, where the
baked rebuild-valued System Toggles live (the rofi nomarchy-menu is the
instant surface; the CC holds config values), and reachable from the menu
via System › Control Center. Base machinery (the sysfs oneshot + AC-replug
udev in power.nix) is unchanged, so it lands on the next sys-rebuild like
its siblings.
Instant-effect (no rebuild) is refiled in BACKLOG § PROPOSED as
[blocked:hw]: it needs a udev-writable threshold node, confirmable only on
a laptop with the control.
Verified: V0 (bash -n; nix flake check --no-build, green) + V1
(nomarchy-control-center package builds — the writeShellApplication
shellcheck gate passes). Session spot-check queued in HARDWARE-QUEUE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On Hyprland the `top` layer renders above every window, including a real
fullscreen surface — so a browser video gone fullscreen sat *under* the
bar (BACKLOG item 30). Move the bar to `layer: bottom` in the generated
waybar.nix and all four whole-swap jsoncs (parity rule); the exclusive
zone still reserves its space in normal tiling, but a fullscreen window
now covers it. Rationale comment kept in waybar.nix; data jsoncs left
comment-free (they carry none).
Verified: V0 (nix flake check --no-build, green) + V1
(homeConfigurations.nomarchy.activationPackage builds; built
.config/waybar/config shows "layer": "bottom"). V3 queued in
HARDWARE-QUEUE (fullscreen covers bar + returns on exit; floating-overlap
trade-off).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Leveraged Nano Banana to generate a 4k functional minimalist wallpaper. Added the new preset with a solid, high-legibility waybar and flat rofi launcher.
Added pickers for terminal, keyboard layout, and auto-login to the Control Center TUI, wiring them directly to Nix defaults via theme-state.json settings. Verified: V1.
Added toggles for updates, battery limit, bluetooth, and printing to the Control Center. Wired default values to read from theme-state.json settings. Verified: V1.