Files
2026-07-10 09:00:50 +02:00

3.5 KiB

Flake-based NixOS + home-manager config (public half)

Usage, quick-start, and how to consume the modules are in README.md — read it first.

This is the public half of a two-repo split: reusable modules + an example template host. The matching private repo holds the real inventory (nixosConfigurations.<host>, hosts/<host>/, SSH/Syncthing topology) and imports this one as a flake input. Deploy happens from the private repo, not here.

Editing invariant — pick the layer before adding config:

  • generic/reusable → a module here (modules/*.nix, nixosModules.* / homeModules.*); make machine/user specifics options with defaults, never hard-code personal values.
  • machine list / hostnames / topology (SSH hosts, Syncthing peers, IPs) → the private inventory repo, never here. The example host carries only placeholders.
  • secrets (keys, tokens, passwords) → neither repo; runtime files or a secrets manager decrypting to a path. See the SSH section.

Overrides = options (the consumer contract)

Private imports these modules read-only (flake input) — it can't patch a package list or a hard-coded value in place. So anything a consumer might reasonably want to change is exposed as an option with a default, never baked into config. That is what makes this repo a baseline others extend rather than a fork-and-patch.

Pattern (see modules/texlive.nix): option-bearing config lives in its own sub-module under the local.* namespace, imports-ed by home.nix. A module that declares options must use the split { options = …; config = …; } form, so isolating it per file keeps home.nix bare. Override is then one line, e.g. local.texlive.package = pkgs.texlive.withPackages (ps: [ ps.scheme-full ]);. A plain value with nothing to vary goes straight in the bare package list — no option, don't over-abstract.

Maxim: keep $HOME clean (XDG)

Standing principle for every addition: minimise dotfiles/dirs in $HOME. Route a tool's config → ~/.config, state/history → ~/.local/state, cache → ~/.cache, data → ~/.local/share, normally by setting env vars in home.sessionVariables (use config.xdg.{config,state,cache,data}Home). Prefer this to letting a tool litter ~.

Cannot be relocated, leave alone: ~/.zshenv (bootstraps ZDOTDIR), ~/.nix-profile and ~/.nix-defexpr (nix), ~/.icons (cursor theme — spec mandates ~/.icons), ~/.pki/nssdb (NSS cert/key DB — path hardcoded in NSS, ignores XDG; created by any Chromium/NSS/CEF app, e.g. grayjay's embedded webview).

Desktop environment

Wayland. Compositor Hyprland, bar Waybar, terminal foot — all configured declaratively in modules/home.nix (wayland.windowManager.hyprland, programs.waybar, programs.foot). Font is JetBrainsMono Nerd Font; Waybar/foot use Nerd Font glyphs (nf-md set) for icons, so new glyphs should come from that set for visual consistency.

Hyprland uses the master layout and a German keyboard (kb_layout = "de"). Look deliberately minimal: animations, blur, rounding, and shadows are all turned off on purpose — don't reintroduce them when adding desktop tweaks.

Rust dev environments

Before setting up Rust for a project, read the devShells comment in flake.nix. Short version: default is the shared rust devShell (use flake ~/.nixos-config#rust via direnv); give a project its own flake.nix only when it needs its own pinned Rust version or native C deps. The comment explains the tradeoff.