Compare commits
6 Commits
1f4bd3d5fa
...
v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82659566ac | ||
|
|
994025f0c8 | ||
|
|
b0b2a4d732 | ||
|
|
964a5c98b7 | ||
|
|
c45fb80b79 | ||
|
|
0c668c2eb1 |
18
README.md
18
README.md
@@ -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.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) |
|
||||||
| `nomarchy.services.flatpak.enable` | `false` | Opt-in: Flatpak + the Flathub remote |
|
| `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.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
|
Beyond the `nomarchy.*` surface, the system layer turns on the usual
|
||||||
desktop services with `lib.mkDefault` (override natively). One worth
|
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
|
example of it in `templates/downstream/home.nix` or `system.nix`. New
|
||||||
installs then enable it by uncommenting + tweaking, rather than hunting the
|
installs then enable it by uncommenting + tweaking, rather than hunting the
|
||||||
docs for the option name.
|
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
|
## Roadmap & known issues
|
||||||
|
|
||||||
|
|||||||
@@ -138,11 +138,21 @@ how to override it. Items marked ✓ are shipped.
|
|||||||
tracks the palette), `ls`→eza, `cd`→zoxide, plus `lt`/`tree`.
|
tracks the palette), `ls`→eza, `cd`→zoxide, plus `lt`/`tree`.
|
||||||
`nomarchy.shell.enable`. (Deliberately did NOT alias grep→rg / find→fd:
|
`nomarchy.shell.enable`. (Deliberately did NOT alias grep→rg / find→fd:
|
||||||
their flags differ enough to surprise; `rg`/`fd` ship as themselves.)
|
their flags differ enough to surprise; `rg`/`fd` ship as themselves.)
|
||||||
- **Default application suite:** install a complete-workstation set
|
- ✓ **Default application suite:** a starter complete-workstation set —
|
||||||
(vscode, libreoffice, gimp, inkscape, texlive-full, …) behind a
|
`libreoffice-fresh`, `vscode`, `gimp`, `inkscape` — ships *active* in the
|
||||||
`nomarchy.apps.*` option surface so each is individually opt-out for
|
downstream `templates/downstream/home.nix` `home.packages`, with the heavier
|
||||||
users who want a leaner machine. Watch closure size (texlive-full is
|
opt-ins (`texliveFull` — multi-GB; `texliveMedium` is lighter — plus
|
||||||
multi-GB — likely default-off or a lighter scheme).
|
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
|
- ✓ **Plymouth logo contrast:** the shipped art was a fixed navy that
|
||||||
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
||||||
element from the palette at build time (flat fill, alpha kept):
|
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
|
application suite above — heavier or more personal integrations shipped
|
||||||
**off by default**, each a `nomarchy.services.<name>.enable` toggle a
|
**off by default**, each a `nomarchy.services.<name>.enable` toggle a
|
||||||
downstream flips on in one line. Keeps the base lean while making common
|
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`
|
(system-side), each with a commented example in the downstream `system.nix`
|
||||||
template: `tailscale`, `syncthing` (runs as the login user, GUI on
|
template: `tailscale`, `syncthing` (runs as the login user, GUI on
|
||||||
127.0.0.1:8384), `podman` (rootless, `docker` aliased, user subuid/subgid),
|
127.0.0.1:8384), `podman` (rootless, `docker` aliased, user subuid/subgid),
|
||||||
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI).
|
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI),
|
||||||
More candidates by area:
|
`steam` (`programs.steam` — the 32-bit stack, controller udev, Remote-Play
|
||||||
- ✓ **cloud/sync:** Syncthing (`services.syncthing`); Nextcloud client (todo)
|
ports a bare package can't), `libvirt` (libvirtd + virt-manager, user added
|
||||||
- **local AI:** LM Studio (`lmstudio`); Ollama (`services.ollama`, optional
|
to the `libvirtd` group), `obs` (OBS Studio + a v4l2loopback virtual camera
|
||||||
GPU accel) — pairs with the menu's Ask-Claude philosophy
|
usable as a webcam in Zoom/Teams), `docker` (rootful; asserts against the
|
||||||
- ✓ **containers/VMs:** Podman (`virtualisation.podman`); Docker / libvirt +
|
podman docker-compat), `kdeconnect`, `gamemode`, `adb` (android-tools;
|
||||||
virt-manager (todo)
|
systemd handles the udev rules), `wireshark` (Qt GUI + the `wireshark`
|
||||||
- ✓ **networking:** Tailscale (`services.tailscale`); WireGuard (todo)
|
group), `ollama` (local LLM API on 127.0.0.1:11434), `printing` (CUPS +
|
||||||
- **gaming/media:** Steam (`programs.steam`); OBS Studio
|
Avahi mDNS), `openrgb` (RGB lighting daemon), and `restic` (scheduled
|
||||||
- **devices:** printing (CUPS + Avahi); KDE Connect / phone integration;
|
daily backup — a small option surface: `repository`/`passwordFile`/`paths`,
|
||||||
OpenRGB
|
7/4/6 retention). More candidates by area:
|
||||||
- ✓ **backup:** Pika Backup (`pika-backup`, GUI over Borg); restic/borg
|
- ✓ **cloud/sync:** Syncthing (`services.syncthing`); Nextcloud client is a
|
||||||
services (todo)
|
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
|
- ✓ **escape hatch:** Flatpak (`services.flatpak`) + Flathub, for apps
|
||||||
outside nixpkgs
|
outside nixpkgs
|
||||||
|
|
||||||
Surface decided: `nomarchy.services.*`, system-side for system services
|
Surface decided: `nomarchy.services.*`, system-side for system services
|
||||||
(home-side ones can extend the same prefix later). Remaining: curate the
|
(home-side ones can extend the same prefix later). Remaining: curate the
|
||||||
rest (Ollama, containers, Steam/OBS, printing, backups, Flatpak …) and
|
rest (Ollama, containers, Steam/OBS, printing, backups, Flatpak …). The
|
||||||
decide how it relates to `nomarchy.apps.*` (opt-out suite). Unfree entries
|
opt-out application *suite* is deliberately **not** a parallel
|
||||||
are already covered (`allowUnfree = true`).
|
`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
|
- ✓ **Display / monitor management:** declarative `nomarchy.monitors` (a
|
||||||
per-output schema — name/resolution/position/scale/transform/mirror/
|
per-output schema — name/resolution/position/scale/transform/mirror/
|
||||||
bitdepth/vrr/disable) generates Hyprland `monitor` rules, keeping the
|
bitdepth/vrr/disable) generates Hyprland `monitor` rules, keeping the
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ let
|
|||||||
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
||||||
# Nomarchy menu dispatcher — thin presentation layer over
|
# Nomarchy menu dispatcher — thin presentation layer over
|
||||||
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
|
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
|
||||||
# hyprctl and friends. Icons are nf-md glyphs (Pango falls back to a
|
# hyprctl and friends. Menu entries carry real icons from the theme's
|
||||||
# Nerd Font for them). `nomarchy-menu` with no argument shows the
|
# icon set (Papirus) via rofi's per-row icon protocol — see row() below.
|
||||||
# module picker.
|
# `nomarchy-menu` with no argument shows the module picker.
|
||||||
|
|
||||||
urlencode() {
|
urlencode() {
|
||||||
local s="$1" out="" ch i
|
local s="$1" out="" ch i
|
||||||
@@ -58,16 +58,22 @@ let
|
|||||||
printf '%s' "$out"
|
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
|
case "''${1:-}" in
|
||||||
power)
|
power)
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Lock" \
|
row "Lock" system-lock-screen
|
||||||
" Logout" \
|
row "Logout" system-log-out
|
||||||
" Suspend" \
|
row "Suspend" system-suspend
|
||||||
" Hibernate" \
|
row "Hibernate" system-hibernate
|
||||||
" Reboot" \
|
row "Reboot" system-reboot
|
||||||
" Shutdown" \
|
row "Shutdown" system-shutdown
|
||||||
| rofi -dmenu -p power) || exit 0
|
} | rofi -dmenu -show-icons -p Power) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
*Lock) loginctl lock-session ;;
|
*Lock) loginctl lock-session ;;
|
||||||
*Logout) hyprctl dispatch exit ;;
|
*Logout) hyprctl dispatch exit ;;
|
||||||
@@ -134,12 +140,12 @@ let
|
|||||||
exec blueman-manager ;;
|
exec blueman-manager ;;
|
||||||
|
|
||||||
capture)
|
capture)
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Region → clipboard" \
|
row "Region → clipboard" applets-screenshooter
|
||||||
" Region → file" \
|
row "Region → file" applets-screenshooter
|
||||||
" Full screen → clipboard" \
|
row "Full screen → clipboard" camera-photo
|
||||||
" Full screen → file" \
|
row "Full screen → file" camera-photo
|
||||||
| rofi -dmenu -p capture) || exit 0
|
} | rofi -dmenu -show-icons -p Capture) || exit 0
|
||||||
dir="$HOME/Pictures/Screenshots"
|
dir="$HOME/Pictures/Screenshots"
|
||||||
file="$dir/$(date +%Y%m%d-%H%M%S).png"
|
file="$dir/$(date +%Y%m%d-%H%M%S).png"
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
@@ -183,16 +189,16 @@ let
|
|||||||
tools)
|
tools)
|
||||||
# Tools submenu — utilities you invoke. Each leaf is also reachable
|
# Tools submenu — utilities you invoke. Each leaf is also reachable
|
||||||
# directly (SUPER+CTRL+<mnemonic>); this just keeps the root short.
|
# directly (SUPER+CTRL+<mnemonic>); this just keeps the root short.
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Calculator" \
|
row "Calculator" accessories-calculator
|
||||||
" Clipboard" \
|
row "Clipboard" edit-paste
|
||||||
" Emoji" \
|
row "Emoji" face-smile-big
|
||||||
" Files" \
|
row "Files" system-file-manager
|
||||||
" Web search" \
|
row "Web search" system-search
|
||||||
" Capture" \
|
row "Capture" applets-screenshooter
|
||||||
" Ask Claude" \
|
row "Ask Claude" internet-chat
|
||||||
" Back" \
|
row "Back" go-previous
|
||||||
| rofi -dmenu -p tools) || exit 0
|
} | rofi -dmenu -show-icons -p Tools) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
*Calc*) exec "$0" calc ;;
|
*Calc*) exec "$0" calc ;;
|
||||||
*Clipboard*) exec "$0" clipboard ;;
|
*Clipboard*) exec "$0" clipboard ;;
|
||||||
@@ -208,18 +214,17 @@ let
|
|||||||
# System submenu — connectivity and machine state. Snapshots and the
|
# System submenu — connectivity and machine state. Snapshots and the
|
||||||
# power-profile picker self-gate (BTRFS+snapper / laptop on ppd), so
|
# power-profile picker self-gate (BTRFS+snapper / laptop on ppd), so
|
||||||
# the submenu shrinks to match the hardware, like the Waybar modules.
|
# 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*)
|
bats=(/sys/class/power_supply/BAT*)
|
||||||
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
choice=$( {
|
||||||
entries+=(" Power profile")
|
row "Network" network-wireless
|
||||||
fi
|
row "Bluetooth" bluetooth
|
||||||
entries+=(" Back")
|
row "Do Not Disturb" notification-disabled
|
||||||
choice=$(printf '%s\n' "''${entries[@]}" | rofi -dmenu -p system) || exit 0
|
command -v btrfs-assistant >/dev/null 2>&1 && row "Snapshots" timeshift
|
||||||
|
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
||||||
|
row "Power profile" preferences-system-power
|
||||||
|
fi
|
||||||
|
row "Back" go-previous
|
||||||
|
} | rofi -dmenu -show-icons -p System) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
*Network*) exec "$0" network ;;
|
*Network*) exec "$0" network ;;
|
||||||
*Bluetooth*) exec "$0" bluetooth ;;
|
*Bluetooth*) exec "$0" bluetooth ;;
|
||||||
@@ -233,14 +238,14 @@ let
|
|||||||
# Root picker — grouped into category submenus so the top level stays
|
# Root picker — grouped into category submenus so the top level stays
|
||||||
# short and scannable. Apps/Theme/Power/Keybindings are frequent enough
|
# short and scannable. Apps/Theme/Power/Keybindings are frequent enough
|
||||||
# to keep at the top; everything else lives under Tools or System.
|
# to keep at the top; everything else lives under Tools or System.
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Apps" \
|
row "Apps" applications-all
|
||||||
" Theme" \
|
row "Theme" preferences-desktop-theme
|
||||||
" Tools" \
|
row "Tools" applications-utilities
|
||||||
" System" \
|
row "System" preferences-system
|
||||||
" Power" \
|
row "Power" system-shutdown
|
||||||
" Keybindings" \
|
row "Keybindings" preferences-desktop-keyboard
|
||||||
| rofi -dmenu -p menu) || exit 0
|
} | rofi -dmenu -show-icons -p Menu) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
*Apps*) exec rofi -show drun ;;
|
*Apps*) exec rofi -show drun ;;
|
||||||
*Theme*) exec "$0" theme ;;
|
*Theme*) exec "$0" theme ;;
|
||||||
@@ -283,6 +288,10 @@ in
|
|||||||
drun-display-format = "{name}";
|
drun-display-format = "{name}";
|
||||||
display-drun = "apps";
|
display-drun = "apps";
|
||||||
display-run = "run";
|
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
|
# Whole-swap themes bring their own rofi.rasi; otherwise the theme
|
||||||
@@ -335,22 +344,34 @@ in
|
|||||||
columns = 1;
|
columns = 1;
|
||||||
dynamic = true;
|
dynamic = true;
|
||||||
scrollbar = false;
|
scrollbar = false;
|
||||||
spacing = px 2;
|
spacing = px 4; # a little air so the rounded zebra rows separate
|
||||||
padding = mkLiteral "8px 0px 0px 0px";
|
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" = {
|
"element" = {
|
||||||
padding = mkLiteral "8px 12px";
|
padding = mkLiteral "10px 14px";
|
||||||
border-radius = px t.ui.rounding;
|
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";
|
background-color = mkLiteral "@accent";
|
||||||
text-color = mkLiteral "@bg";
|
text-color = mkLiteral "@bg";
|
||||||
};
|
};
|
||||||
"element-icon" = {
|
"element-icon" = {
|
||||||
background-color = mkLiteral "transparent";
|
background-color = mkLiteral "transparent";
|
||||||
size = mkLiteral "1em";
|
size = px t.ui.iconSize; # real icons (Papirus), not 1em font glyphs
|
||||||
};
|
};
|
||||||
"element-text" = {
|
"element-text" = {
|
||||||
background-color = mkLiteral "transparent";
|
background-color = mkLiteral "transparent";
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ let
|
|||||||
gapsOut = 12;
|
gapsOut = 12;
|
||||||
borderSize = 2;
|
borderSize = 2;
|
||||||
rounding = 10;
|
rounding = 10;
|
||||||
|
iconSize = 36; # rofi launcher + menu icon size (px) for the generated theme
|
||||||
activeOpacity = 1.0;
|
activeOpacity = 1.0;
|
||||||
inactiveOpacity = 0.95;
|
inactiveOpacity = 0.95;
|
||||||
terminalOpacity = 0.96;
|
terminalOpacity = 0.96;
|
||||||
|
|||||||
@@ -29,6 +29,96 @@ in
|
|||||||
pika.enable = lib.mkEnableOption ''
|
pika.enable = lib.mkEnableOption ''
|
||||||
Pika Backup, a friendly GUI for scheduled Borg backups (the app;
|
Pika Backup, a friendly GUI for scheduled Borg backups (the app;
|
||||||
configure repositories and schedules inside it)'';
|
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 [
|
config = lib.mkMerge [
|
||||||
@@ -80,5 +170,111 @@ in
|
|||||||
(lib.mkIf cfg.pika.enable {
|
(lib.mkIf cfg.pika.enable {
|
||||||
environment.systemPackages = [ pkgs.pika-backup ];
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,107 @@
|
|||||||
# nomarchy.keyboard.layouts = [ "de" "fr" ]; # rofi-prompt for a layout when a
|
# nomarchy.keyboard.layouts = [ "de" "fr" ]; # rofi-prompt for a layout when a
|
||||||
# # new keyboard connects + remember it
|
# # 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; [
|
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
|
# 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
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,23 @@
|
|||||||
# nomarchy.services.podman.enable = true; # rootless containers (docker → podman)
|
# nomarchy.services.podman.enable = true; # rootless containers (docker → podman)
|
||||||
# nomarchy.services.flatpak.enable = true; # Flatpak + the Flathub remote
|
# nomarchy.services.flatpak.enable = true; # Flatpak + the Flathub remote
|
||||||
# nomarchy.services.pika.enable = true; # Pika Backup (GUI Borg backups)
|
# 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";
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ window {
|
|||||||
border-color: @yellow;
|
border-color: @yellow;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
width: 40%;
|
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;
|
location: center;
|
||||||
anchor: center;
|
anchor: center;
|
||||||
x-offset: 0;
|
x-offset: 0;
|
||||||
@@ -90,6 +91,12 @@ element {
|
|||||||
spacing: 15px;
|
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 {
|
element-icon {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ window {
|
|||||||
border-color: @yellow;
|
border-color: @yellow;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
width: 40%;
|
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;
|
location: center;
|
||||||
anchor: center;
|
anchor: center;
|
||||||
x-offset: 0;
|
x-offset: 0;
|
||||||
@@ -90,6 +91,12 @@ element {
|
|||||||
spacing: 15px;
|
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 {
|
element-icon {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
|
|||||||
Reference in New Issue
Block a user