CLAUDE.md: build commands, the 8 missing crates, leaner entries
Adds a build & check section, maps every workspace member, links gotchas.md, and trims entries down to purpose + warnings (the rest lives in each crate's //! doc). Also drops the comment in turn.rs that repeated the module doc.
This commit is contained in:
parent
afeb0f9794
commit
b99ce2b572
2 changed files with 144 additions and 243 deletions
381
CLAUDE.md
381
CLAUDE.md
|
|
@ -16,6 +16,27 @@ when you need depth on a subsystem. This file is the index.
|
||||||
- Agent trust model (trust boundary, prompt-injection threat model,
|
- Agent trust model (trust boundary, prompt-injection threat model,
|
||||||
capability = accepted risk), credential isolation + sandbox threat model:
|
capability = accepted risk), credential isolation + sandbox threat model:
|
||||||
**[docs/trust-boundary/security.md](docs/trust-boundary/security.md)**.
|
**[docs/trust-boundary/security.md](docs/trust-boundary/security.md)**.
|
||||||
|
- Odd-looking nspawn / container plumbing usually has a story:
|
||||||
|
**[docs/process/gotchas.md](docs/process/gotchas.md)**.
|
||||||
|
|
||||||
|
## Build & check
|
||||||
|
|
||||||
|
Always through the devshell — a bare `cargo` fails (`failed to find tool
|
||||||
|
"cc"`, `cannot find -lsqlite3`). Details:
|
||||||
|
[`docs/process/conventions.md`](docs/process/conventions.md#building--local-checks).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nix develop -c cargo clippy --all-targets -- -D warnings
|
||||||
|
nix develop -c cargo test
|
||||||
|
nix fmt # treefmt is the CI gate, NOT bare cargo fmt
|
||||||
|
```
|
||||||
|
|
||||||
|
Changed a `hivectl` / `swarmctl` verb or flag? Regenerate its doc — only
|
||||||
|
CI's `nix flake check` catches the drift:
|
||||||
|
`nix develop -c cargo run --bin hivectl -- markdown-docs > docs/tools/hivectl-cli.md`
|
||||||
|
(same for `swarmctl` → `docs/tools/swarmctl-cli.md`). CI red but local
|
||||||
|
green → build the suspect check (e.g. `nix build
|
||||||
|
.#checks.x86_64-linux.hivectl-docs`) before blaming the builder.
|
||||||
|
|
||||||
## Repo map
|
## Repo map
|
||||||
|
|
||||||
|
|
@ -27,251 +48,140 @@ hand-maintained per-file tree drifts out of sync with the code.
|
||||||
|
|
||||||
### Rust workspace (`Cargo.toml` members)
|
### Rust workspace (`Cargo.toml` members)
|
||||||
|
|
||||||
|
Per-hive (host + in-container):
|
||||||
|
|
||||||
- **`hive-c0re/`** — host daemon (runs as the unprivileged `hive-core`
|
- **`hive-c0re/`** — host daemon (runs as the unprivileged `hive-core`
|
||||||
user). `src/main.rs` is the `hive-c0re` binary — **daemon-only**
|
user), **daemon-only** — the operator CLI is `hivectl`. Owns the sqlite
|
||||||
(`serve` + the periodic vacuum/sweep loops); the operator CLI lives in
|
broker, reminder queue, meta flake, lifecycle (`nixos-container`
|
||||||
the separate `hivectl` crate, which talks to the daemon over the host
|
shellouts), gateway wiring, per-container stats and the axum operator
|
||||||
admin socket. Owns the sqlite broker, the reminder queue, the meta
|
dashboard. Agent forge/matrix accounts are `swarm-controller`'s. Largest
|
||||||
flake, lifecycle (`nixos-container` shellouts), gateway / forge /
|
crate.
|
||||||
matrix wiring (agent forge and matrix accounts are
|
- **`hivectl/`** — operator CLI; talks to `hive-c0re` over the host admin
|
||||||
`swarm-controller`'s), per-container stats, and the axum operator
|
socket, does NOT link it. Verb reference (CI-enforced):
|
||||||
dashboard (`dashboard/`). Largest crate.
|
|
||||||
- **`hivectl/`** — standalone operator CLI (`hivectl` binary). Talks to
|
|
||||||
the `hive-c0re` daemon over the host admin socket (`hive-host-sock`
|
|
||||||
wire types) — does NOT link `hive-c0re`. Full, always-current verb
|
|
||||||
reference (CI-enforced against the clap tree, see `docs/process/conventions.md`):
|
|
||||||
[`docs/tools/hivectl-cli.md`](docs/tools/hivectl-cli.md).
|
[`docs/tools/hivectl-cli.md`](docs/tools/hivectl-cli.md).
|
||||||
- **`hive-agent/`**, **`hive-agent-mcp/`** —
|
- **`hive-priv/`** — minimal root helper, socket-activated at
|
||||||
in-container harness, two sibling crates for every agent (not a
|
`/run/hive/priv.sock`; the few root ops (bind-mount edits, nsenter)
|
||||||
single `hive-ag3nt/` dir — that's the runtime/binary-family nickname,
|
`hive-c0re` delegates. See `docs/trust-boundary/boundary.md`.
|
||||||
not a directory).
|
- **`hive-agent/`** — the in-container serve loop: turn-loop *policy*
|
||||||
- **`hive-agent/`** — the serve-loop binary: turn-loop *policy* layer
|
(`turn.rs`) over `hive-runtime`, per-agent web UI, event + turn-stats
|
||||||
(`turn.rs`) over `hive-runtime`, per-agent web UI (`web_ui/`
|
sinks, system-prompt renderer, claude launch config (`mcp_config.rs`).
|
||||||
module dir), event + turn-stats sqlite sinks, login flow, system-prompt
|
With `hive-agent-mcp` it's what "hive-ag3nt" refers to — there is no
|
||||||
renderer, and the claude launch-config layer (`mcp_config.rs`:
|
such directory.
|
||||||
tool-group/capability → `--allowedTools`, `--mcp-config` render).
|
- **`hive-agent-mcp/`** — the embedded MCP server (`hive-mcp-http` unit).
|
||||||
- **`hive-agent-mcp/`** — the embedded MCP server (long-lived
|
- **`hive-runtime/`** — the `Runtime` interface an agent's turns run on:
|
||||||
streamable-http listener, `hive-mcp-http` systemd unit).
|
a `claude` backend (over `hive-claude`) and an `acp` backend whose stream
|
||||||
- **`hive-runtime/`** — the runtime an agent's turns run on: one
|
is translated into claude's `stream-json` shape. Links no hyperhive
|
||||||
`Runtime` interface (`run`/`compact`/`archive`/`canceller`/`choices`) with a `claude` backend
|
binary crate, so the subagent daemon uses it too.
|
||||||
(a pass-through to `hive-claude`) and an `acp` backend (any Agent Client
|
- **`hive-bash-mcp/`**, **`hive-matrix-mcp/`**, **`hive-subagent-mcp/`** —
|
||||||
Protocol agent, spawned from the command/args/env nix hands it — no agent
|
per-agent MCP daemons serving streamable-http directly (no stdio
|
||||||
is named in Rust). The ACP backend translates its stream into claude's
|
bridge): background bash tasks, matrix-sdk tools, nested subagent
|
||||||
`stream-json` shape, so the harness's consumers read either unchanged.
|
sessions (optionally goal-driven over several turns; daemon state is
|
||||||
Depends on no hyperhive binary crate, so the subagent daemon can use it
|
in-memory, the claude session survives a restart).
|
||||||
too.
|
- **`hive-screen-mcp/`** — stdio MCP bridge for GUI agents: screenshot,
|
||||||
- **`hive-jobq/`** — job-DAG scheduler, extracted from hive-c0re's
|
keyboard, mouse. All userspace.
|
||||||
in-tree `job_queue` as a domain-agnostic library. **Runtime-only —
|
- **`hive-forge/`** — `hive-forge` Forgejo CLI; one module per verb.
|
||||||
nothing writes the graph to disk**; hive-c0re starts empty each boot
|
- **`hive-forge-notify/`** — notification pollers → todos on the in-agent
|
||||||
and re-derives desired state via the reconcile sweep, so node ids and
|
socket. Two binaries: `hive-forge-notify`, `hive-github-notify`.
|
||||||
timestamps are stable within a run, not across restarts. One
|
- **`hive-jobq/`** — the job-DAG scheduler library. **Runtime-only —
|
||||||
shared graph for the whole system (not a DAG per job); enqueuing
|
nothing writes the graph to disk**, so node ids are stable within a run,
|
||||||
inserts a self-contained sub-DAG and returns the ids of the nodes the job
|
not across restarts. `hive-c0re`'s `job_queue/` is being removed in its
|
||||||
asked for, in the order it named them. Generic over
|
favour — new scheduler-shaped code goes here.
|
||||||
the node payload `N` and the resource name `R`; resource deps are named
|
- **`hive-jobq-wire/`** — presentation of a `hive-jobq` graph to viewers
|
||||||
counting semaphores acquired all-or-nothing at node start. `hive-c0re`'s
|
(`WireNode` / `WireResource`); kept out of `hive-jobq` on purpose.
|
||||||
remaining `job_queue/` module is the c0re-specific layer *over* this
|
- **`hive-jobq-metrics/`** — OTEL export of a graph's state rollup on a
|
||||||
crate, and is being removed in favour of it — new scheduler-shaped code
|
timer.
|
||||||
belongs here, not there.
|
- **`hive-log/`** — the one log-sink chooser: journald *or* stdout, never
|
||||||
- **`hive-jobq-wire/`** — wire types for serving a `hive-jobq` graph to a
|
both (under a unit, stdout already is the journal). Do not grow it into a
|
||||||
viewer, plus the `WireNode` / `WireResource` traits a host implements to
|
utility crate.
|
||||||
say how its `N` and `R` render. Deliberately *not* part of `hive-jobq`:
|
- **`hive-metric/`** — one-shot CLI pushing a labeled metric over OTLP.
|
||||||
that crate is logic, this is presentation, and folded together they
|
|
||||||
remix. `GraphWire::wire_snapshot` is blanket-implemented for any
|
Wire types + socket plumbing:
|
||||||
`Graph<N, R>` whose parameters implement both — so a payload that has
|
|
||||||
never said how it displays cannot reach a viewer at all.
|
- **`hive-types/`** — leaf newtypes, chiefly the validated `Ident`.
|
||||||
- **`hive-log/`** — the one log-sink chooser, called by `hive-c0re`,
|
- **`hive-sh4re/`** — shared payload types (`Message`, `HelperEvent`, …).
|
||||||
`hive-agent` and `swarm-controller` and by nothing else. `init()` builds
|
- **`hive-host-sock/`** (hivectl ↔ c0re), **`hive-priv-sock/`** (c0re ↔
|
||||||
the `EnvFilter` those binaries always built, then installs **exactly
|
priv), **`hive-core-agent-sock/`** (harness ↔ c0re, `/run/hive/mcp.sock`)
|
||||||
one** sink: the native journald layer when an `fstat` of stdout matches
|
— per-socket wire types, split out so each client links only its protocol.
|
||||||
the device and inode numbers systemd exports in `$JOURNAL_STREAM`, the
|
- **`hive-agent-sock/`** — the *in-agent* socket the harness serves to
|
||||||
`fmt` stdout layer otherwise. Under a unit stdout already **is** the
|
in-container producers (todos, reminders); also holds the `extra_mcp`
|
||||||
journal, so both layers together store every record twice. Deliberately
|
spec. ⚠️ **This socket never leaves the container** — `hive-c0re` is not
|
||||||
single-purpose — do not grow it into a utility crate.
|
in the path, unlike `hive-core-agent-sock`.
|
||||||
- **`hive-screen-mcp/`** — stdio MCP bridge for GUI agents
|
- **`hive-sock-client/`** — the shared JSON-line unix-socket client; retry
|
||||||
(`services.hyperhive.agent.gui.enable`): `screenshot` via `grim`, `type_text` /
|
is a policy value (`Retry::None` / `Retry::RideOutRestart`).
|
||||||
`key_press` via `wtype` (Wayland virtual-keyboard protocol), and
|
|
||||||
`mouse_move` / `mouse_click` as RFB pointer events to the local neatvnc
|
Swarm-level:
|
||||||
server. All userspace, no daemon of its own.
|
|
||||||
- **`hive-priv/`** — minimal root privileged-helper, socket-activated at
|
- **`swarm-controller/`** — owns what is true **across** hives; opt-in,
|
||||||
`/run/hive/priv.sock`; performs the few root operations (bind-mount
|
one per swarm. Serves HTTP over a unix socket nginx proxies to — ⚠️
|
||||||
edits, nsenter) the unprivileged `hive-c0re` delegates to it. See
|
**the socket's directory is its access control**; the crate README has
|
||||||
`docs/trust-boundary/boundary.md`.
|
the constraint and a unit test pins the path.
|
||||||
- **`hive-forge/`** — `hive-forge` Forgejo CLI wrapper; one module per
|
- **`swarmctl/`** — swarm operator CLI; runs as **root and acts directly**
|
||||||
verb under `src/verbs/`.
|
(README says why). Does not link `swarm-controller` — its wire shapes
|
||||||
- **`hive-forge-notify/`** — per-agent notification poller daemons; turns
|
are a local mirror. ⚠️ Edits authelia's **`users.yml` in place**, shared
|
||||||
unread notification threads into todos on the harness's in-agent
|
with `swarm-authelia-bridge`; that crate's README says what both writers
|
||||||
socket. Two binaries from one crate: `hive-forge-notify` (the hive's
|
must uphold. Verb reference (CI-enforced):
|
||||||
Forgejo) and `hive-github-notify` (github.com, installed by
|
|
||||||
`nix/agent-modules/github.nix`). Was a task inside the `hive-agent`
|
|
||||||
serve loop; own process since it needs nothing else from the harness.
|
|
||||||
- **`hive-matrix-mcp/`** — per-agent matrix-sdk daemon
|
|
||||||
(`hive-matrix-daemon`); serves its MCP tools (`send_message`,
|
|
||||||
`read_room`, …) directly over streamable-http (no stdio bridge),
|
|
||||||
same shape as `hive-bash-mcp`.
|
|
||||||
- **`hive-bash-mcp/`** — per-agent bash-task runner daemon
|
|
||||||
(`hive-bash-daemon`); serves its MCP tools (`run`/`status`/`kill`)
|
|
||||||
directly over streamable-http (no stdio bridge), writes task files
|
|
||||||
under `/harness/bash-tasks/`, and records the favorite-tools
|
|
||||||
`bash_commands` stat into turn-stats.sqlite.
|
|
||||||
- **`hive-subagent-mcp/`** — per-agent subagent runner daemon
|
|
||||||
(`hive-subagent-daemon`); spawns nested sessions on request, on the
|
|
||||||
parent agent's runtime via `hive-runtime` (claude or ACP), and
|
|
||||||
serves `start`/`continue`/`status`/`interrupt` directly over
|
|
||||||
streamable-http (no stdio bridge), plus a second subagent-facing route
|
|
||||||
carrying `goal_reached`/`need_help` — served per session under a minted
|
|
||||||
token, since neither tool takes a session name. Independent of `hive-bash-mcp` (a
|
|
||||||
subagent is a much heavier capability than a bash command). A `start`
|
|
||||||
with a `goal` is a multi-turn run: the daemon re-prompts the subagent
|
|
||||||
toward the goal each time a turn ends, up to a per-session turn cap. No
|
|
||||||
task files — the daemon's state is in-memory only, live only as long as
|
|
||||||
the process is; the actual claude session survives a daemon restart
|
|
||||||
independently (see `session.rs`'s module doc).
|
|
||||||
- **`hive-sh4re/`** — shared wire types (Agent / Manager request +
|
|
||||||
response, `Message`, `HelperEvent`) used across the unix
|
|
||||||
sockets. Host-admin-socket and hive-priv-socket wire types have been
|
|
||||||
split out into their own crates (below) so `hivectl` and `hive-priv`
|
|
||||||
don't need to pull in the rest of `hive-sh4re`.
|
|
||||||
- **`hive-host-sock/`** — wire types for the host admin socket
|
|
||||||
(`/run/hyperhive/host.sock`), the protocol `hivectl` speaks to
|
|
||||||
`hive-c0re`. Split out of `hive-sh4re` so a standalone `hivectl` only
|
|
||||||
depends on this protocol crate, not the whole daemon crate.
|
|
||||||
- **`hive-priv-sock/`** — wire types for the `hive-priv` privileged-helper
|
|
||||||
socket (`/run/hive/priv.sock`), shared by `hive-priv` (server) and
|
|
||||||
`hive-c0re` (client). Also split out of `hive-sh4re`.
|
|
||||||
- **`hive-core-agent-sock/`** — wire types for the *host*-served per-agent
|
|
||||||
+ manager socket (`/run/hive/mcp.sock`), the protocol an agent's harness
|
|
||||||
speaks to `hive-c0re`. Same split rationale as the two above; the shared
|
|
||||||
payload types it references stay in `hive-sh4re`.
|
|
||||||
- **`hive-agent-sock/`** — what's common across the in-container "agent
|
|
||||||
plugins" (matrix/bash/subagent MCP daemons, `forge_notify`, any
|
|
||||||
user-configured MCP server). Wire types for the *in-agent* socket, served
|
|
||||||
by the harness to those producers — nothing restricts the `subsystem` set
|
|
||||||
on the todo ops, any producer can push its own. Carries the loose-ends-v2
|
|
||||||
**todo** ops plus harness-local reminders. ⚠️ Distinct from
|
|
||||||
`hive-core-agent-sock` above: **this socket never leaves the container**
|
|
||||||
and `hive-c0re` is not in the path at all — no broker round-trip, no
|
|
||||||
long-poll, no marker files. Also carries `extra_mcp`: the
|
|
||||||
`services.hyperhive.agent.extraMcpServers` spec + parsing, shared by `hive-agent` and
|
|
||||||
`hive-subagent-mcp` — not a socket protocol, just the natural home since
|
|
||||||
both already depend on this crate.
|
|
||||||
- **`hive-types/`** — zero-dependency (bar serde) leaf crate holding the
|
|
||||||
foundational newtypes, chiefly `Ident` (1–63 chars of `[a-z0-9-]`,
|
|
||||||
constructed only via the validating parser). Lets every wire-type crate
|
|
||||||
and both binaries type their agent-name fields as a validated ident and
|
|
||||||
get serde-checked parsing at the socket boundary, without coupling to
|
|
||||||
`hive-sh4re`.
|
|
||||||
- **`hive-sock-client/`** — the shared JSON-line-over-unix-socket client
|
|
||||||
every daemon uses to talk to a hyperhive socket. Generic over the
|
|
||||||
request/response types, so the host-served control socket and the
|
|
||||||
harness's in-agent socket both use it with their own wire-type crates.
|
|
||||||
Retry is a policy value (`Retry::None` for callers already inside a poll
|
|
||||||
loop, `Retry::RideOutRestart` for callers with no natural retry), and
|
|
||||||
the response is either decoded (`request`) or drained (`notify`).
|
|
||||||
Deliberately separate from the `*-sock` crates — those stay
|
|
||||||
dependency-free wire types.
|
|
||||||
- **`hive-metric/`** — small CLI to push a single labeled metric to the
|
|
||||||
OTEL collector via the OpenTelemetry Rust SDK / OTLP HTTP exporter.
|
|
||||||
- **`swarm-controller/`** — swarm-level daemon, opt-in per host
|
|
||||||
(`services.hyperhive.deploy.swarm-controller.enable`). Where `hive-c0re` owns
|
|
||||||
the agents on **one** host, this owns what is true **across** hives; a
|
|
||||||
swarm runs one of them, so most hives leave it off. Serves HTTP over a
|
|
||||||
unix socket the gateway's nginx proxies to — ⚠️ **the socket's
|
|
||||||
directory is its access control**; the constraint that governs it is in
|
|
||||||
the crate's README, and a unit test pins the path.
|
|
||||||
- **`swarm-secret-client/`** — client for the swarm's secret store, over
|
|
||||||
`vaultrs`. Owns the *agreements* both ends of the store must share rather
|
|
||||||
than the HTTP: the path a credential lives at, the field its bytes are in,
|
|
||||||
and the translation from this deployment's environment into a logged-in
|
|
||||||
client. ⚠️ Reads the **`BAO_`** env spellings explicitly — `vaultrs`'s own
|
|
||||||
defaults look for `VAULT_ADDR`/`VAULT_CLIENT_CERT`/`VAULT_CLIENT_KEY`, which
|
|
||||||
no unit in this tree sets, so falling through to them yields a client with
|
|
||||||
**no identity** and a TLS handshake failure that names no cause.
|
|
||||||
- **`swarm-review-classifier/`** — the review classifier's try-out daemon,
|
|
||||||
in its own container where `deploy.review-classifier.enable` is set. Takes
|
|
||||||
a PR and classifications from `swarm-controller` over the queue, runs one
|
|
||||||
`claude --print` per classification (no tools, no session) and replies
|
|
||||||
with the rows and the overall verdict. Holds no forge credential. Design:
|
|
||||||
[`docs/swarm/review-classifier.md`](docs/swarm/review-classifier.md).
|
|
||||||
- **`swarm-agent-verify/`** — the check that a presented
|
|
||||||
`swarm-agent.<agent>.<secret>` token holds the secret stored at
|
|
||||||
`swarm/agents/<agent>/queue`, read under the verifier's own certificate.
|
|
||||||
Shared by `swarm-nats-auth` (the queue's auth callout) and
|
|
||||||
`swarm-logs-auth`.
|
|
||||||
- **`swarm-logs-auth/`** — the log store gateway's `auth_request` responder
|
|
||||||
for agents: nginx sends it `/select/logsql/` requests carrying an agent
|
|
||||||
token, it answers 200 or 401 via `swarm-agent-verify`. Runs on the log
|
|
||||||
store's host (`swarm-victorialogs.nix`).
|
|
||||||
- **`swarm-builder/`** — the swarm builder's build daemon, in its own
|
|
||||||
container where `deploy.builder.enable` is set. Takes an agent config PR's
|
|
||||||
head from `swarm-controller` over the queue, builds it on its host's agent
|
|
||||||
base through the host nix daemon (`nix/builder/check-flake`), and replies
|
|
||||||
with the store path or the error tail; the controller writes the commit
|
|
||||||
status. Holds a read-only forge token. Design:
|
|
||||||
[`docs/swarm/builder.md`](docs/swarm/builder.md).
|
|
||||||
- **`swarmctl/`** — swarm-level operator CLI, installed by the
|
|
||||||
swarm-controller module on the host that runs the daemon. Runs as
|
|
||||||
**root and acts directly** — it serves no socket, publishes no HTTP
|
|
||||||
route and has no priv helper; the crate's README records why the
|
|
||||||
rootless shape was examined and rejected. `agent create` is the one
|
|
||||||
verb that talks to a service rather than acting locally: it POSTs
|
|
||||||
`/api/agents` to swarm-controller over the daemon's unix socket and
|
|
||||||
prints the queued job id without waiting (the DAG settling would not
|
|
||||||
mean the agent is up). With `--swarm`, the controller verbs go
|
|
||||||
through the swarm domain's gateway instead, as the operator's own SSO
|
|
||||||
login (`swarmctl login`). Does not link `swarm-controller` — its wire
|
|
||||||
shapes are a local mirror kept in this crate, not a shared crate, so
|
|
||||||
the two binaries can be deployed independently. ⚠️ Its user store is
|
|
||||||
authelia's own **`users.yml`, read and
|
|
||||||
written in place** — one file, shared with `swarm-authelia-bridge`; see
|
|
||||||
that crate's README for what both writers must uphold. Full, always-current
|
|
||||||
verb reference (CI-enforced against the clap tree, same pattern as
|
|
||||||
`hivectl`'s — see `docs/process/conventions.md`):
|
|
||||||
[`docs/tools/swarmctl-cli.md`](docs/tools/swarmctl-cli.md).
|
[`docs/tools/swarmctl-cli.md`](docs/tools/swarmctl-cli.md).
|
||||||
|
- **`swarm-authelia-bridge/`** (+ **`swarm-authelia-bridge-sock/`** wire
|
||||||
|
types) — the other writer of authelia's users DB; runs inside
|
||||||
|
`swarm-authelia`.
|
||||||
|
- **`swarm-secret-client/`** — OpenBao client over `vaultrs`. ⚠️ Reads
|
||||||
|
the **`BAO_`** env spellings explicitly — `vaultrs`'s `VAULT_*` defaults
|
||||||
|
are set by no unit here, and falling through to them yields a client
|
||||||
|
with **no identity** and a TLS failure that names no cause.
|
||||||
|
- **`swarm-queue-client/`** — the one authenticated connect to the swarm
|
||||||
|
NATS queue.
|
||||||
|
- **`swarm-nats-auth/`** — NATS auth-callout responder; without it the
|
||||||
|
queue is fail-closed and admits nobody.
|
||||||
|
- **`swarm-agent-verify/`** — checks a `swarm-agent.<agent>.<secret>`
|
||||||
|
token against the store; shared by `swarm-nats-auth` and
|
||||||
|
`swarm-logs-auth`.
|
||||||
|
- **`swarm-logs-auth/`** — nginx `auth_request` responder for agent access
|
||||||
|
to the log store.
|
||||||
|
- **`swarm-logs/`** — agent CLI: a LogsQL query in, log lines out.
|
||||||
|
- **`swarm-matrix-client/`** — appservice calls against the swarm
|
||||||
|
homeserver, shared by `swarm-controller` and `swarm-matrix-ctl`.
|
||||||
|
- **`swarm-matrix-ctl/`** — the one binary run inside
|
||||||
|
`containers.hive-matrix`; new in-container jobs are verbs here, not
|
||||||
|
crates.
|
||||||
|
- **`swarm-builder/`** — builds agent config PR heads for commit status.
|
||||||
|
Design: [`docs/swarm/builder.md`](docs/swarm/builder.md).
|
||||||
|
- **`swarm-review-classifier/`** — one `claude --print` per PR
|
||||||
|
classification, no tools, no forge credential. Design:
|
||||||
|
[`docs/swarm/review-classifier.md`](docs/swarm/review-classifier.md).
|
||||||
|
|
||||||
### External dependencies with no directory here
|
### External dependencies with no directory here
|
||||||
|
|
||||||
- **`hive-claude`** — reusable, app-agnostic driver for headless
|
- **`hive-claude`** — app-agnostic driver for headless `claude --print`
|
||||||
`claude --print`: spawns the CLI, streams + classifies stream-json,
|
(stream-json, `Telemetry`, the self-compacting `InfiniteSession`).
|
||||||
parses per-turn `Telemetry`, and drives a durable self-compacting
|
⚠️ **Its own repo, not a workspace member** — there is no
|
||||||
`InfiniteSession` (name + `SessionStore` + `CompactionPolicy`). Uses
|
`hive-claude/` directory and `grep` here will not find it.
|
||||||
`thiserror` (it's a library); the `hive-*` binaries consume it with
|
|
||||||
`anyhow`. ⚠️ **Its own repo, not a workspace member** — consumed as a
|
|
||||||
dependency in the root `Cargo.toml`, so there is no `hive-claude/`
|
|
||||||
directory to read and `grep` here will not find it.
|
|
||||||
|
|
||||||
### Other top-level dirs
|
### Other top-level dirs
|
||||||
|
|
||||||
- **`frontend/`** — npm workspaces → static dashboard + per-agent UI
|
- **`frontend/`** — npm workspaces built hermetically by
|
||||||
dist, built hermetically by `nix/packages/frontend.nix`. Packages:
|
`nix/packages/frontend.nix`: `shared`, `dashboard` (operator SPA),
|
||||||
`shared` (terminal pane + Catppuccin palette), `dashboard` (the
|
`agent` (per-container UI), `swarm-ui` (Preact; packaged separately by
|
||||||
operator SPA), `agent` (the default per-container UI), `swarm-ui`
|
`nix/packages/swarm-ui.nix`, not in `packages.default`'s closure).
|
||||||
(swarm-level UI shell — Preact + wouter + TypeScript + JSX, project-
|
- **`nix/`** — `host-modules/` (the host stack), `agent-modules/`
|
||||||
bootstrap scope; packaged separately by `nix/packages/swarm-ui.nix`,
|
(per-agent harness features), `container-modules/` (guest side of
|
||||||
not bundled into `packages.default`'s closure — see that file).
|
service containers), `templates/{agent,ruth}.nix` (container entry
|
||||||
- **`nix/`** — `host-modules/` (the host stack: hyperhive core options,
|
points), `packages/`, `docs/` (options doc), `module-eval/` (NixOS
|
||||||
`hive-{c0re,priv,forge,gateway,matrix,network,tls,ci}`, otel, swarm),
|
module-eval tests), `builder/` (`check-flake`), `script-tests/`, plus
|
||||||
`agent-modules/` (the per-agent harness feature modules),
|
`sources.nix` / `rust.nix` / `checks.nix` / `devshell.nix` /
|
||||||
`container-modules/` (modules imported inside service containers —
|
`treefmt.nix` behind the thin `flake.nix`.
|
||||||
guest side), `templates/{agent,ruth}.nix` (container entry points),
|
|
||||||
`packages/` (flake package outputs), `docs/` (the options-doc
|
|
||||||
derivation), plus `sources.nix` / `rust.nix` / `checks.nix` /
|
|
||||||
`devshell.nix` / `treefmt.nix` behind the thin `flake.nix`.
|
|
||||||
- **`docs/`** — subsystem reference docs (see *Reading paths* below).
|
- **`docs/`** — subsystem reference docs (see *Reading paths* below).
|
||||||
- **`branding/`**, **`scripts/`** — static assets + helper scripts.
|
- **`branding/`**, **`scripts/`** — static assets + helper scripts.
|
||||||
|
|
||||||
## Reading paths
|
## Reading paths
|
||||||
|
|
||||||
**[`docs/README.md`](docs/README.md) is the single index** — grouped by topic
|
**[`docs/README.md`](docs/README.md) is the single index**, grouped by
|
||||||
(getting started, agent lifecycle, trust boundary, integrations, networking,
|
topic. Don't add a second copy of it here — a parallel list used to live
|
||||||
scheduler, process). Read it instead of a second copy here; this file used to
|
in this file and drifted.
|
||||||
carry its own parallel "Reading paths" list, and the two drifted out of sync
|
|
||||||
with each other.
|
|
||||||
|
|
||||||
## Conventions & process
|
## Conventions & process
|
||||||
|
|
||||||
- **Never add `#[allow(clippy::…)]`** — fix the lint instead (extract a
|
- **Never add `#[allow(clippy::…)]`** — fix the lint instead (extract a
|
||||||
helper, add backticks, etc.). Details + worked examples: →
|
helper, add backticks, etc.). Worked examples:
|
||||||
[`docs/process/conventions.md`](docs/process/conventions.md#building--local-checks).
|
[`docs/process/conventions.md`](docs/process/conventions.md#building--local-checks).
|
||||||
- **Pre-push lint hook** (catches tracker-tag and comment-block failures
|
- **Pre-push lint hook** (catches tracker-tag and comment-block failures
|
||||||
before CI does — install once per clone):
|
before CI does — install once per clone):
|
||||||
|
|
@ -279,15 +189,12 @@ with each other.
|
||||||
- **Comment/PR-description length**: size it to how non-obvious the
|
- **Comment/PR-description length**: size it to how non-obvious the
|
||||||
thing is, not to how much investigation it took to find it — a
|
thing is, not to how much investigation it took to find it — a
|
||||||
mechanical fix gets a one-line comment, a genuinely non-obvious
|
mechanical fix gets a one-line comment, a genuinely non-obvious
|
||||||
invariant or decision earns real prose.
|
invariant or decision earns real prose. Don't restate a module's `//!`
|
||||||
|
doc in a comment further down the same file.
|
||||||
- **Operator-facing doc with real implementation detail mixed in**: wrap
|
- **Operator-facing doc with real implementation detail mixed in**: wrap
|
||||||
the implementation part in a `<details><summary>…</summary>` block
|
the implementation part in a `<details><summary>…</summary>` block
|
||||||
(blank line after `<summary>` so the markdown inside still renders,
|
(blank line after `<summary>` so the markdown inside renders) rather
|
||||||
not a second file) rather than splitting into a sibling page — see
|
than a sibling page — see `docs/integrations/github.md`'s
|
||||||
`docs/integrations/github.md`'s "Implementation" section. Zero nav
|
"Implementation" section. It only collapses in a rendered browser, and
|
||||||
churn, works uniformly regardless of whether the doc already had a
|
the `<summary>` line isn't markdown-processed, so keep it plain prose
|
||||||
clean boundary. Caveat: it only collapses in a rendered browser —
|
with no backticks.
|
||||||
reading the file as raw text (`cat`, the Read tool) shows everything,
|
|
||||||
same as today. Also: the `<summary>` line itself isn't markdown-
|
|
||||||
processed — backticks render as literal characters, not styled code
|
|
||||||
— so keep summary text plain prose, no inline-code formatting.
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,6 @@ use crate::mcp_config;
|
||||||
// `docs/turn-loop/claude-invocation.md`. Unknown keys are silently ignored by
|
// `docs/turn-loop/claude-invocation.md`. Unknown keys are silently ignored by
|
||||||
// claude-code; if a key gets renamed we'll spot it because the corresponding
|
// claude-code; if a key gets renamed we'll spot it because the corresponding
|
||||||
// behavior will start firing mid-turn again.
|
// behavior will start firing mid-turn again.
|
||||||
//
|
|
||||||
// The runtime mechanics — spawning the agent, streaming its output, session
|
|
||||||
// lookup/archive — live in the generic `hive-runtime` crate. This module is
|
|
||||||
// the hyperhive *policy* layer on top:
|
|
||||||
// it builds the per-turn [`Config`] from the bus, forwards the stream to the
|
|
||||||
// event bus via [`BusSink`], and owns compaction / auto-reset / retry.
|
|
||||||
|
|
||||||
/// Fixed, harness-owned claude session title. Every turn / compact /
|
/// Fixed, harness-owned claude session title. Every turn / compact /
|
||||||
/// checkpoint resumes THIS title (`--resume <title>`); the create path
|
/// checkpoint resumes THIS title (`--resume <title>`); the create path
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue