Files
nixos-config/AGENTS.md

8.1 KiB

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

# NixOS system rebuild
sudo nixos-rebuild switch --flake .#<hostname>
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 <name>  # Update single input

# Development shell
nix develop .#infraShell           # OpenTofu + nixos-anywhere

# Format Nix files
alejandra .                        # Format all .nix files
alejandra <file.nix>               # Format single file

Testing

No formal test suite. Verification is done via:

nix flake check                    # Syntax and evaluation check
nix build .#nixosConfigurations.<host>.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:

{
  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-<name> m3-atlas, m3-kratos
Options camelCase path extraServices.ollama.enable
Feature flags features.<category>.<name>.enable features.cli.nushell.enable
Secrets <service>-env.age or descriptive n8n-env.age, wg-DE.age

Option Definitions

Use lib functions for custom options:

{
  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

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:

    agenix -e secrets/my-secret.age
    
  2. Register in secrets.nix:

    "secrets/my-secret.age".publicKeys = systems ++ users;
    
  3. Declare in host's secrets.nix:

    age.secrets.my-secret = {
      file = ../../secrets/my-secret.age;
      owner = "service-user";  # Optional
      mode = "644";            # Optional
    };
    
  4. Reference in config:

    environmentFiles = [config.age.secrets.my-secret.path];
    

Container Services Pattern

OCI containers via podman:

{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:

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:

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.<name>.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;