diff --git a/hive-ag3nt/src/identity.rs b/hive-ag3nt/src/identity.rs index 97f511df..1145ff8b 100644 --- a/hive-ag3nt/src/identity.rs +++ b/hive-ag3nt/src/identity.rs @@ -48,25 +48,6 @@ pub fn swarm_name() -> Option { .filter(|s| !s.is_empty()) } -/// One peer hive in the same swarm. Parsed from `HYPERHIVE_PEERS`. -#[derive(Debug, Clone, serde::Deserialize)] -pub struct PeerHive { - pub label: String, - pub domain: String, -} - -/// Peer hives in the same swarm, parsed from `HYPERHIVE_PEERS` env var -/// (JSON array of `{label,domain}` objects, emitted by the c0re NixOS -/// module from `services.hyperhive.peers`). Returns empty vec on -/// single-hive deploys (env var absent). -#[must_use] -pub fn peers() -> Vec { - env::var("HYPERHIVE_PEERS") - .ok() - .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_default() -} - /// Hive-qualified agent identity. When the hive domain is configured, returns /// `${label}@${domain}` (e.g. `iris@darkest.space`); when not, returns just /// the short label so callers can render a single string regardless of diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index 7192d64a..690a2373 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -266,24 +266,6 @@ struct StateSnapshot { /// var, set from `services.hyperhive.swarmName`. `None` when /// unset — chrome omits the swarm segment of the breadcrumb. swarm_name: Option, - /// Peer hives in the same swarm. Parsed from `HYPERHIVE_PEERS` - /// (JSON array of `{label,domain}` objects, emitted by the c0re - /// NixOS module from `services.hyperhive.peers`). Empty on - /// single-hive deploys. Feeds the P33RS dashboard tab. Each entry - /// exposes `name` (the operator-chosen label) and `url` (dashboard - /// link derived as `http:///`; HTTP-only until the gateway - /// has TLS and the scheme is threaded through). - peer_hives: Vec, -} - -/// One peer hive for the P33RS dashboard tab. Derived from -/// `HYPERHIVE_PEERS` env; `url` is the peer's dashboard root so the -/// tab can render a clickable card without knowing the remote port. -/// HTTP-only until per-peer TLS is wired through the gateway layer. -#[derive(Serialize)] -struct PeerHiveView { - name: String, - url: String, } /// `OpQuestion` + computed `question_refs` / `answer_refs`. Built @@ -493,36 +475,9 @@ async fn api_state(headers: HeaderMap, State(state): State) -> axum::J forge_public_url: std::env::var("HIVE_FORGE_PUBLIC_URL").ok().filter(|s| !s.is_empty()), hive_name: std::env::var("HYPERHIVE_HIVE_NAME").ok().filter(|s| !s.is_empty()), swarm_name: std::env::var("HYPERHIVE_SWARM_NAME").ok().filter(|s| !s.is_empty()), - peer_hives: parse_peer_hives(), }) } -/// Parse `HYPERHIVE_PEERS` env var into dashboard-ready `PeerHiveView` -/// entries. The env var is a JSON array of `{label, domain}` objects -/// emitted by the c0re NixOS module from `services.hyperhive.peers`. -/// Each entry becomes `{ name: label, url: "http://domain/" }` for the -/// P33RS tab. Returns empty vec when unset (single-hive deploy). -fn parse_peer_hives() -> Vec { - #[derive(serde::Deserialize)] - struct Raw { - label: String, - domain: String, - } - let Ok(json) = std::env::var("HYPERHIVE_PEERS") else { - return Vec::new(); - }; - let Ok(raw): Result, _> = serde_json::from_str(&json) else { - tracing::warn!("HYPERHIVE_PEERS is not valid JSON; ignoring"); - return Vec::new(); - }; - raw.into_iter() - .map(|r| PeerHiveView { - name: r.label, - url: format!("http://{}/", r.domain), - }) - .collect() -} - /// Group live containers by their assigned web UI port; clusters with /// more than one member are port-hash collisions the operator needs /// to resolve by renaming. Manager (fixed at 8000) and sub-agents diff --git a/hive-c0re/src/meta.rs b/hive-c0re/src/meta.rs index a9d013b7..15660350 100644 --- a/hive-c0re/src/meta.rs +++ b/hive-c0re/src/meta.rs @@ -325,8 +325,6 @@ const CANONICAL_INPUTS: &[&str] = &["nixpkgs", "nixpkgs-unstable"]; /// touching process-wide env). const FORWARDED_VARS: &[&str] = &[ "HIVE_FORGE_URL", - "HIVE_FORGE_PUBLIC_URL", - "HYPERHIVE_PEERS", "HYPERHIVE_HIVE_DOMAIN", "HYPERHIVE_HIVE_NAME", "HYPERHIVE_SWARM_NAME", diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index 8de18a11..c8a98dd3 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -53,7 +53,7 @@ in message if it's missing. Exposed to agents as `HYPERHIVE_HIVE_DOMAIN`; consumed by `hive-ag3nt::identity::hive_domain()` for `@` - qualified labels. + qualified labels (#589). ''; }; @@ -86,57 +86,12 @@ in 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 + they federate together (#589). Exposed to agents as `HYPERHIVE_SWARM_NAME`; surfaced in the dashboard chrome and per-agent system prompt when set. ''; }; - # Peer hives in the same swarm. Each entry declares a remote hive - # reachable from this host. Serialised to JSON and injected as - # `HYPERHIVE_PEERS` into the hive-c0re service and forwarded to agent - # containers via `meta.rs::FORWARDED_VARS`. Consumed by - # `identity.rs::peers()` + the dashboard's `peer_hives` state field - # (feeds the P33RS dashboard tab). - options.services.hyperhive.peers = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule { - options = { - domain = lib.mkOption { - type = lib.types.str; - example = "lab.example.com"; - description = '' - DNS domain of the peer hive. Used to construct the peer's - dashboard URL (`http://''${domain}/`) and for Matrix - federation auto-discovery (`matrix.''${domain}`). - Must be reachable from this host. - ''; - }; - tlsCertFile = lib.mkOption { - type = lib.types.nullOr lib.types.path; - default = null; - description = '' - Optional path to a PEM cert/bundle to trust for this peer's - TLS. Null = system CA bundle (for Let's Encrypt peers). Set - to the peer's self-signed cert for `selfSignedTls = true` - peers. Forward-compat slot; not yet used in v0. - ''; - }; - }; - }); - default = { }; - example = { - lab = { domain = "lab.example.com"; }; - edge = { domain = "edge.corp"; }; - }; - description = '' - Peer hives in the same swarm. The attrset key is a short label - used in dashboard links and log messages -- it does not need to - match the remote hive's `hiveName`. Null `tlsCertFile` uses the - system CA bundle; set it for self-signed TLS peers (forward-compat - slot, not yet used in v0). - ''; - }; - options.services.hyperhive.c0re = { enable = lib.mkOption { type = lib.types.bool; @@ -354,16 +309,6 @@ in # wrong). Absent when `behindGateway = false` — dashboard # falls back to `:3000`. HIVE_FORGE_PUBLIC_URL = "https://${config.services.hyperhive.forge.domain}"; - } - // lib.optionalAttrs (config.services.hyperhive.peers != { }) { - # Peer hives serialised as a JSON array of {label, domain} objects. - # Consumed by hive-ag3nt::identity::peers() + the dashboard's - # peer_hives StateSnapshot field (P33RS tab). tlsCertFile is - # nix-side-only (host nginx/trust config); rust never needs the path. - HYPERHIVE_PEERS = builtins.toJSON ( - lib.mapAttrsToList (label: p: { inherit label; inherit (p) domain; }) - config.services.hyperhive.peers - ); }; serviceConfig = { ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --hyperhive-flake ${cfg.hyperhiveFlake} --dashboard-port ${toString cfg.dashboardPort} --operator-pronouns ${lib.escapeShellArg cfg.operatorPronouns} --context-window-tokens ${lib.escapeShellArg (builtins.toJSON cfg.contextWindowTokens)}";