Compare commits

..
Author SHA1 Message Date
atlas
1a0cb0fb44 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.
2026-08-05 11:15:41 +02:00
atlas
30a94d35e9 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.
2026-08-05 11:15:41 +02:00
10 changed files with 39 additions and 20 deletions

View file

@ -297,7 +297,7 @@ status_text, status_set_at, hive_name, swarm_name }`:
or when `running = false` (see above). or when `running = false` (see above).
- `hive_name` / `swarm_name`: display names read from - `hive_name` / `swarm_name`: display names read from
`HYPERHIVE_HIVE_NAME` / `HYPERHIVE_SWARM_NAME` env (sourced 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. Both `None` when the options aren't configured.
### Timestamps on the wire ### Timestamps on the wire

View file

@ -121,7 +121,7 @@ Every agent's export includes these resource attributes automatically:
| `service.name` | `hyperhive-agent` (constant) | | `service.name` | `hyperhive-agent` (constant) |
| `agent` | agent logical name (e.g. `iris`) | | `agent` | agent logical name (e.g. `iris`) |
| `hive` | hive display name (`services.hyperhive.hiveName`) | | `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 Additional labels can be appended via `extraResourceAttributes` (see option
reference above); custom per-data-point labels can be passed with reference above); custom per-data-point labels can be passed with

View file

@ -20,17 +20,19 @@ the additional config needed when the swarm spans multiple hosts.
```nix ```nix
services.hyperhive = { services.hyperhive = {
domain = "pr1ma.example.com"; # machine-addressable DNS domain domain = "pr1ma.example.com"; # machine-addressable DNS domain
hiveName = "pr1ma"; # human display name (optional) hiveName = "pr1ma"; # human display name (optional)
swarmName = "constellat1on"; # shared swarm display name (optional) swarm.name = "constellat1on"; # shared swarm display name (optional)
}; };
``` ```
`domain` is required when matrix federation is on (`matrix.enable`); `domain` is required when matrix federation is on (`matrix.enable`);
it drives `HYPERHIVE_HIVE_DOMAIN` in every container so agents can it drives `HYPERHIVE_HIVE_DOMAIN` in every container so agents can
form qualified labels (`iris@pr1ma.example.com`). `hiveName` and 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 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 See `docs/conventions.md` § Hive identity for the env-var chain
and `qualify()` / `qualified_label()` semantics. and `qualify()` / `qualified_label()` semantics.

View file

@ -437,8 +437,9 @@ impl AgentServer {
`status_set_at` are stale pre-stop values and should not be treated as live), \ `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 \ 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`, \ long ago it was set. Also returns the hive + swarm display names (`hive_name`, \
`swarm_name`) when the operator has configured `services.hyperhive.{hiveName, \ `swarm_name`) when the operator has configured \
swarmName}`; both lines omitted when unset. Pass `name` to query a peer (e.g. \ `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 \ check whether iris is idle before pinging them); omit `name` to get your own \
identity stamp handy for state files / commit messages / cross-agent \ identity stamp handy for state files / commit messages / cross-agent \
attribution that won't drift across renames or session-continue boundaries \ attribution that won't drift across renames or session-continue boundaries \

View file

@ -42,7 +42,7 @@ pub fn hive_name() -> Option<String> {
/// Human display name of the wider swarm this hive belongs to (e.g. /// Human display name of the wider swarm this hive belongs to (e.g.
/// `constellat1on`). Federated hives at different DNS domains can /// `constellat1on`). Federated hives at different DNS domains can
/// share a swarm name. Returns None when the host-side /// 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] #[must_use]
pub fn swarm_name() -> Option<String> { pub fn swarm_name() -> Option<String> {
non_empty_env("HYPERHIVE_SWARM_NAME") non_empty_env("HYPERHIVE_SWARM_NAME")

View file

@ -268,7 +268,9 @@ fn read_active_model(name: &hive_types::Ident) -> Option<String> {
/// Host-side hive + swarm display names, read from the c0re service's /// Host-side hive + swarm display names, read from the c0re service's
/// own process env. The `hive-c0re.nix` module sets these from /// 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 /// `hive-agent::identity::{hive_name, swarm_name}` accessors read the
/// same env vars after they're forwarded into each sub-agent's /// same env vars after they're forwarded into each sub-agent's
/// harness service environment by `meta::render_flake`; surfacing /// harness service environment by `meta::render_flake`; surfacing

View file

@ -117,7 +117,7 @@ pub(super) struct StateSnapshot {
hive_name: Option<String>, hive_name: Option<String>,
/// Human name of the wider swarm this hive belongs to (e.g. /// Human name of the wider swarm this hive belongs to (e.g.
/// `"constellat1on"`). Sourced from `HYPERHIVE_SWARM_NAME` env /// `"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. /// unset — chrome omits the swarm segment of the breadcrumb.
swarm_name: Option<String>, swarm_name: Option<String>,
/// Peer hives in the same swarm. Parsed from `HYPERHIVE_PEERS` /// Peer hives in the same swarm. Parsed from `HYPERHIVE_PEERS`

View file

@ -243,7 +243,7 @@ in
description = '' description = ''
Human-readable swarm name, rendered per-agent by Human-readable swarm name, rendered per-agent by
`meta.rs::render_flake` from the host's `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`. `hyperhive.hiveName`.
`null` means the hive is not part of a named swarm. `null` means the hive is not part of a named swarm.

View file

@ -56,8 +56,8 @@ in
// lib.optionalAttrs (config.services.hyperhive.hiveName != null) { // lib.optionalAttrs (config.services.hyperhive.hiveName != null) {
HYPERHIVE_HIVE_NAME = config.services.hyperhive.hiveName; HYPERHIVE_HIVE_NAME = config.services.hyperhive.hiveName;
} }
// lib.optionalAttrs (config.services.hyperhive.swarmName != null) { // lib.optionalAttrs (config.services.hyperhive.swarm.name != null) {
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName; HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarm.name;
} }
// lib.optionalAttrs (!config.services.hyperhive.github.enable) { // lib.optionalAttrs (!config.services.hyperhive.github.enable) {
# GitHub integration is on by default; only signal the OFF override to # GitHub integration is on by default; only signal the OFF override to

View file

@ -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 # Top-level hyperhive enable flag. When true, automatically enables
# hive-c0re and the on-by-default hyperhive subsystems. # hive-c0re and the on-by-default hyperhive subsystems.
options.services.hyperhive.enable = lib.mkEnableOption "hyperhive the agent swarm coordinator"; 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 # Human display name for this hive. Distinct from the DNS domain
# domain above (machine-readable) — see # above (machine-readable) — see docs/conventions.md::Hive identity
# docs/conventions.md::Hive identity for the # for the domain-vs-name-vs-swarm distinction + the env-var
# domain-vs-name-vs-swarm distinction + the env-var # propagation chain. The swarm's display name is
# propagation chain. # `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 { options.services.hyperhive.hiveName = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr lib.types.str;
default = null; 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; type = lib.types.nullOr lib.types.str;
default = null; default = null;
example = "constellat1on"; example = "constellat1on";