diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ce5873b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,166 @@ +# 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`.