Aspects
An aspect is one feature. It is active at every scope where its at predicate holds.
Each other key gives one element to the sink of that name. The element is a value, or a function
that asks for args (see Args).
In this example, hosts collect packages. Users live under hosts and have no packages sink,
so the packages of a user go up to its host.
# Hosts with users. A host collects `packages`; a user has no such sink, so its packages go up to its host.{ yen, lib, ... }:{ yen.kinds.fleet = { spawns.host = _: yen.host; sinks.out.reduce = yen.lib.reduce.merge; }; yen.kinds.host = { spawns.user = s: lib.filterAttrs (_: u: lib.any (yen.lib.same s) u.hosts) yen.user; sinks.packages.out = { host, packages, ... }: { packages.${host.name} = packages; }; }; yen.kinds.user.fields.hosts = yen.lib.is lib.isList;
yen.fleet.main = { }; yen.flake = { out, ... }: out; yen.host.web = { }; yen.host.db = { }; yen.user.alice.hosts = [ yen.host.web ]; yen.user.bob.hosts = [ yen.host.web yen.host.db ];}One aspect, many files
Section titled “One aspect, many files”at from several files is a union. The keys of every file apply wherever the aspect is active:
# One aspect, two files. `at` is the union of both files.{ yen, ... }:{ yen.aspects.nginx = { at = yen.host.web; packages = "nginx"; };}{ yen, ... }:{ yen.aspects.nginx = { at = yen.host.db; packages = { host, ... }: "nginx-conf-${host.name}"; # a function under the same key: one more element };}nginx is active at both hosts, never at the users. Read it with r.active.nginx:
{ "fleet:main" = false; "fleet:main/host:db" = true; "fleet:main/host:db/user:bob" = false; "fleet:main/host:web" = true; "fleet:main/host:web/user:alice" = false; "fleet:main/host:web/user:bob" = false;}Static content lands once
Section titled “Static content lands once”Static content counts once per receiver. zsh is active at web and at its two users, and web gets one zsh.
Content that names the scope ({ user, ... }:) lands once per scope: each user gives its own dotfiles.
{ yen, ... }:{ # active at hosts and at users; static content lands once at each receiver yen.aspects.zsh = { at = [ yen.kinds.host yen.kinds.user ]; packages = "zsh"; }; # content that names the scope lands once per scope yen.aspects.dotfiles = { at = yen.kinds.user; packages = { user, ... }: "dotfiles-${user.name}"; };}{ db = [ "nginx-conf-db" "nginx" "zsh" "dotfiles-bob" ]; web = [ "nginx-conf-web" "nginx" "zsh" "dotfiles-alice" "dotfiles-bob" ];}