Commit graph hyperhive/docs/web-ui
Author SHA1 Message Date
iris
07b62612b0 docs: restructure into topic subdirectories, collapse duplicated index
Per mara's go-ahead on hyperhive#3902 ("getting started is good, but
terminal rendering does not go in there i think"):

Moved 21 top-level docs/*.md files into 7 new topic subdirectories
(existing web-ui/, turn-loop/, swarm/, tools/, crates/ untouched):
  getting-started/  setup.md
  agent-lifecycle/  agent-hierarchy.md, approvals.md, persistence.md
  trust-boundary/   boundary.md, security.md
  integrations/     forge.md, matrix.md, github.md, knowledge.md
  networking/       gateway.md, network.md, snapshot-store.md
  scheduler/        jobq.md, coordinator.md, ci.md, observability.md
  process/          conventions.md, gotchas.md, pr-review-gate.md
  web-ui/           terminal-rendering.md (moved into the EXISTING dir,
                    per mara's correction to the original getting-started
                    guess -- it's UI implementation detail, not onboarding)

The physical layout now matches docs/README.md's own topical headers,
which already amounted to this taxonomy -- see the scoping comment on
the issue for the two findings that motivated this (a genuine
duplication between CLAUDE.md's old "Reading paths" list and
docs/README.md's grouped one, since drifted out of sync with each
other; and the flat layout not matching the grouping we already had).

Fixed every cross-reference this moved across the whole repo (~120
files: docs/ internal links at every depth, Rust doc comments, nix
module option docs, crate READMEs) -- verified two ways: a grep sweep
confirming zero remaining references to any old path, and a script
that resolves every markdown link in docs/**/*.md + CLAUDE.md +
README.md against the filesystem and reports anything that doesn't
exist (zero broken links).

Collapsed CLAUDE.md's "Reading paths" section (the duplicate) down to
a pointer at docs/README.md, now the single index. Rewrote
docs/README.md itself to use the new subdirectory paths and added the
one doc it was missing that CLAUDE.md's old copy had (pr-review-gate.md).

Classified all 22 docs/*.md files first via a haiku subagent (mara's
suggestion) on two axes -- proposed grouping and operator-vs-
implementation focus -- before finalizing the taxonomy; spot-checked
the report and found internal inconsistencies (its classification
table disagreed with its own summary section for a few files), so this
taxonomy is my original proposal + the one correction mara gave
directly, not a blind application of the subagent's table. The
operator-focus data it gathered is still useful for a follow-up
content pass (docs skewing 'mixed' rather than pure operator-facing),
not addressed in this PR -- structure only.

nix fmt clean, both pre-push lints clean.
2026-09-02 01:55:37 +02:00
iris
d9937ee834 dashboard: also remove the tombstone revive trigger
mara asked on PR #3854 to remove the revive action alongside the
blank-name spawn form. Both posted to /api/request-spawn as the last
two frontend callers; with this the dashboard has no UI path left that
hits that endpoint (backend removal/decision stays damocles's call).

Drops the K3PT ST4T3 tombstone row's ⊕ R3V1V3 form, leaving PURG3 as
the only per-tombstone action. Updated the two doc/comment spots that
described the now-gone button.
2026-08-31 19:35:45 +02:00
iris
8475d9921f dashboard: remove the spawn-new-agent trigger from the Y3R C4LL tab
Frontend half of removing hive-level agent spawning (swarm-level
creation now covers it, and its forge-works confirmation just landed
in hive/hive-chat). Removes call.js's blank-name spawn-request form
(R3QU3ST SP4WN) and its now-orphaned .spawnform CSS.

Deliberately keeps core.js's tombstone-list revive action (R3V1V3) --
a different feature (respawn an *existing* agent, reusing its kept
state), not agent creation, and not what this issue asked to remove.
It happens to post to the same /api/request-spawn action with the
tombstone's own name pre-filled rather than a blank input.

Backend endpoint + wiring is a separate slice (damocles).
2026-08-31 19:30:38 +02:00
iris
b33bb7a3d3 Move dashboard settings into Y3R C4LL tab, drop standalone S3TT1NGS page
mara (issue #3817): remove the home link + page, put the setting toggle into the Y3R C4LL tab. Deleted settings.html/.js/.css; the browser-notification toggle (the only content there) now renders as a ◆ PR3F3R3NC3S ◆ section under Y3R C4LL's approvals/inbox, wired the same way (NOTIF.bind()/NOTIF.show() in common.js — no behavior change, just a new mount point). Updated build.mjs's entry lists and every doc/comment that pointed at the old page.
2026-08-31 12:57:31 +02:00
iris
146db58bab docs: trim M4TR1X-page LinksMenu paragraph to the pointer, not the impl
mara: strip impl details from docs. Dropped the nix-module name, struct literal, and gating-condition restatement — docs/swarm/ui.md::Quick links already covers that; this section only needs to say where the link lives now.
2026-08-31 12:55:40 +02:00
iris
19ed400cdd docs: M4TR1X page is reached via swarm-ui's LinksMenu, not opened directly
mara (PR#3820): the operator doesn't type /matrix/ into the browser — it's a swarm-level link (hive-matrix.nix registers it into services.hyperhive.swarm.controller.links, rendered by swarm-ui's LinksMenu). Corrected the M4TR1X page doc, and fixed the hive-matrix.nix comment that still described the removed H0M3 tile in present tense while I was in there.
2026-08-31 12:55:40 +02:00
iris
40be8222b8 docs: fix stale Matrix-tile reference in M4TR1X page section
argus (PR#3820 review): the M4TR1X page section still said the operator opens /matrix/ from the H0M3 hub's Matrix tile — that tile no longer exists after this PR removed it. Fixed to say the page is opened directly.
2026-08-31 12:55:40 +02:00
iris
2490181055 H0M3: remove Forge/Matrix tiles from hive home
mara (issue #3816): remove the swarm-service links (forge, matrix) from the hive home hub. Both surfaces are still reachable directly (forge's own public URL, /matrix/); they just no longer get a tile on H0M3. Dropped the now-dead reveal/href-fill logic in home.js and updated the two docs that described the old gating.
2026-08-31 12:55:40 +02:00
damocles
22adfd1451 remove the 1NFR4 dashboard panel and the now-writer-less audit log 2026-08-31 00:18:21 +02:00
damocles
7516a4e10e remove hive-level infra-container restart from web ui and agents 2026-08-31 00:18:21 +02:00
iris
f14056996e terminal: catch the remaining stale ask/answer references
argus, reviewing PR#3793: a third stale  ask mention survived in the
same file/table the first pass touched (docs/terminal-rendering.md's
icon legend) — tool_icon() has no ask/answer arm at all, confirmed by
reading the function directly. Swept the whole tree this time instead
of trusting the earlier narrow grep: found three more —
docs/web-ui/dashboard.md's S3TT1NGS section still documented the
expand-tool-output toggle as living on the dashboard, which moved to
the per-agent page's own SettingsMenu popover in #3780 and was never
followed up here; markdown.ts/streamRow.ts/terminal.css had the same
send/ask/answer/recv phrasing as the original two comments.
2026-08-30 20:13:49 +02:00
damocles
2850270829 hive-c0re/hive-sh4re: remove the ask/answer wire protocol + core routing 2026-08-30 01:18:17 +02:00
damocles
46183795dd hive-c0re, docs: sweep remaining stale ask/answer-dashboard references 2026-08-29 23:28:32 +02:00
damocles
ff0a6660aa dashboard: remove the Y3R C4LL questions pane (ask/answer removal, frontend) 2026-08-29 20:35:27 +02:00
iris
cd339af91b agent.css: delete dead .overflow-btn/.overflow-menu/.overflow-item rules
`OverflowMenu.tsx`/`.css` were deleted (rebuild button removed outright,
dashboard link moved into `MetaNav`), but `agent.css` still carried the
whole trigger+popover+item rule set — grepped the entire `agent`
package, none of these classnames appear in any current markup.

Also fixed three tombstone comments elsewhere in the file that pointed
at the now-also-deleted `.overflow-item-*` classes as "where it moved
to" — they'd have dangled once those rules were gone too. And two stale
doc claims caught in the same sweep: `docs/web-ui/agent.md` still listed
`OverflowMenu.tsx` in the header's component tree and described "the
overflow menu" as a live effort-picker location.
2026-08-29 10:16:00 +02:00
iris
668ccc2278 agent: remove rebuild button, move dashboard link into the links menu
mara (#3704): 'remove rebuild button, move link to dashboards into
links menu.'

The overflow (⋯) menu existed for exactly two items: the dashboard
back-link and a rebuild-container action. Rebuild is gone outright —
the dashboard's own R3BU1LD button already covers it, this was just a
rarely-used shortcut not worth its own menu. The dashboard link moves
into MetaNav's links popover (now the first item, above stats/forge/
config/extras) instead. With both gone, OverflowMenu had nothing left
to justify existing as a separate component — deleted along with its
CSS and the now-unused rebuildAction.ts (only consumer).

MetaNav gained a dashboardBase prop (Root.tsx already computes this
via resolveDashboardBase for InboxPanel/pause — reused, not
duplicated) and renders the dashboard link as a real <a>, same
treatment as every other item in that popover — no dangling
window.open()-only affordance.

Updated docs/web-ui/agent.md's Header section and the couple of
now-stale OverflowMenu references in index.html's/MetaNav.css's own
comments.

Verified: header now shows a single trailing icon-badge (was two),
popover opens with dashboard first then the agent_links() set.
tsc --noEmit clean, build clean, both pre-push lints clean.
2026-08-28 23:40:56 +02:00
iris
8e97fc6263 docs: shape.md — fix stale app.js example, app.js no longer exists
argus, non-blocking note on PR#3702: the relative-path-resolution
example still used static/app.js as its illustrative filename after
that file was deleted in the cutover. Mechanism described was still
correct, just a stale filename a future reader could get confused
chasing. Swapped to static/main.js (the agent page's own script) and
static/stats.js (the /stats subpage example, more accurate than
main.js there since that's specifically about a subpage's own
script).
2026-08-28 23:18:21 +02:00
iris
fa2b360e74 agent: cutover — index.html now serves the Preact rewrite, app.js deleted
mara: 'i merged this without realizing you still did not delete the
old code. pls follow up with ripping out the old code.'

- index.html: dropped the old static header/main/composer/overflow-
  menu markup and app.js's <script> tag. Now just <div id=preact-root>
  + <script src=static/main.js>. main.css's <link> lands after
  agent.css's — cascade order argus flagged matters for LoginFlow's
  .login-card / MetaNav's popover to win against agent.css's legacy
  rules, confirmed explicitly rather than assumed at this exact step.
- build.mjs: app.js dropped from the esbuild entryPoints (stats.js
  keeps its own bundle, unaffected — separate page, separate script).
- frontend/packages/agent/src/app.js deleted (1717 lines). screen.html
  has its own inline <script>, untouched — never depended on app.js.
- docs/web-ui/agent.md: rewrote the Header section to describe the
  real Preact component tree and the badges+pills-together layout
  (deferred from the earlier commits on this PR specifically so it
  wouldn't describe a hybrid state — this is that promised follow-up).
  Touched up the one other app.js-specific mention in the endpoints
  section. Left the Main/composer/side-panel/live-view/slash-command
  sections alone — behavior there is unchanged, verified faithfully
  ported throughout this PR's earlier commits.

Verified against the REAL dist/index.html (not the dev-preview
harness) — a scratch mock server serving the actual built output
end-to-end, screenshotted clean. tsc --noEmit clean, build clean, both
pre-push lints clean.
2026-08-28 23:14:52 +02:00
iris
638e1ac2c6 swarm-ui: delete StatusChip, migrate its 3 callers to shared Badge
mara: non-interactive Badge and StatusChip render identically (same
padding/radius/font, same tone-to-color mapping) and StatusChip's
4-tone/single-label shape is a strict subset of Badge's — no real
reason to keep both. Deletes StatusChip.tsx/.css, migrates AgentsPage's
config-PR chip, HivesPage's freshness chip, and ComponentsPage's own
table-status sample to Badge (tone/value, no onClick). Also drops the
now-redundant standalone StatusChip demo section on /components (the
Badge section already covers all 4 former chip tones plus accent).

Updated the two stale StatusChip references outside swarm-ui too:
design-guide.md's component-list example and colors.css's WCAG-
contrast-rationale comment.
2026-08-28 13:21:49 +02:00
iris
4af890f01d hive dashboard: bulk pause + resume in the selection bar
Mechanical addition to the existing bulk-action framework
(renderSelectionBar/addBulkButton, swarm.js) -- two per-agent actions
already exist (POST /api/pause/, /api/resume/, see hive-agent-menu.js),
this just gives the selection bar the same all-or-nothing enablement
rule the other six bulk buttons already use (pause enabled only when
none of the selection is already paused, and vice versa for resume).

.btn-pause reuses .badge-paused's yellow so the trigger and the
resulting state pill read as one colour; .btn-resume is green like
.btn-start (both are "go" actions). Docs updated to list both in the
Selection bar reference.
2026-08-24 11:37:04 +02:00
iris
b25aa157df swarm-ui: give Panel an optional header icon slot
Adds an `icon` prop to Panel (small emoji glyph left of the title,
aria-hidden, chosen per panel with no default) and wires it into every
current Panel caller: hives (bee), create-agent's form (robot) and info
panel (identity card, moved off the info panel's body copy where it
started as a one-off), jobs (puzzle piece), the components gallery
itself (toolbox), and the 404 page (compass). Adds a components-page
demo section and a whimsy-section pointer in the design guide.

Closes: #3508
2026-08-19 17:22:48 +02:00
iris
afe627e0a9 swarm-ui: derive theme override from colors.css instead of duplicating hex values
mara's review: the theme override read as a hand-copied duplicate of
colors.css's hex values instead of deriving from it. Restructured
colors.css to declare each palette's 16 hex values exactly once
(--mocha-baseNN, --latte-baseNN) and have every activation block
(the default, the prefers-color-scheme media query, and two new
:root[data-theme='light'|'dark'] blocks) just re-point the active
--baseNN slot at one of those two raw palettes via var() - never a
second copy of a hex value.

theme-apply.ts simplifies to match: it now only toggles a data-theme
attribute on <html>, same shape motion-apply.ts already had. No
palette values live in JS at all anymore.

Re-verified the override still genuinely outranks the media query
with the new mechanism: same seed-localStorage-while-forcing-the-
opposite-OS-preference test as before, both directions still render
the stored override correctly.
2026-08-18 23:58:48 +02:00
iris
72e087b086 swarm-ui: fix WCAG contrast failures in the light-theme accent slots
argus review: the literal Catppuccin Latte accent hexes (base08-0F)
fail badly as StatusChip fill-text (green/amber/red/yellow on
--purple-dim/base03: 1.4:1-3:1, need 4.5:1) and even as plain text on
--bg/base00 in the agent/dashboard packages that also import this file
(2.3:1-4.8:1). Root cause: Latte's own accents are calibrated against
Lattes near-white base/crust, not a mid-gray surface1; the Mocha row
does not hit this because Mochas pastel accents are already light, so
they contrast fine against a dark surface1 - Lattes saturated-but-mid
accents do not have the same headroom against Lattes own lighter
surface1.

Fix: darken each accent slot from stock Latte (same hue/saturation,
lower HSL lightness via binary search) until real WCAG contrast against
base03 clears 4.5:1 with margin - verified this also clears >7:1
against base00, so both the swarm-ui chip case and the plain-text case
elsewhere are covered by one set of values. base00-07 stay stock Latte
(no contrast role, just surfaces/foreground). Yellow and peach read
closer to olive/brown than a bright yellow/orange once darkened this
far - an inherent property of darkening a warm hue in sRGB, not a
mapping mistake; boosting saturation further did not rescue it
(checked).

Verified with headless-chromium screenshots against the built swarm-ui
bundle: StatusChip text (the exact case argus flagged) and every chip
tone on /components now read clearly.
2026-08-18 23:29:20 +02:00
iris
56e7a309e8 swarm-ui: respect prefers-color-scheme for a light theme default
colors.css shipped one fixed dark (Catppuccin Mocha) palette with no
light variant and no OS/browser-preference detection, so anyone
without a stylix-managed session (a phone browser, a future PWA
install) got the dark palette regardless of their light-mode
preference. This is an accessibility gap, not a cosmetic one - some
people need light for low-vision/contrast reasons, others need dark
for photosensitivity, the same reasoning that already gates
prefers-reduced-motion elsewhere.

Add a Catppuccin Latte row behind `@media (prefers-color-scheme:
light)`, ported through the identical base16 slot mapping (including
the existing sky-over-teal base0C substitution) so a swap between the
two rows never changes what a slot means. A stylix-generated
colors.css replaces the file wholesale with a single unconditional
:root block and has no media query in it, so a themed deployment is
unaffected either way.

Verified with headless chromium screenshots forcing both
prefers-color-scheme values against the built swarm-ui bundle - both
render with correct contrast, and the default (no forced preference)
render matches the light row.
2026-08-18 23:29:20 +02:00
iris
f0c362b688 docs: clarify dynamic colour derivation still traces to base16
Per mara's follow-up: the doc shouldn't read as 'no dynamic colour at
all' — mixing/lighter/darker derivation is fine and matches Material's
own approach, the constraint is that every derived colour still
traces back to the base16/stylix contract, not an independent source.
2026-08-18 21:21:11 +02:00
iris
61b7bb4b4d docs: rework design guide per mara's review
Addresses all 7 line comments from her REQUEST_CHANGES review:
- drop the issue-#3444 history pointer and any issue-number tracking
  refs throughout (a design guide states expectations, it isn't a
  change log or a status report)
- stop naming specific rejected technical solutions (SSE/WS) for a
  design constraint — state the chosen shape only
- flip the component-first heuristic: build the primitive first/
  alongside its first real caller, not after — the point is giving the
  next thing built ready-made blocks, not lagging behind usage
- drop the 'Open questions' section entirely — that's what the issue
  thread is for, not a doc
- stop leading Visual language with 'basis: Material Design' and then
  immediately carving out big exceptions — lead with what we actually
  want, mention Material as a minor closing influence instead
- drop 'future work'/timeline framing everywhere (motion override,
  PWA-as-future-slice, 'not shipped yet' theming caveats) — state the
  target design as the expectation, not its current build status
- reworded the stylix-wins theming bullet to drop 'build time', which
  reads wrong from a frontend dev's perspective (stylix supplies the
  palette separately, it isn't decided by the frontend's own build)
2026-08-18 21:21:11 +02:00
iris
a5864c0fde docs: fix design-guide accuracy nits argus flagged
- matrix-rain reference is in packages/dashboard/src/home.js, not
  swarm-ui — cite it correctly (dashboard package) rather than implying
  it lives inside this doc's own scope.
- drop FormField from the visible component-first inventory (it has no
  /components demo, deliberately — a real exception to the 'every new
  ui/ component gets a demo' rule stated two paragraphs later) and note
  the exception explicitly instead of leaving the contradiction.
2026-08-18 21:21:11 +02:00
iris
7dc3e710b4 docs: swarm-ui design guide
Distills the design-language discussion on #3444 into a durable
reference: visual language, motion, theming policy, data-freshness/
refresh, error UX, empty states, layout/viewport, component-first
design, and attention — plus an open-questions table pointing at the
still-unbuilt issues (#3452/#3453/#3454/#3456) instead of asserting
them as settled.

Mirrors css-vars.md's shape and links to it + to /components rather
than duplicating either. First draft for comment, not a final spec.
2026-08-18 21:21:11 +02:00
iris
1111577c91 extract build-queue rollup as a shared Preact component
New @hive/shared/jobq-rollup.js (JobqRollup.tsx + jobq-rollup.css),
mirroring JobqGraph's shape exactly: JSX use plus an imperative
mountJobqRollup(container, props) for a plain-.js call site. Fetches
Vec<hive_jobq_wire::StateCount> off `endpoint`, sums Running+Finishing
roots as "running" and Pending roots as "queued", renders nothing when
both are zero. Optional `queueHref` adds a "view queue -> " link.

Swapped dashboard's hand-rolled queue-summary banner (swarm.js) over to
this component instead of keeping two parallel implementations - same
"one shared component" pattern JobqGraph already set for the rebuild
queue tree view. Mounted once into a new #jobq-rollup-section, kept as
a sibling of (not inside) #containers-section since that section gets
replaceChildren()-wiped on every container-state render, which would
tear down and remount a Preact tree on every tick. Refreshed via the
mount handle's .refresh() on rebuild_queue_changed, same as builds.js's
JobqGraph handle.

Also mounted in swarm-ui's /jobs page, above JobqGraph, with no
queueHref (a link back to the page you're already on is noise) - the
literal ask on hyperhive#3364.

Verified: npm run build (whole workspace) and swarm-ui typecheck both
clean, comment-block + issue-ref lints run manually, headless-chromium
screenshots of both the dashboard SW4RM tab and swarm-ui's /jobs page
against mocked /api/jobq/rollup payloads - banner renders identically
in both, with and without the queue link as expected.
2026-08-16 22:08:38 +02:00
iris
ecf01f5e87 docs: remove historic framing, state what JobqGraph is now 2026-08-16 15:18:25 +02:00
iris
37161cd136 dashboard: replace <hive-jobq-graph> with a shared Preact component
Ports the shadow-DOM <hive-jobq-graph> custom element
(frontend/packages/shared/src/jobq-graph/) to a Preact component
(JobqGraph.js) shared by the dashboard and swarm-ui, per hyperhive#3310.

- JobqGraph.js: written with plain h() calls (no JSX) so the same file
  compiles unmodified under both the dashboard's text-loader CSS config
  and swarm-ui's JSX config. Exports `JobqGraph` for JSX use and
  `mountJobqGraph(container, props)` for the dashboard's non-JSX
  imperative mount, returning a `{refresh(), update()}` handle matching
  the old custom element's public surface. Same rendering contract as
  before: indented state tree, payload.label verbatim, payload.data as
  a generic key/value list, "waits on: <label>" text for Node-kind deps,
  per-state filter checkboxes, optional cancel button.
- jobq-graph.css: light-DOM adaptation of the old shadow-scoped
  stylesheet (:host -> .jg-root, otherwise unchanged).
- dashboard/src/builds.js: local mountJobqGraph() renamed to
  mountRebuildQueue() to avoid colliding with the newly-imported shared
  mountJobqGraph; cancel handling is now a plain onCancel callback
  instead of a DOM CustomEvent listener (no shadow boundary to cross
  anymore).
- dashboard + shared package.json: added preact as a dependency (matches
  swarm-ui's existing pin, 10.29.8) - the dashboard was a vanilla-JS MPA
  with no Preact/JSX pipeline before this.
- Removed the old hive-jobq-graph.js/.css entirely (confirmed via grep
  it had exactly one consumer, dashboard/src/builds.js, so this is a
  clean swap, not parallel maintenance of two implementations).
- Updated stale doc-comment references to the old element name in
  builds.html, tabs.js, swarm.js, docs/web-ui/dashboard.md, and
  hive-c0re/src/job_queue/mod.rs.

Verified: npm run build (whole frontend workspace) and npm run
typecheck (swarm-ui) both clean; cargo build/clippy/test -p hive-c0re
all clean (331 tests, 0 failures); headless-chromium screenshot of
/builds.html against a mock GET /api/jobq/graph payload confirms full
visual/behavioral parity with the old custom element (tree, filter
checkboxes, cancel buttons, error text, waits-on line, data list, live
build log panel).

This covers the dashboard-replacement half of hyperhive#3310 only. The
swarm-ui half (rendering the CreateAgent DAG on the agent-creation page)
is downstream of hyperhive#3306/#3124 landing - no swarm-ui page exists
yet to mount it in.
2026-08-16 15:18:25 +02:00
iris
c67100588e docs+nix: fix stale certFingerprint/HYPERHIVE_PEERS references (hyperhive#3294)
Follow-up to the plumbing removal: docs/swarm/README.md gets the
biggest rewrite (drops the whole "Fingerprint format" section, fixes
the runtime-effects list, the WireGuard config example + "what the
mesh does" bullet), docs/gateway.md and hive-gateway/options.nix drop
4 "needs no certFingerprint" mentions, swarm-peers-removed.nix's
migration-warning text no longer tells an upgrading operator to carry
a field over that no longer exists, swarm.nix/swarm-wireguard.nix/
swarm-controller.nix/swarm-controller's main.rs get comment fixes
where they described the now-removed HYPERHIVE_PEERS shape. Also
caught one more stale "peer hives" mention in docs/web-ui/README.md's
SW4RM tab description that the first pass on this issue missed.
2026-08-15 19:56:11 +02:00
iris
8c8f0e2758 docs+nix: fix stale peer-hives-dashboard references (hyperhive#3294)
Follow-up to the peer-hives removal: docs/web-ui/dashboard.md drops
the whole "P33R H1V3S" section + its stale #peers hash and tab-strip
mentions; docs/swarm/README.md's runtime-effects list and
cross-references point at swarm-ui's roster page instead. Nix comments
in hive-c0re/environment.nix, swarm.nix and swarm-wireguard.nix that
described HYPERHIVE_PEERS/certFingerprint as dashboard-consumed are
updated to say what's actually still true (agent identity only).

Deliberately NOT removed: the `certFingerprint` nix option itself.
It has no remaining Rust consumer, but deleting a documented,
potentially already-set option is a bigger, breaking change than
removing dead display code — flagged in docs/swarm/README.md with a
note instead of silently dropped, so an operator or reviewer can make
that call explicitly rather than have it made for them here.
2026-08-15 19:55:29 +02:00
iris
4388719b76 docs(web-ui/agent): fix stale NavLink type name
Verified against hive-agent/src/web_ui/state.rs: the struct is AgentLink
(AgentLinkKind for kind), not NavLink -- NavLink doesn't exist anywhere in
the Rust or frontend source.
2026-08-15 12:45:22 +02:00
iris
26b55f34d3 docs(web-ui/shape): fix stale CSS bundle count, SSE route prefix, bind-retry cap claims
Verified against frontend/packages/dashboard/build.mjs, hive-c0re/src/dashboard/mod.rs,
and hive-agent/src/web_ui/mod.rs:
- dashboard ships 9 page CSS bundles + colors/theme/common, not 4
- dashboard SSE routes are /api/dashboard/stream + /api/dashboard/history, not
  /dashboard/stream + /dashboard/history
- per-agent bind_with_retry has a MAX_BIND_ATTEMPTS=12 cap (gives up), unlike the
  dashboard's genuinely uncapped retry loop
- assets/swarm.js, assets/call.js -> swarm.js, call.js (no assets/ dir exists)
2026-08-15 12:45:22 +02:00
iris
3e9f2f2fd5 docs(dashboard): fix stale facts found in source-verification sweep
- server-warnings banner: was described as disk-pressure-only; it's now
  a push-based registry with multiple producers (forge/CI boot
  failures, agent-state warnings), and shown on more standalone pages
  than listed
- browser tab title: actual default/format is "hyperhive // h1ve-c0re",
  not "hive / c0re"
- SW4RM container tree: ContainerView.parent comes from
  agent_config/topology.rs, not the ambiguous dashboard/topology.rs
  (which only holds set-parent endpoints)
- T00L GR0UPS: tool-group enumeration was missing "forge"; root agent's
  default (MANAGER_DEFAULT) is not literally "all groups" -- it excludes
  forge and web_tools
- ST4TS moved to its own /stats.html page a while back; section still
  called it a dashboard tab
- P33RS is a headline block within the SW4RM tab, not its own tab --
  contradicted the doc's own chrome-header description
- active model badge: reads hyperhive-harness.json's active_model
  field, not a bare harness/hyperhive-model file
- themed dialogs: modal.js lives in the shared package
  (@hive/shared/modal.js), and themedToast takes (message, opts) not
  a single options object
- graceful stop: backend uses a Signal/Drain job-queue node pair, not
  a "GracefulStop" transient kind; hivectl flag is `stop --graceful`,
  not a bare `--graceful`
- container_state_changed event: named a nonexistent
  auto_update::rebuild_agent as an emit site; actual sites are
  actions::approve and the job queue's own node execution

Verified against hive-c0re/src (dashboard/, stats/, job_queue/,
container_view.rs), hive-sh4re/src/permissions.rs, and the dashboard
frontend package (tabs.js, stats.js, swarm.js, builds.js, modal.js).

No structural/prose changes beyond what the fact corrections required.
2026-08-15 12:45:22 +02:00
iris
4f03a82cc5 docs: fix 3 more stale dashboard.rs refs argus caught in review
hive-c0re/src/dashboard.rs became a module directory
(hive-c0re/src/dashboard/) a while back; three more references to it
as a single file survived the #3281 sweep (conventions.md x2,
web-ui/shape.md's StateSnapshot pointer). Same bug class the sweep
was hunting for, argus caught it in review.
2026-08-15 12:45:22 +02:00
iris
dd8b5db7ab docs: fix remaining stale internal references from the #3281 sweep
Two follow-ups the per-file sweep workers flagged but couldn't fix
themselves (either not their assignment, or not visible from their
worktree):

- web-ui/dashboard.md's P33RS tab named dashboard.rs, which no longer
  exists (hive-c0re/src/dashboard/ is a module dir now); the function
  moved to state_snapshot.rs.
- approvals.md and conventions.md used hive_ag3nt:: as a Rust
  module-path prefix. hive-agent is a bin-only crate (no lib target),
  so that prefix never resolved to anything; also fixed the
  hive-ag3nt/prompts/system.md path to the real hive-agent/prompts/.

All three verified directly against the current source tree, not
guessed.
2026-08-15 12:45:22 +02:00
iris
f104d39c72 docs(web-ui/agent): add section headers, dedupe shared shape/rendering detail, trim changelog framing 2026-08-15 12:45:22 +02:00
iris
721a99ed64 docs(web-ui/shape): add routes header, trim historical framing 2026-08-15 12:45:22 +02:00
iris
785b59a4bb docs(dashboard): fix misplaced CR3D3NTIALS content, dedupe, trim history 2026-08-15 12:45:22 +02:00
iris
5bd085fbac web-ui: expose per-agent paused status, add pause/resume to the agent page's own overflow menu
hive-agent's own web_ui module never exposed the agent's own paused
status to its own /api/state — the dashboard's cross-container view
knew it, but a per-agent page had no way to know it's paused. Added
StateSnapshot.paused (a direct stat of the same harness-local pause
marker hive-c0re's Coordinator::is_paused checks).

The per-agent page's ⋯ overflow menu now has a pause/resume item that
POSTs to hive-c0re's existing /api/pause/<name> / /api/resume/<name> —
the same endpoints the dashboard's <hive-agent-menu> already uses,
same cross-origin form-submit pattern the existing rebuild-container
item uses. The item's label tracks state.paused on every /api/state
refresh so a pause/resume triggered from the dashboard while this page
is open doesn't leave a stale action showing.
2026-08-11 20:42:53 +02:00
iris
ecf9ff4d80 web-ui: remove dead ask->operator inline-answer binding from the per-agent terminal
hyperhive#2922: the inline-answer slot (pendingAskBinds/reconcileAskBinds/
buildAnswerForm) depended on a since-removed /api/loose-ends endpoint
and had been silently non-functional the whole time — nothing ever
reassigned lastLooseEnds, so the reconciler always no-op'd.

Per mara's call on the issue (ask/answer is deprecated per #2850, only
the main dashboard UI needs to work, remove the broken per-agent inline
view): ripped out the dead JS (binding + form + CSS) rather than
restoring the endpoint. An ask tool call now renders like any other
tool call, no inline answer affordance; the operator answers via the
dashboard's own question surfacing.

Also fixed adjacent doc staleness this same removal made newly
contradictory (docs/web-ui/agent.md, docs/terminal-rendering.md):
the doc already described the loose-ends/bash-tasks flyouts and the
ask-binding as recently dead, but the endpoint reference table and a
header-pills bullet list still described them as live.
2026-08-11 20:21:52 +02:00
atlas
07852cabc1 feat(3088): move the gateway's nginx + dnsmasq onto the host
The gateway's nginx + dnsmasq no longer run in their own nspawn container.
`nix/host-modules/hive-gateway/default.nix` loses the
`containers.hive-gateway` wrapper and everything that existed only to punch
holes in it: `privateNetwork = false`, `CAP_NET_ADMIN`, five bind mounts,
its own `stateVersion`, `networking.firewall.enable = false`,
`networking.resolvconf.enable = false`, and the `hive-gateway-resolv`
path+service pair. 465 -> 303 lines.

The container never bought isolation here. It shared the host netns by
necessity — nginx binds the host's :80/:443, dnsmasq answers on the bridge —
so each of those settings was undoing a boundary the gateway could not
afford in the first place.

Four things made it more than a deletion, none of them visible in the nix
diff:

- The self-signed cert service also imports the hive CA leaf, so removing it
  with the container would have left nginx naming a missing cert file, which
  it refuses to load at all.
- The nginx reload is a hive-priv verb. It still needs root, but no longer
  for the reason its doc gave, and `--machine=` was both transport and
  scope — so the unit name is now hard-coded in the helper as the
  containment.
- The lifecycle verb named a container that stops existing.
- `journalctl -M hive-gateway` had no machine to enter.

Per the operator's ruling, the operator verb keeps working and agents lose
it. `InfraContainer` answered three questions that used to share an answer;
it now splits into `name()` (identity), `target()` (Container vs HostUnit),
`service_unit()` (the systemd unit), and `agent_restartable()`, which the
MCP restart path checks before the capability so the refusal cannot read as
"ask for infra_admin". `SIBLING_CONTAINERS` drops the gateway — it gates the
requests that name a container as a string — while `FromStr` still accepts
it, because that answers what a name is, not who may act on it. The
dashboard's gateway journal reads host journald filtered to `nginx.service`.

Prose was corrected where it only named a location, and re-argued where the
container was doing security work: a `0666` per-agent socket was safe
because only the gateway container had the directory bind-mounted. There is
no mount now, so the directory permissions are the whole of the access
control — the constraint holds, its mechanism doesn't.

Gate: nix fmt / clippy --all-targets -D warnings / cargo test all clean (710
tests); hivectl-cli.md regenerated from the clap tree. The nix eval was run
in both TLS shapes at this commit: every delta in the rendered
virtualHosts is one of the three intended path moves, dnsmasq settings are
byte-identical, and the absence probe flips true -> false with bindMounts
emptied.
2026-08-11 18:01:03 +02:00
iris
b785f96d30 dashboard: distinct "gave up" badge for a crash-looped container
Frontend half of the two-PR split on the systemd restart-bound work
(clause 2): once a container's unit hits systemd's bounded restart
limit and stops on its own, that read exactly like a deliberate stop
("not running") — no way to tell "gave up" from "off on purpose".

Renders ContainerView.failed as a distinct red "gave up" badge on the
container row, in place of the muted "not running" badge. Both states
have running: false; failed is the new orthogonal fact that tells them
apart, same "independent flags, no state machine" shape as
paused/needs_update/needs_login. An older backend without the field
serves failed: undefined, which reads falsy, so this degrades cleanly
to the existing single "not running" badge.

Frontend-only — no Rust changes. Safe to merge in either order
relative to the backend PR carrying ContainerView.failed itself.
2026-08-10 23:14:36 +02:00
iris
1e13b88c8c jobq graph: state filter on /api/jobq/graph + multi-select checkboxes
GET /api/jobq/graph gains a states query param (comma-separated
hive_jobq::State names): narrows the served root groups to the named
states, keeping a group whole (filtering by a root's own state, which
is already its subtree's rolled-up answer). Absent, empty, or fully
unrecognised is the identity filter, matching prior behaviour.

hive-jobq-graph.js gains a row of per-state checkboxes above the tree,
re-fetching the endpoint with the selection on toggle. Default
selection hides Done and Skipped.

Server-side filtering (not client-side hiding) so hive-jobq-graph-update's
node list, and everything downstream of it in builds.js (count pill,
live-log panel), only ever sees what's actually shown.
2026-08-10 23:05:03 +02:00
iris
e525dcb6d4 agent icon: 404 when unconfigured, client-side fallback
hive_sh4re::assets::branding_svg() resolved a server-side default
icon at runtime from HIVE_ASSETS_DIR — the only consumer was
serve_icon(), which fell back to it whenever the agent had no
`hyperhive.icon` override. Removed both the fallback and the
function: serve_icon() now 404s when /etc/hyperhive/icon.svg is
absent, and the per-agent web UI (app.js) picks up the existing
dashboard swarm.js pattern — swap the <img> src to the
frontend-bundled /favicon.svg on load failure, guarded against
looping if the fallback itself 404s.

Updated the doc/comment claims that said the server always returns
an image (docs/web-ui/agent.md, nix/agent-modules/default.nix, the
hive-c0re/forge/users.rs comment referencing the old shared-asset
set). forge-avatar-sync and the matrix avatar sync are unaffected —
both are gated on hyperhive.icon != null and never depended on the
removed fallback.
2026-08-10 20:59:59 +02:00
iris
aa14339be7 jobq-graph: re-add per-node cancel button
Fixes #3067.

<hive-jobq-graph> gains a `cancellable` attribute: any non-terminal
node (Pending/Running/Finishing) gets a small cancel button, and a
click dispatches `hive-jobq-graph-cancel` (`detail: { id }`) rather
than POSTing anything itself -- which endpoint actually cancels a
node is the host's domain concept, same "push data out, host decides"
shape `hive-jobq-graph-update` already uses.

builds.js turns it on for R3BU1LD QU3U3, confirms via themedConfirm,
then POSTs the existing `/api/rebuild-queue/{id}/cancel` endpoint.
No manual refresh needed -- cancelling flips node state, which
already fires rebuild_queue_changed over SSE, and the page's existing
handler for that tick already calls jobqGraphEl.refresh().

Also removed ~130 lines of dead `.rqe-*` CSS in system-sections.css
left over from the bespoke pre-<hive-jobq-graph> queue renderer
(confirmed zero JS references before deleting each rule; kept the
still-used `.rqe-kind`/`.rqe-agent`/`.rqe-source*`).

docs/web-ui/dashboard.md's R3BU1LD QU3U3 section updated to match
current behaviour (cancel button, waits-on text instead of the old
"no per-node actions" note, sibling order no longer implies anything
since deps render as text not a reordered rail).
2026-08-09 17:40:39 +02:00
atlas
a1243fe04a docs: follow the swarm service names to the swarm domain
The three moves above falsify prose in five files, and none of it is
caught by a gate: clippy, cargo test and nix flake check read exactly
zero markdown.

Corrected where a doc stated a DEFAULT or enumerated the vhosts --
gateway (ACME requirements + the header table + the two Forgejo
reachability lines), matrix (gatewayHost, firewall rationale, agent
reachability), network (container table + the HTTP resolution bullet),
turn-loop config, dashboard.

Two mentions are deliberately left alone. `docs/tools/hivectl.md` says
the URL is read from the daemon "instead of assuming forge.<domain>" --
that sentence is about not assuming a shape and stays true. And
matrix.md's breaking-change note describes what `serverName` USED to
default to; it is history, correctly labelled, and rewriting it would
erase the record of an earlier migration.

The ACME line gained a requirement rather than a rename: with the
service names under the swarm domain, every one of those names has to
resolve to this host, not just the hive's own.
2026-08-09 17:32:44 +02:00
atlas
433b294099 refactor(nix): swarm.peers becomes swarm.hives, a directory of every hive
One attrset describing every hive in the swarm including this one,
identical on every host, with hiveName selecting which entry is us.
"My peers" is derived (swarm.peerHives) rather than declared.

Every field in the old per-host peer list was intrinsic to the hive it
described, never to the pair -- so the list was a directory each host
kept its own copy of. Beyond the deduplication it removes a bug class:
two hosts could hold different endpoints for the same third hive with
nothing to detect the disagreement.

Drops the per-hive caCert. Trust inside a swarm derives from the swarm
root, which every hive chains to. What that genuinely removes is
trusting a hive whose root this swarm does not own -- a cross-swarm
problem that wants a mechanism of its own, not a field that happened to
work.

The matrix container's certificateFiles block goes with it and could
NOT be migrated: that list is read at build time and the swarm root is
a runtime file (its key must never enter the store), so there is no
build-time name to put there. caCert being a nix path was precisely
what made it the build-time distribution channel. Agents are unaffected
-- hive-tls folds the root into the hive trust bundle and the meta
renderer embeds that one file. Tracked separately.

Migration is an assertion plus warnings, not a rename: hives is peers
union {self}, and the set gains a member no existing config has written
down. A rename migrates a name and a default can re-root a meaning;
neither can conjure a new member. The warning explains, the self-entry
assertion stops the build.
2026-08-05 20:44:16 +02:00