NixOS flake config for my personal machines.
| Host | Machine | Role |
|---|---|---|
| blackbox | Ryzen 7 5800X3D, Radeon RX 9070 XT | Desktop — gaming, audio production, streaming |
| nixpad | ThinkPad X1 Yoga Gen 6 (i7-1185G7, Iris Xe) | Laptop — niri-only convertible with LUKS |
Each host is a mkHost call in flake.nix and a directory under hosts/ containing default.nix (options) and hardware-configuration.nix.
Hosts configure themselves through mySystem.* options defined in modules/nixos/options.nix. This drives conditional module loading and feature gating.
wms— compositors to enable on this host. Options:hyprland,niri.monitors— list of displays with name, resolution, refresh rate, position, scale, VRR flag, and aprimarydesignation (used by noctalia and steam). Consumed by both hyprland and niri configs.
form—desktoporlaptop. Gates the kernel (CachyOS on desktop, linuxPackages_latest on laptop), the power management stack, and the scx scheduler.gpu—amd,intel,nvidia, ornone. Activates the matching GPU module (nvidiais currently an empty stub).swapfile.enable/swapfile.sizeGB— opt-in swapfile at/var/lib/swapfile.peripherals.wooting— Wooting keyboard udev rules.
gaming— Steam extras, Proton tooling, Prism (jdk8/17/21), mod managers.streaming— OBS, DaVinci Resolve, v4l2loopback kernel module.audioProduction— Bitwig, yabridge, Wine, plugin paths.
cache.enable— pull from the homelab Harmonia binary cache.remoteBuilder.enable— use the homelab as a distributed-build machine.
enable— restic push to the homelab REST server.paths/exclude— what gets backed up and what doesn't.onCalendar— systemd timer schedule.
Click to expand
.
├── flake.nix
├── flake.lock
├── hosts/
│ ├── blackbox/ # desktop
│ │ ├── default.nix
│ │ └── hardware-configuration.nix
│ └── nixpad/ # laptop (LUKS)
│ ├── default.nix
│ └── hardware-configuration.nix
└── modules/
├── nixos/ # system-level
│ ├── default.nix
│ ├── options.nix # mySystem.* option definitions
│ ├── boot.nix # systemd-boot, kernel (form-gated), swap
│ ├── desktop.nix # pipewire, ly, locale, scx (desktop-gated)
│ ├── flatpak.nix # declarative flatpaks via nix-flatpak
│ ├── homelab.nix # Harmonia cache + remote builder (mySystem.homelab)
│ ├── networking.nix # resolved, tailscale, mullvad, NM (laptop-gated)
│ ├── nix.nix # lix, substituters, nh
│ ├── performance.nix # sysctl tweaks, gamemode
│ ├── programs.nix # steam (millennium), regionlock, fonts, nix-ld, appimage
│ ├── restic.nix # restic push to homelab REST server (mySystem.backup)
│ ├── secrets.nix # sops-nix
│ ├── users.nix
│ ├── hardware/ # gated hardware modules
│ │ ├── default.nix # bluetooth, TPM2
│ │ ├── amd.nix # amdgpu, lact, opencl
│ │ ├── intel.nix # intel-media-driver, iHD, compute runtime
│ │ ├── nvidia.nix
│ │ ├── laptop.nix # PPD, thermald, fprintd, power tunables
│ │ └── wooting.nix # udev rules
│ └── wm/
│ ├── hyprland.nix
│ └── niri.nix # nixpkgs niri + nirinit session restore
│
└── home/ # home-manager
├── default.nix
├── packages.nix # general CLI/GUI tools
├── desktop/
│ ├── default.nix # conditionally imports per-WM modules
│ ├── common/ # compositor-agnostic
│ │ ├── default.nix
│ │ ├── packages.nix
│ │ ├── services.nix # cliphist, udiskie
│ │ ├── theme.nix # GTK/Qt/kvantum catppuccin
│ │ ├── nautilus.nix # nautilus + GTK bookmarks
│ │ ├── noctalia.nix
│ │ └── xdg.nix # portals, mime, userDirs
│ └── wm/
│ ├── hyprland/{default.nix,binds.nix}
│ └── niri/{default.nix,binds.nix}
├── programs/
│ ├── default.nix # feature-gated imports
│ ├── agent-sandbox.nix # shared bwrapper preset for agent sandboxes
│ ├── agents.nix # claude + claude-work (unsandboxed), codex + opencode (bwrapper-sandboxed)
│ ├── audio.nix # bitwig, yabridge (gated on audioProduction)
│ ├── chat.nix # chatterino; vesktop + slack (bwrapper-sandboxed)
│ ├── cli.nix
│ ├── fastfetch/ # module + λ-styled logo
│ ├── firefox.nix
│ ├── gaming.nix # steam extras, prism, mod managers (gated on gaming)
│ ├── git.nix
│ ├── kiro.nix # kiro-cli (work agent), bwrapper-sandboxed
│ ├── laptop.nix # pen/tablet + misc laptop utils
│ ├── neovim.nix # via nvf
│ ├── obs.nix # (gated on streaming)
│ ├── rustypaste.nix # rustypaste client + paste-clip (homelab pastebin)
│ ├── spotify.nix # spicetify
│ ├── terminals.nix # ghostty + alacritty
│ └── thunderbird.nix
└── shell/
├── default.nix
└── zsh.nix # zsh + p10k (also imported by the homelab flake)
niri itself now comes from nixpkgs (programs.niri) — the niri-flake input is gone.
- home-manager — user environment, imported as a NixOS module
- nvf — Neovim configuration framework
- noctalia — quickshell-based bar, universal across compositors (
cachixbranch) - Chaotic-Nyx — CachyOS kernel (desktop only) + nyx binary cache (all hosts)
- nix-bwrapper — bubblewrap sandboxing (codex, opencode, kiro, slack, vesktop)
- nirinit — session restore for niri
- sops-nix — secrets management
- catppuccin/nix — Theming
- spicetify-nix — Spotify Theming
- regionlock — SDR matchmaking region biasing (Deadlock)
- grimoire — GameBanana mod manager (Deadlock mods)
- nix-flatpak — declarative flatpak management
- nix-index-database — prebuilt nix-index + comma
- NUR — Firefox extensions
- Millennium — Steam theming + extensions
The homelab runs the maintenance loop for the desktop flake (gegnep/nixos) end to end — bump, build, serve, scan, report. In normal operation the desktops substitute everything from the homelab instead of compiling; only a local change ahead of the homelab's last build forces local work.
- flake-builder (
services/flake-builder.nix) — nightly timer that maintains an isolated clone ofgithub:gegnep/nixos, runsnix flake update(all inputs), builds bothblackboxandnixpadtoplevels, and only if both succeed commits and pushes the lock (chore: bump flake.lock (automated)). A failed build never advances the lock — the hosts must evaluate exactly the lock the homelab built, or substitution breaks. Last successful pair of toplevels is kept as gcroots under/var/lib/flake-buildersonh cleancan't evict closures before the hosts pull them. Runs atNice=19/CPUWeight=25so nightly kernel compiles don't starve services. - Harmonia (
services/buildserver.nix) — serves the resulting store paths; the desktops listhttp://homelab:5000+ thehomelab-1key as a substituter. - nightly scan — a scheduled Claude routine that runs after the bump window and reports to
gegnep/nixosissues. It covers both this repo and the homelab flake (gegnep/nixos-prod), tagging each finding with its repo. It triages any open build failure first (root cause from the embedded log, snippet-ready fix commented on the issue, labeledtriaged), then scans both configs for deprecated/renamed/removed options and packages — verified against the locked input revs via the mcp-nixos connector (also hosted here,services/mcp-nixos.nix), not channel HEAD. Findings are graded Critical / Warning / Info with file:line, a ready-to-apply fix, and a source link; each run diffs against the previous scan so unchanged items carry as one-liners, and each new report closes the previous night's issue as superseded.
Issue labels are the state machine:
| Labels | Opened by | Meaning | Closed by |
|---|---|---|---|
flake-builder + automated |
the bump job, on failure | lock not advanced, hosts pinned to last-good; log tail embedded | the next green bump |
↳ + triaged |
the scan | diagnosis + fix commented | — |
nightly-scan + automated |
the scan, daily | that night's findings report | the next scan (superseded); immediately, on a clean run |
Failure path: bump fails → flake-builder issue (+ ntfy push) → scan triages it that night → fix lands in the desktop repo → next bump goes green, closes the issue, Harmonia serves the new closures.
Catppuccin Mocha Lavender across the stack. catppuccin.autoEnable = true themes everything the catppuccin/nix modules support (bat, btop, fzf, ghostty, lazygit, tmux, atuin, eza, mpv, mangohud, obs, kvantum, gtk icons, ...); spicetify and nvf theme through their own mechanisms. The exceptions, documented in the relevant module:
- Firefox — opted out of catppuccin/nix (it fights the managed extension set); content theming via Stylus with manually-imported per-site userstyles.
- Hyprland — opted out; manual mocha palette in
wm/hyprland(the module currently injects a broken lua-inline block into hyprlang). - GTK4 / libadwaita — symlinks from the catppuccin-gtk package into
~/.config/gtk-4.0/viaxdg.configFile(seemodules/home/desktop/common/theme.nix). Required because GTK4 doesn't read themes the way GTK3 does. - Discord — runs as bwrapper-sandboxed Vesktop; catppuccin is a one-time Vencord toggle whose state persists in the sandbox home (
~/.bwrapper/vesktop/).
- systemd-boot, CachyOS kernel, 32 GiB swapfile, scx scheduler active
- LACT for AMD GPU power/fan control
- 2560x1440@165 + 1920x1080@100 dual monitor
- Both hyprland and niri sessions available
- Homelab Harmonia cache; restic backups (home + bulk storage) to the homelab
- systemd-boot, mainline kernel, 16 GiB swapfile, LUKS2 on root
- Power-profiles-daemon, thermald, fprintd, fwupd, battery thresholds at 75/90
- NetworkManager (laptop-gated)
- Aggressive PCI/USB/audio runtime PM via powerManagement.powertop + modprobe options
- niri-only
- Homelab Harmonia cache + remote builder; restic backups to the homelab
# On the target host:
nh os switch
# Or from anywhere:
sudo nixos-rebuild switch --flake /path/to/flake.#<hostname>portions of this configuration were developed in collaboration with Claude; AI suggestions should never replace your own understanding of your system
