Commit graph

2,109 commits

Author SHA1 Message Date
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
atlas
5ed0288634 hive-tls: default leafValidityDays to 397 (was 3650/~10y)
A 10-year leaf is pointless given the leaf auto-rotates (re-signed
within 30 days of expiry) and is long enough to make browsers warn.
397 days sits just under the 398-day CA/Browser-Forum leaf cap (so
browsers accept it) while bounding the blast radius of a leaf-key
compromise. The re-sign runs at service activation (hive-tls-ca is a
oneshot, no timer), so 397 stays comfortably above any gateway
rebuild gap.
2026-06-23 10:46:11 +02:00
iris
9634327b59 docs(web-ui): document the 'all' stats window
Follow-up to the stats 'all' time-range feature: the agent and hive
stats endpoint docs enumerated the window options but predated 'all'.
Add it to the /api/stats and /api/stats-hive window lists, and note
that 'all' ranges from the earliest recorded turn with an adaptive
bucket width.
2026-06-23 00:21:11 +02:00
iris
684c85686e feat(stats): add an 'all' time range to agent + hive stats
Adds a Window::All option to the per-agent stats page and the hive-wide
rollup, selectable as a new 'all' tab on both.

- hive-ag3nt (per-agent, time-bucketed): All ranges from MIN(started_at)
  to now (fallback to now on an empty table) with an adaptive bucket
  width laddered by span — hourly <=2d, daily <=90d, weekly <=2y, 30-day
  beyond — so the trend series stays bounded (~<=104 buckets) at any age.
- hive-c0re (swarm rollup, not time-bucketed): All sets from=0 so the
  aggregate covers every recorded turn across all agents.
- frontend: an 'all' button on both the agent stats and dashboard hive
  stats window selectors (createTabStrip + fetch already pass the window
  string through, so no JS change needed).

cargo check passes on both crates; FE builds clean. Fixes #1919.
2026-06-22 23:47:20 +02:00
lexis
d4dd5aad3e docs(tools/forge): document read-before-comment guard + --force flag 2026-06-22 23:33:13 +02:00
lexis
73a58776fa docs(turn-loop): document graceful stop recv behavior (follow-up to #1920) 2026-06-22 23:27:33 +02:00
damocles
1c84b3ef10 fix(#1916): direct the agent to end its turn on graceful stop instead of a fenced-empty recv 2026-06-22 23:24:54 +02:00
iris
581e5e3b4c fix(dashboard): send graceful=true not =1 for the kill query param
The kill endpoint deserializes ?graceful as a strict bool (true/false),
so the dashboard's ?graceful=1 failed with 'provided string was not
true or false' and graceful shutdown silently broke. The stop and
bulk-stop buttons build the param at two call sites in tabs.js; send
graceful=true instead (a hard kill still omits the param entirely).
Keeps the API contract strict — the FE one-liner damocles and I agreed
on, superseding the lax-bool deserializer in the closed #1917.
Fixes #1914.
2026-06-22 23:24:36 +02:00
atlas
d4f106d590 hive-gateway: route dashboard by path, not Accept header
The dashboard vhost split static-vs-backend on the request Accept
header (map $http_accept $dashboard_spa_target), so the same URL
behaved differently by content-type — e.g. /api/state fetched with
Accept: text/html wrongly returned index.html.

Now that all hive-c0re routes live under /api/ plus the single
/webhook/knowledge endpoint, route by path instead: /api/ and
/webhook/ proxy to c0re (SSE settings on /api/), everything else
serves the dist with try_files $uri /index.html. Drops the
dashboard Accept-header map and the @c0re named location.

Updates docs/gateway.md accordingly.
2026-06-22 23:08:23 +02:00
iris
5ae5657ca4 fix(dashboard): extract themed-dialog styles into an importable modal.css
The themed dialog component (modal.js: themedConfirm / themedPrompt /
themedToast) is raised from common.js's data-async / data-confirm
handler, which every page loads — but its .tc-* styles lived only in
dashboard.css (the main tabbed dashboard's stylesheet). So on any
standalone page (core/C0R3, settings, flow, logs) a dialog rendered
completely unstyled: the build-queue rebuild-cancel confirm came up as
raw text.

Extract the .tc-* rules into a dedicated modal.css component (paired
with modal.js) and @import it from common.css, so the styles load
wherever a dialog can fire — not just the main dashboard. esbuild
inlines the @import into the common.css bundle, so there's no extra
request and the main dashboard is visually unchanged (it loads
common.css too). The stale 'themedConfirm() in common.js' comment is
gone with the move. Fixes #1910.
2026-06-22 22:24:42 +02:00
iris
aa55f8c777 fix(dashboard): import appendLinkified in schedules.js
renderReminders() calls appendLinkified() (for the reminder file_path
and message bodies) but schedules.js only imported { $, el } from
common.js, so the reminders_changed SSE handler threw
'ReferenceError: appendLinkified is not defined' and the reminders
pane failed to render. appendLinkified is exported from common.js;
add it to the import. Fixes #1909.
2026-06-22 22:18:39 +02:00