From e426f2244f1a773ad75dc4e078070af0f313e881 Mon Sep 17 00:00:00 2001 From: mjallen18 Date: Mon, 16 Mar 2026 14:16:55 -0500 Subject: [PATCH] docs --- DOCUMENTATION.md | 1435 ++++++++++++++++++++++++++++++++++++++++++++++ flake.lock | 6 +- 2 files changed, 1438 insertions(+), 3 deletions(-) create mode 100644 DOCUMENTATION.md diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md new file mode 100644 index 0000000..efc8580 --- /dev/null +++ b/DOCUMENTATION.md @@ -0,0 +1,1435 @@ +# Snowfall Lib — Comprehensive Reference + +> Unified configuration for systems, packages, modules, shells, templates, and more with Nix Flakes. +> Built on top of [flake-utils-plus](https://github.com/gytis-ivaskevicius/flake-utils-plus). + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [Flake Inputs & Outputs](#flake-inputs--outputs) +3. [Getting Started](#getting-started) +4. [Library Bootstrap (`snowfall-lib/default.nix`)](#library-bootstrap) +5. [Library Modules](#library-modules) + - [attrs](#attrs) + - [checks](#checks) + - [flake](#flake) + - [fp (Functional Programming)](#fp-functional-programming) + - [fs (Filesystem)](#fs-filesystem) + - [home](#home) + - [internal](#internal) + - [module](#module) + - [overlay](#overlay) + - [package](#package) + - [path](#path) + - [shell](#shell) + - [system](#system) + - [template](#template) +6. [NixOS / Darwin / Home Modules](#nixos--darwin--home-modules) + - [NixOS User Module](#nixos-user-module) + - [Darwin User Module](#darwin-user-module) + - [Home-Manager User Module](#home-manager-user-module) +7. [Directory Conventions](#directory-conventions) +8. [Special Arguments Injected by Snowfall Lib](#special-arguments-injected-by-snowfall-lib) +9. [Virtual Systems](#virtual-systems) +10. [Version History](#version-history) + +--- + +## Overview + +Snowfall Lib is a Nix Flakes library that provides a **convention-over-configuration** approach to managing: + +- NixOS, nix-darwin, and virtual system configurations +- Home-Manager user configurations +- Reusable NixOS/darwin/home-manager modules +- Nixpkgs overlays +- Custom packages +- Development shells +- CI checks +- Flake templates +- User library extensions + +It works by scanning well-known directory layouts inside your flake, automatically wiring everything into flake outputs while giving you full override capability. + +### Design Principles + +- **File-system driven**: directories under `systems/`, `homes/`, `packages/`, `modules/`, `overlays/`, `shells/`, `checks/`, and `templates/` are discovered automatically. +- **Composable library**: every sub-library is a plain attribute set merged into `lib.snowfall.*`. +- **Namespace isolation**: all user packages are placed under a configurable namespace attribute in nixpkgs (e.g. `pkgs.myorg`). +- **Functional style**: heavy use of `pipe`, point-free composition, and higher-order helpers. + +--- + +## Flake Inputs & Outputs + +### Inputs (`flake.nix`) + +| Input | URL | +|---|---| +| `nixpkgs` | `github:nixos/nixpkgs/release-25.11` | +| `flake-utils-plus` | `github:gytis-ivaskevicius/flake-utils-plus/master` | + +### Outputs + +``` +snowfall-lib +├── mkLib # function: create the extended lib +├── mkFlake # function: convenience wrapper (mkLib + lib.mkFlake) +├── nixosModules +│ └── user # ./modules/nixos/user/default.nix +├── darwinModules +│ └── user # ./modules/darwin/user/default.nix +├── homeModules +│ └── user # ./modules/home/user/default.nix +├── formatter # nixfmt-tree for x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin +└── snowfall # internal config & lib exposed for documentation tooling + ├── config # { root, src, namespace, lib-dir, meta } + ├── raw-config + └── internal-lib +``` + +--- + +## Getting Started + +### Creating the Library + +```nix +# In your flake.nix +{ + inputs.snowfall-lib.url = "github:snowfallorg/lib"; + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + outputs = inputs: + inputs.snowfall-lib.lib.mkFlake { + inherit inputs; + src = ./.; + + snowfall = { + namespace = "myorg"; # optional, default: "internal" + meta = { + name = "my-flake"; + title = "My Flake"; + }; + }; + }; +} +``` + +### Using `mkLib` Directly + +```nix +let + lib = inputs.snowfall-lib.lib.mkLib { + inherit inputs; + src = ./.; + snowfall.namespace = "myorg"; + }; +in +lib.mkFlake { ... } +``` + +### `mkLib` Signature + +``` +mkLib : { inputs, src, snowfall? } -> lib +``` + +`mkLib` returns the merged nixpkgs lib extended with: +- all `lib` attributes from every input that exposes one (accessible as `lib..*`) +- the `snowfall.*` sub-library namespace +- the user's own `lib/` modules (merged under `lib..*`) + +### `mkFlake` Signature + +``` +mkFlake : { + inputs, + src, + snowfall?, + systems?, + homes?, + modules?, + overlays?, + packages?, + shells?, + checks?, + templates?, + channels?, + channels-config?, + outputs-builder?, + alias?, + extra-exported-overlays?, +} -> +``` + +All options are optional; only `inputs` and `src` are required. + +| Option | Type | Description | +|---|---|---| +| `inputs` | `Attrs` | Flake inputs (must include `self`) | +| `src` | `Path` | Root of the user's flake | +| `snowfall` | `Attrs` | Snowfall-specific config (namespace, meta, root) | +| `systems` | `Attrs` | Overrides/extra modules for system configs | +| `homes` | `Attrs` | Overrides/extra modules for home configs | +| `modules` | `Attrs` | Override maps for `nixos`, `darwin`, `home` module sets | +| `overlays` | `[Overlay]` | Extra overlays applied to channels | +| `packages` | `Attrs` | Additional packages merged over discovered ones | +| `shells` | `Attrs` | Additional dev shells merged over discovered ones | +| `checks` | `Attrs` | Additional checks merged over discovered ones | +| `templates` | `Attrs` | Additional templates merged over discovered ones | +| `channels` | `Attrs` | Per-channel nixpkgs configuration | +| `channels-config` | `Attrs` | Global nixpkgs config applied to all channels | +| `outputs-builder` | `channels -> Attrs` | Additional per-system outputs | +| `alias` | `Attrs` | Alias maps for packages, shells, checks, modules, templates | +| `extra-exported-overlays` | `Attrs` | Extra overlays to include in the `overlays` output | + +--- + +## Library Bootstrap + +**File**: `snowfall-lib/default.nix` + +This is the entry point. It accepts `core-inputs` (Snowfall Lib's own inputs) and `user-options` (`{ inputs, src, snowfall? }`), then: + +1. **Builds `snowfall-config`** from user options with defaults: + - `namespace` defaults to `"internal"` + - `root` defaults to `src` + - `meta.name` / `meta.title` default to `null` + +2. **Collects library inputs**: gathers the `.lib` attribute from every input that has one (both from core inputs and user inputs). + +3. **Bootstraps the Snowfall sub-library** (`snowfall-lib`): uses `fix` to lazily load every subdirectory of `snowfall-lib/` as a Nix file, passing a shared `attrs` set containing `{ snowfall-lib, snowfall-config, core-inputs, user-inputs }`. All resulting attribute sets are deep-merged. + +4. **Builds `base-lib`**: shallow-merges `nixpkgs.lib`, input libs, top-level (non-attrset) snowfall lib values, and `{ snowfall = snowfall-lib; }`. + +5. **Loads the user's `lib/` modules**: discovers all `default.nix` files under `/lib/`, calls each with `{ inputs, snowfall-inputs, namespace, lib }`, and deep-merges the results into `user-lib`. + +6. **Returns the final `lib`**: `merge-deep [ base-lib user-lib ]`. + +--- + +## Library Modules + +Each module file exports an attribute set that is deep-merged into the top-level `snowfall-lib`. The modules are accessed as `lib.snowfall..`. + +--- + +### attrs + +**File**: `snowfall-lib/attrs/default.nix` + +Attribute set utilities. + +#### `attrs.map-concat-attrs-to-list` + +``` +(a -> b -> [c]) -> Attrs -> [c] +``` + +Map over an attribute set and flatten the result into a single list. + +```nix +attrs.map-concat-attrs-to-list (name: value: [name value]) { x = 1; y = 2; } +# => [ "x" 1 "y" 2 ] +``` + +#### `attrs.merge-deep` + +``` +[Attrs] -> Attrs +``` + +Recursively merge a list of attribute sets (later entries win at every level). + +```nix +attrs.merge-deep [{ a.b = 1; } { a.c = 2; }] +# => { a = { b = 1; c = 2; }; } +``` + +#### `attrs.merge-shallow` + +``` +[Attrs] -> Attrs +``` + +Merge a list of attribute sets at the top level only (later entries win; sub-attrs are replaced, not merged). + +```nix +attrs.merge-shallow [{ a = { x = 1; }; } { a = { y = 2; }; }] +# => { a = { y = 2; }; } +``` + +#### `attrs.merge-shallow-packages` + +``` +[Attrs] -> Attrs +``` + +Merge package attribute sets: derivations are kept as-is; nested attribute sets (e.g. `some.value`) are merged one level deep. + +```nix +attrs.merge-shallow-packages [ { vim = ; some.value = true; } { some.value = false; } ] +# => { vim = ; some.value = false; } +``` + +#### `attrs.merge-with-aliases` + +``` +(Attrs -> Attrs -> Attrs) -> [Attrs] -> Attrs -> Attrs +``` + +Fold a list of items using a merge function, then apply aliases so that `alias.default = "vim"` adds `result.default = result.vim`. + +#### `attrs.apply-aliases-and-overrides` + +``` +Attrs -> Attrs -> Attrs -> Attrs +``` + +Given a pre-built attribute set, apply aliases and then overlay overrides on top. + +```nix +attrs.apply-aliases-and-overrides packages-set { default = "vim"; } { extra = ...; } +``` + +--- + +### checks + +**File**: `snowfall-lib/checks/default.nix` + +#### `check.create-checks` + +``` +{ channels, src?, pkgs?, overrides?, alias? } -> Attrs +``` + +Discover all `default.nix` files under `/checks/`, build them as derivations, apply aliases and overrides, and filter by the current system. + +Each check's `default.nix` receives via `callPackageWith`: +- All `pkgs` attributes +- `channels` — all nixpkgs channel sets +- `lib` — the full Snowfall-extended lib +- `inputs` — user inputs (without `src`) +- `namespace` — the configured namespace string + +```nix +# checks/my-check/default.nix +{ pkgs, lib, ... }: +pkgs.runCommand "my-check" {} "echo ok > $out" +``` + +--- + +### flake + +**File**: `snowfall-lib/flake/default.nix` + +Utilities for working with flake inputs, plus the central `mkFlake` function. + +#### `flake.without-self` + +``` +Attrs -> Attrs +``` + +Remove the `self` key from an attribute set of flake inputs. + +#### `flake.without-src` + +``` +Attrs -> Attrs +``` + +Remove the `src` key from an attribute set. + +#### `flake.without-snowfall-inputs` + +``` +Attrs -> Attrs +``` + +Remove both `self` and `src` (composed from the two above). + +#### `flake.without-snowfall-options` + +``` +Attrs -> Attrs +``` + +Remove all Snowfall-specific top-level `mkFlake` options so the remainder can be forwarded safely to `flake-utils-plus.lib.mkFlake`. Removed keys: `systems`, `modules`, `overlays`, `packages`, `outputs-builder`, `outputsBuilder`, `packagesPrefix`, `hosts`, `homes`, `channels-config`, `templates`, `checks`, `alias`, `snowfall`. + +#### `flake.get-libs` + +``` +Attrs -> Attrs +``` + +Transform an attribute set of inputs into an attribute set of their `.lib` attributes; entries without a `lib` attrset are dropped. + +```nix +flake.get-libs { nixpkgs = nixpkgs; empty = {}; } +# => { nixpkgs = nixpkgs.lib; } +``` + +#### `mkFlake` (the main entry point) + +See [Getting Started](#getting-started) for the full signature. Internally it: + +1. Creates system configurations via `system.create-systems` +2. Creates home-manager configurations via `home.create-homes` +3. Creates NixOS, Darwin, and Home modules via `module.create-modules` +4. Creates overlays via `overlay.create-overlays` +5. Creates packages, shells, and checks inside `outputs-builder` +6. Merges everything and delegates to `flake-utils-plus.lib.mkFlake` +7. Post-processes `packages` output to include home-manager activation packages (as `homeConfigurations-`) + +--- + +### fp (Functional Programming) + +**File**: `snowfall-lib/fp/default.nix` + +Small functional programming helpers. + +#### `fp.compose` + +``` +(b -> c) -> (a -> b) -> a -> c +``` + +Compose two functions right-to-left. + +```nix +fp.compose (x: x + 2) (x: x + 1) # equivalent to x: (x+1)+2 +``` + +#### `fp.compose-all` + +``` +[(x -> y)] -> a -> b +``` + +Compose a list of functions right-to-left. + +```nix +fp.compose-all [ add-two add-one ] # equivalent to fp.compose add-two add-one +``` + +#### `fp.call` + +``` +(a -> b) -> a -> b +``` + +Apply a function to an argument (identity combinator, useful for point-free pipelines). + +#### `fp.apply` + +``` +a -> (a -> b) -> b +``` + +Flip of `call` — apply an argument to a function. + +--- + +### fs (Filesystem) + +**File**: `snowfall-lib/fs/default.nix` + +All filesystem helpers are safe: operations on non-existent paths return `{}` or `[]`. + +#### Kind predicates + +``` +fs.is-file-kind : String -> Bool -- kind == "regular" +fs.is-symlink-kind : String -> Bool -- kind == "symlink" +fs.is-directory-kind : String -> Bool -- kind == "directory" +fs.is-unknown-kind : String -> Bool -- kind == "unknown" +``` + +Used with `builtins.readDir` results. + +#### `fs.get-file` + +``` +String -> String +``` + +Resolve a path relative to the **user's flake source** (`user-inputs.src`). + +```nix +fs.get-file "systems" +# => "/path/to/user-flake/systems" +``` + +#### `fs.get-snowfall-file` + +``` +String -> String +``` + +Resolve a path relative to `snowfall-config.root` (the root of the Snowfall-configured portion of the flake, which may differ from `src`). + +```nix +fs.get-snowfall-file "modules/nixos" +# => "/path/to/user-flake/modules/nixos" +``` + +#### `fs.internal-get-file` + +``` +String -> String +``` + +Resolve a path relative to the Snowfall Lib flake itself (internal use). + +#### `fs.safe-read-directory` + +``` +Path -> Attrs +``` + +`builtins.readDir` that returns `{}` if the path does not exist. + +#### `fs.get-entries-by-kind` + +``` +(String -> Bool) -> Path -> [Path] +``` + +Return all entries in a directory whose kind satisfies the predicate. Returns full paths. + +#### `fs.get-directories` + +``` +Path -> [Path] +``` + +Return all subdirectories of a path. + +#### `fs.get-directories-with-default` + +``` +Path -> [Path] +``` + +Return all subdirectories that contain a `default.nix` file. + +```nix +fs.get-directories-with-default ./systems/x86_64-linux +# => [ "./systems/x86_64-linux/my-host" ] +``` + +#### `fs.get-files` + +``` +Path -> [Path] +``` + +Return all regular files (non-recursive) in a directory. + +#### `fs.get-files-recursive` + +``` +Path -> [Path] +``` + +Return all regular files recursively under a directory. + +#### `fs.filter-files` + +``` +(Path -> Bool) -> Path -> [Path] +``` + +Filter the non-recursive file listing by a predicate. + +#### `fs.filter-files-recursive` + +``` +(Path -> Bool) -> Path -> [Path] +``` + +Filter the recursive file listing by a predicate. + +#### `fs.get-nix-files` + +``` +Path -> [Path] +``` + +All `*.nix` files (non-recursive) in a directory. + +#### `fs.get-nix-files-recursive` + +``` +Path -> [Path] +``` + +All `*.nix` files recursively under a directory. + +#### `fs.get-default-nix-files` + +``` +Path -> [Path] +``` + +All files named exactly `default.nix` (non-recursive). + +#### `fs.get-default-nix-files-recursive` + +``` +Path -> [Path] +``` + +All `default.nix` files recursively. This is the primary function used to discover packages, modules, overlays, etc. + +#### `fs.get-non-default-nix-files` + +``` +Path -> [Path] +``` + +All `*.nix` files whose name is **not** `default.nix` (non-recursive). + +#### `fs.get-non-default-nix-files-recursive` + +``` +Path -> [Path] +``` + +All `*.nix` files recursively whose name is **not** `default.nix`. + +--- + +### home + +**File**: `snowfall-lib/home/default.nix` + +Home-Manager configuration management. + +> **Requires** the `home-manager` flake input. + +#### `home.split-user-and-host` + +``` +String -> { user: String, host: String } +``` + +Parse a `"user@host"` string. If no `@` is present, `host` is `""`. + +```nix +home.split-user-and-host "alice@my-machine" +# => { user = "alice"; host = "my-machine"; } +``` + +#### `home.create-home` + +``` +{ + path, + name?, + modules?, + specialArgs?, + channelName?, + system?, +} -> Attrs +``` + +Create a single home-manager configuration. `name` defaults to the parent directory name of `path`. If the name contains no `@`, the system is appended automatically: `"alice@x86_64-linux"`. + +The configuration is built using `home-manager.lib.homeManagerConfiguration` and automatically includes: +- The Snowfall home user module (`modules/home/user/default.nix`) +- A nix-registry patch module that disables the flake-utils-plus options module (incompatible with standalone home-manager) +- Default `snowfallorg.user.enable = true` and `snowfallorg.user.name` + +Special args injected into modules: + +| Arg | Value | +|---|---| +| `system` | The target system string | +| `name` | The unique `user@system` name | +| `user` | Parsed username | +| `host` | Parsed hostname (may be `""`) | +| `format` | `"home"` | +| `inputs` | User flake inputs (without `src`) | +| `namespace` | Snowfall namespace string | +| `pkgs` | The nixpkgs package set for the system | +| `lib` | The Snowfall-extended lib with `hm` attribute | + +#### `home.get-target-homes-metadata` + +``` +Path -> [{ system: String, name: String, path: Path }] +``` + +Scan a directory (e.g. `homes/x86_64-linux`) for subdirectories that contain `default.nix` and return metadata for each. + +#### `home.create-homes` + +``` +{ + users?, + modules?, +} -> Attrs +``` + +Discover and create all home-manager configurations. Scans `/homes///default.nix`. Applies per-user overrides from `homes.users.` and shared modules from `homes.modules`. + +Auto-discovered home modules from `modules/home/` are injected into every home. + +#### `home.create-home-system-modules` + +``` +Attrs -> [Module] +``` + +When home-manager is used **inside** a NixOS or Darwin system (not standalone), this produces the list of NixOS/Darwin modules that integrate each home into the system. It handles: + +- Passing `extraSpecialArgs` to home-manager +- Injecting `home-manager.sharedModules` +- Per-user `home-manager.users.` configuration scoped to the correct host +- `home-manager.useGlobalPkgs = true` by default + +--- + +### internal + +**File**: `snowfall-lib/internal/default.nix` + +Internal helpers not intended for direct user consumption. + +#### `internal.system-lib` + +The complete library as seen by system and module evaluation contexts. Shallow-merges `nixpkgs.lib`, all input libs, and `{ = user-lib; }`. + +#### `internal.user-lib` + +The user's own library loaded from `/lib/`. Deep-merges all discovered `default.nix` files. Each file can be a function accepting `{ inputs, snowfall-inputs, namespace, lib }` or a plain attribute set. + +#### `internal.create-simple-derivations` + +``` +{ + type, + channels, + src?, + pkgs?, + overrides?, + alias?, +} -> Attrs +``` + +Generic helper used by both `shell.create-shells` and `check.create-checks`. Discovers `default.nix` files under `src` (defaults to `/`), builds them with `callPackageWith`, and filters by the current system. Each derivation receives `{ channels, lib, inputs, namespace }`. + +--- + +### module + +**File**: `snowfall-lib/module/default.nix` + +#### `module.create-modules` + +``` +{ + src?, + overrides?, + alias?, +} -> Attrs +``` + +Discover all `default.nix` files recursively under `src` and expose them as a set keyed by their relative path (e.g. `"networking/firewall"`). + +`src` defaults to `/modules/nixos`. + +Each module wrapper: +1. Derives `system`, `target`, `format`, and `virtual` from module arguments. +2. Injects `lib`, `inputs`, `namespace` into module arguments. +3. Calls the module with the enriched args. +4. Attaches `_file` for error attribution. + +Modules are keyed by their **relative path** from `src`, without the trailing `/default.nix`, e.g. `"hardware/nvidia"`. + +```nix +# modules/nixos/hardware/nvidia/default.nix +{ lib, pkgs, config, namespace, ... }: +{ + options.${namespace}.hardware.nvidia.enable = lib.mkEnableOption "NVIDIA support"; + config = lib.mkIf config.${namespace}.hardware.nvidia.enable { ... }; +} +``` + +--- + +### overlay + +**File**: `snowfall-lib/overlay/default.nix` + +#### `overlay.create-overlays-builder` + +``` +{ + src?, + namespace?, + extra-overlays?, +} -> channels -> [Overlay] +``` + +Produce the `overlaysBuilder` function expected by `flake-utils-plus`. Returns a list of overlays that: +1. Expose all user packages under `pkgs.`. +2. Apply any overlays discovered under `src` (defaults to `/overlays`). +3. Append any extra overlays. + +Each discovered overlay `default.nix` receives `user-inputs // { channels, namespace, inputs, lib }`. + +#### `overlay.create-overlays` + +``` +{ + src?, + packages-src?, + namespace?, + extra-overlays?, +} -> Attrs +``` + +Create the exported `overlays` flake output. Returns a set containing: + +- `"package/"` — a per-package overlay for each discovered package. +- `""` — each discovered overlay from `overlays/`. +- `"default"` — a combined overlay that applies all packages and overlays. +- Any extra overlays passed in. + +Overlays that set `__dontExport = true` are excluded from the exported set. + +--- + +### package + +**File**: `snowfall-lib/package/default.nix` + +#### `package.create-packages` + +``` +{ + channels, + src?, + pkgs?, + overrides?, + alias?, + namespace?, +} -> Attrs +``` + +Discover all `default.nix` files recursively under `src` (defaults to `/packages`), build each with `callPackageWith`, apply aliases and overrides, and filter by the current system. + +Each package's `default.nix` receives via `callPackageWith`: +- All standard `pkgs` attributes +- `pkgs.` pointing to the currently-building package set (enables packages to depend on sibling packages) +- `channels` — all nixpkgs channel sets +- `lib` — the full Snowfall-extended lib +- `inputs` — user inputs +- `namespace` — the namespace string + +Packages are keyed by the **parent directory name** of their `default.nix`, e.g. `packages/my-tool/default.nix` → `"my-tool"`. + +A `meta.snowfall.path` attribute is attached to every built derivation for traceability. + +--- + +### path + +**File**: `snowfall-lib/path/default.nix` + +File path manipulation utilities. + +#### `path.split-file-extension` + +``` +String -> [String] +``` + +Split `"my-file.md"` into `[ "my-file" "md" ]`. Asserts that the file has an extension. + +#### `path.has-any-file-extension` + +``` +String -> Bool +``` + +Return `true` if the string/path has any file extension. + +#### `path.get-file-extension` + +``` +String -> String +``` + +Return the extension of a file name (e.g. `"txt"` from `"my-file.final.txt"`). Returns `""` if none. + +#### `path.has-file-extension` + +``` +String -> String -> Bool +``` + +`has-file-extension "nix" "foo.nix"` → `true`. Curried for use with `filter`. + +#### `path.get-parent-directory` + +``` +Path -> String +``` + +Return the **name** (not full path) of the parent directory. + +```nix +path.get-parent-directory "/a/b/c/default.nix" +# => "c" +``` + +Composed from `baseNameOf ∘ dirOf`. + +#### `path.get-file-name-without-extension` + +``` +Path -> String +``` + +Return the file name without its extension. + +```nix +path.get-file-name-without-extension ./some-dir/my-file.pdf +# => "my-file" +``` + +#### `path.get-output-name` + +``` +Path -> String +``` + +Convenience for package/shell/check output naming. Discards the Nix path string context (required when using a path as an attrset key) and returns the parent directory name. + +```nix +path.get-output-name ./foo/bar/default.nix +# => "bar" +``` + +Composed from `unsafeDiscardStringContext ∘ get-parent-directory`. + +#### `path.get-directory-name` + +``` +Path -> String +``` + +Return the base name of a directory path, discarding string context. + +```nix +path.get-directory-name /templates/foo +# => "foo" +``` + +#### `path.get-relative-module-path` + +``` +String -> Path -> String +``` + +Strip the `src` prefix and the trailing `/default.nix` from a module path, yielding the relative module key used in `module.create-modules`. + +```nix +path.get-relative-module-path "/modules/nixos" "/modules/nixos/foo/bar/default.nix" +# => "foo/bar" +``` + +--- + +### shell + +**File**: `snowfall-lib/shell/default.nix` + +#### `shell.create-shells` + +``` +{ channels, src?, pkgs?, overrides?, alias? } -> Attrs +``` + +Discover all `default.nix` files under `/shells/`, build them as derivations, apply aliases and overrides, and filter by the current system. + +Each shell's `default.nix` receives the same arguments as checks (see [checks](#checks)). + +```nix +# shells/dev/default.nix +{ pkgs, lib, ... }: +pkgs.mkShell { + packages = with pkgs; [ git curl ]; +} +``` + +--- + +### system + +**File**: `snowfall-lib/system/default.nix` + +System configuration management for NixOS, nix-darwin, and virtual (nixos-generators) targets. + +#### `system.get-inferred-system-name` + +``` +Path -> String +``` + +Return the system name from a file path. For `*.nix` files returns the parent directory name; for directories returns `baseNameOf`. + +#### `system.is-darwin` + +``` +String -> Bool +``` + +True if the system target string contains `"darwin"` (e.g. `"aarch64-darwin"`). + +#### `system.is-linux` + +``` +String -> Bool +``` + +True if the system target string contains `"linux"`. + +#### `system.is-virtual` + +``` +String -> Bool +``` + +True if the target corresponds to a nixos-generators virtual format (e.g. `"x86_64-iso"`). + +#### `system.get-virtual-system-type` + +``` +String -> String +``` + +Return the virtual system format string embedded in the target, or `""` if not virtual. See [Virtual Systems](#virtual-systems) for the full list. + +```nix +system.get-virtual-system-type "x86_64-iso" +# => "iso" + +system.get-virtual-system-type "x86_64-linux" +# => "" +``` + +#### `system.get-target-systems-metadata` + +``` +Path -> [{ target: String, name: String, path: Path }] +``` + +For a given target directory (e.g. `systems/x86_64-linux`), enumerate subdirectories containing `default.nix` and return metadata for each. + +#### `system.get-system-builder` + +``` +String -> (Attrs -> Attrs) +``` + +Return the appropriate system builder function for a target: + +| Target | Builder | +|---|---| +| Virtual (any format) | `nixos-generators.nixosGenerate` with `format` set | +| `*-darwin` | `darwin.lib.darwinSystem` | +| `*-linux` | `nixpkgs.lib.nixosSystem` | + +All builders automatically include the corresponding Snowfall user module. + +> **Note**: Virtual systems require the `nixos-generators` input. Darwin systems require the `darwin` input. + +#### `system.get-system-output` + +``` +String -> String +``` + +Return the flake output attribute name for configurations: + +| Target | Output | +|---|---| +| Virtual | `"Configurations"` | +| Darwin | `"darwinConfigurations"` | +| Linux | `"nixosConfigurations"` | + +#### `system.get-resolved-system-target` + +``` +String -> String +``` + +For virtual targets, replace the format with `"linux"` to get the real CPU architecture target. For real targets, returns unchanged. + +```nix +system.get-resolved-system-target "x86_64-iso" +# => "x86_64-linux" +``` + +#### `system.create-system` + +``` +{ + target?, + system?, + path, + name?, + modules?, + specialArgs?, + channelName?, + builder?, + output?, + systems?, + homes?, +} -> Attrs +``` + +Create a single system configuration. All optional fields default from the target string. + +Special args injected into system modules: + +| Arg | Value | +|---|---| +| `target` | The original target string (e.g. `"x86_64-iso"`) | +| `system` | The resolved system (e.g. `"x86_64-linux"`) | +| `format` | `"linux"`, `"darwin"`, or the virtual format string | +| `virtual` | `Bool` | +| `host` | The system name | +| `systems` | Attribute set of all created systems (for cross-system references) | +| `lib` | The Snowfall-extended lib | +| `inputs` | User inputs (without `src`) | +| `namespace` | Snowfall namespace | + +If the `home-manager` input exists, home-manager modules are automatically added. + +#### `system.create-systems` + +``` +{ + systems?, + homes?, +} -> Attrs +``` + +Discover and create all system configurations. Scans `/systems///default.nix`. + +- Applies per-host overrides from `systems.hosts.` +- Applies shared NixOS modules from `systems.modules.nixos` +- Applies shared Darwin modules from `systems.modules.darwin` +- Auto-discovers and injects user modules from `modules/nixos/` or `modules/darwin/` +- All created systems are passed back as the `systems` special arg (enables cross-host references) + +--- + +### template + +**File**: `snowfall-lib/template/default.nix` + +#### `template.create-templates` + +``` +{ + src?, + overrides?, + alias?, +} -> Attrs +``` + +Discover all **directories** under `/templates/` and expose them as flake templates. If the template directory contains a `flake.nix`, its `description` field is automatically extracted and attached to the template metadata. + +```nix +# templates/my-template/flake.nix +{ + description = "A minimal NixOS configuration template"; + # ... +} +``` + +--- + +## NixOS / Darwin / Home Modules + +These modules are part of the flake's `nixosModules`, `darwinModules`, and `homeModules` outputs, and are also automatically injected by Snowfall Lib into every created system/home. + +--- + +### NixOS User Module + +**File**: `modules/nixos/user/default.nix` +**Output**: `nixosModules.user` + +Provides `snowfallorg.users.` options for declarative NixOS user management. + +> **Migration note**: `snowfallorg.user` (singular) is a renamed alias for `snowfallorg.users` (plural). + +#### Options + +``` +snowfallorg.users. +├── create Bool (default: true) — whether to create the OS user +├── admin Bool (default: true) — whether to add the user to the wheel group +└── home + ├── enable Bool (default: true) + ├── path String (default: "/home/") + └── config Submodule — home-manager-compatible configuration +``` + +When `create = true`, a corresponding `users.users.` entry is created with: +- `isNormalUser = true` +- `name = ` +- `home = ` +- `group = "users"` +- `extraGroups = [ "wheel" ]` if `admin = true` + +The `home.config` submodule accepts full home-manager configuration if `home-manager` is available as a flake input. + +--- + +### Darwin User Module + +**File**: `modules/darwin/user/default.nix` +**Output**: `darwinModules.user` + +Same concept as the NixOS module but for nix-darwin. The `admin` option is absent (macOS user management works differently). + +#### Options + +``` +snowfallorg.users. +├── create Bool (default: true) +└── home + ├── enable Bool (default: true) + ├── path String (default: "/Users/") + └── config Submodule +``` + +When `create = true`, creates a `users.users.` entry with `home` and `isHidden = false`. + +--- + +### Home-Manager User Module + +**File**: `modules/home/user/default.nix` +**Output**: `homeModules.user` + +Provides `snowfallorg.user` options for a home-manager configuration. + +#### Options + +``` +snowfallorg.user +├── enable Bool (default: false) — enable automatic home configuration +├── name String — the username +└── home.directory String — the home directory path +``` + +When `enable = true`: +- `home.username` is set to `snowfallorg.user.name` +- `home.homeDirectory` is set to `snowfallorg.user.home.directory` + +The default `home.directory` is determined in order: +1. `osConfig.users.users..home` if available (NixOS/darwin integration) +2. `/Users/` on Darwin +3. `/home/` on Linux + +--- + +## Directory Conventions + +Snowfall Lib auto-discovers files in the following directories relative to `snowfall-config.root` (defaults to your flake's `src`): + +``` +/ +├── systems/ +│ └── / # e.g. x86_64-linux, aarch64-darwin, x86_64-iso +│ └── / +│ └── default.nix +│ +├── homes/ +│ └── / # e.g. x86_64-linux +│ └── / # or @ for host-scoped homes +│ └── default.nix +│ +├── modules/ +│ ├── nixos/ +│ │ └── / +│ │ └── default.nix +│ ├── darwin/ +│ │ └── / +│ │ └── default.nix +│ └── home/ +│ └── / +│ └── default.nix +│ +├── packages/ +│ └── / +│ └── default.nix +│ +├── overlays/ +│ └── / +│ └── default.nix +│ +├── shells/ +│ └── / +│ └── default.nix +│ +├── checks/ +│ └── / +│ └── default.nix +│ +├── templates/ +│ └── / +│ ├── flake.nix # optional — description is extracted automatically +│ └── ... +│ +└── lib/ + └── / + └── default.nix # merged into lib..* +``` + +All directories are optional; Snowfall Lib handles non-existent paths gracefully. + +--- + +## Special Arguments Injected by Snowfall Lib + +### System modules (`modules/nixos/`, `modules/darwin/`) + +| Arg | Type | Description | +|---|---|---| +| `system` | `String` | Resolved system (e.g. `"x86_64-linux"`) | +| `target` | `String` | Original target (e.g. `"x86_64-iso"`) | +| `format` | `String` | `"linux"`, `"darwin"`, or the virtual format | +| `virtual` | `Bool` | Whether this is a virtual system | +| `systems` | `Attrs` | All created system configs (for cross-system references) | +| `lib` | `Attrs` | Snowfall-extended lib | +| `inputs` | `Attrs` | User flake inputs (without `src`) | +| `namespace` | `String` | Snowfall namespace string | + +### System configurations (`systems///default.nix`) + +Same as system modules plus: + +| Arg | Type | Description | +|---|---|---| +| `host` | `String` | The system's hostname | + +### Home configurations (`homes///default.nix`) + +| Arg | Type | Description | +|---|---|---| +| `system` | `String` | The home's target system | +| `name` | `String` | Unique home name (`user@system`) | +| `user` | `String` | The username | +| `host` | `String` | The bound hostname (may be `""`) | +| `format` | `String` | Always `"home"` | +| `inputs` | `Attrs` | User flake inputs (without `src`) | +| `namespace` | `String` | Snowfall namespace | +| `pkgs` | `Attrs` | nixpkgs package set for this system | +| `lib` | `Attrs` | Snowfall-extended lib with `hm` attribute | + +### Packages (`packages//default.nix`) + +Arguments are supplied via `callPackageWith` so any subset can be requested: + +| Arg | Type | Description | +|---|---|---| +| `pkgs.*` | Any | All standard nixpkgs attributes | +| `pkgs.` | `Attrs` | All currently-building user packages | +| `channels` | `Attrs` | All nixpkgs channel sets | +| `lib` | `Attrs` | Snowfall-extended lib | +| `inputs` | `Attrs` | User flake inputs | +| `namespace` | `String` | Snowfall namespace | + +### Shells and Checks + +Same as packages. + +### Overlays (`overlays//default.nix`) + +Overlays are imported as functions and called with: + +```nix +user-inputs // { + channels, + namespace, + inputs, # same as user-inputs + lib, +} +``` + +The overlay function itself should return the standard `final: prev: { ... }` overlay. + +--- + +## Virtual Systems + +Virtual systems use [nixos-generators](https://github.com/nix-community/nixos-generators) to produce machine images. They are enabled by using a virtual format name **instead of** `linux` in the target string. + +The supported formats (in priority order, most-specific first): + +| Format | Target example | +|---|---| +| `amazon` | `x86_64-amazon` | +| `azure` | `x86_64-azure` | +| `cloudstack` | `x86_64-cloudstack` | +| `docker` | `x86_64-docker` | +| `do` | `x86_64-do` | +| `gce` | `x86_64-gce` | +| `install-iso-hyperv` | `x86_64-install-iso-hyperv` | +| `hyperv` | `x86_64-hyperv` | +| `install-iso` | `x86_64-install-iso` | +| `iso` | `x86_64-iso` | +| `kexec` | `x86_64-kexec` | +| `kexec-bundle` | `x86_64-kexec-bundle` | +| `kubevirt` | `x86_64-kubevirt` | +| `proxmox-lxc` | `x86_64-proxmox-lxc` | +| `lxc-metadata` | `x86_64-lxc-metadata` | +| `lxc` | `x86_64-lxc` | +| `openstack` | `x86_64-openstack` | +| `proxmox` | `x86_64-proxmox` | +| `qcow` | `x86_64-qcow` | +| `raw-efi` | `x86_64-raw-efi` | +| `raw` | `x86_64-raw` | +| `sd-aarch64-installer` | `aarch64-sd-aarch64-installer` | +| `sd-aarch64` | `aarch64-sd-aarch64` | +| `vagrant-virtualbox` | `x86_64-vagrant-virtualbox` | +| `virtualbox` | `x86_64-virtualbox` | +| `vm-bootloader` | `x86_64-vm-bootloader` | +| `vm-nogui` | `x86_64-vm-nogui` | +| `vmware` | `x86_64-vmware` | +| `vm` | `x86_64-vm` | + +> **Important**: The order matters. `"vm-bootloader"` must appear before `"vm"` so that a target containing `"vm-bootloader"` does not falsely match `"vm"`. + +Virtual systems output their configurations under `Configurations` (e.g. `isoConfigurations`). The `format` special arg is set to the virtual format string so modules can conditionally apply settings. + +--- + +## Version History + +| Tag | Notable Changes | +|---|---| +| `v3.0.3` | Update nixpkgs to 25.11; `fold` → `foldr` correctness fix | +| `v3.0.2` | Fix: flatten home configs into packages for flake schema compliance; expose activation packages | +| `v3.0.1` | Refactor: eliminate DRY violations; add `fs.get-directories-with-default`, `path.get-relative-module-path`, `path.get-directory-name`, `path.get-output-name`; switch `fold` to `foldr` | +| `v3.0.0` | Refactor: point-free style, pipe-based data transformations, improved attrs helpers, `create-simple-derivations` shared helper | +| `v2.1.x` | Per-channel configuration; same-username-across-targets support; namespace injection in overlays and home-manager | +| `v2.0.0` | Auto-extract template descriptions; replace `./` path roots with `self` for evaluation speed | +| `v1.0.x` | Initial release | diff --git a/flake.lock b/flake.lock index 9e71b22..96b63b4 100644 --- a/flake.lock +++ b/flake.lock @@ -39,11 +39,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1764972694, - "narHash": "sha256-K0CgZH/GOxtURWS/e2R5Iiod3KWQF5jCyIdgFkJ55c8=", + "lastModified": 1773686730, + "narHash": "sha256-TYN0biAPPdNSaLoUPrwAglfuKxiz22GsGbeS6B2+19k=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9ce11f6f11a98a3deeb0c57192a4c9996df50966", + "rev": "18e54fc4e894a2f96720d3428c59ed7343fae26b", "type": "github" }, "original": {