`services.hyperhive.enable` and `services.hyperhive.c0re.enable` are gone. One switch, `services.hyperhive.deploy.hive-controller.enable` (default false, as the old toggle was), now gates hive-c0re and hive-priv. Both old paths are `mkRenamedOptionModule` shims in deploy.nix, so a host config that still sets either evaluates as before and gets a rename warning. Every other read of the old toggle is resolved, including the 29 made through the `hyperhiveCfg`/`hiveCfg` aliases: - Dropped: each swarm service and its glue keeps only its own deploy toggle (authelia, bao and its PKI glue, grafana, victorialogs, victoriametrics, the secret publisher, swarm-ca, the OIDC client rows, the controller/nats/matrix-ctl/publisher/services-issuer identities), the forge, and the `domain` deprecation warning. - To deploy.hive-controller.enable: the queue-agent credential reader and its assertion, which feed hive-c0re and write under its state dir, plus their policy-order entry; the network identity assertions; hive-tls's two writes into hive-c0re's environment. - hive-tls runs where the gateway runs self-signed (`gateway.enable && useSelfSigned`), not on every host. - The matrix appservice-token reader and its assertion stay on `deploy.matrix.enable` plus their client-identity checks. They read deploy.matrix's token file and registration script; their deploy.bao inputs are the client-half options a hive sets to read a store it does not run, so gating on deploy.bao.enable would drop the tested remote-reader case. - The `hiveName` assertion moves from hive-network.nix to hyperhive.nix and fires wherever the hive, the store or the homeserver runs: each turns the name into an identifier with no fallback. On a host with `deploy.allSwarmServices` and no hive, the documented services-host recipe, authelia, bao, grafana, victorialogs, victoriametrics, the OIDC client rows and the hive CA now render; before, the old toggle being off left them out. Refs #4500
229 lines
10 KiB
Nix
229 lines
10 KiB
Nix
# Top-level, cross-cutting hyperhive options: the hive's identity
|
|
# (domain + display names) and hive-wide feature toggles read by several
|
|
# subsystem modules. Imported by the ./default.nix aggregator.
|
|
{
|
|
lib,
|
|
config,
|
|
options,
|
|
...
|
|
}:
|
|
let
|
|
hiveCfg = config.services.hyperhive;
|
|
in
|
|
{
|
|
# The swarm's display name moved under `swarm` when the swarm-global
|
|
# settings were consolidated; the hive's own name and domain stayed put,
|
|
# because they describe this hive rather than the swarm it joins.
|
|
imports = [
|
|
(lib.mkRenamedOptionModule
|
|
[ "services" "hyperhive" "swarmName" ]
|
|
[ "services" "hyperhive" "swarm" "name" ]
|
|
)
|
|
];
|
|
|
|
# Canonical hive DNS domain shared by every subsystem that needs a
|
|
# stable hostname. Typed nullOr (default null) so the option always
|
|
# exists, but it's REQUIRED wherever this host runs a hive — an
|
|
# assertion in hive-network.nix fails eval when it's unset, since
|
|
# matrix bakes it in on first boot and the gateway/forge/agent URLs all
|
|
# derive from it (no safe default). Full identity-surface
|
|
# context (HYPERHIVE_HIVE_DOMAIN / HIVE_NAME / SWARM_NAME env-var
|
|
# chain → identity.rs → claude prompt): docs/process/conventions.md::
|
|
# Hive identity (label + domain + display names).
|
|
options.services.hyperhive.domain = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
# Read out of the swarm directory rather than derived here. The
|
|
# directory is what every OTHER hive reads this hive's address from,
|
|
# so deriving it separately gave two homes for one value with
|
|
# nothing asserting they agreed — and a disagreement surfaces as
|
|
# "the other hives can't reach me", on a machine other than the
|
|
# misconfigured one.
|
|
#
|
|
# ⚠️ The `<hiveName>.<swarm.domain>` formula did NOT move here from
|
|
# there and back: it lives once, on `hives.<name>.domain`, which
|
|
# this reads. Restoring a direct fallback here would recreate the
|
|
# second path (and, since that default reads `swarm.domain` too, a
|
|
# value that can differ from the directory's).
|
|
default =
|
|
if hiveCfg.hiveName != null && hiveCfg.swarm.hives ? ${hiveCfg.hiveName} then
|
|
hiveCfg.swarm.hives.${hiveCfg.hiveName}.domain
|
|
else
|
|
null;
|
|
defaultText = lib.literalExpression "services.hyperhive.swarm.hives.\${hiveName}.domain, or null when there is no entry for this hive";
|
|
example = "darkest.space";
|
|
description = ''
|
|
Canonical host domain for hyperhive subsystems that need a
|
|
stable name (currently: `services.hyperhive.swarm.matrix.serverName`
|
|
derives from this, defaulting to
|
|
`matrix.''${services.hyperhive.domain}` when `serverName` is
|
|
null). **Required** when
|
|
`services.hyperhive.deploy.hive-controller.enable` — eval fails
|
|
with a helpful message if it's unset (it's baked into matrix on
|
|
first boot and drives the gateway/forge/agent URLs, with no safe
|
|
default; changing it later is destructive). Exposed to agents as
|
|
`HYPERHIVE_HIVE_DOMAIN`; consumed by
|
|
`hive-agent::identity::hive_domain()` for `<name>@<domain>`
|
|
qualified labels.
|
|
|
|
**Deprecated as a place to write.** It is read from this hive's
|
|
own entry in `services.hyperhive.swarm.hives`, whose `domain`
|
|
defaults to `<hiveName>.<swarm.domain>` — so a conventional hive
|
|
states nothing at all, and a non-conventional one states its
|
|
address in the directory every other hive reads. Setting it here
|
|
still wins and still works, with a warning: the directory is
|
|
shared, this option is not, so a value written only here is
|
|
invisible to the rest of the swarm.
|
|
'';
|
|
};
|
|
|
|
# Deprecation warning for the shorthand above, fired on PRIORITY.
|
|
#
|
|
# ⚠️ Not `isDefined`, and not `files`: the module system injects an
|
|
# option's own `default` as a definition attributed to the declaring
|
|
# file, so both say "defined, in hyperhive.nix" for a config that set
|
|
# nothing — measured, after this warning fired on the conventional
|
|
# case. `mkOptionDefault` is priority 1500, so anything lower is a
|
|
# definition someone actually wrote (100 plain, 1000 mkDefault).
|
|
config.warnings = lib.optional (options.services.hyperhive.domain.highestPrio < 1500) ''
|
|
services.hyperhive.domain is set explicitly and is deprecated. This
|
|
hive's address belongs in the swarm directory, which every hive in
|
|
the swarm shares a copy of:
|
|
|
|
services.hyperhive.swarm.hives."${toString hiveCfg.hiveName}".domain = "${toString hiveCfg.domain}";
|
|
|
|
(Or drop the value entirely if it is the conventional
|
|
`<hiveName>.<swarm.domain>` — that is the directory entry's own
|
|
default.)
|
|
|
|
Setting it here still wins, so nothing is broken right now. What it
|
|
does not do is tell the other hives: they read this hive's address
|
|
out of their copy of the directory, so a value written only here
|
|
leaves them pointing somewhere else with nothing detecting it.
|
|
'';
|
|
|
|
# Where the swarm lives. Declared beside the hive's own identity
|
|
# because it is what that identity is derived FROM — every hive in a
|
|
# swarm is a sub-domain of it. Unlike the renamed options nearby, this
|
|
# is genuinely new: nothing moved here, so there is no alias.
|
|
options.services.hyperhive.swarm.domain = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
example = "darkest.space";
|
|
description = ''
|
|
DNS domain of the wider swarm this hive belongs to. Each hive
|
|
occupies its own sub-domain of it, which is why every entry in
|
|
`services.hyperhive.swarm.hives` defaults its `domain` to
|
|
`<name>.<swarm.domain>` — set this plus
|
|
`services.hyperhive.hiveName`, list the hives by name, and no
|
|
hive in the swarm states an address at all.
|
|
|
|
**Required** when
|
|
`services.hyperhive.deploy.hive-controller.enable`, and deliberately
|
|
not defaulted: there is no fallback worth having. A guessed
|
|
swarm domain is a wrong hostname that evaluates cleanly and
|
|
deploys, which is worse than an eval failure telling an
|
|
operator to write down the one address their swarm answers to.
|
|
Upgrading past this costs one line, once.
|
|
'';
|
|
};
|
|
|
|
# Human display name for this hive. Distinct from the DNS domain
|
|
# above (machine-readable) — see docs/process/conventions.md::Hive identity
|
|
# for the domain-vs-name-vs-swarm distinction + the env-var
|
|
# propagation chain. The swarm's display name is
|
|
# `services.hyperhive.swarm.name`, one level out: this hive is named
|
|
# here, the swarm it belongs to is named there.
|
|
options.services.hyperhive.hiveName = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
example = "pr1ma";
|
|
description = ''
|
|
Human-readable name of this single-host hive instance.
|
|
**Required** when this host runs a hive, the swarm's secret store
|
|
or its homeserver
|
|
(`services.hyperhive.deploy.hive-controller.enable`,
|
|
`deploy.bao.enable`, `deploy.matrix.enable`). Distinct from
|
|
`services.hyperhive.domain` (the machine-addressable DNS name)
|
|
but no longer merely cosmetic: a hive occupies
|
|
`<hiveName>.<swarm.domain>`, so this is the label the hive is
|
|
*addressed* by as well as the one it is called. Exposed to
|
|
agents as `HYPERHIVE_HIVE_NAME`; surfaced in the dashboard
|
|
chrome and per-agent system prompt.
|
|
'';
|
|
};
|
|
|
|
# Each of these deployments turns `hiveName` into an identifier with no
|
|
# fallback: hive-c0re's OIDC client and matrix localpart, the CN of the
|
|
# store's `client.pem` (./glue-bao-tls.nix), and the `hives/<name>` path
|
|
# the matrix token and queue credential readers fetch. A null there renders
|
|
# as an empty string that evaluates and deploys.
|
|
config.assertions = [
|
|
{
|
|
assertion =
|
|
!(
|
|
hiveCfg.deploy.hive-controller.enable || hiveCfg.deploy.bao.enable || hiveCfg.deploy.matrix.enable
|
|
)
|
|
|| hiveCfg.hiveName != null;
|
|
message = ''
|
|
hyperhive requires services.hyperhive.hiveName to be set on a host
|
|
that runs a hive, the swarm's secret store or its homeserver — it is
|
|
this hive's label within the swarm, and the leftmost part of the
|
|
domain it is addressed by (`<hiveName>.<swarm.domain>`), not only a
|
|
display name. Set it (`services.hyperhive.hiveName = "pr1ma";`).
|
|
'';
|
|
}
|
|
];
|
|
|
|
# The one hive-level option that describes something ABOVE the hive,
|
|
# which is why it sits under `swarm` with the swarm-global services
|
|
# rather than beside `hiveName`.
|
|
options.services.hyperhive.swarm.name = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
example = "constellat1on";
|
|
description = ''
|
|
Human-readable name of the wider swarm this hive belongs to.
|
|
Hives at different DNS domains can share a swarm name when
|
|
they federate together. Exposed to agents as
|
|
`HYPERHIVE_SWARM_NAME`; surfaced in the dashboard chrome and
|
|
per-agent system prompt when set.
|
|
'';
|
|
};
|
|
|
|
# `singleHostSwarm` 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
|
|
# "scope concept: special agents".
|
|
options.services.hyperhive.ruthless = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
example = true;
|
|
description = ''
|
|
Run this hive "ruthless" — with no root (manager) agent at all (no
|
|
ruth). When `true`, hive-c0re skips the root-agent auto-management
|
|
sweep entirely (it otherwise creates the root agent's container when
|
|
missing and restarts it when present but stopped). Defaults to
|
|
`false` (the root agent is auto-managed as required
|
|
infrastructure). Exposed to hive-c0re as `HYPERHIVE_RUTHLESS`.
|
|
'';
|
|
};
|
|
|
|
options.services.hyperhive.github.enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
example = false;
|
|
description = ''
|
|
Hive-wide switch for the per-agent GitHub integration (the `gh` CLI
|
|
wrapper + git credential helper, per `hyperhive.github.enable`). On by
|
|
default: every agent gets the integration, inert until a PAT is
|
|
provisioned via the dashboard credentials tab or `hivectl github
|
|
set-token`. Set `false` to turn it off for the whole hive --- the
|
|
meta-flake renderer (`hive-c0re/src/meta.rs`) then injects
|
|
`hyperhive.github.enable = false` into every agent. Exposed to hive-c0re
|
|
as `HYPERHIVE_GITHUB_DISABLED` (set only when the integration is off).
|
|
'';
|
|
};
|
|
}
|