nixos/docs/agents.md
Julian Sutter 7143d71bf5 docs: Create comprehensive agents.md and deprecate .clinerules
- Added docs/agents.md with complete repository guide
- Includes all project structure, workflows, testing procedures
- Covers package management, security, rollback procedures
- Added maintenance section with changelog for future updates
- Deprecated .clinerules, pointing to agents.md instead
- Created single source of truth for AI agent operations
2026-02-03 22:26:32 -08:00

20 KiB

NixOS Configuration Repository - AI Agent Guide

This guide provides everything you need to know to work efficiently with this NixOS configuration repository. Keep this file handy when making changes.

Repository Overview

This repository manages NixOS configurations for multiple systems using flakes and Home Manager. All systems are defined declaratively in Nix expressions.

Managed Systems

Hostname Type Hardware Special Notes
framework Desktop/Laptop Framework AMD AI 300 series User: jsutter, Uses nixos-hardware module
aurora Desktop Custom Users: jsutter, isutter, aksutter
labrizor Desktop Custom User: jsutter
skip01 Server (WIP) Custom Headless configuration

Core Technologies

  • NixOS: 25.11 (stable channel)
  • Nixpkgs Unstable: For packages requiring latest versions
  • Home Manager: Release 25.11
  • Plasma Manager: KDE Plasma configuration management
  • Flakes: For reproducible, declarative system definitions

Project Structure

nixos/
├── appflakes/           # Local flake inputs
│   └── octofriend/      # Custom application flake
├── desktop/             # Desktop environment configurations
│   ├── plasma.nix       # KDE Plasma + Plasma Manager
│   ├── dev.nix          # Development tools and languages
│   ├── office.nix       # Office applications
│   ├── gaming.nix       # Games and gaming platforms
│   ├── media.nix        # Audio/video software
│   ├── virtualization.nix  # VMs and containers
│   ├── tailscale.nix    # VPN configuration
│   ├── 2dprinting.nix   # Printer setup
│   ├── 3dprinting.nix   # 3D printer tools
│   ├── dnm.nix          # Framework-specific config
│   └── stp-elc-udmshare.nix  # Specific mount/share config
├── docs/                # Documentation
│   └── agents.md        # This file
├── servers/             # Server configurations (future use)
├── systems/             # Hardware-specific configurations
│   ├── common.nix       # Shared system settings (bootloader, nix config, etc.)
│   ├── common-headless.nix  # Common settings for headless systems
│   ├── framework.nix    # Framework laptop hardware config
│   ├── aurora.nix       # Aurora desktop hardware config
│   ├── labrizor.nix     # Labrizor desktop hardware config
│   └── skip01.nix       # Skip01 server config
├── users/               # User configurations with Home Manager
│   ├── common-home.nix  # Shared user packages and settings
│   ├── jsutter.nix      # Primary user configuration
│   ├── isutter.nix      # Secondary user configuration
│   └── aksutter.nix     # Secondary user configuration
├── flake.nix            # Top-level flake definition
└── .clinerules          # Project-specific rules for AI agents

Core Principles

1. Declarative Configuration

  • All system state must be defined in Nix expressions
  • Never use imperative commands for permanent changes
  • Every configuration change should be reproducible

2. Modular Architecture

  • Maintain separation between hardware, software, and user configurations
  • Use existing modules before creating new ones
  • Follow the established directory structure strictly

3. Security First

  • Never expose sensitive data (passwords, private keys, API tokens)
  • Use proper user privilege separation
  • Validate all external inputs and configurations

Configuration Patterns

Function Parameters

Always include the appropriate parameters based on what the module needs:

# For modules using unstable packages
{ config, pkgs, pkgs-unstable, lib, ... }:

# For stable-only modules
{ config, pkgs, lib, ... }:

# For modules using special args from flake
{ config, pkgs, pkgs-unstable, lib, octofriend, ... }:

# For Home Manager modules
{ pkgs, ... }:

System Configuration Pattern

{ config, lib, pkgs, ... }:
{
  # Always include hostname first
  networking.hostName = "system-name";
  
  # Hardware configuration
  fileSystems."/" = { 
    device = "/dev/disk/by-partlabel/primary";
    fsType = "ext4";
  };
  fileSystems."/boot" = {
    device = "/dev/disk/by-partlabel/ESP";
    fsType = "vfat";
  };
  
  # System-specific settings
  # Group related configurations together
}

User Configuration Pattern

{ config, pkgs, pkgs-unstable, home-manager, ... }:
{
  # System user definition
  users.users.username = {
    shell = pkgs.zsh;
    isNormalUser = true;
    description = "User Description";
    extraGroups = [ "networkmanager" "wheel" ];  # Only essential groups
  };

  # Home Manager configuration
  home-manager.users.username = {
    home.username = "username";
    home.homeDirectory = "/home/username";
    home.stateVersion = "25.05";
    
    # User configurations
  };
}

Desktop Module Pattern

{ config, pkgs, pkgs-unstable, lib, ... }:
{
  # System packages for this category
  environment.systemPackages = with pkgs; [
    package1
    package2
  ];

  # Configuration options
  services.service-name.enable = true;

  # Home Manager integrations (if applicable)
}

Package Management Guidelines

Stable vs Unstable Packages

# PREFERRED: Use stable packages by default
environment.systemPackages = with pkgs; [
  firefox
  git
  vim
];

# ACCEPTABLE: Use unstable when necessary
# Add comments explaining why unstable is needed
environment.systemPackages = with pkgs; [
  firefox
  pkgs-unstable.windsurf  # Latest features not in stable
];

Package Selection Criteria

  1. Use stable unless: Package doesn't exist OR needs newer version
  2. Document reasons: Always comment why unstable is used
  3. Test thoroughly: Unstable packages may have issues
  4. Review regularly: Check if unstable packages can move to stable

Common Package Sets by Module

  • dev.nix: IDEs, languages, development tools
  • office.nix: LibreOffice, productivity apps
  • gaming.nix: Steam, Lutris, game launchers
  • media.nix: Audio/video players, editors
  • virtualization.nix: VirtualBox, Docker, other virt tools
  • plasma.nix: KDE Plasma applications and themes

System-Specific Information

Framework (framework.nix)

  • Uses nixos-hardware module: framework-amd-ai-300-series
  • Additional modules: dnm.nix, stp-elc-udmshare.nix
  • Single user: jsutter

Aurora (aurora.nix)

  • Multi-user system: jsutter, isutter, aksutter
  • Additional modules: 3dprinting.nix, 2dprinting.nix
  • No specialized hardware module

Labrizor (labrizor.nix)

  • Single user: jsutter
  • Additional modules: 3dprinting.nix
  • No specialized hardware module

Common Settings (systems/common.nix)

Includes:

  • Hardware firmware and fwupd
  • NetworkManager with VPN plugins (OpenVPN, OpenConnect)
  • Systemd-boot EFI bootloader
  • Latest kernel
  • Nix settings with experimental features (flakes, nix-command)
  • Weekly garbage collection (7-day retention)
  • Auto-optimized Nix store
  • Trusted users: root, jsutter
  • Timezone: America/Los_Angeles
  • Locale: en_US.UTF-8
  • PipeWire audio stack
  • SSH service enabled
  • Zsh shell enabled
  • Passwordless sudo for wheel group
  • Flatpak enabled
  • USB plugdev group rules

File Naming Conventions

  • Use lowercase with hyphens: vpn-config.nix, development-tools.nix
  • System configurations must match hostname: framework.nix, aurora.nix
  • User configurations must match username: jsutter.nix, isutter.nix
  • Common configurations: common.nix, common-home.nix

Code Style

  • Use 2-space indentation
  • Align attribute lists consistently
  • Add comments for non-obvious configurations
  • Group related configurations together

Example:

{
  # Audio configuration
  sound.enable = true;
  hardware.pulseaudio.enable = false;
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
  };
}

Common Workflows

Adding a New Package

  1. Determine appropriate module (desktop/, systems/, users/)
  2. Check if package exists in stable channel: nix search nixpkgs package-name
  3. Use unstable only if necessary with documentation
  4. Add to appropriate environment.systemPackages or home.packages
  5. Run dry-run before applying
  6. Update relevant documentation if it affects multiple systems

Example:

# In desktop/dev.nix
environment.systemPackages = with pkgs; [
  # Added for Python development
  python312
  python312Packages.pip
  pkgs-unstable.windsurf  # Latest AI features not in stable
];

Creating a New Desktop Module

  1. Create file in desktop/ with descriptive name
  2. Include proper function parameters
  3. Add packages, services, and configurations
  4. Test module independently
  5. Add to commonDesktopModules in flake.nix if for all desktops
  6. Add to specific system in flake.nix if selective

Adding a New System

  1. Create systems/<hostname>.nix following existing patterns
  2. Set networking.hostName = "<hostname>"
  3. Configure hardware (fileSystems, hardware-specific settings)
  4. Add system entry to flake.nix:
new-system = mkSystem {
  modules = commonDesktopModules ++ [
    ./systems/new-system.nix
    ./users/username.nix
  ];
};
  1. Test with dry-run and build

Modifying User Configuration

  1. Edit appropriate file in users/
  2. For shared changes: modify common-home.nix
  3. For user-specific changes: modify <username>.nix
  4. Home Manager configuration goes in home-manager.users.<username>

Testing and Validation

Pre-commit Testing

ALWAYS run these commands before submitting changes:

# 1. Syntax check
nix flake check

# 2. Dry run for affected systems (run for ALL affected)
sudo nixos-rebuild dry-run --flake .#framework
sudo nixos-rebuild dry-run --flake .#aurora
sudo nixos-rebuild dry-run --flake .#labrizor

# 3. Check flake outputs
nix flake show

Applying Changes

# Build and switch (active system only)
sudo nixos-rebuild switch --flake .#hostname

# Build only (test without switching)
sudo nixos-rebuild build --flake .#hostname

# Build and boot (adds to GRUB menu)
sudo nixos-rebuild boot --flake .#hostname

Build Verification

  • Test on at least one system before merging
  • Verify all services start correctly: systemctl status
  • Check for package conflicts
  • Validate hardware-specific configurations

Updating Packages

# Update flake inputs
nix flake update

# Check what changed
nix flake diff

# Rebuild after update
sudo nixos-rebuild switch --flake .#hostname

Security Rules

Sensitive Data Handling

  • NEVER commit plaintext passwords
  • NEVER commit private SSH keys
  • NEVER commit API tokens or secrets
  • ALWAYS use hashed passwords: hashedPassword = "$6$..."
  • CONSIDER using sops-nix for advanced secret management

User Privilege Management

# GOOD: Minimal necessary groups
extraGroups = [ "networkmanager" "wheel" "audio" ];

# BAD: Over-privileged users
extraGroups = [ "networkmanager" "wheel" "audio" "video" "input" "disk" "lp" "scanner" ];

SSH Key Management

# GOOD: Use authorizedKeys for SSH access
openssh.authorizedKeys.keys = [
  "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBNVUh+RrcOSMRV6qysnsdPs5AyK8dSm4QhhnwgpikyI user@domain"
];

# FORBIDDEN: Never include private keys

Rollback Procedures

Configuration Rollback

# List available generations
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system

# Rollback to previous working generation
sudo nixos-rebuild switch --profile-name generation-123

# Or use rollback shortcut
sudo nixos-rebuild switch --rollback

# Rollback specific system
sudo nixos-rebuild switch --rollback --flake .#hostname

Emergency System Recovery

If a system fails to boot after changes:

  1. Boot from installation media
  2. Mount root filesystem: mount /dev/disk/by-partlabel/primary /mnt
  3. Roll back: sudo nixos-rebuild switch --rollback --install-bootloader /mnt
  4. Identify and fix configuration issues
  5. Test before rebooting

Booting into Previous Generations

At boot time (GRUB menu):

  1. Hold Shift during boot to see GRUB menu
  2. Select "Advanced options for NixOS"
  3. Choose previous generation

NixOS Installation (New System)

# Partition disk (example for NVMe)
sudo parted /dev/nvme0n1 -- mklabel gpt
sudo parted /dev/nvme0n1 -- mkpart primary ext4 512MB 100%
sudo parted /dev/nvme0n1 -- mkpart ESP fat32 1MB 512MB
sudo parted /dev/nvme0n1 -- set 2 esp on
sudo mkfs.ext4 /dev/disk/by-partlabel/primary
sudo mkfs.vfat /dev/disk/by-partlabel/ESP

# Mount filesystems
sudo mount -o rw /dev/disk/by-partlabel/primary /mnt/
sudo mkdir /mnt/boot
sudo mount -o rw /dev/disk/by-partlabel/ESP /mnt/boot/
sudo mkdir /mnt/root
sudo git clone https://git.symbiotrip.com/jsutter/nixos /mnt/root/nixos

# Install (no root password, impure for git access)
sudo -i
cd /mnt/root/nixos
nixos-install --flake .#<name> --no-root-password --impure

# Set password after install
nixos-enter --root '/mnt'
passwd jsutter

Module Dependencies

Known Dependencies

  • plasma.nix depends on: common.nix, home-manager
  • dev.nix is included in all desktop systems
  • All desktop systems include: common.nix, plasma.nix, dev.nix, office.nix, gaming.nix, media.nix, virtualization.nix, tailscale.nix
  • User files include Home Manager configuration

Avoiding Circular Dependencies

  • Don't import system modules into user modules
  • Use common.nix for shared system settings only
  • Use common-home.nix for shared user settings only
  • Hardware-specific modules should not depend on desktop modules

Emergency Tools

Useful Commands

# Check what packages provide a command
nix-locate bin/commandname

# Search for packages
nix search nixpkgs package-name
nix search nixpkgs-unstable package-name

# Check Nix store size
du -sh /nix/store

# Garbage collect manually
sudo nix-collect-garbage -d

# Profile Nix operations
sudo nix-env --profile /nix/var/nix/profiles/system --list-generations

# Check hardware info
lshw
lspci
lsusb
lsblk
hwinfo

Troubleshooting Common Issues

Build Errors

  1. Read the error message carefully
  2. Check for syntax errors in the modified file
  3. Verify all attributes are closed properly
  4. Run nix flake check to validate syntax

Service Failures

# Check service status
systemctl status service-name

# View service logs
journalctl -u service-name -e

# Restart service
systemctl restart service-name

Package Conflicts

  • If two modules try to enable the same service with different settings
  • Use lib.mkForce to override settings if necessary
  • Or consolidate the configuration in one place

Flakes Reference

Input Structure

inputs = {
  nixpkgs.url = "nixpkgs/nixos-25.11";              # Stable
  nixpkgs-unstable.url = "nixpkgs/nixos-unstable";  # Unstable
  nixos-hardware.url = "github:NixOS/nixos-hardware/master";
  home-manager.url = "github:nix-community/home-manager/release-25.11";
  plasma-manager.url = "github:nix-community/plasma-manager";
  octofriend.url = "path:./appflakes/octofriend";   # Local flake
};

Special Args

Available in all modules:

  • pkgs: Stable Nix packages
  • pkgs-unstable: Unstable Nix packages
  • octofriend: Local octofriend flake

Output Structure

outputs = {
  self,                             # Self reference
  nixpkgs,                          # Stable packages
  nixpkgs-unstable,                 # Unstable packages
  nixos-hardware,                   # Hardware modules
  home-manager,                     # Home Manager
  plasma-manager,                   # Plasma Manager
  octofriend                        # Custom app flake
}: {
  nixosConfigurations = {
    framework = { ... };  # Define each system
    aurora = { ... };
    labrizor = { ... };
  };
};

Documentation Requirements

Code Comments

  • Explain non-obvious configurations
  • Document reasons for unstable package usage
  • Note hardware-specific requirements
  • Reference external dependencies

Example:

# Use unstable neovim for LuaLS integration not in stable
pkgs-unstable.neovim  # Latest features needed for Lua development

Commit Messages

Use clear, descriptive commit messages:

  • Reference affected systems/modules
  • Explain reasoning for significant changes
  • Include testing steps when applicable

Example:

feat(framework): Add 3D printing support for Prusa printers

- Added 3dprinting.nix module with PrusaSlicer and Cura
- Installed USB rules for Prusa devices
- Added to framework system configuration

Tested: Prusa MK4 recognized and can start print via USB

Performance Considerations

Nix Settings

The repository uses optimized Nix settings:

  • auto-optimise-store: Auto-optimizes the Nix store
  • keep-outputs = true: Keeps build outputs
  • keep-derivations = true: Keeps derivations for evaluation
  • download-buffer-size: 512MB for faster downloads

Garbage Collection

Automatically runs weekly:

  • Deletes builds older than 7 days
  • Run manually: sudo nix-collect-garbage -d

Build Caching

Consider using nix-serve or Cachix for:

  • Faster rebuilds
  • Shared cache across systems
  • CI/CD integration

Resources

Official Documentation

Community Resources

Quick Reference

Essential Commands

Action Command
Update system sudo nixos-rebuild switch --flake .#hostname
Dry run sudo nixos-rebuild dry-run --flake .#hostname
Rollback sudo nixos-rebuild switch --rollback
Update flakes nix flake update
Check flakes nix flake check
Search packages nix search nixpkgs name
Garbage collect sudo nix-collect-garbage -d

File Paths Reference

Type Location
Common system settings systems/common.nix
System hardware config systems/<hostname>.nix
Common user settings users/common-home.nix
User config users/<username>.nix
Desktop apps desktop/<category>.nix
Flake definition flake.nix

Maintenance & Changelog

This section tracks changes to the repository structure and when this document was updated. Keep this in sync!

Current Repository State

  • Last Updated: February 2026
  • NixOS Version: 25.11
  • Managed Systems: 3 (framework, aurora, labrizor)
  • Users: jsutter (primary), isutter, aksutter

Repository Change Log

Date Change Updated Sections
2026-02 - Created Created agents.md with comprehensive guide and deprecated .clinerules All sections

When to Update This Document

Update agents.md when any of the following occur:

  • Structural Changes:

    • New system added to flake.nix
    • New user configuration added
    • New or renamed desktop module
    • Directory restructuring
  • Configuration Changes:

    • New shared settings in systems/common.nix
    • New shared user settings in users/common-home.nix
    • Changes to module pattern or function parameters
    • New package categories or organizational changes
  • Technology Updates:

    • NixOS version changes
    • Channel updates (stable/unstable)
    • New major inputs added to flake
    • Significant Nix configuration changes
  • Procedure Changes:

    • New testing workflow
    • Changed emergency procedures
    • Updated installation steps
    • New common commands

Update Template

When making changes, add an entry using this format:

| YYYY-MM - One-line description | More detail if needed | Section(s) affected |
| --- | --- | --- |

Version History for agents.md

  • v1.0 (2025-01): Initial creation with full repository documentation

Getting Help

When unsure about something:

  1. Check this documentation first
  2. Review existing similar configurations
  3. Search NixOS manual and wiki
  4. Consult the .clinerules file for additional guidelines
  5. Test changes with dry-run before applying

Remember: This repository values declarative, reproducible configurations. When in doubt, prefer explicit configuration over implicit behavior. Test thoroughly, document changes, and never skip the dry-run step!