collective-public
The public part of a personal Nix configuration. It holds collective-lib, a Nix library with a type system for Nix values and a test framework; modules for Nix-on-Droid, NixOS and Home Manager; a package for renting GPUs; and scripts that turn a Windows machine into a NixOS-WSL development box.
It is published from a folder inside a private configuration repository, and its own README advises against depending on it directly: it changes whenever the configuration does. nix-reflect, a Nix evaluator written in Nix, is built on it.
collective-lib
A library of plain Nix functions, exposed as the flake's lib output. lib.typed is nixpkgs' lib merged with everything below, 1,022 names in all, so code can switch to it with one with.
| File | Lines | What it is |
|---|---|---|
typelib.nix | 5,388 | a type system for Nix values, outside the module system |
log.nix | 1,383 | structured logging and tracing, aware of the type system |
functions.nix | 1,014 | missing functional basics and variadic functions |
strings/strings.nix | 971 | string formatting and multi-line indentation |
attrsets.nix | 740 | attribute-set helpers |
tests.nix | 660 | the test framework: suites, expectations, runners |
script-utils/ansi-utils.nix | 567 | terminal colours and styles for generated scripts |
colors.nix | 556 | colour schemes and hex and RGB formatting for configs |
script-utils/log-utils.nix | 527 | logging for generated shell scripts |
dispatchlib.nix | 460 | dispatch on a value's type or shape |
wm.nix | 407 | window-management intents and key bindings, independent of the window manager |
nixlike.el | 397 | Emacs: evaluate Nix on the fly in a Nix or Tvix REPL |
Types for Nix values
The largest part is a type system that lives outside NixOS's module system. Objects are attribute sets carrying their type and supertype; fields are checked when an object is created and again when it changes, so a value built as a type stays valid for it. Built-in values are wrapped (Int, Bool, …) and the raw value is in .value.
Each type is a subtype and an instance of the one before it. Every example below was evaluated against this flake by capture.py when the page was built.
Declare a type, construct it positionally
with lib.typed;
let A = Type "A" { fields = [ { a = "int"; } { b = Int; } { c = Default Int 5; } ]; };
x = A 1 (Int 2);
in [ x.a x.b.value x.c.value ][1,2,5]
A field of the wrong type is refused
with lib.typed;
let A = Type "A" { fields = [ { a = "int"; } { b = Int; } ]; };
in (A 1 "two").b.valueerror: Upcast error:
Raw values keep their builtin type
with lib.typed; typeOf true"bool"
Wrapped values report their type
with lib.typed; typeOf (Bool true) == Booltrue
But Int does not check its argument
with lib.typed; (Int "123").value"123"
The README is older than the code. Its typed-function example uses defun, which now lives inside the logging layer and is not exported, and its examples use a String type that lib.typed does not export. The eval and parser modules it describes have moved to nix-reflect.
Tests
tests.nix is a small test framework: nested attribute sets of expectations (expect.eq, expect.error, …) gathered into suites, run with lib._tests.run {} or one module at a time. Each library module carries its own suite, and nix-reflect's suites use the same framework.
| Module | Passed | Tests | Result |
|---|---|---|---|
attrsets | 127 | 127 | all pass |
clib | 12 | 12 | all pass |
collections | 62 | 62 | all pass |
colors | 8 | 8 | all pass |
data | 13 | 13 | all pass |
dispatchlib | 27 | 27 | all pass |
errors | 12 | 12 | all pass |
fan | 1 | 1 | all pass |
functions | 134 | 134 | all pass |
lists | 70 | 70 | all pass |
log | 56 | 56 | all pass |
script-utils | 31 | 38 | 7 failing |
strings | 85 | 94 | 8 failing, 1 skipped |
syntax | 4 | 4 | all pass |
tests | 3 | 3 | all pass |
typelib | 448 | 448 | all pass |
The failures are in two places: seven tests of stripping styled text back to plain text in the terminal-styling helpers, and eight tests of padding strings to a display width when they contain multi-byte characters.
Modules and packages
Nix-on-Droid
- supervisord: a small service manager that keeps daemons running across app restarts; other modules declare programs for it, and Home Manager modules can too.
- nod-exec: a TCP command server inside Nix-on-Droid, port 18357 by default, used by NOD Term and X11 Droid.
- pulseserver: health-checks and restarts the PulseServer app.
- sshd, termux, session, dbus, fonts: an SSH server under supervision, Termux integration, restarting daemons after Android stops the app, a session bus and fonts.
Everywhere else
- unexpected-keyboard: a 1,500-line library for building keyboard layouts in Nix, which generates the layouts loaded by the Omni keyboard.
- handheld-daemon (NixOS): Handheld Daemon for handheld gaming PCs, without letting power-profiles-daemon start again.
- vastai: the Vast.ai GPU-rental command-line client, with Docker images and provisioning scripts.
Windows development boxes
The windows/ scripts provision a development machine from a fresh Windows host in one command: they install WSL2 and NixOS-WSL, cap WSL at 48 GB of memory and a 1.5 TiB virtual disk (a ceiling, not an allocation), clone the private configuration and apply it, then manage the Windows side declaratively from inside WSL, installing applications with winget and setting power options.
Where it comes from
Because every push replaces the whole tree, this site is written in the private repository's collective-public/ folder like everything else here.