From 070b237d03fe0c2c3fb726bbfe102d2726fe6867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Fri, 15 May 2026 17:17:48 +0200 Subject: [PATCH] docs: SPA pattern noted, todo cleared; harness-base git config mkDefault programs.git.config.user.{name,email} in harness-base.nix now mkDefault so the per-agent applied flake's override merges without mkForce. --- CLAUDE.md | 30 ++++++++++++++++++++++++++++-- TODO.md | 9 --------- nix/templates/harness-base.nix | 15 +++++++-------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2f3c1c6..0933e93 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,8 +21,8 @@ hive-c0re/ host daemon + CLI (one binary, subcommand-dispatched) src/actions.rs approve/deny/destroy src/auto_update.rs startup rebuild scan + ensure_manager src/lifecycle.rs `nixos-container` shellouts, per-agent flake generator - src/dashboard.rs axum HTTP UI: containers, approvals, async-form actions - assets/ CSS + JS shipped via include_str! + src/dashboard.rs axum HTTP: static shell + /api/state JSON + actions + assets/ index.html, dashboard.css, app.js (include_str!) hive-ag3nt/ in-container harness crate; produces TWO binaries src/lib.rs re-exports + DEFAULT_SOCKET, DEFAULT_WEB_PORT @@ -120,6 +120,32 @@ nix/ marks them `failed` with note `"agent state dir missing"` so they fall out of `pending`. They stay in sqlite for audit. +## Web UI shape + +Both the dashboard (port 7000) and the per-agent web UIs (8000 / +8100-8999) are SPAs with the same skeleton: + +- `GET /` → static `assets/index.html` (placeholders for state-driven + sections). +- `GET /static/*.css` + `GET /static/*.js` → static assets shipped via + `include_str!` so there's no runtime file dependency. +- `GET /api/state` → JSON snapshot the JS app renders into the DOM. +- `POST /` (approve, deny, kill, restart, rebuild, destroy, + request-spawn, update-all, send, login/*) → idempotent action endpoints. +- `GET /events/stream` (per-agent) and `GET /messages/stream` (dashboard) + are `text/event-stream` SSE for live updates. + +The JS app handles all `form[data-async]` submissions via a delegated +listener: read `data-confirm`, swap the button to a spinner, POST +`application/x-www-form-urlencoded` (axum's `Form` extractor rejects +multipart), then on success call `refreshState()` (re-fetch `/api/state` +and re-render). No full-page reloads. + +Per-agent + dashboard state shapes live in `dashboard.rs::StateSnapshot` +and `web_ui.rs::StateSnapshot`. When adding new state fields, plumb +through the snapshot struct and the relevant `assets/app.js` render +function — never reach for server-side HTML rendering again. + ## Agent MCP surface + turn loop The harness ships an embedded MCP server (rmcp 1.7) that claude launches as diff --git a/TODO.md b/TODO.md index 8091c35..a7f72c7 100644 --- a/TODO.md +++ b/TODO.md @@ -30,15 +30,6 @@ Pick anything from here when relevant. Cross-cutting design notes live in only see them by watching the live panel of the agent that sent them. - **Per-agent UI substance.** Show last N inbox messages, last turn timing, link back to dashboard. -- **Static-asset SPA-style web UI.** Move toward: `index.html` is static, - CSS/JS is static, all dynamic state is fetched over SSE / JSON endpoints. - Currently the index HTML is server-rendered with state-dependent - fragments inlined; the live event stream + async forms are already SSE / - fetch. Goal is a cleaner split so the UI is one HTML file + JS app + - small JSON API. -- **Background JS refresh on the live panel.** Already there for sends; - any remaining places that reload the whole page should switch to fetch + - partial updates. - **xterm.js terminal** embedded per-agent, attached to a PTY exposed by the harness. Pairs well with the unprivileged-container work — would let the operator drop into the container without `nixos-container root-login`. diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index 8140244..814e605 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: { # Shared scaffolding for any hyperhive harness container — both # sub-agents (`agent-base.nix`) and the manager (`manager.nix`) extend @@ -18,18 +18,17 @@ # Git is needed by claude's Bash tool (for the agent <-> manager config # request flow) and by hive-c0re's own setup_applied / setup_proposed. - # `programs.git.enable` installs the binary + manages `/etc/gitconfig` - # declaratively so the inline module in `applied//flake.nix` can - # override `user.name` / `user.email` per agent without fighting a raw - # `environment.etc."gitconfig"` block. + # The per-agent `applied//flake.nix` overrides `user.name` and + # `user.email` with the agent's identity — values here are `mkDefault` + # so the per-agent override wins without needing `mkForce`. programs.git = { enable = true; config = { user = { - name = "hyperhive"; - email = "hyperhive@local"; + name = lib.mkDefault "hyperhive"; + email = lib.mkDefault "hyperhive@local"; }; - init.defaultBranch = "main"; + init.defaultBranch = lib.mkDefault "main"; }; };