Commit Graph

21 Commits

Author SHA1 Message Date
ac3b75b018 feat(template): ship Chromium by default; record product decisions
All checks were successful
Check / eval (push) Successful in 2m49s
- home.packages: chromium active; mime → chromium-browser.desktop
- Decisions: markdown docs stay in-repo; PPD default confirmed
- Formatter + zram still open (explained in session, not closed)

V0: flake check --no-build green.
2026-07-10 14:37:52 +01:00
910f357f08 fix(desktop): hardware findings — charge limit, polkit ws, bar deps
All checks were successful
Check / eval (push) Successful in 3m3s
Latitude 5310 QA:
- Clock tooltip: drop empty {calendar} popup; plain date+zone
- Charge limit: restart oneshot via polkit + dual write/delay for
  Dell unplug race; toast verifies sysfs; looser menu match
- pwvucontrol ships with waybar (right-click volume)
- Print/region→clipboard toasts success
- Polkit (and pinentry) open on current workspace + stayfocused

V0: flake check --no-build green. V3: retest A3/A4/B1/tooltip/polkit.
2026-07-10 13:29:44 +01:00
d547393e7b fix(desktop): unfree CLI default, bar icon spacing, unified clock
All checks were successful
Check / eval (push) Successful in 3m0s
Hardware findings on Latitude: nix-shell blocked unfree; whole-swap
bars collided icon+percentage; clock needed calcurse + one module.

- Export NIXPKGS_ALLOW_UNFREE=1 + ~/.config/nixpkgs/config.nix
- Mono Nerd face + trailing spaces on battery/volume icons (all bars)
- Single clock `HH:MM · Day DD Mon`; calcurse ships with waybar
- V3 queue entries for laptop re-check

Verification: V0 — nix flake check --no-build green; V2/V3 pending on
session (user-visible bar + CLI unfree).
2026-07-10 12:58:37 +01:00
Bernardo Magri
caaac88da9 feat(install): copy templates/downstream and patch install values
All checks were successful
Check / eval (push) Successful in 3m4s
Make the downstream template the single source of truth for machine
flakes: nomarchy-install copies flake/system/home/theme-state and
patch-template.py only fills hostname, user, keyboard, detected
hardware, snapper, resume, and password. Install and flake-init users
now share the same commented opt-ins and starter home.packages.

Also: BACKLOG boreal-as-default proposal; installer audit notes;
HARDWARE.md from prior work if uncommitted.
2026-07-09 09:23:50 +01:00
Bernardo Magri
be8d8a7d9b feat(waybar): open a calendar (calcurse) on the clock click
All checks were successful
Check / eval (push) Successful in 2m54s
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>
2026-07-08 20:19:30 +01:00
28a28e05d3 feat(waybar): right-click volume opens a floating pwvucontrol mixer
All checks were successful
Check / eval (push) Successful in 2m55s
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>
2026-07-07 22:31:00 +01:00
Bernardo Magri
edd0bd38ce feat(display): per-profile workspace→output pins (item 15c)
All checks were successful
Check / eval (push) Successful in 3m0s
Lock bump / bump (push) Successful in 2m53s
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>
2026-07-05 23:09:14 +01:00
Bernardo Magri
8d54eecd67 feat(hyprland): launch-or-focus binds (item 17)
All checks were successful
Check / eval (push) Successful in 3m4s
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>
2026-07-05 20:56:01 +01:00
Bernardo Magri
1921839e0e feat(displays): hotplug auto-switch for display profiles (item 15b)
All checks were successful
Check / eval (push) Successful in 2m57s
nomarchy-display-profile gains `match <outputs>`: an exact set match
wins, else the largest profile whose named outputs are all connected;
any tie prints nothing — the watcher must never flap between ambiguous
layouts. nomarchy-display-profile-watch (exec-once when profiles are
declared, the keyboard-watcher poll pattern — session units race
Hyprland IPC on relogin) reacts to output-set CHANGES only, reads
settings.displayProfileAuto from the live state each time (the menu's
new Auto-switch row toggles it instantly, no rebuild), and applies via
the tool — so an auto-pick persists a concrete profile that the next
rebuild bakes. A separate boolean rather than an "auto" pseudo-profile
for exactly that bake semantics.

Verified: V0 (flake check); V1 — a scratch 4-profile downstream builds;
tool + watcher pass bash -n; the match matrix exercised end-to-end:
three exact picks, an unambiguous-superset pick, a tie -> none, a
no-fit -> none; the watcher is exec-once'd in the rendered config; the
menu renders the Auto-switch row. Remains: V3 real dock/undock
(HARDWARE-QUEUE, rides the slice-a entry). Slice c (workspace binding)
stays, tagged optional.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 18:14:07 +01:00
Bernardo Magri
9df18261f9 feat(displays): display profiles — docked/undocked switching (item 15a)
All checks were successful
Check / eval (push) Successful in 3m4s
nomarchy.displayProfiles: named layouts for the same outputs, each a
list of nomarchy.monitors-style entries. The active profile lives in
the in-flake state (settings.displayProfile) on the night-light
pattern: nomarchy-display-profile apply <name> fires the baked hyprctl
rules instantly and writes the state with --no-switch; the next rebuild
bakes the profile's entries over nomarchy.monitors whole-by-name.
Monitor-rule composition is extracted to pure monitor-rules.nix
(renderer + 3-layer resolve, incl. a disable-guard so a stale menu
resolution pick can't resurrect a profile-disabled panel, and junk
state degrading to base config instead of an eval error) — because a
writeText/toFile state fixture is unreadable at flake-check eval time,
the new checks.display-profiles unit-tests the pure function directly.
Menu: System › Display gains a self-gated "Profiles ›" row (●/○ active
mark, Base layout to clear); commented template example + README row.

Verified: V0 (flake check, forcing the new check's asserts); V1 — a
scratch downstream through lib.mkFlake builds: the generated tool
passes bash -n with correct rules (disable/vrr/float scale), the baked
hyprland.conf shows the exact expected overlay, the menu renders, and
list/usage smoke-test clean. Remains: V3 live switching on a dock
(HARDWARE-QUEUE). Slices b (hotplug auto-switch) + c (workspace
binding) stay in item 15.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 17:52:19 +01:00
Bernardo Magri
774bdad6e4 feat(desktop): viewers (zathura+imv) + xdg-mime defaults (item 8)
All checks were successful
Check / eval (push) Successful in 2m52s
The complete-workstation gap: no PDF/image viewer shipped and nothing
set mime defaults, so 'open a photo' fell to GIMP. Two new default-on
toggles: nomarchy.viewers (programs.zathura — Stylix themes it, target
added to the explicit list — plus imv) and nomarchy.mime (mkDefault
xdg.mimeApps: pdf→zathura, image→imv, av→mpv, text→code, dir→thunar;
html/http(s)→firefox as inert entries that only activate when a
browser is installed — the ship-a-browser Decision stays open, now
smaller). Associations for absent apps are skipped by GIO, so the
whole thing degrades as the user curates the suite. Deviation from
the backlog text: viewers are a module toggle, not template package
lines — zathura's theming needs its HM module (the real-config
boundary of the toggle discipline).

V1: template-home generation asserted — mimeapps.list rendered, themed
zathurarc, binaries in home-path. V3 open-a-file smoke queued.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 20:06:45 +01:00
Bernardo Magri
1e4427f6af docs(webcam): tuning tools in the app-suite template + libcamera gap filed
All checks were successful
Check / eval (push) Successful in 3m2s
- templates/downstream/home.nix: commented "Webcam tuning" entries
  (cameractrls, v4l-utils) — bare packages, so template not toggle,
  per the option-surface rule; rarely needed since the IR-hide covers
  the common dual-sensor case.
- agent/BACKLOG.md PROPOSED: the portal/Flatpak camera picker still
  lists the internal IR sensor (libcamera path, untouched by the v4l2
  rule) — three options laid out, recommending document-only until a
  T14s-style machine is available to test a libcamera-side rule.

Closes BACKLOG NOW#7. Verified: V0 (flake check green; template still
evaluates through mkFlake).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 10:13:50 +01:00
Bernardo Magri
aed41793f8 feat(keyboard): per-device layout memory in-flake (no ~/.local/state)
Phase 2 of the in-flake-state philosophy, mirroring night-light: the
nomarchy-keyboard-watch daemon now remembers per-device layouts in the
git-tracked state file (settings.keyboard.devices) instead of
~/.local/state/nomarchy/keyboard-layouts.

- Reads the LIVE working-tree map (theme-sync get → jq) so a pick this
  session is honoured at once; writes instantly with --no-switch (no
  rebuild). Writes the whole map back at the dot-free parent path
  (read-modify-write) so a device name with a dot can't corrupt the
  tool's dotted set-path (Hyprland only sanitises spaces→-).
- Graduation: nomarchy.keyboard.devices now mkDefault-merges entries
  from settings.keyboard.devices, so each remembered device becomes a
  generated Hyprland device{} block on the next rebuild (reproducible,
  hotplug-applied). A hand-written keyboard.devices.<name> still wins;
  once baked, the watcher's is_declared check makes it step back.
- theme.nix seeds settings.keyboard.devices = {} (sparse state still
  evaluates); options/template descriptions updated; ROADMAP marked done.

Eval-verified (graduation + mkDefault precedence) and the set/get
writer round-trips. Still needs the on-hardware hotplug re-verify (the
picker path isn't testable in CI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 09:18:33 +01:00
Bernardo Magri
685126ab47 feat(nightlight): menu-driven, in-flake on/off (no ~/.local/state)
Night light is off by default and configured entirely through the menu,
writing into the downstream flake instead of ~/.local/state — so the
choice is git-tracked and reproducible across a clone+rebuild.

Two flags under a new settings.* section of the state file (exposed as
the nomarchy.settings option):
- settings.nightlight.installed — sticky, gates the hyprsunset unit;
  nomarchy.nightlight.enable mkDefault-reads it. First enable from the
  menu rebuilds to create the unit (the one accepted rebuild).
- settings.nightlight.on — runtime on/off, toggled instantly
  (theme-sync set --no-switch + systemctl), no rebuild. An ExecCondition
  reads the live flag at session start so an off survives reboot;
  splitting it from the sticky flag means a later unrelated rebuild
  never undoes an instant-off (no decay).

Drops the ~/.local/state/nomarchy/nightlight-off marker and the
ConditionPathExists hack. theme-sync set now skips the wallpaper
re-apply for non-wallpaper keys, and its rebuild notifications are
generic ("changes" not "theme").

First cut of the broader principle — any user-settable config gets a
menu writer that lands it in the flake; no state outside the checkout.
Docs (README §4, ROADMAP, template) updated to reflect it.

Eval- and round-trip-verified; on-hardware check pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 20:24:58 +01:00
Bernardo Magri
6a4af69b0f feat(updates): passive update-awareness indicator + notification
Add opt-in nomarchy.updates (modules/home/updates.nix): a nomarchy-updates
checker on a systemd user timer (interval, default daily) that surfaces a
Waybar indicator + a notification when updates are available, without ever
changing anything (you still run sys-update / flatpak update).

It counts:
- flake inputs behind upstream — only the flake's DIRECT inputs (root.inputs:
  nixpkgs, the Nomarchy input, home-manager, stylix…), not the transitive
  closure, via `git ls-remote` vs the locked rev. Offline → skipped, never a
  false alarm.
- Flatpak updates, when the flatpak CLI is present (.flatpak, gated on
  services.flatpak being on) — Bernardo's suggestion.

Waybar custom/updates self-gates (hidden until the timer finds something;
accent "󰚰 N", signal 9 for instant refresh), in the generated bar and both
summer whole-swaps. The notification fires only when the count grows, so a
daily timer doesn't nag. Click → the upgrade flow in a terminal (sys-update /
flatpak update, each confirmed). nomarchy-updates ships always on PATH and
self-gates so the static whole-swap bars can exec it even when the feature
is off.

Verified: flake check clean; home generation builds; the jq direct-input
filter + status self-gate exercised against the real flake.lock; script
passes bash -n. Pending an on-machine check (ls-remote/notify/timer need a
live session).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:59:09 +01:00
Bernardo Magri
964a5c98b7 feat(services): openrgb + restic toggles; close out the opt-in services item
Finishing the four remaining "opt-in services" candidates — but two of
them aren't service-shaped, so the package-vs-toggle principle applies:

  - Nextcloud client  → a bare tray app; already in the app-suite menu,
                        not a service.
  - WireGuard         → NetworkManager (on distro-wide) imports .conf
                        tunnels natively, so there's no daemon to "just
                        enable". Only the wg/wg-quick CLI is missing →
                        wireguard-tools added to the app-suite menu.

The two that ARE config-backed become nomarchy.services.* toggles:

  - openrgb → services.hardware.openrgb (daemon + device udev rules).
  - restic  → a small scaffolded surface (repository / passwordFile /
              paths) over services.restic.backups: daily timer, 7/4/6
              retention, --exclude-caches, repo auto-init. Asserts that
              repository + passwordFile are set when enabled. passwordFile
              is typed `str`, not `path`, so a flake-relative secret can't
              be copied into the world-readable store.

README option table and ROADMAP (services now "Seventeen shipped";
cloud-sync / networking / backup / devices areas updated) + the downstream
system.nix examples. Both branches eval-verified; the restic assertions
confirmed firing when repo/password are unset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 21:02:20 +01:00
Bernardo Magri
c45fb80b79 feat(services): full optional app menu + 7 more opt-in service toggles
Make the whole workstation menu available, all off/commented by default.

home.nix: the bare GUI apps become a categorized commented menu (~50
suggestions across browsers, comms, office, notes, code, graphics, A/V,
media, gaming, files/sync, security, system, local AI) — uncomment to add.

services.nix: the members that need system config (not just a package)
become opt-in nomarchy.services.* toggles, each with a commented example
in the downstream system.nix:
  - docker     → rootful Docker + user in docker group; asserts against the
                 podman docker-compat (both provide the `docker` command)
  - kdeconnect → programs.kdeconnect (opens phone-pairing ports)
  - gamemode   → Feral GameMode daemon
  - adb        → android-tools (programs.adb was removed; systemd ≥258 does
                 the device uaccess udev rules, so no group needed)
  - wireshark  → Qt GUI + user in wireshark group (capture without root)
  - ollama     → local LLM runtime on 127.0.0.1:11434
  - printing   → CUPS + Avahi/mDNS network printer discovery

README option table and ROADMAP (services item now "Fifteen shipped";
local-AI / containers / gaming / devices areas marked) updated. All seven
branches eval-verified with the toggles forced on; the docker/podman
assertion confirmed firing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:52:38 +01:00
Bernardo Magri
0c668c2eb1 feat(apps): starter workstation app suite + steam/libvirt/obs services
The "default application suite" roadmap item, but deliberately NOT a
nomarchy.apps.* option surface: a bare package install has no config to
put behind a toggle, so a thin `mkIf x { systemPackages = [p]; }` only
reinvents what a package list already gives. Instead the suite is a
curated home.packages list in templates/downstream/home.nix (extending
the existing `# firefox` convention) — active staples (libreoffice,
vscode, gimp, inkscape, mpv, amberol) plus commented suggestions. The
opt-out is deleting a line; it also keeps the apps out of the live ISO
automatically (the ISO never scaffolds from the template).

The members that DO need system config become nomarchy.services.* opt-in
toggles instead (config behind the switch, like the existing services):
  - steam   → programs.steam (32-bit stack, controller udev, RP ports)
  - libvirt → libvirtd + virt-manager, login user added to libvirtd group
  - obs     → obs-studio + a v4l2loopback virtual camera (exclusive_caps=1)
              selectable as a webcam in Zoom/Teams

README option table, ROADMAP (services item now "Eight shipped"; suite
item marked done with the no-surface rationale) and the downstream
system.nix examples updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:45:10 +01:00
Bernardo Magri
8d3911de1a docs(template): ship opt-in features as commented examples downstream
Convention: an off-by-default feature that needs nomarchy.* settings in the
downstream files should appear commented-out in templates/downstream/{home,
system}.nix, so a new install enables it by uncommenting + tweaking rather
than hunting the docs for the option name. Apply it now: night light,
nomarchy.monitors, per-device keyboard layouts (home.nix) and power
management (system.nix). Also fix the stale keyboard.layout note
(console/LUKS follow xkb automatically now). Documented in README S6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 16:53:13 +01:00
Bernardo Magri
6763bef73e fix(install): pre-activation, writable home.nix, keyboard/locale selection
- Pre-activation failure ("desktop pre-activation failed"): the in-chroot
  HM build hard-coded `--option substituters ""`, which only works on
  OFFLINE installs (where the ISO store is copied in). Online installs
  (now common — wifi works) had no pins and built from source. Fix: build
  the generation in the live env (its store always has the pins), nix copy
  the closure to the target, chroot only activates. In-chroot build kept
  as fallback. Uses path: (not git+file:) to sidestep libgit2 ownership.
- Read-only home.nix: templates come out of the store mode 0444 and cp
  preserves it — chmod -R u+w after staging so the user can edit it.
- Keyboard + locale selection: gum prompts (localectl layouts/variants +
  curated UTF-8 locale list) and NOMARCHY_LOCALE/KB_LAYOUT/KB_VARIANT for
  unattended. One choice flows everywhere — services.xserver.xkb (source
  of truth) + console.useXkbConfig (tty/greeter) + boot.initrd.systemd
  (so the LUKS passphrase prompt uses the layout; script initrd can't) +
  the generated home.nix's nomarchy.keyboard.* for the Hyprland session.
- test-install.sh: NOMARCHY_OVMF env override for sandboxed OVMF paths.

Verified end-to-end in QEMU: offline LUKS install completes, boots to a
themed desktop (no autogenerated-config banner), Plymouth renders the LUKS
prompt on the theme-tinted background.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 07:38:31 +01:00
Bernardo Magri
f211ef0d09 feat: Nomarchy ground-up rewrite on NixOS 26.05
Full replacement of the previous iteration, rebuilt around three ideas:

- Pure evaluation: theme-state.json lives inside the flake and is read
  via the nomarchy.stateFile option — no --impure, ever.
- All-Home-Manager theming: `nomarchy-theme-sync apply` writes the JSON
  and runs `home-manager switch`; every theme change is one atomic,
  rollbackable generation. Wallpaper (swww) is the sole runtime piece.
- Flat, downstream-first layout: modules/{nixos,home} with one
  options.nix each, exported as nixosModules/homeModules + overlay +
  flake template; system (nixos-rebuild) and desktop (home-manager
  switch) rebuild paths are fully split.

Ships 21 themes imported from the previous iteration (palettes,
wallpapers, btop themes, six whole-swap Waybar identities), Stylix for
the GTK/Qt/cursor long tail, a live ISO target with offline theme
switching, and docs/TESTING.md with the QEMU verification workflow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:59:13 +01:00