Skip to content

Every Den battery

A Den battery is an aspect that Den ships. You include it, sometimes with an argument: (den.batteries.user-shell "fish"). In yen there is nothing to ship. The argument becomes a typed field of the host or the user, and the battery is a short aspect whose at says where it applies.

The table lists every battery in Den’s modules/aspects/batteries/. The count is how often each one appears in the 20 most starred public Den configurations on GitHub (October 2026).

Den battery Uses yen
unfree [ … ] 41 nixos.unfree, or by hand: Unfree packages from many files
primary-user 30 nixos.primary-user, or by hand: From Den
define-user 27 nixos.define-user, or by hand: From Den
hostname 25 nixos.hostname, or by hand below
forward 16 a sink whose key gives to another sink: Custom classes
user-shell "fish" 11 a shell field and one aspect, below
inputs', self' 21 inputs is an arg of every yen module; per system: inputs.x.packages.${pkgs.stdenv.hostPlatform.system}
flake-scope – nothing: yen, lib and inputs are args of every yen module
host-aspects 9 an aspect at the users within the host that opt in: includes and provides
mutual-provider 6 nothing: in Den it is inert; in yen within routes both ways
tty-autologin "ana", vm-autologin 7 a host field that names a user, below
insecure [ … ] 5 nixos.insecure, or by hand below: nixpkgs.config does not merge lists
import-tree ./dir 2 the yen template already loads modules/ with import-tree; plain NixOS files go in a nixos.imports
os class (os-class) – an os sink that forwards to nixos and darwin: nix-darwin machines
user class (os-user) – an account sink on the user, below
home-manager – an aspect where a host has users: From Den
hjem, maid – a user sink, chosen by a classes field: den/custom-classes.nix
wsl – a host field wsl and an aspect whose at reads it, as in Many hosts, one base

user-shell "fish" and tty-autologin "ana" take an argument. In yen the argument is a typed field on the instance. This file declares the Den schema, with both fields.

modules/fleet.nix
# Den's schema, declared: hosts build NixOS and hold users. Battery parameters are typed fields.
{
yen,
inputs,
...
}:
let
inherit (yen.lib) opt maybe;
in
{
yen.kinds.fleet = {
spawns.host = _: yen.host;
sinks.out.reduce = yen.lib.reduce.merge;
};
yen.kinds.host = {
fields.autologin = maybe yen.kinds.user; # (1) den.batteries.tty-autologin "ana"
spawns.user = yen.lib.pointing "hosts" yen.user;
sinks.nixos.out =
{ host, nixos, ... }:
{
nixosConfigurations.${host.name} = inputs.nixpkgs.lib.nixosSystem { modules = nixos; };
};
};
yen.kinds.user.fields = {
hosts = yen.lib.listOf yen.kinds.host;
shell = opt (yen.lib.enum [
"bash"
"zsh"
"fish"
]) "bash"; # (2) den.batteries.user-shell "fish"
};
yen.fleet.main = { };
yen.flake = { out, ... }: out;
yen.host.box.autologin = yen.user.ana;
yen.user.ana = {
hosts = [ yen.host.box ];
shell = "fish";
};
yen.user.bob.hosts = [ yen.host.box ];
yen.aspects.box = {
at = yen.host.box;
nixos = {
boot.loader.grub.device = "nodev";
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";
};
nixpkgs.hostPlatform = "x86_64-linux";
system.stateVersion = "25.05";
};
};
}

(1) is the autologin field of a host. Its type is a user or nothing, so autologin must be a user that exists. (2) is the shell field of a user. Its type is one of three names, and the default is bash. A typo such as shell = "fsh" is an error at yen.user.ana.shell.

Each battery below is an aspect. Its at says where it applies, and its nixos key gives a NixOS module to the sink of that name.

modules/batteries.nix
# Den batteries as yen aspects. A battery's `includes` site becomes the aspect's `at`; its argument becomes a field.
{ yen, lib, ... }:
{
# den.batteries.hostname
yen.aspects.hostname = {
at = yen.kinds.host;
nixos =
{ host, ... }:
{
networking.hostName = host.name;
};
};
# den.batteries.user-shell: the shell is the user's field
yen.aspects.user-shell = {
at = yen.kinds.user;
nixos =
{ user, pkgs, ... }:
{
programs.${user.shell}.enable = lib.mkIf (user.shell != "bash") true;
users.users.${user.name}.shell = pkgs.${user.shell};
};
};
# den.batteries.tty-autologin: on the hosts that name a user
yen.aspects.tty-autologin = {
at = s: s.autologin or null != null;
nixos =
{ host, ... }:
{
services.getty.autologinUser = host.autologin.name;
};
};
# den.batteries.define-user, short
yen.aspects.define-user = {
at = yen.kinds.user;
nixos =
{ user, ... }:
{
users.users.${user.name}.isNormalUser = true;
};
};
# Den's `user` class (os-user): a user sink that writes users.users.<name>.
# yen calls it `account`, because `user` is the arg that holds the user itself.
# A sink with no elements gives nothing, so keep defaults out of it: they go in define-user.
yen.kinds.user.sinks.account.nixos =
{ user, account, ... }:
{
users.users.${user.name} = lib.mkMerge account;
};
yen.aspects.ana-tools = {
at = yen.user.ana;
account = {
description = "Ana";
extraGroups = [ "wheel" ];
};
};
}

permittedInsecurePackages is a list, but it is in nixpkgs.config, and nixpkgs.config does not merge lists. When two NixOS modules set it, only one list survives, with no error. We wrote this page first without the sink, on NixOS 25.05, and bob’s entry was lost. The fix is the same as for unfree (Unfree packages from many files): a sink of names, and one module that sets the option.

modules/insecure.nix
# den.batteries.insecure: nixpkgs.config does not merge lists. When two modules set permittedInsecurePackages,
# only one list survives. A sink collects the names, and one module sets the option.
{ yen, lib, ... }:
{
yen.kinds.host.sinks.insecure.nixos =
{ insecure, ... }:
{
nixpkgs.config.permittedInsecurePackages = lib.flatten insecure;
};
yen.aspects.matrix-client = {
at = yen.host.box;
insecure = [ "olm-3.2.16" ];
};
yen.aspects.old-tool = {
at = yen.user.bob; # from a user: the names go up to each of bob's hosts
insecure = [ "python-2.7.18.8" ];
};
}
ContributeCommunitySponsor