# hivectl `hivectl` is the operator-facing host CLI for hyperhive. It lives on the host (not inside any container). It talks to `hive-c0re` over the host admin socket `/run/hyperhive/host.sock`, which is root-only by default — so it needs `sudo` unless you grant sudoless access by listing your login user in `services.hyperhive.c0re.adminUsers` (adds you to the `hive-admin` group that owns the socket; see [`docs/boundary.md`](../boundary.md#host-admin-socket-access-hivectl)). Available via the `hive-c0re` package in the host NixOS config. Unlike the `hive-c0re` daemon subcommands (which go through the broker), `hivectl` covers direct host-side administration: manual provisioning of forge + matrix accounts, gateway htpasswd management, container lifecycle shortcuts, and interactive agent shell access. This page is the curated guide. For the exhaustive flag-by-flag reference auto-generated from the binary's own command tree, see [`hivectl-cli.md`](hivectl-cli.md) — emitted by the hidden `hivectl markdown-docs` subcommand and kept in lockstep with the code by the `hivectl-docs` flake check (CI fails if the committed copy drifts). Regenerate with `nix build .#default && ./result/bin/hivectl markdown-docs > docs/tools/hivectl-cli.md`. ## Forge Manual entry to the same idempotent provisioning flow `hive-c0re` runs at boot. Useful for recovery, ad-hoc re-provisioning, or fixing a single agent without bouncing the daemon. ```bash hivectl forge create-user iris # provision (or refresh) forge account for agent `iris` hivectl forge create-user mara # create forge account for a human user; prints token to stdout hivectl forge create-user mara --password hunter2 # set a web-login password hivectl forge create-user mara --password-stdin # read password from stdin (safer for scripting) hivectl forge reconcile-config iris # show local-applied <-> forge config divergence, then prompt hivectl forge reconcile-config iris --from forge # reset local applied checkout to forge main (effective next deploy) hivectl forge reconcile-config iris --verbose # include the full diff, not just --stat ``` - For **agents** (name has a state dir under `/var/lib/hyperhive/agents/`): token is persisted to `/forge-token`. Re-running refreshes the token (idempotent — scope always matches current `TOKEN_SCOPES`). - For **non-agents** (humans): creates the account and prints the token to stdout; no state dir is created. Re-running after account already exists re-mints the token and prints it again — safe for password resets. - Without `--password` / `--password-stdin` a random throwaway password is used (fine for agents — they auth by token). - `reconcile-config ` shows the divergence between the agent's local applied config checkout and its forge `agent-configs/` `main`, then reconciles. `--from forge` resets the local checkout to forge `main` (takes effect on the next deploy — it does not auto-rebuild). `--from local` is not supported yet (forge `main` is core-only branch-protected; resolve via a config PR). With no `--from` it prompts for the direction after the diff. ## Matrix Manual entry to the same idempotent matrix provisioning flow `hive-c0re` runs at boot. Requires the `hive-matrix` container to be running (`services.hyperhive.matrix.enable = true`). ```bash hivectl matrix create-user iris # provision (or re-provision) matrix account for agent `iris` hivectl matrix create-user mara # create matrix account for a human; prints access_token to stdout hivectl matrix create-user mara --password hunter2 # set a client-login password hivectl matrix sync-admin # provision / refresh the hive internal admin account hivectl matrix promote-user mara # promote an existing matrix user to homeserver admin hivectl matrix reset-password iris # generate and set a new random password for `iris`; prints it hivectl matrix invite mara # invite a user to the hive Space hivectl matrix invite @mara:server --room '#hive-chat:server' # ...or to a specific room/alias ``` - `create-user`: for agents, persists the `access_token` to `/matrix-token`. Skips registration when the file already exists — delete it first to force re-registration. - `sync-admin`: ensures the hive's internal admin matrix user exists (used by `hive-c0re` for admin-room commands). Token persisted to the admin token path. Safe to run again — idempotent. - `promote-user`: promotes an already-registered user to homeserver admin via the matrix admin API. Requires `sync-admin` to have run first (needs a valid admin token). - `reset-password`: calls the matrix admin API to set a new random password and prints it to stdout. Useful if an agent or human lost credentials. - `invite`: invites a matrix user (full `@user:server` or a bare localpart, qualified with the homeserver's `server_name`) to the hive Space by default, or to a `--room` id / `#alias`. Uses the hive admin token; the admin account must be a member of the target room with invite power (it owns the hive Space, so that case always works). Idempotent — already-member / already-invited is a no-op. ## GitHub Write an operator-supplied GitHub personal access token (PAT) into an agent's token file so its `gh` wrapper + git credential helper can act as the bot account. Unlike forge/matrix there is no account creation — the PAT is for an existing GitHub account. A CLI alternative to the dashboard credentials tab; the [GitHub integration](../github.md) is on by default (`hyperhive.github.enable`), so no per-agent config is needed. ```bash hivectl github set-token damocles --token-stdin # paste the PAT on stdin (preferred) hivectl github set-token damocles --token # inline (visible in shell history) ``` - `set-token`: writes `/github-token` (`0600`, agent-owned) via hive-priv — the same credential-injection path as forge/matrix tokens. The `gh` wrapper / git credential helper read it live, so a freshly-set or rotated PAT takes effect with no rebuild or restart. Refuses an empty token. See [github.md](../github.md) for the full flow + security notes. ## Gateway Manage users in the gateway's HTTP Basic auth htpasswd file (`services.hyperhive.gateway.auth`). `hivectl` sends the request over the host admin socket; the `hive-c0re` daemon owns the htpasswd file at its canonical path (`/var/lib/hyperhive/gateway/gateway.htpasswd`) and performs the write. ```bash hivectl gateway create-user alice --password-stdin # add (or update) user; read password from stdin hivectl gateway create-user bob --password hunter2 # add user inline (visible in shell history) hivectl gateway delete-user bob # remove user hivectl gateway list-users # list all usernames, one per line ``` Passwords are hashed with BCrypt (cost 12) by the daemon. The file is created if it does not exist. Re-running `create-user` with the same username updates the password hash in place. ## Agents Container lifecycle shortcuts that go through the host admin socket. Requires the `hive-c0re` daemon to be running. ```bash hivectl agents list # roster: every agent's status + technical state hivectl agents list --json # same data as raw JSON rows (for scripting) hivectl agents restart iris # stop + start the `iris` container (no rebuild) hivectl agents restart-all # stop + start every managed agent container in sequence hivectl agents pause iris # park iris's turn loop, leave the container running hivectl agents resume iris # let it drive turns again, draining what queued up ``` `list` prints a padded table with one row per managed agent — `NAME STATUS REV PARENT REMIND`. STATUS collapses the health flags (`running` / `stopped`, plus ` paused` / ` needs-login` / ` needs-update` when set — `paused` is orthogonal to running, see below); REV is the first 12 chars of the agent's locked config sha; PARENT is its place in the topology tree (`-` for a root agent); REMIND is the count of pending reminders. It reuses the same per-agent aggregation the dashboard renders, so the CLI roster and the web UI never drift. `--json` emits the raw rows instead of the table. `restart` is the manual equivalent of the MCP `restart` tool — useful when you need to kick a container from the host without going through the agent hierarchy. Failures on `restart-all` are collected and reported at the end rather than aborting mid-run. `pause` / `resume` are the "stop burning tokens without losing the container" pair. Pausing writes a marker file into the agent's harness dir (`//harness/paused`) which the harness re-stats every 5 s at the top of its serve loop; while it's there the agent drives no turns, but the container, its mounts, its warm caches, its web UI and its MCP daemons all stay up. Inbox messages queue **unacked**, so a resume drains the backlog rather than dropping it. Points worth knowing: - **Sticky.** The marker lives on the persistent harness mount, so a paused agent stays paused across a container restart — and pausing a *stopped* agent makes it come up parked. - **Not a DAG.** Unlike `restart`/`stop`, there's no container operation to sequence, so it applies immediately with nothing to wait on. - **Stopping a paused agent is still fast.** The graceful-stop handshake is skipped for a paused agent (it would never answer), which is safe precisely because the pause check sits at the top of the loop: a paused agent has no turn in flight to checkpoint. - Visible as ` paused` in `agents list`'s STATUS column, as a `paused` field on the JSON rows, and as a badge on the dashboard card. ### Per-agent resource limits ```bash hivectl agents set-limits sock --cpu-quota 400% --memory-max 8G hivectl agents set-limits sock --memory-max 8G # CPU falls back to the hive default hivectl agents set-limits sock --reset # drop all overrides ``` Overrides the hive-wide `services.hyperhive.agentCpuQuota` / `agentMemoryMax` for one agent, persisted to `meta/resource-limits.json` (see [`persistence.md`](../persistence.md)). Values are systemd's `CPUQuota=` / `MemoryMax=` syntax: a percentage (`400%` = four full cores) for CPU; a size (`8G`), a percentage of physical RAM, or `infinity` for memory. Both are validated before they're persisted — they go into a systemd drop-in verbatim, and a typo there makes the unit fail to start. **Declarative, not incremental**: each invocation replaces the agent's whole entry. `set-limits sock --memory-max 8G` leaves `sock` with *only* a memory override, reverting any previously-set CPU quota to the hive default. To avoid a forgotten flag silently wiping an override, a bare `set-limits ` with no flags is rejected — clearing requires the explicit `--reset`. The command rewrites the container's drop-in and reloads systemd, so new containers and restarts pick the values up immediately. ## Choom Drop into an interactive Claude session inside an agent container. Replaces the current process with `machinectl shell @h-` running claude from the agent's state dir. Requires root (same as all `machinectl shell` operations) — hyperhive ships no polkit rule granting those actions to the operator group, so `choom` refuses up front with a message naming that requirement rather than letting systemd reject the exec later. It also needs the daemon socket, unlike the other exec-into-a-container paths: the "is this actually an agent?" pre-flight reads the agents root, which is owned by the daemon's user and not group-readable, so the check is a `HostRequest` rather than a local `stat`. A rootless `choom` therefore tells you it needs root, instead of reporting a permission problem with the state dir. ```bash hivectl choom iris # fresh blank Claude session in iris's container hivectl choom iris --resume # rejoin a prior session by id ``` Bare `choom` starts a fresh blank session. `--resume ` passes through as `claude --resume ` to rejoin a prior session by its session id — the flag name deliberately matches the claude flag it maps to. (choom never uses claude's `--continue`: that's a bare flag that takes no argument and resumes the cwd's *latest* session, i.e. the harness's; a value after it would be consumed as the first prompt, silently poking the live harness session.) A value is required when the flag is given. Either way choom never collides with the harness's live session in the same project dir: the harness pins its own id via `--resume`, so a blank choom session is invisible to it. The container must be running. choom reproduces the harness's own claude invocation so the operator lands in a faithful copy of the agent's environment: - **as the agent user**, not root: `machinectl shell` defaults to root, which would make claude read `/root/.claude` (empty) instead of the agent's `/home//.claude` where its OAuth credentials live. choom prefixes the machine with `@` (the meta-flake sets the agent's unix user name to its label). - **from `/agents//state`**: the session and `CLAUDE.md` (the persona) resolve against the right project dir. - **with the harness flags**: `--settings`, `--mcp-config`, and `--system-prompt-file` from `/run/hive-config/` — the same files the harness writes each turn — so the operator gets the agent's settings, the hyperhive/matrix MCP tools, and the role prompt. Each flag is included only when its file exists. - **without the onboarding walkthrough**: a boot-time oneshot (`hive-claude-onboarding`) seeds `hasCompletedOnboarding` and the project trust flags into `~/.claude.json` once before the harness starts, so the first interactive choom lands straight in a session instead of the onboarding/trust dialog the headless harness never completes. It's the single place hyperhive touches that file. ## Open Print (and best-effort open in a browser) one of the hive's web surfaces. Requires the `hive-c0re` daemon to be running. ```bash hivectl open # operator dashboard (same as `open home`) hivectl open home # operator dashboard (https:///) hivectl open forge # the forge (Forgejo) web UI hivectl open matrix # the matrix GUI (fluffychat) ``` The URL is resolved from the running daemon (`HostRequest::Urls`), which reads the per-surface public URLs from c0re's service env — so custom forge / matrix domains resolve correctly instead of assuming `forge.`. The URL is **always printed** (the reliable core, since the host is usually headless / driven over SSH), then `xdg-open` is tried as a convenience — a missing or failing opener is reported as a note, not an error. A surface has no URL when it isn't browser-reachable: `home` needs `services.hyperhive.domain`; `forge` needs `services.hyperhive.forge.behindGateway = true`; `matrix` needs `services.hyperhive.matrix.gui.enable = true`. In those cases the command exits with a hint naming the option to set.