Compare commits

...

6 Commits

Author SHA1 Message Date
Bernardo Magri
82659566ac chore: untrack config.rasi (scratch reference committed by mistake)
config.rasi was the rofi theme dropped in to show the desired style; it's
not part of the distro. Remove it from tracking (the file stays on disk,
untracked). Its content informed 994025f and remains in that history.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:12:02 +01:00
Bernardo Magri
994025f0c8 feat(rofi): real icons, zebra rows, content-fit menus across all themes
Reworked the menu look, palette-driven so it lands on every theme:

  - Real Papirus icons in place of Nerd Font glyphs: a row() helper emits
    rofi's per-row icon protocol, and the five static menus (root, Tools,
    System, Power, Capture) map each entry to a freedesktop icon name
    (verified present in Papirus). Entry text is now clean ("Apps"), the
    case-matching is unchanged.
  - Larger icons via a new t.ui.iconSize knob (36px, generated theme); the
    summer whole-swaps keep their 40px identity.
  - Rounded, roomy rows with subtle zebra striping: alternate rows lift to
    @surface (a faint bg0 wash on the summer cream/slate windows), the
    selected row to @accent — using rofi's normal/alternate/selected row
    parities.
  - Content-fit windows: fixed-num-lines=false so a 6-entry menu stops
    reserving 8 rows of empty space (the launcher still fills + scrolls).
    Dropped the fixed height:50% from the summer .rasi so they size to
    content too — which also unhid their clipped Power/Keybindings rows.
  - Title-cased the menu prompts.

Verified by building the HM config and rendering the generated theme plus
both summer whole-swaps headlessly (sway + grim): icons resolve, zebra
shows, every menu hugs its rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:11:25 +01:00
Bernardo Magri
b0b2a4d732 docs(services): note the restic-nomarchy list/restore wrapper
VM-verified the full batch of opt-in service toggles (libvirt, docker, obs
+ v4l2loopback, ollama, printing, openrgb, wireshark, adb, gamemode,
kdeconnect, restic) in a headless nixosTest — all green, no module bugs.

The one thing worth surfacing: services.restic ships a pre-configured
`restic-nomarchy` wrapper (repository + passwordFile baked in) for listing
and restoring snapshots. Mention it in the option description and README so
the restore path is discoverable — a backup you can't restore is half a
feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 21:18:49 +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
9 changed files with 472 additions and 75 deletions

View File

@@ -224,6 +224,18 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
| `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) |
| `nomarchy.services.flatpak.enable` | `false` | Opt-in: Flatpak + the Flathub remote |
| `nomarchy.services.pika.enable` | `false` | Opt-in: Pika Backup (GUI Borg backups) |
| `nomarchy.services.steam.enable` | `false` | Opt-in: Steam via `programs.steam` (32-bit libs, controller udev, Remote-Play ports) |
| `nomarchy.services.libvirt.enable` | `false` | Opt-in: libvirt/KVM + virt-manager GUI (login user added to `libvirtd`) |
| `nomarchy.services.obs.enable` | `false` | Opt-in: OBS Studio + a v4l2loopback virtual camera (selectable as a webcam in Zoom/Teams) |
| `nomarchy.services.docker.enable` | `false` | Opt-in: rootful Docker (user in `docker` group); don't enable alongside podman |
| `nomarchy.services.kdeconnect.enable` | `false` | Opt-in: KDE Connect phone integration (opens its firewall ports) |
| `nomarchy.services.gamemode.enable` | `false` | Opt-in: Feral GameMode performance daemon (`gamemoderun`) |
| `nomarchy.services.adb.enable` | `false` | Opt-in: Android adb/fastboot tools (systemd handles device udev rules) |
| `nomarchy.services.wireshark.enable` | `false` | Opt-in: Wireshark Qt GUI (user in `wireshark` group, capture without root) |
| `nomarchy.services.ollama.enable` | `false` | Opt-in: Ollama local LLM runtime on `127.0.0.1:11434` (CPU; GPU via `services.ollama.acceleration`) |
| `nomarchy.services.printing.enable` | `false` | Opt-in: CUPS + Avahi/mDNS network printer discovery |
| `nomarchy.services.openrgb.enable` | `false` | Opt-in: OpenRGB daemon for RGB peripheral/motherboard lighting |
| `nomarchy.services.restic.enable` | `false` | Opt-in: scheduled daily restic backup (set `.repository` + `.passwordFile`; 7/4/6 retention; list/restore via the `restic-nomarchy` wrapper) |
Beyond the `nomarchy.*` surface, the system layer turns on the usual
desktop services with `lib.mkDefault` (override natively). One worth
@@ -336,6 +348,12 @@ reload # exec zsh (reload the shell)
example of it in `templates/downstream/home.nix` or `system.nix`. New
installs then enable it by uncommenting + tweaking, rather than hunting the
docs for the option name.
- **Applications:** the starter complete-workstation set (LibreOffice, VS
Code, GIMP, Inkscape) lives in the `home.packages` list in your
`home.nix` — it's a plain package list, so curate it directly: delete a
line to slim the machine, uncomment an extra (a browser, email, full TeX
Live), or add your own. No `nomarchy.apps.*` toggles — a package list is
already its own opt-out, so the distro doesn't impose these or wrap them.
## Roadmap & known issues

View File

@@ -138,11 +138,21 @@ how to override it. Items marked ✓ are shipped.
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).
- **Default application suite:** a starter complete-workstation set
`libreoffice-fresh`, `vscode`, `gimp`, `inkscape` — ships *active* in the
downstream `templates/downstream/home.nix` `home.packages`, with the heavier
opt-ins (`texliveFull` — multi-GB; `texliveMedium` is lighter — plus
browser/email) commented just below. **Decision: no `nomarchy.apps.*` option
surface.** Unlike `nomarchy.services.*` (real config behind each toggle —
systemd units, subuid ranges, the Flathub oneshot), a bare package install
has nothing behind the toggle: `mkIf x { environment.systemPackages = [p]; }`
just reinholds what a package list already gives, and the honest opt-out for
a package is *deleting the line*. So the suite is the user's own curated list
(extending the existing `# firefox` convention), not a distro-module feature —
which also keeps the apps out of the live ISO automatically (it never starts
from the template) and respects that editor/office/graphics are personal-taste
choices, not defaults to impose. Unfree `vscode` evaluates fine — `mkFlake`
and the system both set `allowUnfree = true`.
-**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):
@@ -281,31 +291,51 @@ how to override it. Items marked ✓ are shipped.
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. **Five shipped** in `modules/nixos/services.nix`
additions trivial. **Seventeen shipped** in `modules/nixos/services.nix`
(system-side), each with a commented example in the downstream `system.nix`
template: `tailscale`, `syncthing` (runs as the login user, GUI on
127.0.0.1:8384), `podman` (rootless, `docker` aliased, user subuid/subgid),
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI).
More candidates by area:
-**cloud/sync:** Syncthing (`services.syncthing`); Nextcloud client (todo)
- **local AI:** LM Studio (`lmstudio`); Ollama (`services.ollama`, optional
GPU accel) — pairs with the menu's Ask-Claude philosophy
-**containers/VMs:** Podman (`virtualisation.podman`); Docker / libvirt +
virt-manager (todo)
-**networking:** Tailscale (`services.tailscale`); WireGuard (todo)
- **gaming/media:** Steam (`programs.steam`); OBS Studio
- **devices:** printing (CUPS + Avahi); KDE Connect / phone integration;
OpenRGB
-**backup:** Pika Backup (`pika-backup`, GUI over Borg); restic/borg
services (todo)
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI),
`steam` (`programs.steam` — the 32-bit stack, controller udev, Remote-Play
ports a bare package can't), `libvirt` (libvirtd + virt-manager, user added
to the `libvirtd` group), `obs` (OBS Studio + a v4l2loopback virtual camera
usable as a webcam in Zoom/Teams), `docker` (rootful; asserts against the
podman docker-compat), `kdeconnect`, `gamemode`, `adb` (android-tools;
systemd handles the udev rules), `wireshark` (Qt GUI + the `wireshark`
group), `ollama` (local LLM API on 127.0.0.1:11434), `printing` (CUPS +
Avahi mDNS), `openrgb` (RGB lighting daemon), and `restic` (scheduled
daily backup — a small option surface: `repository`/`passwordFile`/`paths`,
7/4/6 retention). More candidates by area:
-**cloud/sync:** Syncthing (`services.syncthing`); Nextcloud client is a
bare tray app (in the app-suite menu, not a service)
-**local AI:** Ollama (`nomarchy.services.ollama`, optional GPU accel)
ships; LM Studio is a (commented) app-suite package (a bare GUI, no
service) — pairs with the menu's Ask-Claude philosophy
-**containers/VMs:** Podman (`virtualisation.podman`); libvirt +
virt-manager (`nomarchy.services.libvirt`); Docker (`nomarchy.services.docker`)
-**networking:** Tailscale (`services.tailscale`); WireGuard needs no
toggle — NetworkManager (on by default) imports `.conf` tunnels natively;
the `wireguard-tools` CLI is in the app-suite menu
-**gaming/media:** Steam (`nomarchy.services.steam`); OBS Studio
(`nomarchy.services.obs`, with the v4l2loopback virtual camera); GameMode
(`nomarchy.services.gamemode`)
-**devices:** printing (CUPS + Avahi, `nomarchy.services.printing`); KDE
Connect (`nomarchy.services.kdeconnect`); OpenRGB
(`nomarchy.services.openrgb`). Plus dev tooling — Android `adb` and
`wireshark` toggles
-**backup:** Pika Backup (`pika-backup`, GUI over Borg); scheduled
headless restic (`nomarchy.services.restic`)
-**escape hatch:** Flatpak (`services.flatpak`) + Flathub, for apps
outside nixpkgs
Surface decided: `nomarchy.services.*`, system-side for system services
(home-side ones can extend the same prefix later). Remaining: curate the
rest (Ollama, containers, Steam/OBS, printing, backups, Flatpak …) and
decide how it relates to `nomarchy.apps.*` (opt-out suite). Unfree entries
are already covered (`allowUnfree = true`).
rest (Ollama, containers, Steam/OBS, printing, backups, Flatpak …). The
opt-out application *suite* is deliberately **not** a parallel
`nomarchy.apps.*` surface — it's a curated `home.packages` list in the
downstream template (see "Default application suite" above), since a bare
package install has no config to put behind a toggle. Unfree entries are
already covered (`allowUnfree = true`).
-**Display / monitor management:** declarative `nomarchy.monitors` (a
per-output schema — name/resolution/position/scale/transform/mirror/
bitdepth/vrr/disable) generates Hyprland `monitor` rules, keeping the

View File

@@ -41,9 +41,9 @@ let
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
# Nomarchy menu dispatcher thin presentation layer over
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
# hyprctl and friends. Icons are nf-md glyphs (Pango falls back to a
# Nerd Font for them). `nomarchy-menu` with no argument shows the
# module picker.
# hyprctl and friends. Menu entries carry real icons from the theme's
# icon set (Papirus) via rofi's per-row icon protocol see row() below.
# `nomarchy-menu` with no argument shows the module picker.
urlencode() {
local s="$1" out="" ch i
@@ -58,16 +58,22 @@ let
printf '%s' "$out"
}
# Emit one dmenu row with a themed icon: `row "Label" icon-name`. The NUL
# + 0x1f field separator is rofi's per-row icon protocol; printed straight
# to the pipe because bash can't store NUL in a variable. Rendered when
# rofi has show-icons (on globally; passed explicitly on the icon menus).
row() { printf '%s\0icon\x1f%s\n' "$1" "$2"; }
case "''${1:-}" in
power)
choice=$(printf '%s\n' \
"󰌾 Lock" \
"󰍃 Logout" \
"󰤄 Suspend" \
"󰒲 Hibernate" \
"󰜉 Reboot" \
"󰐥 Shutdown" \
| rofi -dmenu -p power) || exit 0
choice=$( {
row "Lock" system-lock-screen
row "Logout" system-log-out
row "Suspend" system-suspend
row "Hibernate" system-hibernate
row "Reboot" system-reboot
row "Shutdown" system-shutdown
} | rofi -dmenu -show-icons -p Power) || exit 0
case "$choice" in
*Lock) loginctl lock-session ;;
*Logout) hyprctl dispatch exit ;;
@@ -134,12 +140,12 @@ let
exec blueman-manager ;;
capture)
choice=$(printf '%s\n' \
"󰆟 Region clipboard" \
"󰆟 Region file" \
"󰍹 Full screen clipboard" \
"󰍹 Full screen file" \
| rofi -dmenu -p capture) || exit 0
choice=$( {
row "Region clipboard" applets-screenshooter
row "Region file" applets-screenshooter
row "Full screen clipboard" camera-photo
row "Full screen file" camera-photo
} | rofi -dmenu -show-icons -p Capture) || exit 0
dir="$HOME/Pictures/Screenshots"
file="$dir/$(date +%Y%m%d-%H%M%S).png"
case "$choice" in
@@ -183,16 +189,16 @@ let
tools)
# Tools submenu utilities you invoke. Each leaf is also reachable
# directly (SUPER+CTRL+<mnemonic>); this just keeps the root short.
choice=$(printf '%s\n' \
"󰃬 Calculator" \
"󰅌 Clipboard" \
"󰒨 Emoji" \
"󰈞 Files" \
"󰖟 Web search" \
"󰄄 Capture" \
"󰭹 Ask Claude" \
"󰁍 Back" \
| rofi -dmenu -p tools) || exit 0
choice=$( {
row "Calculator" accessories-calculator
row "Clipboard" edit-paste
row "Emoji" face-smile-big
row "Files" system-file-manager
row "Web search" system-search
row "Capture" applets-screenshooter
row "Ask Claude" internet-chat
row "Back" go-previous
} | rofi -dmenu -show-icons -p Tools) || exit 0
case "$choice" in
*Calc*) exec "$0" calc ;;
*Clipboard*) exec "$0" clipboard ;;
@@ -208,18 +214,17 @@ let
# System submenu connectivity and machine state. Snapshots and the
# power-profile picker self-gate (BTRFS+snapper / laptop on ppd), so
# the submenu shrinks to match the hardware, like the Waybar modules.
entries=(
"󰖩 Network"
"󰂯 Bluetooth"
"󰂛 Do Not Disturb"
)
command -v btrfs-assistant >/dev/null 2>&1 && entries+=("󰋚 Snapshots")
bats=(/sys/class/power_supply/BAT*)
choice=$( {
row "Network" network-wireless
row "Bluetooth" bluetooth
row "Do Not Disturb" notification-disabled
command -v btrfs-assistant >/dev/null 2>&1 && row "Snapshots" timeshift
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
entries+=("󰓅 Power profile")
row "Power profile" preferences-system-power
fi
entries+=("󰁍 Back")
choice=$(printf '%s\n' "''${entries[@]}" | rofi -dmenu -p system) || exit 0
row "Back" go-previous
} | rofi -dmenu -show-icons -p System) || exit 0
case "$choice" in
*Network*) exec "$0" network ;;
*Bluetooth*) exec "$0" bluetooth ;;
@@ -233,14 +238,14 @@ let
# Root picker grouped into category submenus so the top level stays
# short and scannable. Apps/Theme/Power/Keybindings are frequent enough
# to keep at the top; everything else lives under Tools or System.
choice=$(printf '%s\n' \
"󰀻 Apps" \
"󰏘 Theme" \
"󰦬 Tools" \
"󰒓 System" \
"󰐥 Power" \
"󰋖 Keybindings" \
| rofi -dmenu -p menu) || exit 0
choice=$( {
row "Apps" applications-all
row "Theme" preferences-desktop-theme
row "Tools" applications-utilities
row "System" preferences-system
row "Power" system-shutdown
row "Keybindings" preferences-desktop-keyboard
} | rofi -dmenu -show-icons -p Menu) || exit 0
case "$choice" in
*Apps*) exec rofi -show drun ;;
*Theme*) exec "$0" theme ;;
@@ -283,6 +288,10 @@ in
drun-display-format = "{name}";
display-drun = "apps";
display-run = "run";
# Size the window to the actual number of rows instead of always
# reserving `lines` (8) — so a 6-entry menu doesn't leave empty space,
# while the app launcher still fills + scrolls past `lines`.
fixed-num-lines = false;
};
# Whole-swap themes bring their own rofi.rasi; otherwise the theme
@@ -335,22 +344,34 @@ in
columns = 1;
dynamic = true;
scrollbar = false;
spacing = px 2;
spacing = px 4; # a little air so the rounded zebra rows separate
padding = mkLiteral "8px 0px 0px 0px";
};
# Rounded, roomy rows with subtle zebra striping: alternate rows
# lift to @surface, the selected row to @accent. normal/alternate/
# selected are rofi's row parities (the `.normal` suffix is the
# match-state, untouched by our menus).
"element" = {
padding = mkLiteral "8px 12px";
padding = mkLiteral "10px 14px";
border-radius = px t.ui.rounding;
spacing = px 8;
spacing = px 12; # gap between the (larger) icon and the label
};
"element selected" = {
"element normal.normal" = {
background-color = mkLiteral "@bg";
text-color = mkLiteral "@fg";
};
"element alternate.normal" = {
background-color = mkLiteral "@surface";
text-color = mkLiteral "@fg";
};
"element selected.normal" = {
background-color = mkLiteral "@accent";
text-color = mkLiteral "@bg";
};
"element-icon" = {
background-color = mkLiteral "transparent";
size = mkLiteral "1em";
size = px t.ui.iconSize; # real icons (Papirus), not 1em font glyphs
};
"element-text" = {
background-color = mkLiteral "transparent";

View File

@@ -38,6 +38,7 @@ let
gapsOut = 12;
borderSize = 2;
rounding = 10;
iconSize = 36; # rofi launcher + menu icon size (px) for the generated theme
activeOpacity = 1.0;
inactiveOpacity = 0.95;
terminalOpacity = 0.96;

View File

@@ -29,6 +29,96 @@ in
pika.enable = lib.mkEnableOption ''
Pika Backup, a friendly GUI for scheduled Borg backups (the app;
configure repositories and schedules inside it)'';
steam.enable = lib.mkEnableOption ''
Steam (Valve's game store/launcher) via programs.steam which wires up
the 32-bit graphics libraries, controller udev rules and Remote-Play
firewall ports a bare package can't. Unfree'';
libvirt.enable = lib.mkEnableOption ''
libvirt/KVM virtualisation with the virt-manager GUI runs the
libvirtd daemon and adds the login user to the `libvirtd` group, so VMs
can be managed without root'';
obs.enable = lib.mkEnableOption ''
OBS Studio for screen recording and streaming, plus a v4l2loopback
virtual camera so an OBS scene can be selected as a webcam in Zoom,
Teams or a browser (screen capture itself already works over the
desktop's PipeWire portal)'';
docker.enable = lib.mkEnableOption ''
Docker (rootful) with the login user in the `docker` group. Mutually
exclusive with the podman toggle's docker-compat (both provide the
`docker` command) enable only one'';
kdeconnect.enable = lib.mkEnableOption ''
KDE Connect for phone integration shared clipboard, notifications and
file transfer with a paired phone; opens the firewall ports it needs'';
gamemode.enable = lib.mkEnableOption ''
Feral GameMode a daemon games ask to apply a performance CPU governor
and IO/nice priorities while running (via `gamemoderun`)'';
adb.enable = lib.mkEnableOption ''
the Android platform tools (adb/fastboot) for flashing/debugging phones.
systemd 258 applies the device uaccess udev rules automatically, so the
tools alone are enough no group dance'';
wireshark.enable = lib.mkEnableOption ''
Wireshark (the Qt GUI) for packet capture, with the login user in the
`wireshark` group so capture works without root'';
ollama.enable = lib.mkEnableOption ''
Ollama, a local LLM runtime serving an API on 127.0.0.1:11434 (pair it
with the lmstudio/alpaca GUIs). CPU by default set
`services.ollama.acceleration` natively for GPU offload'';
printing.enable = lib.mkEnableOption ''
CUPS printing with Avahi/mDNS, so network printers are auto-discovered
(add vendor drivers via `services.printing.drivers`)'';
openrgb.enable = lib.mkEnableOption ''
the OpenRGB daemon and GUI for controlling RGB lighting on peripherals
and (where supported) motherboards installs the udev rules for device
access. Some motherboard controllers also need `hardware.i2c.enable`'';
restic = {
enable = lib.mkEnableOption ''
a scheduled (daily) restic backup headless, complementing the Pika
GUI. Backs up `paths` with sane retention (7 daily / 4 weekly /
6 monthly); needs a `repository` and a `passwordFile` (below). List
and restore with the generated `restic-nomarchy` wrapper (repo +
password baked in), e.g. `restic-nomarchy snapshots`'';
repository = lib.mkOption {
type = lib.types.str;
default = "";
example = "/mnt/backup/restic";
description = ''
The restic repository as a path or URL e.g. `/mnt/backup/restic`,
`sftp:user@host:/srv/restic`, `b2:bucket:/path`. Required when
`restic.enable` is set.
'';
};
passwordFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "/etc/nomarchy/restic-password";
description = ''
Path to a file holding the repository password. Give an absolute
path that lives ON THE MACHINE not a `./file` in the flake, which
would copy the secret into the world-readable Nix store. Required
when `restic.enable` is set.
'';
};
paths = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "/home" ];
description = "Paths to include in the backup.";
};
};
};
config = lib.mkMerge [
@@ -80,5 +170,111 @@ in
(lib.mkIf cfg.pika.enable {
environment.systemPackages = [ pkgs.pika-backup ];
})
(lib.mkIf cfg.steam.enable {
# The Steam package alone misses the system bits a game needs: the
# 32-bit graphics stack, controller udev rules, Remote-Play ports.
programs.steam.enable = true;
})
(lib.mkIf cfg.libvirt.enable {
virtualisation.libvirtd.enable = true;
programs.virt-manager.enable = true;
# Group membership lets the user reach the system libvirtd socket
# (manage VMs) without sudo. Merges with the user's other extraGroups.
users.users.${args.username}.extraGroups = [ "libvirtd" ];
})
(lib.mkIf cfg.obs.enable {
environment.systemPackages = [ pkgs.obs-studio ];
# Virtual camera: OBS streams a scene into a v4l2 loopback device that
# Zoom/Teams/browsers then pick up as a webcam. exclusive_caps=1 is the
# bit that makes those apps actually list the device.
boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
boot.kernelModules = [ "v4l2loopback" ];
boot.extraModprobeConfig = ''
options v4l2loopback devices=1 video_nr=10 card_label="OBS Virtual Camera" exclusive_caps=1
'';
})
(lib.mkIf cfg.docker.enable {
virtualisation.docker.enable = true;
users.users.${args.username}.extraGroups = [ "docker" ];
# Podman's docker-compat and real Docker both claim the `docker`
# command — guard against enabling both (unless you turn that off).
assertions = [{
assertion = !(cfg.podman.enable && config.virtualisation.podman.dockerCompat);
message = ''
nomarchy.services: docker and podman both provide the `docker`
command. Enable only one, or set
`virtualisation.podman.dockerCompat = false`.
'';
}];
})
(lib.mkIf cfg.kdeconnect.enable {
programs.kdeconnect.enable = true; # installs the app and opens its ports
})
(lib.mkIf cfg.gamemode.enable {
programs.gamemode.enable = true;
})
(lib.mkIf cfg.adb.enable {
# `programs.adb` was removed — systemd ≥258 handles the device uaccess
# udev rules, so the tools package is all that's needed now.
environment.systemPackages = [ pkgs.android-tools ];
})
(lib.mkIf cfg.wireshark.enable {
programs.wireshark = {
enable = true;
package = pkgs.wireshark; # the Qt GUI (the module defaults to the CLI)
};
users.users.${args.username}.extraGroups = [ "wireshark" ];
})
(lib.mkIf cfg.ollama.enable {
services.ollama.enable = true;
})
(lib.mkIf cfg.printing.enable {
services.printing.enable = true;
# mDNS so network printers show up without manual setup.
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
};
})
(lib.mkIf cfg.openrgb.enable {
services.hardware.openrgb.enable = true;
})
(lib.mkIf cfg.restic.enable {
assertions = [
{
assertion = cfg.restic.repository != "";
message = "nomarchy.services.restic.repository must be set when restic is enabled.";
}
{
assertion = cfg.restic.passwordFile != null;
message = "nomarchy.services.restic.passwordFile must be set when restic is enabled.";
}
];
services.restic.backups.nomarchy = {
repository = cfg.restic.repository;
passwordFile = cfg.restic.passwordFile;
paths = cfg.restic.paths;
initialize = true; # create the repo on first run if it doesn't exist
extraBackupArgs = [ "--exclude-caches" ];
pruneOpts = [ "--keep-daily 7" "--keep-weekly 4" "--keep-monthly 6" ];
timerConfig = {
OnCalendar = "daily";
Persistent = true; # catch up a missed run after downtime
};
};
})
];
}

View File

@@ -34,7 +34,107 @@
# nomarchy.keyboard.layouts = [ "de" "fr" ]; # rofi-prompt for a layout when a
# # new keyboard connects + remember it
# ── Application suite ───────────────────────────────────────────────
# A starter complete-workstation set, installed for your user — yours to
# curate. Delete a line to slim the machine; uncomment a suggestion (or
# add your own) to extend it. The desktop itself — terminal, editor
# keybinds, theming — comes from the modules; these are the heavier
# standalone apps the distro doesn't impose by default.
#
# Apps that need system setup beyond a package (Steam's 32-bit stack,
# a daemon, group membership, a kernel module) are NOT here — they're
# opt-in service toggles in system.nix instead (nomarchy.services.* —
# steam, libvirt, obs, docker, gamemode, kdeconnect, adb, wireshark,
# ollama, printing).
home.packages = with pkgs; [
libreoffice-fresh # office suite (documents, sheets, slides)
vscode # code editor (unfree; allowUnfree is on)
gimp # raster image editor
inkscape # vector graphics
mpv # media player
amberol # music player (local library; streaming → spotify below)
# ── More apps — uncomment to add ─────────────────────────────────
# Web browsers
# firefox
# chromium
# ungoogled-chromium
# brave # (unfree)
# google-chrome # (unfree)
# Communication
# signal-desktop
# telegram-desktop
# element-desktop # Matrix
# vesktop # Discord (themeable client)
# slack # (unfree)
# zoom-us # (unfree)
# teams-for-linux # community client (no official Linux app)
# thunderbird # email
# Office & documents
# onlyoffice-desktopeditors # stronger MS-Office fidelity
# kdePackages.okular # PDF viewer
# xournalpp # PDF annotation
# pdfarranger
# calibre # ebook library
# texliveFull # full LaTeX toolchain — multi-GB (texliveMedium is lighter)
# Notes / research
# logseq
# obsidian # (unfree)
# joplin-desktop
# anki-bin # flashcards
# zotero # reference manager
# Code & data
# zed-editor
# lazygit
# dbeaver-bin # database GUI
# bruno # API client
# distrobox # containerized dev shells
# Graphics & design
# krita # digital painting
# blender # 3D
# darktable # RAW photo
# Audio / video
# audacity
# shotcut # video editor
# kdePackages.kdenlive # video editor (pulls in KDE libs)
# handbrake # transcoder
# Media
# vlc
# spotify # (unfree)
# newsflash # RSS reader
# Gaming (Steam + GameMode are service toggles in system.nix)
# lutris
# heroic # Epic/GOG launcher
# bottles # Wine prefixes
# prismlauncher # Minecraft
# protonup-qt # Proton-GE manager
# mangohud # in-game overlay
# Files, sync & torrents
# nextcloud-client
# localsend # AirDrop-like transfer
# qbittorrent
# Security
# keepassxc
# bitwarden-desktop
# System
# gnome-disk-utility
# gparted
# baobab # disk usage
# wireguard-tools # WireGuard CLI (NetworkManager imports .conf tunnels natively)
# Local AI (Ollama is a service toggle in system.nix)
# lmstudio # (unfree; large closure)
# alpaca # GTK Ollama UI
];
}

View File

@@ -36,6 +36,23 @@
# nomarchy.services.podman.enable = true; # rootless containers (docker → podman)
# nomarchy.services.flatpak.enable = true; # Flatpak + the Flathub remote
# nomarchy.services.pika.enable = true; # Pika Backup (GUI Borg backups)
# nomarchy.services.steam.enable = true; # Steam (32-bit libs, controllers, ports)
# nomarchy.services.libvirt.enable = true; # libvirt/KVM + virt-manager GUI
# nomarchy.services.obs.enable = true; # OBS Studio + v4l2loopback virtual camera
# nomarchy.services.docker.enable = true; # Docker rootful (not alongside podman)
# nomarchy.services.kdeconnect.enable = true;# KDE Connect phone integration (opens ports)
# nomarchy.services.gamemode.enable = true; # Feral GameMode performance daemon
# nomarchy.services.adb.enable = true; # Android adb/fastboot tools
# nomarchy.services.wireshark.enable = true; # Wireshark GUI (wireshark group, no root)
# nomarchy.services.ollama.enable = true; # local LLM runtime (127.0.0.1:11434)
# nomarchy.services.printing.enable = true; # CUPS + Avahi network printer discovery
# nomarchy.services.openrgb.enable = true; # RGB peripheral/motherboard lighting daemon
# nomarchy.services.restic = { # scheduled (daily) restic backup
# enable = true;
# repository = "/mnt/backup/restic"; # path or URL (sftp:/b2:/…)
# passwordFile = "/etc/nomarchy/restic-password"; # absolute path, NOT in the flake
# paths = [ "/home" ];
# };
system.stateVersion = "26.05";
}

View File

@@ -29,7 +29,8 @@ window {
border-color: @yellow;
border-radius: 15px;
width: 40%;
height: 50%;
/* No fixed height — size to content (fixed-num-lines:false) so every
* entry shows without scrolling and there's no empty space below. */
location: center;
anchor: center;
x-offset: 0;
@@ -90,6 +91,12 @@ element {
spacing: 15px;
}
/* Zebra striping: every other row lifts with a faint light wash over the
* dark window (bg0 at ~12% alpha). The selected row below still wins. */
element alternate.normal {
background-color: #fdf6e31f;
}
element-icon {
background-color: transparent;
text-color: inherit;

View File

@@ -29,7 +29,8 @@ window {
border-color: @yellow;
border-radius: 15px;
width: 40%;
height: 50%;
/* No fixed height — size to content (fixed-num-lines:false) so every
* entry shows without scrolling and there's no empty space below. */
location: center;
anchor: center;
x-offset: 0;
@@ -90,6 +91,12 @@ element {
spacing: 15px;
}
/* Zebra striping: every other row lifts with a faint dark wash over the
* cream window (bg0 at ~12% alpha). The selected row below still wins. */
element alternate.normal {
background-color: #2d353b1f;
}
element-icon {
background-color: transparent;
text-color: inherit;