319 lines
16 KiB
Markdown
319 lines
16 KiB
Markdown
# 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 `<state>/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 <agent>` shows the divergence between the agent's local
|
|
applied config checkout and its forge `agent-configs/<agent>` `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
|
|
`<state>/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 <pat> # inline (visible in shell history)
|
|
```
|
|
|
|
- `set-token`: writes `<state>/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. Everything scoped to a
|
|
single agent lives under `hivectl agent <name> <verb>` — the name is
|
|
hoisted onto the parent command, so none of the verbs below repeat it.
|
|
|
|
```bash
|
|
hivectl list-agents # roster: every agent's status + technical state
|
|
hivectl list-agents --json # same data as raw JSON rows (for scripting)
|
|
hivectl agent iris restart # stop + start the `iris` container (no rebuild)
|
|
hivectl agent iris pause # park iris's turn loop, leave the container running
|
|
hivectl agent iris resume # let it drive turns again, draining what queued up
|
|
```
|
|
|
|
`list-agents` 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.
|
|
|
|
`agent <name> 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. For more than one agent at once, use
|
|
the top-level `hivectl restart --agents` (or `--agent <name>` repeated) —
|
|
it rides a single DAG and reports per-target failures at the end rather
|
|
than aborting mid-run, instead of shelling out to `agent <name> restart`
|
|
in a loop.
|
|
|
|
`pause` / `resume` are the "stop burning tokens without losing the
|
|
container" pair. Pausing writes a marker file into the agent's harness
|
|
dir (`<state>/<name>/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 `list-agents`'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 agent sock set-limits --cpu-quota 400% --memory-max 8G
|
|
hivectl agent sock set-limits --memory-max 8G # CPU falls back to the hive default
|
|
hivectl agent sock set-limits --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 <name>` 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 <name>@h-<name>`
|
|
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 agent iris choom # fresh blank Claude session in iris's container
|
|
hivectl agent iris choom --resume <session-id> # rejoin a prior session by id
|
|
```
|
|
|
|
Bare `choom` starts a fresh blank session. `--resume <value>` passes
|
|
through as `claude --resume <value>` 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/<name>/.claude` where its OAuth credentials live. choom
|
|
prefixes the machine with `<name>@` (the meta-flake sets the agent's
|
|
unix user name to its label).
|
|
- **from `/agents/<name>/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.
|
|
|
|
## Watch
|
|
|
|
Follow an agent's live turn/tool-call event stream from the CLI:
|
|
|
|
```bash
|
|
hivectl agent iris watch # tail iris's live events; Ctrl-C to stop
|
|
```
|
|
|
|
Dials the same unix socket the gateway's nginx `proxy_pass`es through
|
|
(`/run/hive-agent/<name>/web.sock` — see [Per-agent unix-socket
|
|
upstream](../gateway.md#per-agent-unix-socket-upstream)) directly and
|
|
speaks a bare HTTP/1.1 request for the agent's existing `/events/stream`
|
|
SSE endpoint over it. No gateway hop, no daemon round-trip for the
|
|
stream itself — the daemon socket is only used for the "does this agent
|
|
exist" pre-flight, same reasoning as `choom` above. Requires the agent
|
|
to be running with its web UI socket bound; a fresh spawn/rebuild that
|
|
hasn't come up yet gets a clear connection-refused hint rather than a
|
|
raw OS error.
|
|
|
|
Prints one compact line per event — reuses the `_icon`/`_summary` fields
|
|
the harness already stamps onto stream-json events for the web UI
|
|
(`stream_enrich.rs`), so tool calls and turn markers read as short
|
|
glyph-prefixed lines instead of raw JSON. Not an attempt at the web
|
|
UI's full collapsible-details rendering (`docs/terminal-rendering.md`)
|
|
— that's presentation for a browser, this is a `tail -f`.
|
|
|
|
## 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://<domain>/)
|
|
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.<domain>`. 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.
|