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.
This commit is contained in:
müde 2026-05-15 17:17:48 +02:00
parent 124fd97288
commit 070b237d03
3 changed files with 35 additions and 19 deletions

View file

@ -21,8 +21,8 @@ hive-c0re/ host daemon + CLI (one binary, subcommand-dispatched)
src/actions.rs approve/deny/destroy src/actions.rs approve/deny/destroy
src/auto_update.rs startup rebuild scan + ensure_manager src/auto_update.rs startup rebuild scan + ensure_manager
src/lifecycle.rs `nixos-container` shellouts, per-agent flake generator src/lifecycle.rs `nixos-container` shellouts, per-agent flake generator
src/dashboard.rs axum HTTP UI: containers, approvals, async-form actions src/dashboard.rs axum HTTP: static shell + /api/state JSON + actions
assets/ CSS + JS shipped via include_str! assets/ index.html, dashboard.css, app.js (include_str!)
hive-ag3nt/ in-container harness crate; produces TWO binaries hive-ag3nt/ in-container harness crate; produces TWO binaries
src/lib.rs re-exports + DEFAULT_SOCKET, DEFAULT_WEB_PORT 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 marks them `failed` with note `"agent state dir missing"` so they fall out
of `pending`. They stay in sqlite for audit. 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 /<action>` (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 ## Agent MCP surface + turn loop
The harness ships an embedded MCP server (rmcp 1.7) that claude launches as The harness ships an embedded MCP server (rmcp 1.7) that claude launches as

View file

@ -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. 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, - **Per-agent UI substance.** Show last N inbox messages, last turn timing,
link back to dashboard. 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 - **xterm.js terminal** embedded per-agent, attached to a PTY exposed by
the harness. Pairs well with the unprivileged-container work — would let the harness. Pairs well with the unprivileged-container work — would let
the operator drop into the container without `nixos-container root-login`. the operator drop into the container without `nixos-container root-login`.

View file

@ -1,4 +1,4 @@
{ pkgs, ... }: { pkgs, lib, ... }:
{ {
# Shared scaffolding for any hyperhive harness container — both # Shared scaffolding for any hyperhive harness container — both
# sub-agents (`agent-base.nix`) and the manager (`manager.nix`) extend # 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 # 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. # request flow) and by hive-c0re's own setup_applied / setup_proposed.
# `programs.git.enable` installs the binary + manages `/etc/gitconfig` # The per-agent `applied/<name>/flake.nix` overrides `user.name` and
# declaratively so the inline module in `applied/<name>/flake.nix` can # `user.email` with the agent's identity — values here are `mkDefault`
# override `user.name` / `user.email` per agent without fighting a raw # so the per-agent override wins without needing `mkForce`.
# `environment.etc."gitconfig"` block.
programs.git = { programs.git = {
enable = true; enable = true;
config = { config = {
user = { user = {
name = "hyperhive"; name = lib.mkDefault "hyperhive";
email = "hyperhive@local"; email = lib.mkDefault "hyperhive@local";
}; };
init.defaultBranch = "main"; init.defaultBranch = lib.mkDefault "main";
}; };
}; };