Commit graph

1,732 commits

Author SHA1 Message Date
atlas
36e5e19d8e refactor(gateway): extract the _ vhost agent + dashboard location groups
Step 3 of the hive-gateway.nix vhost cleanup. Lift the /agent/ catch-all
(+ its two internal error-page targets) and the catch-all dashboard proxy
out of the inline //-chain into agentLocations / dashboardProxyLocation
bindings. The default _ server's locations now read as a flat composition
of named groups — matrixRedirectLocations // wellKnownLocations //
agentLocations // dashboardProxyLocation // <auth optionalAttrs> — instead
of a deep nested literal. The auth-401 group stays inline (a self-contained
lib.optionalAttrs already).

Pure readability refactor, eval-identical: generated virtualHosts toJSON is
byte-identical before/after (8888 bytes, diff empty).
2026-06-07 21:52:23 +02:00
iris
90b7d61792 docs: fix dead /home.html alias in the H0M3 page heading
The route swap (#1501) renamed the source home.html → index.html (served
at /), so /home.html 404s. Drop the stale alias from the dashboard.md
section heading and align it with the leet-speak heading convention
(## FL0W page / ## L0GS page): "## Home page (`/`, `/home.html`)" →
"## H0M3 page (`/`)".

Trailing fix from the #1495 docs PR (the heading nit both argus and I
flagged, which an AGit push issue prevented from landing before merge).
2026-06-07 21:24:31 +02:00
lexis
60fb6a29c3 docs: fix front-matter for dashboard route at /dashboard.html (post-H0M3 routing swap) 2026-06-07 21:13:31 +02:00
lexis
a5268560e1 docs: add operator inbox + flow agent filter + flow collapse + home page docs (follow-up to #1469 #1472 #1473 #1464) 2026-06-07 21:13:17 +02:00
iris
8ddab401f9 feat(dashboard): serve H0M3 at /, relocate dashboard to /dashboard.html (#1464)
Step 2 of the nav restructure: make the H0M3 menu hub the landing page
at / and move the dashboard SPA to /dashboard.html, with every surface
linking back to the hub.

Mechanism (frontend-only, no host-side change — confirmed against the
ServeDir route table): the dashboard's ServeDir fallback serves
index.html at / via append_index_html_on_directories, and there is no
SPA path-routing catch-all to break. The dashboard SPA is served as the
plain file dashboard.html so it never shadows the exact-match
/dashboard/stream + /dashboard/history SSE routes registered before the
fallback.

- Swap the HTML entry files: the H0M3 page becomes index.html (loads
  home.js → served at /), and the dashboard SPA becomes dashboard.html
  (loads tabs.js → served at /dashboard.html). build.mjs copies the new
  set; JS bundle names are unchanged (referenced by absolute /static/
  paths, independent of the HTML filename).
- H0M3 Dashboard tile now points at /dashboard.html.
- The dashboard gains a "← home" back-link in its chrome; flow.html and
  logs.html relabel their back-link from "← dashboard" to "← home"
  (href stays / — which is the hub now). Pages link to the hub, not to
  each other.
- Agent page (app.js + stats.js): the "↑ dashboard" link now targets
  /dashboard.html. The API base (rebuild / answer-question /
  mark-all-read POSTs) stays the origin root, unchanged.
- Comment-only: tabs.js / flow.js / common.js references to the
  dashboard's old index.html filename updated to dashboard.html.

Note for review: git renders the file swap as a deleted home.html + an
added dashboard.html + a heavily-modified index.html, because index.html
exists on both sides with swapped content. It's a content swap, not a
rewrite — the built dist/ is verified (index.html→home.js, dashboard.html
→tabs.js).

Deferred to a follow-up: removing the FL0W / L0GS / M4TR1X "→" page-links
from the dashboard tab strip (touches tabs.js gating/overflow), and the
shared reusable chrome component (a later step).
2026-06-07 21:00:34 +02:00
atlas
d7e4028a16 refactor(gateway): extract the _ vhost matrix location groups into named bindings
Step 2 of the hive-gateway.nix vhost cleanup (follows the sub-domain
vhost extraction). Lift the two deepest-nested location groups of the
default _ server — the /matrix/ 301 redirect and the
.well-known/matrix/{client,server} discovery JSON, each carrying its own
let block — out of the inline //-chain into matrixRedirectLocations /
wellKnownLocations bindings. The _ vhost locations now open with
matrixRedirectLocations // wellKnownLocations // ... instead of two ~60-line
nested literals. agent/dashboard/auth groups stay inline (a later step).

Pure readability refactor, eval-identical: the generated
services.nginx.virtualHosts toJSON is byte-identical before/after (8888
bytes, diff empty) on a host with matrix+forge+gui+auth+tls enabled.
2026-06-07 20:40:55 +02:00
atlas
a03aafb004 refactor(gateway): extract forge + matrix sub-domain vhosts into named bindings
Step 1 of the hive-gateway.nix vhost-builder cleanup. The two
sub-domain vhosts (forge, matrix) were inline `lib.optionalAttrs`
blocks `//`-appended to the virtualHosts attrset, burying the
top-level structure. Lift them into `forgeVhost` / `matrixVhost`
bindings in the config-closure let so the composition reads as
`{ "_" = ...; } // forgeVhost // matrixVhost` — the three vhosts are
now visible at a glance. Also fixes a garbled merge-mangled comment on
the nginx-reload host-trigger.

Pure readability refactor, eval-identical: verified the generated
`services.nginx.virtualHosts` toJSON is byte-identical before/after
(8888 bytes, diff empty) on a host with matrix+forge+gui+auth+tls all
enabled. The deeper `_` vhost location-group extraction is a follow-up.
2026-06-07 20:40:55 +02:00
iris
e949129e75 refactor(flow): drop operator-inbox UI, now lives on Y3R C4LL (#1483)
The operator inbox moved to the dashboard's Y3R C4LL tab in #1469
(◆ 1NB0X ◆ section, with per-message + mark-all read). FL0W goes back
to being the pure event firehose, so remove its now-redundant inbox UI:

- flow.js: drop the operatorInbox store, inboxAppendFromEvent,
  buildInboxListNode, renderInbox, the inbox-pill click wiring, and the
  onAnyEvent hook that fed them. The side panel was only used for the
  inbox flyout on this page, so drop Panel.bind() + the Panel import too.
- flow.html: remove the inbox pill, the offscreen inbox-section div, and
  the side-panel markup.
- flow.css: remove the .flow-pill* and .flow-inbox-headless rules.
- home.html: Flow tile desc → "live all-agents message firehose".
- docs/web-ui/dashboard.md: drop the FL0W 0PER4T0R 1NB0X section, point
  at Y3R C4LL, and fix the count-pill + /op-send descriptions.

The agent filter, sent→delivered collapse, compose box, and OS
notifications on operator-bound traffic are unaffected.
2026-06-07 20:40:20 +02:00
damocles
f9fe3280f9 chore: justify the remaining keep-only cast + serde-default allows with reasons 2026-06-06 14:25:41 +02:00
atlas
30be7cd632 fix(dashboard): rustfmt api_operator_inbox match expression
The operator-inbox handler landed with an unformatted long match line
(`match state.coord.broker.unread_for_recipient(...)`) that rustfmt
wants wrapped. It was force-merged during the CI outage so the formatting
gate didn't catch it, and now the treefmt check fails for every PR based
on current main. Pure formatting, no logic change.
2026-06-06 13:49:53 +02:00
atlas
812a072e1c fix(matrix): point the tuwunel container resolver at the bridge dnsmasq
The hive-matrix nixos-container came up with an EMPTY /etc/resolv.conf
even with networking.nameservers set, so tuwunel hard-failed at boot
(no nameservers found). The nixos-container default useHostResolvConf=true
puts in-container resolvconf in host-tracking mode: it ignores
networking.nameservers and never receives the host resolv.conf across the
shared-netns boundary, so resolvconf regenerates an empty file.

When the hive network module is on, turn off host-tracking (mkForce, to
beat the module default) so resolvconf honours networking.nameservers,
pointing the resolver at the gateway-container dnsmasq at bridgeIp.
Network module off -> inherit the host resolv.conf.
2026-06-06 13:27:23 +02:00
damocles
c819eab947 chore: justify the cast_precision_loss allows with reasons (#1474 slice) 2026-06-06 13:10:00 +02:00
atlas
09bcf9fd7a chore(ci): drop issue tag from hive-ci-prefetch 401 log string
The runner's prefetch 401/403 diagnostic baked a literal issue tag into
its runtime journal output. Per the hive-wide rule (no issue/PR #NNN tags
in code), strip it — the message already explains the stale-core-token
condition and the operator remedy in full prose, so nothing is lost.
2026-06-06 12:34:51 +02:00
iris
7d00928c69 feat(dashboard): operator inbox with mark-as-read on Y3R C4LL
Agents that `send(to: "operator")` were easy to miss — they only
surfaced on the FL0W firehose with no read-state (#1469). Surface them
on the Y3R C4LL ("things waiting on you") tab as a proper inbox.

Backend:
- broker: `unread_for_recipient(recipient, limit)` — unacked messages
  for a recipient, newest-first. Mirrors `mark_all_read`'s filter
  EXACTLY (`recipient = ?1 AND acked_at IS NULL`, no `delivered_at`
  condition) so everything listed is exactly what mark-read clears —
  operator rows never get `delivered_at` set (no agent-socket recv).
- dashboard: `GET /api/operator-inbox` → `{ messages: [...] }` (id,
  from, body, at, in_reply_to, validated file_refs). Mark-read reuses
  the existing `POST /api/agent/operator/mark-all-read` (the route
  format-validates the name; "operator" passes; `mark_all_read`
  already acks `to="operator"` rows).

Frontend (Y3R C4LL):
- New ◆ 1NB0X ◆ section listing unread messages (sender · time · body,
  path-linkified) + a "✓ mark all read" button.
- Cold-loaded on page load + on tab activation; appended live from the
  broker `sent` stream (deduped on row id); cleared on mark-all-read.
- Unread count folds into the Y3R C4LL tab pill + the browser-title
  `(N)` prefix, so messages are visible from any tab.

Removing the now-redundant FL0W operator-inbox UI is a clean follow-up
(deferred to avoid a flow.js conflict with the in-flight #1473).
Backend (broker + route) is host-side — @damocles to review per plan.

Closes #1469.
2026-06-06 12:34:31 +02:00
iris
4c77eefc51 feat(flow): filter the timeline by agent
Adds an agent filter to the FL0W header (#1473): a select listing the
live agents narrows the timeline to messages involving the chosen agent
(matched on `from` OR `to`). Each message row now carries
`data-from`/`data-to`; non-matching rows get `.flow-hidden`. New rows
pick up the active filter at render time; changing the filter re-scans
existing rows. The selection persists in localStorage so a reload or
tab-switch keeps the view. The dropdown is populated from the live
container list (and stays current on container add/remove); a saved
selection survives even if that agent isn't currently listed.

Pure frontend; composes with the sent+delivered collapse (the surviving
collapsed row keeps its `data-from`/`data-to`). Closes #1473.
2026-06-06 12:05:02 +02:00
atlas
d9c7b7fcc1 fix(ci): hive-ci prefetch — correct partOf unit name + 401-harden token fetch
Two bugs that together kept the runner registration token from
refreshing (#1475):

1. Unit name: the prefetch's before/wantedBy/partOf targeted
   nixos-container@hive-ci.service, but a declarative containers.<n> is
   the host unit container@<n>.service (confirmed against the live
   container@hive-matrix.service during the #1465 incident). The wrong
   name made all three silent no-ops, so the partOf never bound — the
   RemainAfterExit oneshot stayed 'active (exited)' and never re-ran on
   nixos-container restart, leaving the stale token in place. Corrected
   to container@hive-ci.service.

2. 401-hardening: the registration-token fetch used a bare curl -sf | jq,
   so a forge-core-token that is stale/invalid for the current forge
   (e.g. after a forge rebuild) 401s and fails silently every attempt for
   the full 60s loop, then exits with a misleading 'core token absent or
   forge unreachable'. Now capture the HTTP status and fail fast + loudly
   on 401/403 with a clear message pointing at re-minting the core token.
2026-06-06 11:58:13 +02:00
atlas
c5e23fd3a3 fix(matrix): correct container ordering unit name to container@<n>.service
The host systemd unit for a declarative nixos-container is
container@<name>.service (confirmed from the live
container@hive-matrix.service status), not nixos-container@. The prior
commit's nixos-container@ ordering targeted a non-existent unit (a
silent no-op). Use container@hive-{matrix,gateway}.service so the
after-ordering actually takes effect.
2026-06-06 11:51:37 +02:00
iris
a2fe3f2e01 feat(flow): collapse back-to-back sent+delivered into one line
When a message directly wakes its recipient, the broker emits `sent`
then `delivered` for the same row id ~instantly, rendering two
near-identical lines on the FL0W timeline. Track each recent `sent`
row and, when its `delivered` lands within COLLAPSE_SECS (3s), upgrade
that row in place (arrow → green ✓, title "sent + delivered") instead
of adding a second line. A delivery that arrives later (recipient was
busy) still renders as its own row, so genuine delivery latency stays
visible.

`Sent` and `Delivered` share the same broker row id
(dashboard_events.rs), so matching is exact. The recentSent map is
bounded to 256 entries. Reply threading is unaffected (msgRowMap still
resolves the surviving row).

Closes #1472.
2026-06-06 11:50:01 +02:00
iris
a5f1337876 fix(home): un-leet the menu link labels
Per mara on #1464: keep l33t only in page headlines, not link labels
(we were overdoing it). H0M3's tiles now read Dashboard / Flow / Logs /
Matrix; the page banner headline stays H0M3.
2026-06-06 11:49:31 +02:00
iris
b0eb824cfa feat(frontend): add the H0M3 menu-hub page (#1464 step 1)
First step of the dashboard-tab consolidation (#1464): a static menu
page linking to every top-level surface, so the tab strip can later
shed its `→` page-links and the dashboard can graduate Stats/Settings
to their own pages.

- dashboard/src/home.{html,css,js}: a responsive grid of link tiles
  (D4SHB04RD, FL0W, L0GS, M4TR1X). Pure portal — no tabbar/SSE. Colours
  from the shared theme.css, base typography from common.css. The
  Matrix tile is hidden until home.js confirms `matrix_gui_enabled`
  (same gating as the dashboard's M4TR1X tab); home.js also fills the
  swarm/hive identity line.
- build.mjs: emit home.{html,css,js}.

Served at `/home.html` for now (additive — reachable via the existing
ServeDir, links to surfaces at their current routes). Promoting it to
`/` (and relocating the dashboard to `/dashboard` + wiring `← home`
back-links) is the next step — a route swap that touches hive-c0re's
static router, coordinating with damocles. Deliberately decoupled so
this page ships standalone without conflicting with the in-flight
tabs.js change (#1449/#1451).

Part of #1464.
2026-06-06 11:49:31 +02:00
damocles
3cac374c60 forge: revalidate the core token against the live forge before trusting it 2026-06-06 11:26:59 +02:00
damocles
2a840c14a2 chore: drop stale dead_code allows + the unused operator_questions get method 2026-06-06 11:14:35 +02:00
atlas
43776afbfd fix(matrix): order hive-matrix container start after the gateway (resolver)
Per operator review on the PR: when the network module is on, the
matrix container's resolver is the dnsmasq in the gateway container, so
order the matrix container start after the gateway container. This is
robustness for tuwunel's lazy federation lookups, not a boot
requirement — the boot fix is the resolv.conf nameserver line (the
failure was a parse error on an empty resolv.conf, not connectivity).
Soft 'after' (not 'requires') keeps lifecycles decoupled; network.enable
asserts gateway.enable so the gateway container unit always exists.
2026-06-06 11:02:25 +02:00
atlas
38f2435767 fix(matrix): give hive-matrix container a DNS resolver so tuwunel can boot
tuwunel hard-fails to start when /etc/resolv.conf has no nameserver
line (Failed to configure DNS resolver: no nameservers found in
config -> exit 1 -> systemd start-limit). The declarative
containers.hive-matrix generates its own resolv.conf via resolvconf
and, unlike agent containers whose resolv.conf is written by
hive-c0re's lifecycle, has no nameserver source -> it comes up empty
(just 'options edns0'). Defaulting network.enable on surfaced this:
the host DNS moved to the bridge dnsmasq but the container was never
pointed at it, so the homeserver could not boot, taking down matrix
for all agents.

Point the container at the hive resolver (the dnsmasq the network
module runs at bridgeIp) when the network module is enabled; the
container always shares the host netns (privateNetwork = false) so it
reaches bridgeIp whether or not isolateContainers is set. With the
network module off, inherit the host resolv.conf.
2026-06-06 10:50:55 +02:00
damocles
b7529f2e00 feat(matrix): log message-handler firing + wake delivery to localise the no-wake bug 2026-06-06 09:19:02 +02:00
damocles
7529c67f6b docs: slim CLAUDE.md to a lean repo index (drop the drifting per-file map) 2026-06-06 08:56:02 +02:00
lexis
f32684b242 docs: add endpoint name for container_stats (GET /api/container-resources) for parity 2026-06-06 08:52:02 +02:00
lexis
840abab82d accuracy fix: container_stats.rs tracks mem metrics only, not swap 2026-06-06 08:52:02 +02:00
lexis
bb990508c6 docs(CLAUDE.md): add hive_stats.rs and container_stats.rs entries (follow-up to #1430 #1432) 2026-06-06 08:52:02 +02:00
iris
e70584b632 feat(frontend): split theme CSS vars into a standalone theme.css
Phase 1 of stylix integration (#1457): extract the Catppuccin palette
into a dedicated, separately-linked stylesheet so a theme swap can
replace just that file without rebuilding the rest of the frontend.

- shared/src/theme.css (new): the `:root` palette, moved out of
  base.css (which now holds only the body typography it references).
- shared/package.json: export `./theme.css`.
- dashboard/src/theme.css + agent/src/theme.css (new): one-line
  re-exports of @hive/shared/theme.css so each package's esbuild emits
  its own standalone `dist/static/theme.css` (palette is NOT inlined
  into the page bundles).
- both build.mjs: add theme.css to the CSS build list.
- every page (dashboard index/flow/logs, agent index/stats/screen):
  link `theme.css` first, ahead of the page CSS, so the `:root` vars
  resolve for everything.
- docs/web-ui/css-vars.md: document the split + the no-rebuild rationale.

Behaviour-neutral — same colours, just relocated. Verified both
`npm run build` outputs: theme.css emits standalone (383b) with the
palette; no `--*` palette defs duplicated into common.css/agent.css.

Phase 2 (nix derivation that swaps theme.css from stylix colours) is a
follow-up; touches nix/frontend.nix, coordinating with damocles.

Part of #1457.
2026-06-06 08:46:45 +02:00
iris
a3e6585266 docs: tighten favorite-tools head normalisation wording
Per damocles (capture-side owner): "argv[0] basename" undersells the
normalisation and misleads — the head is the basename of the first
*real* command, looking past `cd repo &&` prefixes, env-assignments,
and prefix-runners (sudo/env), so `cd /repo && cargo build` records
`cargo`, not `cd`. Match the persistence.md phrasing.
2026-06-06 08:13:12 +02:00
iris
b9aa38960e docs(web-ui): document the /stats favorite-tools doughnut
Backfills the agent.md Stats-page section for the favorite-tools
doughnut (per-agent most-run bash commands) shipped by #1446 + #1448.
Notes the normalised bash_commands heads, the bash_breakdown read, and
the hidden-until-data behaviour (missing table degrades to empty).

Part of #1450 / completes the per-agent half of #1433's docs.
2026-06-06 08:13:12 +02:00
lexis
c31aaf7f4c accuracy fix: matrix ids owned by hive-c0re service user, not root (post-privsep) 2026-06-06 08:10:26 +02:00
lexis
6afaf03864 docs: document hive-chat room auto-creation in Matrix Space (follow-up to #1452) 2026-06-06 08:10:26 +02:00
iris
0a7d66c19e cleanup(dashboard): remove dead CSS selectors
Four selectors defined in dashboard.css but referenced nowhere in the
repo (verified against all html/js/rs, including dynamically-built class
names):

- .role-m1nd / .role-ag3nt — old per-role colouring; only `.role-pending`
  is still applied (`'role role-pending'`), and there's no `'role-' +`
  builder, so the m1nd/ag3nt variants are unreachable.
- .journal-body — the journald viewer is now a link to the dedicated
  logs.html page (`menuLink('journal logs →', …)`), not an inline panel.
- .talkform (+ its select/input/placeholder/focus rules) — old operator
  T4LK form styling, no longer emitted.

Part of #1450. Pure dead-code removal, no behaviour change; dashboard
bundle still builds (dashboard.css 36.9kb → 36.1kb).
2026-06-06 08:10:12 +02:00
atlas
a5ccb6048a fix(matrix): pin room_version=10 on the hive chat room createRoom
The restricted join rule needs room version >= 8. Pin it explicitly so a
future homeserver-default change can't silently invalidate the restricted
rule (which would fall back to invite-only and break the operator-joins-
from-the-Space path). Per review on the PR.
2026-06-06 07:59:24 +02:00
atlas
fe17b5f8a7 feat(matrix): auto-create a hive chat room as a child of the hive Space
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).
2026-06-06 07:59:24 +02:00
damocles
6e39515669 feat: type-scope events vacuum to prune only stream rows (14d) + drop turn-stats vacuum 2026-06-06 07:57:27 +02:00
iris
f8cf76b62d docs(web-ui): document the new per-agent /stats chips + result trend
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.
2026-06-06 07:56:43 +02:00
iris
a5914274ba feat(stats): surface "favorite tools" (most-run bash commands) on /stats
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.
2026-06-06 00:53:12 +02:00
damocles
1569d55f78 feat: capture normalised bash command heads for the favorite-tools stat 2026-06-06 00:52:56 +02:00
atlas
48b7c24265 fix(nix): emit explicit port in .well-known/matrix/server delegation
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.
2026-06-06 00:37:07 +02:00
damocles
31d9cb561a fix: hive-forge agit pr-create sets multi-line body via rest patch 2026-06-06 00:36:29 +02:00
damocles
57b1a2d3ea docs: clarify certFingerprint does not govern matrix federation tls 2026-06-06 00:21:52 +02:00
damocles
e029944cb3 docs: specify certFingerprint format and generation recipe 2026-06-05 23:38:54 +02:00
damocles
c5c47b29b4 fix: own /run/hive-agent as hive-core so the unprivileged daemon can create per-agent socket dirs on first launch 2026-06-05 23:30:50 +02:00
damocles
4c8e916ae6 fix: add /run/lock to hive-priv ReadWritePaths so nixos-container can lock on first launch 2026-06-05 23:20:35 +02:00
iris
dbb9f2a787 stats(p3): normalise cpu% against host CPU count, not process affinity
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.
2026-06-05 23:06:33 +02:00
iris
03ea6d1bda feat(stats): per-container cpu/mem load (#1424 p3)
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.
2026-06-05 23:06:33 +02:00
damocles
14c7b0d406 feat: group host-side /var/lib/hyperhive state into db/ forge/ matrix/ run/ subdirs with startup migration 2026-06-05 23:01:47 +02:00