Bernardo Magri 00f5311499 feat(power): laptop power management (power-profiles-daemon + TLP)
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>
2026-06-14 17:35:42 +01:00

Nomarchy

The rock-solid reproducibility of NixOS 26.05. The out-of-the-box polish of Omarchy/Omakub. One JSON file rules the look of the entire desktop; every theme change is a Home Manager generation — atomic, rollbackable, never partial.

┌──────────────────────────────────────────────────────────────────────────┐
│                  theme-state.json  (single source of truth)              │
│                  lives INSIDE your flake checkout, git-tracked           │
└───────────────────────────────────┬──────────────────────────────────────┘
                                    │
        nomarchy-theme-sync apply gruvbox                                   
            1. merges the preset into the JSON (atomic write)               
            2. runs `home-manager switch` (no sudo, no system rebuild)      
                                    │
                                    ▼ pure read (nomarchy.stateFile)
┌──────────────────────────────────────────────────────────────────────────┐
│  Home Manager bakes EVERYTHING into one read-only generation:            │
│    Hyprland (colors/gaps/borders)      Waybar (palette or whole-swap)    │
│    Ghostty (full ANSI palette)         btop (asset or generated)         │
│    Stylix → GTK, Qt, cursors, fonts                                      │
└───────────────────────────────────┬──────────────────────────────────────┘
                                    ▼
              wallpaper via awww (the one runtime piece:                    
              applied post-switch + at session start, `bg next` cycles)     

1. Layout

Flat on purpose. Two module trees, one options file each, no hidden layers.

.
├── flake.nix                      # inputs + the downstream API (exports below)
├── lib.nix                        # nomarchy.lib.mkFlake — one-call downstream wrapper
├── theme-state.json               # ★ THE single source of truth (git-tracked!)
├── themes/                        # 21 presets: <slug>.json + optional <slug>/ assets
│   ├── nord.json                  #   palette (required, works alone)
│   └── nord/                      #   assets (optional, fixed filenames)
│       ├── backgrounds/           #     wallpapers (auto-picked, SUPER+SHIFT+T cycles)
│       ├── btop.theme             #     hand-made config drop (else generated)
│       └── waybar.css             #     whole-swap: replaces the generated bar style
├── modules/
│   ├── nixos/                     # the distro, system side
│   │   ├── default.nix            #   Hyprland session, Pipewire, greetd, fonts
│   │   ├── options.nix            #   nomarchy.system.* toggles
│   │   ├── plymouth.nix           #   boot splash, tinted from the JSON
│   │   └── file-manager.nix       #   Thunar GUI + gvfs/tumbler/udisks2
│   └── home/                      # the distro, user side
│       ├── default.nix            #   entry point
│       ├── options.nix            #   nomarchy.* option surface
│       ├── theme.nix              #   JSON ingestion + wallpaper hook
│       ├── stylix.nix             #   GTK/Qt/cursors/fonts from the same JSON
│       ├── hyprland.nix           #   all JSON-driven
│       ├── waybar.nix
│       ├── ghostty.nix
│       ├── btop.nix
│       ├── rofi.nix               #   launcher + nomarchy-menu (power, clip)
│       ├── swaync.nix             #   notifications, same JSON
│       ├── idle.nix               #   hyprlock + hypridle, same JSON
│       ├── yazi.nix               #   flagship TUI file manager + plugins
│       ├── osd.nix                #   swayosd volume/brightness OSD
│       └── shell.nix              #   zsh + starship + bat/eza/zoxide
├── hosts/
│   ├── default/                   # reference machine (thin: boot, user, hostname)
│   └── live.nix                   # bootable live ISO (try the distro, no install)
├── pkgs/
│   ├── nomarchy-theme-sync/       # state writer + rebuild dispatcher (Python)
│   └── nomarchy-install/          # live-ISO installer (gum + disko + mkFlake)
├── templates/downstream/          # `nix flake init -t` starter for users
├── docs/TESTING.md                # how to verify changes (incl. AI-agent rules)
├── docs/OVERRIDES.md              # how downstream users override defaults
└── tools/                         # maintainer-only
    ├── import-palettes.py         #   converts old-distro themes → JSON + assets
    ├── test-live-iso.sh           #   build the ISO + boot it in QEMU
    ├── test-install.sh            #   full offline-install regression in QEMU
    └── vm/                        #   headless-VM helpers (QMP keys, VNC shots,
                                   #   offline-pin gap analysis)

Rule of thumb: modules/ is the distro (reusable, no machine specifics), hosts/ is a machine, themes/ is data, pkgs/ is code, tools/ is maintainer-only. If a new file doesn't obviously belong to one of those, it probably shouldn't exist.

2. Try it first (live ISO)

Boot the full desktop from a USB stick or VM without installing anything:

nix build .#nixosConfigurations.nomarchy-live.config.system.build.isoImage
# → result/iso/*.iso — dd to a stick, or boot it in QEMU:
tools/test-live-iso.sh

The live session auto-logs-in, seeds the flake at ~/.nomarchy, and pins the locked inputs into the ISO store — so theme switching (including the home-manager switch it triggers) works offline, exactly like on an installed system. Verification checklist: docs/TESTING.md.

Like what you see? nomarchy-install (in a terminal) walks you through installing to disk: pick a disk, LUKS2 full-disk encryption by default (in exchange the desktop logs in passwordless — the passphrase already gates the machine), user + hostname + timezone, hardware autodetection (DMI → nixos-hardware profile), a hibernation-ready swapfile sized to RAM, then disko partitions (GPT + ESP + BTRFS subvolumes incl. @snapshots — snapper timeline snapshots are on) and nixos-install runs — without a network when the ISO was built from a clean tree (the target's flake.lock is composed from the rev the ISO carries). The installed machine gets the standard downstream layout: the flake at ~/.nomarchy (/etc/nixos symlinks to it), one mkFlake call, your system.nix/home.nix. First boot lands in the fully themed desktop — the installer pre-activates the Home Manager generation. UEFI only for now.

3. Using Nomarchy on your machine (downstream)

Nomarchy is consumed as a flake input — you never fork or edit this repo:

mkdir my-machine && cd my-machine
nix flake init -t "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1"

You own two files day-to-day: system.nix and home.nix (plus theme-state.json, written by the CLI). Your flake.nix is set up once — later by the installer — and never hand-edited; it's a single call:

outputs = { nomarchy, ... }:
  nomarchy.lib.mkFlake {
    src = ./.;
    username = "me";
    hardwareProfile = "framework-13-7040-amd"; # optional, nixos-hardware name
  };
mkFlake arg Default Purpose
src — (required) Your flake directory (./.)
username — (required) Login name; flows into system.nix and names the HM config
hardwareProfile null One nixos-hardware module name, or a list of them (pinned + tested by Nomarchy; unknown names fail with suggestions)
system "x86_64-linux" Platform

(Power users can skip mkFlake and wire nixosModules.nomarchy / homeModules.nomarchy / overlays.default by hand — the wrapper is sugar.)

Two deliberately separate rebuild paths:

sudo nixos-rebuild switch --flake .#default   # system: rare
home-manager switch --flake .#me              # desktop: every theme change, no sudo

Day-to-day you'll use the shipped shortcuts instead:

sys-update    # nix flake update + system rebuild (BTRFS snapshot first when available)
home-update   # home-manager switch (no flake update, no sudo)

Order matters when pulling distro updates. home-update does not touch the lock — it rebuilds the desktop against the current flake.lock. A new Nomarchy revision (new keybinds, theming, modules) arrives only when the lock is updated, which sys-update does (nix flake update). So to pull an update that affects the desktop layer: run sys-update first (updates the lock + rebuilds the system), then home-update (re-applies the desktop against the new lock). Doing them in the other order rebuilds the desktop against the old inputs and silently skips the new home-side changes. After a home-side keybind/config change, also hyprctl reload (or relogin) so the running session re-reads it.

Override anything via the nomarchy.* surface or plain NixOS/HM options: appearance (gaps/colors/fonts) changes through nomarchy-theme-sync, behaviour (input/misc/monitor/chrome) is mkDefault so a plain home.nix assignment wins, and bind/exec-once lists concatenate. Full guide with examples: docs/OVERRIDES.md.

Option Default Purpose
nomarchy.stateFile — (required) Path to your theme-state.json
nomarchy.terminal "ghostty" Terminal for keybinds and $TERMINAL
nomarchy.keyboard.layout "us" XKB layout for the Hyprland session (installer writes it; pairs with xkb + console.useXkbConfig in system.nix)
nomarchy.keyboard.variant "" XKB variant for the session
nomarchy.hyprland.enable true Nomarchy's Hyprland config
nomarchy.waybar.enable true Nomarchy's Waybar
nomarchy.rofi.enable true Themed rofi launcher + nomarchy-menu dispatcher
nomarchy.swaync.enable true swaync notifications, themed
nomarchy.idle.enable true hyprlock + hypridle (idle lock 5 min, display off 10, suspend 30)
nomarchy.yazi.enable true yazi TUI file manager, themed + curated plugins
nomarchy.osd.enable true swayosd on-screen display for volume/brightness/mute
nomarchy.shell.enable true zsh + starship prompt + bat/eza/zoxide (zsh is the default login shell)
nomarchy.ghostty.enable true Nomarchy's Ghostty
nomarchy.btop.enable true btop with per-theme colors
nomarchy.stylix.enable true GTK/Qt/cursor theming
nomarchy.themesDir Nomarchy's themes/ Where per-theme app overrides are probed
nomarchy.system.plymouth.enable true Branded boot splash, background from the theme JSON (recolors on system rebuilds)
nomarchy.system.fileManager.enable true Thunar GUI + gvfs/tumbler/udisks2 (the "open folder" handler)
nomarchy.system.greeter.enable true greetd/tuigreet
nomarchy.system.audio.enable true Pipewire stack
nomarchy.system.bluetooth.enable true Bluetooth + blueman

4. How theming works

Pure JSON ingestion

The trap with "read a mutable file from Nix" is pure evaluation: flakes cannot read arbitrary $HOME paths without --impure (the old prototype required it — never again). Nomarchy's convention: the state file lives inside the consuming flake and is wired via nomarchy.stateFile = ./theme-state.json;. Reading it is pure — it's flake source. It must be git-tracked (nomarchy-theme-sync runs git add --intent-to-add after every write as a safety net).

One change = one generation

nomarchy-theme-sync apply <theme> merges the preset into the JSON and runs home-manager switch (override the command with $NOMARCHY_REBUILD, or pass --no-switch to only write). Everything is baked: Hyprland, Waybar, Ghostty, btop, and — via Stylix, mapped onto base16 roles — GTK, Qt, cursors and fonts. No runtime patching means no partial states, and home-manager generations is also your theme history. Waybar even restyles in place: it re-reads style.css when the symlink flips.

The wallpaper is the one runtime piece (awww — nixpkgs' swww — is imperative; nothing in Nix consumes the path): applied at session start and after every switch via a tiny activation hook, cycled instantly with bg next.

Per-theme app assets (themes/<slug>/)

Recoloring covers 95% of theming; the rest is one optional assets directory per theme — a single place to look, unlike the old distro's split:

Asset Mechanism
backgrounds/ wallpapers; empty wallpaper in the state means "first one"; bg next cycles
btop.theme baked into the generation (generated from the palette when absent)
waybar.css whole-swap: replaces the generated bar style entirely (probed at eval time, self-contained)
waybar.jsonc whole-swap for the bar layout (must be plain JSON)
rofi.rasi whole-swap: replaces the generated launcher/menu theme entirely

Six ported themes ship a waybar.css identity (catppuccin, lumon, nord, retro-82, summer-day, summer-night). Custom user themes can live in $NOMARCHY_PATH/themes/ (preset lookup) and nomarchy.themesDir (eval-time asset probe).

5. Day-to-day

nomarchy-theme-sync list               # 21 presets (nord, gruvbox, rose-pine, …)
nomarchy-theme-sync apply kanagawa     # whole desktop, one generation (~a switch)
nomarchy-theme-sync set ui.gapsOut 16  # tweak one knob (also a switch)
nomarchy-theme-sync bg next            # cycle wallpapers — instant, no rebuild
nomarchy-theme-sync bg auto            # back to the theme's default wallpaper
nomarchy-theme-sync get colors.accent
sys-update                             # update inputs + rebuild the system (snapshots first)
home-update                            # rebuild just the desktop layer

Keybinds: SUPER+Return terminal · SUPER+D launcher · SUPER+T theme picker · SUPER+SHIFT+T next wallpaper · SUPER+X power menu · SUPER+E file manager (yazi) · SUPER+N notifications · SUPER+CTRL+V clipboard history · SUPER+Q close · SUPER+1..9 workspaces · Print region screenshot.

6. Extending

  • New theme: drop a JSON into themes/ (schema = any existing preset), plus an optional themes/<slug>/ assets directory.
  • New themed value: add the key to theme-state.json and consume it in the Nix modules. One place — there is no second renderer to keep in sync.
  • Importing more old-distro palettes: tools/import-palettes.py <palettes-dir> themes/.

Roadmap

  • Menu system (apps launcher + theme switching + system actions), built on rofi 2.0 (native Wayland on 26.05) — its .rasi theme is baked from theme-state.json like every other app, with rich per-element styling:

    • ✓ shipped: modules/home/rofi.nix (per-element theme generated from the palette, themes/<slug>/rofi.rasi whole-swap) and the nomarchy-menu dispatcher: root picker (no args) · power (lock/logout/suspend/hibernate/reboot/shutdown, SUPER+X) · theme (SUPER+T) · clipboard (cliphist, SUPER+CTRL+V) · calc (qalc, copy/chain) · files (fd → xdg-open) · web (Google). SUPER+D is rofi -show drun.
    • ✓ shipped modules: network (nmtui in $TERMINAL) · bluetooth (blueman-manager) · capture (grim/slurp submenu: region/full → clipboard/file, saved to ~/Pictures/Screenshots) · keybinds (the cheatsheet, see below) · ask (free-text → claude CLI in a terminal; auths via OAuth, no API key; pulled fresh via npx @anthropic-ai/claude-code@latest rather than the nixpkgs package, which lags model releases — nodejs is bundled for npx; REPL stays open)
    • ✓ keybindings cheatsheet: modules/home/keybinds.nix is the single source for both the Hyprland binds and the SUPER+? rofi list, so they can't drift; nomarchy-menu keybinds renders the padded two-column sheet (generated/mouse binds carried in its extra rows)
    • ✓ shipped binds: SUPER+Spacerofi -show drun (quick launch) · SUPER+Mnomarchy-menu (main menu) · SUPER+? → the cheatsheet; SUPER+D stays -show drun
    • launcher icons: ✓ show-icons on, drawing from the theme's icon set (Papirus, via the icon-themes work below)
    • decision record: resolves the old Walker/Lua question — no GTK4 launcher, no second theming pipeline; the dispatcher owns the menu structure, so the renderer stays swappable (we moved fuzzel → rofi 2.0 once mainline gained native Wayland, for its richer theming)
  • Calculator module rework: the current calc flow (modules/home/rofi.nix) is unsatisfying — you commit the expression blind, then the result only appears in the next menu's -mesg line, and qalc -t misparses common phrasings (e.g. 15% of 200rem(15, 1 B) instead of 30). Rework toward live results as you type (rofi-calc-style: each keystroke re-evaluates and the answer is the top entry, Enter copies), a more robust qalc invocation, and graceful handling of parse errors. Decide whether to keep the hand-rolled dmenu loop or adopt a dedicated calc mode/plugin.

  • Theme parity with legacy: summer-day/night now carry their legacy bar layouts as waybar.jsonc whole-swaps (adapted: dead legacy script modules dropped, Nerd-Fonts-v2 codepoints remapped to FontAwesome/v3, logo button opens nomarchy-menu); the other four identity themes are palette recolors and already match. Remaining: a visual pass over all six on the live ISO

  • Per-theme rofi identity: the themes/<slug>/rofi.rasi whole-swap ships, and summer-day/night carry their legacy designs (inverted window, green inputbar, yellow bottom-border). Remaining: author .rasi identities for the other four ported themes if/when they want one (the generated palette theme is the default and looks fine)

  • Faster switches: move backgrounds/ out of the flake source (the 86 MB re-copy on every state write is the main eval tax), then pre-built theme variants if still needed

  • Greeter (tuigreet/SDDM) theming from the same JSON (Plymouth ships since v1: nomarchy.system.plymouth.*, background tinted from the state file)

  • Installer round 2: multi-disk BTRFS RAID, impermanence, BIOS/legacy boot (v1 nomarchy-install is single-disk UEFI — see pkgs/nomarchy-install)

  • launch-or-focus UX scripts (swayosd volume/brightness OSD ships since v1: nomarchy.osd.*, media keys drive swayosd-client, themed from the JSON)

  • Distro branding, round 2: distroName = "Nomarchy" ships (os-release PRETTY_NAME, systemd-boot entries, ISO menu label). ✓ tuigreet greeting (Welcome to <distroName>) and a branded users.motd (doubling as a helper cheat sheet), both keyed off distroName. ✓ isoImage.splashImage — the vendored vector logo (modules/nixos/branding/logo.svg, from legacy) recolored to the palette accent on the theme base, built at ISO-build time (hosts/live.nix). Remaining: isoImage.grubTheme so UEFI boot matches the isolinux splash (needs a full grub theme dir), and the distroId question (it changes DEFAULT_HOSTNAME and upstream isNixos checks — needs a test pass; nixos-* CLI names stay regardless)

  • fastfetch branding: modules/home/fastfetch.nix (nomarchy.fastfetch.enable) — the vendored vector logo, recolored to the palette accent and rendered to compact block-art via chafa at build time (tracks the theme), fronting a curated module list. Replaces the oversized legacy ASCII with a themed, sized logo.

  • Nomarchy logo font in Waybar: vendored Nomarchy.ttf (modules/nixos/branding/), installed via fonts.packages, and the summer-day/night menu buttons now use its U+F000 glyph with font-family: Nomarchy pinned in their CSS (Nerd Fonts also occupy U+F000, so the pin is required). The other themes have no logo button.

  • Quality-of-life command aliases: assemble a curated collection of shell aliases/abbreviations for common operations (git, nix, navigation, the nomarchy helpers, …), themed into the zsh shell experience (modules/home/shell.nix). Decide scope and which to ship on by default.

  • Theme-switch feedback: ✓ the "rebuilding…" notification is now persistent (timeout 0) and replaced in place by "applied ✓" / failure via a synchronous tag, so a multi-minute switch never reads as a failed selection. (An honest indeterminate indicator — HM gives no % — a literal progress widget would be cosmetic; revisit only if wanted.)

  • Icon themes: ✓ ships papirus-icon-theme; the resolved name lives on nomarchy.theme.iconTheme (the JSON's optional icons field, else Papirus-Dark/Light by mode) and feeds both Stylix's gtk.iconTheme (Thunar/GTK apps) and rofi's show-icons. Remaining (optional): per-theme icons overrides for the presets, or shipping more icon packs.

  • Nicer shell out of the box: ✓ zsh is the default login shell, with a starship prompt themed from the JSON, autosuggestions + syntax highlighting, and modern-CLI ergonomics — cat→bat (theme "ansi", so it tracks the palette), ls→eza, cd→zoxide, plus lt/tree. nomarchy.shell.enable. (Deliberately did NOT alias grep→rg / find→fd: their flags differ enough to surprise; rg/fd ship as themselves.)

  • Default application suite: install a complete-workstation set (vscode, libreoffice, gimp, inkscape, texlive-full, …) behind a nomarchy.apps.* option surface so each is individually opt-out for users who want a leaner machine. Watch closure size (texlive-full is multi-GB — likely default-off or a lighter scheme).

  • Plymouth logo contrast: the shipped art was a fixed navy that vanished on dark bases. modules/nixos/plymouth.nix now recolors every element from the palette at build time (flat fill, alpha kept): logo/lock/bullet → text, entry/progress-box → surface, progress-bar → accent. Reads on light and dark; follows the theme as of the last system rebuild (like the background tint).

  • Hibernate double-unlock: on resume from hibernate the LUKS passphrase already gates the machine, but hypridle's before_sleep_cmd also locked hyprlock, so the user typed a password twice. Fixed with a nomarchy-hibernate-unlock systemd unit (modules/nixos/default.nix) that dismisses hyprlock after a hibernate resume (WantedBy hibernate.target, After systemd-hibernate.service → runs post-resume), gated on the disk being LUKS-encrypted. Suspend (and the RAM-resume phase of suspend-then-hibernate) keep locking — they have no passphrase gate.

  • Key agents & pinentry: ships modules/home/keys.nix (nomarchy.keys.enable): one agent — services.gpg-agent with enableSshSupport fronts SSH, so a single pinentry-qt (native-Wayland, Stylix-themed Qt) handles GPG and SSH passphrases alike. SSH_AUTH_SOCK comes from the agent's zsh integration; cache TTLs (30 min / 2 h) govern re-prompting. gnome-keyring stays the Secret Service (modern versions run no SSH agent, so no socket contention); screen lock doesn't flush the cache. Remaining (optional): a session-level SSH_AUTH_SOCK export so GUI clients launched outside a shell also see the agent.

  • Sanitize & organize the repo: a housekeeping pass for consistency and clarity. Candidate targets (scope still to be defined): prune now-redundant config (e.g. the installer still writes console.useXkbConfig / boot.initrd.systemd.enable into system.nix, which are distro-wide defaults as of the LUKS-keymap fix); reconcile the README option tables with the actual nomarchy.* surface; audit comments/docs for drift against the code; and re-check that every file still earns its place under the modules/hosts/themes/pkgs/tools rule of thumb.

  • Laptop power / battery management: a real power story behind a nomarchy.system.power.* surface (modules/nixos/power.nix), replacing the old "only services.upower for Waybar reporting" baseline:

    • profiles: power-profiles-daemon ships by default (the upstream- aligned choice — power-saver/balanced/performance via powerprofilesctl, switched through polkit so no root prompt). A power-profile menu module (in the SUPER+M picker) and the first Waybar custom/* indicator (click to cycle) both self-gate on a battery being present + PPD running, so they hide on desktops and under TLP — no system→home wiring. TLP is the opt-in (backend = "tlp") for deeper battery tuning; the two are mutually exclusive (asserted).
    • thermal: thermald behind power.thermal.enable; the installer turns it on for a GenuineIntel CPU.
    • longevity: power.batteryChargeLimit (e.g. 80) — a backend- independent sysfs oneshot writes charge_control_end_threshold. Off by default; the installer scaffolds it commented-out on laptops.
    • installer: writes power.laptop = true (battery probe) and power.thermal.enable (Intel) into the generated system.nix.
    • Remaining: cohere with modules/home/idle.nix (AC-vs-battery idle timeouts / no auto-suspend on AC) and review logind lid handling, plus a boot-only→event-driven charge-limit re-apply (udev) if a firmware resets the threshold on unplug.
  • Opt-in services & integrations: the counterpart to the opt-out application suite above — heavier or more personal integrations shipped off by default, each a nomarchy.services.<name>.enable toggle a downstream flips on in one line. Keeps the base lean while making common additions trivial. Candidates by area:

    • cloud/sync: Nextcloud client; Syncthing (services.syncthing)
    • local AI: LM Studio (lmstudio); Ollama (services.ollama, optional GPU accel) — pairs with the menu's Ask-Claude philosophy
    • containers/VMs: Docker/Podman; libvirt + virt-manager
    • networking: Tailscale (services.tailscale); WireGuard
    • gaming/media: Steam (programs.steam); OBS Studio
    • devices: printing (CUPS + Avahi); KDE Connect / phone integration; OpenRGB
    • backup: restic/borg (services.restic)
    • escape hatch: Flatpak (services.flatpak) for apps outside nixpkgs

    Decisions: the curated set; whether system services and GUI apps share one surface or split (nomarchy.services.* system-side vs home-side packages); and how it relates to nomarchy.apps.* (opt-out suite). Unfree entries are already covered (allowUnfree = true).

  • Display / monitor management: today Hyprland just uses monitor = ,preferred,auto,1 (mkDefault). Add a real external-monitor/dock story: declarative per-output config, hotplug profiles (kanshi-style, or Hyprland's own monitor rules), and optionally a GUI arranger (nwg-displays writes Hyprland monitor config). Decide declarative-only vs GUI, and the option shape (nomarchy.monitors vs plain Hyprland monitor lists).

  • Night light / blue-light filter: schedulable colour-temperature shift via hyprsunset (Hyprland-native; wlsunset/gammastep are alternatives) — sunset/sunrise or a fixed schedule, with a menu + Waybar toggle.

  • Runtime keyboard-layout switching: the session layout is a single nomarchy.keyboard.layout today. Support a list of layouts with a toggle bind (hyprctl switchxkblayout / xkb grp: options) and a Waybar indicator for the active layout. Natural follow-on to the LUKS-keymap work — keep the system (console/initrd) and session layouts in sync.

  • Do-Not-Disturb: a swaync DND toggle (swaync-client -dn) wired into the menu and a Waybar indicator, to silence notifications for presentations/focus.

  • Snapshot browse/restore UX: snapper already takes BTRFS timeline snapshots (nomarchy.system.snapper); surface them from the desktop — a rofi menu (or btrfs-assistant) to browse/diff/restore and boot-from- snapshot — so rollback isn't CLI-only.

  • Update awareness: updates are manual today (sys-update/home-update); add a Waybar indicator / notification when flake inputs are stale or a new nixpkgs rev is available (optionally with a pending-change count). Augments, never replaces, the explicit rebuild flow.

  • "nomarchy" control center: a single TUI/GUI front-end over the common toggles — theme, power profile, opt-in services, display, DND — built on the same nomarchy-theme-sync / nomarchy.* surface the menu already uses. Plus a first-boot welcome that lands new installs in a guided "pick your theme / essentials" flow (ties into the branding work).

Known issues & follow-ups

  • Yazi TOML parse error on startup: yazi 26.x made fetchers' group field required, so [[plugin.prepend_fetchers]] failed to parse and yazi fell back to presets. Fixed by adding group = "git" to both git fetcher entries in modules/home/yazi.nix (the git plugin's setup() only renders the linemode; the fetcher still needs registering).
  • Starship prompt styling: dropped the powerline look (the [] separator glyph + bg: fills) for a flat prompt — bold-accent directory, warn git branch, subtext status/duration, character, all plain colored text (modules/home/shell.nix). Also wired in cmd_duration, which was configured but never referenced in format.
  • xfce deprecation warnings: moved xfce.exopkgs.xfce4-exo and the three Thunar plugins to their new top-level names in modules/nixos/file-manager.nix; the eval warnings are gone.
  • Rofi function keybindings: direct SUPER+CTRL+<mnemonic> binds jump straight to each nomarchy-menu module — V clipboard · C calc · W web · F files · N network · B bluetooth · S capture · A ask — added to modules/home/keybinds.nix, so they also show in the SUPER+? cheatsheet.
  • Enable nix-ld by default: programs.nix-ld.enable is on distro-wide (modules/nixos/default.nix), so prebuilt/foreign dynamically-linked binaries run out of the box.
  • Hyprland border colors off for some themes: the cause was v1 forcing an accent→accentAlt gradient on every theme; legacy used a solid border (accent for nord/retro-82/lumon, the text tone for kanagawa/summer-day/summer-night). Added a palette-resolved border field ({active, inactive}) to the theme schema (theme.nix), consumed solid in hyprland.nix, and declared it in every preset so a switch always replaces it. All six identity themes now match legacy exactly.
  • Waybar shows non-existent workspaces: the v1 summer port "fixed" legacy's deprecated persistent_workspaces (underscore — silently ignored by current Waybar, so legacy only ever showed existing workspaces) into the modern persistent-workspaces (hyphen), which Waybar honours → all 10 rendered as phantoms. Dropped the block from themes/summer-{day,night}/waybar.jsonc; the other themes use the generated waybar.nix, which never had it, so they already match.
  • GTK/Qt ignore the theme's light/dark mode: Stylix set polarity but not the org.freedesktop.appearance color-scheme that GTK4/libadwaita and Qt6 read via the portal, so a light theme could still render apps dark. stylix.nix now sets dconf org/gnome/desktop/interface color-scheme = prefer-light/prefer-dark from t.mode (xdg-desktop-portal-gtk already ships, and programs.dconf is on system-side), so libadwaita/Qt follow the palette. Needs a live session to confirm the portal picks it up for all apps.
Description
NixOS based distribution with Omarchy flavour
Readme MIT 308 MiB
Languages
Nix 71.4%
Python 11.9%
Shell 11.8%
CSS 4.9%