A dedicated System → VPN flow (nomarchy-vpn) past the wifi picker:
- NetworkManager VPN/WireGuard connections shown ● active / ○ inactive,
toggled up/down on select (networkmanager-group users need no sudo).
- Import a *.conf / *.ovpn via the fd picker → nmcli connection import,
type chosen by extension. networkmanager-openvpn ships system-side
(networking.networkmanager.plugins, mkDefault) so the openvpn type is
available; WireGuard is native to NetworkManager.
- Tailscale block, self-gated on the CLI (= nomarchy.services.tailscale):
read-only status + up/down + exit-node; privileged actions go through a
sudo terminal (the snapshot pattern), no operator wiring.
Waybar custom/vpn shield (nomarchy-vpn-status): self-hides unless a NM
tunnel or Tailscale is up; @good tone; click opens the submenu. Wired
into the generated bar and both summer whole-swaps. Decided import-first;
creation deferred to nm-connection-editor. ROADMAP marked shipped.
Eval + home/system builds green; both scripts pass bash -n. Pending an
on-machine check (live nmcli import/connect + Tailscale paths).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nomarchy.system.autoTimezone (off by default): geoclue + automatic-
timezoned drive /etc/localtime from your location, so travelling to
another zone updates the Waybar clock on its own.
Menu-driven, in-flake state (the night-light / keyboard philosophy):
the flag is settings.autoTimezone in theme-state.json (git-tracked); a
System-menu entry toggles it. Because it's a SYSTEM service — not a user
unit it can start/stop instantly like night-light — the toggle
(nomarchy-autotimezone, run in a terminal) writes the flag --no-switch
then drives `sudo nixos-rebuild` (bakes the service + the time.timeZone
override) plus `home-manager switch` (the Waybar-refresh watcher); both
sides read the one flag.
- modules/nixos/timezone.nix: parses settings.autoTimezone from
nomarchy.system.stateFile (like Plymouth), gates geoclue2 +
automatic-timezoned, and mkForce-nulls time.timeZone — automatic-
timezoned sets it null at normal priority, which collides with the
installer's static value (a hard eval error), so force wins and
reverts cleanly when disabled. Ships the nomarchy-autotimezone toggle.
- modules/home/timezone.nix: a tiny user service watching timedate1's
change signal that reloads Waybar (SIGUSR2) on a real zone change, so
the clock follows live (Waybar captures the zone at construction).
Gated on the same flag via nomarchy.settings.autoTimezone.
- rofi menu: "Auto timezone (on/off)" in the System submenu.
- option + template example + ROADMAP entry; theme.nix seeds the flag.
Eval-verified on (geoclue+daemon on, tz forced null over a static
installer value, watcher present) and off (static tz intact, nothing
extra); home + system both build green. Needs an on-hardware check
(geoclue detection + the SIGUSR2 clock refresh aren't CI-testable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two menu improvements.
Back everywhere: every list menu now ends with a "↩ Back" entry that
returns one level up — power, theme, power-profile, clipboard, files,
capture, not just Tools/System — so you no longer have to Esc out and
reopen to back up. A `back` helper + a shared `BACK` label keep it uniform;
matched exactly so it can't collide with clipboard/filename content. Esc
still quits instantly.
Snapshot fallback: btrfs-assistant 2.2 segfaults on 26.05 (libbtrfsutil
ABI), so `nomarchy-menu snapshot` now launches nomarchy-snapshots instead —
a keyboard-driven snapper browser/restore. snapper is root-only here and
rofi can't run as root under Wayland, so it runs in a terminal via sudo
(one password prompt) and uses fzf to pick: browse/diff (read-only),
restore files (undochange), or roll back (root config only), each behind a
typed-`yes` confirmation — safer than a one-click rofi rollback.
btrfs-assistant stays installed for when nixpkgs fixes it.
Verified: flake check clean; home generation builds and the menu passes
bash -n with all Back + snapshot wiring; nomarchy-snapshots passes
shellcheck (writeShellApplication) in a snapper-enabled system build.
Pending an on-machine check of the restore/rollback paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nomarchy roots are BTRFS, never ZFS, but the zfs module's `true` default for
forceImportRoot emits a warning on every eval/build ("recommended to set it
to false, the new default from 26.11"). Adopt that default early via
mkDefault — silences the noise, future-proofs for 26.11, and a real ZFS-root
downstream can still force it back on.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nixos-hardware "common-*" profiles the installer selects cover the
basics (microcode, the Intel/AMD VA-API media stack, weekly fstrim), and
power.nix adds thermald + power-profiles-daemon. This adds the gap above
them, generically and detected at install time.
New modules/nixos/hardware.nix exposes a vendor-keyed nomarchy.hardware.*
surface — broadly-beneficial bits default ON when the vendor is detected
(opt-out), heavy/experimental bits behind opt-in toggles:
- intel.enable -> GuC/HuC (i915.enable_guc=3); intel.computeRuntime
(opt-in: intel-compute-runtime + vpl-gpu-rt)
- amd.enable -> amd_pstate=active + radeonsi VA-API env; amd.rocm.enable
+ amd.rocm.gfxOverride (opt-in: ROCm HIP/OpenCL)
- fingerprint.enable -> fprintd; fingerprint.pam (opt-in: login + sudo)
- npu.enable (opt-in/experimental) -> the in-kernel driver
(amdxdna/intel_vpu) keyed by vendor; userspace runtime is BYO
hardware-db.sh now detects Intel/AMD, a fingerprint reader (libfprint USB
vendor IDs) and an NPU (Intel VPU / AMD XDNA PCI IDs), emitting NOMARCHY
lines the installer bakes into system.nix — safe defaults active, opt-ins
commented. Audited against the commons to avoid double-setting.
Verified: flake check green; a toggles-on build has amd_pstate=active +
i915.enable_guc=3 in kernel-params and ships fprintd.service; detection
runs correctly on the (AMD Ryzen-AI) dev machine. On-hardware verification
of the AMD/NPU/Intel-compute runtime bits is still pending.
Docs: template commented examples, README option table, ROADMAP status.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Start the opt-in services surface: nomarchy.services.{tailscale,syncthing},
off by default, in modules/nixos/services.nix. Tailscale ships the daemon
(authenticate with `sudo tailscale up`); Syncthing runs as the login user
with its GUI on 127.0.0.1:8384 (overrideDevices/Folders off so GUI-managed
folders survive rebuilds). username is read lazily, only when Syncthing is
on. Commented examples in the downstream system.nix template per the opt-in
convention.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface snapper snapshots from the desktop: `nomarchy-menu snapshot` (in the
SUPER+M picker, self-gated) launches btrfs-assistant, the polkit-aware
browse/diff/restore/rollback UI -- safer than a fat-fingerable rofi rollback
for a destructive root-only op. Shipped system-side gated on
nomarchy.system.snapper.
Also snapshot /home by default (hourly 5 / daily 7 / weekly 4) when it's its
own BTRFS subvolume -- the installer only set up snapper for /. A boot
oneshot creates the required /home/.snapshots subvolume if missing, so
already-installed machines get it too (no disko change).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous nomarchy-hibernate-unlock ran `pkill hyprlock` after a
hibernate resume, but killing a Wayland session-lock client without
releasing the lock trips hyprlock's "go to a tty" crash failsafe -- the
compositor keeps the screen locked for safety. So resume showed a hyprlock
error screen instead of unlocking.
Fix it the right way: never engage the lock before an encrypted hibernate
(the LUKS passphrase at resume is the gate). Replace the post-resume unlock
with a nomarchy-lock-before-sleep unit that takes over hypridle's
before_sleep_cmd: it locks on the RAM-resume sleeps (suspend / hybrid-sleep
/ suspend-then-hibernate) always, and on hibernate.target only when the disk
is unencrypted. idle.nix drops before_sleep_cmd accordingly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The downstream flake at ~/.nomarchy is a live working tree by design —
nomarchy-theme-sync rewrites theme-state.json on every switch — so Nix's
dirty-tree warning fired on every sys-update/home-update and was just
noise. Default nix.settings.warn-dirty to false (mkDefault, overridable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ship `services.fwupd.enable` distro-wide (mkDefault) for firmware updates
via LVFS — the daemon + metadata-refresh timer only, no automatic
flashing, so applying an update stays an explicit `fwupdmgr update`. A
no-op where LVFS sees no devices; overridable natively. Sits with the
other mkDefault desktop services rather than a nomarchy toggle (it's a
single service, like upower).
Also documents the `nomarchy.system.power.*` options in the README table
(missed when the power module landed) and adds a short note on the
fwupd default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a `nomarchy.system.power.*` surface (modules/nixos/power.nix),
replacing the bare `services.upower` (Waybar reporting only) baseline:
- power-profiles-daemon ships by default; switched through polkit (no
root prompt). TLP is the opt-in `backend = "tlp"` for deeper battery
tuning — the two are mutually exclusive (asserted).
- thermald behind `power.thermal.enable` (Intel-only).
- `power.batteryChargeLimit` (e.g. 80): a backend-independent sysfs
oneshot writes charge_control_end_threshold; gated on `power.laptop`.
Switcher + indicator live home-side and self-gate on a battery being
present + powerprofilesctl running, so they hide on desktops and under
TLP — no system->home wiring (like the Waybar battery widget):
- rofi.nix: `nomarchy-menu power-profile` module + a picker entry shown
only on laptops with PPD.
- waybar.nix: first `custom/*` module — click cycles the profile.
Installer writes `power.laptop = true` (battery probe) and
`power.thermal.enable` (GenuineIntel) into the generated system.nix, and
scaffolds the charge limit commented-out.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hypridle locks hyprlock before every sleep -- right for suspend, but
redundant for hibernate: the LUKS passphrase entered at boot already gates
the resume, so the user typed a password twice. Add a nomarchy-hibernate-
unlock systemd unit (WantedBy hibernate.target, After systemd-hibernate.service
=> runs post-resume) that dismisses hyprlock, gated on the disk being LUKS-
encrypted. Suspend (and the RAM-resume phase of suspend-then-hibernate) keep
locking -- they have no passphrase gate; an unencrypted hibernate keeps its
lock too. idle.nix gains a pointer comment; roadmap item marked done.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Setting only services.xserver.xkb.layout moves the graphical session but
leaves console.useXkbConfig unset, so the virtual-console keymap -- and the
systemd initrd the LUKS passphrase prompt runs in -- fall back to US (seen
on a Latitude 5410: X11 Layout gb, VC Keymap unset, LUKS prompt US).
Default console.useXkbConfig + console.earlySetup + boot.initrd.systemd.enable
distro-wide, so xkb.layout alone reaches the console and the encrypted-disk
prompt. Moved the latter two out of plymouth.nix -- they no longer hinge on
the splash being enabled. All mkDefault: an explicit console.keyMap or a
scripted initrd still wins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two branding follow-ups, using the vendored legacy assets:
- fastfetch (modules/home/fastfetch.nix, nomarchy.fastfetch.enable): the
vector logo recolored to the palette accent and rendered to compact
block-art via chafa at build time (so it tracks the theme), fronting a
curated module list. Replaces the oversized legacy ASCII.
- Waybar logo glyph: vendor Nomarchy.ttf (modules/nixos/branding/),
install it via fonts.packages, and switch the summer-day/night menu
buttons to its U+F000 mark with `font-family: Nomarchy` pinned in CSS
(Nerd Fonts also occupy U+F000, so the pin is required). Glyph stored as
the JSON escape for robustness.
Also log a roadmap item for a quality-of-life alias collection.
Verified: font family resolves as "Nomarchy" and the ttf maps U+F000;
both summer jsonc parse; chafa logo builds headless; nix flake check passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Round 2 of distro branding, text half: tuigreet now shows
'Welcome to <distroName>', and users.motd carries a branded banner that
doubles as a cheat sheet for the distro helpers (sys-update, home-update,
nomarchy-theme-sync, SUPER+?). Both key off system.nixos.distroName so the
brand name stays in one place.
Deferred (need an asset / a boot test): ISO splashImage/grubTheme art and
the distroId switch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three quick known-issue fixes:
- yazi: 26.x made the fetcher `group` field required, so the git
prepend_fetchers failed to parse and yazi fell back to presets. Add
`group = "git"` to both entries (the git plugin's setup() only renders
the linemode — the fetcher still needs registering here).
- file-manager: xfce.exo and the three Thunar plugins moved to top-level;
use pkgs.xfce4-exo / pkgs.thunar-{archive-plugin,volman,media-tags-plugin}.
Clears the eval-time deprecation warnings.
- nix-ld: enable programs.nix-ld distro-wide so foreign dynamically-linked
binaries (downloaded tools, npx-fetched claude-code, language servers)
run without patchelf.
Also drops the now-stale claude-code mention from the allowUnfree comment
(the ask module uses npx). nix flake check passes; xfce warnings gone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
zsh is now the default login shell (programs.zsh.enable +
users.defaultUserShell, mkOverride 500 to beat bash.nix's mkDefault;
per-user shell= still overrides). modules/home/shell.nix configures the
interactive experience (nomarchy.shell.enable):
- zsh: completion, autosuggestions, syntax highlighting, big shared
history, autocd.
- starship prompt themed from the palette (a `nomarchy` palette built
from theme-state.json colors).
- bat as cat (theme "ansi" → tracks the terminal/theme palette), eza as
ls (icons + git + dirs-first), zoxide as cd (--cmd cd).
- rg/fd shipped as themselves — deliberately NOT aliased over grep/find
(flag differences surprise).
home.shell.enableZshIntegration = true is the single lever; starship,
eza, zoxide, ghostty and yazi all emit their zsh hooks from it (no
per-module edits). Verified: flake check green, default shell resolves
to zsh, .zshrc carries the starship/zoxide/eza/yazi hooks + aliases,
starship palette renders, all tools in the live ISO closure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The media keys called wpctl/brightnessctl directly with no visual
feedback — changing volume showed nothing on screen. Now they drive
swayosd-client, which performs the action AND shows a themed OSD.
- modules/home/osd.nix: services.swayosd, style.css generated from the
palette (base bg, accent progress/border); nomarchy.osd.enable.
- hyprland media binds → swayosd-client (--output-volume raise/lower/
mute-toggle, --input-volume mute-toggle, --brightness raise/lower).
- modules/nixos: services.udev.packages = [ swayosd ] installs the
backlight rule (chgrp video + g+w) so brightness works for video-group
users without root (the installer/live user is in video).
swaync is unaffected (it was already running — this was purely the
missing OSD). Verified: flake check green, swayosd.service bound to
graphical-session.target, hyprland config verifies, swayosd in the live
ISO closure. On-screen rendering needs a real session to confirm.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Legacy shipped only Thunar (and a stray nautilus extension, mid-migration).
This pairs a keyboard-driven TUI flagship that fits the distro's identity
with the GUI half for point-and-click + the "open folder" handler.
yazi (modules/home/yazi.nix, nomarchy.yazi.enable, SUPER+E, `y` shell
wrapper cd's on exit): themed from theme-state.json (mgr/mode/status
mapped from the palette; merges over yazi's defaults so it tracks the
theme) with a curated, correctly-wired plugin set —
full-border, git (setup + prepend_fetchers), smart-enter (l/Enter),
chmod (cm), mount (M), compress (caa), mediainfo (audio/subtitle only —
images/videos keep native thumbnails), glow (markdown previews).
Preview/tooling deps: ffmpegthumbnailer, poppler-utils, p7zip, jq, fd,
ripgrep, fzf, chafa, mediainfo, glow.
Thunar (modules/nixos/file-manager.nix, nomarchy.system.fileManager.enable):
GTK file manager (Stylix-themed) + archive/volman/media-tags plugins +
gvfs/tumbler/udisks2 backends + thumbnailers + exo. udisks2 also backs
yazi's mount plugin.
Verified: flake check green, HM generation builds (yazi TOML/init.lua
render, all 8 plugins resolve), every package present in the live ISO
closure (offline install draws from it — no source-build leak).
Not verified: yazi's runtime preview/plugin behaviour needs a real
session (TUI; can't drive in CI here).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Plymouth boot splash ported from the legacy branch (modules/nixos/
plymouth/): logo + eased progress + LUKS entry, background tinted from
theme-state.json via the new nomarchy.system.stateFile (wired by
mkFlake/lib.nix; null → Tokyo Night fallback). Default on; OFF on the
live ISO (boot-message visibility on the install medium). Pulls
boot.initrd.systemd, which also drives the keyboard-at-LUKS feature.
- system.nixos.distroName = "Nomarchy" (os-release PRETTY_NAME,
systemd-boot entries, ISO menu label). distroId left "nixos" (feeds
DEFAULT_HOSTNAME + upstream isNixos checks — roadmapped).
- nixpkgs.config.allowUnfree distro-wide (here + both import-nixpkgs
sites) — unblocks claude-code for the menu's ask-Claude module.
- systemd-boot.configurationLimit = 10 so entries don't fill the ESP.
- Live ISO: nomarchy.idle.enable = false — hypridle was suspending the
VM mid-install (the install-hung regression); installed systems keep it.
- flake.nix offline pins (verified 0-leak via a foreign-identity
gap-analysis probe): the repo's own standalone HM gen + inputDerivations,
mustache-go + stdenv (stylix re-renders base16 per switch), microcode-amd/
intel (enableRedistributableFirmware activated updateMicrocode →
source-build cascade), buildEnv's builder.pl, findXMLCatalogs, and the
representativeInstall mirror (xkb/initrd-systemd/microcode).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nixpkgs.config.allowUnfree in the system module (covers the live ISO
via useGlobalPkgs and every mkFlake machine) plus the two explicit
`import nixpkgs` sites (repo + lib.nix) so the standalone HM desktop
sees the same package set. Unblocks claude-code for the menu system's
ask-Claude module, vendor drivers, etc. Opt out with
`nixpkgs.config = lib.mkForce { allowUnfree = false; }`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Roadmap items 1+2 plus the issues found testing on a Latitude 5410:
- Ship the 10 most popular Nerd Fonts by default (iosevka swapped for
mononoki: 1.1 GB vs 27 MB) and warn from nomarchy-theme-sync when a
configured fonts.mono/fonts.ui family isn't installed (fc-match) —
fontconfig substitutes silently otherwise.
- hardware.enableRedistributableFirmware: installed systems shipped NO
firmware blobs (wifi/SOF audio/BT) — nixos-generate-config only emits
microcode lines referencing this flag, it never sets it.
- Live ISO wifi: networking.wireless.enable = mkForce false killed
NetworkManager's supplicant — since 26.05 the NM module drives its
wifi backend THROUGH networking.wireless (dbusControlled). Devices
vanished from nmtui with iwlwifi loaded and no rfkill block.
- Hyprland 0.55: launch sessions via start-hyprland (watchdog; bare
binary warns), add the new gesture keyword (workspace_swipe is gone —
touchpads had no gestures at all), media keys via wpctl/bindel/bindl
plus the missing mic/play/next/prev binds.
- Offline theme switching: pin mustache-go + stdenv + the repo's own
standalone HM generation (incl. home-files inputDerivation) into the
ISO — stylix re-renders base16 templates per switch and an offline
`apply` cascaded into building stdenv from source (1107 drvs).
Verified with tools/vm/gap-analysis.py: 17 config drvs, zero fetches.
- Stylix: track release-26.05 (kills the HM version-skew warning and
the stale home-manager follows), lock updated.
- Roadmap: swaync (no notification daemon ships today).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- LUKS2 is the installer default; in exchange the generated config sets
the new nomarchy.system.greeter.autoLogin (greetd initial_session) —
the disk passphrase already gates the machine.
- @snapshots subvolume + nomarchy.system.snapper.enable: hourly/daily
timeline snapshots of / and the nixos-rebuild-snap helper, ported from
the previous iteration (3bdfc35), guarded to no-op on non-BTRFS roots.
- @swap subvolume with a swapfile sized to RAM by default (disko
mkswapfile handles NOCOW); the installer computes the resume offset
and wires boot.resumeDevice + resume_offset for hibernation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>