This is the human-readable version of how the flake works now.
Think of the repo like a tree:
inventory/says what existsdendrites/say what kinds of reusable capability can growfruits/are named things the tree can actually runhosts/carry the weird machine-specific exceptionslib/is the assembly logic that snaps those pieces together
The goal is to keep the root simple and make composition legible.
When you build .#nixosConfigurations.desktoptoodle:
flake.nixloads the flake-parts glue inmodules/- the glue builds passive registries from
dendrites/,fruits/,homes/, andhosts/ inventory/hosts.nixis normalized into the current host schema- the resolver figures out which dendrites and fruits the host needs
- validation checks that the combination makes sense
- the resolved modules are handed to
nixosSystem
So the root flake is not doing the detailed work itself. It is routing into the composition library.
A reusable capability branch.
Examples:
basestoragedesktopsystem
A child specialization of a bigger branch.
Examples:
storage/zfsstorage/tapedesktop/gnome
A small internal module imported by a branch.
Examples:
dendrites/base/leaves/system.nixdendrites/base/leaves/services.nix
Leaves are usually implementation details of a branch, not something a host selects directly.
A named deployable outcome.
Example:
fossilsafe
Fruits are the things you actually run, expose, or keep alive.
The repo avoids two common problems:
- giant root flakes that hand-wire everything
- unlimited recursive auto-loading where adding a file silently changes behavior
Instead, it uses a middle path:
- the root discovers only first-class modules by convention
- each branch owns its own internal imports
- helper code stays inert until explicitly referenced
Each dendrite and fruit has metadata so the assembly layer can answer questions like:
- what does this provide
- what does it require
- what conflicts with it
- what kinds of hosts should use it
Metadata describes a thing. It is not supposed to secretly implement the thing.
Hosts are not required to be tiny. They are allowed to carry a lot of local data.
What matters is that the data is separated cleanly:
roles,dendrites,fruits,userswhat the host is selectingnetworksexplicit membership in special inventory-defined networkspublicYggdrasila deliberate host-level switch for future public Ygg exposure, currently kept falsefactsmachine-specific facts like pool names, host IDs, and tape device pathsorg.*settings consumed by moduleshardwareModuleslow-level hardware importsoverrideshost-specific escape hatches
That is why a machine like desktoptoodle can still own a lot of tape-library
detail without collapsing the whole architecture.
r640-0 currently works like this:
- role:
workstation - dendrite selection includes
storage/zfs - facts include the ZFS pool name and mount root
- policy includes linked users under
org.storage.zfs - a host override still exists for machine-specific behavior
That split is intentional:
- branch selection says what kind of capability is present
- facts say what hardware or local identity exists
- policy says how that capability should behave
This architecture depends on compatibility checks.
The flake already validates things like:
- unknown users or roles
- conflicting dendrites
- missing required ZFS facts
- missing tape devices
- missing FossilSafe fruit attachment for FossilSafe-backed tape setups
If a new branch or fruit has strict requirements, the right answer is usually to add another validation rule.
This repo wants filenames to explain themselves.
That means:
dendrites/storage/storage.nixhosts/r640-0/r640-0.nixfruits/fossilsafe/fossilsafe.nix
not default.nix everywhere.
It makes the tree easier to scan and helps the registry conventions stay obvious.