From 30a94d35e9d9fc7e518ecd655d4e871a09b59721 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 5 Aug 2026 11:15:41 +0200 Subject: [PATCH 1/2] refactor(nix): move the swarm display name under services.hyperhive.swarm services.hyperhive.swarmName becomes services.hyperhive.swarm.name, with one mkRenamedOptionModule in hyperhive.nix -- the module that declares it, same convention as the forge and matrix renames, so each migration stays independent of its siblings. hiveName deliberately stays where it is. It names this hive; swarm.name names the group the hive belongs to, and that they now sit one level apart is the distinction rather than an inconsistency. The per-agent hyperhive.swarmName is an internal mirror rendered from the host value and does not move, same split as forge and matrix. --- nix/host-modules/hive-c0re/environment.nix | 4 ++-- nix/host-modules/hyperhive.nix | 26 +++++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/nix/host-modules/hive-c0re/environment.nix b/nix/host-modules/hive-c0re/environment.nix index 0a86bbba..03309b30 100644 --- a/nix/host-modules/hive-c0re/environment.nix +++ b/nix/host-modules/hive-c0re/environment.nix @@ -56,8 +56,8 @@ in // lib.optionalAttrs (config.services.hyperhive.hiveName != null) { HYPERHIVE_HIVE_NAME = config.services.hyperhive.hiveName; } -// lib.optionalAttrs (config.services.hyperhive.swarmName != null) { - HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName; +// lib.optionalAttrs (config.services.hyperhive.swarm.name != null) { + HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarm.name; } // lib.optionalAttrs (!config.services.hyperhive.github.enable) { # GitHub integration is on by default; only signal the OFF override to diff --git a/nix/host-modules/hyperhive.nix b/nix/host-modules/hyperhive.nix index 46f7f660..79b40777 100644 --- a/nix/host-modules/hyperhive.nix +++ b/nix/host-modules/hyperhive.nix @@ -7,6 +7,16 @@ ... }: { + # 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" ] + ) + ]; + # Top-level hyperhive enable flag. When true, automatically enables # hive-c0re and the on-by-default hyperhive subsystems. options.services.hyperhive.enable = lib.mkEnableOption "hyperhive — the agent swarm coordinator"; @@ -39,11 +49,12 @@ ''; }; - # Human display names for hive + swarm. Distinct from the DNS - # domain above (machine-readable) — see - # docs/conventions.md::Hive identity for the - # domain-vs-name-vs-swarm distinction + the env-var - # propagation chain. + # Human display name for this hive. Distinct from the DNS domain + # above (machine-readable) — see docs/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; @@ -61,7 +72,10 @@ ''; }; - options.services.hyperhive.swarmName = lib.mkOption { + # 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"; From 1a0cb0fb44e2345d4efae8f2c9f87dad0e964a08 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 5 Aug 2026 11:15:41 +0200 Subject: [PATCH 2/2] docs: name the swarm display name by its new path Two sites spelled it as a brace group, services.hyperhive.{hiveName, swarmName}, which no anchored rewrite can handle correctly now that only one of the two moves; both are written out separately. One of them is an MCP tool description, so it is rendered into every agent's system prompt. --- docs/conventions.md | 2 +- docs/observability.md | 2 +- docs/swarm.md | 10 ++++++---- hive-agent-mcp/src/mcp/mod.rs | 5 +++-- hive-agent/src/identity.rs | 2 +- hive-c0re/src/container_view.rs | 4 +++- hive-c0re/src/dashboard/state_snapshot.rs | 2 +- nix/agent-modules/claude-settings.nix | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/conventions.md b/docs/conventions.md index 894b6f48..a390dbbd 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -297,7 +297,7 @@ status_text, status_set_at, hive_name, swarm_name }`: or when `running = false` (see above). - `hive_name` / `swarm_name`: display names read from `HYPERHIVE_HIVE_NAME` / `HYPERHIVE_SWARM_NAME` env (sourced from - `services.hyperhive.hiveName` / `services.hyperhive.swarmName`). + `services.hyperhive.hiveName` / `services.hyperhive.swarm.name`). Both `None` when the options aren't configured. ### Timestamps on the wire diff --git a/docs/observability.md b/docs/observability.md index 97993735..28350376 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -121,7 +121,7 @@ Every agent's export includes these resource attributes automatically: | `service.name` | `hyperhive-agent` (constant) | | `agent` | agent logical name (e.g. `iris`) | | `hive` | hive display name (`services.hyperhive.hiveName`) | -| `swarm` | swarm display name (`services.hyperhive.swarmName`, if set) | +| `swarm` | swarm display name (`services.hyperhive.swarm.name`, if set) | Additional labels can be appended via `extraResourceAttributes` (see option reference above); custom per-data-point labels can be passed with diff --git a/docs/swarm.md b/docs/swarm.md index 37eeba76..addf88f5 100644 --- a/docs/swarm.md +++ b/docs/swarm.md @@ -20,17 +20,19 @@ the additional config needed when the swarm spans multiple hosts. ```nix services.hyperhive = { domain = "pr1ma.example.com"; # machine-addressable DNS domain - hiveName = "pr1ma"; # human display name (optional) - swarmName = "constellat1on"; # shared swarm display name (optional) + hiveName = "pr1ma"; # human display name (optional) + swarm.name = "constellat1on"; # shared swarm display name (optional) }; ``` `domain` is required when matrix federation is on (`matrix.enable`); it drives `HYPERHIVE_HIVE_DOMAIN` in every container so agents can form qualified labels (`iris@pr1ma.example.com`). `hiveName` and -`swarmName` are purely display — they surface in the dashboard chrome +`swarm.name` are purely display — they surface in the dashboard chrome header and per-agent system prompts. Federated hives at different -domains can share a `swarmName`. +domains can share a `swarm.name`; that it sits under `swarm` and +`hiveName` does not is the whole distinction — one names this hive, the +other names the group it belongs to. See `docs/conventions.md` § Hive identity for the env-var chain and `qualify()` / `qualified_label()` semantics. diff --git a/hive-agent-mcp/src/mcp/mod.rs b/hive-agent-mcp/src/mcp/mod.rs index 83a4bec3..354aa5d2 100644 --- a/hive-agent-mcp/src/mcp/mod.rs +++ b/hive-agent-mcp/src/mcp/mod.rs @@ -437,8 +437,9 @@ impl AgentServer { `status_set_at` are stale pre-stop values and should not be treated as live), \ and the target's self-reported `status` text (set via `set_status`) plus how \ long ago it was set. Also returns the hive + swarm display names (`hive_name`, \ - `swarm_name`) when the operator has configured `services.hyperhive.{hiveName, \ - swarmName}`; both lines omitted when unset. Pass `name` to query a peer (e.g. \ + `swarm_name`) when the operator has configured \ + `services.hyperhive.hiveName` / `services.hyperhive.swarm.name`; both lines \ + omitted when unset. Pass `name` to query a peer (e.g. \ check whether iris is idle before pinging them); omit `name` to get your own \ identity stamp — handy for state files / commit messages / cross-agent \ attribution that won't drift across renames or session-continue boundaries \ diff --git a/hive-agent/src/identity.rs b/hive-agent/src/identity.rs index a136ad48..85c36619 100644 --- a/hive-agent/src/identity.rs +++ b/hive-agent/src/identity.rs @@ -42,7 +42,7 @@ pub fn hive_name() -> Option { /// Human display name of the wider swarm this hive belongs to (e.g. /// `constellat1on`). Federated hives at different DNS domains can /// share a swarm name. Returns None when the host-side -/// `services.hyperhive.swarmName` option is unset. +/// `services.hyperhive.swarm.name` option is unset. #[must_use] pub fn swarm_name() -> Option { non_empty_env("HYPERHIVE_SWARM_NAME") diff --git a/hive-c0re/src/container_view.rs b/hive-c0re/src/container_view.rs index 29fbe451..2c52e624 100644 --- a/hive-c0re/src/container_view.rs +++ b/hive-c0re/src/container_view.rs @@ -268,7 +268,9 @@ fn read_active_model(name: &hive_types::Ident) -> Option { /// Host-side hive + swarm display names, read from the c0re service's /// own process env. The `hive-c0re.nix` module sets these from -/// `services.hyperhive.{hiveName, swarmName}`. The agent-side +/// `services.hyperhive.hiveName` + `services.hyperhive.swarm.name` +/// (the hive names itself; the swarm it joins is named one level out). +/// The agent-side /// `hive-agent::identity::{hive_name, swarm_name}` accessors read the /// same env vars after they're forwarded into each sub-agent's /// harness service environment by `meta::render_flake`; surfacing diff --git a/hive-c0re/src/dashboard/state_snapshot.rs b/hive-c0re/src/dashboard/state_snapshot.rs index df3f486b..66edacbf 100644 --- a/hive-c0re/src/dashboard/state_snapshot.rs +++ b/hive-c0re/src/dashboard/state_snapshot.rs @@ -117,7 +117,7 @@ pub(super) struct StateSnapshot { hive_name: Option, /// Human name of the wider swarm this hive belongs to (e.g. /// `"constellat1on"`). Sourced from `HYPERHIVE_SWARM_NAME` env - /// var, set from `services.hyperhive.swarmName`. `None` when + /// var, set from `services.hyperhive.swarm.name`. `None` when /// unset — chrome omits the swarm segment of the breadcrumb. swarm_name: Option, /// Peer hives in the same swarm. Parsed from `HYPERHIVE_PEERS` diff --git a/nix/agent-modules/claude-settings.nix b/nix/agent-modules/claude-settings.nix index 5070e8e5..26b96ffb 100644 --- a/nix/agent-modules/claude-settings.nix +++ b/nix/agent-modules/claude-settings.nix @@ -243,7 +243,7 @@ in description = '' Human-readable swarm name, rendered per-agent by `meta.rs::render_flake` from the host's - `services.hyperhive.swarmName`. Same build-time/runtime split as + `services.hyperhive.swarm.name`. Same build-time/runtime split as `hyperhive.hiveName`. `null` means the hive is not part of a named swarm.