docs: scrub self-ref cookies across 5 files (#719 batch 2)
All five files scrubbed to 0 issue-ref cookies. Most refs were '(closes #NNN)' style attribution after closed work landed. - docs/turn-loop.md: 6 → 0 (#598 unified binary, #419 auth-fail, #542 mtime resumption, #519 role markers, #442 spawn path, #474/#478 partial edit) - docs/approvals.md: 5 → 0 (#317 flake validation, #250 withdraw, #441 rebuild-queue dispatch, #753 manager port hash, #425 crash-watch grace) - docs/terminal-rendering.md: 2 → 0 (#666 ask-operator inline) - docs/conventions.md: 3 → 0 (#753 port hash, #692 parent sentinel, #486 reparenting) - docs/security.md: 4 → 0 (#240 + #658 ×2 + #673/#678 attribution) Combined with PR #810 (docs/web-ui.md 14→0), this PR closes the small / medium files. Remaining: agent-hierarchy.md (13), gotchas.md (13), persistence.md (13). gateway.md is atlas's lane.
This commit is contained in:
parent
a8d8159038
commit
5ca96b8c85
5 changed files with 27 additions and 29 deletions
|
|
@ -30,7 +30,7 @@ happens after a decision lands.
|
||||||
applied.
|
applied.
|
||||||
3a. **Flake validation (ApplyCommit only):** after the proposal tag
|
3a. **Flake validation (ApplyCommit only):** after the proposal tag
|
||||||
is planted, hive-c0re reads `proposal/<id>:flake.lock` and
|
is planted, hive-c0re reads `proposal/<id>:flake.lock` and
|
||||||
runs two checks (closes #317). If either check fails, no
|
runs two checks. If either check fails, no
|
||||||
pending approval is created for the operator — the row is
|
pending approval is created for the operator — the row is
|
||||||
marked failed and surfaces on the dashboard with the
|
marked failed and surfaces on the dashboard with the
|
||||||
validation message:
|
validation message:
|
||||||
|
|
@ -66,7 +66,7 @@ happens after a decision lands.
|
||||||
### Withdrawing a pending approval
|
### Withdrawing a pending approval
|
||||||
|
|
||||||
The manager can call `cancel_loose_end(kind: "approval", id)` to
|
The manager can call `cancel_loose_end(kind: "approval", id)` to
|
||||||
withdraw an approval that hasn't been acted on yet (closes #250).
|
withdraw an approval that hasn't been acted on yet.
|
||||||
The row transitions to `ApprovalStatus::Cancelled` (distinct from
|
The row transitions to `ApprovalStatus::Cancelled` (distinct from
|
||||||
`Denied`/`Failed`), the dashboard pulls the card out of the
|
`Denied`/`Failed`), the dashboard pulls the card out of the
|
||||||
pending pane, and `ApprovalResolved { status: "cancelled" }` fires
|
pending pane, and `ApprovalResolved { status: "cancelled" }` fires
|
||||||
|
|
@ -202,7 +202,7 @@ approval id to retry. Because tags are first-class git objects,
|
||||||
rejected and failed trees stay browsable forever — `git log
|
rejected and failed trees stay browsable forever — `git log
|
||||||
--tags` in the applied repo is the audit trail.
|
--tags` in the applied repo is the audit trail.
|
||||||
|
|
||||||
### Dispatch via `rebuild_queue` (#441)
|
### Dispatch via `rebuild_queue`
|
||||||
|
|
||||||
Long-running approval work — `ApplyCommit`, `UpdateMetaInputs`,
|
Long-running approval work — `ApplyCommit`, `UpdateMetaInputs`,
|
||||||
`Spawn` — no longer runs inline inside `actions::approve`. Instead
|
`Spawn` — no longer runs inline inside `actions::approve`. Instead
|
||||||
|
|
@ -344,7 +344,7 @@ Differences from sub-agents:
|
||||||
(vs `agent-base`).
|
(vs `agent-base`).
|
||||||
- Container name is `hm1nd` (no `h-` prefix).
|
- Container name is `hm1nd` (no `h-` prefix).
|
||||||
- Web UI port via `lifecycle::agent_web_port("hm1nd")` — same
|
- Web UI port via `lifecycle::agent_web_port("hm1nd")` — same
|
||||||
FNV-1a hash as every other agent (8100..8999 range) since #753.
|
FNV-1a hash as every other agent (8100..8999 range).
|
||||||
- `set_nspawn_flags` adds two extra binds: `/var/lib/hyperhive/agents`
|
- `set_nspawn_flags` adds two extra binds: `/var/lib/hyperhive/agents`
|
||||||
→ `/agents` (RW) so the manager can edit per-agent proposed repos,
|
→ `/agents` (RW) so the manager can edit per-agent proposed repos,
|
||||||
and `/var/lib/hyperhive/applied` → `/applied` (RO) so the manager
|
and `/var/lib/hyperhive/applied` → `/applied` (RO) so the manager
|
||||||
|
|
@ -424,8 +424,8 @@ regular claude turn so the manager can react. Variants
|
||||||
such transient was cleared in the last 30s (`RECENT_TRANSIENT_GRACE`
|
such transient was cleared in the last 30s (`RECENT_TRANSIENT_GRACE`
|
||||||
tombstone, three `POLL_INTERVAL`s — closes the race where a
|
tombstone, three `POLL_INTERVAL`s — closes the race where a
|
||||||
lifecycle op finishes between two crash-watch polls and the
|
lifecycle op finishes between two crash-watch polls and the
|
||||||
container shows briefly as "stopped without transient" before the
|
container shows briefly as "stopped without transient" before
|
||||||
next start, #425). Manager can `start` it again or escalate.
|
the next start). Manager can `start` it again or escalate.
|
||||||
- `NeedsLogin { agent }` — sub-agent has no claude session yet.
|
- `NeedsLogin { agent }` — sub-agent has no claude session yet.
|
||||||
Manager can't act directly (interactive OAuth); typically flags
|
Manager can't act directly (interactive OAuth); typically flags
|
||||||
the operator.
|
the operator.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ exist because something already went wrong without them.
|
||||||
- The manager is `hm1nd` (no `h-` prefix, fixed name).
|
- The manager is `hm1nd` (no `h-` prefix, fixed name).
|
||||||
- `MAX_AGENT_NAME` in `lifecycle.rs` enforces the cap.
|
- `MAX_AGENT_NAME` in `lifecycle.rs` enforces the cap.
|
||||||
- Per-agent web UI port = `WEB_PORT_BASE + FNV1a(name) % WEB_PORT_RANGE`
|
- Per-agent web UI port = `WEB_PORT_BASE + FNV1a(name) % WEB_PORT_RANGE`
|
||||||
(8100..8999) for every agent including the manager (#753); dashboard
|
(8100..8999) for every agent including the manager; dashboard
|
||||||
`cfg.dashboardPort` (default 7000).
|
`cfg.dashboardPort` (default 7000).
|
||||||
|
|
||||||
## Identity = socket
|
## Identity = socket
|
||||||
|
|
@ -32,12 +32,12 @@ angle-bracket and asterisk shapes below are structurally safe.
|
||||||
(`agent_server::handle_send` fans out via `Coordinator::broadcast_send`).
|
(`agent_server::handle_send` fans out via `Coordinator::broadcast_send`).
|
||||||
- `operator` — the human at the dashboard. Messages accumulate in the
|
- `operator` — the human at the dashboard. Messages accumulate in the
|
||||||
inbox view; no agent ever `recv`'s them.
|
inbox view; no agent ever `recv`'s them.
|
||||||
- `<parent>` — the sender's parent per `topology.json` (`#692`).
|
- `<parent>` — the sender's parent per `topology.json`. Rewritten at
|
||||||
Rewritten at send time by `topology::resolve_recipient`: looks up
|
send time by `topology::resolve_recipient`: looks up
|
||||||
`parent_of(sender)` and falls back to `operator` when the sender is
|
`parent_of(sender)` and falls back to `operator` when the sender is
|
||||||
a root agent (or absent from topology entirely). Lets agents address
|
a root agent (or absent from topology entirely). Lets agents address
|
||||||
their parent without learning the label, so runtime reparenting
|
their parent without learning the label, so runtime reparenting
|
||||||
(`#486`) propagates with zero agent-side restart.
|
propagates with zero agent-side restart.
|
||||||
|
|
||||||
When the resolver rewrites `<parent>`, the broker stores the
|
When the resolver rewrites `<parent>`, the broker stores the
|
||||||
*resolved* label as the message's recipient — the dashboard and
|
*resolved* label as the message's recipient — the dashboard and
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Security model
|
# Security model
|
||||||
|
|
||||||
## Nix builds and credential isolation (issue #240)
|
## Nix builds and credential isolation
|
||||||
|
|
||||||
### Background
|
### Background
|
||||||
|
|
||||||
|
|
@ -19,12 +19,11 @@ any file in the container that the nixbld user can read.
|
||||||
**What is NOT exposed**:
|
**What is NOT exposed**:
|
||||||
|
|
||||||
- `/home/<name>/.claude/` — mode `0700`, owned by the per-agent
|
- `/home/<name>/.claude/` — mode `0700`, owned by the per-agent
|
||||||
user `<name>` (post-#658 — was `/root/.claude` owned by root
|
user `<name>`. nixbld users cannot read it.
|
||||||
pre-#658). nixbld users cannot read it.
|
|
||||||
- `$HYPERHIVE_STATE_DIR/forge-token` (= `/agents/<name>/state/forge-token`)
|
- `$HYPERHIVE_STATE_DIR/forge-token` (= `/agents/<name>/state/forge-token`)
|
||||||
— written at mode `0600` by `hive-c0re/src/forge.rs` and chowned to the
|
— written at mode `0600` by `hive-c0re/src/forge.rs` and chowned to the
|
||||||
per-agent uid:gid by `lifecycle::chown_to_agent` (post-#673/#678).
|
per-agent uid:gid by `lifecycle::chown_to_agent`. nixbld users
|
||||||
nixbld users cannot read it.
|
cannot read it.
|
||||||
|
|
||||||
**Policy**: all credential files written to agent state directories MUST be mode
|
**Policy**: all credential files written to agent state directories MUST be mode
|
||||||
`0600` or stricter. Do not create world-readable secret files in agent state dirs.
|
`0600` or stricter. Do not create world-readable secret files in agent state dirs.
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ parent's negative pull.
|
||||||
| `.tool-use` (flat) | `→ Name args…` | cyan | tool_use w/o rich renderer | stream-json |
|
| `.tool-use` (flat) | `→ Name args…` | cyan | tool_use w/o rich renderer | stream-json |
|
||||||
| `.tool-use` `<details>` | `Write/Edit <path> · +N` (no `→`) | cyan, body is +/- diff | `renderRichToolUse` Write/Edit | stream-json |
|
| `.tool-use` `<details>` | `Write/Edit <path> · +N` (no `→`) | cyan, body is +/- diff | `renderRichToolUse` Write/Edit | stream-json |
|
||||||
| `.tool-use` `<details open>` | `send → to · NL`, `ask → to`, `answer #id` | cyan, body is markdown | rich renderer for send / ask / answer | stream-json |
|
| `.tool-use` `<details open>` | `send → to · NL`, `ask → to`, `answer #id` | cyan, body is markdown | rich renderer for send / ask / answer | stream-json |
|
||||||
| `.tool-use .ask-answer-inline-slot` | (sub-block under `ask → operator`) | inherits row | inline answer form bound by `reconcileAskBinds` to the loose-end | #666 |
|
| `.tool-use .ask-answer-inline-slot` | (sub-block under `ask → operator`) | inherits row | inline answer form bound by `reconcileAskBinds` to the loose-end | rich renderer |
|
||||||
| `.tool-result` (flat) | `← <txt>` | muted | short `tool_result` (≤120c, non-recv) | stream-json |
|
| `.tool-result` (flat) | `← <txt>` | muted | short `tool_result` (≤120c, non-recv) | stream-json |
|
||||||
| `.tool-result-block` `<details>` | `Nl · headline` | muted, body is text | long generic `tool_result` | stream-json |
|
| `.tool-result-block` `<details>` | `Nl · headline` | muted, body is text | long generic `tool_result` | stream-json |
|
||||||
| `.tool-result-block` `<details open>` | `recv ← <txt>` | muted, body is markdown | `tool_result` correlated to a prior `recv` tool_use via id | stream-json |
|
| `.tool-result-block` `<details open>` | `recv ← <txt>` | muted, body is markdown | `tool_result` correlated to a prior `recv` tool_use via id | stream-json |
|
||||||
|
|
@ -105,7 +105,7 @@ isn't in the built-in `fmtToolUse` switch:
|
||||||
This keeps `mcp__matrix__send_message` and similar from
|
This keeps `mcp__matrix__send_message` and similar from
|
||||||
dumping raw JSON.
|
dumping raw JSON.
|
||||||
|
|
||||||
## Inline ask-operator answer (#666)
|
## Inline ask-operator answer
|
||||||
|
|
||||||
When an agent calls `mcp__hyperhive__ask` with `to == "operator"`
|
When an agent calls `mcp__hyperhive__ask` with `to == "operator"`
|
||||||
(default), the rich tool-use renderer mounts an empty
|
(default), the rich tool-use renderer mounts an empty
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ claude has access to in return.
|
||||||
## The loop
|
## The loop
|
||||||
|
|
||||||
Each agent harness (`hive serve`, with role picked from `$HIVE_ROLE`
|
Each agent harness (`hive serve`, with role picked from `$HIVE_ROLE`
|
||||||
— `"agent"` for sub-agents, `"manager"` for the manager; post-#598
|
— `"agent"` for sub-agents, `"manager"` for the manager — one
|
||||||
this is one binary not two) runs:
|
binary, not two) runs:
|
||||||
|
|
||||||
1. Long-poll `Recv` on its socket. The host-side broker
|
1. Long-poll `Recv` on its socket. The host-side broker
|
||||||
(`broker.rs::recv_blocking_batch`) returns immediately if there's
|
(`broker.rs::recv_blocking_batch`) returns immediately if there's
|
||||||
|
|
@ -31,8 +31,8 @@ this is one binary not two) runs:
|
||||||
(`Bus::emit_status("rate_limited")`), sleeps
|
(`Bus::emit_status("rate_limited")`), sleeps
|
||||||
`HIVE_RATE_LIMIT_SLEEP_SECS` (default 300), then retries.
|
`HIVE_RATE_LIMIT_SLEEP_SECS` (default 300), then retries.
|
||||||
The dashboard and per-agent page show a `⊘ rate limited` badge
|
The dashboard and per-agent page show a `⊘ rate limited` badge
|
||||||
while the harness is parked. **Auth-failed detection** (closes
|
while the harness is parked. **Auth-failed detection**: both
|
||||||
#419): both stdout and stderr pumps also match
|
stdout and stderr pumps also match
|
||||||
`AUTH_FAIL_MARKERS` (`"authentication_failed"`, `401`, etc.).
|
`AUTH_FAIL_MARKERS` (`"authentication_failed"`, `401`, etc.).
|
||||||
On match the harness writes `{state_dir}/hyperhive-needs-login`,
|
On match the harness writes `{state_dir}/hyperhive-needs-login`,
|
||||||
emits `needs_login_idle` status, requeues the inflight message
|
emits `needs_login_idle` status, requeues the inflight message
|
||||||
|
|
@ -40,7 +40,7 @@ this is one binary not two) runs:
|
||||||
the same path used at boot. The operator re-authenticates via
|
the same path used at boot. The operator re-authenticates via
|
||||||
the per-agent web UI login flow; on success the sentinel is
|
the per-agent web UI login flow; on success the sentinel is
|
||||||
cleared and the queued message drives the next turn normally.
|
cleared and the queued message drives the next turn normally.
|
||||||
**Mtime-snapshot resumption** (closes #542): `wait_for_login`
|
**Mtime-snapshot resumption**: `wait_for_login`
|
||||||
snapshots the `~/.claude/` dir (newest file mtime + file count)
|
snapshots the `~/.claude/` dir (newest file mtime + file count)
|
||||||
at entry and only resumes when that snapshot advances — not
|
at entry and only resumes when that snapshot advances — not
|
||||||
just when credentials exist on disk. This prevents a silent
|
just when credentials exist on disk. This prevents a silent
|
||||||
|
|
@ -176,8 +176,8 @@ socket at `/run/hive/` once at startup:
|
||||||
- `claude-system-prompt.md` — rendered from
|
- `claude-system-prompt.md` — rendered from
|
||||||
`hive-ag3nt/prompts/system.md` by `hive_ag3nt::prompt::render`:
|
`hive-ag3nt/prompts/system.md` by `hive_ag3nt::prompt::render`:
|
||||||
HTML-comment markers (`<!-- role:agent -->...<!-- /role:agent -->`,
|
HTML-comment markers (`<!-- role:agent -->...<!-- /role:agent -->`,
|
||||||
same for `role:manager`) gate the role-specific blocks (closes
|
same for `role:manager`) gate the role-specific blocks; everything
|
||||||
#519); everything else is shared. Five placeholders are then
|
else is shared. Five placeholders are then
|
||||||
substituted: `{label}` (short agent name), `{qualified_label}`
|
substituted: `{label}` (short agent name), `{qualified_label}`
|
||||||
(hive-qualified `name@domain` form), `{operator_pronouns}`,
|
(hive-qualified `name@domain` form), `{operator_pronouns}`,
|
||||||
`{hive_identity}` (e.g. `` on hive `pr1ma` ``; empty when
|
`{hive_identity}` (e.g. `` on hive `pr1ma` ``; empty when
|
||||||
|
|
@ -350,10 +350,9 @@ meta's.
|
||||||
`agent.nix`, commits the changes, and calls `request_apply_commit`
|
`agent.nix`, commits the changes, and calls `request_apply_commit`
|
||||||
with the commit sha — the first ApplyCommit on a freshly-init'd
|
with the commit sha — the first ApplyCommit on a freshly-init'd
|
||||||
config creates the container. Fails if a proposed repo for this
|
config creates the container. Fails if a proposed repo for this
|
||||||
name already exists. (The pre-#442 path through a separate
|
name already exists. (The operator can also direct-spawn an empty
|
||||||
manager-side `request_spawn` was removed; operator can still
|
agent from the dashboard's `◆ R3QU3ST SP4WN` button, which routes
|
||||||
direct-spawn an empty agent from the dashboard's `◆ R3QU3ST SP4WN`
|
via `HostRequest::RequestSpawn`.)
|
||||||
button which routes via `HostRequest::RequestSpawn`.)
|
|
||||||
- `kill(name)` — graceful stop. No approval required.
|
- `kill(name)` — graceful stop. No approval required.
|
||||||
- `start(name)` — start a stopped sub-agent. No approval.
|
- `start(name)` — start a stopped sub-agent. No approval.
|
||||||
- `restart(name)` — stop + start. No approval.
|
- `restart(name)` — stop + start. No approval.
|
||||||
|
|
@ -398,7 +397,7 @@ meta's.
|
||||||
approval (use `remind` for unapproved self-wake). Long downtime
|
approval (use `remind` for unapproved self-wake). Long downtime
|
||||||
fires once per recurring row on resume (catch-up clamp).
|
fires once per recurring row on resume (catch-up clamp).
|
||||||
- `edit_schedule(id, body?, description?, interval_seconds?, next_fire_at_unix?, targets_add?, targets_remove?)` —
|
- `edit_schedule(id, body?, description?, interval_seconds?, next_fire_at_unix?, targets_add?, targets_remove?)` —
|
||||||
partial-update a schedule (#474/#478). Pass only the fields to
|
partial-update a schedule. Pass only the fields to
|
||||||
change; absent fields are left alone. `targets_add` / `targets_remove`
|
change; absent fields are left alone. `targets_add` / `targets_remove`
|
||||||
mutate the recipient list in the same transaction; re-adding a
|
mutate the recipient list in the same transaction; re-adding a
|
||||||
previously-cancelled target drops its tombstone + history (fresh
|
previously-cancelled target drops its tombstone + history (fresh
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue