Skip to content

Repository files navigation

NixOS Flake — codebam

Personal NixOS configuration managing three machines: a desktop, a laptop, and a Steam Deck. The same flake defines every host via a shared module tree, with per-host overrides for hardware, networking, and services.

Hosts

Host Arch Root FS Disk
nixos-desktop x86_64 btrfs on LUKS Patriot P400L 1 TB
nixos-laptop x86_64 bcachefs Samsung MZVLB1T0HALR 1 TB
nixos-steamdeck x86_64 btrfs Micron 2500 1 TB

Desktop (nixos-desktop)

  • AMD Ryzen 7 5700X3D + Radeon RX 7900 XTX
  • Dual 2560x1440@240 Hz monitors (DP-1, DP-3)
  • linuxPackages_latest, AMD pstate + prefcore, full preempt
  • aarch64 binfmt emulation
  • GPU overclocking via applyGpuSettings systemd service (3050 MHz core, 334 W power cap)
  • AMDGPU overdrive enabled
  • BTRFS @root wiped every boot via cleanupRoot
  • ROCm support enabled (Ollama)

Laptop (nixos-laptop)

  • Samsung SSD, bcachefs root filesystem
  • linuxPackages_latest
  • Power management: power-profiles-daemon, thermald, upower, powertop
  • No Steam or discrete GPU

Steam Deck (nixos-steamdeck)

  • Jovian NixOS module (vendored prebuilt through chaotic): Steam Deck device support, Decky Loader, Steam auto-start
  • Sway session (Plasma6 forced off)
  • Extest layer, Gamescope, Proton CachyOS
  • RetroArch with libretro cores, Prism Launcher, Moonlight
  • VRAM-based swapfile (2 GB)
  • Distributed builds off the desktop

Flake Structure

/persistent/etc/nixos/
├── flake.nix                    # Entry point: hosts, inputs, packages, devShell
├── flake.lock
├── modules/                     # Shared NixOS modules (every host)
│   ├── default.nix
│   ├── chaotic.nix              # Chaotic NG (vendors prebuilt Jovian; Mesa Git off)
│   ├── lix.nix                  # Lix Nix implementation overlay
│   ├── hardware/                # Bluetooth, uinput, graphics, QMK, redistributable firmware
│   ├── programs/                # nix-index, UWSM/sway, fish, wireshark, gnupg,
│   │                              gaming (Steam/Gamescope), sops-pass
│   ├── security/                # ACME, polkit, apparmor, rtkit, no sudo
│   ├── services/                # scx_lavd, tailscale, pipewire, openssh, ...
│   ├── stylix/                  # kanagawa scheme, Papirus icons, capitaine cursor,
│   │                              JetBrainsMono Nerd Font, synthwave wallpaper
│   ├── system/                  # boot, cleanup-root, env, fonts, journald,
│   │                              networking, nix, nixpkgs (overlays), preservation,
│   │                              streaming-mode, sysctl, systemd, time, xdg, zram
│   └── users/                   # Root + codebam (immutable, fish, Yubikey SSH keys)
├── desktop/
│   ├── disko.nix                # GPT → LUKS → btrfs subvolumes
│   └── configuration/           # cleanupRoot, Viewport, AMDGPU, nftables
│                                  VPN-bypass, services (Lidarr/Prowlarr/Transmission/
│                                  Navidrome/Ollama/OpenRGB/nginx/SearXNG/FlareSolverr),
│                                  audio routing (media ducker, DeepFilterNet), SOPS
│                                  secrets, GPU OC, makano user, nix-serve (tailnet cache),
│                                  daily flake update + kernel/firmware reboot notice
├── desktop-laptop/              # Shared: Podman, IVPN, OBS Studio
├── laptop/
│   └── configuration/           # cleanupRoot (bcachefs), power-profiles-daemon, thermald
├── steamdeck/
│   └── configuration/           # cleanupRoot (btrfs), Jovian, Decky, Steam, RetroArch,
│                                  gaming/extest, lsfg-vk, Moonlight, distributed builds
├── home/                        # Shared home-manager for codebam
│   ├── home.nix                 # Packages, env vars, custom scripts
│   ├── programs.nix             # fish, git, gh, tmux, starship, fastfetch, gpg, wlogout,
│   │                              helix, firefox, mpv (Anime4K), mangohud, browsers,
│   │                              terminals (ghostty, rio)
│   ├── agents.nix               # opencode/opencode2/pi providers, MCP servers, AGENTS.md
│   ├── opensandbox.nix          # rootless-podman OpenSandbox server, osb/MCP wrappers
│   ├── opensandbox-work.nix     # pinned per-work-type sandbox images + osb-work helper
│   ├── qwen-image.nix           # Qwen-Image-2.1 CLI over stable-diffusion.cpp (desktop)
│   ├── services.nix             # swayidle, wl-clip-persist, gpg-agent, tmux user unit
│   ├── shell-common.nix         # bash, carapace, zoxide, direnv, nushell, tmux, fzf
│   ├── stylix.nix               # Per-user theming targets
│   ├── sway.nix                 # Sway config (keybindings, outputs, inputs, gaps, bars)
│   ├── terminal.nix             # defaultTerminal option
│   ├── viewport.nix             # Viewport bootstrap config
│   ├── voxtype.nix              # Offline dictation daemon and transcript processing
│   ├── waybar.nix               # Base Waybar bar config
│   └── xdg.nix                  # MIME apps
├── pkgs/                        # Local derivations (also a standalone flake)
│   ├── default.nix              # The one definition of every local derivation
│   ├── flake.nix                # `nix run github:codebam/nixos?dir=pkgs#<name>`
│   ├── unfree.nix               # Unfree names the hosts and package flake allow
│   ├── agent-overview.nix       # tmux agent dashboard
│   ├── dsh.nix                  # DeepSeek Harness CLI
│   ├── dsh-tool-nu.nix          # dsh's Nushell (`nu`) tool plugin
│   ├── opencode-cli.nix         # @opencode/cli v2 (opencode2)
│   ├── opencode-desktop-beta.nix
│   ├── opensandbox-{sdk,cli,mcp}.nix  # OpenSandbox Python SDK, osb CLI, MCP server
│   ├── pinentry-auto.nix        # terminal-aware pinentry
│   ├── polariumcode/            # Polarium Code desktop app (AppImage wrapper)
│   ├── ripwire.nix              # C++ codebase-map CLI + MCP server
│   ├── sigmashake-desktop.nix
│   ├── ssg.nix                  # sigmashake CLI
│   ├── voxtype-plainify.nix     # transcript filter (a sed program, not a package)
│   └── zvec-grep.nix            # hybrid workspace search + MCP server
├── scripts/                     # manual desktop tools, see scripts/README.md
├── secrets/                     # SOPS-encrypted secrets (Yubikey + age)
└── .sops.yaml                   # SOPS key configuration

Installing a single package

Every derivation in pkgs/ is defined once, in pkgs/default.nix, and exposed two ways, so one can be installed without adopting a host. Prefer the ?dir=pkgs flake: its only input is nixpkgs, so it does not pull this repo's disko/lanzaboote/chaotic/... inputs for a single tool.

nix run   github:codebam/nixos?dir=pkgs#ripwire
nix build github:codebam/nixos?dir=pkgs#dsh
nix profile install github:codebam/nixos?dir=pkgs#zvec-grep

For a NixOS config or another flake, consume the overlay instead:

{
  inputs.packages.url = "github:codebam/nixos?dir=pkgs";
  # ...
  nixpkgs.overlays = [ inputs.packages.overlays.default ];  # then pkgs.ripwire, ...
}

The parent flake exposes the same set (packages.<system>.<name> and overlays.default), so nix run github:codebam/nixos#ripwire works too — it just evaluates the whole input graph. Unfree names are allowed through pkgs/unfree.nix, shared with the hosts, so ssg, sigmashake-desktop and polariumcode resolve without extra config. voxtype-plainify is not here: it is a sed program, not a derivation.

Flake Inputs

Input Source
nixpkgs nixos-unstable
chaotic chaotic-cx/nyx (nyxpkgs-unstable; vendors prebuilt Jovian)
home-manager nix-community/home-manager
disko nix-community/disko
lanzaboote nix-community/lanzaboote (Secure Boot)
rust-overlay oxalica/rust-overlay
sops-nix Mic92/sops-nix
stylix danth/stylix
preservation nix-community/preservation
nix-index-database nix-community/nix-index-database
lsfg-vk-flake pabloaul/lsfg-vk-flake (Steam Deck)
voxtype peteonrails/voxtype v0.7.5
sops-pass codebam/sops-pass
viewport codebam/viewport (compositor; default servoshell backend)

Key Features

Root-on-TMPFS with Cleanup

Every bare-metal host wipes / to a fresh subvolume on every boot using cleanup-root, a custom stage-1 systemd service supporting both btrfs and bcachefs. Old roots archived under old_roots/ for 30 days. A noCleanup boot specialisation preserves the current root for troubleshooting.

Immutable Users

mutableUsers = false. codebam (uid 1000, all hosts) and makano (uid 1001, desktop) with declarative passwords, groups, SSH keys, and shell.

Lix

Nix implementation replaced by Lix, bringing nixpkgs-review, nix-eval-jobs, nix-fast-build, and colmena.

Audio Pipeline (Desktop)

  • Media ducker: LSP sidechain compressor ducks media when game audio detected
  • Game listen: Direct-to-DAC loopback for low-latency game audio
  • DeepFilterNet: AI noise cancellation for microphone input
  • Low-latency quantum (256/512), configurable sample rates (44.1k–96k)

Services

  • Media: Lidarr, Prowlarr, Transmission, Navidrome behind nginx + ACME
  • Search: SearXNG on 127.0.0.1:8081 (JSON API for agents)
  • Cloudflare: FlareSolverr container (loopback) for interstitial solving
  • Local AI: Ollama (loopback, AMD ROCm override)
  • Networking: Tailscale, IVPN, NetworkManager/iwd, systemd-resolved (DoT)
  • Gaming: Steam (extest, Gamescope, Proton CachyOS); Steam firewall holes closed
  • GPU: OpenRGB
  • Monitoring: SMART disk monitoring
  • Cache: nix-serve-ng on the desktop serves the tailnet (laptop/Deck pull locally-built paths instead of compiling them)

Desktop

  • Viewport (Smithay rewrite): primary Wayland compositor, servoshell (Servo) backend
  • Sway (sway_git): fallback under UWSM
  • Waybar: transparent status bar with system stats, MPRIS controls, GPU telemetry
  • Swaylock, Wlogout: screen lock and session management
  • ArRPC + Mprisence: Discord Rich Presence

Home Manager

  • Shells: nushell (default login shell), atuin, fish, bash, tmux, starship, zoxide, direnv, fzf
  • Editors: Helix (git, nixd LSP), vim → hx alias
  • Browsers: Firefox, Google Chrome, Ungoogled Chromium
  • Terminals: Ghostty, Rio
  • Agents: OpenCode (v1 stable + v2 opencode2), OpenCode Desktop, Pi, and dsh, plus Hermes (CLI, gateway, and Desktop) on the desktop. The host harnesses keep their zvec-grep/ripwire/OpenSandbox/Playwright MCP rows and are trusted host tools; Hermes' terminal and file tools are the exception (its OpenSandbox backend, under Sandboxes below); dsh's OpenSandbox world (the web profile) also registers the shared memory MCP and the isolated, headless Playwright MCP (its file access is scoped to the session workspace by Playwright's default guardrail, and it runs on the host network). Hermes and dsh additionally register the agentic-inbox email MCP, a host-side stdio bridge that authenticates with the local wrangler login token (run npx wrangler login once from that checkout); both harnesses carry a standing instruction that outbound mail is sent only after an explicit authorization for that exact message.
  • Sandboxes: rootless-podman OpenSandbox service plus pinned per-work-type images (osb-work list: nix, python, web, bun, rust, c-cpp, dotnet, lua, steel, shell, browser, code). opencode2's shell tool executes through opencode-sandbox-shell (home/opencode-sandbox-shell.nix): one container per workspace root, the workspace and a read-only /nix/store bind-mounted at their host paths, no credentials; OPENCODE2_NO_SANDBOX=1 in the launching environment restores the host shell for that session. Hermes' terminal and file tools execute through the registered opensandbox terminal backend (home/hermes-opensandbox.nix) with home/opensandbox-exec.nix as the per-command executor: the same container shape, one per workspace root. A session directory that cannot be a workspace -- the home directory contains ~/.gnupg -- falls back to the host shell with a notice in its first command's output; HERMES_OPENSANDBOX_FALLBACK=error refuses instead, and HERMES_NO_SANDBOX=1 restores the host shell for that process. The dsh plugin is installed per profile with dsh's own plugin manager (dsh plugin --profile web add @codebam/dsh-opensandbox). The default world is the untrusted-agent tier: project plus /nix/store read-only, no credentials or host Nix daemon, a mount-fenced ctx.fs, and no host-side MCP bridges other than the isolated, headless Playwright browser row and the Wrangler-authenticated agentic-inbox email bridge. Both run as the host user and read their host state (browser profile, Wrangler token) outside the sandbox. A human scopes one directory with /directory-add in a session, or launches dsh-host-access for reviewed host builds/commits/pushes. dsh-no-opensandbox is the unhardened built-in bwrap/Landlock fallback for a session when the local OpenSandbox server is unhealthy. The sandbox network is created without podman's per-network DNS server (--disable-dns in home/opensandbox.nix): aardvark-dns is a single process per network with no self-healing, and when it dies, or is left behind in a torn-down rootless netns, every sandbox silently loses name resolution while egress keeps working (podman-container-tools/podman#20396). Without it the containers get the host's resolvers through pasta -- 169.254.1.1 (systemd-resolved) first -- so the host's DoT policy and the tailnet search domain still apply. Egress filtering is the known gap: sandbox traffic still reaches the LAN/tailnet as the host user, and rootless podman's network mode makes a host-nft source rule unreliable; the intended follow-up is OpenSandbox network_policy with the bridge network.
  • Dev: gh, git (signed commits), claude-code
  • Images: qwen-image renders a prompt with Qwen-Image-2.1 through stable-diffusion.cpp (HIP on the desktop card) into the current directory; qwen-image-models downloads and verifies the ~10 GiB of GGUF weights into ~/.local/share/qwen-image first (also done on demand by qwen-image). The desktop-only package pin and the model flags live in home/qwen-image.nix, the version pin in pkgs/default.nix.
  • Media: mpv (Anime4K upscaling), OBS Studio (VAAPI)
  • Gaming: MangoHud, Prism Launcher (Deck), Moonlight (Deck)

Security

  • AppArmor enabled, polkit (local/active wheel passwordless), no sudo
  • OpenSSH: key-only, no root, kbd-interactive off, tailnet-only (openFirewall = false)
  • GPG agent with Yubikeys (graphical pinentry)
  • SOPS secrets via age + Yubikeys
  • Secure Boot via lanzaboote

Convenience

# Development shell with Nix tooling
nix develop

# Format all Nix files
nix fmt

# Check all configurations (builds every host)
nix flake check

# Build a single local package
nix build .#ripwire

# Rebuild
nh os switch

About

My NixOS configuration

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages