pure frontend — Notification API + existing /api/state and /messages/stream signals. Caveats: secure-context requirement (HTTPS or localhost), per-browser permission grant. Includes a sketch of the implementation: request-permission button, count deltas on refreshState, SSE hook on operator-bound sends, localStorage 'muted' toggle.
6.1 KiB
TODO
Pick anything from here when relevant. Cross-cutting design notes live in CLAUDE.md; high-level project intro in README.md.
Permissions / policy
- Per-agent send allow-list. Today any agent can
sendto any other recipient (peer, manager, operator). Add a per-agent policy that constrains thetofield — declared inagent.nix, e.g.hyperhive.allowedRecipients = [ "manager" "alice" ]. Broker rejects with anErr { message }when the policy denies. Default: unrestricted (back-compat). The manager can still always send anywhere. Useful for sandboxing untrusted sub-agents so they can only talk to the manager, not other sub-agents.
Security
- Unprivileged containers (userns mapping). Today the nspawn container
runs as a fully privileged root. Goal:
PrivateUsersChown=yes(or the nixos-container equivalent) so uid 0 inside maps to an unprivileged uid on the host, and a container-root compromise lands the attacker on an ordinary user account, not the host's root. Requires per-agent state dirs to be chown'd to that uid on the host side. - Bash command allow-list. Replace the blanket
Bashallow with a pattern allow-list (Bash(git *),Bash(nix build .*), etc.) per claude-code's--allowedToolsextended grammar. Likely lives inagent.nixso each agent can scope its own shell surface.
Per-agent extension
- Custom per-agent MCP tools. Today every sub-agent gets the
same fixed MCP surface (
send,recv). To move bitburner-agent (and anything else with rich domain tooling) into hyperhive, an agent needs a way to ship its own tools alongside hyperhive's. Sketch:agent.nixdeclares a list of extra MCP servers (command + args + env), each registered into the agent's--mcp-configblob at flake-render time. The harness MCP server remains the hyperhive surface; new servers slot in as additional entries undermcpServers.<name>so claude sees them asmcp__<name>__<tool>. Per-agent tool whitelist (allowedTools) derived from the same config so the operator stays in control of what's exposed.
UI / UX
-
Browser notifications for operator-bound events. Dashboard pings the OS notification center when (a) a new approval lands in the queue, (b) a new
ask_operatorquestion is queued, (c) a broker message is sentto: "operator". All three data sources are already in/api/state+/messages/streamso this is pure frontend. Sketch:- Small "🔔 enable notifications" button somewhere (header
or near the inbox section). Clicks call
Notification.requestPermission(). Hide once granted. - Track last-seen counts in the JS app
(
approvals.length,questions.length). OnrefreshState, if the count went up, firenew Notification(...)per new item. - SSE handler for
messages/streamfires a notification onkind === 'sent' && to === 'operator'(already triggersrefreshState; just adds a notify call alongside). - Notification body links back to the dashboard (
onclick → window.focus()+ section anchor). Caveats: Notification API requires a secure context (HTTPS or localhost). Most operators access via LAN / Tailscale — works fine for localhost forwards, otherwise needs a TLS cert in the module. Persist a per-browser "muted" toggle in localStorage so the operator can silence without revoking permission.
- Small "🔔 enable notifications" button somewhere (header
or near the inbox section). Clicks call
-
Terminal:
/modelslash command. Operator-typeable model override from the terminal. Depends on the model-override work above; once an override mechanism exists, wire a/model <name>command that POSTs to a new endpoint. -
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.
Telemetry
- Harness stats per agent in sqlite, charted on the agent page.
bitburner-agent samples 18 series; for hyperhive the generally-applicable
ones are:
- turns/min, tool calls/turn, turn duration p50/p95
- claude exit code distribution (ok vs
--compact-retry vs failure) - inbox depth (current + max-over-window)
- messages sent/received per turn (split by recipient: peer / operator / manager / system)
- approval queue length (across all agents — dashboard-level)
- per-tool usage counts (Read/Edit/Bash/send/recv/…)
- time-since-last-turn (helps spot stuck agents)
- notes file size growth (cues compaction)
Backend: a
statstable with(agent, ts, key, value)written from the harness onTurnEnd;GET /api/stats?since=…returns the series; agent page renders with a small chart lib (uPlot is light).
Manager → operator question channel
Spawn flow
- Two-step spawn. Today
request_spawn(name)is one shot: manager asks → operator approves → container is created with a defaultagent.nixand empty/state/. Manager has no way to pre-stage per-agent prompt material, package additions, or initial notes before the agent first wakes. Split into:request_spawn_draft(name)— host creates the per-agentproposed/repo (initial commit) andstate/dir with no container; manager now has/agents/<name>/{config,state}/to edit + commit just like an existing agent.request_spawn_commit(name, commit_ref)— submits the queued approval; operator sees the diff in the dashboard like a normalapply_commit; on approve the container is created from that commit. Backwards-compat: keep the existing one-shotrequest_spawnfor trivial agents (operator can still type a name in the dashboard). Surface "drafts" as a new section between K3PT ST4T3 and approvals.
Loop substance
- Notes compaction.
/state/is bind-mounted persistently and agents are told (in the system prompt) to keep/state/notes.mdfor durable knowledge — but we don't currently nudge them to compact when notes grow. Bitburner-agent's pattern: a short-lived secondary claude session that takes the existing notes + a "compact this" prompt and rewrites them in place. Add when the notes start bloating.