Commit graph

2,119 commits

Author SHA1 Message Date
atlas
14ae7367cd fix(systemd): set explicit SyslogIdentifier on hyperhive-declared units
Follow-up to the harness fix: any unit whose ExecStart is a generated
wrapper (a NixOS `script =` block or a writeShellScript) gets its journal
SyslogIdentifier derived from the wrapper's store-path basename — an
opaque, unstable name. Pin an explicit stable identifier on every unit
hyperhive declares.

script/wrapper units (leaked store paths): forgejo-gpg-init,
hive-gateway-self-signed-cert, hive-tls-ca, hive-ci-prefetch,
hyperhive-isolated-dns, tea-login, forge-avatar-sync,
matrix-avatar-sync, hive-dashboard-links.

direct-binary units (basename already sane; explicit for tidiness +
future-proofing): hive-c0re, hive-priv, hive-matrix-daemon,
hive-bash-daemon, weston.

Only changes the displayed line identifier; journalctl -u <unit>
filtering (keys on _SYSTEMD_UNIT) is unaffected.
2026-06-23 22:53:33 +02:00
iris
fae2025247 docs(approvals): update helper-events routing to reflect shipped behavior
notify_manager (always-root) has been replaced by notify_submitter
(routes to the approval submitter, with root fallback for legacy rows).
Update three locations:

- Step 6 of end-to-end flow: "root agent's inbox" →
  "submitting agent's inbox"; explain notify_submitter + submitter column.
- InitConfig paragraph: remove limitation note; "to the root agent's inbox
  (current limitation...)" → "to the submitting agent's inbox via notify_submitter".
- Section header + prose: "Helper events to the root agent" →
  "Helper events to the submitting agent"; rewrite lead paragraph around
  notify_submitter semantics (approvals.submitter column, legacy fallback).
2026-06-23 22:45:43 +02:00
iris
60403fd27c docs(approvals): drop tracker-tag refs; add topology.rs pointer for role
Remove three bare #NNN tracker-tag references in docs/approvals.md
(hive-rules: no #NNN in code/comments/docs):

- Step 6 of end-to-end flow: "tracked in #1953" → "a known limitation
  under active development"
- InitConfig paragraph: same rewrite
- Helper events section: same rewrite

Also add a code pointer for `can_manage_top_level_agents`: the role is
defined as ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS in hive-c0re/src/topology.rs,
now noted inline so reviewers can verify the name is real.
2026-06-23 22:45:43 +02:00
iris
136102cd27 docs(approvals): reframe stale 'the manager' as the root agent
The last docs/ piece of the manager-cleanup. The manager is no longer a
structural role — root-ness is purely topological. Reframe:
- title 'Approvals + manager + helper events' -> 'Approvals + helper events'
- section headers: 'Manager view of applied'/'Manager policy'/'Manager
  (ruth) is hive-c0re-managed'/'Helper events to the manager' ->
  root-agent / root-bootstrap-container equivalents
- body prose: 'the manager (ruth)' -> 'the root agent' (or 'the submitter'
  in the approval-flow steps)
- authority semantics: 'manager-only' -> approvals are submitted by an
  agent with the approvals tool group, for its direct children
- dropped the stale 'the manager refuses to destroy itself' line (the
  bootstrap container is now destroyable + transient; recreated on startup)

Kept the genuine code/protocol identifiers (nixosConfigurations.manager,
manager_server, role:manager prompt block, notify_manager, the
/run/hyperhive/manager/ socket path) — renaming those would diverge from
the source (de-hardcoding is its own backend cleanup).
2026-06-23 22:45:43 +02:00
atlas
e816cf4d72 fix(ci-log): address review — prose tags, correct module doc, typed miss
- Remove the two issue-number tags from Rust comments (tracker-tag lint).
- Correct the module doc: the durable download is keyed by the per-repo
  run NUMBER + attempt segment (matches the code + persisted_logs doc),
  not a global id — the earlier 'global id' wording was stale.
- Replace the fragile e.to_string().contains("out of range") branch with
  a typed StreamerMiss enum (StepOutOfRange vs Unavailable), so a usage
  error can never silently fall through to the persisted-log path if a
  message string changes.
2026-06-23 22:45:05 +02:00
atlas
d340c1773a fix: ci-log durable persisted-log fallback for pruned runs
ci-log drove only the live run-view streamer (POST .../runs/<n>/jobs/<j>
with logCursors), which reads the live act_runner task record. Forgejo
prunes that record once a run completes, so the streamer 500s with
'task ... resource does not exist' on quick or older runs even though
the web UI still shows the logs — the reader (argus, atlas) then had to
ask the operator to relay the error.

Add a fallback: when the streamer errors or returns no lines, download
the persisted whole-job log via the same web route the run page's view-
raw-logs link uses, .../runs/<n>/jobs/<job>/attempt/<a>/logs, keyed by
the per-repo run number with the attempt segment. It survives the task
prune. Live and recent runs keep the rich per-step streamed view; only
the pruned case takes the flat fallback (where --step can't apply). New
--attempt flag (default 1) selects the run attempt for re-runs.

Verified against a real pruned run whose streamer 500'd: the fallback
prints the full persisted log; a completed short job ends cleanly at
'Job succeeded', confirming the route returns complete logs.
2026-06-23 22:45:05 +02:00
damocles
3d2e0ef561 feat(#1906): non-root weston gui on a fixed vnc port 2026-06-23 22:41:20 +02:00
atlas
5caec9c1a9 fix(forge): config-repo main is fast-forward-only (no auto force-push)
Per operator directive: a silent automatic force-push is a bug. The
config-repo merge path already never force-pushes (run_merge_config_pr
lands via ff_push_to_main, a non-force git push). So set the branch
protection's enable_force_push to false — main only ever advances by
fast-forward.

The legacy push_config mirror does force-push (it re-points the status
tags and rewinds main on a failed-build rollback); the protection now
rejects those non-ff updates, so the mirror runs best-effort until the
agent-opened PR-merge flow retires it. Docs + comments updated to match.
2026-06-23 22:37:27 +02:00
atlas
60da6c14b4 fix(forge): reword tracker-tag references in doc comments to prose
Address argus review on the config-repo PR surface: 6 issue-number tags
appeared in Rust doc comments in forge.rs; the tracker-tag lint matches
${'#'}NNN in code comments (markdown docs are exempt, doc comments are not).
Reword to prose, no behavior change.
2026-06-23 22:37:27 +02:00
atlas
558552ec54 docs(forge): s/mirror/config repo/ in dashboard anchor bullet for consistency
Address iris review nit on #1948: the bullet above now reframes the
agent-configs entry as a config repo, so the dashboard-anchor bullet
should match. Pure wording, no behavior change.
2026-06-23 22:37:27 +02:00
atlas
2fe79aaef5 feat(#1787): make agent-configs/<n> the agent-editable, PR-merge config surface
Wires the per-agent config repo as the editable PR surface the #1838
merge handler (run_merge_config_pr) consumes, without yet retiring the
push_config force-mirror (that waits for #1838 P2 — the agent-opens-PR
MCP surface — so config changes keep working through the transition).

ensure_config_repo now, after creating agent-configs/<name>:
- adds the agent as a WRITE collaborator (can push config-change branches
  + open PRs);
- branch-protects main core-only via apply_config_repo_branch_protection:
  push + merge whitelists are core-only (only hive-c0re lands on main, via
  its verify-and-ff-push handler), operator-team approval required, the
  agent can't push main directly or self-merge.

The protection sets enable_force_push=true as a TRANSITIONAL allowance so
push_config's applied->main force-mirror keeps working until P2 retires it
(a protected branch otherwise rejects force-push). Forgejo's force-push
allowlist is deploy-keys-only — no per-user list — so this is a plain
enable_force_push toggle; only core is in the push-whitelist so only core
can force-push anyway. At P2, flip it to false and keep core in the
push-whitelist so ff_push_to_main still lands.

Agent code repos (AGENTS_ORG) are intentionally untouched — their merge
flow has no auto-merge handler yet, so switching them to core-only-merge
would strand those PRs.

All steps idempotent (runs on every spawn + startup sweep). Updated the
CONFIG_ORG doc comment + docs/forge.md to drop the "mirror-only" framing.
2026-06-23 22:37:27 +02:00
damocles
f7d84f4847 fix(#1957): persist hivectl-start running-agents snapshot in the broker kv table 2026-06-23 22:07:46 +02:00
iris
e5da5b900e docs: fix remaining bare /kill/ and /rebuild/ paths → /api/ variants
coordinator.md: GracefulStop entry referenced the old bare /kill/<agent>
path with the lax graceful=1 bool — update to /api/kill/<agent>?graceful=true.

approvals.md: the auto-update badge description referenced /rebuild/<name>
(bare, no /api/ prefix) — update to /api/rebuild/<name>.
2026-06-23 22:05:05 +02:00
iris
4634094502 docs(web-ui/dashboard): fix stale /kill/ bare paths → /api/kill/ + graceful=true
The graceful-stop description at the ■ ST0P confirm-dialog paragraph
referenced `/kill/<name>?graceful=1` and `/kill/<name>` (bare, no /api/
prefix; lax bool `1` instead of `true`).

The backend has registered these under /api/ since the /api/-prefix
migration, and the frontend was updated to send `graceful=true` (not `1`)
in commit f2f1a0b3 (fix: send graceful=true not =1 for the kill query param).
Align the docs with shipped code.
2026-06-23 22:05:05 +02:00
damocles
ebaf192476 fix(#1953): gate approval cancel on submitter ownership + document submitter_of errors 2026-06-23 22:04:56 +02:00
damocles
3618399d94 fix(#1953): route approval helper-events to the submitter, not the root agent 2026-06-23 22:04:56 +02:00
damocles
14539de7d0 fix(#1962): pin harness SyslogIdentifier so otel ExecStart wrapper doesn't rename the log unit 2026-06-23 21:44:19 +02:00
damocles
21ec7dc23d feat(#1930): forward otel headers credential into agent containers via nspawn --load-credential 2026-06-23 21:16:18 +02:00
damocles
838cc9af9a feat(#1930): move otel stats export to host-level services.hyperhive.otel 2026-06-23 21:16:18 +02:00
iris
e18ddff0b0 docs(approvals): reframe stale 'the manager' as the root agent
The last docs/ piece of the manager-cleanup. The manager is no longer a
structural role — root-ness is purely topological. Reframe:
- title 'Approvals + manager + helper events' -> 'Approvals + helper events'
- section headers: 'Manager view of applied'/'Manager policy'/'Manager
  (ruth) is hive-c0re-managed'/'Helper events to the manager' ->
  root-agent / root-bootstrap-container equivalents
- body prose: 'the manager (ruth)' -> 'the root agent' (or 'the submitter'
  in the approval-flow steps)
- authority semantics: 'manager-only' -> approvals are submitted by an
  agent with the approvals tool group, for its direct children
- dropped the stale 'the manager refuses to destroy itself' line (the
  bootstrap container is now destroyable + transient; recreated on startup)

Kept the genuine code/protocol identifiers (nixosConfigurations.manager,
manager_server, role:manager prompt block, notify_manager, the
/run/hyperhive/manager/ socket path) — renaming those would diverge from
the source (de-hardcoding is its own backend cleanup).
2026-06-23 21:06:30 +02:00
iris
211dab6f90 fix(dashboard): carry pr_number on live approval_added
Completes the merge_config_pr approval-card link for live-added approvals.
The ApprovalAdded SSE event now carries pr_number (only for
merge_config_pr); applyApprovalAdded was dropping it, so a live-added
merge_config_pr card showed the sha but not the 'review PR on forge' link
until a cold /api/state reload. Carry pr_number through the same way as
sha_short.
2026-06-23 18:44:13 +02:00
damocles
12ed5da11a refactor(#1825): drop MANAGER_NAME special-cases in crash_watch + tombstones 2026-06-23 18:35:23 +02:00
atlas
6dcc1cb7e1 fix(reopen): add # Errors doc to run()
Address argus review on #1938's reopen verb: public fns returning Result
need a # Errors doc per the workspace convention. Document the patch_json
and print_json failure modes.
2026-06-23 18:35:19 +02:00
atlas
11fb2ac0fc hive-forge: add 'reopen' verb (pr reopen / issue reopen)
hive-forge had close but no reopen, so reopening required the non-obvious
workaround 'issue edit <n> --state open'. Add a reopen verb mirroring close
(PATCH state=open), wired into both 'pr reopen' (kind-checked PR) and
'issue reopen' (kind-checked issue). Updates docs/forge.md + the subcommand
enumerations.
2026-06-23 18:35:19 +02:00
iris
efb34ef677 fix(dashboard): drop stale manager destroy-hiding comment + vestigial block
Follow-up to the destroy-guard removal — the bootstrap/root container is
now destroyable end-to-end. The frontend already offered DESTR0Y/PURG3
for every container; the only manager-gating left was a stale doc-comment
('destroy/purge hidden for the manager') and a vestigial bare block
wrapping the menu appends. Drop both (no behaviour change), and update the
dashboard.md menu doc: 'disabled for the bootstrap container' -> available
for any container (hive-c0re recreates it on next startup if destroyed).
2026-06-23 18:33:45 +02:00
damocles
9ee5a94d50 fix(#1930): headersCredential str type (no nix-store copy) + route traces to otlp 2026-06-23 17:46:41 +02:00
damocles
97ef00742e feat(#1930): optional per-agent OTEL stats export via claude-code telemetry 2026-06-23 17:46:41 +02:00
damocles
4c53898382 fix(#1940): carry pr_number on the live approval_added event 2026-06-23 17:28:01 +02:00
damocles
6516d4282e fix(#1932): hivectl start restores only the previously-running agents 2026-06-23 17:25:15 +02:00
iris
d1125207b4 fix(#1940): render merge_config_pr approval cards
renderApprovals had no merge_config_pr case, so those approvals
mis-rendered as generic spawn cards (spawn chip, no sha, 'container will
be created' body). Add a dedicated branch:
- distinct glyph + 'merge-pr' kind chip
- show the reviewed PR-head sha (sha_short), like apply_commit
- a 'review PR on forge' link built from pr_number (now on ApprovalView),
  gated on forge_present, mirroring the apply_commit 'commit on forge' link
- no config-diff side-panel (apply_commit-only for now)
History rows get the 'merge-pr' chip too.
2026-06-23 17:24:03 +02:00
damocles
00f682991c refactor(#1896): remove dead forge_notify reason plumbing + fix docs 2026-06-23 17:23:06 +02:00
atlas
abd70531d5 hive-forge: fix stale ci-rerun CLI variant doc
The clap subcommand doc in main.rs still described the old web-route
implementation (--job, 'POSTs the rerun web action'), which surfaces in
hive-forge --help. Update it to match the workflow-dispatch rework.
2026-06-23 14:53:11 +02:00
atlas
c9c59c2a1d hive-forge: ci-rerun dispatches a fresh run via workflow-dispatch API
The previous implementation POSTed Forgejo's run-page rerun web route,
which is CSRF-gated and answers a bare token POST with 404 — so the verb
never actually re-ran anything against the agent token.

Rework it to dispatch a fresh run of the workflow via the
GitHub-compatible workflow-dispatch API
(POST /repos/<o>/<r>/actions/workflows/<workflow>/dispatches {"ref":<branch>}),
which accepts a plain agent token (verified end-to-end on Forgejo 15.0.3).
A dispatched run is equivalent to the old empty-commit retrigger, minus
the commit.

The branch is resolved from exactly one of --pr (the PR head branch),
--run (branch + workflow looked up from that run in the Actions runs
list), or --branch (directly); --workflow picks the workflow file for
--pr/--branch (default ci.yml). Dispatch re-runs the whole workflow, so
the old --job single-job variant is dropped.

Also add workflow_dispatch to .forgejo/workflows/ci.yml for explicitness
(Forgejo 15.0.3 dispatches the pull_request workflow without it, but the
trigger makes the API path intent-clear and cross-version robust), remove
the now-unused Client::post_web_no_content, and update docs/tools/forge.md.
2026-06-23 14:53:11 +02:00
atlas
cd4bdf4eea feat(#1778): add hive-forge ci-rerun to re-run CI without an empty commit
When a CI run fails for a transient reason (remote-builder flap, cold-daemon
window, act_runner hiccup) the only retrigger path was an empty commit, which
litters PR history and forces a force-push to clean up. This verb POSTs the
rerun action directly.

- `ci-rerun --run <n>` re-runs all jobs of a run (run number = the `runs/<n>`
  the UI shows, same value ci-log / artifact-get take, surfaced as a CI
  context's target_url by pr-status).
- `--pr <n>` resolves the run from the PR head sha's CI status target_url.
- `--job <i>` re-runs a single job.

Forgejo exposes no REST endpoint for rerunning a run, so this rides the run
page's web routes (`<base>/<owner>/<repo>/actions/runs/<n>[/jobs/<i>]/rerun`)
via a new `Client::post_web_no_content` (web base like post_json_web, tolerates
the redirect/empty response the rerun handler returns). Mirrors ci-log's
web-route approach + auth path.

docs/tools/forge.md updated with the verb.
2026-06-23 14:53:11 +02:00
damocles
658812c263 feat(#1940): expose pr_number on approvalview for merge_config_pr 2026-06-23 14:50:27 +02:00
damocles
e593547063 feat: make the bootstrap/root container destroyable (drop stale destroy guard + redundant hive-priv manager allows) 2026-06-23 14:50:03 +02:00
iris
20e26ad28d docs(persistence): correct the root-container destroy claim (imperative, not declarative)
The 'non-destroyable (declarative; would fight with host NixOS config)'
claim was stale: the root/bootstrap container is imperative
infrastructure, managed end-to-end by hive-c0re (auto_update::
ensure_root_agent recreates it on startup if absent). The actions::
destroy bail is a soft policy guard, and destroying the container is
transient anyway — it's recreated on the next hive-c0re startup.
2026-06-23 14:48:10 +02:00
iris
80c33f5108 docs(security): drop redundant bootstrap-container allowlist entry
The hive-priv container allowlist's explicit MANAGER_NAME allow is
redundant — the bootstrap container's name passes the generic
agent-name char validation anyway. Describe the allowlist as just the
agent-name convention + the sibling service containers.
2026-06-23 14:48:10 +02:00
iris
7e0190e27c docs: address mara review on #1936
- Drop the redundant 'including the root/bootstrap container' /
  'sub-agents + root' enumerations in the port-range + state-dir
  uniformity statements — 'every agent' / 'all agents' is enough (and
  calling out '+ root' reintroduces the special-case framing).
- Stop describing the root agent's privileged (manager-flavour) socket
  as a current thing (it's being removed): drop the conventions.md
  capability clause, the network.md per-agent-privileged-socket list
  entry, and the persistence.md /run/hyperhive/manager/mcp.sock
  runtime-dir bullet.
2026-06-23 14:48:10 +02:00
iris
c24ca4dfe1 docs(dashboard): reframe stale 'the manager' as the root/submitting agent
Schedule columns, tool-group/capability defaults, terminal addressing
(@root), destroy/move guards, and approval-resolution notes now refer to
the root agent (or the submitting agent, for approval flows) rather than
'the manager'. Also fixed the stale 'moving the manager' move-refusal
example (the root agent is reparentable) to a cycle example.
2026-06-23 14:48:10 +02:00
iris
ec5c7d49c4 docs: reframe stale 'the manager' as the root/bootstrap container (infra + web-ui)
Port-range, network-isolation, state-dir, web-UI-port, priv allowlist,
and rebuild-source mentions now refer to the root/bootstrap container
rather than 'the manager' — no structural manager exists (root-ness is
topological). Real artifact names (the manager.nix template toplevel,
/run/hyperhive/manager/mcp.sock) are left as-is.
2026-06-23 14:48:10 +02:00
iris
adb76f3cdf docs(persistence): reframe stale 'the manager' as the root agent
Config-repo editor, meta RO-mount, non-destroyable container, and the
topology.json example now refer to the root agent / bootstrap container
rather than 'the manager'. The /run/hyperhive/manager/mcp.sock path is a
real runtime path, kept (clarified as the root agent's manager-flavour
socket).
2026-06-23 14:48:10 +02:00
iris
d6debd4762 docs(conventions): reframe stale 'the manager' as the root/bootstrap agent
The manager is no longer a structural role — root-ness is purely
topological (an agent with no parent). Reframe the naming + socket
lines that presented 'the manager' as a fixed coordinating agent,
while keeping the manager-flavour socket/protocol identifiers (those
still name live code).
2026-06-23 14:48:10 +02:00
damocles
b5420a31fd fix(#1838): drop tracker tag from dashboard merge-config-pr comment (lint) 2026-06-23 13:49:35 +02:00
damocles
96e41c807d fix(#1838): extract dispatch_rebuild_approval so dispatch stays under the clippy line cap 2026-06-23 13:42:20 +02:00
damocles
ef958983e0 docs(#1838): document the merge-config-pr approval kind + queue dispatch 2026-06-23 13:12:12 +02:00
damocles
0b86295776 feat(#1838): run_merge_config_pr handler (verify pr head, ff forge main, deploy) 2026-06-23 13:12:12 +02:00
damocles
5f5626456a wip(#1838): extract deploy_applied_target shared deploy tail + dedup approve dispatch 2026-06-23 13:12:12 +02:00
damocles
449e3fcb7b wip(#1838): add MergeConfigPr approvalkind + match-site arms 2026-06-23 13:12:12 +02:00
atlas
4e4e9f8a60 hive-tls: leafValidityDays default 30 (per mara: ahead of the ~47-day proposal)
Short-lived leaf bounds the blast radius of a key compromise. Doc notes
the renewal caveat: re-sign is activation-only today, so a hive that
stays up >30 days without a rebuild would need a periodic re-sign timer
to avoid leaf expiry (follow-up).
2026-06-23 10:46:11 +02:00