# 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 ```sh # 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 ```nix # 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 ```nix # 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 ` 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 ` 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`.