diff --git a/docs/tools/hivectl-cli.md b/docs/tools/hivectl-cli.md index d4653290..49b83751 100644 --- a/docs/tools/hivectl-cli.md +++ b/docs/tools/hivectl-cli.md @@ -50,7 +50,7 @@ Sibling to the `hive-c0re` daemon binary. Covers host-side admin operations that * `gateway` — Gateway htpasswd user management. Add, remove, or list users in an htpasswd file used by the gateway's HTTP Basic auth (`services.hyperhive.gateway.auth`). Credentials are stored as `BCrypt` hashes — no extra service or PAM required * `agents` — Agent container management. Requires the hive-c0re daemon to be running (connects to the host admin socket) * `wg` — WireGuard inter-hive mesh setup helpers (`services.hyperhive.swarm`) -* `peer-config` — Generate the federation peer-config block for THIS hive — the nix a peer operator pastes into their `services.hyperhive.swarm.peers` to trust + reach this hive. Emits `caCert` (+ a `cp` line for the cert) when this hive serves a self-signed CA, the WireGuard public key when the mesh key exists, and the `wireguard{Address,Endpoint}` you pass. Reads local state (the TLS CA cert, the wg key) + asks the daemon for this hive's domain; never mutates. `wg init` calls this at the end, so a fresh mesh setup prints the hand-over block too +* `peer-config` — Generate the federation peer-config block for THIS hive — the nix a peer operator pastes into their `services.hyperhive.swarm.peers` to trust + reach this hive. Emits `caCert` (+ a `cp` line for the cert) when this hive serves a self-signed CA, the WireGuard public key when the mesh key exists, and the `wireguard{Address,Endpoint}` you pass. The hive's own domain is filled in automatically from the running daemon (`services.hyperhive.domain`). Reads local state (the TLS CA cert, the wg key); never mutates. `wg init` calls this at the end, so a fresh mesh setup prints the hand-over block too * `choom` — Open an interactive Claude session inside an agent container * `stop` — Stop containers hive-wide in one operator action. Bare `hivectl stop` stops **everything** — all sub-agents plus the ci, forge, gateway, and matrix infra containers. Narrow it with scope flags: `--agents` (all sub-agents), `--ci` / `--forge` / `--gateway` / `--matrix` (named infra), and `--agent ` (repeatable) for specific sub-agents. Flags are additive (e.g. `--agents --matrix`). Requires the hive-c0re daemon (connects to the host admin socket). hive-c0re itself is never stopped — it services the request * `start` — Start containers hive-wide — the inverse of `hivectl stop`. Bare `hivectl start` starts everything back up; the same scope flags as `stop` narrow it (`--agents`, `--ci`, `--forge`, `--gateway`, `--matrix`, `--agent `). Requires the hive-c0re daemon @@ -317,7 +317,6 @@ Generate (if absent) this hive's WireGuard private key, print its public key, an ###### **Options:** * `--address
` — This hive's mesh address (e.g. `10.42.0.1/32`) to bake into the printed snippet. Omit to get a placeholder you fill in -* `--domain ` — This hive's DNS domain. When set, `init` also prints the `peer-config` block peers paste to federate with this hive (CA + this mesh key), so setup is one command. Omit to skip that and just enable the mesh locally @@ -349,13 +348,12 @@ Show the live mesh interface state (`wg show wg-hive`). Requires the mesh to be ## `hivectl peer-config` -Generate the federation peer-config block for THIS hive — the nix a peer operator pastes into their `services.hyperhive.swarm.peers` to trust + reach this hive. Emits `caCert` (+ a `cp` line for the cert) when this hive serves a self-signed CA, the WireGuard public key when the mesh key exists, and the `wireguard{Address,Endpoint}` you pass. Reads local state (the TLS CA cert, the wg key) + asks the daemon for this hive's domain; never mutates. `wg init` calls this at the end, so a fresh mesh setup prints the hand-over block too +Generate the federation peer-config block for THIS hive — the nix a peer operator pastes into their `services.hyperhive.swarm.peers` to trust + reach this hive. Emits `caCert` (+ a `cp` line for the cert) when this hive serves a self-signed CA, the WireGuard public key when the mesh key exists, and the `wireguard{Address,Endpoint}` you pass. The hive's own domain is filled in automatically from the running daemon (`services.hyperhive.domain`). Reads local state (the TLS CA cert, the wg key); never mutates. `wg init` calls this at the end, so a fresh mesh setup prints the hand-over block too **Usage:** `hivectl peer-config [OPTIONS]` ###### **Options:** -* `--domain ` — Override this hive's DNS domain (the `swarm.peers` attrset key the peer declares). Omit to auto-fill from the running daemon (`services.hyperhive.domain`); pass it only when the daemon is down or you're scripting offline * `--wg-address ` — This hive's WireGuard mesh address (e.g. `10.42.0.1/32`), emitted as `wireguardAddress`. Omit when not running the mesh * `--wg-endpoint ` — This hive's public WireGuard endpoint (`host:port`), emitted as `wireguardEndpoint`. Omit when peers dial in / no mesh diff --git a/hive-c0re/src/bin/hivectl.rs b/hive-c0re/src/bin/hivectl.rs index 73677da0..a7c1c25d 100644 --- a/hive-c0re/src/bin/hivectl.rs +++ b/hive-c0re/src/bin/hivectl.rs @@ -94,16 +94,11 @@ enum Cmd { /// to trust + reach this hive. Emits `caCert` (+ a `cp` line for the /// cert) when this hive serves a self-signed CA, the WireGuard public /// key when the mesh key exists, and the `wireguard{Address,Endpoint}` - /// you pass. Reads local state (the TLS CA cert, the wg key) + asks the - /// daemon for this hive's domain; never mutates. `wg init` calls this - /// at the end, so a fresh mesh setup prints the hand-over block too. + /// you pass. The hive's own domain is filled in automatically from the + /// running daemon (`services.hyperhive.domain`). Reads local state (the + /// TLS CA cert, the wg key); never mutates. `wg init` calls this at the + /// end, so a fresh mesh setup prints the hand-over block too. PeerConfig { - /// Override this hive's DNS domain (the `swarm.peers` attrset key - /// the peer declares). Omit to auto-fill from the running daemon - /// (`services.hyperhive.domain`); pass it only when the daemon is - /// down or you're scripting offline. - #[arg(long)] - domain: Option, /// This hive's WireGuard mesh address (e.g. `10.42.0.1/32`), /// emitted as `wireguardAddress`. Omit when not running the mesh. #[arg(long)] @@ -453,12 +448,6 @@ enum WgCmd { /// printed snippet. Omit to get a placeholder you fill in. #[arg(long)] address: Option, - /// This hive's DNS domain. When set, `init` also prints the - /// `peer-config` block peers paste to federate with this hive - /// (CA + this mesh key), so setup is one command. Omit to skip - /// that and just enable the mesh locally. - #[arg(long)] - domain: Option, }, /// Print the nix snippet to add a peer hive to the mesh. Pure output — /// paste it into this hive's config. Get `` from the peer's @@ -592,9 +581,7 @@ async fn main() -> Result<()> { AgentsCmd::RestartAll => agents_restart_all(&socket).await, }, Cmd::Wg { cmd } => match cmd { - WgCmd::Init { address, domain } => { - wg_init(&socket, address.as_deref(), domain.as_deref()).await - } + WgCmd::Init { address } => wg_init(&socket, address.as_deref()).await, WgCmd::Peer { domain, pubkey, @@ -607,11 +594,10 @@ async fn main() -> Result<()> { WgCmd::Status => wg_status(), }, Cmd::PeerConfig { - domain, wg_address, wg_endpoint, } => { - let domain = resolve_hive_domain(&socket, domain).await?; + let domain = require_hive_domain(&socket).await?; peer_config(&domain, wg_address.as_deref(), wg_endpoint.as_deref()); Ok(()) } @@ -671,27 +657,23 @@ async fn query_hive_domain(socket: &Path) -> Option { .and_then(|r| r.domain) } -/// Resolve this hive's domain for snippet generation: the explicit -/// `--domain` override if given, else the daemon. Errors with a clear -/// hint when neither is available, so `peer-config` never silently emits -/// a wrong key. -async fn resolve_hive_domain(socket: &Path, over: Option) -> Result { - if let Some(d) = over { - return Ok(d); - } +/// Require this hive's domain from the daemon for snippet generation. +/// Errors with a clear hint when it can't be resolved, so `peer-config` +/// never silently emits a wrong key. +async fn require_hive_domain(socket: &Path) -> Result { query_hive_domain(socket).await.context( "could not determine this hive's domain from the daemon — is hive-c0re running \ - and `services.hyperhive.domain` set? pass --domain to override", + and `services.hyperhive.domain` set?", ) } /// `wg init` — generate (if absent) the hive's WireGuard key, print its /// public key + the nix snippet to enable the mesh, then (best-effort) /// the `peer-config` block peers paste to federate with this hive, so a -/// fresh setup is one command. The domain comes from `--domain` or the -/// daemon; if neither resolves, the peer block is skipped (init still -/// succeeds — its core job is enabling the mesh locally). -async fn wg_init(socket: &Path, address: Option<&str>, domain: Option<&str>) -> Result<()> { +/// fresh setup is one command. The domain comes from the daemon; if it +/// can't be resolved, the peer block is skipped (init still succeeds — +/// its core job is enabling the mesh locally). +async fn wg_init(socket: &Path, address: Option<&str>) -> Result<()> { use std::os::unix::fs::PermissionsExt as _; let key_path = Path::new(WG_KEY_PATH); if key_path.exists() { @@ -736,13 +718,9 @@ async fn wg_init(socket: &Path, address: Option<&str>, domain: Option<&str>) -> println!(" }};"); // Also print the block a peer pastes to federate with us (CA + this - // mesh key) — one-stop setup. Domain from --domain or the daemon; - // best-effort, so init still succeeds when neither resolves. - let resolved = match domain { - Some(d) => Some(d.to_owned()), - None => query_hive_domain(socket).await, - }; - if let Some(d) = resolved { + // mesh key) — one-stop setup. Domain comes from the daemon; + // best-effort, so init still succeeds when it can't be resolved. + if let Some(d) = query_hive_domain(socket).await { println!(); peer_config(&d, address, None); }