Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/docs/tools/hivectl.md
atlas a429b30448 rename claude.md to agents.md for agents and the repo
Claude Code (>= 2.1.277) and opencode both read AGENTS.md, but Claude
Code reads it only when no CLAUDE.md exists in its cwd or above. So
this is a plain rename with no CLAUDE.md stub left behind.

- hive-agent/src/agents_md_migrate.rs: new. At harness start, before
  the first turn, renames state/CLAUDE.md to state/AGENTS.md when only
  the former exists; logs an error naming both paths when both exist
  and touches neither; does nothing otherwise. Idempotent.
- hive-agent/src/main.rs: calls it in serve_main; checkpoint prompt
  and a comment name AGENTS.md.
- hive-agent/src/claude_md_watch.rs: the size watch reads AGENTS.md;
  todo text, doc comments and tests follow. Module name, todo
  subsystem key ("claude_md") and metric name
  (hyperhive.agent.claude_md.lines) are unchanged so existing todo
  rows and dashboard history carry over.
- hive-agent/src/turn.rs, hive-agent/prompts/system.md: prompts tell
  the agent its file is AGENTS.md.
- hive-agent/src/{otel_turn_metrics,stats}.rs,
  frontend/packages/agent/src/stats.js, hive-subagent-mcp/src/*.rs:
  comments and a tool parameter description naming the agent's file.
- nix/host-modules/swarm-grafana/dashboards/agents.json: panel title
  and description.
- claude-plugins skills claude-subagents, state-hygiene: they mean the
  agent's own state file.
- CLAUDE.md -> AGENTS.md at the repo root; docs/crates/README.md link
  (checked by check-doc-refs.sh), hive-c0re/README.md,
  .prettierignore and the nix/sources.nix comment follow.
- docs/: every prose mention of the agent's file; persistence.md
  documents the boot-time rename, claude-invocation.md the shadowing.

Fixes #5509
2026-10-18 02:33:06 +02:00

229 lines
12 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, 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.
## 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 `AGENTS.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://<hive>.hives.<swarm 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.