Commit graph

2,381 commits

Author SHA1 Message Date
atlas
03e07c7d37 chore(nix): fix remaining stale shared-netns references in harness-base.nix
- Option doc: 'Default points at the in-host tuwunel (shared netns)'
  → updated to reflect that c0re forwards the gateway URL at runtime
- DNS oneshot comment: 'inert in shared-netns mode' → removed since
  isolation is always on; oneshot always runs
2026-07-04 22:54:38 +02:00
atlas
9067398e3c chore(docs,nix): remove stale shared-netns references from matrix URL docs
Agents run in private netns (always-on isolation) and can't reach
host loopback directly. hive-c0re forwards HIVE_MATRIX_URL set to
`matrix.<domain>` via the gateway. Update two places that still
referenced the removed shared-netns path.
2026-07-04 22:54:38 +02:00
atlas
2ddabdc410 fixup! fix(#2245): drop TCP fallback from gateway nginx upstream 2026-07-04 22:42:56 +02:00
atlas
32e4c687b8 docs(gateway): remove stale TCP loopback fallback section
The TCP fallback was removed from gateway_nginx.rs in the previous
commit. Update docs/gateway.md to match:
- Step 4: remove 'TCP loopback for agents not yet rebuilt' — always UDS now
- Remove the 'TCP loopback fallback' subsection entirely
2026-07-04 22:42:56 +02:00
atlas
0456206e52 fix(#2245): drop TCP fallback from gateway nginx upstream
Agents run in private netns (always-on isolation). The TCP fallback
to 127.0.0.1:<port> was unreachable from the gateway's host netns
regardless of whether the per-agent socket marker existed.

Remove the conditional entirely: always use the unix socket path.
If the socket is not yet bound, nginx returns 502 which is already
handled by the error_page 502 503 504 = /__hive_agent_unreachable
directive in every location block.

Also removes the unused lifecycle::agent_web_port call and the
now-misleading '.bound state' mention from the render doc comment.
2026-07-04 22:42:56 +02:00
atlas
4947037454 chore(nix): trim stale body from deprecated isolateContainers option doc
The option is a no-op (marked DEPRECATED — ignored); the Prerequisite,
Migration, and Rust counterpart sections all described the migration that
already completed. Strip to just the deprecation notice.

Also fix the bridgeIp description: 'once netns isolation lands' is past
tense — isolation is unconditional now. Rephrase to present tense.
2026-07-04 21:57:26 +02:00
atlas
bc6353c232 docs(network): fix stale '(shared netns)' in bridge firewall table row
The parenthetical was backwards — this rule opens bridge ports so
*isolated* agents (in private netns, connected via veth) can reach
nginx. Remove the misleading '(shared netns)' tag, replace with the
accurate description.
2026-07-04 21:18:57 +02:00
atlas
1e986a0270 chore(nix): remove stale 'privsep phase 2' labels from comments
privsep is complete and always on. the phased-rollout framing
is historical — drop it from the inline comments, keeping the
accurate description of what the user + delegation actually do.
2026-07-04 21:04:18 +02:00
atlas
480b35aac4 docs(boundary): update to reflect always-on network isolation
All three area:ops pillars are now complete: network isolation is
always on (private netns, no shared-netns mode), the gateway is live,
and hive-c0re runs as the unprivileged hive-core user.

- Rewrite the intro to say the boundary is enforced, not aspirational
- Update 'Why network isolation is the load-bearing step' section to
  use past tense for the shared-netns world and note completion
- Mark network isolation as Complete in the sequencing list
2026-07-04 20:58:55 +02:00
atlas
a363d1f317 docs(gotchas): document nix fmt failure in git worktrees 2026-07-04 20:50:50 +02:00
iris
c594de07ca docs(ci): document CI checks, local equivalents, and pre-push hook 2026-07-04 20:48:58 +02:00
atlas
460ed50a80 chore(nix): remove stale phased-rollout comments in network + gateway modules 2026-07-04 20:44:50 +02:00
atlas
902d4dd461 docs(network): rewrite for always-on isolation; remove phased-rollout rationale
The two-phase network rollout (bridge-first, then isolateContainers) is
complete. Both options are now deprecated no-ops — isolation is always on.
Update the doc to reflect current state:

- Drop the phased-rollout intro ('off by default during rollout') and the
  v1/v2 comparison table; keep a brief historical note
- Remove 'Why ship before netns isolation' section (rollout is done)
- Update configuration example: network.enable is no longer needed
- Merge firewall description into a single table (80/443 always open)
- Remove 'Prerequisites before flipping on' and 'Migration behaviour'
  subsections (isolation was a one-time flip; no longer a toggle)
- Simplify resolver wiring: hive-priv always drops the marker; remove
  'only when isolated' conditional framing
2026-07-04 20:30:23 +02:00
atlas
f111dac231 fix(test): update effort_validation test to accept low and max levels
The test's invalid-values list included "low" which was valid before
this PR but is now a legitimate effort level. Replace with "lowest"
(still invalid) so the test keeps its coverage without false-failing.
2026-07-04 19:52:33 +02:00
atlas
742f4ef916 feat(#2220): add low and max effort levels
claude --effort now accepts low, medium, high, xhigh, max.
Expand EFFORT_LEVELS from 3 to 5, update NixOS enum + description,
and fix the stale doc comment in web_ui.rs.

Closes #2220
2026-07-04 19:52:33 +02:00
iris
c6e97ef600 docs(forge-tools): clarify create_repo MCP tool vs repo-create CLI
Agents cannot create repos directly via their forge token (no Create
scope; push-to-create disabled). Document the two paths:
- mcp__hyperhive__create_repo (forge tool group): creates under agents/
  org via hive-c0re, adds write-collaborator access, enables branch
  protection. The standard agent path.
- hive-forge repo-create / repo-add-collaborator (CLI): use the agent's
  own token; repo lands under agent's user account or org.
2026-07-04 19:01:07 +02:00
iris
0ae2dbd8fa docs(turn-loop): document forge + web_tools tool groups in Privileged tools section
The 'Privileged tools (by tool group)' section listed execution,
lifecycle/approvals, scheduling/diagnostics, capability-gated, and
matrix but was missing:

- forge (create_repo) — the only agent path to create a repo under the
  agents/ org; direct token creation is disabled for agents. Opt-in,
  not in any default preset.
- web_tools — enables Claude built-in WebFetch/WebSearch tools. Off by
  default. The tool whitelist section already mentioned these but the
  group was absent from the privileged-tools list.
2026-07-04 19:01:07 +02:00
iris
315f7c1f13 fix(docs/bash): fix broken prose sentence from prettier reformatting
The prettier markdown formatter (8406a452) converted a prose '+' into
a markdown list marker '-', splitting 'fires a wake...and the exit code
+ last stdout lines' into a dangling incomplete sentence followed by an
orphaned list item. Rewrite the sentence to avoid the pattern entirely.
2026-07-04 19:01:07 +02:00
iris
65dd64abd1 docs(matrix-tools): add missing open_dm to matrix tool list
open_dm(user_id) resolves (find-or-create) the DM room and returns
its room id without sending anything. It is the counterpart to
send_dm for cases where you need a room id to pass to a room-based
tool such as send_file or send_message.

The tool was present in hive-matrix-mcp (mcp.rs, handlers.rs,
protocol.rs) and the terminal-rendering icon table but was missing
from the tools/matrix.md reference doc.
2026-07-04 19:01:07 +02:00
iris
1b8b83fee1 fix(terminal-rendering): move fmtToolUse table after numbered list
The heading was inserted between items 3 and 4, breaking GFM ordered
list numbering (Forgejo renders items 4+ restarting at 1). Move the
subsection to after item 5 and update the in-prose reference to use
an anchor link instead of 'see table below'.
2026-07-04 18:56:59 +02:00
iris
8f876d0154 docs(terminal-rendering): expand fmtToolUse with complete pattern table
Replace the sparse 3-line prose description of fmtToolUse with a full
reference table covering every tool case added over the past several
PRs. Adds a new subsection listing the short-name convention (* suffix),
all Claude built-ins (Read/Write/Edit/Glob/Grep/Bash/TodoWrite), the
full hyperhive MCP surface (recv/send/ask/answer/remind/set_status/
get_loose_ends/get_agent_meta/cancel_loose_end/ack_until/kill/restart/
start/update/get_logs/get_host_journal/request_apply_commit/
request_init_config/request_update_meta_inputs), all scheduling tools
(list_schedules/cancel_schedule/fire_schedule_now/edit_schedule/
request_schedule_prompt — added in the previous PR), bash MCP tools
(run/status/kill), and matrix MCP tools (send_message/send_dm/
send_reply/send_reaction/read_room/mark_read/join_room/open_dm/
invite_user/download_file).
2026-07-04 18:56:59 +02:00
damocles
9b2d16ae6a fix(#2190): replace MANAGER_AGENT fallbacks with "operator" for attribution
- loose_ends.rs: NULL submitter on legacy approval rows → "operator"
- questions.rs: NULL submitter on cancel_loose_end → "operator"
- server.rs: HostRequest::RequestSpawn submitter → "operator"
- dashboard.rs: web-UI spawn submitter → "operator"
- socket_server.rs: submit_init_config with no declared parent → "operator"
- mcp.rs: drop MANAGER_AGENT exception from check_send_allowed; keep <parent> only
2026-07-04 18:56:16 +02:00
atlas
500c50745b docs(gotchas): document nixSrc stable-docs-drv approach 2026-07-04 18:46:50 +02:00
atlas
eadb25fc07 fix(#2213): decouple docs drvs from self store path via narrow nixSrc
The docs evaluation referenced self.nixosConfigurations.agent-base and
self.nixosModules.default — both tied to self's full flake store path.
Every commit produces a new self hash (even when only Rust or frontend
files change), so docs drvs change on every commit and the remote
builder (muede-pc2) must rebuild them from scratch each time.

Fix: use builtins.path on the nix/ directory with
builtins.unsafeDiscardStringContext to produce a content-addressed store
path (nixSrc) that only changes when .nix files change. Evaluate both
hostEval and agentEval from nixSrc using stub package args (pkgs.emptyFile /
pkgs.emptyDirectory) instead of self.overlays.default, which avoids
pulling in the Rust and frontend build closures.

Now docs drvs only change when a .nix file changes. PRs that touch only
Rust or frontend code hit the remote builder cache instead of forcing a
rebuild. Closes the disk-pressure-induced CI failure loop on muede-pc2.

Forge URLs in transformOptions updated to prepend nix/ prefix correctly
(nixSrc is a copy of nix/, so stripped paths need nix/ re-added).
2026-07-04 18:46:50 +02:00
damocles
672e77c849 feat(#2102): skip startup rebuild for stopped/unchanged containers 2026-07-04 18:45:27 +02:00
atlas
e60986cb76 chore(#2185): add scripts/pre-push hook to catch lint failures before CI
Wraps check-issue-refs.sh and check-comment-blocks.sh so a push that
would fail the tracker-tag or comment-block CI jobs is caught locally
before it reaches the remote — eliminating the fix-and-repush round-trip.

Install once per clone:
  ln -sf ../../scripts/pre-push .git/hooks/pre-push

Also adds a one-liner hint to CLAUDE.md so it surfaces in every
agent's context at session start.
2026-07-04 18:43:35 +02:00
iris
99347a24d9 docs(agent-ui): update effort levels to include low and max
Three references to the effort level set in docs/web-ui/agent.md still
listed the old three-item set (medium/high/xhigh). Update all three to
match the expanded set added by PR 2221: low/medium/high/xhigh/max.

Closes #2220 (docs side).
2026-07-04 18:34:23 +02:00
iris
40bd868f65 fix(agent-term): guard edit_schedule targets_add/remove against empty arrays
Empty arrays are truthy in JS so 'if (input.targets_add)' would emit
'+0 tgt' for an explicit []. Add .length guard so zero-element lists
are silently skipped — consistent with fmtArgsGeneric's [N] handling.

The MCP schema defaults both fields to null, making this theoretical,
but the guard is cleaner.
2026-07-04 18:22:05 +02:00
iris
f11357537e feat(agent-term): add formatters for scheduling and remaining request_* tools
Scheduling tools and the two remaining request_* tools fell through to
fmtArgsGeneric. They already had appropriate icons (⏱️ / 📦) but the
arg display was multi-field verbose.

New fmtToolUse cases:
- request_init_config: 'request_init_config* iris'
- request_update_meta_inputs: 'request_update_meta_inputs* [nixpkgs, …]'
  (or 'all' when inputs list is empty)
- list_schedules: 'list_schedules*()' (no args, explicit)
- cancel_schedule: 'cancel_schedule* #42 all' or '#42 [iris, dmatrix]'
- fire_schedule_now: 'fire_schedule_now* #42'
- edit_schedule: 'edit_schedule* #42 · body · interval · +2 tgt'
  (lists which fields are being changed, not their values)
- request_schedule_prompt: 'request_schedule_prompt* → iris at 14:00Z +3600s'

Closes #2201
2026-07-04 18:22:05 +02:00
iris
f4727e30ba docs(web-ui): update reading path to point at terminal-rendering.md
The 'How does the per-agent terminal render tool calls?' reading path
was pointing only at web-ui/agent.md. terminal-rendering.md is the
authoritative reference (added recently with the full row taxonomy
table). Update the pointer to send readers there first, with a
note that web-ui/agent.md has the high-level summary.
2026-07-04 18:06:55 +02:00
iris
bf39e014e3 docs(agent-ui): update per-stream rendering section, cross-ref terminal-rendering.md
The 'system' bullet was stale — it only mentioned the drop list
(init/result/rate_limit_event) and omitted the five specific handlers
added recently: plugin_install (muted note), commands_changed
(expandable details), compact_boundary (compact summary note),
thinking_tokens (in-place counter), and the generic catch-all.

Expand the bullet to cover the full dispatch shape, and add a
cross-reference to docs/terminal-rendering.md which has the
authoritative row taxonomy table and full dispatch walkthrough.
2026-07-04 18:06:55 +02:00
iris
231f2ae2f4 fix(dashboard): correct topology bulk-move endpoint description
The selection bar's M0V3 action uses two different endpoints:
- single agent: POST /api/topology/set-parent (form-encoded)
- multiple agents: POST /api/topology/set-parent-bulk (JSON array)

The previous text said 'POSTs to /api/topology/set-parent ... once
per selected agent' — wrong on both counts for multi-agent moves.
The bulk endpoint lands all moves in one topology.json commit.
2026-07-04 14:34:24 +02:00
iris
42b2f8ec40 fix: correct HIVE_DOCS_DIR path description (nix store path, not /run/ mount) 2026-07-04 14:31:39 +02:00
iris
b41e3276c3 docs(turn-loop): add dedicated section for hyperhive.docs.enable agent.nix option
The option was only mentioned in passing in the system-prompt render
section. Add a proper ### section (following the pattern of Agent icon,
user.passwordlessSudo, etc.) with the nix snippet, default, effect on
$HIVE_DOCS_DIR + system prompt, and a note on the narrow docs flake
input that avoids full container rebuilds on doc edits.
2026-07-04 14:31:39 +02:00
damocles
4842a1ca1d refactor(#1825): remove dead manager_port field from dashboard snapshot 2026-07-04 13:54:42 +02:00
iris
527022c5f2 fix: correct 409 endpoint name — /api/loose-ends not /api/state 2026-07-04 13:52:49 +02:00
iris
8e441ead93 docs(agent-ui): document HTTP error codes for POST endpoints
After the fix in c708f698, POSTs no longer always return 200 — they use
semantic status codes: 400 for bad input, 409 for retryable state
conflicts (turn in flight, hive-c0re busy), 500 only for genuine failures.
Update the preamble to the Per-agent endpoints section to reflect this.
2026-07-04 13:52:49 +02:00
atlas
49aa326a0e chore(#2165): add damocles@pr1ma + lexis@pr1ma mailmap entries 2026-07-04 13:50:16 +02:00
atlas
467d3fa82e fix(#1845): correct ProtectSystem=strict comment (nix called directly via NIX_REMOTE=daemon) 2026-07-04 13:44:42 +02:00
atlas
7e83d906b2 fix(#1845): upgrade hive-c0re ProtectSystem full → strict
hive-c0re never writes outside its StateDirectory + RuntimeDirectory:
  - /etc writes (nixos-containers) go through hive-priv, not c0re
  - /etc/hyperhive/serve.json is read-only at startup (written by the
    NixOS activation script, not by the daemon)
  - nix builds delegate to hive-priv via the privileged Unix socket;
    hive-c0re itself never invokes nix directly

So strict is safe: systemd keeps /var/lib/hyperhive (StateDirectory)
and /run/hyperhive (RuntimeDirectory) writable; everything else is
read-only, shrinking the writable attack surface to exactly what the
service needs.
2026-07-04 13:44:42 +02:00
iris
174876094e docs(observability): document OTEL configuration options
Add docs/observability.md covering all services.hyperhive.otel.*
options: enable, endpoint, protocol, headersCredential,
extraResourceAttributes, debug (new in cb0a66147a), and
metricIntervalMs.

Includes:
- Built-in OTEL_RESOURCE_ATTRIBUTES labels (service.name, agent, hive, swarm)
- Cumulative temporality note (avoids Prometheus DELTA drop)
- Network note for host-side collectors on non-standard ports,
  cross-referencing docs/network.md exposeHostPorts

Also:
- CLAUDE.md: add reading-path entry for the new doc
- docs/network.md: link the OTEL mention to observability.md

Closes no issue — gap found during doc sweep.
2026-07-04 13:17:42 +02:00
iris
2f8e9e2bb4 docs(turn-loop): document docs-pointer system-prompt injection, drop stale CLAUDE.md mention 2026-07-04 13:13:33 +02:00
damocles
c708f698ee fix(#2175): return 409/400 not 500 for turn-in-flight + validation errors 2026-07-04 13:13:20 +02:00
iris
cea2f2faff docs(terminal-rendering): expand fmtToolUse description to cover new cases
The renderer dispatch section only mentioned recv and Bash as fmtToolUse
examples. Update the description to cover the full range: matrix tools,
remind, scheduling, and the fmtArgsGeneric fallback.
2026-07-04 13:12:17 +02:00
iris
66057a97f7 fix(agent-term): split join_room/open_dm cases to fix open_dm always showing ?
join_room and open_dm shared a fall-through case with
(fmtRoom(input.room) || fmtUser(input.user_id) || '?'). fmtRoom()
returns the string '?' when input.room is undefined — truthy — so
the fmtUser() fallback was never reached and open_dm always displayed
'open_dm* ?'.

Split into two separate cases: join_room reads input.room, open_dm
reads input.user_id. Both degrade to '?' via fmtRoom/fmtUser's own
null guard.
2026-07-04 13:12:17 +02:00
iris
44bb64fa1f docs(terminal-rendering): fix stale send_message fmtArgsGeneric example
mcp__matrix__send_message now has a specific fmtToolUse case and no
longer falls through to fmtArgsGeneric. Update the prose to reflect
that common tools have specific cases.
2026-07-04 13:12:17 +02:00
iris
6c56bf76d6 feat(agent-term): matrix-tool icons + formatters, fill remaining fmtToolUse gaps
Add specific icons for matrix tools that had the generic 💬 fallback:
- mcp__matrix__read_room → 📖
- mcp__matrix__mark_read → 👁️
- mcp__matrix__list_rooms / list_room_members / list_invites → 📋
- mcp__bash__kill → 🛑 (was generic 🔧)

Add fmtToolUse cases for high-use tools that fell through to fmtArgsGeneric:
- set_status: 'set_status* "idle"' instead of 'set_status text: "idle"'
- get_loose_ends: 'get_loose_ends* [iris]' or 'get_loose_ends*()'
- get_agent_meta: 'get_agent_meta* iris' or 'get_agent_meta*()'
- cancel_loose_end: 'cancel_loose_end* question #42'
- bash kill: 'kill* abc123 [force]'
- Matrix tools: 'read_room* !abc1234 [50]', 'mark_read* !abc1234',
  'send_message* → !room: "body"', 'send_dm* → @mara: "body"',
  'send_reply*', 'send_reaction*', 'join_room*', 'open_dm*',
  'invite_user*', 'download_file*'

Also extend the short-name shortening to cover mcp__matrix__ prefix
(was only hyperhive + bash), so matrix tool rows show 'read_room*'
instead of 'mcp__matrix__read_room' as the prefix.

Two small helpers added: fmtRoom (truncates !id before ':' for
readability; keeps #alias intact) and fmtUser (@user:server → @user).

Closes #2198. Updates terminal-rendering.md icon list.
2026-07-04 13:12:17 +02:00
atlas
3a4b8d9873 fix(#1748): route all nix invocations through the host daemon (NIX_REMOTE=daemon)
Root contexts (systemd services running as root, PID 1) default to
store=auto which resolves to the LOCAL nix store — bypassing the host
daemon, its remote builders (muede-pc2), and any prebuilt derivation
outputs already in the shared store. This causes spurious full
rebuilds of agent toplevels that the host already built and cached.

Two changes:

harness-base.nix:
- Add systemd.globalEnvironment.NIX_REMOTE = "daemon" — sets
  DefaultEnvironment in systemd.conf so every unit in the container
  inherits NIX_REMOTE=daemon. Non-root contexts already default to
  the daemon socket; this only matters for root services that would
  otherwise use the local store.
- Add NIX_REMOTE = "daemon" to environment.variables so interactive
  shells also have it set (redundant with /etc/profile.d/nix-daemon.sh
  but explicit and profile-agnostic).

hive-c0re.nix (hive-priv service):
- Add NIX_REMOTE = "daemon" to the service environment. hive-priv
  runs as root and invokes nixos-container update + nix prebuild; these
  must route through the host daemon so they see the shared store and
  remote builders, not a private local store.

The sandbox-fallback = true in harness-base.nix is kept as a belt-
and-suspenders fallback but becomes a no-op for the common case once
nix routes through the daemon (the daemon builds on the host where
sandboxing works).
2026-07-04 13:12:02 +02:00
atlas
3e5ddbd2c0 fix(#1845): add ProtectSystem=full to hive-c0re service hardening
ProtectSystem=full makes /usr, /etc, and /boot read-only. Safe for
hive-c0re because it never writes to those paths directly:
- /etc writes (e.g. /etc/nixos-containers) go through hive-priv
- /etc/hyperhive/serve.json reads are read-only
- All runtime writes go to StateDirectory (/var/lib/hyperhive) and
  RuntimeDirectory (/run/hyperhive), which remain writable under full

ProtectSystem=strict (everything read-only) is still deferred — it
requires auditing ReadWritePaths for every nix path c0re touches.
RestrictAddressFamilies deferred pending a watched deploy.

Also tightens the comment block to not mention a numbered issue.
2026-07-04 13:01:47 +02:00
atlas
ef2b3a735c fix: remove tracker tag from source comment (lint) 2026-07-04 13:01:47 +02:00