diff --git a/CLAUDE.md b/CLAUDE.md index f0f29ffc..57513436 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -154,7 +154,8 @@ frontend/ npm workspaces (esbuild → static dist). Built {index, stats, screen}.html + {app, stats}.js + agent.css → dist/{*.html, static/*}. -hive-ag3nt/ in-container harness crate; produces TWO binaries +hive-ag3nt/ in-container harness crate; produces ONE `hive` + binary (post-#598) picking role from `HIVE_ROLE` env src/lib.rs re-exports + DEFAULT_SOCKET, DEFAULT_WEB_PORT src/client.rs generic JSON-line request/response over unix socket src/web_ui.rs per-container axum HTTP page (incl /api/cancel, @@ -192,12 +193,14 @@ hive-ag3nt/ in-container harness crate; produces TWO binaries `` markers per `mcp::Flavor`; owns `write_system_prompt` (re-exported from turn.rs for callers). - src/bin/hive-ag3nt.rs sub-agent main (Serve + Mcp subcommands) - src/bin/hive-m1nd.rs manager main (Serve + Mcp subcommands) - Static UI assets served by ServeDir from - $HIVE_STATIC_DIR (= hyperhive.frontend - .mergedDist — default agent dist + per-agent - extraFiles, set per the harness-base module). + src/bin/hive.rs unified harness main (Serve + Mcp + Wake + subcommands); role from `HIVE_ROLE` env, picks + agent or manager wire surface server-side. Wake + currently agent-only (#693). Static UI assets + served by ServeDir from $HIVE_STATIC_DIR + (= hyperhive.frontend.mergedDist — default agent + dist + per-agent extraFiles, set per the + harness-base module). prompts/ static role/tools/settings for claude (include_str!): system.md — unified system prompt; shared sections plus `` / diff --git a/README.md b/README.md index 3bcf3955..5e87f046 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,24 @@ the container as environment variables. Common options: See `nix/templates/harness-base.nix` for the full list of options and their descriptions. +## Operator CLI + +`hivectl` is the operator-facing host CLI for ad-hoc administration that +doesn't go through the broker (built alongside `hive-c0re` when the host +module is enabled): + +```sh +sudo hivectl forge create-user mara # provisions a forge user +sudo hivectl forge create-user mara --password # … with a fixed password +sudo hivectl matrix create-user mara # provisions a matrix user +sudo hivectl matrix create-user mara --password-stdin # … reading from stdin +``` + +For agent names (i.e., a `Coordinator::agent_state_root(name)` exists), +`hivectl` persists the resulting token to the agent's state dir like the +boot sweep does. For non-agent names (e.g. the operator's own forge/matrix +account), it prints the token to stdout and writes nothing. + ## Build / deploy ```sh diff --git a/docs/gotchas.md b/docs/gotchas.md index eff10354..5f13dce6 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -65,17 +65,20 @@ propagate in. Operators don't need to set anything on their side. ## Claude credentials are per-agent `/var/lib/hyperhive/agents//claude/` bind-mounts to -`/root/.claude` (RW). Sharing one dir across agents is NOT viable — +`/home//.claude` (RW; was `/root/.claude` pre-#658 when every +harness ran as root). Sharing one dir across agents is NOT viable — OAuth refresh tokens rotate, so any sibling refresh invalidates all the others. Login flow runs from the per-agent web UI; creds persist across `destroy`/recreate (`--purge` wipes them). ## Persistent notes dir per agent -`/var/lib/hyperhive/agents//state/` bind-mounts to `/state` -(RW). System prompts tell agents to keep durable knowledge here -(`/state/notes.md`, anything else under `/state/`). The harness also -writes its events log here (`/state/hyperhive-events.sqlite`). +`/var/lib/hyperhive/agents//state/` bind-mounts to +`/agents//state` (RW; uniform for sub-agents + manager +post-#604, was `/state` pre-#604). The harness exposes the same path +via `$HYPERHIVE_STATE_DIR`. System prompts tell agents to keep +durable knowledge here (`notes.md`, anything else). The harness also +writes its events log here (`hyperhive-events.sqlite`). Survives `destroy`/recreate alongside the claude dir. ## Web UI ports collide on hash diff --git a/docs/persistence.md b/docs/persistence.md index aea02c8f..dd9b3f52 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -136,11 +136,13 @@ Under `/var/lib/hyperhive/agents//`: precise changes from the manager; RW into the manager via the `/agents` tree bind. - `claude/` — claude OAuth credentials, bind-mounted RW to - `/root/.claude` inside the container. + `/home//.claude` inside the container (post-#658 — was + `/root/.claude` pre-#658 when every harness ran as root). - `state/` — durable notes, the events.sqlite db, and the turn-stats sqlite db. Bind-mounted to `/agents//state` - inside the container (the manager still uses the legacy - `/state` mount point — same host path either way). + inside the container (uniform for sub-agents + manager + post-#604). The `$HYPERHIVE_STATE_DIR` env var exposes the + same path to in-container scripts. Under `/var/lib/hyperhive/applied//` — the hive-c0re-only applied repo. Tracks `flake.nix` (module-only boilerplate; never diff --git a/docs/security.md b/docs/security.md index 32c6951c..22e4ab64 100644 --- a/docs/security.md +++ b/docs/security.md @@ -18,8 +18,12 @@ any file in the container that the nixbld user can read. **What is NOT exposed**: -- `/root/.claude/` — mode `0700`, owned by root. nixbld users cannot read it. -- `/state/forge-token` — written at mode `0600` by `hive-c0re/src/forge.rs`. +- `/home//.claude/` — mode `0700`, owned by the per-agent + user `` (post-#658 — was `/root/.claude` owned by root + pre-#658). nixbld users cannot read it. +- `$HYPERHIVE_STATE_DIR/forge-token` (= `/agents//state/forge-token`) + — written at mode `0600` by `hive-c0re/src/forge.rs` and chowned to the + per-agent uid:gid by `lifecycle::chown_to_agent` (post-#673/#678). nixbld users cannot read it. **Policy**: all credential files written to agent state directories MUST be mode diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 1817a613..6bfea1c1 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -5,7 +5,9 @@ claude has access to in return. ## The loop -Each agent harness (`hive-ag3nt serve` or `hive-m1nd serve`) runs: +Each agent harness (`hive serve`, with role picked from `$HIVE_ROLE` +— `"agent"` for sub-agents, `"manager"` for the manager; post-#598 +this is one binary not two) runs: 1. Long-poll `Recv` on its socket. The host-side broker (`broker.rs::recv_blocking_batch`) returns immediately if there's @@ -263,10 +265,12 @@ External MCP servers (and any other in-container process) can inject a wake-up event into the agent's inbox via the per-agent socket at `/run/hive/mcp.sock`. Two equivalent paths: -- **Shell out to `hive-ag3nt wake --from