From 4fa17de387949b08bb66199ed2ab1f60ee5df63d Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 26 Jun 2026 22:23:28 +0200 Subject: [PATCH] feat(#2006): add services.hyperhive.manageRootAgent to opt out of root-agent auto-management --- hive-c0re/src/auto_update.rs | 32 +++++++++++++++++++++++++++----- nix/modules/hive-c0re.nix | 23 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/hive-c0re/src/auto_update.rs b/hive-c0re/src/auto_update.rs index 99f8cbff..af2cb95f 100644 --- a/hive-c0re/src/auto_update.rs +++ b/hive-c0re/src/auto_update.rs @@ -164,12 +164,33 @@ pub async fn rebuild_agent( result } +/// Whether hive-c0re auto-manages the root/manager agent — creating it on +/// startup and restarting it when present-but-stopped. Controlled by the +/// host option `services.hyperhive.manageRootAgent`, threaded in via the +/// `HYPERHIVE_MANAGE_ROOT_AGENT` env var. Defaults to enabled when the +/// var is unset (back-compat: the root agent was always managed before +/// this opt-out existed); only an explicit `false` / `0` / `no` disables. +fn manage_root_agent() -> bool { + match std::env::var("HYPERHIVE_MANAGE_ROOT_AGENT") { + Ok(v) => !matches!(v.trim().to_ascii_lowercase().as_str(), "false" | "0" | "no"), + Err(_) => true, + } +} + /// Auto-create the manager container on startup if it isn't already there. /// hive-c0re manages the manager end-to-end: operators no longer declare /// `containers.h-ruth` in their host NixOS config. Bypasses the approval -/// queue — the root/manager is auto-managed by default (an operator opt-out -/// is a separate host setting). Idempotent. +/// queue — the root/manager is auto-managed by default. Operators who +/// don't want a root agent at all set `services.hyperhive.manageRootAgent +/// = false`, which short-circuits this whole function. Idempotent. pub async fn ensure_root_agent(coord: &Arc) -> Result<()> { + if !manage_root_agent() { + tracing::info!( + "root-agent auto-management disabled (services.hyperhive.manageRootAgent = false) - \ + skipping root agent create/start" + ); + return Ok(()); + } let existing = lifecycle::list().await.unwrap_or_default(); let current_rev = current_flake_rev(&coord.hyperhive_flake); if existing @@ -201,9 +222,10 @@ pub async fn ensure_root_agent(coord: &Arc) -> Result<()> { // install) is brought back up here: the startup sweep's rebuild only // restarts a container that was already running, so without this it // stays down until a manual `nixos-container start`. The sub-agent - // `was_running` guard is intentionally left untouched. (An operator - // opt-out of this whole auto-management is tracked as a separate - // host setting.) + // `was_running` guard is intentionally left untouched. (Operators + // opt out of this whole auto-management with + // `services.hyperhive.manageRootAgent = false`, gated at the top of + // this function.) if !lifecycle::is_running(MANAGER_NAME).await { tracing::info!("manager container present but not running — starting"); if let Err(e) = lifecycle::start(MANAGER_NAME).await { diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index 52e8e07d..2791d7a6 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -187,6 +187,25 @@ in ''; }; + # Whether hive-c0re auto-manages the root/manager agent on startup + # (create it if missing, restart it if present-but-stopped). Some hives + # don't want a root agent auto-managed at all — see issue tracker + # "scope concept: special agents". + options.services.hyperhive.manageRootAgent = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = '' + Whether hive-c0re auto-manages the root (manager) agent on + startup: creating its container when missing and restarting it + when it's present but stopped. Defaults to `true` (the historical + behaviour — the root agent was treated as required infrastructure). + Set to `false` on hives that don't want a root agent at all; + hive-c0re then skips the root-agent create/start sweep entirely. + Exposed to hive-c0re as `HYPERHIVE_MANAGE_ROOT_AGENT`. + ''; + }; + # Hive-wide OTEL stats export. Set ONCE here at host level; the # meta-flake renderer (`hive-c0re/src/meta.rs::otel_config`) reads the # HYPERHIVE_OTEL_* env exported below off hive-c0re's unit and injects @@ -873,6 +892,10 @@ in # prompts). `hive_sh4re::assets::*` reads paths underneath. # `forge.rs` reads the avatar PNGs from here on startup. HIVE_ASSETS_DIR = "${cfg.assets}/share/hyperhive"; + # Whether hive-c0re auto-manages the root/manager agent on + # startup (`auto_update::ensure_root_agent`). Default true = + # historical behaviour; false makes the root-agent sweep a no-op. + HYPERHIVE_MANAGE_ROOT_AGENT = lib.boolToString config.services.hyperhive.manageRootAgent; } // lib.optionalAttrs (config.services.hyperhive.domain != null) { # Identity env vars threaded into c0re's own service env and