- regenerate docs/tools/hivectl-cli.md for the new `subvol snapshot send` verb
- close the TOCTOU on the no-overwrite guard: File::options().create_new(true)
(O_CREAT|O_EXCL) instead of exists()-then-create, so the guarantee is
atomic against a concurrent request racing the same dest filename
- warn (not silently swallow) if cleaning up a partial export after a
failed btrfs send itself fails, so a stuck garbage file masquerading
as a completed export is visible in the log
Per mara's PR review:
- snapshot label is now mandatory (was optional w/ timestamp default)
and must start with "hive-" — hive-priv enforces this as an
allow-list on top of the existing credential-name charset check, so
only hivectl-issued labels can reach the btrfs shellout.
- nest under `subvol snapshot create`/`subvol snapshot delete`
instead of othering delete as a separate top-level `delete-snapshot`
verb.
Per argus's review:
- regenerate docs/tools/hivectl-cli.md (hivectl markdown-docs) to
include the new subcommands — CI's hivectl-docs-fresh check compares
this file against generated output.
A `status` or `run` call whose inline `wait_seconds` poll observes a
terminal task hands the caller the full result in that same tool
response. The completion wake fired unconditionally regardless,
producing a redundant `bash-task-<id>` inbox message for information
the agent already has.
Add a one-shot, in-memory wake-suppression registry in hive-bash-mcp's
runner: `wait_for_task` (shared by both BashRun's and BashStatus's
inline-wait paths) marks a task's wake suppressed the moment it
observes a terminal state; `run_task`'s completion handler consumes
that flag before calling `send_wake` and skips the wake if set.
In-memory only (daemon restart wipes it) — fine, since a task still
running across a restart is separately marked `interrupted` on boot
and gets its own fresh wake. Narrow best-effort race window between
the terminal write and the wake send; acceptable given this daemon's
existing best-effort delivery tolerance elsewhere.
docs/tools/bash.md updated to describe the new suppression behavior.
MergeConfigPr approvals had a fully-implemented approve handler
(run_merge_config_pr, ff_push_to_main, mark_pr_merged) and dashboard
display, but no way to submit one. An agent with the `approvals` tool
group calling request_merge_config_pr(agent, pr_number) is the missing
piece.
What this adds:
- RequestMergeConfigPr variant in hive-sh4re AgentRequest + ToolGroup::Approvals
- submit_merge_config_pr: fetches PR head sha (the drift-gate reviewed sha),
queues a MergeConfigPr row, sets fetched_sha, emits approval_added with
pr_number so the dashboard card links to the forge PR
- handle_request_merge_config_pr: topology (require_descendant) +
tool-group (require_group(approvals)) guards before submit
- socket_server/mod.rs: dispatch arm for RequestMergeConfigPr
- hive-ag3nt MCP tool: request_merge_config_pr with full description
- docs/tools/lifecycle.md: documents the new tool + boundary table row
Unlike submit_apply_commit, no flake pre-flight at submission time (eval-
verify happens at approval time inside run_merge_config_pr, same as the
rest of the merge pipeline). Applied repo must already exist (guard added
with a clear error message pointing at request_apply_commit for first-spawn).
every agent lifecycle verb on the admin socket (rebuild / restart /
restart-all / kill / stop / start) now submits job-queue DAGs and
returns their ids; hivectl polls the new HostRequest::QueueDag and
prints a live node-chain progress line per DAG (fan-out children
included), exiting non-zero on failure — --no-wait opts out. DagView
and the queue wire enums move to hive_sh4re::jobs (wire types live in
the shared crate); the last fused rebuild path (lifecycle::rebuild)
is gone. tracker: #2166
coordinator.md rewrites the queue section (node inventory, DAG shapes,
resources, desired-state reconciliation, boot reconcile); approvals.md
+ persistence.md + hivectl --graceful help updated to match. agent_power
lives in broker.sqlite like approvals/questions (own connection + busy
timeout) instead of a separate db file.
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.
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.
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.
- .prettierrc: proseWrap=preserve (no prose reflow)
- .prettierignore: exclude hivectl-cli.md (auto-generated) + 11 docs
with multi-line list-item continuations prettier would strip to col 0
(CommonMark limitation in prettier's list handling)
- format 16 markdown files: cosmetic only (*→_, table alignment,
heading normalisation) — verified no broken continuations, idempotent
The edit_schedule MCP tool accepts interval_seconds as Option<u64>
(positive values only), mapping None→leave-alone and Some(v)→set.
The handler wraps this as .map(Some) before dispatching, so there
is no way to express Some(None) = clear via the agent surface.
The old doc said 'Clearing interval_seconds to null flips
recurring → one-shot' which is only true for the dashboard
PATCH endpoint (which uses the full double-Option form).
Corrected: interval_seconds is positive-only via the MCP tool;
toggling recurring→one-shot is operator-only via the dashboard.
The kill tool (previous commit) produces the 'killed' terminal status,
but the status tool docs listed only pending/running/done/timed_out/
interrupted. Add 'killed' to complete the enum.
feat b16629801b added the kill tool to
hive-bash-mcp but docs/tools/bash.md wasn't updated. The tool was
described only in the MCP server tool-description string; add a proper
section to the reference doc.
kill(id, force?) fires SIGINT (force: false, default) or SIGKILL
(force: true) to the task's process group. Fire-and-forget — the
completion wake fires as usual. A pending task is cancelled outright.
Escalation pattern: SIGINT first, then force: true if it doesn't exit.
hive-forge comments on a PR now merges review bodies (the summary
text from approve / request-changes / comment reviews) into the
comment listing, fixed in 1cff77f5. The verb list inline comment and
the 'Which read verb when' table row both said 'only the comments'
which was stale. Updated both to reflect the review-body inclusion.
The human-readable matrix MCP reference was missing three behaviours
documented only in the MCP server instructions string:
- send_file / download_file tools (issues 1829, 1830)
- [file:]/[image:]/[audio:]/[video:] attachment markers in read_room (issue 1830)
- unread guard: send_message, send_dm, send_file, send_reply all
reject if the room has unread messages (issue 1828)
- send_redact (omitted from the tool list entirely)
Add all four to docs/tools/matrix.md to match the MCP server
instructions added in the previous commit.
Part of the #1802 hive-forge audit: the read verbs (view / issue / pr /
comments / comment-show / timeline / diff / pr-status / pr-reviews) look
overlapping but each has a distinct output shape. Add a selection table +
rule-of-thumb so agents pick the right one (esp. 'view first' to clear the
read-before-comment guard) instead of guessing. Zero blast radius — pure
docs, no verb changes (the audit concluded the CLI is structurally clean
and renames/removals aren't worth the caller breakage).
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.
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.
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.
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.
Per operator review (#1899): the hive's own domain should never be
typed by hand. Remove the --domain flag from peer-config and wg init
entirely; both now resolve it from the daemon (HostRequest::HiveDomain).
peer-config errors with a clear hint if the daemon can't answer; wg init
prints the peer block best-effort (skips it, still enables the mesh, if
unresolved). Regenerated docs/tools/hivectl-cli.md.
Per operator review: hivectl shouldn't make the operator retype this
hive's own domain. Add a HostRequest::HiveDomain admin-socket query
(c0re answers from HYPERHIVE_HIVE_DOMAIN, already in its service env) and
a domain field on HostResponse.
hivectl peer-config now resolves the domain as: --domain override (kept
for offline/scripted use), else the daemon query; errors with a clear
hint when neither resolves. wg init resolves it best-effort too, so it
prints the hand-over peer-config block without --domain (skipped, not
failed, when the daemon is unreachable).
Regenerated docs/tools/hivectl-cli.md.
Add `hivectl peer-config --domain <this-hive-domain>`: prints the
`services.hyperhive.swarm.peers."<domain>"` nix block a peer operator
pastes to federate with this hive. Emits `caCert = ./<hive>-ca.pem` plus
a `cp /var/lib/hive-tls/ca.pem ./<hive>-ca.pem` line when this hive
serves a self-signed CA (the cert file exists); omits caCert for
ACME/public-CA hives (trusted by the default bundle). Includes the
WireGuard public key when the mesh key exists, and the
wireguardAddress/Endpoint passed via flags.
`wg init` gains an optional --domain; when set it calls peer-config at
the end, so a fresh mesh setup prints the hand-over block in one command.
Pure output — reads local state (TLS CA cert presence, wg key), never
mutates. Regenerated docs/tools/hivectl-cli.md.
Closes#1897.
Group issue/PR operations under `pr` and `issue` parent commands
(`hive-forge pr close 42`, `issue create …`, `pr status --pr 42`) per the
operator decision — kind-namespaced verbs replace the flat surface.
- new `verbs::pr_cmd` / `verbs::issue_cmd` parent commands wrap the existing
per-verb modules (reuse their Args + run fns) under `#[command(subcommand)]`.
- kind-validation (the win over the old generic verbs): the generics that work
on both (view/comment/comments/close/labels/assign/timeline) call
`assert_kind` first, so `pr close <issue>` / `issue close <pr>` are rejected
with a 'use the other command' message. PR-only / issue-only verbs are
kind-correct by construction. `number` exposed `pub(crate)` on the shared
verbs so the wrappers can probe it.
- every flat kind verb (`close`, `pr-create`, `pr-status`, `issue-edit`, …)
kept as a `#[command(hide = true)]` back-compat alias — still parses, dropped
from --help; removed in a later sweep once usage migrates. (`pr`/`issue`
bare-show become `pr show` / `issue show` — the names are now parents.)
- docs/tools/forge.md documents the new surface + the deprecated aliases.
cargo build/clippy/fmt clean, 54 tests pass; --help surface + alias parsing
smoke-tested.
New agents get a btrfs subvolume state root automatically when the host
FS is btrfs, but agents that predate that migration are left on plain
dirs and miss the subvolume feature set (snapshots, per-subvol
usage/quota, send/receive migration). Add an opt-in operator verb to
convert an existing plain-dir agent in place.
btrfs cannot promote a directory to a subvolume in place, so the new
privileged op stages a sibling subvolume mirroring the dir (create +
`cp -a --reflink=auto` preserving ownership/permissions/xattrs + match
the root's owner and mode), then atomically renames the original aside
and the subvolume into place, then removes the original. Any failure
before the swap leaves the original untouched; idempotent (no-op if
already a subvolume) and btrfs-gated.
The `hivectl subvol upgrade <agent> --yes` verb composes it client-side
like `restart`: stop the agent so its state bind-mount is released, run
the migration via hive-priv, then restart it — the restart is attempted
regardless of the migration outcome so a failed migration never leaves
the agent down.
- hive-sh4re: UpgradeAgentSubvolume priv request variant.
- hive-priv: the migration handler plus stage/cleanup helpers.
- hive-c0re: priv_client wrapper and the hivectl verb; regen CLI docs.