5.5 KiB
5.5 KiB
Agent Guidelines for NixOS Configuration
Project Overview
This repository contains a NixOS configuration managed with Nix Flakes. It defines:
- Hosts:
cryodev-main(x86_64 server),cryodev-pi(aarch64 Raspberry Pi) - Modules: Reusable NixOS modules in
modules/nixos/ - Packages: Custom packages in
pkgs/ - Templates:
raspberry-pi,generic-serverfor bootstrapping new hosts
Build & Development Commands
Prerequisites
- Nix with Flakes enabled
- Git
Core Commands
# Build host configuration
nix build .#nixosConfigurations.cryodev-main.config.system.build.toplevel
nix build .#nixosConfigurations.cryodev-pi.config.system.build.toplevel
# Build Raspberry Pi SD image (requires binfmt on x86_64)
nix build .#nixosConfigurations.cryodev-pi.config.system.build.sdImage
# Format code (required before committing)
nix fmt
# Run all checks (lint, formatting, deploy-rs validation)
nix flake check
# Quick evaluation test (faster than full build)
nix eval .#nixosConfigurations.cryodev-main.config.system.build.toplevel.name
# Update flake inputs
nix flake update
# Enter development shell
nix develop
Deployment
# Deploy to cryodev-main via deploy-rs
nix run github:serokell/deploy-rs -- .#cryodev-main
# Manual deployment via SSH
nixos-rebuild switch --flake .#<hostname> \
--target-host <user>@<ip> --use-remote-sudo \
--ssh-option="-p 2299"
Code Style & Conventions
Formatting
- Tool:
nixfmtvia pre-commit hooks - Run:
nix fmtbefore every commit - Indentation: 2 spaces
- Line length: 80-100 characters (follow formatter)
Module Structure
# Standard module pattern
{ config, lib, pkgs, inputs, outputs, constants, ... }:
let
cfg = config.services.myService;
in
{
options.services.myService = {
enable = lib.mkEnableOption "My service";
port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = "Port to listen on";
};
};
config = lib.mkIf cfg.enable {
# Implementation here
};
}
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Files | kebab-case | hardware-configuration.nix |
| Options | camelCase | services.myService.enable |
| Variables | camelCase | let myValue = ...; |
| Hosts | kebab-case | cryodev-main, cryodev-pi |
Imports
# Local modules: relative paths
imports = [ ./hardware.nix ./networking.nix ];
# Shared modules: via outputs
imports = [ outputs.nixosModules.common ];
# External inputs
imports = [ inputs.sops-nix.nixosModules.sops ];
Constants
Use constants.nix for domains, IPs, and ports:
{ constants, ... }:
{
services.nginx.virtualHosts."${constants.services.forgejo.fqdn}" = { ... };
}
Error Handling
config = lib.mkIf cfg.enable {
assertions = [
{ assertion = cfg.port > 1024; message = "Port must be > 1024"; }
];
warnings = lib.optional (cfg.debug) "Debug mode enabled!";
};
Option Conflicts
Use lib.mkDefault for default values that can be overridden:
services.nginx.enable = lib.mkDefault true;
Directory Structure
.
├── flake.nix # Entry point, inputs/outputs
├── constants.nix # Central config (domains, IPs, ports)
├── hosts/
│ ├── cryodev-main/ # x86_64 server
│ │ ├── default.nix # Host entry point
│ │ ├── hardware.nix # Hardware configuration
│ │ ├── services/ # Service configurations
│ │ └── secrets.yaml # SOPS-encrypted secrets
│ └── cryodev-pi/ # aarch64 Raspberry Pi
├── modules/nixos/ # Reusable modules
│ ├── common/ # Shared base configuration
│ ├── sops/ # Secret management
│ ├── forgejo/ # Git server
│ ├── headscale/ # VPN control server
│ └── ...
├── lib/utils.nix # Helper functions
├── apps/ # Nix apps (rebuild)
├── pkgs/ # Custom packages
├── overlays/ # Nixpkgs overlays
├── templates/ # Host templates
├── scripts/ # Helper scripts (install.sh)
└── docs/ # Documentation
Key Patterns
Adding a New Raspberry Pi Host
- Copy template:
cp -r templates/raspberry-pi hosts/new-pi - Update
hosts/new-pi/networking.nix(hostname) - Add to
flake.nix:new-pi = mkNixosConfiguration "aarch64-linux" [ ./hosts/new-pi ]; - Add to
.forgejo/workflows/build-pi-image.ymlmatrix - Push → SD image is built automatically
SOPS Secrets
- Secrets encrypted with age using SSH host keys
- Config in
.sops.yaml, secrets inhosts/<host>/secrets.yaml - Reference:
config.sops.secrets."path/to/secret".path
Special Args Available in Modules
inputs: Flake inputs (nixpkgs, sops-nix, etc.)outputs: This flake's outputs (nixosModules, packages)constants: Values fromconstants.nixlib: Extended nixpkgs.lib withlib.utils
Deployment Workflows
| Host | Strategy | Trigger |
|---|---|---|
cryodev-main |
Push via deploy-rs | Forgejo Actions on push to main |
cryodev-pi |
Pull via Comin | Automatic polling |
| SD Images | Built in CI | Push to main (for Pi hosts) |
Verification Checklist
Before committing:
nix fmtpassesnix flake checkpasses (or at leastnix evalworks)- New hosts added to
flake.nix - Constants in
constants.nix, not hardcoded - Secrets use SOPS, not plaintext