retention is a host concern — agents have no business doing their own cleanup, and a misbehaving harness could skip it. drop spawn_events_vacuum from both hive-ag3nt and hive-m1nd, drop the matching Bus::vacuum + EventStore::vacuum methods. new hive_c0re::events_vacuum module sweeps every existing agents/<name>/state/hyperhive-events.sqlite on the same hourly cadence as the broker vacuum. same two-stage delete (older than 7 days, trim to 2000 newest). called from main alongside broker vacuum. also: server-side state badge entered into todo.md (today's badge is derived client-side from sse, fine for idle/thinking but a state machine that grows compacting/napping wants authoritative status from the harness).
6.5 KiB
6.5 KiB
TODO
Pick anything from here when relevant. Cross-cutting design notes live in CLAUDE.md; high-level project intro in README.md.
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 settings
- Model override. Hard-coded to
haikuin the turn loop right now. Surface as a per-agent override: operator via dashboard, manager viarequest_apply_commitsetting an attr on the agent's flake (most natural place since the flake already carries per-agent env/identity). Pair with a model status indicator on the agent page (active / queued / last switched) once the override is in place.
UI / UX
- Per-agent UI substance. Show last N inbox messages, last turn timing, link back to dashboard.
- State badge: compacting + napping states. Idle/thinking already
ship (driven from SSE turn_start/turn_end). Add
compacting 📦andnapping 😴once the/compacttrigger andnaptool exist — both need a harness signal (an explicitLiveEvent::StateChangevariant or piggyback on Note). - Server-side state badge. Today the badge is computed client-side
from
turn_start/turn_endevents. On page reload mid-turn the history replay re-derives it, but with acompacting/nappingstate coming and a non-trivial state machine it's better to track authoritative state in the harness and expose it viaGET /api/state(status: "thinking" | "idle" | "compacting" | "napping"). JS just renders. Drops the derive-from-events-and-pray code path. - Terminal: inline diffs for Write/Edit. Today a
Write/Edittool-use row just shows the file path. Render the actual change inline in the terminal: forEdit, a small+/-per-line diff betweeninput.old_stringandinput.new_string; forWrite, the first few lines ofinput.content(it's all "+"). Keep collapsed by default (<details>like the existing tool_result rollups), expand to full diff on click. Color via the same.diff-add/.diff-delclasses the dashboard approval diff already uses. - 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
- TTL / cancel on
ask_operator. Questions today block forever; the manager turn stays alive until the operator answers. Add a per-questionttl_seconds(or a dashboard "cancel" button that resolves the question with a sentinel answer) so a long-idle question can time out and let the manager fall back. Wire the timeout intoOperatorQuestions::wait_answeredand surface remaining-time on the dashboard.
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
naptool. Agent-side MCP toolmcp__hyperhive__nap(seconds)that parks the turn loop for a short while before next-message processing. Use cases: agent decides it has nothing useful to do, or wants to throttle itself between rapid wake events. Implementation: harness records a "wake-not-before" timestamp;recv_blockingskips the long poll until that ts; the state badge readsnapping · MM:SSduring. Operator can cancel via the same/cancelslash command or a dashboard button.- 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.
Lifecycle / reliability
- Container crash events. Watch
container@*.servicevia D-Bus, pushHelperEvent::ContainerCrashto the manager's inbox so the manager can react (restart, escalate, etc.).