# AGENTS.md — nix-config Personal NixOS/nix-darwin configuration using flake-parts, import-tree, home-manager, and nixvim. --- ## Repository Overview ``` flake.nix # Thin entry: delegates to import-tree ./modules Justfile # Task runner (deploy, dry-run, update, gc, etc.) modules/ config.nix # flake-parts options schema (flake.modules, flake.globalConfig) systems.nix # Supported systems list hosts/ dnsc-machine/ # Only active NixOS host (x86_64-linux) base/ # macOS system defaults + NixOS locale/boot/user base / # One directory per feature module default.nix # Always the primary file _sub-module.nix # Underscore-prefixed for large module splits ``` `import-tree` auto-discovers every `.nix` file under `modules/` — **no manual imports list in flake.nix**. New modules are picked up automatically; just create `modules//default.nix`. --- ## Build / Validation Commands There is no CI and no `nix fmt`/`nix flake check` target configured. | Goal | Command | |---|---| | Deploy to host | `just deploy ` (`sudo nixos-rebuild switch --flake .#`) | | Deploy with trace | `just debug ` (adds `--show-trace --verbose`) | | Dry-run build | `just dry ` — evaluates the closure without realising it | | Update all inputs | `just update` (`nix flake update`) | | Garbage collect | `just gc` (`sudo nix-collect-garbage --delete-old`) | | Wipe old profiles | `just clean` (removes profiles older than 7 days) | | NixOS REPL | `just repl` | **Only active host:** `dnsc-machine` ``` just dry dnsc-machine # fastest sanity check — no sudo required just deploy dnsc-machine ``` There are no unit tests or `checks` outputs. Validation = dry-run build succeeds + manual deploy. **Linting tools available** (installed as system packages): `nil` (LSP), `statix` (linter). Run `statix check .` to lint Nix files for common anti-patterns. --- ## Flake Architecture ``` inputs.flake-parts → mkFlake framework inputs.import-tree → auto-loads modules/ inputs.nixpkgs → nixpkgs-unstable (channel tarball URL, not github:) inputs.home-manager → follows nixpkgs inputs.nix-darwin → LnL7/nix-darwin master inputs.nixvim → nix-community/nixvim inputs.helium → custom browser flake inputs.dms → DankMaterialShell (COSMIC alternative desktop) ``` **Custom flake-parts options** (defined in `modules/config.nix`): - `flake.modules.nixos.` — NixOS system modules - `flake.modules.darwin.` — nix-darwin system modules - `flake.modules.homeManager.` — home-manager user modules - `flake.globalConfig.{username,fullname,email}` — shared personal values --- ## Module Pattern Every feature lives in `modules//default.nix` and registers itself into the module registry. Host configs (`modules/hosts//default.nix`) opt in by listing modules explicitly. ### Standard tri-layer module ```nix { inputs, ... }: { flake.modules.nixos. = { pkgs, ... }: { # NixOS system-level config home-manager.sharedModules = [ inputs.self.modules.homeManager. ]; }; flake.modules.darwin. = { pkgs, ... }: { # nix-darwin system-level config home-manager.sharedModules = [ inputs.self.modules.homeManager. ]; }; flake.modules.homeManager. = { pkgs, config, ... }: { # home-manager user-level config }; } ``` ### System-only module (no HM layer) ```nix { ... }: { flake.modules.nixos. = { pkgs, ... }: { # NixOS config only, e.g. bluetooth, printing, gaming }; } ``` ### Sub-module splitting (for large modules like neovim) ```nix flake.modules.homeManager.neovim = { pkgs, ... }: { imports = [ ./_options.nix ./_lsp.nix ./_formatter.nix ]; }; ``` ### Host definition pattern ```nix { inputs, config, ... }: let hostname = "dnsc-machine"; in { flake.nixosConfigurations.dnsc-machine = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = with config.flake.modules.nixos; [ home-manager base shell # ... feature modules by name { imports = [ ./_hardware-configuration.nix ]; networking.hostName = hostname; system.stateVersion = "24.11"; } ]; }; } ``` --- ## Code Style ### Formatting - **2-space indentation** throughout, no tabs - Opening brace on the same line as the attribute/binding - Closing brace on its own line - No trailing commas in attribute sets or lists (standard Nix) - Multi-line function arguments use the exploded form: ```nix { inputs, config, ... }: ``` Short arg lists use the inline form: `{ pkgs, ... }:` ### Inline embedded languages Use language comments to enable editor syntax highlighting inside multiline Nix strings: ```nix interactiveShellInit = /* fish */ '' fish_vi_key_bindings insert ''; extraConfig = /* lua */ '' vim.opt.number = true ''; ``` ### Naming conventions | Thing | Convention | Example | |---|---|---| | Module directories | `kebab-case` | `cli-tools/`, `nvidia-graphics/` | | Primary module file | `default.nix` | every feature dir | | Sub-module files | `_kebab-case.nix` (underscore prefix) | `_lsp.nix`, `_formatter.nix` | | Hardware config | `_hardware-configuration.nix` | matches sub-module style | | `flake.modules.nixos.*` keys | `kebab-case` | `flake.modules.nixos.cli-tools` | | `flake.modules.homeManager.*` keys | `kebab-case` name, `homeManager` namespace | `flake.modules.homeManager.shell` | | `let` bindings | `camelCase` | `hmConfig`, `commonPackages` | | Host names | `kebab-case` with owner prefix | `dnsc-machine`, `dnsc-server` | | Fish functions | `snake_case` | `fish_greeting`, `tmux_sessionizer` | | Fish abbrs | short lowercase | `lg`, `gg`, `g` | ### Attribute ordering In NixOS/HM options, follow upstream conventions: - `enable = true;` first - then primary config attributes - then nested option sets ### No conditional feature flags Feature modules do **not** use `mkEnableOption`/`mkIf`. Everything in a module is unconditionally enabled when that module is included in a host's modules list. Opt-in/opt-out happens at the host level by adding or removing the module name. --- ## Adding a New Feature Module 1. Create `modules//default.nix` 2. Define `flake.modules.nixos.` and/or `flake.modules.homeManager.` 3. To activate on a host, add `` to the `modules = with config.flake.modules.nixos; [ ... ]` list in the host's `default.nix` 4. No registration in `flake.nix` needed — `import-tree` picks it up automatically --- ## Commit Style Lowercase, brief, imperative — no conventional-commits prefix required: ``` add bluetooth module fix cli tools config remove gtk handling update nixpkgs input ```