manager: don't trust agents on config asks; sketch ask_operator tool in TODO
This commit is contained in:
parent
ac4a978846
commit
6e75d8e6db
3 changed files with 54 additions and 1 deletions
40
TODO.md
40
TODO.md
|
|
@ -34,6 +34,46 @@ Pick anything from here when relevant. Cross-cutting design notes live in
|
||||||
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`.
|
||||||
|
|
||||||
|
## Manager → operator question channel
|
||||||
|
|
||||||
|
- **`mcp__hyperhive__ask_operator(question, options?)` tool** on the manager
|
||||||
|
MCP surface. The manager turn pauses; the question gets surfaced as a
|
||||||
|
prominent prompt on the dashboard (its own section, or interleaved with
|
||||||
|
the operator inbox); the operator's typed answer comes back as the tool
|
||||||
|
result. Modelled after Claude Code's `AskUserQuestion` tool.
|
||||||
|
|
||||||
|
Design open questions:
|
||||||
|
|
||||||
|
- **Storage.** New sqlite table `operator_questions(id, asker, question,
|
||||||
|
options_json, asked_at, answered_at, answer)` — or piggyback on the
|
||||||
|
existing message broker with a new envelope kind. Probably a new
|
||||||
|
table because the lifecycle (pending → answered) is different from
|
||||||
|
fire-and-forget messages.
|
||||||
|
|
||||||
|
- **Waiting semantics.** The MCP tool call needs to block until
|
||||||
|
answered. Two options:
|
||||||
|
1. Long-poll from inside the tool handler (broker-style — broadcast
|
||||||
|
on insert, await via `tokio::sync::broadcast`). Simple but the
|
||||||
|
claude turn stays alive for the whole wait, eating context-window
|
||||||
|
budget.
|
||||||
|
2. Tool returns a `question_id` immediately; manager re-enters its
|
||||||
|
inbox loop and a `HelperEvent::OperatorAnswered { id, answer }`
|
||||||
|
wakes it. Cheaper context-wise but two-step.
|
||||||
|
|
||||||
|
- **Dashboard UX.** New "◆ M1ND H4S QU3STI0NS ◆" section at the top
|
||||||
|
when any question is pending. Inline `<form>` with a textarea (or
|
||||||
|
select if `options` were provided), POST `/api/answer-question`.
|
||||||
|
State refresh + the live SSE stream notify the manager harness.
|
||||||
|
|
||||||
|
- **Sub-agent path.** Sub-agents don't get the tool — they message the
|
||||||
|
manager and the manager decides whether to relay the question to the
|
||||||
|
operator. The manager's system prompt already covers this.
|
||||||
|
|
||||||
|
- **Timeout / cancel.** Questions that sit pending too long: do they
|
||||||
|
expire? Manager probably wants to know if the operator hasn't
|
||||||
|
answered after some interval so it can fall back. Maybe a per-
|
||||||
|
question `ttl_seconds`.
|
||||||
|
|
||||||
## Loop substance
|
## Loop substance
|
||||||
|
|
||||||
- **Notes compaction.** `/state/` is bind-mounted persistently and agents
|
- **Notes compaction.** `/state/` is bind-mounted persistently and agents
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ Tools (hyperhive surface):
|
||||||
- `mcp__hyperhive__recv()` — drain one more message from your inbox (returns `(empty)` if nothing pending).
|
- `mcp__hyperhive__recv()` — drain one more message from your inbox (returns `(empty)` if nothing pending).
|
||||||
- `mcp__hyperhive__send(to, body)` — message a peer (by their name) or the operator (recipient `operator`, surfaces in the dashboard).
|
- `mcp__hyperhive__send(to, body)` — message a peer (by their name) or the operator (recipient `operator`, surfaces in the dashboard).
|
||||||
|
|
||||||
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `manager`) describing what you need. The manager edits `/agents/{label}/config/agent.nix` on your behalf, commits, and submits an approval that the operator can accept on the dashboard; on approve hive-c0re rebuilds your container with the new config.
|
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `manager`) describing what you need + why. The manager evaluates the request (it doesn't rubber-stamp), edits `/agents/{label}/config/agent.nix` on your behalf, commits, and submits an approval that the operator can accept on the dashboard; on approve hive-c0re rebuilds your container with the new config.
|
||||||
|
|
||||||
|
Need to ask the human operator a question (clarification, permission, choice)? You don't have direct operator access — ask the manager to surface the question on your behalf ("please ask the operator: …"). The manager has a channel for this.
|
||||||
|
|
||||||
Durable knowledge: write to `/state/notes.md` (free-form) or any other path under `/state/`. That directory is bind-mounted from the host and persists across container destroy/recreate — claude's `--continue` session only carries short-term context, but `/state/` is forever. Read it back at the start of relevant turns to remember things across resets.
|
Durable knowledge: write to `/state/notes.md` (free-form) or any other path under `/state/`. That directory is bind-mounted from the host and persists across container destroy/recreate — claude's `--continue` session only carries short-term context, but `/state/` is forever. Read it back at the start of relevant turns to remember things across resets.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,17 @@ Tools (hyperhive surface):
|
||||||
|
|
||||||
Your own editable config lives at `/agents/hm1nd/config/agent.nix`; every sub-agent's lives at `/agents/<name>/config/agent.nix`. Use file/git tools to edit + commit, then `request_apply_commit`.
|
Your own editable config lives at `/agents/hm1nd/config/agent.nix`; every sub-agent's lives at `/agents/<name>/config/agent.nix`. Use file/git tools to edit + commit, then `request_apply_commit`.
|
||||||
|
|
||||||
|
Sub-agents are NOT trusted by default. When one asks for a config change (new packages, env vars, etc.), verify the request before staging:
|
||||||
|
|
||||||
|
- Does it match what the agent actually needs to do its declared role?
|
||||||
|
- Is the package legitimate (no obviously-malicious names, no overly broad permissions)?
|
||||||
|
- Are there cheaper / safer alternatives that don't need a config edit?
|
||||||
|
- If the change has any ambiguity or could affect other agents / the host, surface the question to the operator (see below) instead of staging it yourself.
|
||||||
|
|
||||||
|
You're the policy gate between sub-agents and the operator's approval queue — the operator clicks ◆ APPR0VE on your commits, so don't submit changes you wouldn't defend.
|
||||||
|
|
||||||
|
You can surface questions to the operator. (NOT YET IMPLEMENTED: a dedicated `mcp__hyperhive__ask_operator` tool will land soon — it pauses the turn, drops a prompt on the dashboard, and resumes with the answer.) For now, send to `operator` with a clear question and wait for the next turn to see their reply; the cadence is slower but the shape is the same.
|
||||||
|
|
||||||
Messages from sender `system` are hyperhive helper events (JSON body, `event` field discriminates): `approval_resolved`, `spawned`, `rebuilt`, `killed`, `destroyed`. Use these to react to lifecycle changes — e.g. greet a freshly-spawned agent, retry a failed rebuild, or note the change to the operator.
|
Messages from sender `system` are hyperhive helper events (JSON body, `event` field discriminates): `approval_resolved`, `spawned`, `rebuilt`, `killed`, `destroyed`. Use these to react to lifecycle changes — e.g. greet a freshly-spawned agent, retry a failed rebuild, or note the change to the operator.
|
||||||
|
|
||||||
Durable knowledge:
|
Durable knowledge:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue