keep hivectl verb help concise: short about + terse long help (#2512)

This commit is contained in:
damocles 2026-07-15 23:27:25 +02:00 committed by mara
commit 30e48d202b
2 changed files with 219 additions and 306 deletions

View file

@ -53,77 +53,67 @@ struct Cli {
#[derive(Subcommand)]
enum Cmd {
/// Forgejo user provisioning. Manual entry point to the same
/// idempotent flow c0re runs automatically at boot
/// (`forge::ensure_all`) — useful for recovery, ad-hoc reprovisioning,
/// or single-agent fixes without bouncing the daemon.
/// Forgejo user provisioning.
///
/// Manual entry point to the same idempotent provisioning c0re runs at
/// boot — for recovery, ad-hoc reprovisioning, or fixing one agent
/// without bouncing the daemon.
Forge {
#[command(subcommand)]
cmd: ForgeCmd,
},
/// matrix-tuwunel user provisioning. Manual entry point to the same
/// idempotent flow c0re runs automatically at boot
/// (`matrix::ensure_all`) — useful when the boot-time sweep skipped
/// an agent (e.g. matrix container wasn't up yet) or to re-register
/// after wiping a token file.
/// matrix-tuwunel user provisioning.
///
/// Manual entry point to the same idempotent provisioning c0re runs at
/// boot — for re-registering an agent the boot sweep skipped, or after
/// wiping a token file.
Matrix {
#[command(subcommand)]
cmd: MatrixCmd,
},
/// GitHub account provisioning: write an operator-supplied personal
/// access token (PAT) into an agent's `github-token` state file so its
/// `gh` wrapper + git credential helper can authenticate. Unlike
/// forge/matrix there is no account creation — the operator supplies a
/// PAT for an existing GitHub account. A CLI alternative to the dashboard
/// credentials tab; the integration is on by default
/// (`hyperhive.github.enable`), so no per-agent config is needed.
/// GitHub account provisioning.
///
/// Store an operator-supplied personal access token (PAT) for an agent
/// so its `gh` and git can authenticate. No account is created — the
/// PAT is for an existing GitHub account.
Github {
#[command(subcommand)]
cmd: GithubCmd,
},
/// 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.
/// Gateway htpasswd user management.
///
/// Add, remove, or list users for the gateway's HTTP Basic auth.
Gateway {
#[command(subcommand)]
cmd: GatewayCmd,
},
/// Agent container management. Requires the hive-c0re daemon to be
/// running (connects to the host admin socket).
/// Agent container management.
///
/// Lifecycle actions on managed agent containers. Needs the hive-c0re
/// daemon running.
Agents {
#[command(subcommand)]
cmd: AgentsCmd,
},
/// Operator approval queue: list pending requests, approve / deny them.
/// Requires the hive-c0re daemon to be running (connects to the host
/// admin socket).
/// Operator approval queue: list, approve, or deny pending requests.
///
/// Needs the hive-c0re daemon running.
Approvals {
#[command(subcommand)]
cmd: ApprovalsCmd,
},
/// WireGuard inter-hive mesh setup helpers (`services.hyperhive.swarm`).
/// WireGuard inter-hive mesh setup helpers.
///
/// One-time-setup convenience so nobody has to remember the `wg` dance:
/// `wg init` generates + stores this hive's private key and prints the
/// public key plus the nix snippet to enable the mesh; `wg peer` prints
/// the snippet to add a remote hive; `wg status` wraps `wg show`. The
/// verbs own the imperative state (the key file); the printed nix goes
/// into the operator's host config (kept in git), so nothing here mutates
/// declarative config behind the operator's back.
/// Generate this hive's mesh key and print the nix to enable the mesh,
/// add a peer, or inspect live interface state.
Wg {
#[command(subcommand)]
cmd: WgCmd,
},
/// 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.
/// Generate the federation peer-config block for THIS hive.
///
/// Prints the nix a peer operator pastes into their swarm config to
/// trust and reach this hive.
PeerConfig {
/// This hive's WireGuard mesh address (e.g. `10.42.0.1/32`),
/// emitted as `wireguardAddress`. Omit when not running the mesh.
@ -136,11 +126,8 @@ enum Cmd {
},
/// Open an interactive Claude session inside an agent container.
///
/// Runs claude as the agent user from its state dir with the harness's
/// settings / MCP / system prompt. Bare `choom <name>` is a fresh
/// session; `--resume <session-id>` rejoins a prior one. Never
/// collides with the harness's live session. Requires root + a running
/// container. See `docs/tools/hivectl.md` (Choom) for details.
/// A fresh session by default, or resume a prior one. Requires root
/// and a running container.
Choom {
/// Agent name (e.g. `damocles`, `iris`).
name: String,
@ -153,14 +140,10 @@ enum Cmd {
#[arg(long = "resume", value_name = "SESSION")]
resume_session: Option<String>,
},
/// 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 <name>` (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.
/// Stop containers hive-wide in one operator action.
///
/// Bare `hivectl stop` stops everything; scope flags narrow it to
/// specific sub-agents or infra containers.
Stop {
#[command(flatten)]
scope: ScopeArgs,
@ -177,13 +160,11 @@ enum Cmd {
#[arg(long)]
no_wait: bool,
},
/// Start containers hive-wide — the inverse of `hivectl stop`. Bare
/// `hivectl start` restores the previously-running agents from the
/// last broad-scope `stop`, or starts everything if no prior stop
/// exists; the same scope flags as `stop` narrow it (`--agents`,
/// `--ci`, `--forge`, `--gateway`, `--matrix`, `--agent <name>`). A
/// targeted `--agent <name>` start is never filtered. Requires the
/// hive-c0re daemon.
/// Start containers hive-wide — the inverse of `hivectl stop`.
///
/// Bare `hivectl start` restores the agents stopped by the last
/// broad-scope `stop` (or starts everything if none); scope flags
/// narrow it.
Start {
#[command(flatten)]
scope: ScopeArgs,
@ -192,13 +173,9 @@ enum Cmd {
#[arg(long)]
no_wait: bool,
},
/// Restart containers hive-wide — `stop` then `start` over the same
/// scope. Bare `hivectl restart` restarts **everything** (all sub-agents
/// plus the ci/forge/gateway/matrix infra containers); the same scope
/// flags as `stop`/`start` narrow it (`--agents`, `--ci`, `--forge`,
/// `--gateway`, `--matrix`, `--agent <name>`). If the stop phase reports
/// a failure the start phase is skipped so the operator can investigate.
/// Requires the hive-c0re daemon.
/// Restart containers hive-wide — `stop` then `start` over one scope.
///
/// Bare `hivectl restart` restarts everything; scope flags narrow it.
Restart {
#[command(flatten)]
scope: ScopeArgs,
@ -209,36 +186,24 @@ enum Cmd {
},
/// Per-agent disk accounting + optional quotas via btrfs qgroups.
///
/// Opt-in: `quota enable` turns on btrfs qgroup accounting for the
/// agent-state filesystem (a one-time, I/O-heavy rescan — that's why
/// it isn't automatic). Then `quota show` reports per-agent usage and
/// `quota limit` caps an agent. No-op on non-btrfs hosts. Operates on
/// agent state subvolumes (created by the btrfs-subvolume migration);
/// agents still on a plain dir report no qgroup usage.
/// Opt-in: enable qgroup accounting, then report per-agent usage or
/// cap an agent. No-op on non-btrfs hosts.
Quota {
#[command(subcommand)]
cmd: QuotaCmd,
},
/// btrfs subvolume management for agent state dirs.
///
/// New agents get a btrfs subvolume state root automatically (when the
/// host FS is btrfs); agents that predate that are left on plain dirs.
/// `subvol upgrade <agent>` opts an existing plain-dir agent into the
/// subvolume feature set (snapshots, per-subvol usage/quota, migration)
/// by migrating its state dir in place. Requires the hive-c0re daemon
/// (for the stop/start) and root (for the privileged migration).
/// Upgrade an existing plain-dir agent's state into a btrfs subvolume
/// so it gains snapshots and per-subvol usage/quota.
Subvol {
#[command(subcommand)]
cmd: SubvolCmd,
},
/// Print (and best-effort open in a browser) a hive web surface URL.
///
/// Resolves the URL from the running daemon (`HostRequest::Urls`), so
/// custom forge / matrix domains work without guessing `forge.<domain>`.
/// Prints the URL unconditionally — the reliable core, since the host
/// is usually headless / driven over SSH where `xdg-open` is a no-op —
/// then tries `xdg-open` as a convenience. Bare `hivectl open` opens the
/// operator dashboard.
/// Resolves the URL from the running daemon so custom forge / matrix
/// domains work. Bare `hivectl open` opens the operator dashboard.
Open {
/// Which surface to open. Defaults to the operator dashboard.
#[arg(value_enum, default_value_t = OpenTarget::Home)]
@ -246,21 +211,16 @@ enum Cmd {
},
/// Emit the full CLI reference as `CommonMark` to stdout.
///
/// Hidden tooling command (not part of day-to-day operator admin):
/// walks this binary's own clap command tree and renders every verb,
/// flag, and help string as markdown. Used by the docs build to keep
/// the published `hivectl` reference in lockstep with the code — no
/// hand-maintained command list to drift out of date.
/// Hidden tooling command used by the docs build to keep the published
/// `hivectl` reference in lockstep with the code.
#[command(hide = true)]
MarkdownDocs,
/// Generate a shell completion script for `hivectl` and print it to
/// stdout.
///
/// Pipe it into your shell's completion path — e.g. for zsh:
/// `hivectl completions zsh > ~/.zsh/completions/_hivectl` (with that
/// dir on `$fpath`). The hyperhive NixOS module installs the zsh script
/// system-wide automatically, so this is mainly for ad-hoc / other-shell
/// use. Supports bash, zsh, fish, elvish, and powershell.
/// Supports bash, zsh, fish, elvish, and powershell. The NixOS module
/// already installs the zsh script system-wide; this is for ad-hoc or
/// other-shell use.
Completions {
/// Shell to emit completions for.
shell: clap_complete::Shell,
@ -325,24 +285,9 @@ impl ScopeArgs {
enum ForgeCmd {
/// Create or refresh the Forgejo account + token for `<name>`.
///
/// When `<name>` matches an existing agent (i.e. it has a state
/// dir under `/var/lib/hyperhive/agents/`), persists the token to
/// `<state>/forge-token` (idempotent: re-mints + rewrites every
/// call so the on-disk scope matches the current
/// `forge::TOKEN_SCOPES`).
///
/// When `<name>` is **not** an agent (a human or any other
/// non-container account), creates the forgejo user and prints the
/// freshly-minted token to stdout — no `/var/lib/hyperhive/agents/`
/// directory is created for the user.
///
/// Without `--password` / `--password-stdin` a random throwaway is
/// used (fine for agents — they auth by token via tea / hive-forge).
/// Set a password to log into the forge web UI afterwards.
/// `--password` is idempotent: re-running with the same value sets
/// the same password (covers password resets on already-created
/// accounts since `forgejo admin user create` silently no-ops once
/// the user exists).
/// For an existing agent, persists the token to its state dir; for a
/// human/other account, prints the token to stdout. Set a password to
/// enable forge web-UI login (a random throwaway is used otherwise).
CreateUser {
/// Forgejo username. For agents: the container/agent name
/// (`<n>` in `h-<n>`; manager uses the literal `manager`).
@ -368,20 +313,10 @@ enum ForgeCmd {
enum MatrixCmd {
/// Create or refresh the matrix account + access token for `<name>`.
///
/// When `<name>` matches an existing agent (i.e. it has a state
/// dir under `/var/lib/hyperhive/agents/`), persists the token to
/// `<state>/matrix-token`. Skips registration when the file is
/// already populated; delete it to force re-registration.
///
/// When `<name>` is **not** an agent (a human or any other
/// non-container account), registers the matrix user and prints
/// the freshly-minted access token to stdout — no
/// `/var/lib/hyperhive/agents/` directory is created for the user.
///
/// Without `--password` / `--password-stdin` a random throwaway is
/// used (fine for agents — they auth by `access_token`, never by
/// password). Set a password to log into a matrix web client
/// afterwards.
/// For an existing agent, persists the token to its state dir; for a
/// human/other account, prints the access token to stdout. Set a
/// password to enable matrix web-client login (a random throwaway is
/// used otherwise).
CreateUser {
/// Matrix localpart. For agents: the container/agent name.
/// For humans: any matrix localpart — `mara`, `damocles`, etc.
@ -400,34 +335,25 @@ enum MatrixCmd {
#[arg(long, conflicts_with = "password")]
password_stdin: bool,
},
/// Provision (or re-provision) the hive system admin matrix account
/// (`@hive:<server>`). hive-c0re runs this automatically on startup
/// before the agent sweep so the account is the first registered
/// user — Conduit/tuwunel grants admin rights to the first user.
/// Run manually to recover a missing admin token file.
/// Provision (or re-provision) the hive system admin matrix account.
///
/// Runs automatically on startup; run manually to recover a missing
/// admin token.
SyncAdmin,
/// Promote a matrix user to homeserver admin via the admin API.
/// Uses the hive system admin token at
/// `/var/lib/hyperhive/matrix/admin-token`. The `server_name` is
/// discovered automatically from the running homeserver.
/// Promote a matrix user to homeserver admin.
PromoteUser {
/// Matrix localpart of the user to promote (e.g. `argus`).
name: String,
},
/// Reset a matrix user's password via the admin API and persist the
/// new password to `/var/lib/hyperhive/matrix/creds/<name>-password`
/// so the next `ensure_user_for` (or `create-user`) can re-login.
/// Reset a matrix user's password via the admin API.
///
/// After this command succeeds, run `hivectl matrix create-user
/// <name>` to mint a fresh access token for the agent.
/// Persists the new password so a later `create-user` can re-login.
ResetPassword {
/// Matrix localpart of the account to reset (e.g. `argus`).
name: String,
},
/// Invite a matrix user to the hive Space (default) or a specific
/// room. Uses the hive admin token; the admin account must be a
/// member of the target room with invite power (it owns the hive
/// Space). Idempotent — already-member / already-invited is a no-op.
/// Invite a matrix user to the hive Space, or a specific room with
/// `--room`. Idempotent.
Invite {
/// User to invite: a full id (`@mara:server`) or a bare
/// localpart (qualified with the homeserver's `server_name`).
@ -441,13 +367,11 @@ enum MatrixCmd {
#[derive(Subcommand)]
enum GithubCmd {
/// Write a GitHub PAT into `<agent>`'s state dir (`github-token`, 0600,
/// agent-owned) via hive-priv. The GitHub integration is on by default
/// (`hyperhive.github.enable`), so the `gh` wrapper + git credential
/// helper pick the token up with no per-agent config. The token is read
/// live at invocation, so no rebuild/restart is needed. Prefer
/// `--token-stdin`: an inline `--token` is visible in shell history +
/// process listings.
/// Store a GitHub PAT for `<agent>` so its `gh` and git can
/// authenticate.
///
/// Prefer `--token-stdin` — an inline `--token` is visible in shell
/// history.
SetToken {
/// Logical agent name (the container/agent name).
agent: String,
@ -463,13 +387,10 @@ enum GithubCmd {
#[derive(Subcommand)]
enum GatewayCmd {
/// Add a new user or update the password of an existing user in the
/// gateway htpasswd file. The daemon bcrypt-hashes the password (cost 12)
/// and writes the credential store — hivectl relays over the host socket
/// and never touches the file.
/// Add a user or update an existing user's password in the gateway
/// htpasswd.
///
/// Pass `--password-stdin` when scripting or when you don't want the
/// password visible in shell history.
/// Use `--password-stdin` to keep the password out of shell history.
CreateUser {
/// Username to add or update.
username: String,
@ -483,8 +404,7 @@ enum GatewayCmd {
#[arg(long)]
password_stdin: bool,
},
/// Remove a user from the gateway htpasswd file. Exits with an error
/// when the user is not found so callers can detect the no-op case.
/// Remove a user from the gateway htpasswd.
DeleteUser {
/// Username to remove.
username: String,
@ -495,19 +415,15 @@ enum GatewayCmd {
#[derive(Subcommand)]
enum WgCmd {
/// Generate (if absent) this hive's WireGuard private key, print its
/// public key, and print the nix snippet to enable the mesh. Idempotent:
/// an existing key is reused, never clobbered (clobbering would break a
/// live mesh). Share the printed public key with peer hives.
/// Generate this hive's WireGuard key (if absent) and print its public
/// key plus the nix to enable the mesh.
Init {
/// 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.
#[arg(long)]
address: Option<String>,
},
/// Print the nix snippet to add a peer hive to the mesh. Pure output —
/// paste it into this hive's config. Get `<pubkey>` from the peer's
/// `hivectl wg init`.
/// Print the nix to add a peer hive to the mesh.
Peer {
/// Peer hive's DNS domain (the `swarm.peers` attrset key).
domain: String,
@ -522,29 +438,23 @@ enum WgCmd {
#[arg(long)]
endpoint: Option<String>,
},
/// Show the live mesh interface state (`wg show wg-hive`). Requires the
/// mesh to be enabled + up.
/// Show the live mesh interface state.
Status,
}
#[derive(Subcommand)]
enum QuotaCmd {
/// Enable btrfs qgroup accounting on the agent-state filesystem. Run
/// once before `show` / `limit`. Triggers a full btrfs rescan (I/O
/// heavy on a large filesystem), so it's a deliberate opt-in.
/// Idempotent; a no-op on non-btrfs hosts.
/// Enable btrfs qgroup accounting on the agent-state filesystem.
///
/// Run once before `show` / `limit`. No-op on non-btrfs hosts.
Enable,
/// Report per-agent disk usage (referenced + exclusive bytes) from
/// btrfs qgroups. With no name, shows every agent that has a state
/// subvolume; pass a name to show just that one. Requires `enable`
/// first.
/// Report per-agent disk usage from btrfs qgroups (all agents, or one
/// by name).
Show {
/// Agent to show (omit for all agents with a state subvolume).
name: Option<String>,
},
/// Set or clear an agent's disk quota (a referenced-usage cap). `size`
/// accepts a byte count or a `K`/`M`/`G`/`T` suffix (e.g. `5G`), or
/// `none` to clear the limit. Requires `enable` first.
/// Set or clear an agent's disk-usage quota.
Limit {
/// Agent whose state subvolume to limit.
name: String,
@ -560,10 +470,7 @@ use hive_host_sock::HOST_SOCKET as DEFAULT_HOST_SOCKET;
#[derive(Subcommand)]
enum AgentsCmd {
/// Show all managed agents with their status (running / needs-login /
/// needs-update) and technical state (deployed sha, parent, pending
/// reminders). The host roster overview; reuses the dashboard's
/// per-agent aggregation. Requires the daemon running.
/// Show all managed agents with their status and technical state.
List {
/// Emit the raw JSON rows instead of the padded table (for
/// scripting). The table is the default human-readable shape.
@ -571,10 +478,6 @@ enum AgentsCmd {
json: bool,
},
/// Stop and start a single agent container without rebuilding config.
/// Useful for "kick the container" when the process is stuck or the
/// container needs a clean restart without changing the NixOS config.
/// Rides the job queue (serialized against in-flight rebuilds for
/// the same agent); waits with live progress unless `--no-wait`.
Restart {
/// Agent name (e.g. `damocles`, `ruth`).
name: String,
@ -582,23 +485,21 @@ enum AgentsCmd {
#[arg(long)]
no_wait: bool,
},
/// Restart ALL managed agent containers via one restart DAG each —
/// unrelated agents overlap, each serializes on its own lease.
/// Waits for the whole set with live progress unless `--no-wait`.
/// Restart all managed agent containers.
RestartAll {
/// Return immediately after the restart DAGs are queued.
#[arg(long)]
no_wait: bool,
},
/// Spawn a new agent container directly (`h-<name>`). Bypasses the
/// approval queue — operator-on-the-host only. For approval-gated
/// spawns, use `request-spawn`.
/// Spawn a new agent container directly, bypassing the approval queue.
///
/// Operator-on-the-host only; use `request-spawn` for an approval-gated
/// spawn.
Spawn {
/// Agent name (e.g. `iris`).
name: String,
},
/// Queue a spawn request as an approval. The container is created on
/// `hivectl approvals approve <id>` (or the dashboard APPR0VE button).
/// Queue a spawn request for operator approval.
RequestSpawn {
/// Agent name.
name: String,
@ -608,13 +509,12 @@ enum AgentsCmd {
/// Agent name.
name: String,
},
/// Tear down a sub-agent container. The container is removed; persistent
/// state (config repos + Claude credentials) is kept by default. Pass
/// `--purge` to also wipe the agent's state dirs (config + creds +
/// notes). No undo.
/// Tear down a sub-agent container, keeping its state by default. No
/// undo.
Destroy {
/// Agent name.
name: String,
/// Also wipe the agent's state dirs (config + creds + notes).
#[arg(long)]
purge: bool,
},
@ -623,9 +523,7 @@ enum AgentsCmd {
/// Agent name.
name: String,
},
/// Move an agent in the topology tree. Set `--parent` to a new parent
/// agent name, or pass `--root` to promote the agent to root (no
/// parent). Exactly one is required. Refuses cycles and unknown agents.
/// Move an agent in the topology tree — under a new parent, or to root.
SetParent {
/// Agent to move.
child: String,
@ -638,8 +536,7 @@ enum AgentsCmd {
},
}
/// Operator approval queue: list pending requests and approve / deny them.
/// Requires the hive-c0re daemon (connects to the host admin socket).
/// Operator approval queue: list, approve, or deny pending requests.
#[derive(Subcommand)]
enum ApprovalsCmd {
/// List pending approval requests submitted by agents.
@ -658,13 +555,10 @@ enum ApprovalsCmd {
#[derive(Subcommand)]
enum SubvolCmd {
/// Convert an existing plain-dir agent state root into a btrfs subvolume
/// in place. Stops the agent (so its state bind-mount is released),
/// migrates `…/agents/<name>/` to a subvolume preserving
/// ownership/permissions/xattrs, then restarts it. Idempotent (no-op if
/// already a subvolume) and safe (the original dir is left untouched on
/// any failure before the final swap). Requires `--yes` since it bounces
/// the agent and moves its state.
/// Convert a plain-dir agent state root into a btrfs subvolume in
/// place, so it gains snapshots and per-subvol usage/quota.
///
/// Bounces the agent to migrate its state, so it requires `--yes`.
Upgrade {
/// Agent name (e.g. `damocles`, `iris`).
name: String,
@ -673,9 +567,7 @@ enum SubvolCmd {
#[arg(long)]
yes: bool,
},
/// Read-only snapshots of an agent's state subvolume — the first step
/// of the (in-progress) inter-hive migration path, or a manual
/// point-in-time backup.
/// Read-only snapshots of an agent's state subvolume.
Snapshot {
#[command(subcommand)]
cmd: SnapshotCmd,
@ -684,8 +576,7 @@ enum SubvolCmd {
#[derive(Subcommand)]
enum SnapshotCmd {
/// Create a read-only snapshot. Agent must already be a subvolume
/// (`subvol upgrade` first). Prints the snapshot's host path.
/// Create a read-only snapshot (agent must already be a subvolume).
Create {
/// Agent name (e.g. `damocles`, `iris`).
name: String,