den.policies
See Policies for conceptual background.
den.policies
Section titled “den.policies”Type: lazyAttrsOf policyFunction
A registry of named policies. Each entry is a function from context to a
list of policy effects. The module system wraps bare functions into
{ __isPolicy = true; name; fn; } records automatically.
den.policies.my-policy = { host, ... }: [ (policy.resolve { enriched = true; })];Declaring a policy here only registers it. Activation happens via
includes — see Activation.
Policy effects
Section titled “Policy effects”All constructors are accessed via den.lib.policy. Policies return lists
of these effects.
policy.resolve bindings
Section titled “policy.resolve bindings”Create a new scope with bindings merged into the current context.
policy.resolve { myFlag = true; }Variants:
policy.resolve.shared bindings— shared (non-isolated) fan-outpolicy.resolve.to kind bindings— target a specific entity kindpolicy.resolve.shared.to kind bindings— shared fan-out with explicit target kindpolicy.resolve.withIncludes includes bindings— attach includes to the new scopepolicy.resolve.to.withIncludes kind includes bindings— both
policy.include aspect
Section titled “policy.include aspect”Inject an aspect into the current resolution:
policy.include { nixos.environment.variables.MARKER = "yes"; }policy.exclude aspect
Section titled “policy.exclude aspect”Remove an aspect via the constraint registry:
policy.exclude den.aspects.unwantedpolicy.deliver spec
Section titled “policy.deliver spec”The user-facing delivery primitive: declare one delivery edge from a source
into a target class at a path, with an explicit mode. route and provide
(below) are sugar shims over deliver.
# Class source — move a class's collected content (the `route` case):policy.deliver { from = "myClass"; # class name → collect that class's bucket to = "nixos"; # target class at = [ "services" "myService" ]; # attrpath ([] = merge at the class root) mode = "nest"; # "merge" | "nest" | "verbatim"}
# Module source — inject a NEW module (the `provide` case):policy.deliver { from = { module = { pkgs, ... }: { ... }; }; to = "nixos";}mode is exhaustive and explicit:
merge(default) — union into the target class bucket (use withat = []).nest— evaluate and place the source atat.verbatim— place the collected module wrappers by reference so a target whose optionmergere-instantiates them (e.g. a microvm guest config) sees the live modules together with its base modules. There is noreinstantiateflag — verbatim is requested bymodedirectly.verbatimapplies only to class sources, not module sources.
Class sources accept two optional fields:
guard = args: bool— only deliver when the predicate holds against the target’s module-system args (e.g.{ options, ... }: options ? wsl). A failed guard means the delivered content contributes nothing.adaptArgs = args: attrs— an args/specialArgs adapter for the delivered modules: with a non-emptyat, the source modules are evaluated in a submodule whosespecialArgsareadaptArgsapplied to the target’s args (e.g. injectosConfig = config); at the root (at = []), it adapts the args each module function receives.
deliver deliberately does not expose appendToParent (parent-targeting is
constructor-internal) — use a class source whose to already names the target.
policy.route spec
Section titled “policy.route spec”Route class or quirk content from one scope partition into a target class. A
permanent sugar shim over policy.deliver —
fromClass→from, intoClass→to, path→at, and reinstantiate = true→
mode = "verbatim":
policy.route { fromClass = "myClass"; intoClass = "nixos"; path = [ "services" "myService" ];}Additional spec fields (passed through to the underlying edge):
intoPath = item: path— public alias forpaththat pairs withfromClass/intoClass(theforwardbattery’s naming). Passing bothpathandintoPathis an error.guard/adaptArgs— same semantics as ondeliver(see above).collectSubtree = true— also collect the source class’s content from the scope’s descendant scopes, not just the scope itself. Used by the built-in flake-parts policy so per-systempackagesgather host/user contributions.
policy.provide spec
Section titled “policy.provide spec”Deliver a module directly to a target class, bypassing the aspect tree. A
permanent sugar shim over policy.deliver with a module
source (class→to, module→from.module, path→at; mode is derived
from path — merge at the root, nest under a non-empty path):
policy.provide { class = "nixos"; module = { pkgs, ... }: { ... }; }policy.instantiate spec
Section titled “policy.instantiate spec”Request post-pipeline instantiation. Pass an entity to use its own
instantiate/intoAttr metadata:
policy.instantiate den.hosts.x86_64-linux.iglooOr pass a custom spec to instantiate something that isn’t an entity (e.g. a third-party builder fed by a den class — the terranix pattern):
policy.instantiate { name = "${host.name}-tf"; class = "terranix"; # which class bucket to collect instantiate = { modules, ... }: modules; # how to build from collected modules intoAttr = [ "terranixModules" host.name ]; # where the result lands};policy.spawn
Section titled “policy.spawn”Request a deferred node spawn, resolved post-walk over the parent
pipeline’s full scope-tree state (host + siblings) so projected content
sees fleet-wide pipe values. classes defaults to the spawning entity’s
classes at the drain site when null:
policy.spawn { }policy.spawn { classes = [ "homeManager" ]; }policy.pipe
Section titled “policy.pipe”See den.quirks reference for the pipe builder API.
policy.pipelineOnly value
Section titled “policy.pipelineOnly value”Tag a value with collisionPolicy = "class-wins" — when the value
collides with a module-system arg (e.g., NixOS provides lib), the
class value wins silently.
Activation
Section titled “Activation”Policies are activated by including them in includes lists. The pipeline
distinguishes policies from aspects by the __isPolicy tag.
# For all entities of a kindden.schema.host.includes = [ den.policies.my-policy ];
# For a specific aspect's subtreeden.aspects.igloo.includes = [ den.policies.my-policy ];
# For all entities globallyden.default.includes = [ den.policies.my-policy ];Policies and aspects mix freely in includes.
den.lib.policy.mkPolicy name fn
Section titled “den.lib.policy.mkPolicy name fn”Create a named policy record for direct use in includes. Use this when
defining inline policies that don’t need the den.policies registry:
den.default.includes = [ (den.lib.policy.mkPolicy "host-guards" ({ host, ... }: [ (den.lib.policy.resolve { isNixos = host.class == "nixos"; isDarwin = host.class == "darwin"; }) ]))];Returns { __isPolicy = true; name; fn; } — the pipeline recognizes this
as a policy and routes it to the dispatch system.
Deactivation
Section titled “Deactivation”Use excludes to prevent a policy from firing in a subtree:
den.aspects.igloo = { excludes = [ den.policies.blocked ];};Excludes are authoritative — parent excludes cannot be overridden by child includes. The constraint registry uses the policy’s identity for matching.
Combinators
Section titled “Combinators”den.lib.policy.for entity policyOrList
Section titled “den.lib.policy.for entity policyOrList”Wrap a policy to fire only when a specific entity is in context, matched
by id_hash:
den.lib.policy.for den.hosts.x86_64-linux.igloo den.policies.igloo-onlyAccepts a single policy or a list. Identity is preserved through the wrapper.
den.lib.policy.when predicate policyOrList
Section titled “den.lib.policy.when predicate policyOrList”Wrap a policy to fire only when a predicate over the current context returns true:
den.lib.policy.when ({ host, ... }: host.wsl.enable) den.policies.wsl-setupAccepts a single policy or a list. Identity is preserved.
Composition
Section titled “Composition”Combinators compose:
den.lib.policy.when (ctx: ctx.flag or false) (den.lib.policy.for entity den.policies.my-policy)Built-in policies
Section titled “Built-in policies”Entity traversal (core.nix)
Section titled “Entity traversal (core.nix)”| Policy | From | To | Behavior |
|---|---|---|---|
host-to-users | host | user | One { host, user } per host.users entry |
Battery-driven class routing
Section titled “Battery-driven class routing”These fire automatically with their battery (most via den.default.includes,
so they are active without any explicit inclusion):
| Policy | Source | Behavior |
|---|---|---|
os-to-host | batteries/os-class | Route os class content to the host’s class (nixos/darwin) in every host/user scope |
user-to-host | batteries/os-user | Route user class content to users.users.<userName>, injecting osConfig |
host-to-hm-users / hm-user-detect | batteries/home-manager | Import the HM OS module; forward each HM user’s homeManager class into home-manager.users.<name>. The *-user-detect policy covers users resolved by registry/policy rather than host.users. hjem and maid batteries register the same family (host-to-hjem-users, host-to-maid-users, …) |
host-to-wsl-host / wsl-to-host | batteries/wsl | Resolve the wsl-host entity when host.wsl.enable; route wsl class content to the host’s OS at wsl |
Flake-parts (policies/flake-parts.nix, opt-in via den.schema)
Section titled “Flake-parts (policies/flake-parts.nix, opt-in via den.schema)”| Policy | From | To | Behavior |
|---|---|---|---|
system-to-flake-parts | flake-system | flake-parts | One { flake-parts } per system |
packages-to-flake-parts | flake-system | flake-parts | Route packages class into perSystem packages (collectSubtree) |
The flake-scope battery carries its own internal policy
(den-flake-scope) for pipeline-arg enrichment — see
Batteries.
Flake output traversal (flake.nix)
Section titled “Flake output traversal (flake.nix)”| Policy | From | To | Behavior |
|---|---|---|---|
flake-to-systems | flake | flake-system | One { system } per den.systems entry |
system-to-os-outputs | flake-system | host | One { host } per host + instantiate |
system-to-hm-outputs | flake-system | home | One { home } per home + instantiate |
packages-to-flake | flake-system | — | Route packages class to flake output |
apps-to-flake | flake-system | — | Route apps class to flake output |
checks-to-flake | flake-system | — | Route checks class to flake output |
devShells-to-flake | flake-system | — | Route devShells class to flake output |
legacyPackages-to-flake | flake-system | — | Route legacyPackages class to flake output |
den.lib.policyInspect.inspect
Section titled “den.lib.policyInspect.inspect”Lightweight inspection utility that calls resolve functions directly without running the full pipeline:
den.lib.policyInspect.inspect { kind = "host"; context = { host = den.hosts.x86_64-linux.igloo; };}Parameters:
kind— entity kind stringcontext— attrset representing the current pipeline context
Returns an attrset keyed by policy name with resolved targets, routing type, and other metadata.
See also
Section titled “See also”- Policies explanation — conceptual overview
- Policy Activation Deep Dive — registry/activation model, dispatch internals
- den.quirks — pipe builder API (a policy effect type)