The hive Space was created empty — joining it surfaced no rooms because
Matrix doesn't auto-join a Space's children. Provision a default
"hive-chat" room on the matrix sweep, wire it bidirectionally to the
Space (m.space.child on the Space, m.space.parent on the room), and
invite @hive + every agent. The room uses a restricted join rule
allowing any Space member to join, so the operator (a Space member) can
join it from the Space hierarchy without an explicit invite.
Idempotent, mirroring ensure_hive_space: persisted chat-room-id wins,
else rediscover a non-space room named hive-chat, else createRoom. The
space-child link is re-applied each sweep (idempotent PUT) so a
recovered room reconverges its hierarchy link. Room id persisted to
matrix/chat-room-id (0600, survives destroy --purge).
Backfills the agent /stats page docs after the P1 stats enrichments:
the result-trend stacked bar (per-bucket result outcomes over time) and
the cache hit-rate + tokens/turn summary chips.
The surfacing half of the per-agent favorite-tools stat. Reads a
`bash_commands(ts INTEGER NOT NULL, head TEXT NOT NULL)` table from the
per-agent turn-stats.sqlite — one row per bash task, written by
hive-bash-mcp (the capture half, landing separately) — and rolls up the
top-10 command heads for a doughnut, mirroring the existing
tool_breakdown.
- stats.rs: new `Snapshot.bash_breakdown` + `read_bash_breakdown()`.
The read is guarded: a missing `bash_commands` table (capture hasn't
shipped / agent hasn't run a bash task) maps to an empty list, never
an error — the snapshot degrades gracefully. Unit tests cover both
the absent-table and populated cases (incl. window cutoff + ordering).
- frontend: a "favorite tools (bash)" doughnut card on the agent /stats
page, kept hidden until bash_breakdown has data so it never shows a
permanently-empty doughnut while capture is pending.
Part of #1433 (does not close it — pairs with the hive-bash-mcp capture
half). Inert until the capture lands; merge order with it is irrelevant.
The matrix server-server spec resolves a portless m.server delegated
host to the federation default port 8448 (not 443 — the URL convention
that https implies 443 does not apply to the m.server field). The
gateway reused publicPortSuffix, which intentionally drops :443 for the
client base_url, so .well-known/matrix/server advertised the bare
gateway host. Peers then federated to <gatewayHost>:8448, which nothing
listens on, while the federation endpoint actually lives on the gateway
443 vhost (/_matrix/ proxied to tuwunel). Always emit the explicit port
in the federation delegation so peers reach the live 443 endpoint.
Per review: available_parallelism() respects the hive-core process's
CPU affinity, so if it's ever affinity-pinned the denominator would
under-count and inflate cpu_pct. Read the online host CPUs from
/sys/devices/system/cpu/online instead (fall back to the process count,
then 1) so the 'percent of total host CPU' definition holds regardless.
C0NT41N3R L04D on the SYST3M tab + GET /api/container-resources.
Backend (hive-c0re/src/container_stats.rs): reads cgroup v2 cpu.stat +
memory.{current,peak,max} for each running agent machine
(machine-h\x2d<name>.scope under machine.slice), read-only/world-
readable so no hive-priv. CPU is a two-sample (~200ms) host-normalised
percentage; one shared sleep covers all agents. Skips agents whose
scope dir is absent (= not running). Network omitted: agents share the
host netns, no per-container counter.
Frontend: a polled C0NT41N3R L04D table on SYST3M (agent / cpu / mem /
peak / limit with meter bars), reusing the ST4TS table style. Polls
/api/container-resources every 5s only while the tab is active.
Backend reviewed-in-principle by damocles (path escaping + cpu delta
math); ping for the on-host sign-off.
Adds the ST4TS tab to the strip list + a section covering the swarm
rollup, the /api/stats-hive endpoint shape, the read-only/skip-missing
aggregation, pull-on-activation, and the labelled cost estimate. Ships
with the feature (this branch / PR).
Builds the dashboard UI on the /api/stats-hive endpoint: a new ST4TS
tab showing swarm totals (active agents, turns, tokens, labelled est
cost), a busiest-first per-agent table, and a model-mix bar list.
Plain tables/CSS bars — no chart lib in the dashboard bundle; per-agent
trend charts stay on each agent's own /stats page. Fetched on tab
activation + window change (pull-only, no SSE).
Also adds conn.busy_timeout(500ms) in hive_stats read_agent per review:
turn_stats is rollback-journal, so a read landing mid-INSERT would hit
SQLITE_BUSY and silently drop that active agent — wait the write out.
#1424 P2 backend. New hive_stats module aggregates every agent's
turn-stats.sqlite read-only (reusing Coordinator::kept_state_names +
agent_harness_dir, skipping missing/unreadable dbs) into swarm totals,
a busiest-first per-agent rollup, swarm model mix, and a labelled USD
cost estimate (rough model->price table; can move to a nix option
later). Exposed as GET /api/stats-hive?window=. Dashboard UI follows.
First slice of #1424 (per-agent /stats enrichments):
- Backend: add per-bucket result_counts to the stats Snapshot (mirrors
model_counts), so result outcomes can be charted over time, not just
as a window total.
- Frontend: two new summary chips — cache hit-rate % (cached input vs
all input-side tokens) and avg tokens/turn — both derived from the
existing per-bucket token sums. Plus a stacked result-trend chart so
error / rate-limit / compaction spikes are visible across the window.
Hive-wide aggregate, cost estimate, and container resource load land in
follow-up PRs.
Replaces the fork-and-PR instructions with the supported no-fork path
now that the CLI helper shipped: hive-forge clone + pr-create --agit.
Agents are read-only collaborators, so they push HEAD to
refs/for/<base>/<topic> via AGit instead of forking. Same --topic
updates the open PR.
clippy::unnecessary_wraps — the helper always returns Ok. Build the
DaemonResponse directly and wrap with Ok() at the call sites. Fixes the
CI clippy failure on this PR.
When an agent parks on a long-poll that expires with nothing to show,
nudge it to spend the idle time on other useful work instead of
immediately re-blocking on the same call.
- recv: when wait_seconds > 0 and the inbox is empty at timeout, the
'(empty)' result now carries IDLE_WAIT_HINT. Immediate peeks
(no/zero wait) are unchanged.
- bash_status: when wait_seconds > 0 and the task is still
pending/running at timeout, append BASH_IDLE_WAIT_HINT. Finished
tasks and no-wait calls are unchanged.
Both thread a 'waited' flag into the formatter so the hint only fires
on an actual wait-timeout. Unit tests cover both. Implements #1411.
Per #1407 review: the options reference should be markdown here; the
HTML + CSS belongs in the website repo where the theme lives and the
stylesheet can be shared with /docs.
- nix/docs/default.nix: drop the cmark-gfm HTML rendering, the inline
<style>, and the HTML index. Emit index.md + host.md + agent.md only
(CommonMark from nixosOptionsDoc).
- Remove nix/docs/style.css.
- Update docs/gotchas.md + CLAUDE.md to describe the md-only output and
point at the website for HTML rendering.
The website (hyperhive/website#26) renders these .md to themed HTML for
/options/, sharing one docs.css with the prose /docs/ tree.
The CSS theme-variable reference documents the dashboard/agent web-UI
stylesheets, so it belongs under docs/web-ui/ alongside shape/dashboard/
agent. Wire it into the web-ui.md index (split list + reading path) and
the CLAUDE.md file map. Closes#1405.
The "hive-forge container shape" section described the container
isolation model but omitted the port and firewall knobs that operators
need when exposing forge externally or overriding the Forgejo ROOT_URL.
Add two subsections:
"Network and port configuration" — covers httpPort (default 3000),
sshPort (default 2222), and openFirewall (default false, was previously
true — breaking change note included). Explains the shared-netns
rationale for why openFirewall is safe to leave off for agent use but
must be set for browser/external-git-client access. Clarifies that
forge.behindGateway obviates forge.openFirewall for HTTP reach.
"rootUrl override" — documents forge.rootUrl (default null) with the
auto-derivation table (behindGateway ? http://domain/ : http://domain:port/)
and explains when to override (TLS, https:// clone URLs, bespoke shapes).
Notes the auto-derivation always produces http://, so TLS operators must
set rootUrl explicitly.
The sentence 'ruth is always reachable regardless of the list' documents
a bug in check_send_allowed (name-based carve-out), not intended
behavior. The structural parent carve-out is fine to mention since it's
topology-based, not name-based.
Updated example to show [ "operator" ] (restrict to operator-only)
and replaced the ruth-name claim with a note about the parent carve-out.
Five per-agent agent.nix options were undocumented:
- hyperhive.allowedRecipients — restricts which peers send() accepts;
note added inline to the send tool description
- hyperhive.claudeMarketplaces — Claude Code plugin marketplace sources
(default: official Anthropic marketplace)
- hyperhive.claudePlugins — plugin specs installed at harness boot
- hyperhive.claudePluginsAutoUpdate — pull latest marketplace index
before install; off by default
- hyperhive.cargo.shortMessages — shell wrapper injecting
--message-format short on cargo compile subcommands; on by default
The daemon does not call join_room_by_id. It fires a wake and writes
to mcp-loose-ends/matrix.json; the agent calls list_invites + join_room.
Replace the inaccurate 'Auto-accept invites' paragraph with 'Invite
wakes' describing the actual flow. Merge the pending-invites paragraph
into a single accurate block.
The matrix.md provisioning section mentioned trustedServers in passing
("wired up later by extending trustedServers") but never explained it
as a configurable option, and maxRequestSize was undocumented entirely.
Add a "Configuration tuning" subsection before "Assertion rationale":
- trustedServers (default []) — list of peer homeserver names to trust;
federation is protocol-on but no peer trusted until listed; link to
swarm.md for the multi-hive use case.
- maxRequestSize (default 20 MB) — request body limit matching the
matrix-spec recommendation; when and why to raise or lower it.