The hive no longer sets an agent's CPU or memory cap: caps come from the swarm, else the hive-wide defaults. The container load tab was the only hive UI that set them, and its figures are already exported as OTEL metrics, so with the tab gone nothing wrote meta/resource-limits.json.
Removed: the file's reader and writer, the `hivectl agent set-limits` verb with its host-socket request, the `GET /api/container-resources` and `POST /api/resource-limits/{name}` dashboard endpoints, and the `cpu_quota`/`memory_max` fields of the container view that only the tab read. A leftover resource-limits.json is ignored.
249 lines
13 KiB
Markdown
249 lines
13 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/trust-boundary/boundary.md`](../trust-boundary/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
|
|
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 autogenerated 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
|
|
|
|
Reconciles an agent's config between this hive and the forge. `hivectl`
|
|
makes no forge accounts: a human's first SSO login to the forge makes
|
|
theirs, and `swarmctl forge make-admin <name>` makes it a site admin.
|
|
swarm-controller makes an agent's, and `swarmctl agent mint-forge-token
|
|
<agent>` checks and, if needed, re-mints its token.
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
- `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 doesn't autorebuild). `--from local` isn't
|
|
supported yet (forge `main` is 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.deploy.matrix.enable = true`).
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
Human matrix accounts come from SSO, not `hivectl`; matrix homeserver
|
|
admin should eventually come from membership in authelia's `admins`
|
|
group; nobody has built that sync yet.
|
|
|
|
- `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 sender
|
|
token; the 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.
|
|
|
|
## 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/hive-gateway/conf/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
|
|
```
|
|
|
|
The daemon hashes passwords with BCrypt (cost 12). It creates the file
|
|
if it doesn't 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>` — `hivectl` hoists
|
|
the name 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 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; 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 an agent at all. 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.** hivectl skips the graceful-stop
|
|
handshake 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.
|
|
|
|
## 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, or membership in
|
|
`hive-admin` (the same sudoless-`hivectl` group as the [host admin
|
|
socket](../trust-boundary/boundary.md) — hive-c0re ships a polkit rule
|
|
granting that group the one action `machinectl shell` needs); `choom`
|
|
checks this itself and refuses up front with a message naming the
|
|
requirement rather than letting systemd reject the exec later with an
|
|
opaque polkit prompt. Same caveat as the socket grant: a shell opened
|
|
before the operator added you to `hive-admin` doesn't see it until you log
|
|
back in — secondary group membership applies at login.
|
|
|
|
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 the daemon's user owns and which isn't group-readable, so the check
|
|
is a `HostRequest` rather than a local `stat`. An unprivileged `choom`
|
|
therefore names the grant it wants, 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, that is, the
|
|
harness's; claude would consume a value after it as the first prompt,
|
|
silently poking the live harness session.) Passing the flag requires a
|
|
value. 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](../networking/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/web-ui/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)
|
|
```
|
|
|
|
hivectl resolves the URL 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 typically headless / driven over SSH), then hivectl tries
|
|
`xdg-open` as a convenience, reporting a missing or failing opener 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.swarm.forge.publicUrl` (set by default); `matrix` needs
|
|
`services.hyperhive.swarm.matrix.gatewayHost` (set by default). In those cases the command
|
|
exits with a hint naming the option to set.
|