Files
dotfiles/AGENTS.md
2026-03-21 19:43:35 -04:00

7.2 KiB

AGENTS.md

Project Overview

NixOS dotfiles for two hosts using Nix flakes + home-manager:

  • mreow — Framework 13 AMD AI 300 laptop, niri WM, greetd, swaylock
  • yarn — Desktop, Jovian-NixOS (Steam deck mode), impermanence, sddm, deploy-rs target

Secrets in system/secrets/ and home-manager/secrets/ are encrypted with git-crypt. Never read or write files in those directories.

Build & Deploy Commands

# Build and apply (default: boot, or pass switch/test/build)
./deploy.sh              # nixos-rebuild boot --flake . --use-remote-sudo
./deploy.sh switch       # apply immediately
./deploy.sh test         # apply without adding boot entry
./deploy.sh build        # build only, no activation

# Build a specific host without deploying
nix build .#nixosConfigurations.mreow.config.system.build.toplevel -L
nix build .#nixosConfigurations.yarn.config.system.build.toplevel -L

# Remote deploy to yarn via deploy-rs
deploy .#yarn

# Format all Nix files (uses nixfmt-tree, declared in flake.nix)
nix fmt

# Evaluate without building (quick syntax/type check)
nix eval .#nixosConfigurations.mreow.config.system.build.toplevel --no-build 2>&1 | head -5
nix eval .#nixosConfigurations.yarn.config.system.build.toplevel --no-build 2>&1 | head -5

# Update flake inputs
nix flake update
nix flake update --input-name nixpkgs   # update a single input

There are no tests. Validation is done by building the system configuration (nix build -L). Always append -L to nix build for verbose build logs. If nix complains a file isn't found, git add the file first — Nix flakes only see tracked files.

Repository Structure

flake.nix                          # Root flake: inputs, outputs, host definitions
deploy.sh                          # Wrapper around nixos-rebuild
system/
  common.nix                       # Shared system config (boot, audio, users, etc.)
  system-mreow.nix                 # Laptop-specific system config
  system-yarn.nix                  # Desktop-specific system config
  networking.nix                   # NetworkManager, DNS
  impermanence.nix                 # Ephemeral root for yarn
  disk_mreow.nix / disk_yarn.nix   # Disko disk layouts
  vm.nix                           # Virtualization (libvirt, waydroid)
  vr.nix / no-rgb.nix / steam.nix  # Feature modules
  secrets/                         # git-crypt encrypted, DO NOT READ
home-manager/
  home-mreow.nix                   # Laptop home-manager entry point
  home-yarn.nix                    # Desktop home-manager entry point
  gui.nix                          # GUI packages + theming (imports no-gui.nix)
  no-gui.nix                       # CLI tools, dev toolchains, git config
  desktop.nix                      # Desktop environment (niri, dunst, swaylock, noctalia)
  wallpaper.png                    # Shared wallpaper
  progs/                           # One file per program
    fish.nix, alacritty.nix, emacs.nix, helix.nix, niri.nix, ...
    zen/                           # Zen Browser (multi-file: default.nix, ublock.nix, dark-reader.nix)
    opencode.nix                   # AI coding tools config
  util/                            # Helper derivations (blur.nix, inverse_color.nix)
  secrets/                         # git-crypt encrypted, DO NOT READ

Import Hierarchy

flake.nix
 ├─ system/system-{host}.nix → common.nix → networking.nix, vm.nix, steam.nix
 └─ home-manager/home-{host}.nix → gui.nix → no-gui.nix
                                  → desktop.nix → niri.nix, dunst.nix, swaylock.nix, noctalia.nix

Adding a new program: create home-manager/progs/myprog.nix, import it from the appropriate layer (gui.nix for GUI apps, no-gui.nix for CLI tools, or home-{host}.nix for host-specific).

Nix Code Style

Formatter: nixfmt-tree — run nix fmt before committing. All style below conforms to what nixfmt-tree produces.

Module Structure

# Function arguments: destructured attrset, alphabetical-ish, always end with `...`
{ pkgs, lib, inputs, config, ... }:

# Optional let bindings for local values
let
  myThing = "value";
in
{
  imports = [
    ./other-module.nix
  ];

  # Configuration here
}

Conventions

  • Indentation: 2 spaces (enforced by nixfmt-tree)
  • Imports: relative paths (./progs/fish.nix), one per line in a list
  • Package references: use lib.getExe pkgs.foo for bin paths, not ${pkgs.foo}/bin/foo
  • Package lists: group thematically with comments, use with pkgs; or lib.concatLists for multiple groups
  • Unfree packages: explicitly allowlisted per-file via nixpkgs.config.allowUnfreePredicate
  • Comments: lowercase, informal, # style. Use # BUG! or # TODO! prefixes for known issues
  • No trailing commas: Nix syntax does not support them
  • Attribute sets: opening brace on same line, closing brace aligned with the key
  • Overlays: imported inline within the module that needs them via nixpkgs.overlays
  • Special args: passed through specialArgs (system) or extraSpecialArgs (home-manager) in flake.nix — includes inputs, username, hostname, niri-package, homeDirectory, stateVersion

Patterns Used

# Package path references
lib.getExe pkgs.swaylock        # preferred
"${pkgs.avizo}/bin/volumectl"   # acceptable when lib.getExe doesn't work

# Conditional/host-specific overrides
lib.mkForce false               # override inherited values
lib.mkDefault "value"           # set overridable defaults

# Helper derivations (see home-manager/util/)
pkgs.callPackage ../util/blur.nix       # for derivations that take { stdenv, ... }:

# Combining package lists
home.packages = with pkgs; lib.concatLists [
  [ pkg1 pkg2 ]   # group 1
  [ pkg3 pkg4 ]   # group 2
  someList         # from let binding
];

Naming

  • Host configs: system-{hostname}.nix, home-{hostname}.nix, disk_{hostname}.nix
  • Program modules: progs/{program-name}.nix (one program per file)
  • Utility derivations: util/{descriptive-name}.nix
  • Variables: snake_case or camelCase (no strict rule, follow local context)

Key Technical Details

  • nixpkgs channel: unstable (nixos-unstable)
  • Secure boot: lanzaboote with keys extracted from system/secrets/secureboot.tar
  • Disk management: disko
  • Privilege escalation: doas (sudo is disabled), shim at doas-sudo-shim
  • Shell: fish (bash redirects to fish via programs.bash.interactiveShellInit)
  • Wayland: niri compositor, xwayland-satellite for X11 compat
  • Desktop shell: noctalia-shell (bar, launcher, notifications)
  • Git: GPG signing enabled (signByDefault = true), default branch main
  • Impermanence (yarn only): root is ephemeral, /persistent holds state, home is bind-mounted

Agent-Specific Instructions

  • If instructed to commit, disable GPG signing (git commit --no-gpg-sign).
  • Use nix-shell -p <package> if a tool is not available in the environment.
  • For nix build, always append -L for verbose logs.
  • If nix reports a missing file, run git add <file> first — flakes only see git-tracked files.
  • Do not read files under system/secrets/ or home-manager/secrets/.
  • Run nix fmt after editing any .nix file.
  • Validate changes with nix build .#nixosConfigurations.{host}.config.system.build.toplevel -L.