docs: the handbook follows the three layers: swarm, hives, agents
The handbook's sections were agent-lifecycle, integrations, swarm, tools, trust-boundary and web-ui, which do not follow how the system is built, so a reader could not tell which layer a page is about. Its pages now sit in swarm/, hives/ and agents/, with the accounts an agent can hold outside the system in external-accounts/. - swarm/: forge, matrix and the knowledge repo join the swarm pages, and so does the swarmctl reference. - hives/: the dashboard, hivectl and its reference, and the operator/agent boundary, with a README that takes over the old web-ui and tools pages. - agents/: the roster, persistence, config changes, the agent's own web page (was web-ui/agent) and the security model, with a README. - external-accounts/: GitHub and GitLab. Pages are moved whole; none is split yet. Every reference follows: relative links in the docs, `docs/2-handbook/...` paths in code comments, the nix checks that regenerate the CLI references and the ignore list, and docs/README.md, whose handbook section is now by layer.
This commit is contained in:
parent
263b21021a
commit
0e84fe8bc4
5 changed files with 393 additions and 363 deletions
113
docs/2-handbook/hives/README.md
Normal file
113
docs/2-handbook/hives/README.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# Hives
|
||||
|
||||
A **hive** is one host running `hive-c0re` and its agent containers. This
|
||||
section is for the operator of that host: the per-hive dashboard, the
|
||||
`hivectl` CLI and the operator/agent trust boundary on the host. For what
|
||||
the whole swarm shares, see [the swarm UI](../swarm/ui.md) instead.
|
||||
|
||||
- **[Dashboard](dashboard.md)** — every tab and standalone page of the
|
||||
per-hive dashboard, in full detail: endpoint shapes, event wiring, badge
|
||||
rules.
|
||||
- **[hivectl](hivectl.md)** — the curated guide to the host CLI:
|
||||
provisioning forge and matrix accounts, container lifecycle shortcuts,
|
||||
interactive agent shell access.
|
||||
- **[hivectl-cli](hivectl-cli.md)** — the flag-by-flag reference,
|
||||
generated from the binary and kept in lockstep by CI.
|
||||
- **[The operator/agent boundary](boundary.md)** — what the operator may do
|
||||
that an agent may not, and why the line sits where it does.
|
||||
|
||||
For `swarmctl`, the swarm operator's CLI, see
|
||||
[`swarmctl-cli.md`](../swarm/swarmctl-cli.md). The tool surface agents get
|
||||
inside their containers is in
|
||||
[`4-implementation/agent-tools/`](../../4-implementation/agent-tools/README.md).
|
||||
|
||||
## Where things are
|
||||
|
||||
Everything starts at the **dashboard**, served at `/`. A pages menu (the
|
||||
link icon beside the profile avatar, at the right of the tab strip) links to
|
||||
the other surfaces: the API docs and the swarm UI.
|
||||
|
||||
The dashboard is a single page with these tabs:
|
||||
|
||||
- **4G3NTS** — every agent, live. This is the default tab and the one you
|
||||
check most.
|
||||
- **R3BU1LD QU3U3** — the rebuild queue. A build's output and history are on
|
||||
the swarm's `builds` Grafana board.
|
||||
- **K3PT ST4T3** — kept state from agents with no container (tombstones),
|
||||
with a purge button per entry.
|
||||
|
||||
Each agent also has its own page, a full terminal view of that agent's
|
||||
session. Select its name anywhere in the dashboard, or open `/agent/<name>/`
|
||||
(or `http://<host>:<port>/` if the gateway isn't in front). [The agent's web page](../agents/web-page.md)
|
||||
covers it.
|
||||
|
||||
## The things you do here
|
||||
|
||||
**Check on an agent.** 4G3NTS shows every container as a row: name, whether
|
||||
it's running, what it's doing (a live status pill such as `rebuilding…` or
|
||||
`starting…` while something's in flight), and quick links (stats, screen,
|
||||
forge profile). Select the name to open its terminal and watch it work.
|
||||
|
||||
**Review a config change.** Agent config changes (new packages, env vars, MCP
|
||||
servers) are pull requests on the agent's `agent-configs` repo. Review and
|
||||
merge them on the forge; the merge deploys the change. See
|
||||
[`config-changes.md`](../agents/config-changes.md#config-changes).
|
||||
|
||||
**Start, stop, restart or rebuild an agent.** Select one or more agents on
|
||||
4G3NTS (select the icon) and use the selection bar, or use the per-agent `⋮`
|
||||
menu on a single row. Rebuilding downloads and applies the closure the swarm
|
||||
declares for the agent again. The hive applies a changed declaration itself,
|
||||
so use it to retry one that failed.
|
||||
|
||||
**Watch a build.** The R3BU1LD QU3U3 tab shows the rebuild queue live, plus a
|
||||
streaming log of whatever's building. Useful right after merging a config
|
||||
change or bumping a flake input.
|
||||
|
||||
**Grant or revoke a permission.** Not on the hive dashboard: an agent's
|
||||
permissions live in the swarm. Set them with `swarmctl agent permissions`, or
|
||||
on the swarm UI's create-agent screen when creating the agent; see
|
||||
[`5-project/process/conventions.md`](../../5-project/process/conventions.md#permissions).
|
||||
|
||||
**Read an agent's logs.** Logs aren't in the hive dashboard. Every hive ships
|
||||
its agents', daemons' and infra containers' journals to the swarm's
|
||||
VictoriaLogs; read them in Grafana's **Explore**, as
|
||||
[`swarm/services.md`](../swarm/services.md#logs-victorialogs) says.
|
||||
|
||||
**Set up a schedule.** Scheduled prompts are swarm-level: set them with
|
||||
`swarmctl schedule` ([`swarm/schedules.md`](../swarm/schedules.md)) or in the
|
||||
schedules card on the swarm UI's messages tab ([`swarm/ui.md`](../swarm/ui.md)).
|
||||
|
||||
## More depth
|
||||
|
||||
The dashboard and the per-agent pages are single-page apps that share one
|
||||
skeleton: `GET /` returns a static shell, `/api/state` returns JSON, and
|
||||
JavaScript renders, with no full-page reloads.
|
||||
|
||||
- **[Shape (shared by both)](../../4-implementation/web-ui/shape.md)** — the
|
||||
SPA skeleton, SSE multiplexing, terminal pane, listener bind, per-agent
|
||||
relative paths, the `data-async` form pattern and atomic repaint.
|
||||
- **[CSS theme variables](../../4-implementation/web-ui/css-vars.md)** — the
|
||||
Catppuccin Mocha custom properties declared once in `base.css`, and the
|
||||
rule that per-page stylesheets reference them and never redeclare them.
|
||||
- **[swarm-ui design guide](../../5-project/web-ui/design-guide.md)** — the
|
||||
visual language, motion, theming, error UX and component-first principles
|
||||
for the swarm-level Preact app. `/components` on a running swarm UI is the
|
||||
living demo of every building block it names.
|
||||
|
||||
For the code, these jump straight to the relevant section:
|
||||
|
||||
- **"How does the dashboard SPA stay live without polling?"** →
|
||||
[`shape.md`](../../4-implementation/web-ui/shape.md) (SSE multiplexing,
|
||||
Worker-death self-heal, atomic repaint).
|
||||
- **"What does a container row contain?"** → [`dashboard.md`](dashboard.md)
|
||||
(Container row, Selection bar).
|
||||
- **"What endpoints does the dashboard expose?"** →
|
||||
[`dashboard.md`](dashboard.md) (Dashboard endpoints, Dashboard event
|
||||
channel).
|
||||
- **"How does the per-agent terminal render tool calls?"** →
|
||||
[`terminal-rendering.md`](../../4-implementation/web-ui/terminal-rendering.md)
|
||||
(the full row taxonomy and dispatch walkthrough); for a summary see
|
||||
[`web-page.md`](../agents/web-page.md) (Per-stream rendering).
|
||||
- **"Which CSS variable to use, and where are the colours defined?"** →
|
||||
[`css-vars.md`](../../4-implementation/web-ui/css-vars.md) (Palette, the
|
||||
single-source `base.css` rule).
|
||||
109
docs/2-handbook/hives/boundary.md
Normal file
109
docs/2-handbook/hives/boundary.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# The operator/agent boundary
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
|
||||
Design rationale for hyperhive's two-principal trust model. The
|
||||
_implementation_ work — container network isolation, the unifying
|
||||
gateway, core-daemon privsep — is tracked as `area:ops` issues on
|
||||
the forge.
|
||||
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
The operator/agent boundary is technically enforced, not just a
|
||||
convention: containers run in private netns (network isolation is
|
||||
always on), the gateway proxies all operator-facing traffic, and
|
||||
`hive-c0re` runs as the unprivileged `hive-core` user.
|
||||
|
||||
## Two principals, two paths
|
||||
|
||||
- **Operator** — reaches every UI (the dashboard + every
|
||||
per-agent page) through the gateway, on one origin.
|
||||
The core daemon serves operator-authority actions
|
||||
(answer-as-operator, lifecycle POSTs), reachable only via the
|
||||
gateway.
|
||||
- **Agent** — speaks only for itself, only over its per-agent
|
||||
unix socket. The socket's identity _is_ the agent (see
|
||||
`docs/5-project/process/conventions.md`, "identity = socket"). An agent must not
|
||||
be able to reach the core daemon's HTTP surface, another
|
||||
agent's socket, or another agent's web UI.
|
||||
|
||||
## Design rule
|
||||
|
||||
**Operator-authority actions never get a per-agent-socket entry
|
||||
point.** They live in hive-c0re.
|
||||
|
||||
Worked example — destroying or rebuilding a container is a
|
||||
`POST /api/{destroy,rebuild}/{name}` on the core dashboard, _never_ a
|
||||
per-agent-socket `Request` variant. If it were a per-agent-socket
|
||||
request, a compromised agent could `curl` its own socket and destroy
|
||||
or rebuild itself (or, if the variant took an arbitrary target, another
|
||||
agent) without ever touching the core's own authenticated surface.
|
||||
|
||||
## Why network isolation is the load-bearing step
|
||||
|
||||
Without network isolation, containers share the host network namespace
|
||||
and can reach `localhost:<core-port>`, the dashboard, and every other
|
||||
agent's web port — the operator/agent split is on the honour system and
|
||||
every boundary claim above is aspirational. Network isolation is what
|
||||
makes the boundary _real_; the gateway and privsep are ergonomics and
|
||||
defence-in-depth layered on top.
|
||||
|
||||
Network isolation is complete and always on: every agent container
|
||||
runs in a private netns behind the hive bridge, and there is no
|
||||
shared-netns mode. See `docs/4-implementation/networking/network.md`.
|
||||
|
||||
Concretely, the core daemon's dashboard `/api` carries **no
|
||||
application-layer authentication** — the core daemon serves operator-authority
|
||||
routes unauthenticated at the HTTP layer. Their protection is entirely (a) the
|
||||
gateway, which fronts all operator traffic and is where operator auth lives,
|
||||
and (b) network isolation, which keeps agents — and the CI runner's untrusted
|
||||
PR builds — off host-loopback so nothing can reach `127.0.0.1:<dashboard_port>`
|
||||
directly. This is deliberate given the load-bearing role of network isolation
|
||||
above, but it's a standing invariant: the `/api` must never bind to a
|
||||
non-loopback address or get exposed outside the gateway, and every new
|
||||
operator-authority route inherits that assumption. hyperhive treats
|
||||
`swarm-ci-runner` like an agent for this purpose — it runs untrusted PR code and is
|
||||
netns-isolated for the same reason.
|
||||
|
||||
The boundary rests on three layers:
|
||||
|
||||
1. **Gateway** — fronts all surfaces (dashboard + every per-agent UI)
|
||||
on one origin. An nginx nixos-container proxies per-agent UIs under
|
||||
`/agent/<name>/`, which is what lets each agent page's inbox panel
|
||||
POST `mark-all-read` to the core dashboard's
|
||||
`/api/agent/{name}/mark-all-read` go same-origin instead of needing
|
||||
a cross-origin CORS shim. Pure ergonomics — no behavioural risk on
|
||||
its own.
|
||||
2. **Network isolation** — the load-bearing layer: every agent
|
||||
container runs in a private netns behind the hive bridge, always
|
||||
on and unconditional. This is what turns the operator/agent split
|
||||
from an honour-system convention into an enforced boundary.
|
||||
3. **Privsep** — defence in depth on the core process; `hive-c0re`
|
||||
runs as the unprivileged `hive-core` user and delegates root
|
||||
operations to `hive-priv`, a narrow socket-activated helper. See
|
||||
[`docs/4-implementation/trust-boundary/hive-c0re-privilege.md`](../../4-implementation/trust-boundary/hive-c0re-privilege.md) for the privilege boundary table.
|
||||
|
||||
### host admin socket access (`hivectl`)
|
||||
|
||||
`hivectl` drives the whole hive — spawn / kill / destroy / rebuild /
|
||||
deploy — over the **host admin socket** `/run/hyperhive/host.sock`,
|
||||
socket-activated by the `hive-c0re.socket` unit. That socket _is_ the
|
||||
full-control surface, so who can connect to it's a real trust
|
||||
boundary.
|
||||
|
||||
By default the socket is `0660` group-owned by **`hive-admin`**, an
|
||||
empty group — so it's effectively **root-only** until an operator is
|
||||
explicitly granted access. Grant sudoless `hivectl` by listing login
|
||||
users in `services.hyperhive.deploy.hive-controller.adminUsers`; the option adds each to
|
||||
`hive-admin`, and members connect without `sudo`. The runtime dir
|
||||
`/run/hyperhive` is `0751` (traverse-only, no listing) so the group can
|
||||
reach the socket path; the socket's own `0660 hive-admin` mode gates
|
||||
the connection, and the per-agent subdirs under it keep their own
|
||||
restrictive perms. Keep `adminUsers` to trusted operators — membership
|
||||
is equivalent to root over the hive.
|
||||
|
||||
## Implementation detail
|
||||
|
||||
How `hive-priv` is socket-activated and how the per-agent socket directory
|
||||
gets its owner and mode:
|
||||
[socket mechanics](../../4-implementation/trust-boundary/boundary-mechanism.md).
|
||||
528
docs/2-handbook/hives/dashboard.md
Normal file
528
docs/2-handbook/hives/dashboard.md
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
# Dashboard layout
|
||||
|
||||
> Part of [Hives](README.md). See also:
|
||||
> [Shape (shared)](../../4-implementation/web-ui/shape.md) · [Per-agent page](../agents/web-page.md)
|
||||
|
||||
This page covers the per-hive UI that hive-c0re serves. Swarm-wide
|
||||
surfaces — the agent roster, agent creation, linking external forge and
|
||||
matrix accounts, the controller's job graph — are on the
|
||||
[swarm UI](../swarm/ui.md).
|
||||
|
||||
hive-c0re serves the dashboard at `/`.
|
||||
It has a fixed chrome header at the top and a `<main>` that shows exactly
|
||||
one tab pane at a time. The URL hash (`#agents`, `#rebuild`, `#meta`,
|
||||
`#kept`) drives which pane is
|
||||
active; hash changes don't reload the page.
|
||||
|
||||
**Chrome header** (fixed, overlays the active tab pane):
|
||||
- **Pages menu**: a link icon at the right end of the chrome, beside the
|
||||
profile avatar (`links-menu.js`, `@hive/shared`'s `LinksMenu`, the same
|
||||
component the swarm UI uses for its service links), opening a popover with links to **api docs**
|
||||
(`/api/docs/`) and **swarm** (the swarm
|
||||
UI at the swarm apex domain, opened in a new tab). The swarm entry
|
||||
comes from `state.swarm_public_url`, which hive-c0re reads from
|
||||
`HIVE_SWARM_PUBLIC_URL` (set from `services.hyperhive.swarm.domain`);
|
||||
with no domain set there is no swarm entry. The standalone pages link back to `/`.
|
||||
- **Profile menu**: the signed-in user's avatar at the right end of the
|
||||
chrome (`user-menu.js`, the same component as the swarm UI's and the agent
|
||||
page's). It opens a popover with the user's name and links to authelia's
|
||||
settings and sign-out pages. The name comes from `/api/whoami`, which the
|
||||
dashboard's nginx vhost proxies to authelia, and the links from
|
||||
`state.authelia_public_url`, which hive-c0re reads from
|
||||
`HIVE_AUTHELIA_PUBLIC_URL` (set from `services.hyperhive.swarm.authelia.url`).
|
||||
If the name doesn't load the avatar shows a question mark, and without the URL the
|
||||
popover has no links.
|
||||
- **Tab strip**: `◆ 4G3NTS ◆`, `◆ R3BU1LD QU3U3 ◆`,
|
||||
`◆ K3PT ST4T3 ◆`.
|
||||
- **Banner-thin** (`░▒▓█▓▒░ HYPERHIVE / HIVE-C0RE / WE ARE THE WIRED ░▒▓█▓▒░`)
|
||||
— sits below the tab strip.
|
||||
- **No warning banner.** No page shows hive-level warnings (host disk
|
||||
pressure, failing background sweeps, forge boot failures, agents that
|
||||
need a claude login). They live in a push-based registry
|
||||
(`hive-c0re`'s `warnings.rs`): any subsystem raises or clears its own
|
||||
entry through an RAII guard, and each raise logs one
|
||||
`hive warning raised` line. The operator sees the registry as metrics and
|
||||
Grafana alerts: see
|
||||
[Hive-scoped metrics](../../4-implementation/scheduler/observability.md#hive-scoped-metrics-hive-c0re).
|
||||
A container crash is a swarm-level Grafana alert on the crash watcher's
|
||||
own log line, so a hive with no otel export has no operator-visible
|
||||
warning signal beyond `/health/ready`.
|
||||
- **Browser tab title** — `hyperhive // h1ve-c0re` by default; updated
|
||||
to `<swarm> / <hive> // h1ve-c0re` once `hive_name` / `swarm_name`
|
||||
arrive in the state snapshot.
|
||||
|
||||
## 4G3NTS tab
|
||||
|
||||
**C0NTAINERS** — live containers as a flat list, one row per
|
||||
container, sorted alphabetically by agent name; every container the
|
||||
rescan reports gets a row. Pulsing red banner at the top
|
||||
of this section if any two sub-agents hash to the same port
|
||||
(`port_conflicts` from `/api/state`): the operator must rename
|
||||
one of them and rebuild. `lifecycle::{spawn,rebuild}` also
|
||||
preflight this and refuse with a clear error message naming the
|
||||
conflicting agent.
|
||||
|
||||
## K3PT ST4T3 tab
|
||||
|
||||
Passive / rare-interaction state. `kept.js` renders it from the
|
||||
`/api/state` snapshot and keeps it live from the `tombstones_changed`
|
||||
stream event. (The rebuild queue and build logs are dashboard tabs too —
|
||||
see below.)
|
||||
|
||||
Per-container CPU, memory and disk load isn't shown in the hive UI. The
|
||||
same figures go out as OTEL metrics and appear in Grafana (see
|
||||
[observability](../../4-implementation/scheduler/observability.md)). An agent's CPU and memory
|
||||
caps live per agent in the swarm UI.
|
||||
|
||||
**K3PT ST4T3** — agents with kept state and **no container** (size + age +
|
||||
claude-creds badge). One action: `PURG3` (wipes the state
|
||||
dir; `POST /api/purge-tombstone/{name}`).
|
||||
|
||||
⚠️ **Not only *destroyed* agents.** Nothing records a destroy: `Provision`
|
||||
writes every definition-side artifact (state subvolume,
|
||||
meta registration, topology entry) *before* the container exists,
|
||||
and that artifact set survives `lifecycle::destroy`. An agent
|
||||
part-way through a spawn is byte-identical on disk to a tombstone, and
|
||||
the pane lists both. The pane carries a standing warning to that effect, and
|
||||
the row badge says `offline` rather than `destroyed` — the absence of a
|
||||
container is all hive-c0re can actually prove. Fixing it properly
|
||||
needs a recorded destroy — **deferred** to the swarm-controller /
|
||||
snapshot-storage rework where the problem changes shape.
|
||||
|
||||
## Build tab (`#rebuild`)
|
||||
|
||||
The rebuild queue is the **R3BU1LD QU3U3** tab (`#rebuild`). It lives in `builds.js`, which `tabs.js` imports: the
|
||||
dashboard's one tab strip, `/api/state` snapshot and
|
||||
`/api/dashboard/stream` subscription serve them, with
|
||||
`rebuild_queue_changed` on the stream alongside the dashboard's other
|
||||
kinds.
|
||||
The 4G3NTS tab does **not** read the graph endpoint, by design — the swarm
|
||||
view stays independent of job-queue internals. Its per-agent pending
|
||||
badges are transient-only, and its queue-summary banner reads the much
|
||||
narrower `GET /api/jobq/rollup` instead (see Container row, below) — a
|
||||
handful of pre-tallied counts, not the graph. The banner's "view queue →"
|
||||
link goes to the `#rebuild` tab.
|
||||
|
||||
**R3BU1LD QU3U3** — pending, in-flight, and recently settled container
|
||||
operations: rebuilds and first-spawns. One
|
||||
operation runs at a time; the worker drains FIFO. **Is a mounted
|
||||
`JobqGraph`** (the shared generic graph-viewer Preact component,
|
||||
`@hive/shared/jobq-graph.js` — the same one swarm-ui uses) —
|
||||
`builds.js` doesn't render the queue itself; it just mounts the component
|
||||
(`mountJobqGraph(container, props)`, since this page has no JSX
|
||||
pipeline) with an `onUpdate` callback to drive the two things below it
|
||||
that the generic view doesn't show. The component owns fetching, cold
|
||||
and live: `GET /api/jobq/graph` on mount, and a refetch via the mount
|
||||
handle's `.refresh()` on every `rebuild_queue_changed` SSE tick (that
|
||||
event is a bare `{ seq }` trigger carrying no queue payload; both
|
||||
dashboard pages treat the tick as a pure refetch trigger).
|
||||
|
||||
Each row is one root graph node (`parent: null`); a multi-step op's
|
||||
per-agent subgraphs and sub-steps render as nodes within that one
|
||||
entry (structural `parent` edges define the tree; sibling order is
|
||||
array order, unchanged from the wire). A row shows a state glyph (`⏸`
|
||||
pending / `▶` running / `◐` finishing — own work done, a sub-node
|
||||
still running / `✔` done / `✖` failed / `⊘` cancelled / `·` skipped)
|
||||
and each step's own label/agent. A `Node`-kind dep on a sibling shows
|
||||
as a plain "waits on: `<label>`" text line under the row rather than a
|
||||
gutter rail — a rail breaks visually whenever a nested subtree sits
|
||||
between the two related rows, since a text line needs no continuous
|
||||
vertical space to draw.
|
||||
`builds.js` mounts the component with `cancellable` set, which turns on
|
||||
a per-node cancel button (`✕`) on any non-terminal row — the button
|
||||
calls the mount's `onCancel(id)` callback, and the page does the actual
|
||||
`POST /api/rebuild-queue/{id}/cancel`, matching that callback to its
|
||||
own domain concept (the component knows nothing about that endpoint).
|
||||
**Rows carry no source chip, kind label, timing, or build-log
|
||||
deep-link** — the generic graph wire doesn't carry those fields, and
|
||||
rows deliberately present exactly what the endpoint provides rather
|
||||
than reconstructing chrome hive-c0re doesn't send. Settled entries
|
||||
render their **full step tree**, not just a bare summary — the wire
|
||||
doesn't filter `Done` nodes out.
|
||||
|
||||
**State filter.** A row of per-state checkboxes above
|
||||
the tree — one per lifecycle state, matching the row glyphs — lets the
|
||||
operator narrow which root groups render; unchecking a state re-fetches
|
||||
`GET /api/jobq/graph?states=<checked, comma-joined>` rather than
|
||||
hiding rows client-side, so the `onUpdate` callback's node list (and
|
||||
everything downstream of it) only
|
||||
ever sees what's actually shown. Filtering is by a **root's own**
|
||||
state, which is already its subtree's rolled-up answer, so the filter
|
||||
keeps or drops a whole group, never splitting mid-tree. Default selection is
|
||||
every state **except** `Done`/`Skipped` — a fresh queue view leads
|
||||
with what's still moving or needs attention, not the settled tail;
|
||||
builds.js omits the `states` param entirely (identical request to
|
||||
before this filter existed) when the operator has checked every state. Server-side: the query
|
||||
narrows [`Queue::graph_snapshot`]'s already-bounded (`MAX_HISTORY_DAGS`)
|
||||
root set — the history cap and the state filter are independent
|
||||
concerns, so a narrow filter never reaches further back in time to
|
||||
compensate.
|
||||
|
||||
A build's output and history aren't on this page. hive-c0re logs every container build
|
||||
to the journal, and the swarm's `builds` Grafana board reads those lines: the builds with
|
||||
their outcome and runtime, and the output of the one you pick.
|
||||
|
||||
## Container row
|
||||
|
||||
A full-height **square agent icon** (5em, capped) on the left. The
|
||||
icon is the **selection toggle**: select (or Enter/Space) adds/removes
|
||||
the agent from the selection set; `aria-pressed` reflects the state;
|
||||
the tooltip says "select … for bulk actions" or "deselect … (or press
|
||||
Esc to clear all)." The `<img>` points at `<url>/icon`; load failure
|
||||
falls back to the dimmed hyperhive mark (`/favicon.svg`). The card
|
||||
body sits to the right with three stacked lines
|
||||
(`assets/agents.js::renderContainers`).
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
**Icon layout + load strategy:** the `<img>` is absolutely
|
||||
positioned (`inset: 0`) inside the `.container-icon` wrapper —
|
||||
the wrapper is the flex child and sizes itself via `width: 5em` +
|
||||
`aspect-ratio: 1`, the `<img>` is out of flow so its load state
|
||||
(pending, loaded, broken) can never contribute intrinsic size or
|
||||
reflow the row. Without that, the row would briefly grow as the
|
||||
image's natural dimensions arrived, then snap back on
|
||||
`object-fit: contain`. The load itself is fire-and-forget: the
|
||||
dashboard doesn't pre-check whether the agent is reachable, it
|
||||
just lets the `<img>` try and listens for an `error` event. On
|
||||
failure the handler swaps the `src` to `/favicon.svg` (served by
|
||||
the dashboard itself, always reachable) and adds the
|
||||
`icon-unreachable` class for the dimmed look. When the dashboard
|
||||
already knows the container is stopped (`ContainerView.running = false`)
|
||||
the fallback fires immediately, skipping the doomed `<url>/icon`
|
||||
fetch entirely.
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
**Line 1** — agent name (link → new tab), m1nd/ag3nt chip, an
|
||||
**icon-only nav strip** plus live agent-owned state, all populated
|
||||
async from a single `GET /api/dashboard-state` call to the agent's
|
||||
own hive-agent. The response (`DashboardState`) carries: `links` (nav
|
||||
strip entries — `📊 stats`, `🖥 screen` when GUI is enabled, `⬡ forge
|
||||
profile`, `↳ agent-configs mirror`, plus any agent-declared
|
||||
`dashboardLinks` extras), `status_text` / `status_set_at` (agent
|
||||
self-reported status — the `(set N ago)` chip carries a `data-set-at`
|
||||
stamp and ticks every 30s to stay fresh across the long-lived keyed row
|
||||
cache), `rate_limited`, `ctx_tokens` / `context_window_tokens`
|
||||
(context-window badge data). hive-agent is the single source
|
||||
of truth for all of these. The dashboard resolves each `AgentLink.kind`
|
||||
against a per-agent base URL depending on whether hive-gateway is in
|
||||
front (`StateSnapshot.gateway_enabled`, sourced from the
|
||||
`HIVE_GATEWAY_ENABLED` env). The c0re NixOS module sets that env
|
||||
unconditionally — the gateway always runs; the flag stays so the
|
||||
dashboard doesn't have to learn that. Gateway-on: base URL is
|
||||
`/agent/<name>` (same origin, gateway proxies to the
|
||||
per-agent harness — TCP or unix-domain depending on the agent's
|
||||
`HIVE_WEB_SOCKET` opt-in, see
|
||||
`docs/4-implementation/networking/gateway.md::Per-agent unix-socket upstream`).
|
||||
Gateway-off is the flag-absent fallback (a dashboard served outside a
|
||||
hyperhive deploy): base URL is
|
||||
`http://<host>:<container.port>` (direct TCP). Forge
|
||||
links resolve against `state.forge_public_url` (sourced from
|
||||
`services.hyperhive.swarm.forge.publicUrl`) and disappear entirely when
|
||||
that's unset — never guessed from `<host>:3000`. External links are
|
||||
already absolute. The same base URL drives the primary agent-name
|
||||
link + favicon fetch, so the whole row routes through the gateway
|
||||
as a unit.
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
**When the container is stopped** (`ContainerView.running = false`),
|
||||
the dashboard skips the async `dashboard-state` fetch entirely (the agent
|
||||
web server is down), so a single badge replaces the badge chain,
|
||||
the nav strip is empty, and status text / rate-limited / ctx
|
||||
badges disappear. The agent icon goes straight to the dimmed
|
||||
`/favicon.svg` fallback instead of attempting a doomed load from the
|
||||
container's URL. Static fields — `pending_reminders`, `parent`, `config` link — remain visible
|
||||
regardless of run state.
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
**Line 2** — status badges only (no per-card action buttons — actions
|
||||
live in the **selection bar** or the **per-agent `⋮` menu**, see
|
||||
below).
|
||||
|
||||
### Status badges
|
||||
|
||||
**Which single badge:** `ContainerView.failed`
|
||||
(systemd `ActiveState=failed` — the unit exhausted its bounded
|
||||
restarts and gave up on its own) draws a red `✖ gave up` badge;
|
||||
otherwise a plain muted `■ not running` — a container an operator
|
||||
stopped deliberately. Both states read `running: false`; `failed` is
|
||||
the orthogonal fact (a fourth one alongside `paused`/
|
||||
`needs_login`, same "independent flags, no state machine" shape —
|
||||
see `ContainerView`'s own doc comment) that tells them apart. An
|
||||
older hive-c0re without the field serves `failed: undefined`, which
|
||||
reads falsy — degrades cleanly to the single `not running` badge.
|
||||
|
||||
When the container is running, status badges follow — `⊘ rate
|
||||
limited` (red, while the harness parks itself after a 429), `needs
|
||||
login` — plus **one `◐ pending-state…` pill per
|
||||
active transient** (replaces buttons during operator-initiated
|
||||
start / stop / restart / rebuild / destroy). An agent can carry
|
||||
**multiple transients at once** — for example a lease-exempt `prebuild`
|
||||
running alongside a `stop_for_update` on the same agent — and each
|
||||
renders as its own independent badge instead of collapsing
|
||||
into one label, matching the existing multi-badge convention this
|
||||
line already uses for `paused`/model/ctx.
|
||||
|
||||
Any pending badge means the row is actually **running** something
|
||||
right now (see **Pending-badge derivation** below); every row
|
||||
carrying ≥1 badge keeps the amber row tint AND draws a **rotating
|
||||
amber ring** around the agent icon.
|
||||
|
||||
**Pending-badge derivation:** transients only (`transientsState`,
|
||||
keyed `agent -> Map<kind, since_unix>`) — a transient is **derived
|
||||
from a job-queue node currently `Running`** against that agent, not
|
||||
declared per request, so its label follows the operation as it
|
||||
progresses (a rebuild reads `stop_for_update`, then `swap`, then
|
||||
`reconcile` rather than one constant `rebuilding` for its whole
|
||||
life). Two consequences for anything rendering it:
|
||||
|
||||
- The label vocabulary is **open** — it's the node's own wire tag
|
||||
(`NodeKind`'s `&str` conversion, the same strings the graph wire's node
|
||||
labels carry), not a fixed set. Treat it as an opaque display
|
||||
string; don't switch on specific values.
|
||||
- It's **not** exclusively operator-initiated, and **not** limited
|
||||
to rebuild-shaped work — `running_transients()` in hive-c0re is
|
||||
a status-only test (any `Running` node whose payload names a
|
||||
non-empty agent lights a pill), so work the operator never
|
||||
triggered (a crash-recover rebuild, a boot-sweep rebuild, a
|
||||
lease-exempt `prebuild`) lights the same mechanism.
|
||||
|
||||
Ops with no queue node behind them (destroy, migration) supply
|
||||
their own label directly via `TransientSet`/`TransientCleared`
|
||||
events carrying no backing node at all.
|
||||
|
||||
**Queued (not-yet-started) work shows nothing on the card.** Only
|
||||
running work gets a per-agent pending badge, by design — the swarm
|
||||
view stays independent of job-queue internals. The queue-summary
|
||||
banner below is the only queued-work indicator on this tab, and it
|
||||
reads the narrow `/api/jobq/rollup` endpoint rather than the full
|
||||
graph.
|
||||
|
||||
**Active model badge** (`model · <name>`, blue) appears when the
|
||||
container is running and the harness has persisted a model name (the
|
||||
`active_model` field of `hyperhive-harness.json`, the consolidated
|
||||
harness state file in the agent's state dir). Read by hive-c0re's
|
||||
`ContainerView` (`read_active_model`); absent until the agent has
|
||||
completed at least one turn, and hive-c0re suppresses stale values
|
||||
for stopped containers.
|
||||
|
||||
**`ctx · Nk` chip** shows the agent's last-turn context size,
|
||||
populated from `DashboardState.ctx_tokens` (absent until the
|
||||
agent has completed at least one turn). The chip colour (green /
|
||||
yellow / red) keys off `DashboardState.context_window_tokens`
|
||||
(the real context window for the model the agent last ran on,
|
||||
authoritative from the agent side); the badge goes yellow ≥ 50%
|
||||
and red ≥ 75% of that window, matching the harness compaction
|
||||
watermarks. When the window value is absent the badge falls back
|
||||
to fixed 100k / 150k thresholds.
|
||||
|
||||
**Per-agent `⋮` overflow menu** — a `⋮` button appears on the right
|
||||
edge of each container row. Selecting it opens a small dropdown with
|
||||
per-agent actions and navigation links. Contents:
|
||||
|
||||
- `↺ R3ST4RT` (running agents only) / `■ ST0P` (running only) /
|
||||
`▶ ST4RT` (stopped only) — single-agent run-state toggles.
|
||||
Identical to the bulk actions on the selection bar but operate
|
||||
on one agent without requiring a selection.
|
||||
- `↻ R3BU1LD` — always available; queues a rebuild for this agent.
|
||||
- `DESTR0Y` / `PURG3` — destructive, each prompts for confirmation
|
||||
via the themed dialog (see **Themed dialogs** below).
|
||||
|
||||
**Build-queue summary banner** — when the job queue has any active
|
||||
work, a compact amber banner sits above the container list: `◐ build
|
||||
queue — N running · M queued — view queue →` (the link goes to the
|
||||
R3BU1LD QU3U3 tab). The shared `JobqRollup` Preact component
|
||||
(`@hive/shared/jobq-rollup.js` — the same one swarm-ui's `/jobs` page
|
||||
mounts, pointed at swarm-controller's own rollup endpoint instead),
|
||||
mounted once into `#jobq-rollup-section` by `agents.js::initJobqRollup`
|
||||
and refreshed via its own handle rather than being re-rendered by
|
||||
`renderContainers`. Reads `GET /api/jobq/rollup`
|
||||
(`hive-jobq-wire::state_rollup`) — `Vec<{ state, nodes, roots }>`,
|
||||
every lifecycle state present in a fixed order, zero counts included —
|
||||
rather than the full `/api/jobq/graph` tree: `running` sums the
|
||||
`Running` and `Finishing` entries' `roots` (`Finishing` = own work
|
||||
done, subtree still going, still in flight), `queued` reads the
|
||||
`Pending` entry's `roots`. `roots` specifically, not `nodes` — the
|
||||
banner means *N whole operations*, not raw steps (one rebuild is ~7
|
||||
nodes but 1 root); `nodes` exists on the same endpoint for a consumer
|
||||
that wants step-level counts instead, unused here.
|
||||
|
||||
### Themed dialogs
|
||||
|
||||
All confirmations and transient error notices use an in-app themed
|
||||
dialog system (`@hive/shared/modal.js`) rather than the browser's
|
||||
native `confirm()` / `alert()` chrome, so they match the Catppuccin
|
||||
palette and the OS can't style them away. Two primitives, both built
|
||||
on the `openDialog` core:
|
||||
|
||||
- `themedConfirm({ message, danger, confirmLabel, checkboxes })`
|
||||
— a modal confirm that resolves to `null` on cancel or an object
|
||||
of checkbox states on confirm. Destructive actions pass
|
||||
`danger: true` (the confirm button turns red and the cancel
|
||||
button takes focus). Selecting the backdrop and `Esc` both cancel.
|
||||
- `themedToast(message, { type, ... })` — a non-blocking toast (top-right,
|
||||
`info` / `error` / `ok`) for transient validation + action
|
||||
failures, so an error doesn't lock the operator behind a modal.
|
||||
Single-action errors autodismiss; bulk / partial-failure
|
||||
summaries are sticky (select to dismiss) so they aren't missed.
|
||||
|
||||
Every destructive run-state action (`ST0P`, `R3ST4RT`, `R3BU1LD`,
|
||||
`DESTR0Y`, `PURG3`) routes through `themedConfirm`, on both
|
||||
the per-agent `⋮` menu and the bulk selection bar.
|
||||
|
||||
**Graceful stop** — the `■ ST0P` confirm dialog (per-agent and
|
||||
bulk) carries a `stop gracefully — let the agent finish its turn
|
||||
and flush state before the container stops` checkbox. When ticked,
|
||||
the action POSTs `/api/kill/<name>?graceful=true` (the bulk path
|
||||
appends the flag per-agent); unticked is the instant hard stop
|
||||
(`/api/kill/<name>` with no query). hive-c0re enqueues a
|
||||
`Signal` → `Drain` job-queue node pair (`NodeKind::Signal` /
|
||||
`NodeKind::Drain`): `Signal` sets the graceful-stop fence and kicks
|
||||
the harness so it runs one stop-checkpoint turn (so the agent can
|
||||
flush `/state`); `Drain` awaits the harness clearing that fence,
|
||||
bounded by a 3-minute timeout (`GRACEFUL_STOP_TIMEOUT`) that
|
||||
resolves either way and falls back to the downstream mechanical
|
||||
stop. The quiescing progress surfaces through the same
|
||||
rebuild-queue pending-badge mechanism the card already reads for a
|
||||
rebuild, driven by the `Signal`/`Drain` pair rather than a nix
|
||||
build. (The `hivectl stop --graceful` CLI flag enqueues the same
|
||||
`Signal`/`Drain` pair, so the dashboard and CLI paths behave
|
||||
identically.)
|
||||
|
||||
## Selection bar
|
||||
|
||||
Bulk actions (`R3ST4RT` / `ST0P` / `ST4RT` / `P4US3` / `R3SUM3` /
|
||||
`R3BU1LD` / `DESTR0Y` / `PURG3`) live here rather than as per-card
|
||||
buttons — see **Container row** above. Selecting an agent's icon
|
||||
toggles its selection (an in-memory `Set<name>`); `Esc` or the bar's
|
||||
`✕ clear` button drops everything. The selection persists across tab
|
||||
switches in-memory — the bar just hides on non-4G3NTS tabs since other
|
||||
tabs don't show the agent cards needed to cross-reference.
|
||||
|
||||
When the operator selects one or more agents (via the icon), a sticky
|
||||
frosted-mauve bar slides up from the bottom of the viewport
|
||||
(`#selection-bar`, `position: fixed; bottom: 0`). It shows:
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
- **Count + names** — "N agents selected · name1, name2, …"
|
||||
- **Bulk action buttons** — only enabled when ALL selected agents
|
||||
support the action; greyed out with a tooltip naming the blockers
|
||||
when the selection is mixed:
|
||||
- `↺ R3ST4RT` — running agents only
|
||||
- `■ ST0P` — running agents only
|
||||
- `▶ ST4RT` — stopped agents only
|
||||
- `⏸ P4US3` — unpaused agents only (orthogonal to running/stopped —
|
||||
see **Container row**'s own pause/resume note)
|
||||
- `▶ R3SUM3` — paused agents only
|
||||
- `↻ R3BU1LD` — always available
|
||||
- `DESTR0Y` / `PURG3` — always available
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
That list is the whole set — the bar offers no other bulk action.
|
||||
- **`✕ clear`** button + `Esc` key clear the entire selection.
|
||||
|
||||
Every render prunes stale selections (agents destroyed while
|
||||
selected) before the bar appears.
|
||||
|
||||
## Dashboard endpoints
|
||||
|
||||
Also browsable interactively at `/api/docs` (a Swagger UI, linked from
|
||||
the pages menu's **api docs** entry), with the raw spec at `/api/openapi.json`.
|
||||
It's a growing supplement, not yet a full replacement for the list
|
||||
below — some endpoints aren't in it yet.
|
||||
|
||||
- `POST /api/{rebuild,kill,restart,start,destroy}/{name}` — lifecycle.
|
||||
`destroy` accepts `purge=on` to also wipe state dirs.
|
||||
- `POST /api/purge-tombstone/{name}` — wipe a tombstone's state dirs.
|
||||
- `POST /api/rebuild-queue/{id}/cancel` — drop a `Queued` entry.
|
||||
Refuses `Running` / terminal-state entries (in-flight
|
||||
rebuilds can't be safely interrupted). Always 200; body is
|
||||
`{"cancelled": true}` on a successful flip or
|
||||
`{"cancelled": false}` when the entry wasn't in `Queued` state.
|
||||
- `POST /api/agent/{name}/mark-all-read` — ack all pending broker
|
||||
messages for `{name}`. Backfills `delivered_at` for rows
|
||||
not yet delivered and sets `acked_at = now`. Returns
|
||||
`{ "marked": N }`. Agent name validated against
|
||||
`[a-z0-9_-]`, 1-63 chars; 400 on bad input.
|
||||
- `GET /api/build-logs/{agent}?limit=N` — most-recent build log
|
||||
headers for one agent, newest first. Returns
|
||||
`Vec<BuildLogHeader>` (JSON): `id`, `agent`, `kind`, `cmdline`,
|
||||
`started_at`, `finished_at`, `status` (`"ok"` / `"fail"` /
|
||||
`null` while in-progress). `limit` defaults to 10, server-side
|
||||
cap at 50. Agent name validated (`[a-z0-9_-]`, 1-63 chars).
|
||||
- `GET /api/build-logs/id/{id}` — full build log by id. Returns
|
||||
`BuildLogFull` (JSON): all header fields plus `stdout` and
|
||||
`stderr` as plain text (newline-terminated lines, utf-8). HTTP
|
||||
404 when the row is missing (vacuum-reaped or stale id).
|
||||
- `GET /api/build-logs/id/{id}/stream` — live SSE stream of
|
||||
stdout+stderr for an in-progress build (newline-delimited JSON
|
||||
frames). The
|
||||
stream closes when the build finishes or errors.
|
||||
- `GET /api/build-logs/id/{id}/raw` — raw concatenated
|
||||
stdout+stderr as `text/plain`. Works on both finished and in-progress
|
||||
build logs.
|
||||
- `GET /api/reminders` — list pending reminders for the
|
||||
dashboard's queued-reminders panel.
|
||||
- `POST /api/cancel-reminder/{id}` — hard-delete a pending reminder.
|
||||
- `POST /api/retry-reminder/{id}` — re-arm a reminder whose delivery
|
||||
failed (clears the failure state so the scheduler retries).
|
||||
|
||||
- `GET /api/dashboard/stream` — unified live event channel:
|
||||
broker `sent` / `delivered`, plus the mutation events listed
|
||||
below. Each frame carries `seq`.
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
## Dashboard event channel
|
||||
|
||||
Wire vocabulary on `/api/dashboard/stream` (kind tag is in the JSON
|
||||
payload):
|
||||
|
||||
- `sent` / `delivered` — broker traffic, mirrored from the
|
||||
intra-process channel by a forwarder task. Both carry `id: i64`
|
||||
(the broker row id) and `in_reply_to: Option<i64>` for thread
|
||||
rendering.
|
||||
- `transient_set` (name, transient_kind, since_unix) /
|
||||
`transient_cleared` (name) — lifecycle action spinners. The
|
||||
client ticks the elapsed-seconds badge off `since_unix`
|
||||
client-side, no polling. `transient_kind` is an **open**
|
||||
display string (the running node's own tag), not a fixed
|
||||
enum — render it, don't branch on it.
|
||||
- `container_state_changed` (container: ContainerView) /
|
||||
`container_removed` (name) — per-row container mutations,
|
||||
emitted by `Coordinator::rescan_containers_and_emit` from
|
||||
the job queue's own node execution (`job_queue::exec`, for example
|
||||
after a rebuild's stop/swap/start steps or a destroy's teardown
|
||||
step) — and from the 10s
|
||||
`crash_watch` poll. Client upserts/removes by name and
|
||||
reads the pending overlay from `transientsState` since the
|
||||
payload doesn't carry it.
|
||||
- `rebuild_queue_changed` (seq) — **payload-free trigger**, fired on
|
||||
every queue mutation (enqueue, state transition, dedup collapse,
|
||||
terminal-history trim). Unlike the snapshot events below it ships
|
||||
no state at all: the client re-fetches `GET /api/jobq/graph`, which
|
||||
is where it reads the queue from cold too.
|
||||
- `reminders_changed` (seq, reminders: `Vec<PendingReminder>`) —
|
||||
full snapshot of all pending reminders. Emitted after every
|
||||
reminder mutation: agent `remind` calls (`agent_server`),
|
||||
operator cancel / retry (`/api/system/reminders/*`), `cancel_loose_end`
|
||||
with Reminder kind, and the scheduler tick after each delivery
|
||||
batch (`reminder_scheduler`).
|
||||
- `tombstones_changed` (seq, tombstones: `Vec<TombstoneView>`) —
|
||||
full snapshot of destroyed-but-state-kept agents. Emitted on
|
||||
destroy, purge, and revive. The K3PT ST4T3 tab subscribes.
|
||||
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
`/api/state` is **only fetched on cold-load and on the few
|
||||
forms that mutate non-event-derived state** (PURG3, since
|
||||
tombstones aren't event-shaped yet). Every other section — transients,
|
||||
containers —
|
||||
derives from `/api/dashboard/stream` after the initial snapshot,
|
||||
maintaining its own client-side store and applying events on
|
||||
top.
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
Generalised form helper: `form[data-confirm="…"]` pops
|
||||
`confirm()` before submit.
|
||||
|
||||
503
docs/2-handbook/hives/hivectl-cli.md
Normal file
503
docs/2-handbook/hives/hivectl-cli.md
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
# Command-Line Help for `hivectl`
|
||||
|
||||
This document contains the help content for the `hivectl` command-line program.
|
||||
|
||||
**Command Overview:**
|
||||
|
||||
* [`hivectl`↴](#hivectl)
|
||||
* [`hivectl agent`↴](#hivectl-agent)
|
||||
* [`hivectl agent restart`↴](#hivectl-agent-restart)
|
||||
* [`hivectl agent pause`↴](#hivectl-agent-pause)
|
||||
* [`hivectl agent resume`↴](#hivectl-agent-resume)
|
||||
* [`hivectl agent start`↴](#hivectl-agent-start)
|
||||
* [`hivectl agent stop`↴](#hivectl-agent-stop)
|
||||
* [`hivectl agent kill`↴](#hivectl-agent-kill)
|
||||
* [`hivectl agent destroy`↴](#hivectl-agent-destroy)
|
||||
* [`hivectl agent rebuild`↴](#hivectl-agent-rebuild)
|
||||
* [`hivectl agent choom`↴](#hivectl-agent-choom)
|
||||
* [`hivectl agent watch`↴](#hivectl-agent-watch)
|
||||
* [`hivectl agent quota`↴](#hivectl-agent-quota)
|
||||
* [`hivectl agent quota show`↴](#hivectl-agent-quota-show)
|
||||
* [`hivectl agent quota set`↴](#hivectl-agent-quota-set)
|
||||
* [`hivectl agent subvol`↴](#hivectl-agent-subvol)
|
||||
* [`hivectl agent subvol upgrade`↴](#hivectl-agent-subvol-upgrade)
|
||||
* [`hivectl agent subvol snapshot`↴](#hivectl-agent-subvol-snapshot)
|
||||
* [`hivectl agent subvol snapshot create`↴](#hivectl-agent-subvol-snapshot-create)
|
||||
* [`hivectl agent subvol snapshot delete`↴](#hivectl-agent-subvol-snapshot-delete)
|
||||
* [`hivectl agent subvol snapshot send`↴](#hivectl-agent-subvol-snapshot-send)
|
||||
* [`hivectl agent subvol snapshot push`↴](#hivectl-agent-subvol-snapshot-push)
|
||||
* [`hivectl list-agents`↴](#hivectl-list-agents)
|
||||
* [`hivectl quota-enable`↴](#hivectl-quota-enable)
|
||||
* [`hivectl wg`↴](#hivectl-wg)
|
||||
* [`hivectl wg init`↴](#hivectl-wg-init)
|
||||
* [`hivectl wg peer`↴](#hivectl-wg-peer)
|
||||
* [`hivectl wg status`↴](#hivectl-wg-status)
|
||||
* [`hivectl peer-config`↴](#hivectl-peer-config)
|
||||
* [`hivectl stop`↴](#hivectl-stop)
|
||||
* [`hivectl start`↴](#hivectl-start)
|
||||
* [`hivectl restart`↴](#hivectl-restart)
|
||||
* [`hivectl completions`↴](#hivectl-completions)
|
||||
|
||||
## `hivectl`
|
||||
|
||||
Sibling to the `hive-c0re` daemon binary. Covers host-side admin operations that don't go through the broker, plus future recovery / debugging verbs.
|
||||
|
||||
**Usage:** `hivectl [OPTIONS] <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `agent` — Lifecycle actions on ONE managed agent container. Needs the hive-c0re daemon running
|
||||
* `list-agents` — Show all managed agents with their status and technical state
|
||||
* `quota-enable` — Enable btrfs qgroup accounting on the agent-state filesystem
|
||||
* `wg` — WireGuard inter-hive mesh setup helpers
|
||||
* `peer-config` — Generate the federation peer-config block for THIS hive
|
||||
* `stop` — Stop containers hive-wide in one operator action
|
||||
* `start` — Start containers hive-wide — the inverse of `hivectl stop`
|
||||
* `restart` — Restart containers hive-wide — `stop` then `start` over one scope
|
||||
* `completions` — Generate a shell completion script for `hivectl` and print it to stdout
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--socket <SOCKET>` — Path to the hive-c0re host admin socket, used by the daemon-assisted verbs (`agent`, `list-agents`, `stop`, `start`). Global: accepted before or after the subcommand. Verbs that don't talk to the daemon ignore it
|
||||
|
||||
Default value: `/run/hyperhive/host.sock`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent`
|
||||
|
||||
Lifecycle actions on ONE managed agent container. Needs the hive-c0re daemon running.
|
||||
|
||||
Everything here targets a single named agent (`hivectl agent foo restart`, `hivectl agent foo choom`, …) — anything that acts hive-wide lives at the top level instead (`list-agents`, `restart`/`stop`/`start` with a scope, `quota-enable`).
|
||||
|
||||
**Usage:** `hivectl agent <NAME> <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `restart` — Stop and start this agent container without rebuilding config
|
||||
* `pause` — Park this agent's turn loop, leaving the container running
|
||||
* `resume` — Resume this paused agent — it drains whatever queued up while parked
|
||||
* `start` — Start this EXISTING agent container. Fails immediately if `name` has no config/topology entry at all — it never attempts first-time creation, which is swarm-level (`swarmctl agent create`)
|
||||
* `stop` — Gracefully stop this agent container: signal → drain → reconcile. Never escalates to a hard kill — use `kill` for that
|
||||
* `kill` — Hard-stop this managed container
|
||||
* `destroy` — Tear down this sub-agent container, keeping its state by default. No undo
|
||||
* `rebuild` — Apply pending config to this managed container
|
||||
* `choom` — Open an interactive Claude session inside this agent's container
|
||||
* `watch` — Follow this agent's live turn/tool-call event stream from the CLI
|
||||
* `quota` — This agent's disk accounting + optional quota via btrfs qgroups
|
||||
* `subvol` — btrfs subvolume management for this agent's state dir
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<NAME>` — Agent name (for example `damocles`, `iris`)
|
||||
|
||||
|
||||
|
||||
## `hivectl agent restart`
|
||||
|
||||
Stop and start this agent container without rebuilding config
|
||||
|
||||
**Usage:** `hivectl agent restart [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--no-wait` — Return immediately after hivectl queues the restart DAG
|
||||
|
||||
|
||||
|
||||
## `hivectl agent pause`
|
||||
|
||||
Park this agent's turn loop, leaving the container running.
|
||||
|
||||
The harness stops driving turns but keeps serving its web UI and MCP daemons, so the container, its mounts and its warm caches stay up while it burns no tokens. Inbox messages queue unacked and the backlog drains on `resume`. Sticky: it survives a restart, and pausing a stopped agent makes it come up paused.
|
||||
|
||||
**Usage:** `hivectl agent pause [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--no-wait` — Return immediately after hivectl queues the pause DAG instead of waiting for the harness to acknowledge it
|
||||
|
||||
|
||||
|
||||
## `hivectl agent resume`
|
||||
|
||||
Resume this paused agent — it drains whatever queued up while parked
|
||||
|
||||
**Usage:** `hivectl agent resume`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent start`
|
||||
|
||||
Start this EXISTING agent container. Fails immediately if `name` has no config/topology entry at all — it never attempts first-time creation, which is swarm-level (`swarmctl agent create`)
|
||||
|
||||
**Usage:** `hivectl agent start [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--paused` — Start (or leave) the agent paused: if it's currently down, hivectl writes the pause marker before the container boots, so it comes up paused instead of driving turns immediately. If it's already running, this pauses it in place and doesn't attempt a (re)start
|
||||
|
||||
|
||||
|
||||
## `hivectl agent stop`
|
||||
|
||||
Gracefully stop this agent container: signal → drain → reconcile. Never escalates to a hard kill — use `kill` for that
|
||||
|
||||
**Usage:** `hivectl agent stop`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent kill`
|
||||
|
||||
Hard-stop this managed container
|
||||
|
||||
**Usage:** `hivectl agent kill`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent destroy`
|
||||
|
||||
Tear down this sub-agent container, keeping its state by default. No undo
|
||||
|
||||
**Usage:** `hivectl agent destroy [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--purge` — Also wipe the agent's state dirs (config + creds + notes)
|
||||
|
||||
|
||||
|
||||
## `hivectl agent rebuild`
|
||||
|
||||
Apply pending config to this managed container
|
||||
|
||||
**Usage:** `hivectl agent rebuild`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent choom`
|
||||
|
||||
Open an interactive Claude session inside this agent's container.
|
||||
|
||||
A fresh session by default, or resume a prior one. Requires root or `hive-admin` group membership, plus a running container.
|
||||
|
||||
**Usage:** `hivectl agent choom [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--resume <SESSION>` — Resume a prior claude session by its session id, passed through as `claude --resume <value>` (claude's `--continue` takes no value — it resumes the cwd's latest session, which is the harness's, so choom never uses it; this flag matches the claude flag it maps to). Omit for a fresh blank session. Requires a value
|
||||
|
||||
|
||||
|
||||
## `hivectl agent watch`
|
||||
|
||||
Follow this agent's live turn/tool-call event stream from the CLI.
|
||||
|
||||
Prints one compact line per event as they happen. `Ctrl-C` to stop. Requires the agent to be running.
|
||||
|
||||
**Usage:** `hivectl agent watch`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent quota`
|
||||
|
||||
This agent's disk accounting + optional quota via btrfs qgroups.
|
||||
|
||||
Needs `hivectl quota-enable` run once hive-wide first. No-op on non-btrfs hosts.
|
||||
|
||||
**Usage:** `hivectl agent quota <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `show` — Report this agent's disk usage from btrfs qgroups
|
||||
* `set` — Set or clear this agent's disk-usage quota
|
||||
|
||||
|
||||
|
||||
## `hivectl agent quota show`
|
||||
|
||||
Report this agent's disk usage from btrfs qgroups
|
||||
|
||||
**Usage:** `hivectl agent quota show`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent quota set`
|
||||
|
||||
Set or clear this agent's disk-usage quota
|
||||
|
||||
**Usage:** `hivectl agent quota set <SIZE>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<SIZE>` — Size cap (`5G`, `500M`, `1073741824`) or `none` to clear
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol`
|
||||
|
||||
btrfs subvolume management for this agent's state dir.
|
||||
|
||||
Upgrade an existing plain-dir agent's state into a btrfs subvolume so it gains snapshots and per-subvol usage/quota.
|
||||
|
||||
**Usage:** `hivectl agent subvol <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `upgrade` — Convert a plain-dir agent state root into a btrfs subvolume in place, so it gains snapshots and per-subvol usage/quota
|
||||
* `snapshot` — Read-only snapshots of this agent's state subvolume
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol upgrade`
|
||||
|
||||
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`.
|
||||
|
||||
**Usage:** `hivectl agent subvol upgrade [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--yes` — Confirm: this stops the agent, migrates its state dir, and restarts it. Required — the command refuses without it
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol snapshot`
|
||||
|
||||
Read-only snapshots of this agent's state subvolume
|
||||
|
||||
**Usage:** `hivectl agent subvol snapshot <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `create` — Create a read-only snapshot (agent must already be a subvolume)
|
||||
* `delete` — Delete a snapshot created by `subvol snapshot create`
|
||||
* `send` — Export a snapshot to a local file via `btrfs send` — the local-file half of the inter-hive migration transport (`push` is the network half). Also useful standalone as a point-in-time backup: a full send with no `--parent` produces a self-contained archive of the snapshot
|
||||
* `push` — Stream a snapshot to the swarm's snapshot store over the WireGuard mesh — the network half of the migration transport
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol snapshot create`
|
||||
|
||||
Create a read-only snapshot (agent must already be a subvolume)
|
||||
|
||||
**Usage:** `hivectl agent subvol snapshot create --label <LABEL>`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--label <LABEL>` — Snapshot label. Mandatory, and must start with `hive-` — the prefix doubles as an allow-list hive-priv checks so only hivectl-issued snapshot names can reach the `btrfs subvolume snapshot` shellout
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol snapshot delete`
|
||||
|
||||
Delete a snapshot created by `subvol snapshot create`
|
||||
|
||||
**Usage:** `hivectl agent subvol snapshot delete <LABEL>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<LABEL>` — Snapshot label passed to `subvol snapshot create --label`
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol snapshot send`
|
||||
|
||||
Export a snapshot to a local file via `btrfs send` — the local-file half of the inter-hive migration transport (`push` is the network half). Also useful standalone as a point-in-time backup: a full send with no `--parent` produces a self-contained archive of the snapshot
|
||||
|
||||
**Usage:** `hivectl agent subvol snapshot send [OPTIONS] --dest <DEST> <LABEL>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<LABEL>` — Snapshot label passed to `subvol snapshot create --label`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--parent <PARENT>` — Optional parent snapshot label for an incremental send (`btrfs send -p`) — must be an existing, older snapshot of the same agent. Omit for a full send
|
||||
* `--dest <DEST>` — Destination filename (not a path) under the migrate-staging dir. Refused if it already exists
|
||||
|
||||
|
||||
|
||||
## `hivectl agent subvol snapshot push`
|
||||
|
||||
Stream a snapshot to the swarm's snapshot store over the WireGuard mesh — the network half of the migration transport.
|
||||
|
||||
Stages nothing locally: `btrfs send` writes straight into the connection, so a multi-gigabyte agent needs no scratch space on this host. The mesh is the authentication (cryptokey routing binds the sender's address to its key), so there is no credential to pass here.
|
||||
|
||||
No destination argument exists: a swarm has one store, read from `services.hyperhive.swarm.snapshotStore`.
|
||||
|
||||
**Usage:** `hivectl agent subvol snapshot push [OPTIONS] <LABEL>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<LABEL>` — Snapshot label passed to `subvol snapshot create --label`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--parent <PARENT>` — Optional parent snapshot label for an incremental send (`btrfs send -p`) — must be an existing, older snapshot of the same agent, and must already be present on the receiver. Omit for a full send
|
||||
|
||||
|
||||
|
||||
## `hivectl list-agents`
|
||||
|
||||
Show all managed agents with their status and technical state.
|
||||
|
||||
Global — not scoped to one agent, so it lives at the top level rather than under `hivectl agent <name>`. Needs the hive-c0re daemon running.
|
||||
|
||||
**Usage:** `hivectl list-agents [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--json` — Emit the raw JSON rows instead of the padded table (for scripting). The table is the default human-readable shape
|
||||
|
||||
|
||||
|
||||
## `hivectl quota-enable`
|
||||
|
||||
Enable btrfs qgroup accounting on the agent-state filesystem.
|
||||
|
||||
Global one-shot toggle (not per-agent), hence top-level rather than under `hivectl agent <name>`. Idempotent — safe to re-run. Once enabled, `hivectl agent <name> quota show`/`quota set` work.
|
||||
|
||||
**Usage:** `hivectl quota-enable`
|
||||
|
||||
|
||||
|
||||
## `hivectl wg`
|
||||
|
||||
WireGuard inter-hive mesh setup helpers.
|
||||
|
||||
Generate this hive's mesh key and print the nix to enable the mesh, add a peer, or inspect live interface state.
|
||||
|
||||
**Usage:** `hivectl wg <COMMAND>`
|
||||
|
||||
###### **Subcommands:**
|
||||
|
||||
* `init` — Generate this hive's WireGuard key (if absent) and print its public key plus the nix to enable the mesh
|
||||
* `peer` — Print the nix to add a peer hive to the mesh
|
||||
* `status` — Show the live mesh interface state
|
||||
|
||||
|
||||
|
||||
## `hivectl wg init`
|
||||
|
||||
Generate this hive's WireGuard key (if absent) and print its public key plus the nix to enable the mesh
|
||||
|
||||
**Usage:** `hivectl wg init [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--address <ADDRESS>` — This hive's mesh address (for example `10.42.0.1/32`) to bake into the printed snippet. Omit to get a placeholder you fill in
|
||||
|
||||
|
||||
|
||||
## `hivectl wg peer`
|
||||
|
||||
Print the nix to add a peer hive to the mesh
|
||||
|
||||
**Usage:** `hivectl wg peer [OPTIONS] --pubkey <PUBKEY> --address <ADDRESS> <DOMAIN>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<DOMAIN>` — Peer hive's DNS domain (its `swarm.hives` entry's `domain`)
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--pubkey <PUBKEY>` — Peer's WireGuard public key (from its `hivectl wg init`)
|
||||
* `--address <ADDRESS>` — Peer's mesh address (for example `10.42.0.2/32`)
|
||||
* `--endpoint <ENDPOINT>` — Peer's `host:port` endpoint (omit for a peer that only dials out, for example one behind NAT — it must set an endpoint pointing back here)
|
||||
|
||||
|
||||
|
||||
## `hivectl wg status`
|
||||
|
||||
Show the live mesh interface state
|
||||
|
||||
**Usage:** `hivectl wg status`
|
||||
|
||||
|
||||
|
||||
## `hivectl peer-config`
|
||||
|
||||
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.
|
||||
|
||||
**Usage:** `hivectl peer-config [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--wg-address <WG_ADDRESS>` — This hive's WireGuard mesh address (for example `10.42.0.1/32`), emitted as `wireguardAddress`. Omit when not running the mesh
|
||||
* `--wg-endpoint <WG_ENDPOINT>` — This hive's public WireGuard endpoint (`host:port`), emitted as `wireguardEndpoint`. Omit when peers dial in / no mesh
|
||||
|
||||
|
||||
|
||||
## `hivectl stop`
|
||||
|
||||
Stop containers hive-wide in one operator action.
|
||||
|
||||
Bare `hivectl stop` stops every agent and the gateway; scope flags narrow it to specific sub-agents or the gateway. The swarm's forge and matrix are never in scope: systemd on the services host runs them.
|
||||
|
||||
**Usage:** `hivectl stop [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--agents` — All sub-agent containers
|
||||
* `--agent <NAME>` — A specific sub-agent by name. Repeatable: `--agent a --agent b`
|
||||
* `--gateway` — The gateway (`hive-gateway`) — nginx on the host, not a container
|
||||
* `--graceful` — Gracefully quiesce each agent before stopping, instead of a hard stop. Each agent gets a graceful-stop DAG on the job queue: it signals the harness, which runs one stop-checkpoint turn to flush durable `/state` and drains, then the DAG stops the container (bounded by a 3-min timeout that falls back to a hard stop). All drains overlap. Applies to agents only
|
||||
* `--no-wait` — Return immediately after hivectl queues the stop DAGs instead of waiting for them with live per-node progress
|
||||
|
||||
|
||||
|
||||
## `hivectl start`
|
||||
|
||||
Start containers hive-wide — the inverse of `hivectl stop`.
|
||||
|
||||
Bare `hivectl start` starts every agent; scope flags narrow it. The swarm's forge and matrix are never in scope.
|
||||
|
||||
**Usage:** `hivectl start [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--agents` — All sub-agent containers
|
||||
* `--agent <NAME>` — A specific sub-agent by name. Repeatable: `--agent a --agent b`
|
||||
* `--gateway` — The gateway (`hive-gateway`) — nginx on the host, not a container
|
||||
* `--no-wait` — Return immediately after hivectl queues the start DAGs instead of waiting for them with live per-node progress
|
||||
|
||||
|
||||
|
||||
## `hivectl restart`
|
||||
|
||||
Restart containers hive-wide — `stop` then `start` over one scope.
|
||||
|
||||
Bare `hivectl restart` restarts everything; scope flags narrow it. The swarm's forge and matrix are never in scope.
|
||||
|
||||
**Usage:** `hivectl restart [OPTIONS]`
|
||||
|
||||
###### **Options:**
|
||||
|
||||
* `--agents` — All sub-agent containers
|
||||
* `--agent <NAME>` — A specific sub-agent by name. Repeatable: `--agent a --agent b`
|
||||
* `--gateway` — The gateway (`hive-gateway`) — nginx on the host, not a container
|
||||
* `--graceful` — Gracefully quiesce each agent on the stop half (see `stop --graceful`). Applies to agents only
|
||||
|
||||
|
||||
|
||||
## `hivectl completions`
|
||||
|
||||
Generate a shell completion script for `hivectl` and print it to stdout.
|
||||
|
||||
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.
|
||||
|
||||
**Usage:** `hivectl completions <SHELL>`
|
||||
|
||||
###### **Arguments:**
|
||||
|
||||
* `<SHELL>` — Shell to emit completions for
|
||||
|
||||
Possible values: `bash`, `elvish`, `fish`, `powershell`, `zsh`
|
||||
|
||||
|
||||
|
||||
|
||||
159
docs/2-handbook/hives/hivectl.md
Normal file
159
docs/2-handbook/hives/hivectl.md
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# 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.deploy.hive-controller.adminUsers` (adds you to the
|
||||
`hive-admin` group that owns the socket; see
|
||||
[`docs/2-handbook/hives/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: 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/2-handbook/hives/hivectl-cli.md`.
|
||||
|
||||
## 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 REMIND`. STATUS collapses the health flags
|
||||
(`running` / `stopped`, plus ` paused` / ` needs-login`
|
||||
when set — `paused` is orthogonal to running, see below);
|
||||
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](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](../../4-implementation/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/4-implementation/web-ui/terminal-rendering.md`)
|
||||
— that's presentation for a browser, this is a `tail -f`.
|
||||
Loading…
Reference in a new issue