# AGENTS.md - NixOS Configuration Repository **Generated:** 2025-12-29 | **Branch:** master | **Commit:** 460fc92 Multi-host NixOS flake managing servers and workstations with home-manager integration. ## Host Inventory | Host | Type | Purpose | Key Services | |------|------|---------|--------------| | m3-atlas | VPS | Main server | Traefik, containers (n8n, ghost, baserow, vaultwarden, paperless, gitea) | | m3-helios | VPS | DNS/Dashboard | AdGuard Home, Homarr, Traefik | | m3-ares | Workstation | Desktop | WireGuard VPN, Tailscale, sound, podman | | m3-kratos | Workstation | Desktop | WireGuard VPN, Tailscale, Hyprland, gaming | | m3-aether | VM | Cloud-init | Minimal config | | m3-daedalus | - | Home-manager only | Desktop environment (no NixOS config) | ## Key Inputs nixpkgs (unstable), nixpkgs-stable (25.05), home-manager, agenix, disko, nix-colors, m3ta-nixpkgs (private fork) ## Build/Rebuild Commands ```bash # NixOS system rebuild sudo nixos-rebuild switch --flake .# sudo nixos-rebuild switch --flake .#m3-atlas # Home-manager rebuild home-manager --flake . switch home-manager --flake .#m3tam3re@m3-daedalus switch # Flake operations nix flake check # Validate flake nix flake update # Update all inputs nix flake lock --update-input # Update single input # Development shell nix develop .#infraShell # OpenTofu + nixos-anywhere # Format Nix files alejandra . # Format all .nix files alejandra # Format single file ``` ## Testing No formal test suite. Verification is done via: ```bash nix flake check # Syntax and evaluation check nix build .#nixosConfigurations..config.system.build.toplevel --dry-run ``` ## Directory Structure ``` . ├── flake.nix # Flake definition with all hosts ├── secrets.nix # Agenix public key mappings ├── home/ │ ├── common/ # Shared home-manager config (overlays, nix settings) │ ├── features/ # Modular features │ │ ├── cli/ # Shell tools (fish, nushell, starship, zellij) │ │ ├── coding/ # Development tools │ │ └── desktop/ # GUI apps, Hyprland, theming │ └── m3tam3re/ # Per-host user configs ├── hosts/ │ ├── common/ # Shared NixOS config │ │ ├── extraServices/ # Toggle-able services (ollama, podman, flatpak) │ │ ├── users/ # User definitions │ │ └── ports.nix # Port allocations │ └── m3-*/ # Host-specific configs │ ├── default.nix # Entry point (imports common + host modules) │ ├── configuration.nix # Core system config │ ├── hardware-configuration.nix │ ├── programs.nix # Host-specific programs │ ├── secrets.nix # Agenix secret declarations │ └── services/ # Service configurations │ └── containers/ # OCI container definitions ├── modules/ # Custom NixOS/home-manager modules ├── overlays/ # Nixpkgs overlays (stable, locked, pinned, master) ├── pkgs/ # Custom package definitions └── secrets/ # Encrypted .age files ``` ## Code Style Guidelines ### Module Pattern Standard Nix module structure: ```nix { config, lib, pkgs, ... }: { imports = [ ./submodule.nix ]; # Configuration here } ``` ### Formatting - **Formatter**: Use `alejandra` (included in CLI packages) - **Indentation**: 2 spaces - **Line length**: No strict limit, but keep readable - **Trailing commas**: Required in lists and attrsets - **Semicolons**: Required after each attribute ### Naming Conventions | Type | Convention | Example | |------|------------|---------| | Files | lowercase, hyphenated | `hardware-configuration.nix` | | Hosts | `m3-` | `m3-atlas`, `m3-kratos` | | Options | camelCase path | `extraServices.ollama.enable` | | Feature flags | `features...enable` | `features.cli.nushell.enable` | | Secrets | `-env.age` or descriptive | `n8n-env.age`, `wg-DE.age` | ### Option Definitions Use lib functions for custom options: ```nix { config, lib, pkgs, ... }: with lib; let cfg = config.features.cli.myFeature; in { options.features.cli.myFeature.enable = mkEnableOption "enable myFeature"; config = mkIf cfg.enable { # Configuration when enabled }; } ``` ### Imports - Import order: inputs/modules first, then local files - Use relative paths: `./subdir` or `../common` - Group related imports together ### Package Lists ```nix home.packages = with pkgs; [ package1 package2 # Commented packages for reference # disabled-package ]; ``` ## Secrets Management Uses **agenix** for encrypted secrets. ### Adding a New Secret 1. Create the secret file: ```bash agenix -e secrets/my-secret.age ``` 2. Register in `secrets.nix`: ```nix "secrets/my-secret.age".publicKeys = systems ++ users; ``` 3. Declare in host's `secrets.nix`: ```nix age.secrets.my-secret = { file = ../../secrets/my-secret.age; owner = "service-user"; # Optional mode = "644"; # Optional }; ``` 4. Reference in config: ```nix environmentFiles = [config.age.secrets.my-secret.path]; ``` ## Container Services Pattern OCI containers via podman: ```nix {config, ...}: { virtualisation.oci-containers.containers."service-name" = { image = "registry/image:tag"; environmentFiles = [config.age.secrets.service-env.path]; ports = ["127.0.0.1:8080:8080"]; volumes = ["service_data:/data"]; extraOptions = ["--network=web"]; }; # Traefik routing services.traefik.dynamicConfigOptions.http = { services.service-name.loadBalancer.servers = [ { url = "http://localhost:8080/"; } ]; routers.service-name = { rule = "Host(`service.domain.com`)"; tls.certResolver = "godaddy"; service = "service-name"; entrypoints = "websecure"; }; }; } ``` ## Theming Uses **nix-colors** with Dracula scheme: ```nix colorScheme = inputs.nix-colors.colorSchemes.dracula; # Reference colors "#${config.colorScheme.palette.base00}" # Background "#${config.colorScheme.palette.base05}" # Foreground ``` ## Overlays Custom overlays in `overlays/default.nix`: - `stable-packages`: nixpkgs-stable as `pkgs.stable.*` - `locked-packages`: Pinned nixpkgs as `pkgs.locked.*` - `master-packages`: nixpkgs-master as `pkgs.master.*` Use when you need a specific package version: ```nix home.packages = [ pkgs.stable.somePackage ]; ``` ## Common Pitfalls 1. **Missing imports**: Ensure new files are imported in parent `default.nix` 2. **Secret paths**: Use `config.age.secrets..path`, not hardcoded paths 3. **Rebuild required**: Changes need `nixos-rebuild` or `home-manager switch` 4. **Overlay scope**: Overlays must be added to both `home/common` and `hosts/common` 5. **Port conflicts**: Check `hosts/common/ports.nix` before allocating new ports ## Commit Style Short, descriptive messages: - `flake update` - Dependency updates - `+package` - Adding new package - `service-name: description` - Service changes - `host: description` - Host-specific changes ## Container IP Registry (m3-atlas) Network: `10.89.0.0/24`, Gateway: `10.89.0.1` (postgres host) | Service | IP | Port | |---------|-----|------| | baserow | 10.89.0.4 | 3001 | | ghost | 10.89.0.10 | 3002 | | slash | 10.89.0.11 | 3010 | | littlelink | 10.89.0.13 | 3004 | | n8n | 10.89.0.14 | 5678 | | restreamer | 10.89.0.15 | 3006 | | kestra | 10.89.0.17 | 3018 | | pangolin | 10.89.0.20 | 3020 | **Next available IP**: 10.89.0.22 ## Feature Flags Home-manager features use `mkEnableOption` pattern: - `features.cli.*` - Shell tools (nushell, fzf, nitch, starship, secrets) - `features.desktop.*` - GUI apps (crypto, coding, gaming, hyprland, media, office, rofi, fonts, wayland) - `extraServices.*` - NixOS services (ollama, podman, flatpak, virtualisation) Enable in per-host configs: `features.cli.nushell.enable = true;`