A dedicated prose pass distinct from the repo-sanitize item: split the ~200-line roadmap out of the README, reconcile the option tables with the live nomarchy.* surface, and review docs/ + the downstream template for drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
555 lines
34 KiB
Markdown
555 lines
34 KiB
Markdown
# 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:
|
||
|
||
```sh
|
||
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](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:
|
||
|
||
```sh
|
||
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:
|
||
|
||
```nix
|
||
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](https://github.com/NixOS/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:
|
||
|
||
```sh
|
||
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:
|
||
|
||
```sh
|
||
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](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 |
|
||
| `nomarchy.system.power.enable` | `true` | Active power management (see below) |
|
||
| `nomarchy.system.power.backend` | `"ppd"` | `"ppd"` (power-profiles-daemon + menu/Waybar switcher) or `"tlp"` (deeper battery tuning, no switcher) — mutually exclusive |
|
||
| `nomarchy.system.power.laptop` | `false` | Marks a laptop, gating battery-only features; the installer sets it when a battery is present |
|
||
| `nomarchy.system.power.thermal.enable` | `false` | thermald (Intel-only); the installer enables it on a GenuineIntel CPU |
|
||
| `nomarchy.system.power.batteryChargeLimit` | `null` | Stop charging at this % (e.g. `80`) where the hardware supports it; needs `power.laptop` |
|
||
|
||
Beyond the `nomarchy.*` surface, the system layer turns on the usual
|
||
desktop services with `lib.mkDefault` (override natively). One worth
|
||
calling out: **`services.fwupd.enable`** is on by default for firmware
|
||
updates via LVFS — it only refreshes metadata, never flashes on its own,
|
||
so run `fwupdmgr update` to apply. Disable with `services.fwupd.enable =
|
||
false;` on machines without real firmware (VMs/headless).
|
||
|
||
## 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
|
||
|
||
```sh
|
||
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+Space` → `rofi -show drun` (quick launch) ·
|
||
`SUPER+M` → `nomarchy-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 200` →
|
||
`rem(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.
|
||
- **Full docs review & restructure:** a dedicated pass over all the prose,
|
||
not just the code-adjacent cleanup the repo-sanitize item covers. The
|
||
README has grown to ~540 lines with a ~200-line roadmap inline — the
|
||
biggest single move is likely **splitting the roadmap out** (e.g.
|
||
`ROADMAP.md` / `docs/`) so the README stays a focused "what it is / how
|
||
to install / how to override" entry point. Also: reconcile every option
|
||
table against the live `nomarchy.*` surface (snapper and others are
|
||
missing); a pass over `docs/OVERRIDES.md` + `docs/TESTING.md` and the
|
||
`templates/downstream/README.md` for drift; check the install/first-run
|
||
story reads cleanly end to end; and decide whether anything wants a real
|
||
docs site vs. staying Markdown-in-repo. Pairs with the first-boot welcome
|
||
and control-center items (shared "how do I…" surface).
|
||
- **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.exo` → `pkgs.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.
|