Imported from Nicothekiller/nix-configs (
AGENTS.md). Install upstream withnpx skills add Nicothekiller/nix-configs. Copyright stays with the author.
AGENTS.md
This is a NixOS system configuration repository using Nix Flakes. It defines reproducible NixOS installations for multiple x86_64-linux hosts. The entire codebase is written in the Nix expression language.
Repository Structure
flake.nix # Flake inputs and flake-parts entry point
flake.lock # Pinned dependency versions
modules/ # Auto-imported flake-parts modules
hosts.nix # NixOS outputs and host composition
home-manager.nix # Home Manager integration and user base
home/ # Home Manager feature modules (kitty, starship, fastfetch, opencode)
terminal/ # Shell environment (bash, zsh, nushell, aliases, integrations, env)
overlays.nix # Shared nixpkgs overlays (flatpak patch, packet tracer)
patches/ # Local patches (flatpak fonts/icons fix)
boot.nix # Bootloader and kernel (systemd-boot, explicit LTS kernel)
cli-tools.nix # CLI and development packages
applications.nix # Desktop applications
desktop-theme/ # GTK, Qt, cursor, and theme packages
file-manager/ # Dolphin, KIO, MIME, and filesystem helpers
desktop-services.nix # Flatpak and KDE Connect
desktop-services-system.nix # Bluetooth, PolKit, UDisks2, UPower, thermald
fonts.nix # System fonts
gaming.nix # Steam and Proton-GE
hyprland.nix # Hyprland, Noctalia, portals, and user config
audio.nix # PipeWire and audio services
locale.nix # Timezone, locale, and keymaps
network.nix # NetworkManager, firewalld (nftables backend), DNS
nix.nix # Nix settings, nix-ld, nh cleanup
printing.nix # CUPS and printer drivers
ssh.nix # OpenSSH (port restricted via firewalld home zone)
tailscale.nix # Tailscale (manual `tailscale up`, no auth key in repo)
users.nix # User accounts and groups (password set imperatively at install)
secrets.nix # Keyring/secret-service integration (no secret values)
system-state.nix # system.stateVersion (25.11; home.stateVersion is 26.05)
virtualisation.nix # Docker and Compose tools
ai-course-deps.nix # AI course packages (ollama, jupyter)
redes-course-deps.nix # Networks course packages (containerlab, wireshark, packet tracer)
packages/ # Local package definitions
cisco-packet-tracer.nix # Cisco Packet Tracer from a local .deb (see design notes)
hosts/ # Host-specific NixOS modules
nic-on-nixosbtw/ # Intel host using ext4
hardware-configuration.nix # Auto-generated hardware detection (do not edit)
local-configuration.nix # Intel VA-API settings
nic-on-nixosbtw2/ # Intel host with NVIDIA dGPU using btrfs
hardware-configuration.nix # Auto-generated hardware detection (do not edit)
local-configuration.nix # NVIDIA PRIME offload and filesystem settings
dotfiles/ # Out-of-store application configuration
Architecture
This repository uses the dendritic pattern with flake-parts and
import-tree:
- Every
.nixfile undermodules/is automatically imported as a flake-parts module. - Shared features publish NixOS modules through
flake.modules.nixos.<feature>and Home Manager modules throughflake.modules.homeManager.<feature>. - Host definitions include all shared NixOS modules automatically.
- The Home Manager base module includes all shared Home Manager modules automatically.
- Files under
hosts/<hostname>/are ordinary NixOS modules and contain only hardware configuration or host-specific overrides.
There is intentionally no shared configuration.nix, package aggregator, or
manual module import list. Add shared features under modules/; add
host-specific settings under the corresponding hosts/ directory.
Design Notes (intentional choices -- do not "fix")
- All shared modules apply to every host via
sharedModulesinmodules/hosts.nix. Per-host differences go inhosts/<hostname>/local-configuration.nixonly. - Firewall:
networking.firewall.enable = falsewithservices.firewalld.enable = trueplusnetworking.nftables.enable = trueis intentional. firewalld uses nftables as its backend (it fails to build without the nftables option) and provides dynamic interface/network zones for laptops, so rules are managed at runtime viafirewall-cmd, not via rebuilds. - SSH:
services.openssh.enable = truewith no Nix-level hardening because the port is only open in the firewalld home zone. Do not addopenFirewall(it targetsnetworking.firewall, which is disabled). - Users:
users.users.nichas no declarative password. A temporaryinitialPasswordis added at install time and removed afterwards. - Packet Tracer:
flake.nixuses an absolutepath:/home/nic/Downloads/...debinput on purpose. Cisco requires an account to download it, there is nowhere to upload it, the version is frozen at 9.0.1, and flake inputs evaluate without--impure(unlike a git-ignored relative path, which Nix skips unlessgit add-ed). - Flatpak:
modules/overlays.nixswaps in a localmodules/patches/fix-fonts-icons.patchby basename. The upstream PR has sat unreviewed for months, so the overlay stays and fails loudly (viathrow) if nixpkgs renames or merges the patch. - Steam: do not manually set
hardware.graphics.enable32Bitorhardware.steam-hardware.enable; thesteammodule enables both automatically. - btw2 NVIDIA:
GBM_BACKEND=nvidia-drm,WLR_NO_HARDWARE_CURSORS=1, andLIBVA_DRIVER_NAME=iHDwithoutnvidia-vaapi-driverare intentional -- HDMI is wired to the dGPU and Intel handles decode. Bus IDs are host-specific by design and stable across reboots. The defaulthardware.nvidia.packagetracks the stable driver, not latest. - Tailscale: declarative
authKeyFile,useRoutingFeatures, andopenFirewallare intentionally unused (no secrets in repo, no routing features,openFirewalltargets the disabled NixOS firewall). Runtailscale upmanually. - Versions:
system.stateVersion = "25.11"withhome.stateVersion = "26.05"is intentional (Home Manager adopted later). Never bump either to "fix" the skew on existing installs. - Kernel:
boot.kernelPackages = pkgs.linuxPackagesis explicit on purpose so it is easy to change later. - Nix GC: the commented-out
nix.gcblock inmodules/nix.nixdocuments the previous setup and stays untilprograms.nh.cleanproves out long-term. Extrasubstituters/trusted-public-keysappend the officialcache.nixos.org; they do not replace it. hardware-configuration.nixfiles are auto-generated;fmask/dmaskdifferences between hosts come fromnixos-generate-config, do not edit.
Build / Rebuild Commands
There is no Makefile or task runner. All operations use nixos-rebuild and nix.
# Build and activate config for a specific host (requires sudo)
sudo nixos-rebuild switch --flake .#nic-on-nixosbtw
sudo nixos-rebuild switch --flake .#nic-on-nixosbtw2
# Build and activate without adding a boot entry
sudo nixos-rebuild test --flake .#<hostname>
# Build only -- no activation, good for checking if config evaluates
sudo nixos-rebuild build --flake .#<hostname>
# Validate flake structure and NixOS configurations
nix flake check path:.
# Update flake.lock to latest inputs
nix flake update
Formatting
The project uses nixfmt (installed in modules/cli-tools.nix). There is no
pre-commit hook or CI pipeline enforcing formatting.
# Format a single file
nixfmt <file.nix>
# Format all nix files
find . -name '*.nix' -exec nixfmt {} +
Testing / Validation
There are no unit tests or automated NixOS VM tests defined. Manual VM testing is useful for activation and desktop behavior; evaluation is validated by building the configuration:
# Dry-run build to catch evaluation errors without writing to the store
nix build path:.#nixosConfigurations.nic-on-nixosbtw.config.system.build.toplevel --dry-run
# Full build (validates the entire config evaluates and all derivations resolve)
sudo nixos-rebuild build --flake .#<hostname>
Code Style Guidelines
Language: Nix
All files are .nix. No other languages are used. Familiarize yourself with
the NixOS module system before making changes.
File and Directory Naming
- Files: lowercase, kebab-case for multi-word (
local-configuration.nix) - Directories: lowercase, kebab-case (
nic-on-nixosbtw2) - One domain concern per module file in
modules/
Module Signature
Every hand-written module uses a function signature with ... and only the
parameters it actually references:
# Module that uses pkgs
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ git ];
}
# Module that needs no parameters
{ ... }:
{
boot.loader.systemd-boot.enable = true;
}
- Only include parameters (
config,pkgs,lib, etc.) if they are used in the module body. Do not add unused parameters. - Always include
...in the signature to accept extra arguments. - Host
local-configuration.nixfiles may use a bare attrset (no function signature) when no parameters are needed. hardware-configuration.nixfiles are auto-generated -- do not edit them.
Indentation and Formatting
- 2 spaces, no tabs.
- One blank line between the function signature and the opening
{. - One blank line between logically distinct groups of settings.
- Opening
{for nested attrsets goes on the same line as the attribute. - Closing
};on its own line at the attribute's indentation level. - Keep lines under 80 characters for hand-written code.
Attribute Path Style
- Use flat dotted paths for 1-2 settings under a parent:
boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - Use attrset blocks when setting 3+ related values under the same parent:
virtualisation.docker = { enable = true; enableOnBoot = false; };
Package Lists
Scope with pkgs; inline on the list expression, not at module level:
environment.systemPackages = with pkgs; [
git
neovim
];
For sub-namespaces: with pkgs.kdePackages; [ ... ];
Long lists: one item per line, alphabetical order where practical.
Short lists: inline on one line ([ "xhci_pci" "ahci" "nvme" ]).
Imports
- Shared modules under
modules/are auto-imported; do not add manual import lists for them. - Host definitions in
modules/hosts.nixexplicitly reference the matching hardware and local configuration files underhosts/. - Hardware configs use
modulesPathstring concatenation for nixpkgs internals.
Comments
- Use
#with a single space after:# This is a comment - Place comments on the line above the code they describe
- Keep commented-out code as documentation for disabled options
- No multi-line
/* */comments in this codebase
Error Handling
This is a purely declarative configuration -- no explicit error handling
(assert, throw, tryEval). Errors are caught at nixos-rebuild evaluation
time. If you need conditional configuration, use lib.mkIf.
Boolean Options
Use .enable = true; / .enable = false; for service toggles. This is the
standard NixOS pattern.
Adding a New Module
- Create a focused
.nixfile undermodules/. - Publish the feature as
flake.modules.nixos.<feature>,flake.modules.homeManager.<feature>, or both. - Keep each file focused on one concern. Multiple files may contribute to the same feature name when a feature needs to be split by implementation detail.
- Do not add the file to an import list;
import-treediscovers it automatically.
Adding a New Host
- Create
hosts/<hostname>/directory - Generate
hardware-configuration.nixwithnixos-generate-config - Create
local-configuration.nixwith host-specific overrides (at minimum:networking.hostName) - Add a new
nixosConfigurations.<hostname>entry inmodules/hosts.nix
Git Conventions
- Commit messages follow Conventional Commits:
feat:,chore:, etc. - Lowercase, imperative descriptions, no trailing period
- Examples:
feat: add docker,chore: update flake,feat: modularize nix configs - Linear history on
masterbranch (no feature branches observed)