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:
./subdiror../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
-
Create the secret file:
agenix -e secrets/my-secret.age -
Register in
secrets.nix:"secrets/my-secret.age".publicKeys = systems ++ users; -
Declare in host's
secrets.nix:age.secrets.my-secret = { file = ../../secrets/my-secret.age; owner = "service-user"; # Optional mode = "644"; # Optional }; -
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 aspkgs.stable.*locked-packages: Pinned nixpkgs aspkgs.locked.*master-packages: nixpkgs-master aspkgs.master.*
Use when you need a specific package version:
home.packages = [ pkgs.stable.somePackage ];
Common Pitfalls
- Missing imports: Ensure new files are imported in parent
default.nix - Secret paths: Use
config.age.secrets.<name>.path, not hardcoded paths - Rebuild required: Changes need
nixos-rebuildorhome-manager switch - Overlay scope: Overlays must be added to both
home/commonandhosts/common - Port conflicts: Check
hosts/common/ports.nixbefore allocating new ports
Commit Style
Short, descriptive messages:
flake update- Dependency updates+package- Adding new packageservice-name: description- Service changeshost: 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;