Bernardo ran the real power-cycle on the T14s (LUKS + btrfs @swap
swapfile): hibernate → power off → single LUKS unlock → session
restored. BACKLOG #76 deleted; HARDWARE-QUEUE resume entry pruned
(outcome recorded in the remaining no-swap-notify entry, JOURNAL, and
the ROADMAP ✓-entry); Decisions hibernation note marked shipped. The
no-swap Hibernate notify check remains the one open leftover.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tray SNI inventory run live on the T14s: nm-applet, udiskie, Telegram
and EasyEffects are name-based (icon-lookup overridable); Signal and
ZapZap publish pixmaps only (slice 3). Method: watcher's
RegisteredStatusNotifierItems + busctl get-property.
#76: the dev box now runs Nomarchy (migrated 2026-07-11), so the
'not a Nomarchy machine' blocker is gone — retagged [human]; queue
step 1 (swapfile/zram/resume_offset wiring) verified live, only the
power-cycle test remains.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Raise priority.session for HDMI/DisplayPort (1100) and USB (1050) ALSA
outputs so the default sink follows dock plug/unplug; built-in analog
wins again when externals disappear. Rules live in
modules/nixos/dock-audio-rules.nix; checks.dock-audio covers the contract.
Verified: V2 — flake check --no-build; checks.dock-audio green.
V3 pending: HARDWARE-QUEUE #87 real HDMI/USB-dock hotplug.
Explicit HandleLidSwitchDocked=ignore under services.logind so closing
the lid with an external display connected does not suspend. Undocked
lid path left to upstream defaults. checks.clamshell-logind asserts the
baked logind.conf and active logind; real multi-monitor lid V3 queued.
Verified: V2 — flake check --no-build; checks.clamshell-logind green.
V3 pending: HARDWARE-QUEUE #86 lid+external on a laptop.
The Exit node picker listed bare hostnames; Mullvad-style nodes are
meaningless without their location. Rows are now
"hostname — Country City", sliced from `tailscale exit-node list` by
the header's fixed-width column offsets (COUNTRY/CITY can be
multi-word, so field splitting is wrong by construction); nodes without
a location stay a bare hostname, and the pick strips back to the
hostname at the first space before `tailscale set --exit-node`.
Closes BACKLOG LATER "VPN exit-node richer display"; the VPN
HARDWARE-QUEUE entry now covers the location rows.
Verification: V1 — the awk was proven against a fabricated fixture
(one-word city, multi-word "United States / New York, NY", bare
self-hosted node), flake check exit 0, downstream-template-home builds
(writeShellScriptBin syntax-gates the script). Real `tailscale
exit-node list` output stays V3 (existing VPN menu live-paths entry).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Set BOTH nomarchy.nightlight.latitude/.longitude and the night light
switches backing unit: wlsunset computes sunrise/sunset from the
location daily (the fixed .sunrise/.sunset are ignored;
.temperature feeds the night temp). Everything user-facing is
unchanged — same nomarchy-nightlight toggle script, Waybar moon, and
live-state ExecCondition gate; the unit name is a single let-binding
so all three follow together. Declarative-only on purpose: coordinates
are machine config like the keyboard layout, so home.nix (commented
template example), not a menu writer.
checks.nightlight-geo guards the wiring at pure eval: rendered
wlsunset ExecStart carries the coords + night temperature, the
ExecCondition gate landed on the swapped unit, hyprsunset stays off in
geo mode.
Verification: V1 — nix flake check --no-build exit 0 (evals the new
asserts + option-docs sync); built downstream-template-home (default
hyprsunset path unregressed). V3 pending: visible warm shift at the
location's night + instant toggle/off-persistence on the swapped unit
(HARDWARE-QUEUE § Any machine).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New standing rule (LOOP.md §5 step 4, echoed in AGENTS.md): when a task
ships, grep its number/feature name across agent/ and docs/ and update
or delete every cross-reference it made stale, in the same commit —
including pruning checked-off [x] HARDWARE-QUEUE entries whose outcome
is recorded (journal/ROADMAP; git history is the archive).
First application: BACKLOG PROPOSED groomed (the auto time-of-day theme
pitch was stale — shipped as #79; shipped/promoted placeholder lines
removed; v1.0 pointer rewritten; FUTURE promoted-stub dropped);
HARDWARE-QUEUE pruned of 29 checked entries (363→253 lines) with
dangling references reworded and the prune rule documented in its
header.
Also closes the zram user-doc gap: README §3 now documents the zram
default (zstd/50%/prio 100), hibernation working out of the box on new
installs, and the MIGRATION.md runbook for existing machines.
Verification: V0 (docs/meta only).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dev box runs Bernardo's own NixOS (TuringMachine, 25.11), not
Nomarchy — so hibernating it tests that config's hibernate, not
Nomarchy's oom.nix/patch-template/rofi wiring, and can't close#76's V3.
Its layout (LUKS cryptroot + btrfs @ + /swap/swapfile + resume_offset)
does resume, which corroborates the MIGRATION.md runbook, but nothing
more. Rescope the two #76 HARDWARE-QUEUE entries to require a machine
actually running Nomarchy (a Latitude install, or the dev box after
migration), and fix the matching reference in the BACKLOG #76 stub.
Verification: V0 (docs/agent-notes only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add checks.hibernate: a runNixOSTest modeled on nixpkgs' hibernate.nix,
wired to the actual risk #76 introduces — coexistence with the zram swap
that oom.nix now enables by default. It imports oom.nix, puts the disk
swap at a lower priority than zram with an explicit boot.resumeDevice,
and uses systemd-initrd. The test drives a full
hibernate -> power-off -> resume -> crash cycle: a volatile ramfs marker
survives resume but NOT a crash-boot (proving genuine resume), and it
asserts zram sits at priority 100 while the disk swap is lower, so the
hibernate image lands on disk rather than volatile zram.
What QEMU genuinely can't do — feed a boot-time resume_offset for a btrfs
swapfile (offset only exists after first-boot allocation) or drive a
LUKS-initrd unlock — stays a V3 laptop check (HARDWARE-QUEUE, dev box
already runs that exact layout), plus the no-swap notify in a real
session. With this, all V0/V1/V2 work on #76 is done; #76 collapses to a
[blocked:hw] stub and the design record moves to ROADMAP.
Verification: V2 PASS — nix build .#checks.x86_64-linux.hibernate built
the driver fresh and exited 0. nix flake check --no-build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bernardo verified the GTK file-chooser (OpenFile) portal floats on real
hardware; the xdg-desktop-portal-gtk float/center rule already shipped in
hyprland.nix. Drop the "OpenFile not re-probed / optional residual"
caveats in HARDWARE-QUEUE and journal the V3 close. Bookkeeping only, no
code change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Class xdg-desktop-portal-gtk (+ Nix .…-wrapped) from package desktop/
libexec. Polkit already V3 PASS on Latitude. NEXT only #20 remains.
V0: flake check --no-build green.
dmenu mode is case-sensitive by default (dmenu compat), so config.rasi
case-sensitive=false fixed apps/drun but not nomarchy-menu pickers.
rofi_menu helper always passes -i; networkmanager_dmenu gets rofi -i.
V0: flake check --no-build green. V3: type sys in root Menu → System.
Self-gated System › Fingerprint when fprintd is on PATH: enroll, list,
verify, delete-all (terminal), and Use for login writing
settings.fingerprint.pam (hardware.nix default from theme-state). Close#55.
Verified: V1 (HM menu rebuild). V3 pending: real-reader enroll (HARDWARE-QUEUE).
Doctor tripwire was self-hiding under waybar (PATH miss / weak glyph).
Call nomarchy-doctor by store path, strip ANSI tooltips, use + format
+ signal 10 (generated and whole-swap). theme-shot asserts class:bad,
guest btop.theme, and pokes RTMIN+10 before desktop shots.
V2: theme-shot green for rose-pine, summer-night, catppuccin, everforest,
vantablack; bar crops show the red alert-circle. btop TUI visual is
softGL-blocked (Ghostty) → HARDWARE-QUEUE. Closes#51 and #52.
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>
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).
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>
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 "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>
A display profile can now pin workspaces to outputs:
docked = {
monitors = [ … ];
workspaces = { "1" = "DP-3"; "9" = "eDP-1"; };
};
The bare list-of-monitors shape still works (either-type; hyprland.nix
normalizes — coercedTo refuses list-of-submodule sources). Pins bake as
Hyprland `workspace` rules from the active profile and apply instantly
on `nomarchy-display-profile apply`: keyword sets the session rule,
moveworkspacetomonitor moves open workspaces over. Pins from a
previously applied profile linger in-session until reload/rebuild
(hyprctl can only add) — inert if the output is absent, noted in the
applier.
V1: flake check green (checks.display-profiles now asserts
workspaceRule) + scratch-downstream eval: baked settings carry both
rule sets, the generated applier has the keyword+dispatch pairs
(bash -n), match/list correct with mixed shapes. V3 queued in
HARDWARE-QUEUE (rides the dock test). Item 15 complete — deleted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hovering the clock now leads with the zone — "{:%Z (UTC%z)}" above the
calendar — on the generated bar and both summer whole-swaps (parity).
Under auto-timezone the existing tz-watch SIGUSR2 reload keeps it
showing the currently detected zone. %Z is the abbreviation (BST), not
the IANA name — strftime has no code for that, and it satisfies the
"(optional)" nicety.
Verified: V0; V1 — the rendered generated config carries the new
tooltip-format and both summer jsonc parse with it. Hover render
queued for hardware.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nomarchy-doctor-status: silent while nomarchy-doctor exits 0 (or is
absent), so the module only exists when something is actually broken —
then a red warning glyph with the first ✖ lines jq-escaped into the
tooltip; clicking opens the full sheet (nomarchy-menu doctor).
Interval 300s: the health check is real work (unit/disk/git sweeps),
and this is a tripwire, not a monitor. Added to the generated bar
(status group, after battery) and to BOTH summer whole-swap bars
(module list + jsonc block + CSS membership + @red rule) per the
parity rule.
Verified: V0; V1 — template-home builds with the module in config +
CSS, the status script passes bash -n, both summer jsonc still parse;
functional — the self-gate exits silently, and a shimmed failing
doctor yields jq-valid JSON with class "bad" and the ✖ lines in the
tooltip. Live render queued for hardware.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tools › Capture gains "OCR region → clipboard", self-gated on
tesseract: slurp the region (Esc cancels silently, the recording.nix
pattern), grim it, tesseract stdin→stdout, wl-copy. Whitespace-only
recognition toasts "No text recognized" instead of clobbering the
clipboard; success toasts the word count. tesseract ships English-only
through the menu's package set — the unscoped wrapper pulls every
language's traineddata, a real cost on a compile-from-source distro;
overriding with more languages is documented at the package line.
Verified: V0; V1 — template-home builds with the gated row + case and
menu bash -n; functional — the profile's own tesseract read a rendered
test image back verbatim, proving the OCR half of the pipe. The
grim/slurp half needs a session → HARDWARE-QUEUE.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The gate was >=3 appearance entries and it's met: the root's Theme row
becomes "Look & Feel" (pango-escaped & — the root passes
-markup-rows; matched on *Look*), a new lookfeel submenu carries the
Theme grid (SUPER+T hint), Next wallpaper (SUPER+SHIFT+T hint via the
new generalized hintForAction, which menuHint is now sugar over), and
the Night light toggle moved out of System — which thins by one row.
The root stays at six entries; both direct binds still hit the leaves.
Verified: V0; V1 — rendered menu passes bash -n with the mode, escaped
label and relocated night-light row; visual — tokyo-night 1080p
capture renders "Look & Feel" correctly with hints intact. Submenu
flow queued for a session test (HARDWARE-QUEUE).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nomarchy.launchOrFocus (opt-in, commented template example): each
entry gives a key that FOCUSES the app's existing window
(case-insensitive class match via jq + a "(?i)" focuswindow regex) or
launches it when none is open. One shared nomarchy-focus-or-launch
script; a bind whose command was removed from the suite fires a
"not installed" toast instead of failing silently. The same entries
render into the SUPER+? cheatsheet through prettyKeys — bind and
documentation stay one source. README row added.
Verified: V0; V1 — a scratch downstream with two entries renders both
binds (default command = lowercased class; custom mods/command/desc
honored), the script passes bash -n with a usage guard, and the
cheatsheet carries both rows. Focus behaviour needs a session -> V3
(HARDWARE-QUEUE).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
18 hex retunes, hue-preserving OKLCH minimal raises except where the
upstream palette defines a canonical value: muted lifted to >= 2.0 on
lumon/white/retro-82/everforest (solved), gruvbox (bg4 #7c6f64), nord
(#616e88, the community comment-brightening), catppuccin-latte
(overlay1 #8c8fa1); text-on-surface >= 4.5 via surface nudges
(ristretto darker, latte lighter); accentAlt >= 3.0 (latte, summer-day
darkened); warn >= 2.5 — the bar's battery tint — darkened on the
light bases (latte, rose-pine dawn, summer-day) and flexoki-light's
four status colors moved to their canonical light-mode 600 series.
check-theme-contrast.py now gates all four adopted floors (7 pairings
x 21 themes, green). good/bad stay audit-only — identity themes sit at
2.0-2.3 there by design, so no exemption mechanism was needed. The
design audit's contrast findings drop 20 -> 1 (miasma's earthy `bad`,
kept as identity). Item 28 slice (b) complete.
Verified: V0, checks.theme-contrast green, flake check green,
re-audit. Rendering is V3 -> HARDWARE-QUEUE eyeball entries.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The audit's P1s, fixed at the palette level (items 25/27 previously
patched the consumers around these):
- summer-day: surface was the TEXT color (slate #5c6a72 on cream) and
subtext was the BASE (ratio 1.0, invisible) — now a raised cream
surface #efe7d0 and a slate-teal subtext #6e828a in the theme's
family.
- flexoki-light: surface/overlay/muted were all the text black and
subtext the paper — retuned to canonical upstream Flexoki tones
(ui #E6E4D9, #B7B5AC, tx-2 #6F6E69, base-500 #878580).
- miasma: pure-black surface under a #222 base → raised #2e2e2e.
- kanagawa: surface was sumiInk0 (darker than the bg) → upstream's
raised sumiInk4 #2a2a37.
check-theme-contrast.py gains the adopted rule: subtext on base >= 3.0
(all 21 themes pass), so the invisible-secondary-text class cannot
ship again. Model note in the backlog: `overlay` is a mid-tone role
(catppuccin semantics), not a third bg tier.
Verified: V0 + checks.theme-contrast green (21x3); re-audit shows all
four P1 findings gone; a scratch downstream with summer-day active
builds and the new surface hex lands in the rendered ghostty config.
Remains: V3 four-theme eyeball (HARDWARE-QUEUE) and 28b's P2 floors +
exemption list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>