refactor(nix): make all-local a deployment mode, not a default

mara: enableAllLocalDefaults is more of a deployment mode via settings
set, less a default setting.

That reframing is the change. A mode asserts values; an option declares
what it is when nobody asks. Written as default = <flag>, every service
option had to name a switch it has no relationship to, and the answer to
what does all-local turn on was spread across five files.

Two modules now hold the two tiers - local-defaults.nix for the mode and
what it asserts directly, swarm-required-services.nix for the
services-live-here switch and the per-service enables under it. Each
service module keeps its own declaration and loses only the line about
when a deployment wants it.

mkDefault is the right precedence rather than a compromise: it beats an
option default and yields to any explicit definition, so the mode fills
in for an operator who has not spoken and never argues with one who has.
Evaluated config is unchanged in both directions.
This commit is contained in:
atlas 2026-08-05 19:41:11 +02:00
commit 048bdd29a8
8 changed files with 134 additions and 79 deletions

View file

@ -12,6 +12,7 @@
{
imports = [
./hyperhive.nix
./local-defaults.nix
./hive-c0re
./hive-ci.nix
./hive-forge
@ -27,5 +28,6 @@
./swarm-snapshot-store.nix
./swarm-wireguard.nix
./swarm.nix
./swarm-required-services.nix
];
}

View file

@ -99,19 +99,16 @@ in
options.services.hyperhive.swarm.matrix = {
enable = lib.mkOption {
type = lib.types.bool;
default = config.services.hyperhive.swarm.enableRequiredServices;
defaultText = lib.literalExpression "services.hyperhive.swarm.enableRequiredServices";
default = false;
description = ''
Run hive-matrix a private matrix-tuwunel homeserver (in a
nixos-container) for hyperhive agents.
Matrix is a swarm-wide service one homeserver, not one per
hive so this defaults from
`services.hyperhive.swarm.enableRequiredServices`, which says
the swarm's shared services live on this host. That is off by
default, so this is off by default, as before. Set it directly
to run the homeserver somewhere other than the host that holds
the rest of the swarm's services.
hive so `services.hyperhive.swarm.enableRequiredServices`
turns this on as part of saying the swarm's shared services live
on this host. Set it here directly to run the homeserver
somewhere other than the host that holds the rest of them.
'';
};

View file

@ -132,31 +132,9 @@ in
'';
};
# The one switch for "everything runs on this box". Every autoconf
# toggle in the tree defaults from it, so an all-local deployment is a
# single line rather than one line per service that grew a toggle.
options.services.hyperhive.enableAllLocalDefaults = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run the whole swarm on this host: the swarm-wide services
(`services.hyperhive.swarm.enableRequiredServices`) and the swarm
CA (`services.hyperhive.swarm.ca.autoConfigure`) all default from
this, and anything autoconfigurable added later should too.
**Off by default, and that is the load-bearing part.** A swarm's
services and its hives can live on different hosts, and a host has
no way to tell which ones it is meant to be so this is an
operator saying "this is that box", never something inferred.
Turn it on for a dev box or a single-hive swarm and get a working
deployment with no further configuration; leave it off and every
swarm-level artifact is operator-provided.
Each derived toggle can still be set explicitly to override this
one, so "all local except X" needs no new option.
'';
};
# `enableAllLocalDefaults` is declared in ./local-defaults.nix, with
# the values it asserts. It is a deployment mode rather than a setting
# this module's options read, so it lives with its consequences.
# Whether this hive runs "ruthless" — with no root/manager agent at
# all. Some hives don't want a root agent — see issue tracker

View file

@ -0,0 +1,58 @@
# The all-local deployment mode.
#
# `enableAllLocalDefaults` is a *mode*, not a default other options read:
# it says "this box is the whole deployment" and then asserts the values
# that follow from that. mara, on the issue: it is "more of a deployment
# mode via settings set, less a default setting".
#
# That distinction is why the derivations live here as `mkDefault` in a
# `config` block rather than as `default =` inside each option. An option
# declares what IT is and what it is when nobody asks; a mode declares
# what a deployment shape implies. Written the other way round, every
# service option had to name a flag it has no relationship to, and the
# answer to "what does all-local turn on?" was spread across five files.
#
# Adding an autoconfigurable thing later means one line here — not a
# `default =` in the new module pointing back at this flag.
{
lib,
config,
...
}:
let
cfg = config.services.hyperhive;
in
{
options.services.hyperhive.enableAllLocalDefaults = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run the whole swarm on this host. Turning this on asserts the
swarm-level toggles that an all-on-one-box deployment implies:
the swarm's shared services
(`services.hyperhive.swarm.enableRequiredServices`) and the swarm
CA (`services.hyperhive.swarm.ca.autoConfigure`).
**Off by default, and that is the load-bearing part.** A swarm's
services and its hives can live on different hosts, and a host has
no way to tell which ones it is meant to be so this is an
operator saying "this is that box", never something inferred.
Turn it on for a dev box or a single-hive swarm and get a working
deployment with no further configuration; leave it off and every
swarm-level artifact is operator-provided.
Each toggle it asserts can still be set explicitly, which wins
so "all local except X" needs no new option.
'';
};
# What the mode asserts. `mkDefault` (priority 1000) beats an option's
# own `default` (1500) and loses to any explicit definition, which is
# exactly the precedence a deployment mode wants: it fills in for an
# operator who hasn't spoken, and never argues with one who has.
config.services.hyperhive.swarm = {
enableRequiredServices = lib.mkDefault cfg.enableAllLocalDefaults;
ca.autoConfigure = lib.mkDefault cfg.enableAllLocalDefaults;
};
}

View file

@ -5,9 +5,9 @@
#
# - the CLIENT pointer (`url`) exists on every hive, because a hive
# that doesn't run authelia still has to know where to send people.
# - the CONTAINER only exists where the swarm's shared services live
# (`swarm.enableRequiredServices`, itself defaulting from
# `enableAllLocalDefaults`). A hive is a client by default.
# - the CONTAINER only exists where the swarm's shared services live.
# `swarm.enableRequiredServices` asserts this module's `enable`
# (see ./swarm-required-services.nix); a hive is a client by default.
#
# Operator and agents are both subjects of the same provider,
# differentiated by roles/claims rather than by mechanism — there is one
@ -31,7 +31,6 @@
let
cfg = config.services.hyperhive.swarm.authelia;
hyperhiveCfg = config.services.hyperhive;
swarmCfg = config.services.hyperhive.swarm;
hyperhiveDomain = hyperhiveCfg.domain;
# Upstream's `services.authelia.instances.<name>` derives the unit,
@ -51,14 +50,13 @@ in
options.services.hyperhive.swarm.authelia = {
enable = lib.mkOption {
type = lib.types.bool;
default = swarmCfg.enableRequiredServices;
defaultText = lib.literalExpression "services.hyperhive.swarm.enableRequiredServices";
default = false;
example = true;
description = ''
Run the swarm's authelia in a `swarm-authelia` container on this
host. Defaults from
`services.hyperhive.swarm.enableRequiredServices` a swarm has
one SSO provider, and this says it lives here.
host. `services.hyperhive.swarm.enableRequiredServices` turns
this on a swarm has one SSO provider, and that says it lives
here.
With it off, this hive is a *client*: `url` below still points
at whoever runs it, and no container is created.

View file

@ -52,18 +52,15 @@ in
options.services.hyperhive.swarm.ca = {
autoConfigure = lib.mkOption {
type = lib.types.bool;
default = hyperhiveCfg.enableAllLocalDefaults;
defaultText = lib.literalExpression "services.hyperhive.enableAllLocalDefaults";
default = false;
example = true;
description = ''
Run the whole swarm CA on this one host: generate the swarm
root when it is missing, and issue this hive's CA under it.
Defaults from `services.hyperhive.enableAllLocalDefaults`, the
all-on-one-box switch which is off, so this is off, and the
paragraph below still describes what a hive does by default.
Set it directly to run the CA on a host that is not otherwise
all-local.
`services.hyperhive.enableAllLocalDefaults` turns this on as
part of the all-on-one-box mode. Set it here directly to run the
CA on a host that is not otherwise all-local.
**Off by default, deliberately.** A swarm's services and its
hives can live on different hosts, and this host has no way to

View file

@ -0,0 +1,51 @@
# "The swarm-wide services run HERE."
#
# A swarm has one forge, one matrix, one SSO. This says this host is
# where they live, and asserts the per-service `enable`s that follow —
# the same mode-not-default shape as ./local-defaults.nix, one tier down.
#
# Only the *optional* services derive: matrix and authelia. The forge has
# no `enable` to assert, because it is not optional — it is the canonical
# store for the meta flake and every agent's config repo, so it deploys
# with hyperhive itself.
{
lib,
config,
...
}:
let
swarmCfg = config.services.hyperhive.swarm;
in
{
options.services.hyperhive.swarm.enableRequiredServices = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Host the swarm's shared services on this hive. The services that
exist once per swarm rather than once per hive and are *optional*
the matrix homeserver, the SSO provider have their `enable`
asserted from this, so a swarm's service host is declared in one
place.
The forge is swarm-wide too but has nothing to assert: it is the
canonical store for the meta flake and every agent's config repo,
so it deploys with hyperhive itself and is not optional.
`services.hyperhive.enableAllLocalDefaults` turns this on as part
of the all-on-one-box mode. Set it directly to run the swarm's
services on a host that is not otherwise all-local a dedicated
services box with hives elsewhere is exactly that shape.
With it off, this hive is a *client* of those services: it still
configures how to reach them, it just doesn't run them.
'';
};
# Same precedence reasoning as ./local-defaults.nix: fills in for an
# operator who hasn't spoken, yields to one who has.
config.services.hyperhive.swarm = {
matrix.enable = lib.mkDefault swarmCfg.enableRequiredServices;
authelia.enable = lib.mkDefault swarmCfg.enableRequiredServices;
};
}

View file

@ -126,36 +126,10 @@
'';
};
# "The swarm-wide services run HERE." A swarm has one forge, one
# matrix, one SSO — this says this host is where they live. The
# OPTIONAL ones (matrix, authelia) default their own enable from it,
# rather than the operator enabling them one at a time; the forge has
# no enable to derive because it is not optional.
options.services.hyperhive.swarm.enableRequiredServices = lib.mkOption {
type = lib.types.bool;
default = config.services.hyperhive.enableAllLocalDefaults;
defaultText = lib.literalExpression "services.hyperhive.enableAllLocalDefaults";
example = true;
description = ''
Host the swarm's shared services on this hive. The services that
exist once per swarm rather than once per hive and are *optional*
the matrix homeserver, the SSO provider default their
`enable` from this, so a swarm's service host is declared in one
place.
The forge is swarm-wide too but has no `enable` to derive: it is
the canonical store for the meta flake and every agent's config
repo, so it deploys with hyperhive itself and is not optional.
Defaults from `services.hyperhive.enableAllLocalDefaults` (off),
which is the all-on-one-box switch. Set it directly to run the
swarm's services on a host that is not otherwise all-local a
dedicated services box with hives elsewhere is exactly that shape.
With it off, this hive is a *client* of those services: it still
configures how to reach them, it just doesn't run them.
'';
};
# `enableRequiredServices` is declared in ./swarm-required-services.nix
# together with the per-service `enable`s it asserts — it is a
# deployment-shape switch rather than swarm bookkeeping, so it lives
# with its consequences instead of here.
options.services.hyperhive.swarm.snapshotStore = {
address = lib.mkOption {