Skip to content

den.ctx Reference

import { Aside } from ‘@astrojs/starlight/components’;

Each den.ctx.<name> is a submodule with these options:

OptionTypeDescription
descstrHuman-readable description
confctx → aspectLocates the aspect for this context
intoattrset of (ctx → list)Transformations to other contexts
includeslist of aspectParametric aspects activated for this context

Context types are also functors — callable as functions:

aspect = den.ctx.host { host = den.hosts.x86_64-linux.igloo; };

When a context type is applied, ctxApply executes:

ctxApply = self: ctx: {
includes = lib.flatten [
(parametric.fixedTo ctx (cleanCtx self)) # owned configs
(self.conf ctx) # located aspect
(mapAttrsToList (name: into: # transformations
map den.ctx.${name} (into ctx)
) self.into)
];
};

All into transformations have the type source → [ target ]:

  • Fan-out: { host }: map (u: { inherit host user; }) users — one host produces N contexts
  • Conditional: { host }: lib.optional (test host) { inherit host; } — zero or one
  • Pass-through: lib.singleton — forward the same data as-is

An empty list means the target context is not created. This enables conditional activation like HM detection without any explicit if logic in the pipeline.

Context types have their own owned configs and includes, making them aspect-like cutting-points in the pipeline:

den.ctx.hm-host.nixos.home-manager.useGlobalPkgs = true;
den.ctx.hm-host.includes = [
({ host, ... }: { nixos.home-manager.backupFileExtension = "bak"; })
];

These only activate for validated HM hosts — more precise than den.default.includes which runs at every pipeline stage.

Add transformations to existing context types from any module:

den.ctx.hm-host.into.foo = { host }: [ { foo = host.name; } ];
den.ctx.foo.conf = { foo }: { funny.names = [ foo ]; };

The module system merges these definitions. You can also override a host’s mainModule to use a completely custom context flow.

FieldValue
descOS
conf{ host }: fixedTo host aspect
into.defaultlib.singleton (pass-through)
into.userEnumerate host.users
into.hm-hostDetect HM support (from hm-detect.nix)
FieldValue
descOS user
conf{ host, user }: includes user + host aspects
into.defaultlib.singleton (pass-through)
FieldValue
conf_: { } (empty — just a dispatcher)

Aliased as den.default via lib.mkAliasOptionModule. Writing den.default.foo is identical to den.ctx.default.foo.

Every context type transforms into default, so den.default.includes functions run at every pipeline stage. Use take.exactly to restrict matching if you see duplicate values.

FieldValue
descStandalone Home-Manager config
conf{ home }: fixedTo home aspect
into.defaultlib.singleton
FieldValue
descHost with HM-supported OS and HM users
conf{ host }: imports HM NixOS/Darwin module
into.hm-userEnumerate HM-class users

Detection criteria (all must be true):

  1. Host class is nixos or darwin
  2. At least one user has class = "homeManager"
  3. inputs.home-manager exists, or host has a custom hm-module attribute

If detection fails, the HM pipeline is skipped entirely.

FieldValue
descInternal — forwards HM class to host
conf{ host, user }: forward homeManager into host

An internal context type used by hm-user. It combines:

  • The user context (den.ctx.user { host, user })
  • Owned configs from the host aspect
  • Static includes from the host aspect
  • Parametric includes from the host aspect matching { host, user }

This ensures that when the homeManager class is forwarded into home-manager.users.<name>, it receives contributions from both the user’s aspect and the host’s aspect.

Context types are independent of NixOS. Use them for any domain:

den.ctx.myctx = {
desc = "{x, y} context";
conf = { x, y }: { funny.names = [ x y ]; };
includes = [
({ x, ... }: { funny.names = [ "include-${x}" ]; })
];
into = {
other = { x, y }: [{ z = x + y; }];
};
};

Owned attributes (anything not desc, conf, into, includes) are included when the context is applied.

Custom context flows can be designed and tested in isolation — Den’s CI tests use a funny.names class that has nothing to do with NixOS to verify the context mechanics independently.See the CI test suite for examples.