diff --git a/docs/nix.md b/docs/nix.md index 40d55e9..8212454 100644 --- a/docs/nix.md +++ b/docs/nix.md @@ -5,31 +5,232 @@ Prefer these conventions when changing this flake. ## Names +### Reserve `lib` for `nixpkgs.lib` + Use `lib` only for the base `nixpkgs.lib` value. Do not use `lib` for project helper functions. Use `dotfiles.lib` for pure project helpers passed through module arguments. Use `dotfiles.` for project assembly helpers passed through module arguments. +Avoid: + +```nix +{ + lib = dotfilesHelpers; +} +``` + +Use: + +```nix +{ + lib = nixpkgs.lib; + dotfiles.lib = dotfilesHelpers; +} +``` + ## Imports -Prefer explicit import arguments. -Use exact function argument patterns without `...` when the imported file has a closed interface. -Use `...` only when the file intentionally accepts extra arguments. +### Use closed interfaces for helper imports -## `let` bindings +Use exact function argument patterns when an imported helper file has a closed interface. +A helper file has a closed interface when the importer owns the argument set. +The imported file must name each accepted attribute. +This rejects stale or accidental extra attributes. -Minimize `let` bindings. -Use a `let` binding when it names an important intermediate value or avoids repeated complex expressions. +Avoid: + +```nix +{ + inputs, + lib, + self, + ... +}: +``` + +Use: + +```nix +{ + inputs, + lib, + self, +}: +``` + +### Pass import arguments explicitly + +Pass only the values an imported helper file needs. +Bind `lib` to the base `nixpkgs.lib` value at the call site. +Use `inherit` for values that keep the same name. + +Avoid: + +```nix +import ./flake inputs +``` + +Use: + +```nix +import ./flake { + inherit inputs self; + lib = nixpkgs.lib; +} +``` + +### Keep NixOS module interfaces open + +NixOS modules must accept extra arguments because the module system owns their argument shape. +Name the arguments the module uses. +Keep `...` so the module accepts standard module arguments and special arguments. + +Avoid: + +```nix +{ + config, + lib, + pkgs, + registry, +}: +``` + +Use: + +```nix +{ + config, + lib, + pkgs, + registry, + ... +}: +``` + +### Use `@` for forwarding wrappers + +Use `@` when a wrapper must pass the complete argument set to another module function. +Name the arguments the wrapper uses before `...`. +Forward the bound argument set unchanged. + +Avoid: + +```nix +{ dotfiles, ... }: +dotfiles.guest { name = "sample"; } { inherit dotfiles; } +``` + +Use: + +```nix +args@{ dotfiles, ... }: +dotfiles.guest { name = "sample"; } args +``` + +## `let` Bindings + +### Use `let` for important intermediate values + +Use a `let` binding when it names an important intermediate value. +Use a `let` binding when it avoids repeating a complex expression. Do not use a `let` binding only to shorten a standard library call. -## Standard library calls +Avoid: + +```nix +let + inherit (lib) mapAttrs; +in +mapAttrs f attrs +``` + +Use: + +```nix +lib.mapAttrs f attrs +``` + +## Standard Library Calls + +### Qualify standard library calls in flake assembly Prefer qualified standard library calls inside flake assembly code. Use `lib.mapAttrs` instead of inheriting `mapAttrs` from `lib`. This keeps the source of helper functions visible. -## Flake assembly +Avoid: + +```nix +let + inherit (lib) mapAttrs; +in +mapAttrs f attrs +``` + +Use: + +```nix +lib.mapAttrs f attrs +``` + +## Flake Assembly + +### Keep assembly code under `flake/` Keep flake assembly code under `flake/`. -Do not expose assembly helpers as public flake outputs unless an external consumer needs them. Keep `flake.nix` focused on inputs and public outputs. +A public output is any attribute returned by the flake `outputs` function. +Another flake can reference a public output through `inputs..`. +Tools such as `nix flake show` also display public outputs. + +Avoid: + +```nix +# flake.nix +let + mkHosts = hostsDir: ...; +in +{ + nixosConfigurations = mkHosts (self + "/hosts"); +} +``` + +Use: + +```nix +# flake.nix +let + flakeAssembly = import ./flake { + inherit inputs self; + lib = nixpkgs.lib; + }; +in +{ + nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); +} +``` + +### Expose only supported flake outputs + +Use public outputs for the supported interface of this flake. +Do not expose assembly helpers as public outputs unless an external consumer needs them. +Keep internal helpers in `flake/` or `dotfiles` special arguments. + +Avoid: + +```nix +{ + lib = flakeAssembly; + nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); +} +``` + +Use: + +```nix +{ + nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts"); +} +```