diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index 5bf0af7c..f730cf27 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -128,9 +128,11 @@ in options.services.hyperhive.enable = lib.mkEnableOption "hyperhive — the agent swarm coordinator"; # Canonical hive DNS domain shared by every subsystem that needs a - # stable hostname. Nullable + default null so existing configs - # evaluate unchanged; subsystems that need it (matrix) assert - # non-null in their own config block. Full identity-surface + # stable hostname. Typed nullOr (default null) so the option always + # exists, but it's REQUIRED whenever hyperhive is enabled — a config + # assertion (see the `config` block) 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; #2015). Full identity-surface # context (HYPERHIVE_HIVE_DOMAIN / HIVE_NAME / SWARM_NAME env-var # chain → identity.rs → claude prompt): docs/conventions.md:: # Hive identity (label + domain + display names). @@ -143,9 +145,10 @@ in stable name (currently: `services.hyperhive.matrix.serverName` derives from this, defaulting to `matrix.''${services.hyperhive.domain}` when `serverName` is - null). No default — subsystems that opt to require it assert - non-null in their own config and fail eval with a helpful - message if it's missing. Exposed to agents as + null). **Required** when `services.hyperhive.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-ag3nt::identity::hive_domain()` for `@` qualified labels. @@ -828,31 +831,51 @@ in config.services.hyperhive.swarm.wireguard.listenPort ]; - assertions = - lib.optionals config.services.hyperhive.swarm.wireguard.enable [ - { - assertion = config.services.hyperhive.swarm.wireguard.privateKeyFile != null; - message = '' - services.hyperhive.swarm.wireguard.enable requires - services.hyperhive.swarm.wireguard.privateKeyFile to be set. - Generate a key: wg genkey > /etc/wireguard/hive.key - ''; - } - { - assertion = config.services.hyperhive.swarm.wireguard.address != ""; - message = '' - services.hyperhive.swarm.wireguard.enable requires - services.hyperhive.swarm.wireguard.address to be set - (e.g. "10.100.0.1/24"). - ''; - } - ] - ++ lib.optionals config.services.hyperhive.otel.enable [ - { - assertion = config.services.hyperhive.otel.endpoint != ""; - message = "services.hyperhive.otel.enable is true but services.hyperhive.otel.endpoint is empty."; - } - ]; + assertions = [ + { + # `domain` has no safe default: it's baked into the matrix server + # (tuwunnel) on first boot and drives the gateway/forge/agent URLs. + # Under mandatory network isolation agents can only reach the forge + # via `forge.` on the bridge — with no domain there's no + # reachable name (see #2011). Changing it later is destructive + # (deletes Matrix history), so it must be set before first boot. + assertion = config.services.hyperhive.domain != null; + message = '' + services.hyperhive.domain must be set (e.g. "darkest.space"). + It's baked into the matrix server on first boot and into the + gateway / forge / agent URLs, so hyperhive needs a stable domain + and there is no safe default. Agents reach the forge via + forge. on the bridge network, so without it the forge is + unreachable from containers. Changing the domain after first boot + is destructive (deletes Matrix history) — pick it before initial + setup. See docs/gateway.md and docs/matrix.md. + ''; + } + ] + ++ lib.optionals config.services.hyperhive.swarm.wireguard.enable [ + { + assertion = config.services.hyperhive.swarm.wireguard.privateKeyFile != null; + message = '' + services.hyperhive.swarm.wireguard.enable requires + services.hyperhive.swarm.wireguard.privateKeyFile to be set. + Generate a key: wg genkey > /etc/wireguard/hive.key + ''; + } + { + assertion = config.services.hyperhive.swarm.wireguard.address != ""; + message = '' + services.hyperhive.swarm.wireguard.enable requires + services.hyperhive.swarm.wireguard.address to be set + (e.g. "10.100.0.1/24"). + ''; + } + ] + ++ lib.optionals config.services.hyperhive.otel.enable [ + { + assertion = config.services.hyperhive.otel.endpoint != ""; + message = "services.hyperhive.otel.enable is true but services.hyperhive.otel.endpoint is empty."; + } + ]; systemd.services.hive-c0re = { description = "hyperhive coordinator daemon";