diff --git a/docs/content/hive/acmm-policy-matrix.md b/docs/content/hive/acmm-policy-matrix.md index 200beaf2..2892e235 100644 --- a/docs/content/hive/acmm-policy-matrix.md +++ b/docs/content/hive/acmm-policy-matrix.md @@ -11,9 +11,21 @@ catch mistakes are put in place. Hive enforces each level in code: the level decides which agents run, in which policy mode, with which GitHub permissions. Background: [the ACMM paper](https://arxiv.org/abs/2604.09388). +**Terms used in the tables:** a **PR** is a pull request proposing a code +change; **CI** is continuous integration (automated checks); **GH Auth** means +GitHub credentials. **Beads** are internal work-ledger entries, not GitHub +issues. The **KB** is the knowledge base of reusable facts; an **RFC** is a +request for comments on a proposed design. For a first deployment's trust +choices, start with [Securing your hive](/docs/hive/securing-your-hive). + ## Policy Modes -Each agent runs in one of four modes, controlling what actions it can take on GitHub. +The four policy tiers below describe the main autonomy ladder. The roster also +uses `issues-only` for measured/`ISSUES_ONLY` and `issues+prs` for +`ISSUES_AND_PRS` (PR creation without merge authority). `converse` is an +orthogonal comments/reviews capability, not a fifth autonomy level: the reviewer +remains advisory but can authenticate to post reviews. Always read the role's +level-specific qualifications, not just its template's `full` suffix. | Mode | Suffix | Beads | Issues | PRs | Merge | GH Auth | |------|--------|-------|--------|-----|-------|---------| @@ -84,7 +96,22 @@ Delivery agents open GitHub issues — bugs, docs gaps, CI problems, security vu ### L5 — Semi-Autonomous (Semi-Automated) (14 agents) -Agents open issues AND pull requests. Agent PRs get literal `hold` from the level gate — humans batch-review and approve. The dashboard `hive-pause/` label is a separate manual hold, and `hive/` is provenance only. Architect produces RFCs, strategist coordinates across agents, and reviewer works the hold-gated PR queue every 30 minutes, and adjudicator works escalated (`needs-human`) hive PRs through the reviewer lane every 30 minutes (recommend-close only; closing is operator-only below L6). Dedupe runs once a day, reads every open issue and PR, and posts one consolidation checklist issue per repository (near-duplicates, same-root-cause clusters, unlinked PR/issue pairs, already-resolved items), parked with `--needs-decision`; it never closes or edits anyone else's items. The system proposes; it does not merge autonomously. +**Permission boundary:** agents open issues and PRs, but do not merge +autonomously. Agent PRs get literal `hold` from the level gate for human +batch-review and release. The dashboard `hive-pause/` is a separate +manual hold; `hive/` records provenance only. + +**Specialist lanes:** + +- Architect produces RFCs; strategist coordinates across agents. +- Reviewer works the hold-gated PR queue every 30 minutes. +- Adjudicator works escalated (`needs-human`) Hive PRs through the reviewer + lane every 30 minutes. It may recommend closure, but below L6 only an operator + closes them. +- Dedupe runs daily, reads all open issues/PRs, and posts one consolidation + checklist per repository (near-duplicates, common root causes, unlinked + PR/issue pairs and already-resolved items), parked with `--needs-decision`. + It never closes or edits anyone else's items. | Agent | Mode | Template | |-------|------|----------| @@ -105,7 +132,56 @@ Agents open issues AND pull requests. Agent PRs get literal `hold` from the leve ### L6 — Autonomous (15 agents) -Existing autonomous lanes can open issues, create PRs, and auto-merge on green CI. Auto-merge is off below L6; switching to L6 turns it on for every active repository, after which owners can toggle repositories individually. L6 PRs do not get the level hold, except outreach PRs into a repository the hive does not manage, which are still held for human review; outreach PRs into the hive's own repos auto-merge like any other lane's. Contributor PRs can merge through the contributor lane when the author has an operator-trusted tier or the conservative `auto_merge.contributor_tier.auto_promote_after_merged` clean-history ratchet admits them; reviewer verdict, CI, diff fences, soak and branch protection still apply. Hive never needs App Actions write for `action_required` workflow runs: when trusted same-repo bot/App/registry-trusted clanker PRs hit the workflow-approval banner, Hive posts `/ok-to-test` once per head and the repository's self-contained `hive-ok-to-test` workflow approves those runs with its `GITHUB_TOKEN`; if the workflow is absent or a `sentinel-alert` is present, Hive surfaces `workflow-approval-required:` / stage 085 for a human decision. Outreach handles community engagement. Reviewer stays advisory unless the self-authored review gate is enforcing: `review.require_approval: true` (or `governor.review_gate.mode: enforce`) makes the App self-authored sweep require same-head aggregate approval, while `requires_human`/incomplete verdicts can be cleared by a trusted human's normal GitHub Approve review on that exact head. For Hive-authored PRs, `review.self_authored_decision_policy: resolve` (the default) lets the reviewer resolve every decision question itself except those in a named risk class (permissions/credentials, security, sensitive paths, data loss/irreversible, merge/trust policy, external side effects, licensing/legal, unverifiable) or marked `hive-decision-risk: high`; set `escalate` to park every decision question at 085. Swarm `changes_requested`/`reject` still requires a fix or direct human merge. Use actual holds or GitHub branch rules for a universal merge stop. Adjudicator is the reviewer lane: it repairs, de-escalates, or recommends closing (and may close) escalated `needs-human` hive PRs, and never merges. Dedupe posts the same daily consolidation checklist as at L5 and stays recommendation-only. Telemetry and operations remain paused and use `ISSUES_AND_PRS`, so they never merge their own PRs. +**Permission boundary:** autonomous delivery lanes can open issues/PRs and +eligible PRs can merge on green CI. Auto-merge is off below L6. Switching to +L6 enables it for every active repository; owners can then toggle repositories +individually. L6 does not remove other merge gates or grant every role merge +authority. + +#### Destination and author exceptions + +- **Outreach:** no level hold for PRs into a repository managed by this hive. + Outreach PRs into another repository remain held for human review at every + level, including L6. +- **Contributors:** the contributor lane admits operator-trusted authors or + those admitted by the conservative + `auto_merge.contributor_tier.auto_promote_after_merged` clean-history ratchet. + Review, CI, diff fences, soak and branch protection still apply. +- **Nonmerging roles:** reviewer never merges. Adjudicator repairs, + de-escalates, recommends closure and may close escalated `needs-human` Hive + PRs at L6, but never merges. Dedupe stays recommendation-only. Telemetry and + operations stay paused and use `ISSUES_AND_PRS`, despite their `full` + template names; they never merge their own PRs. + +#### Review and decision gates + +The reviewer role remains advisory. Its verdict becomes an enforced merge gate +when `review.require_approval: true` or `governor.review_gate.mode: enforce` +is set. The App sweep checks current-head aggregate approval on self-authored, +trusted-bot and trusted-author paths; it is not scanner-only. +A trusted human merger's GitHub **Approve** review on that exact head can +override any swarm outcome, including `changes_requested`/`reject`; the audit +records who overrode which verdict. Other holds, CI, author admission, path +fences and GitHub rules still bind. A head-bound `/hive decision approve` +on an eligible Hive-authored PR can also answer `requires_human`; bare +`/hive approve` cannot. See [the L6 gate contract](/docs/hive/running-at-level-6#does-the-hive-reviewer-stop-a-merge). + +For Hive-authored PRs, `review.self_authored_decision_policy: resolve` +(default) lets the reviewer resolve non-risk decision questions. The exceptions +are permissions/credentials, security, sensitive paths, data loss/irreversible +actions, merge/trust policy, external side effects, licensing/legal, +unverifiable claims, or `hive-decision-risk: high`. Set `escalate` to park +every decision question at PR stage 085. Use actual holds or GitHub branch +rules for a universal merge stop. + +#### Workflow approval, not App Actions-write permission + +For trusted same-repo bot/App/registry-trusted clanker PRs with +`action_required` workflow runs, Hive posts `/ok-to-test` once per head. +The repository's self-contained `hive-ok-to-test` workflow approves the runs +using its own `GITHUB_TOKEN`; the App needs no Actions-write grant. If that +workflow is missing or `sentinel-alert` is present, Hive surfaces +`workflow-approval-required:` / PR stage 085 for human action. | Agent | Mode | Template | |-------|------|----------| @@ -170,7 +246,16 @@ predate hive's first sight of, or write access to, the repo. 4. **Mode escalation is per-agent.** At L4, some agents are measured (issues only) while others are holdgated (issues + PRs). The level defines the mix. 5. **Knowledge priming works at all levels.** The `${KNOWLEDGE}` template variable injects relevant facts from git sources and wiki layers regardless of the agent's mode. 6. **Brainstorm is always advisory.** It produces KB facts and beads, never GitHub issues or PRs. Its role evolves from inception (L1) to ongoing ideation (L2+), but its mode stays advisory at all levels. -7. **Reviewer is in every pack from L2 up and never merges.** It joined the L5 and L6 rosters in [#8023](https://github.com/hivecommons/hive/issues/8023) and the L2, L3 and L4 rosters in [#13574](https://github.com/hivecommons/hive/issues/13574) (community vote 2026-10-22: review-first entry point at L2 and every level above), at a 30-minute cadence in every governor mode. At L2 it is COMMENT-only; at L3 and L4 it reviews the `hold`-gated queue with exactly the authority those levels already grant — comment and route to a human, no lgtm/approve/merge. Only L1 (observe-only) omits it, so an operator who wants repo-grounded PR review there creates it by hand and a pack apply leaves that agent's mode, model, backend, and pause state alone. Its mode stays `ADVISORY` at every level, including L6: it reads the queue, comments, and returns a verdict. `requires_human` or `reject` stops scanner eligibility only when `review.require_approval: true` requires same-head approval; the App auto-merge sweep does not read those verdicts. Use a hold or GitHub branch rule when merging must stop. See [Running at Level 6](/docs/hive/running-at-level-6#does-the-hive-reviewer-stop-a-merge). +7. **Reviewer is in every pack from L2 up and never merges.** It runs every + 30 minutes in every governor mode. At L2 it is COMMENT-only; at L3/L4 it + comments on the held queue and routes to a human, with no lgtm/approve/merge + authority. L1 omits it; a manually created L1 reviewer's mode, model, + backend and pause state survive pack apply. Its mode remains `ADVISORY`, + including at L6. This role restriction is separate from the enforcing + review gate described above, which **does** read verdicts on the App sweep. + Use a hold or GitHub branch rule for a universal stop. + Roster history: [#8023](https://github.com/hivecommons/hive/issues/8023) + and [#13574](https://github.com/hivecommons/hive/issues/13574). 8. **Telemetry and operations are L5/L6-only opt-in agents.** Below L5 they are absent from the pack roster and dashboard, do not spawn panes, and cannot be kicked. At L5–L6 they use a paused cadence in every governor mode until an operator opts in; they may open issues and PRs but never merge. ## ioscan hardening defaults per level @@ -184,8 +269,8 @@ the pack only supplies the default when the hive leaves the key unset. | `ioscan.canaries` | **on** | **on** | Plants a per-kick `HIVE-CANARY-*` marker and scans agent egress for it. Default flipped on ([#7083](https://github.com/hivecommons/hive/issues/7083)) now that the egress scan is encoding-aware ([#6701](https://github.com/hivecommons/hive/issues/6701), [#6720](https://github.com/hivecommons/hive/issues/6720)). | `ioscan.canaries: false` | | `ioscan.fail_mode` | `open` | **`closed`** (set by the L5/L6 packs' `governor.ioscan_fail_mode`) | `open` redacts a Critical injection finding and continues the kick; `closed` blocks the kick and records an `ioscan_fail_closed` audit entry. | `ioscan.fail_mode: open` (or `closed` to opt in below L5) | -`fail_mode: closed` is the default only at L5–L6 because those are the levels -where agents can merge, so a Critical finding that slips through has the highest +`fail_mode: closed` is the default only at L5–L6, where agent PR creation is +broadest and L6 also permits merges, so a Critical finding that slips through has the highest blast radius. **The tradeoff is real and worth stating plainly: under `closed`, every Critical false-positive becomes a stalled queue item that an operator must clear by hand.** A hive that cannot absorb that operational load should set diff --git a/docs/content/hive/adr/0001-record-architecture-decisions.md b/docs/content/hive/adr/0001-record-architecture-decisions.md index 90a3634e..01e121e2 100644 --- a/docs/content/hive/adr/0001-record-architecture-decisions.md +++ b/docs/content/hive/adr/0001-record-architecture-decisions.md @@ -4,11 +4,16 @@ Status: Accepted +An **Architecture Decision Record (ADR)** explains why a durable technical +choice was made. This series is for maintainers; for setup and daily operation, +start with the relevant operator guide. + ## Context Hive's reference architecture documents the current system model, including the -single-container process model, deterministic pipeline, layered guardrails, ACMM -levels, beads ledger, hub/spoke topology, and observability surfaces. Those docs +single-container process model, deterministic work pipeline, layered guardrails, +[ACMM autonomy levels](/docs/hive/acmm-policy-matrix), the [beads work ledger](/docs/hive/adr/0004-beads-work-ledger), +[hub/spoke fleet topology](/docs/hive/adr/0014-hub-spoke), and monitoring surfaces. Those docs explain how the system works, but they do not preserve why durable choices were made or what trade-offs future maintainers should keep in mind. diff --git a/docs/content/hive/adr/0002-mitm-proxy-network-enforcement.md b/docs/content/hive/adr/0002-mitm-proxy-network-enforcement.md index 2f64f8f2..09b31349 100644 --- a/docs/content/hive/adr/0002-mitm-proxy-network-enforcement.md +++ b/docs/content/hive/adr/0002-mitm-proxy-network-enforcement.md @@ -4,6 +4,15 @@ Status: Accepted (retroactive) +**MITM** means **man-in-the-middle**: a local proxy inspects agent requests to +GitHub and blocks writes outside the agent's allowed mode. Here it is an +intentional enforcement point, not an external attacker. + +**Prerequisites:** [ACMM](/docs/hive/acmm-policy-matrix) is the autonomy-level model. +**Egress** means outgoing traffic; a local **CA** (certificate authority) +lets the proxy inspect HTTPS, and **iptables** supplies the Linux traffic +redirect. Installing a proxy alone does not force traffic through it. + ## Context Hive agents can run powerful coding CLIs in tmux sessions. A malicious prompt or @@ -16,6 +25,9 @@ The deterministic pipeline and merge gate produce the list of PRs that may merge ## Decision +Enforce GitHub write permissions outside the model: route agent API traffic +through a deny-by-default proxy, and reserve PR creation/merge for Hive's relays. + Keep a local MITM proxy in the agent egress path for `api.github.com`. The proxy classifies REST and GraphQL requests by method/path/body and requires the minimum ACMM mode for each write. It denies unknown writes by default, hard-denies the REST diff --git a/docs/content/hive/adr/0003-acmm-autonomy-levels.md b/docs/content/hive/adr/0003-acmm-autonomy-levels.md index b0a2cbef..aa03101e 100644 --- a/docs/content/hive/adr/0003-acmm-autonomy-levels.md +++ b/docs/content/hive/adr/0003-acmm-autonomy-levels.md @@ -4,6 +4,14 @@ Status: Accepted (retroactive) +**ACMM** is the **AI Codebase Maturity Model**. Its levels are an operator's +autonomy choice; a mode is one agent's allowed actions. In operator terms, +`ADVISORY` means observe, `ISSUES_ONLY` (measured) means file issues, +`ISSUES_AND_PRS` (holdgated) means propose code without merging, and +`ISSUES_PRS_MERGE` (full) permits merging subject to the merge gates. +The [policy matrix](/docs/hive/acmm-policy-matrix) is the current per-level roster, +including the review-only `converse` capability. + ## Context Hive needs one operator-facing control for how autonomous agents may be. The diff --git a/docs/content/hive/adr/0005-forge-abstraction.md b/docs/content/hive/adr/0005-forge-abstraction.md index 131a4374..6e8d294b 100644 --- a/docs/content/hive/adr/0005-forge-abstraction.md +++ b/docs/content/hive/adr/0005-forge-abstraction.md @@ -4,6 +4,10 @@ Status: Accepted (retroactive) +A **forge** hosts repositories, issues and code-review requests (for example, +GitHub). This ADR describes an internal interface, not a claim that every +adapter supports running a hive; see [Forge setup](https://github.com/hivecommons/hive/blob/v5/src/docs/forge-app-setup.md). + ## Context Hive's first production paths were GitHub-shaped, but the v4 package model @@ -30,7 +34,12 @@ styles are already neutral. Most Hive code can depend on the work-item model instead of GitHub-specific API types, which makes GitLab and Forgejo support additive rather than a fork of the -scheduler. The canonical `hive-pause/` label gives the dashboard one exact-match manual hold primitive; level-gated GitHub PRs use literal `hold`, and `hive/` is provenance only. +scheduler. + +**Label mapping.** The canonical `hive-pause/` label gives the dashboard +one exact-match manual hold primitive; level-gated GitHub PRs use literal `hold`, +and `hive/` is provenance only. + The trade-off is an intentionally incomplete abstraction: callers that need a real merge still use a forge-specific client until Hive has enough semantics to standardize that operation honestly. diff --git a/docs/content/hive/adr/0006-planning-intelligence.md b/docs/content/hive/adr/0006-planning-intelligence.md index bd8b795e..452dcc50 100644 --- a/docs/content/hive/adr/0006-planning-intelligence.md +++ b/docs/content/hive/adr/0006-planning-intelligence.md @@ -4,6 +4,10 @@ Status: Accepted (retroactive) +A **kick** is a work prompt sent to an agent. An **epic** groups a large piece +of work; its child tasks form a **directed acyclic graph (DAG)**, so dependencies +can be completed before the tasks that need them. + ## Context Large GitHub issues can be too vague for a single agent kick. Hive needs a way @@ -25,12 +29,15 @@ dependency edges and execution tags. Decomposition writes `parent_epic`, out of ready queues until a human approves them. Reviewers may inspect, retag, remove, approve, or reject children before work is released. -The automatic issue-label entry point stays opt-in. `planning.plan_from_label` -defaults off because the label path can feed attacker-controlled issue text into -the architect prompt without per-kick review; even when enabled it is inert -below ACMM L5, where the architect is not scheduled. Approved plans that stop -making progress are re-kicked for unfinished work only, capped at five replans -before human escalation. +The automatic issue-label entry point has three separate limits: + +- **Default off:** `planning.plan_from_label` is opt-in because it can feed + attacker-controlled issue text into the architect prompt without per-kick review. +- **Level condition:** even when enabled, it is inert below ACMM L5, where + the architect is not scheduled. L6's pack may automatically approve plans; + see [the L6 approval boundary](/docs/hive/running-at-level-6#hive-settings). +- **Retry cap:** approved plans that stop making progress are re-kicked for + unfinished work only, capped at five replans before human escalation. ## Consequences diff --git a/docs/content/hive/adr/0007-token-mint.md b/docs/content/hive/adr/0007-token-mint.md index 0e5538e8..c26c1a97 100644 --- a/docs/content/hive/adr/0007-token-mint.md +++ b/docs/content/hive/adr/0007-token-mint.md @@ -9,6 +9,12 @@ the trust boundary stated plainly), see [Token mint](https://github.com/hivecomm ## Context +Hive needs cloud/registry credentials that expire and grant only named actions, +without handing every agent a shared long-lived secret. + +
+Historical token-handling fixes behind the decision + Several v4 security fixes tightened token handling, including stopping full installation-token exposure to agents, avoiding host CLI/PAT leakage, and making shared App-token caches owner-only @@ -18,8 +24,17 @@ hub`, `fix(security): H3 — shared App-token cache owner-only + fail-loud fallbacks`). Hive still needs a way to give agents cloud or registry authority without distributing shared long-lived credentials. +
+ ## Decision +The mint issues credentials that expire quickly and authorize only named +actions. A **JWT** (JSON Web Token) carries the signed claims; its **TTL** +(time to live) bounds validity. A **JWKS** (JSON Web Key Set) publishes the +public verification keys, not the signing secrets. +**Workload Identity Federation** lets another service exchange a verified +workload identity for its own scoped credentials. + Introduce the mint as an opt-in short-lived credential issuer ([mint package](https://github.com/hivecommons/hive/blob/v5/src/pkg/mint/mint.go)). It signs scoped JWTs with bounded TTLs, verification that fails closed, and a JWKS endpoint for downstream Workload diff --git a/docs/content/hive/adr/0008-ioscan-untrusted-input.md b/docs/content/hive/adr/0008-ioscan-untrusted-input.md index d29b43c6..58d218ef 100644 --- a/docs/content/hive/adr/0008-ioscan-untrusted-input.md +++ b/docs/content/hive/adr/0008-ioscan-untrusted-input.md @@ -4,6 +4,12 @@ Status: Accepted (retroactive) +**Behavioral terms:** a **kick** is an agent work prompt. A **canary** is a +secret test marker whose appearance in outgoing (**egress**) text signals a +leak. **Fail open** continues work when a check cannot complete; **fail closed** +blocks it. A **semantic classifier** is a model-based check of meaning, used +in addition to fixed matching rules. + ## Context Hive builds agent kicks from issue titles, labels, comments, and other text that @@ -15,6 +21,8 @@ with structured findings and block decisions ## Decision +### Kick-input contract + Scan untrusted kick-path text before injection and redact blocked content rather than silently dropping the item or passing the raw payload through. `EnforceInput` returns benign text byte-for-byte, but replaces blocked text with a visible @@ -28,7 +36,11 @@ The v4 base also includes the fail-safe default-on mode: absent `ioscan:` configuration scans by default, while an explicit `ioscan.enabled: false` opts out ([config](https://github.com/hivecommons/hive/blob/v5/src/pkg/config/config.go)). -Operators may additionally enable `ioscan.canaries: true`. Hive then prepends a +### Canary-based output protection + +The current [ACMM packs](/docs/hive/acmm-policy-matrix#ioscan-hardening-defaults-per-level) +default canaries on at every level; an explicit `ioscan.canaries` value overrides +that default. With `ioscan.canaries: true`, Hive prepends a random `HIVE-CANARY-...` marker to each kick with instructions that the agent must never repeat it. Active canaries are kept in memory and persisted at `/data/ioscan-canaries.json`; the GitHub MITM proxy scans outgoing issue/PR/ @@ -38,10 +50,14 @@ with `ioscan.fail_mode: closed`, the proxy rejects the GitHub write with 403. Opaque git pushes cannot be inspected safely, so canary fail-closed mode blocks `git-receive-pack` pushes rather than allowing an unscannable exfiltration path. +### Publication scrubbing + Agent-derived advisory text is also scrubbed with `pkg/logscrub` before GitHub publication so GitHub tokens, AWS access keys, bearer tokens, JWTs, and PEM private-key blocks are redacted rather than echoed into comments. +### Optional semantic classifier + Hive also supports an optional semantic prompt-injection classifier under `ioscan.classifier`. It runs after deterministic redaction, scrubs canaries before any model call, caps segment size, caches verdicts by content hash, and @@ -58,5 +74,6 @@ raw injection or secret-bearing text. Visible markers make the behavior auditable and reduce confusion compared with silent omission. The trade-off is false positives: a legitimate title that matches a high-severity rule is withheld until an operator investigates or disables ioscan explicitly. Output -enforcement exists as a pure helper, but the current ADR records the kick-input -path that is wired in this base. +enforcement also exists as a pure helper. The original decision concerned +kick-input redaction; the sections above distinguish the additional wired +canary, publication-scrubbing and optional classifier protections. diff --git a/docs/content/hive/adr/0009-trajectory-review.md b/docs/content/hive/adr/0009-trajectory-review.md index 51e94e5a..10e54dcd 100644 --- a/docs/content/hive/adr/0009-trajectory-review.md +++ b/docs/content/hive/adr/0009-trajectory-review.md @@ -4,6 +4,15 @@ Status: Accepted (retroactive) +**Current behavior:** periodically review an agent's recent transcript for goal +drift; pause and alert on divergence by default. Review-service failures do not +halt agents. Only a proven-idle agent with no output since its last review may +skip an interval, and overdue reviews always run. The addendum below gives the +exact skip predicate; an unchanged transcript alone never qualifies. + +A **lane** is a recurring category of agent work. The **governor tick** is +the scheduler's periodic evaluation, which decides when this review is due. + ## Context Per-action guards can miss goal drift: a session may take individually ordinary @@ -73,6 +82,6 @@ Every decision is recorded with a reason (`first-review`, `overdue`, `active`, `/metrics` as `hive_trajectory_reviews_total{decision}`, `hive_trajectory_skipped_total{reason}` and `hive_trajectory_ran_total{reason}`. -Consequence: token cost now scales with agents that are actually working rather -than with fleet size, without weakening the invariant that a running agent is -always reviewed on cadence. +Consequence: token cost scales with agents actually working rather than fleet +size. Active agents remain reviewed on cadence; only proven-idle agents may +skip, and even they are reviewed once the overdue limit is reached. diff --git a/docs/content/hive/adr/0010-escalation-circuit-breaker.md b/docs/content/hive/adr/0010-escalation-circuit-breaker.md index 49f8f8f1..561dc74e 100644 --- a/docs/content/hive/adr/0010-escalation-circuit-breaker.md +++ b/docs/content/hive/adr/0010-escalation-circuit-breaker.md @@ -4,6 +4,17 @@ Status: Accepted (retroactive) +**Current authority:** the forge's `needs-human` label, not a local ledger +entry, determines whether a PR is escalated. The ledger tracks evidence and +retry budgets; [label authority](#treat-the-forge-label-as-authoritative) +below gives the exact reset rules. + +**Counter terms:** a **head SHA** identifies the latest commit; the **head +tree** is its file-content snapshot, so an empty commit is not a new fix. +**Settled CI** has finished checks, not pending ones. A **re-engagement** is a +delivered retry prompt. A human-authored **control PR** supplies independent +evidence when deciding whether failures are shared across the repository. + ## Context Hive agents can repair their own failing PRs, but an unbounded retry loop can @@ -14,6 +25,8 @@ failure in shard logs ([escalation package](https://github.com/hivecommons/hive/ ## Decision +### Count distinct failures + Track red PRs in a persistent ledger keyed by `repo#number`. Each sweep records distinct failing head SHAs, retains the last CI excerpt, clears history when a PR goes green, and marks escalation once the threshold is crossed. The default @@ -22,6 +35,8 @@ headed "Fix loop escalated — human attention needed", includes failing checks and raw failure evidence when available, and applies the `needs-human` label so future fix dispatch skips the PR. +### Bound retries on an unchanged head + For unchanged red heads, track staleness separately and cap re-engagements at `MaxReEngagements` (six) per current SHA. A branch that moves resets the re-engagement counter; a permanently red, never-moving branch is not nudged @@ -37,6 +52,8 @@ cadence window. The staleness clock starts when CI SETTLES — a head red on one check while others are still running is not yet stuck. The escalation comment quotes the number of kicks actually delivered. +### Exclude independently confirmed shared failures + Shared CI breakage is not a fix attempt. A check is shared only when it fails on every conclusive open PR in the repository and the evidence includes an independent human-authored control. A green PR disproves a repository-wide @@ -49,6 +66,8 @@ does not consume one. An escalation is un-parked automatically — `needs-human` removed, ledger reset, one comment saying why — when the head goes green or when the shared breakage it escalated over clears. +### Hand off after one reviewer pass + A PR escalating for the SECOND time — after the reviewer lane ([#5480]) already repaired or de-escalated it once — gets a structured hand-off note instead of the generic body. The ledger stamps the head SHA the reviewer left on the branch @@ -61,6 +80,8 @@ except the label set. [#5480]: https://github.com/hivecommons/hive/issues/5480 +### Treat the forge label as authoritative + The `needs-human` label on the forge, not the ledger, is the authoritative record that a PR has been escalated. The ledger is a cache of it: a PR that wears the label reads as escalated even to an empty ledger (so the evidence diff --git a/docs/content/hive/adr/0011-knowledge-system.md b/docs/content/hive/adr/0011-knowledge-system.md index 026145b8..85343ba9 100644 --- a/docs/content/hive/adr/0011-knowledge-system.md +++ b/docs/content/hive/adr/0011-knowledge-system.md @@ -22,6 +22,10 @@ remote layer clients behind one `KnowledgeAPI`, and prime agents by formatting a bounded set of selected facts into the kick prompt rather than letting agents query the store directly ([knowledge API](https://github.com/hivecommons/hive/blob/v5/src/pkg/knowledge/api.go)). +**Retrieval implementation.** Similar wording and explicit fact relationships +help select a small relevant set; no external embedding service is required. +The details below are for maintainers of that selection path. + Use a deterministic term-frequency embedder as the default semantic signal: text is tokenized, feature-hashed into a 256-dimensional vector, and L2-normalized, with embeddings cached only for the search/reindex pass @@ -34,8 +38,6 @@ source bead or PR ([retro lessons](https://github.com/hivecommons/hive/blob/v5/s ## Consequences -Rationale not recorded beyond the implementation, linked code, and cited design notes. - Agents can receive durable, source-backed context without depending on an LLM's conversation memory or a hosted embedding API. Layer precedence and explicit promotion preserve the privacy boundary described by the design while still diff --git a/docs/content/hive/adr/0012-skill-registry.md b/docs/content/hive/adr/0012-skill-registry.md index 1f80ae92..74adec8e 100644 --- a/docs/content/hive/adr/0012-skill-registry.md +++ b/docs/content/hive/adr/0012-skill-registry.md @@ -4,6 +4,9 @@ Status: Accepted (back-filled) +**BYO** means **bring your own** agent. A **kick** is the work prompt Hive +delivers to that agent. The API names below define a maintainer contract. + > **Operator guide:** [Skill registry](https://github.com/hivecommons/hive/blob/v5/src/docs/skills.md) covers the on-disk format > and the current wiring status. This ADR records the decision; it is not an > operator guide. diff --git a/docs/content/hive/adr/0013-cel-triggers.md b/docs/content/hive/adr/0013-cel-triggers.md index 9f4c0826..cf53b02a 100644 --- a/docs/content/hive/adr/0013-cel-triggers.md +++ b/docs/content/hive/adr/0013-cel-triggers.md @@ -4,6 +4,13 @@ Status: Accepted (back-filled) +**CEL** is the **Common Expression Language**. Operators write boolean rules +over events to select agents. A **normalized forge event** is Hive's common +representation of a repository-host event, so rules do not depend on a +GitHub-specific webhook payload. + +For configuration and examples, use the [CEL triggers operator guide](https://github.com/hivecommons/hive/blob/v5/src/docs/cel-triggers.md). + ## Context Hive's built-in label and governor triggers cover common flows, but operators diff --git a/docs/content/hive/adr/0014-hub-spoke.md b/docs/content/hive/adr/0014-hub-spoke.md index 62f411d2..e0a7d13d 100644 --- a/docs/content/hive/adr/0014-hub-spoke.md +++ b/docs/content/hive/adr/0014-hub-spoke.md @@ -15,6 +15,13 @@ for firewalled spokes. ## Decision +A **heartbeat** is a periodic status request initiated by a spoke. Its response +can carry **callbacks**: instructions for the spoke to apply, rather than a +new inbound connection from the hub. +This works through **NAT** (network address translation) because the spoke +opens the connection. “Eventually delivered” means a callback waits for a +successful heartbeat, not that an operator command takes effect immediately. + Use spoke-initiated heartbeats as the control channel. A spoke posts identity, repos, ACMM level, agents, governor state, contributors, leaderboard, health, version, image, and related status to `/api/heartbeat`; the hub persists a diff --git a/docs/content/hive/adr/0015-csp-style-src-scope.md b/docs/content/hive/adr/0015-csp-style-src-scope.md index dd0a874e..17a8e4c9 100644 --- a/docs/content/hive/adr/0015-csp-style-src-scope.md +++ b/docs/content/hive/adr/0015-csp-style-src-scope.md @@ -4,8 +4,18 @@ Status: Accepted +**Current scope:** Content Security Policy (CSP) treats style elements and style +attributes separately. This ADR accepts inline style attributes and records the +original sequencing rationale for hardening style elements. The inline-script +condition described in the original context **no longer holds**: [ADR-0016](/docs/hive/adr/0016-csp-script-src-scope) +records the completed inline-handler refactor and closed script policy on its +covered documents, with explicit emitter/document exclusions. + ## Context +**Historical context at adoption.** The measurements and sequencing argument +below explain the original choice, not today's script allowances. + The dashboard's Content-Security-Policy carried one blanket `style-src 'self' 'unsafe-inline'` ([securityHeaders](https://github.com/hivecommons/hive/blob/v5/src/pkg/dashboard/server.go)). That single token covered two different things with two different futures, and hid the fact @@ -32,7 +42,7 @@ maintainable. So for the attributes there is no policy that both permits them and constrains them: the realistic choice is `'unsafe-inline'` or deleting every inline style in the UI. -A second constraint shapes the timing. `script-src` still carries +A second constraint shaped the original timing. At adoption, `script-src` carried `'unsafe-inline'` — that is the other half of #3848 and is staged behind an event-delegation refactor (437 inline `on*=` attributes in `static/index.html`, plus ~145 more built as strings inside the page's own JavaScript and injected @@ -91,12 +101,11 @@ some engines, CSS-based inference of page content. It does **not** enable script execution. This risk is accepted for as long as the UI uses inline style attributes. -It is worth being clear that this residual is currently dominated by a larger -one: while `script-src 'unsafe-inline'` remains, HTML injection already yields -script execution, which subsumes everything the style allowance permits. The -style residual only becomes the *governing* risk once #3848's `script-src` half -lands — which is precisely why the element half is sequenced behind it rather -than in front of it. +**Historical sequencing rationale.** At adoption, the larger inline-script +allowance dominated this residual: HTML injection could yield script execution. +That justified sequencing the style-element work behind the script refactor. +The refactor has since landed as recorded in ADR-0016; do not use that historical +argument to dismiss the remaining style risk today. **Harder.** Nothing meaningfully. The extra directives lengthen the header by about 70 bytes on every response. diff --git a/docs/content/hive/adr/0016-csp-script-src-scope.md b/docs/content/hive/adr/0016-csp-script-src-scope.md index bbfc3382..6177e20c 100644 --- a/docs/content/hive/adr/0016-csp-script-src-scope.md +++ b/docs/content/hive/adr/0016-csp-script-src-scope.md @@ -4,8 +4,21 @@ Status: Accepted +**Current contract:** on the documents covered by this ADR, Content Security +Policy (CSP) allows inline script elements only by their content hashes and +blocks inline event-handler attributes (`script-src-attr 'none'`). The +event-delegation refactor is complete. Read the Decision for the exact policy +and document/proxy exclusions; the Context records the earlier open work. + +**Browser terms:** CSP2/CSP3 are policy versions. A **SPA** is a single-page +application. An **ETag** is a cache validator for a served document; a **nonce** +is a per-response random allowance. **XSS** (cross-site scripting) is attacker +script execution in the page's origin. + ## Context +**Historical context before the refactor.** + The dashboard's Content-Security-Policy carried one blanket `script-src 'self' 'unsafe-inline'`, on both CSP emitters — the Go spoke server ([securityHeaders](https://github.com/hivecommons/hive/blob/v5/src/pkg/dashboard/server.go)) and the Node proxy @@ -31,9 +44,9 @@ CSP hashes and nonces apply to *elements*, never to event-handler attributes (`script-src-attr` accepts only `'none'`, `'unsafe-inline'`, or `'unsafe-hashes'` plus per-attribute-value hashes — rejected here for the same maintainability reasons ADR-0015 rejected it for styles). So the element half -is closable today and the attribute half is not: it requires an -event-delegation refactor of the 21k-line SPA, which remains the open scope of -#3848. +was closable independently; the attribute half required an event-delegation +refactor of the then 21k-line SPA. That was the remaining scope of #3848 at +adoption, and is now completed as described below. ## Decision diff --git a/docs/content/hive/adr/0017-podman-quadlet-lifecycle.md b/docs/content/hive/adr/0017-podman-quadlet-lifecycle.md index 1274b191..b5a2a95a 100644 --- a/docs/content/hive/adr/0017-podman-quadlet-lifecycle.md +++ b/docs/content/hive/adr/0017-podman-quadlet-lifecycle.md @@ -4,6 +4,16 @@ Status: Accepted +**Takeaway for operators:** use Quadlet `.container`/`.pod` units for persistent +Podman deployments, not `podman compose` or `.kube` replay. Follow the +[Quadlet operator guide](https://github.com/hivecommons/hive/blob/v5/src/docs/podman-standalone-quadlet.md); this record preserves +the investigated alternatives, version requirements and limits of the evidence. + +**Terms:** a **spike** is a bounded technical investigation. **Quadlet** +generates systemd service units from Podman container/pod declarations. +**systemd** manages their lifecycle; **rootless** runs under an ordinary +user's service manager, while **rootful** runs under the system manager. + ## Context Standalone Hive under Podman (#4188) needs one persistent lifecycle mechanism diff --git a/docs/content/hive/adr/0018-dashboard-design-tokens.md b/docs/content/hive/adr/0018-dashboard-design-tokens.md index 6f413a79..dfa6dd71 100644 --- a/docs/content/hive/adr/0018-dashboard-design-tokens.md +++ b/docs/content/hive/adr/0018-dashboard-design-tokens.md @@ -4,6 +4,13 @@ Status: Accepted — initial tokens layer landed; migration ratchets remain. +A **design token** is a named value for a shared visual role, such as text color +or spacing. A **ratchet** is a test that prevents migrated code from adding back +the old patterns. This is a frontend-maintainer migration contract, not an +operator theming procedure. +**SPA** means single-page application; **CSP** means Content Security Policy, +the browser's resource/script restrictions. + ## Context The spoke dashboard now has three independently styled UI surfaces: diff --git a/docs/content/hive/adr/0019-escalation-over-stalling.md b/docs/content/hive/adr/0019-escalation-over-stalling.md index 612a3dc9..af1a64c4 100644 --- a/docs/content/hive/adr/0019-escalation-over-stalling.md +++ b/docs/content/hive/adr/0019-escalation-over-stalling.md @@ -4,6 +4,23 @@ Status: Accepted +## Current action boundary + +| Kind of work | Decision park | How a person answers | +|---|---|---| +| Issue | `stage/045-needs-decision` | A human with repo write/maintain/admin permission uses `/hive approve` or `/hive decision `. The command flow clears decision parking, adds `approved-direction`, and lifts `needs-human` even when a human applied it; it never clears `hold`. Label-driven repositories use their configured acceptance labels instead. | +| Pull request | `stage/085-needs-decision` | A trusted merger reviews the exact current head. On Hive-authored PRs at 085 or `stage/070-fixing`, `/hive decision ` routes the full text to the author/fixer; `/hive decision approve ` records head-bound approval. Bare `/hive approve` is acknowledged only, not a release. Other authors use GitHub reviews/manual merging. | + +These are decision signals, not universal merge holds. All other merge gates +still apply; use `hold` or GitHub branch rules when merging must stop. See +[Running at Level 6](/docs/hive/running-at-level-6#does-the-hive-reviewer-stop-a-merge) +for the enforcing review gate and trusted-human override. + +The current commands are implemented by `SweepIssueUnparkCommands` and +`tryUnparkPullRequest` in [issue command handling](https://github.com/hivecommons/hive/blob/v5/src/pkg/github/issue_unpark_command.go) +and [PR decision handling](https://github.com/hivecommons/hive/blob/v5/src/pkg/github/pr_unpark_decision.go). +The amendments below are migration history, not alternate current instructions. + ## Context Hive already has several half-present escalation mechanisms: hold labels keep @@ -24,10 +41,10 @@ per 24 hours. Hive agents escalate stalled work instead of silently parking it. Each escalation must choose one of four moves: -1. **`stage/085-needs-decision`** (originally `needs-direction`; see the - amendment below) — Use when the next step is a maintainer decision, - authority grant, risk acceptance, or product/voice choice. Park the item on - `stage/085-needs-decision` and post exactly one comment to the maintainer +1. **Decision park** (originally `needs-direction`) — Use when the next step + is a maintainer decision, authority grant, risk acceptance, or product/voice + choice. Park an **issue at `stage/045-needs-decision`**, or a **PR at + `stage/085-needs-decision`**, and post exactly one comment to the maintainer with a short question and concrete options `A`, `B`, and `C`. 2. **`needs-spec`** — Use when the issue cannot be implemented safely because the expected behavior, API contract, acceptance criteria, or compatibility @@ -48,7 +65,10 @@ ADR-0010 still governs CI fix-loop counting and `needs-human` authority. This ADR defines what the agent should do after recognizing that the item is no longer a single reactive fix. -Verified RFC case studies map as follows: +### Historical case studies + +The verified RFC cases below retain the original `needs-direction` spelling. +For action today, use the kind-specific decision park above. | Case | Escalation move | |---|---| @@ -76,6 +96,8 @@ records the missing decision or signal that made automation unsafe. ## Amendment (2026-10, [#12683](https://github.com/hivecommons/hive/issues/12683)) +**Historical intermediate state, superseded for issues by the next amendment.** + The `needs-direction` label this ADR introduced, and the `needs-decision` label the issue relay later applied, are retired. Both parked an item on a maintainer ruling with identical gates — hard-suppressed at enumeration, the @@ -93,6 +115,10 @@ identity or consent is required, not that a ruling is owed. ## Amendment (2026-10-17, owner decision: issue park is `stage/045-needs-decision`) +**Stage migration history.** The stage split remains current; the statement +below about preserving `needs-human` reflects the old command behavior. +Current explicit maintainer commands lift it as described at the top. + Issues no longer park at `stage/085-needs-decision`; that stage is PR-only. The issue-side park is `stage/045-needs-decision`, which sits between `040-covered-by-pr` and the PR stages so an issue's stage never reads as diff --git a/docs/content/hive/adr/0020-spek-continuous-convergence.md b/docs/content/hive/adr/0020-spek-continuous-convergence.md index cad3fa0d..2f10bc91 100644 --- a/docs/content/hive/adr/0020-spek-continuous-convergence.md +++ b/docs/content/hive/adr/0020-spek-continuous-convergence.md @@ -6,6 +6,12 @@ Accepted. +**Spek** is the Spektacular spec → plan → implement workflow. A **campaign** is +one tracked run; a **revision** is a linked new run that rechecks it without +overwriting its history. +A **spec lease** is the runner's ownership of the specification-stage work; +a **delta** is the new or changed task set, not the whole prior plan. + ## Context Spektacular campaigns previously ran `spec -> plan -> implement` once. That @@ -44,19 +50,20 @@ The evidence source interface is `RecheckEvidenceSource`. ### Discovery sources -The outward-looking half is opt-in under -`runs.spektacular.recheck.discovery` for typed release/activity/feed signals and -under `runs.spektacular.recheck.sources` for exact document snapshots. Typed -discovery rejects undeclared kinds and hosts outside -`variables.security.http_allowlist`, records evidence on `drift.external`, and -includes that evidence in the spec-stage prompt as context. Exact document -sources are retained as `drift.drift_source` before the revision starts its -spec lease; they require an explicit relay egress proxy and exact-host -allow-list, never follow redirects or links, and have fixed request, time, and -response-size bounds. Empty source lists perform no discovery network access. -All discovery is read-only, non-fatal, and untrusted evidence only; source -failures are recorded and never bypass human checkpoints or automatically apply -external changes. +The outward-looking half has separate opt-ins and safety boundaries: + +- **Typed signals:** `runs.spektacular.recheck.discovery` accepts typed + release/activity/feed signals. It rejects undeclared kinds and hosts outside + `variables.security.http_allowlist`, records evidence on `drift.external`, + and includes that evidence as spec-stage prompt context. +- **Exact documents:** `runs.spektacular.recheck.sources` retains snapshots as + `drift.drift_source` before the revision starts its spec lease. It requires + an explicit relay egress proxy and exact-host allow-list, never follows + redirects or links, and has fixed request, time and response-size bounds. +- **No implicit access:** empty source lists perform no discovery network access. +- **No new authority:** all discovery is read-only, non-fatal and untrusted + evidence only. Failures are recorded; discovery never bypasses human + checkpoints or automatically applies external changes. ## Consequences diff --git a/docs/content/hive/adr/0022-opt-in-earned-codex-reset-redemption.md b/docs/content/hive/adr/0022-opt-in-earned-codex-reset-redemption.md index de335353..6030cda2 100644 --- a/docs/content/hive/adr/0022-opt-in-earned-codex-reset-redemption.md +++ b/docs/content/hive/adr/0022-opt-in-earned-codex-reset-redemption.md @@ -4,6 +4,10 @@ Status: Accepted +An **earned reset** is a rate-limit reset already banked on the contributor's +account, not a credit purchase. **Idempotent** means retrying the same +redemption cannot consume another reset for that logical attempt. + ## Context [#6833](https://github.com/hivecommons/hive/issues/6833) and diff --git a/docs/content/hive/adr/0023-trusted-author-automerge.md b/docs/content/hive/adr/0023-trusted-author-automerge.md index d5c6ebde..d17e808a 100644 --- a/docs/content/hive/adr/0023-trusted-author-automerge.md +++ b/docs/content/hive/adr/0023-trusted-author-automerge.md @@ -4,6 +4,11 @@ Status: Accepted +**Terms:** Prow is repository automation; **Tide** is its merge controller. +**Same-head** means approval/check evidence matches the exact commit being +merged. **SHA pinning** checks that commit ID again before merging. +**Metadata contexts** report workflow bookkeeping, not evidence that tests ran. + ## Context Hive already has two auto-merge routes. The queued route requires a distinct @@ -15,17 +20,29 @@ own green PR in GitHub, but Hive would not do it unless a second person added ## Decision -Add an opt-in `auto_merge.trusted_authors` tier. A PR is eligible only when the -operator enabled the tier, the PR author holds the configured -`authorized_users` role (`merger` by default, or `owner`), and GitHub reports -repo write/maintain/admin permission unless the operator explicitly disables -that API check. GitHub permission errors fail closed. Fork PRs still require a -positive permission check so non-member forks never merge through this path. - -The tier reuses the self-authored sweep's merge mechanics: required CI green, -mergeable state, no hold/exempt/excluded labels, no outstanding -`CHANGES_REQUESTED` review, expected-head-SHA pinning immediately before merge, -and the same merge method selection as `hive-merge`. If the base branch's +Add an opt-in `auto_merge.trusted_authors` tier. + +**Author admission requires all of:** + +- the operator enabled the tier; +- the PR author holds the configured `authorized_users` role (`merger` by + default, or `owner`); +- GitHub reports repo write/maintain/admin permission, unless the operator + explicitly disables that API check. Permission errors fail closed. + +Fork PRs still require a positive permission check, so non-member forks never +merge through this path. + +**Merge checks remain separate from admission:** + +- required CI green and a mergeable state; +- no hold/exempt/excluded labels and no outstanding `CHANGES_REQUESTED` review; +- expected-head-SHA pinning immediately before merge; +- the same merge method selection as `hive-merge`; +- the enforcing swarm-review gate, when configured, as described in + [Running at Level 6](/docs/hive/running-at-level-6#does-the-hive-reviewer-stop-a-merge). + +If the base branch's required-check set is unknown or empty/unprotected, metadata contexts such as Prow `tide` and probot `DCO` are not treated as CI evidence or blockers; Hive still requires at least one real successful check-run on the head SHA before diff --git a/docs/content/hive/adr/0024-provider-credential-lifecycle.md b/docs/content/hive/adr/0024-provider-credential-lifecycle.md index b3eb33b4..54936d0d 100644 --- a/docs/content/hive/adr/0024-provider-credential-lifecycle.md +++ b/docs/content/hive/adr/0024-provider-credential-lifecycle.md @@ -6,6 +6,17 @@ Status: Proposed Authored by the hive project. Reviewer: @hanthor. +**Read this as a proposal, not a setup guide.** The classification vocabulary +and future pool constraints are proposed agreement. The v5 deliverable described +below is read-only provider-status reporting, not a refresh service; v5 has no +credential pool, idle warmer or refresh knob. Present-tense clauses do not +change this record's **Proposed** status. + +**Terms:** a **grant** is the provider's authorization for a consumer. +A **refresh authority** may renew access; a **pool** would select among +explicitly shared provider references; a **broker** would mediate their use. +None of these words implies that Hive can copy rotating credentials safely. + ## Context RFC [#12611](https://github.com/hivecommons/hive/issues/12611) proposes shared @@ -90,13 +101,13 @@ There is no refresh knob. ### Convergence answers (RFC #12611) -1. No existing upstream auth service exists. Each hive runs standalone first, +1. **Service ownership:** no existing upstream auth service exists. Each hive runs standalone first, and the hub aggregates. -2. Claude can only be refreshed on restart. Every other provider needs an +2. **Refresh boundary:** Claude can only be refreshed on restart. Every other provider needs an independent grant. -3. The contract is carried by the hub heartbeat's `providers[]` and by +3. **Status transport:** the contract is carried by the hub heartbeat's `providers[]` and by `/api/status`. -4. Yes. This ADR is that agreement on classification before any +4. **Classification before automation:** this ADR proposes that agreement before any backend-specific keepalive loop is added. ## Consequences diff --git a/docs/content/hive/adr/0025-central-stage-engine.md b/docs/content/hive/adr/0025-central-stage-engine.md index 00d31f08..3b4a2bc8 100644 --- a/docs/content/hive/adr/0025-central-stage-engine.md +++ b/docs/content/hive/adr/0025-central-stage-engine.md @@ -4,12 +4,34 @@ Status: Accepted -Implementation plan: [stage-engine-plan.md](https://github.com/hivecommons/hive/blob/v5/src/docs/stage-engine-plan.md). -Interfaces in this ADR are the contract parallel implementation PRs build -against; change them here first, then in code. +## Current state and reading route + +One engine derives the stage from observed issue/PR facts; one writer applies +`stage/*` labels. Unexpected transitions are recorded, not rejected. This +engine describes lifecycle state; it does not grant merge authority. +The [scope section](#scope-and-extension-points) also records the later, +scheduler-owned `stage/017-possible-existing` exception; do not infer that +the original single-writer decision removed that separate prior-art gate. + +- **Normal operation:** `governor.labels.stage.engine.mode: enforce` (default). +- **Pause engine label writes:** use `shadow`; derivation and observation + continue. It does not reactivate legacy writers, stop merges, or disable + the separate scheduler-owned prior-art gate. +- **Not a rollback option:** `off` and the legacy derivation paths were retired. + To revert code, use the deployment's normal release rollback procedure. +- **Implementers:** [Decision](#decision) and [Design](#design) contain the + contract; [Review-state fold](#review-state-fold-resolved) describes the + resolved review-state rule. + +The [implementation plan](https://github.com/hivecommons/hive/blob/v5/src/docs/stage-engine-plan.md) and Context below preserve +the rollout rationale. They are not a list of remaining operator actions. ## Context +**Original rollout context, with later implementation annotations.** The +half-centralized design and gaps below motivated the migration; do not read +the old writers as supported fallback paths. + The owner's intent: *labels applied from a central facility so that managing them via a state machine is easier.* Hive is half-way there. @@ -23,7 +45,8 @@ re-read-then-write `Enforce` that heals duplicate stage pills records transitions, regressions and history hops (`src/pkg/stagelabels/store.go:397`, `IsRegression` at `src/pkg/stagelabels/store.go:540`). The dashboard activity tracker and the -hub read that store and nothing else (`src/pkg/dashboard/stage_tracker.go:957-962`). +hub read that store and nothing else (`stageStoreOrShared`, +`src/pkg/dashboard/stage_tracker_caption.go:951-956`). **What is not central — three gaps.** @@ -102,7 +125,7 @@ is computed from `Detail.Verdict`, `HumanApprover`/`HumanApprovalHead`, terminal, origin, review); `IssueFacts` / `PRFacts` carry the rest. `DeriveIssue` and `DerivePR` are two `Deriver` implementations behind one interface — not one function. -5. **Behaviour first, semantics later.** The automerge lane precedence is +5. **Rollout invariant: behaviour first, semantics later.** The automerge lane precedence is merge-critical. Golden fixtures are captured from the *current* derivation before any code moves; the new derivers must reproduce them byte-for-byte under `mode: shadow` (compute, diff, log, no writes) with a 0 % mismatch @@ -429,7 +452,7 @@ Leaving 017 for 010 or closed is never a regression. | Rate-limit cost of re-reads | Writer re-reads only when the hint implies a write (today's `Enforce` rule); facts are assembled from list payloads the sweeps already fetch; shadow mode makes zero extra calls. | | In-flight labels during migration | Enforce mode's first pass is a plain reconcile: whatever the legacy writers left is replaced by the derived stage; no label migration script is needed. Legacy spellings keep healing through `Renames`. | | Anomaly noise after a Table change | Anomalies are counted and logged once per item per from→to, never block, and the expected-pair table is regenerated from the diagram in the same PR as the Table change. | -| Rollback | `mode: off` restores the legacy derivation paths until PR-6 deletes them (two releases later); `mode: shadow` is a one-line config change. | +| Pause writes after rollout | Set `governor.labels.stage.engine.mode: shadow` to derive and observe without writes. `off` no longer restores legacy derivation; those paths were deleted. A code rollback is a separate deployment action. | ## Alternatives rejected diff --git a/docs/content/hive/adr/readme.md b/docs/content/hive/adr/readme.md index e7fa1a99..a20b147a 100644 --- a/docs/content/hive/adr/readme.md +++ b/docs/content/hive/adr/readme.md @@ -7,6 +7,21 @@ that shape the system's security model, operating model, and long-lived APIs. ADRs are intentionally short: enough context to understand the choice, the chosen direction, and consequences for future changes. +**Audience and reading route:** maintainers use these records for rationale +and implementation contracts, not installation steps. Operators should start +with [Securing your hive](/docs/hive/securing-your-hive) or +[Troubleshooting](/docs/hive/troubleshooting). Read a record's current-state note +before its historical context or amendments. **Accepted** records document a +decision, not proof that a control is enabled on your deployment; **Proposed** +records are not setup instructions. Retroactive/back-filled records explain +choices already present when recorded. + +Suggested first records: [autonomy levels](/docs/hive/adr/0003-acmm-autonomy-levels) for +permission boundaries, [network enforcement](/docs/hive/adr/0002-mitm-proxy-network-enforcement) +for the proxy, [work ledger](/docs/hive/adr/0004-beads-work-ledger) for agent coordination, +and [escalation](/docs/hive/adr/0019-escalation-over-stalling) for human decisions. The +numbered list remains the complete chronological index. + ## Process 1. Copy the template below to `NNNN-short-title.md` using the next number. @@ -38,6 +53,10 @@ What becomes easier, harder, safer, or riskier because of this decision? ## Records +All records below are **Accepted** (including retroactive/back-filled records) +unless explicitly marked **Proposed**. ADR-0015/0016 preserve historical CSP +sequencing; ADR-0019/0025 give their current action/mode contract first. + - [ADR-0001: Record architecture decisions](/docs/hive/adr/0001-record-architecture-decisions) - [ADR-0002: MITM proxy network enforcement](/docs/hive/adr/0002-mitm-proxy-network-enforcement) - [ADR-0003: ACMM autonomy levels](/docs/hive/adr/0003-acmm-autonomy-levels) @@ -60,6 +79,6 @@ What becomes easier, harder, safer, or riskier because of this decision? - [ADR-0020: Spek continuous convergence](/docs/hive/adr/0020-spek-continuous-convergence) - [ADR-0022: Opt-in redemption of earned Codex resets](/docs/hive/adr/0022-opt-in-earned-codex-reset-redemption) - [ADR-0023: Hive may merge PRs whose author could merge them](/docs/hive/adr/0023-trusted-author-automerge) -- [ADR-0024: Provider credential lifecycle](/docs/hive/adr/0024-provider-credential-lifecycle) +- [ADR-0024: Provider credential lifecycle](/docs/hive/adr/0024-provider-credential-lifecycle) — **Proposed**, not a credential-pool or refresh-service setup guide. - [ADR-0025: One stage engine derives and writes every `stage/*` label](/docs/hive/adr/0025-central-stage-engine) - [ADR-0026: Sandbox runtime selection](https://github.com/hivecommons/hive/blob/v5/src/docs/adr/0026-sandbox-runtime-selection.md) (Proposed) diff --git a/docs/content/hive/agent-configuration.md b/docs/content/hive/agent-configuration.md index e4c061fd..bd1cc672 100644 --- a/docs/content/hive/agent-configuration.md +++ b/docs/content/hive/agent-configuration.md @@ -2,14 +2,16 @@ # Agent Configuration -A hive **agent** is a long-running AI worker — a CLI session the hive keeps alive in tmux, kicks on a cadence with a work prompt, and watches for stalls, rate limits, and login expiry. An agent's configuration is one YAML entry under `agents:` in `hive.yaml`: it names the agent, picks the engine that powers it (a subscription CLI or a self-hosted inference endpoint), and declares how it behaves. Everything else — cadences, models, pins, ACMM level — layers on top. +A hive **agent** is an AI worker. Hive keeps its coding-tool session alive, sends it a work prompt (a **kick**) on a schedule (a **cadence**), and watches for stalls, rate limits, and expired logins. Its configuration chooses the engine, model, and allowed behavior. -Start with only a name, a method, and a model. Add the rest when the agent needs it. +Start with a name, backend (the engine's configuration ID), and model. A **pin** prevents automatic engine/model changes; **beads** are local work records; a **lane** groups matching work. **tmux** is the terminal-session manager Hive uses. **ACMM** selects a policy-level roster and human gates; configuration here does not replace the [ACMM policy](/docs/hive/acmm-policy-matrix). For labels that route or gate agent work, see [Hive Labels and Control Signals](/docs/hive/labels-and-control-signals). ## The smallest agent that works +Before trying this, you need an operator account on a running hive, an installed and authenticated backend, and repository access configured for that hive. This example uses Copilot; importing YAML does not supply a subscription or log it in. + ```yaml agents: scanner: @@ -30,39 +32,61 @@ That is a complete, valid agent. Defaults fill in the rest at load time: You almost never write a full roster by hand: applying an ACMM level (below) generates one for you, and the dashboard edits it live. +**Where to put it and how to check it:** + +- **Existing hive:** use the dashboard's agent controls or import a portable definition. Do not paste this snake_case `agents:` entry into the portable import dialog; the formats differ. Do not overwrite an existing `scanner` entry to try the example. +- **New file-based deployment:** merge the entry under `agents:` in the Hive configuration that deployment loads (`--config`/`HIVE_CONFIG`; container default `/etc/hive/hive.yaml`). Before starting it on real repositories, review its permissions and cadence; add `enabled: false` if you want to configure it before allowing startup. +- Apply file changes through that deployment's normal reload/restart process. Check the dashboard roster for the name and effective backend/model, then the agent session for successful login and the next kick. A saved entry alone does not establish a working backend. Use the dashboard to disable a trial agent afterward. + +The [ownership table](#where-configuration-lives) below explains why editing a mounted seed may not change an already-running hive. + +| Next task | Read | +| --- | --- | +| Choose what it may do | [Behavior](#behavior--what-it-may-do-and-when); permissions remain subject to the ACMM policy and hold gates | +| Change when it receives work | [Cadences and the governor](#cadences-and-the-governor); pausing a cadence is not disabling an agent | +| Change its model or engine | [Atomic backend/model changes](#changing-backend-and-model-together-use-the-atomic-endpoint); update both together to avoid an invalid pairing | +| Understand a surprising work choice | [Explain mode](#explain-mode-debugging-agent-behaviour) before changing permissions or removing gates | +| Keep a definition linked to its source | [Live-linked definitions](#live-linked-agent-definitions-definition_source); a linked refresh can replace definition-owned fields, but not operator lifecycle state | + The formal-verification quality-lane opt-in (`quality.formal`) also lives in the dashboard under Settings -> Features. In Go, `agents:` and the other runtime-owned blocks (`backends`, `providers`, `tool_approval`, `agent_sandbox`, `turn`, and the `governor.{watchdog,litellm,vllm,llm-d,bob,trajectory,kick_limits,gateways,rotation,provider_budget}` keys) are grouped under `config.AgentRuntimeConfig` / `config.AgentRuntimeGovernorConfig` in `pkg/config/agent_config.go` — the configuration surface of the Crux agent runtime ([#13536](https://github.com/hivecommons/hive/issues/13536)). The grouping does not change where anything is written in `hive.yaml`; see [Agent-runtime blocks](https://github.com/hivecommons/hive/blob/v5/src/docs/operator-reference.md#agent-runtime-blocks-configagentruntimeconfig). ## Where configuration lives -Hive's config is layered, and the layering is the point: **a file's location says who owns the setting.** +**Use the dashboard for settings you own.** Hive saves them on persistent storage (a disk volume that survives container replacement). Do not edit `/data/hive.yaml.runtime` by hand. A *seed* is starting configuration, not necessarily the file that wins at the next boot. -```text -/etc/hive/hive.yaml ← ConfigMap seed (Kubernetes) or bind mount (Docker, Podman, LXC). -│ The operator/platform layer. Re-seeded on every pod -│ boot; authoritative for acmm_level and hub.is_public. -├── /data/hive.yaml.dashboard ← Dashboard overlay on the PVC. Every save from the -│ dashboard UI lands here, secret-free, and is merged -│ over the ConfigMap seed at the next boot. Wins for -│ everything except the two ConfigMap-owned keys. -├── /data/agent-configs/ ← One .yaml per dashboard-managed agent -│ (created, imported, or generated by an ACMM pack). -│ Merged over the agents: map at load time. -├── /data/hive.yaml.runtime ← Persisted runtime config (was hive.yaml.bak). Never -│ edit. The boot-time source of truth everywhere; -│ on K8s the ConfigMap only seeds the first boot, after -│ which the entrypoint boots from this file. The legacy name is still -│ read as a fallback during the migration. -├── /data/secrets/ ← Secret VALUES written by the dashboard (writable PVC). -│ /secrets/ ← Secret VALUES from Kubernetes Secret mounts (read-only). -└── /data/policies/agents/ ← Kick templates and per-agent policy Markdown. -``` +### Boot input: first boot versus restart + +These are the container entrypoint paths; a directly launched binary uses the configuration path passed to it. A Kubernetes **ConfigMap** supplies seed text; a **PVC** supplies the persistent disk; an **init container** performs setup before Hive starts. + +| Deployment | No persisted runtime file (first boot/reprovision) | Runtime file already exists (later boot) | +| --- | --- | --- | +| Kubernetes | The init container seeds `/etc/hive/hive.yaml` from the ConfigMap. The entrypoint merges an existing `/data/hive.yaml.dashboard` over that seed, then writes `/data/hive.yaml.runtime`. | The entrypoint boots from nonempty `/data/hive.yaml.runtime` (legacy `hive.yaml.bak` fallback). It does **not** re-merge the ConfigMap seed. | +| Docker, Podman, LXC | The mounted configuration seeds `/data/hive.yaml.runtime`. | The entrypoint restores runtime configuration over the config path, or reads the runtime file directly when the mount is read-only. There is no Kubernetes dashboard-overlay boot merge. | + +During the Kubernetes **seed-plus-overlay fallback** only: + +| Setting | Winner | +| --- | --- | +| Ordinary dashboard settings | Overlay over seed | +| `acmm_level` | Overlay when present; seed is a fallback, not an unconditional platform override | +| `hub.is_public` | Seed when set; the hosting hub can also reassert publication policy by heartbeat | +| GitHub App credentials | Overlay, except a real installed App in the seed is protected against a placeholder overlay wiping it | + +For example, changing `acmm_level` in the ConfigMap of a hive with a runtime file will not apply a new pack on restart. Use the dashboard's pack controls or the hosting hub's supported controls instead. Public-hosting policy remains the hosting administrator's responsibility, not an arbitrary agent setting. -Read the tree top to bottom and you can answer "who set this?" for any value: +### Saved settings and secrets + +| Path | Purpose | +| --- | --- | +| `/data/hive.yaml.dashboard` | Dashboard changes on Kubernetes; an overlay means saved changes layered over starting configuration. | +| `/data/agent-configs/.yaml` | Dashboard-managed, imported, and pack-generated per-agent entries, merged over the agent map at load time. Use dashboard controls rather than racing file synchronization. | +| `/data/hive.yaml.runtime` | Persisted effective runtime configuration, rewritten by saves and used as a later boot input. Never hand-edit it. | +| `/data/policies/agents/` | Kick templates and per-agent policy Markdown. | + +For environment overrides, ownership diagnostics, and detailed exceptions, see [Spoke configuration layering](https://github.com/hivecommons/hive/blob/v5/src/docs/config-layering.md). In particular, `/etc/hive/config.env` and per-agent overlays can affect the final loaded values after boot input selection. -- **The platform owns the seed.** In Kubernetes, an init container re-copies the ConfigMap to `/etc/hive/hive.yaml` on every boot. The entrypoint then merges the dashboard overlay over it — but the ConfigMap stays authoritative for the hub/admin-managed keys (`acmm_level`, `hub.is_public`). -- **You (via the dashboard) own the overlay.** Every dashboard save writes `/data/hive.yaml.dashboard`, so a LiteLLM endpoint or agent tweak survives pod restarts and upgrades. - **Secrets never enter YAML.** `hive.yaml` stores only env var *names* (`api_key_env`) and key file *paths* (`api_key_file`, `governor.backup.key_file`) — never key values. Values live in `/data/secrets/` (dashboard-entered) or `/secrets/` (Kubernetes Secret mounts). Because `Config.Save()` writes the whole config back to disk, a key value in YAML would be persisted in plaintext — so the code refuses the pattern entirely. ## Anatomy of an agent @@ -726,7 +750,7 @@ governor: - **Per-agent, per-mode intervals.** Anything Go's duration parser accepts works (`5m`, `2h`) for interval mode. - **Pausing.** The value `pause` (or `paused`) suspends an agent for that mode without disabling it. - **On-demand agents** (`on_demand: true`) are skipped by the governor timer entirely — they run only when explicitly triggered (the inception workflow drives `brainstorm` this way). -- **Continuous agents** are configured per governor mode by setting that mode's cadence value to the literal `continuous` (case-insensitive), for example `agents.scanner.cadence.surge: continuous` with `busy: 1h`, `quiet: 6h`, and `idle: off`. No agent name (including `scanner`) has special behavior. The legacy `continuous: true` bool remains a shorthand for continuous in every non-QUIET mode, but new configs should prefer per-mode cadence values. They still need an active cadence entry in the current mode, but cadence no longer decides the next kick while continuous mode is on. Instead, the manager waits until the kicked CLI is genuinely back at its input prompt, records that turn end, and the governor schedules the next kick at `ended_at + continuous_cooldown` (default `60s`). The run loop wakes on that time directly (bounded to one early eval per 30s; if the eval cycle then skips the agent for a reason the governor does not track — dashboard pause, first-scan deferral, provider-budget gate, upgrade drain — the wake backs off that re-kick 1m, 2m, … up to 15m until the schedule changes), so the re-kick lands when the cooldown elapses rather than at the next `eval_interval_s` / `eval_interval_webhook_s` tick — on a webhook-healthy spoke that tick is 15 minutes apart, which used to leave a continuous reviewer idle at its prompt for most of each cycle. `/api/status` reports `lastKickEnd` and, while the agent waits for its re-kick, `idleSince`. Enabling continuous on an idle agent, including by entering a mode whose cadence is `continuous`, schedules its first continuous kick after one cooldown; leaving a non-continuous mode clears any pending continuous kick and `/api/status` reports `continuousBlocked: "not_in_mode"` for agents that are continuous only in other modes. Continuous never interrupts a busy turn and still respects `enabled: false`, operator/fleet-breaker pause, governor-mode `pause`/`off` (including QUIET-mode pauses), on-demand, non-kick channels, budget/provider holds, provider rate-limit/quota backoff, and upgrade/restart holds; failed deliveries such as "CLI did not reach input prompt" use capped exponential backoff. The turn-end signal is a pane heuristic, and a missed one used to leave a continuous agent idle at its prompt with no further kicks until the pod restarted (the only re-arm path was the recorded turn end, and every other recovery is keyed off kick attempts). `continuous_turn_ceiling` (default `45m`, `-1` disables) bounds that: when the most recent kick has reported no outcome for that long, the governor logs a warning, records a `presumed-ended` outcome, counts it in `/api/status` `presumedTurnEnds`, and re-arms the next kick after the normal cooldown. Re-arming only schedules an attempt — delivery still refuses to type into a Working pane — so a genuinely long turn is not interrupted. `continuous_budget_pct` (default `80`) stops only the continuous re-kick loop when the current token-budget window reaches that percentage of `governor.budget.total_tokens`; normal cadence resumes, and `/api/status` reports `continuousBlocked: "budget"` plus per-agent `continuousModes`, `continuousKicks`, and `continuousTokens` counters. The dashboard exposes per-mode `Continuous` in the agent settings **Cadences** form; the Governor cadence table is read-only and shows an `∞ continuous` chip in each continuous mode cell. +- **Continuous agents** take another work prompt after their current turn finishes and a cooldown expires. Configure this per mode in the dashboard's **Cadences** form; see the settings and diagnostics below. - **Budget.** When the weekly token budget is exhausted, kicks are suppressed hive-wide (exempt agents excepted) until the period rolls over. Set `stale_timeout` with your cadences in mind: an agent kicked every 4h with a 30-minute stale timeout will look dead between kicks. The shipped packs use "longest cadence × 2". @@ -737,6 +761,31 @@ source-control event (issue opened, PR opened, a label applied, a comment posted), independent of the governor's queue-depth cadence. See [CEL-based agent triggers](https://github.com/hivecommons/hive/blob/v5/src/docs/cel-triggers.md). +### Continuous scheduling: configure and verify + +Set the mode's cadence to `continuous` (case-insensitive), for example `agents.scanner.cadence.surge: continuous`, with `busy: 1h`, `quiet: 6h`, and `idle: off`. No name, including `scanner`, receives special behavior. The legacy `continuous: true` shorthand enables continuous scheduling in every non-QUIET mode; prefer per-mode values for new configuration. An active cadence entry is still required in the current mode. + +The manager waits for the CLI to return to its input prompt, records the turn end, and schedules the next kick at `ended_at + continuous_cooldown` (default `60s`). Enabling continuous on an idle agent, including by entering a continuous mode, schedules the first kick after one cooldown. When a non-continuous mode is selected, pending continuous work is cleared; an agent configured continuous only in other modes reports `continuousBlocked: "not_in_mode"`. + +**Check it:** agent settings expose per-mode **Continuous**. The read-only Governor cadence table shows `∞ continuous`. `/api/status` reports `lastKickEnd`, `idleSince` while waiting, and the per-agent `continuousModes`, `continuousKicks`, and `continuousTokens` counters. + +**The same safety gates still apply.** Continuous never interrupts a busy turn and respects `enabled: false`, operator/fleet-breaker pause, mode `pause`/`off` (including QUIET pauses), on-demand, non-kick channels, token/provider holds, rate-limit/quota backoff, and upgrade/restart holds. Failed deliveries, such as “CLI did not reach input prompt,” use capped exponential backoff. + +| Setting | Default | Operational effect | +| --- | --- | --- | +| `continuous_cooldown` | `60s` | Wait after a completed turn before trying another kick. | +| `continuous_turn_ceiling` | `45m`; `-1` disables | If the most recent kick has no reported outcome by this time, warn, record `presumed-ended`, increment `presumedTurnEnds`, and re-arm after the cooldown. Delivery still refuses to type into a Working pane, so this is not permission to interrupt a long turn. | +| `continuous_budget_pct` | `80` | At this percentage of `governor.budget.total_tokens`, stop only the continuous loop and resume normal cadence. Status reports `continuousBlocked: "budget"`. | + +
+Scheduler timing and recovery reference + +The run loop wakes at the cooldown time, bounded to one early evaluation per 30 seconds, rather than waiting for `eval_interval_s` / `eval_interval_webhook_s`. If evaluation skips the agent for a gate the governor does not track (dashboard pause, first-scan deferral, provider-budget gate, upgrade drain), that wake backs off 1m, 2m, … up to 15m until the schedule changes. + +This avoids leaving a continuous reviewer idle until the next webhook-healthy spoke evaluation, which may be 15 minutes away. Turn-end detection is a terminal-pane heuristic. Missing that signal previously left an idle continuous agent with no further kicks until restart; the turn ceiling now bounds that failure. Re-arming schedules an attempt, not a bypass of delivery checks. + +
+ ### Repo-scoped cadences (`cadence_scope`) By default the governor runs ONE mode for the whole hive: total queue pressure @@ -1112,7 +1161,7 @@ is in [acmm-policy-matrix.md](/docs/hive/acmm-policy-matrix#what-hive-will-say-o | `pause` in a mode | an agent is noisy exactly when the queue is deep (e.g. pause `architect` during surge) | | `stale_timeout` | you changed cadences — keep it above the longest interval | | `clear_on_kick: false` | the agent genuinely benefits from remembering previous kicks (rare; context bloat is real) | -| `channels` | governor timer kicks aren't enough — you want webhook-, schedule-, or bead-triggered work | +| `channels` | Make the default timer trigger explicit; `kick` is the only supported type. For event-based work use [CEL triggers](https://github.com/hivecommons/hive/blob/v5/src/docs/cel-triggers.md) or [work sources](/docs/hive/work-sources), not `webhook`, `schedule`, or `bead` channel types. | | `tools` rules | one agent needs a sharper permission edge than its `mode` tier provides | | a higher ACMM level | your review capacity, CI trust, and appetite for autonomy have all grown — raise the level and let the pack reconcile the roster | | an inference method | you have GPUs (or a LiteLLM gateway) and want agents off subscription seats | diff --git a/docs/content/hive/architecture.md b/docs/content/hive/architecture.md index 10fd53bc..e9b3dd77 100644 --- a/docs/content/hive/architecture.md +++ b/docs/content/hive/architecture.md @@ -2,6 +2,13 @@ # Hive Reference Architecture +**Developer reference, not an installation prerequisite.** Start with the +[introduction](/docs/hive/readme) or [first-session guide](/docs/hive/getting-started). +For a concrete example, skip to [an issue becoming a merged PR](#11-end-to-end-an-issue-becomes-a-merged-pr): +Hive checks a reported problem, assigns an agent, and applies the configured +review and merge gates. That example describes a permitted workflow, not what +every ACMM level allows. + Hive is AI-agent orchestration for open-source projects. A single Go binary enumerates GitHub issues and PRs, classifies them, and dispatches work to AI coding agents (Claude, Copilot, Codex, Antigravity, Goose) on adaptive cadences governed by @@ -13,6 +20,19 @@ merge-gating, permission enforcement) from **judgment calls** (reading code, reasoning about a fix, writing a PR). Deterministic work runs in Go and shell before any LLM sees the task; agents only handle the judgment. +### Reading the diagrams + +- **PR:** pull request; **CI:** automated build/test checks; **LLM:** language model. +- **K8s:** Kubernetes; **UID:** operating-system user ID. +- **MITM:** the checking proxy between agents and remote services; **CA:** certificate authority used to trust its certificates. +- **SSE:** server-sent events, the dashboard's live event stream. + +The word **mode** names three independent settings here: governor **load modes** +(`SURGE`, `BUSY`, `QUIET`, `IDLE`) select scheduling cadences; per-agent +**permission modes** select allowed actions; `HIVE_MODE` selects the process's +deployment role (for example hub or contributor). Changing one is not changing +the other two. + > Goal decomposition, plan review, and stall-triggered re-planning are **not** > covered on this page — they are the planning-intelligence lane. Plan review and > the stall-replan lane run automatically (replan is on by default); decomposition @@ -186,6 +206,12 @@ flowchart LR ## Archetypes for long-running work +
+Optional advanced branch: long-running stages, receipts, and convergence contracts + +The numbered walkthrough continues at [Layered guardrails](#5-layered-guardrails-defense-in-depth). +This branch is for implementers of stage-based work, not first-time operators. + Long-running runs use the settled archetype vocabulary recorded in [#7620](https://github.com/hivecommons/hive/issues/7620) and implemented through the #8290 runs work. The names describe roles in the existing architecture, not @@ -222,6 +248,8 @@ it is wired. | Plan | `pkg/worksource` exposes the same run key with `Stage=plan`. | Planner emits a revisioned plan, allowed scope, effects, and assumptions. | Proof receipts and outcome observations bind the plan revision and approved scope. | Mutation executor journals any approved issue/comment/metadata effects. | | Implement | `pkg/worksource` exposes `Stage=implement` for the lease generation. | Agent or external runner performs an implementation or report-only campaign. | Gate evaluates proof and outcome evidence before publication or stage completion. | Mutation executor applies authorized effects; a report-only audit campaign may exercise the path without opening a PR. | +
+ --- ## 5. Layered guardrails (defense in depth) @@ -284,9 +312,12 @@ removed so the dependency surface only shrinks. ## 6. ACMM — controlling agent autonomy -The **AI Codebase Maturity Model** is the single dial an operator turns. -The level maps deterministically to per-agent modes via `DefaultAgentMode`, which -in turn sets the guardrails in §5. Raising the level is always a human decision. +The **AI Codebase Maturity Model** connects a codebase's tests, coverage, +review practice, and security safeguards to agent autonomy. It is not a +mandatory progression or a rule that every work item must become a PR. +`DefaultAgentMode` supplies defaults; ACMM packs set explicit per-agent modes, +and narrower repository policy still applies. These modes set the guardrails +in §5. Raising the level is always a human decision. ```mermaid flowchart LR @@ -294,7 +325,7 @@ flowchart LR L2["L2 Advisory
observe + report"] L3["L3 Quality-Gated
quality opens PRs"] L4["L4 Security-Aware
more agents file/PR"] - L5["L5 Semi-Autonomous
all PRs, hold gated"] + L5["L5 Semi-Autonomous
delivery PRs, hold gated"] L6["L6 Autonomous
auto-merge switches on"] L1 --> L2 --> L3 --> L4 --> L5 --> L6 ``` @@ -302,13 +333,17 @@ flowchart LR | Level | Name | Effect on agents | |-------|------|------------------| | L1 | Inception (Assisted) | Advisory beads + project inception only | -| L2 | Advisory (Instructed) | Observe and report findings as beads; no GitHub writes | +| L2 | Advisory (Instructed) | Workers observe and report beads; reviewer can post COMMENT-only reviews. No new issues, PRs, approvals, or merges | | L3 | Quality-Gated (Measured) | `quality` opens PRs gated by literal `hold` about testing gaps, coverage, and CI health; others advisory. This measurement foundation is what earns automation at higher levels | -| L4 | Security-Aware (Adaptive) | All agents file issues; quality, ci-maintainer, and sec-check can open PRs gated by literal `hold` | -| L5 | Semi-Autonomous (Semi-Automated) | All agents open PRs — every PR carries literal `hold` for human review | -| L6 | Autonomous | Agents open PRs and **auto-merge on green CI**; switching to L6 enables auto-merge for every active repo, owners may toggle repos afterward, no level hold, except cross-repo outreach PRs (target repo not managed by this hive) remain held | - -`supervisor` is always advisory. The full matrix is in +| L4 | Security-Aware (Adaptive) | Scanner and guide file issues; quality, ci-maintainer, and sec-check can open PRs gated by literal `hold`. Supervisor and brainstorm stay advisory; reviewer comments | +| L5 | Semi-Autonomous (Semi-Automated) | Delivery lanes propose issues and held PRs for human review; specialist lanes retain their narrower rights | +| L6 | Autonomous | Scanner gets merge capability; most delivery agents still propose PRs. Hive's separate auto-merge path can merge eligible PRs after checks/gates pass. Switching to L6 enables auto-merge for active repos, owners may toggle afterward, and cross-repo outreach remains held | + +`supervisor` and `brainstorm` stay advisory. Reviewer never merges; +adjudicator never merges; dedupe remains recommendation-only. Telemetry and +operations are paused opt-ins at L5/L6 and never merge their own PRs. +Existing level holds are not automatically removed by a level change. +The full matrix is in [`acmm-policy-matrix.md`](/docs/hive/acmm-policy-matrix). --- diff --git a/docs/content/hive/backup-dr.md b/docs/content/hive/backup-dr.md index abd34ae4..b979378f 100644 --- a/docs/content/hive/backup-dr.md +++ b/docs/content/hive/backup-dr.md @@ -4,6 +4,30 @@ Hive has two backup paths with different scopes: nightly encrypted hub disaster-recovery archives, and on-demand per-spoke backups an owner can download from the dashboard. +## Choose your recovery task + +| What you need | Access required | Route | +|---|---|---| +| Download a backup of one hive | Dashboard owner | [Owner-triggered spoke backup](#owner-triggered-spoke-backup) | +| Restore that spoke archive | Administrator with shell access to the target data volume | [Spoke restore](#restoring-a-spoke-backup-archive) | +| Restore as a hosted owner with no shell | Hub/deployment administrator must perform it | [No-shell limitation](#still-manual-the-fully-hosted-no-shell-case); **there is no upload/restore endpoint** | +| Back up or rebuild the hub/fleet | Hub/cluster administrator, object-storage access and escrowed key | [Hub backup](#hub-disaster-recovery-hive-backup), [hub restore](#restore), [CronJob](#kubernetes-cronjob) | +| Back up/restore a standalone host volume | Host runtime administrator | [Docker Compose](#docker-compose) or [Podman Quadlet](#podman-quadlet); commands are not interchangeable | +| Move hosts or change runtime | Source and destination deployment administrators | Migration guides below; [same-host Docker → Podman](#docker--podman-migration) is a specific reference case | +| Inspect configuration only | Dashboard owner | [Config export](#config-export-is-not-a-backup), not data recovery | + +**Before any restore:** have the **source archive's escrowed key**, stop writes +to the target, and identify the correct target volume. Keep the source and a +backup of any destination data until identity, keys, ledger and config are +verified. `restore` prepares files; restarting and validating the deployment +remain separate actions. Do not paste private keys or their contents into logs. + +**Terms:** DR = disaster recovery; **escrow** means keeping the decryption key +somewhere safe outside the cluster being backed up; **PVC** = Kubernetes +persistent volume claim. **UID mapping** translates container user IDs to host +IDs. **SELinux** is a host access-control system whose file labels affect +container access; a correct Unix owner alone may not be enough. + > **See also:** [Hub disaster recovery](https://github.com/hivecommons/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md) — the full hub-level runbook (key escrow, spoke fleet recovery, Slack blast, rebuild from zero) that the `hive-backup` archives described here feed into. For moving a live hive to a **different** host or cluster (as opposed to backing it up in place), see [Moving a Hive between hosts, same runtime](https://github.com/hivecommons/hive/blob/v5/src/docs/move-host.md), [Self-hosted Kubernetes cluster move](https://github.com/hivecommons/hive/blob/v5/src/docs/move-kubernetes.md) and [Hub-registered hive cutover](https://github.com/hivecommons/hive/blob/v5/src/docs/move-hub-registered-cutover.md); [Cross-runtime moves](https://github.com/hivecommons/hive/blob/v5/src/docs/move-cross-runtime.md) covers Podman ↔ Docker cross-host and Compose/Quadlet ↔ Kubernetes, using the same-host Docker → Podman migration below as its reference case. ## Config export is not a backup @@ -65,6 +89,9 @@ Environment: ## Restore +**Hub archives only — access: hub/cluster administrator.** For a downloaded +single-spoke archive, use [spoke restore](#restoring-a-spoke-backup-archive). + `hive-backup verify -file ` checks integrity: the GCM auth tag rejects a wrong key or any bit-flip. `hive-backup extract -file -dest ./restore` decrypts into a directory and verifies hashes. Neither mutates a live cluster. A restore operator should inspect the extracted `MANIFEST.json`, re-apply the captured Secret JSON to the new hub namespace, copy `hub/` files back to the hub PVC, and recreate or patch spokes from `spokes//`. Any `spoke_errors` in the manifest are honest gaps: those spokes were not captured and need separate recovery. @@ -112,9 +139,23 @@ Resolution order at backup time is governor config first, then the environment: ## Restoring a spoke backup archive +**Access: shell on the target deployment/data volume.** Hosted dashboard owners +can download archives but cannot upload/restore them. Ask the hub administrator +to carry out this procedure; see the [no-shell limitation](#still-manual-the-fully-hosted-no-shell-case). + > **Status: the decrypt/extract step and the `hive-backup restore` command below are OBSERVED — executed while writing this section, command output included. Loading the restored `/data` into a real container and rebooting it is DOCUMENTED, NOT EXECUTED — no container runtime was available to prove that half.** -This answers epic [#6521](https://github.com/hivecommons/hive/issues/6521) item #16, [#6527](https://github.com/hivecommons/hive/issues/6527) and [#6529](https://github.com/hivecommons/hive/issues/6529): **restoring a `pkg/spokebackup` archive into a fresh deployment is a single command.** `pkg/spokebackup` deliberately reuses `pkg/hubbackup`'s builder (`src/pkg/hubbackup/builder_export.go:1-22`, "so `Verify` and `Extract` accept both archive kinds unchanged") — it produces the same AES-256-GCM-sealed, SHA-256-manifested tar.gz that `hive-backup` already knows how to decrypt. +`hive-backup restore` decrypts a spoke archive and places its files in the +target data directory. That **file-placement step** is one command, not a +one-command live-service recovery. + +**Safe sequence:** stop the target Hive process, mount the intended data +volume, supply the source archive's `HIVE_BACKUP_KEY`, run `-dry-run`, inspect +the identity result, then restore. Restart and verify before retiring source +data. If a target has another hive's ID, stop and resolve the mismatch: +`-force` bypasses the guard and can splice one hive's keys/config onto another. +The [placement limits](#placing-the-files-hive-backup-restore--executed) +below also explain bead merging, file modes and boot-time ownership. There are two verbs, and the difference matters: @@ -125,6 +166,15 @@ There are two verbs, and the difference matters: | Identity guard | none | refuses a destination that belongs to a different hive | | Use it for | inspecting an archive; a **hub** disaster-recovery archive, whose Secret/PVC reassembly is manual | putting a **spoke** archive back on a deployment | +
+Archive layout, implementation evidence and recorded extraction trial + +The spoke builder reuses the hub archive format: AES-256-GCM encryption and +a SHA-256 manifest (`src/pkg/hubbackup/builder_export.go:1-22`). +History: [#6521](https://github.com/hivecommons/hive/issues/6521) item #16, +[#6527](https://github.com/hivecommons/hive/issues/6527) and +[#6529](https://github.com/hivecommons/hive/issues/6529). + ### What the archive contains, and where each path goes on restore The archive uses `spoke/` and `beads/` prefixes (`src/pkg/spokebackup/backup.go:111-116`), plus `bead-synth-wiki/` when synthesized facts exist: @@ -166,7 +216,9 @@ $ cat restored/beads/agentA/bead-0001.json {"agent":"agentA","bead":1} ``` -`hive-id`, the GitHub App key (byte-for-byte, confirmed by SHA-256), and the bead ledger all round-tripped unchanged. `hive-state.json` also round-tripped here only because nothing was running to rewrite it — on a live restore expect it to be overwritten at the next boot, the same caveat the Podman restore section above notes for the same file. +`hive-id`, the GitHub App key (byte-for-byte, confirmed by SHA-256), and the bead ledger all round-tripped unchanged. `hive-state.json` also round-tripped here only because nothing was running to rewrite it — on a live restore expect it to be overwritten at the next boot, as described in [Podman volume restore](#podman-volume-restore). + +
### Placing the files: `hive-backup restore` — executed @@ -181,6 +233,9 @@ hive-backup restore -file hive-spoke-backup--.tar.gz.enc -dest /data -dr hive-backup restore -file hive-spoke-backup--.tar.gz.enc -dest /data ``` +
+Recorded synthetic restore trial (file placement, not a live-service boot) + Executed here against a real archive built by `spokebackup.Build` from a synthetic `/data`-shaped directory (`hive-id`, a `gh-app-key.pem`, both config files, `hive-state.json`, and two agents' bead ledgers): ```text @@ -212,6 +267,8 @@ $ sha256sum src-data/gh-app-key.pem target-fresh/gh-app-key.pem 997d7dab9ff6688a2f76e08fb77996becd53621bdfa1d21d0a453ee1d87bc779 target-fresh/gh-app-key.pem ``` +
+ Points worth knowing before you run it: 1. **Supplying the encryption key.** The key is never in the archive by design (`src/pkg/spokebackup/backup.go`, "Encryption" doc comment: "the archive must be encrypted... The key is deliberately NOT embedded in, or derivable from, the archive"). `restore` resolves it exactly as `extract` does — `hubbackup.LoadKey`, i.e. `HIVE_BACKUP_KEY` in the environment the `hive-backup` binary runs in. **The escrowed key from the source hive is required — the target's own key setting, if any, is irrelevant to decrypting a foreign archive.** If the key was rotated after the archive was taken, the *old* key is what decrypts it (see "Escrow the key" above). @@ -235,12 +292,13 @@ Points worth knowing before you run it: 1 ``` -3. **Where "the target `/data`" is.** On Kubernetes it is the spoke's PVC — run `restore` from an init container or a temporary debug pod mounting the same PVC before the hive Deployment's pod starts (or into a scaled-down Deployment's pod). On Compose/Quadlet it is the `hive-data` volume — use the same container-mediated pattern as the [host-level backup pattern](#host-level-backup-pattern) / [Podman restore](#restore) sections above. The `hive-backup` binary ships inside the hive image (`src/Dockerfile`), so a debug pod or `podman exec` on the hive image already has it. +3. **Where "the target `/data`" is.** On Kubernetes it is the spoke's PVC — run `restore` from an init container or a debug pod mounting the same PVC while the Hive Deployment is scaled down, before restarting it. On Compose/Quadlet it is the data volume — use the container-mediated pattern in [host-level backup](#host-level-backup-pattern) or [Podman volume restore](#podman-volume-restore) below. The `hive-backup` binary ships inside the Hive image (`src/Dockerfile`). 4. **A restore merges into the bead ledger rather than replacing it.** An agent present at the destination but absent from the archive keeps its beads; an agent in both gets the archive's copy. If you want a clean slate, empty `/beads` first. 5. **Modes, and what `restore` does not do.** Every restored root file — the config pair, `hive-id`, `hive-state.json` and the GitHub App keys — is written `0600`, so a hand-built archive cannot widen a credential to world-readable. Ownership is *not* set: the entrypoint re-applies `0600` to the config files (`entrypoint.sh:437-450`, `hive_harden_runtime_config`) and re-chowns `beads/` to each agent's runtime UID (`entrypoint.sh:1847-1853`) on every boot, so a restore run from a host shell does not need to reproduce container-internal UIDs. -6. **(Re)start the container**, then **verify** the same way the Podman section above does: `hive-id` and the GitHub App key SHA-256 must match the source hive; the bead ledger and dashboard config overlay must be present. +6. **(Re)start the container**, then **verify** as in [Podman volume restore](#podman-volume-restore): `hive-id` and the GitHub App key SHA-256 must match the source hive; the bead ledger and dashboard config overlay must be present. -`hive-state.json` round-trips, but on a live restore expect it to be overwritten at the next boot — the same caveat the Podman restore section above notes for the same file. +`hive-state.json` round-trips, but on a live restore expect it to be overwritten +at the next boot — also noted in [Podman volume restore](#podman-volume-restore). ### Still manual: the fully hosted, no-shell case @@ -436,6 +494,8 @@ systemctl --user stop hive-data-volume.service # not destructive podman volume rm hive-data # DESTRUCTIVE -- this is the down -v step ``` + + ### Restore **Recreate the volume through its unit, not with `podman volume create`.** Both give you an empty `hive-data`; only one of them is Hive's. Observed: @@ -556,6 +616,9 @@ Also copy the Docker deployment's `src/hive.yaml` to `%E/hive/hive.yaml` and `sr ## Podman: what was observed +This is supporting evidence, not another restore procedure. Follow +[Podman volume restore](#podman-volume-restore) for the action sequence. + Fedora 44, Podman 5.8.4, systemd 259, cgroup v2, SELinux **enforcing**, Docker 29.7.2, against the real `ghcr.io/hivecommons/hive:stable` image (`sha256:ec8e69bc…`). Three separate deployments, each with its own identity, so a restore returning the wrong data would be visible rather than plausible. ### Backup, wipe, and restore — executed in both root modes diff --git a/docs/content/hive/contributor-relay.md b/docs/content/hive/contributor-relay.md index f4c8c436..1a2eedc5 100644 --- a/docs/content/hive/contributor-relay.md +++ b/docs/content/hive/contributor-relay.md @@ -2,32 +2,22 @@ # ClankeR contributor relay -ClankeR lets a contributor lend their local AI CLI subscription to a hive. A contributor runs a small relay process on their machine; the hive assigns it real work — issues from the project's queue — and the contributor's agent executes each task locally with the CLI and model of their choice, reporting completion/PR metadata back over a WebSocket. +ClankeR lets you lend your AI coding tool to a hive. A **CLI** is a command-line program; its **backend** is the tool selected for the relay to drive. A **hive** assigns tasks from a project's work queue. The **relay** runs on your machine, receives a task, drives your chosen tool/model, and reports the result, including any **PR** (pull request), over a WebSocket connection. Your **registration token** identifies you to that hive; it is separate from your coding-provider login and the task's GitHub credential. For labels that make work eligible or ineligible for contributors, see [Hive Labels and Control Signals](/docs/hive/labels-and-control-signals). For help getting to your first PR, [Join our Discord](https://hivecommons.dev/discord). -The relay turns a hive from a fixed set of resident agents into an elastic swarm: the admin curates *what* is offered (which repos, which labels, which models are acceptable), and contributors decide *how* it gets done (their CLI, their model, their compute, their tokens). The relay connects to `/api/contribute/ws`, receives one task at a time, runs the selected CLI in the contributor's environment, and reports the result back. +The hive operator chooses eligible repositories, labels, and models. You choose the coding tool, model, and machine. Your provider credentials stay local; Hive supplies short-lived GitHub access for each assigned task. -## How it fits together - -```mermaid -sequenceDiagram - participant H as Hive
(Governor Config → Hub tab
curates the work queue) - participant R as Contributor machine
(contributor relay + your CLI/model,
tmux session) +## Pick your route - R->>H: connect wss:///api/contribute/ws
(registration token, CLI backend, model) - H-->>R: accept — or reject if the model
fails the Model Filter - H->>R: task assign (queued issue + short-lived GitHub token) - loop while task runs - R->>H: progress (every 2 min) + heartbeat (30 s) - end - R->>H: result (PR opened / success / failure) -``` +| You want to… | Read | +| --- | --- | +| Complete your first contributed task | [Basic setup](#basic-setup) → [Choosing a model](#choosing-a-model) → [Check your quota protection](#check-your-quota-protection) → [What happens on a task](#what-happens-on-a-task) | +| Configure or troubleshoot a running contributor | [Operator reference](#operator-reference), [CLI backends](#choosing-a-cli-backend), or [repository scope](#contributor-repository-scope) | +| Decide what a hive offers contributors | [Admin: configuring the queue](#admin-configuring-the-queue-governor-config--hub) and [claim behavior](#how-the-hub-picks-work-for-contributors) | +| Implement or debug a relay | [Protocol and implementation reference](#protocol-and-implementation-reference), [DECLARE](#capability-declaration-declare), and [compatibility](#protocol-compatibility) | -- The **work queue** is built from the hive's monitored repos: open candidate issues that pass every contributor admission gate (including disabled repositories, holds, cooldowns, in-flight work, dependencies, assignments, and the admin's title/author/label filters). `GET /api/contribute/status` reports that offerable total as `actionable_items`; its additive `candidate_items` field is the raw pre-admission scanner population. `GET /api/contribute/queue` returns the bounded ordered rows plus the uncapped offerable `queue_total` and separately visible `held_total`. -- The **relay** authenticates with a registration token, receives one task at a time, drives the local CLI inside a tmux session, injects a short-lived GitHub token for the PR, and reports the result. It heartbeats every 30 s and reconnects with exponential backoff; a task is abandoned if the relay observes no forward progress for 30 minutes, or if it crosses an absolute 4-hour backstop. The GitHub token is valid for 55 minutes and is re-minted by the hub before it expires, so a task may outlive any single token ([below](#the-github-token-outlives-the-task-because-the-hub-re-mints-it)). -- Every contributor has a **trust tier** with per-tier rate limits. See [Contributor trust tiers and delegated agent roles](https://github.com/hivecommons/hive/blob/v5/src/docs/contributor-trust-and-roles.md). -- Hives **advertise a few open issues** to newcomers: issues that score as small and well-specified get GitHub's `good first issue` + `help wanted` labels and a welcome comment that deep-links this page for that issue (`/contribute?issue=/%23`) with the claim → DCO-signed PR → `Fixes #n` steps. The label is not a reservation — if a hive agent starts the issue first the label comes off — so claim first. See [Hive-curated good first issues](https://github.com/hivecommons/hive/blob/v5/src/docs/good-first-issue.md). +You do not need the operator or wire-protocol sections to start one relay. In those sections, a **lease** is temporary task ownership; a **claim** reserves an issue; a **fence** rejects stale results from an old assignment; **mint** means issue a short-lived token; and **admission** means checking whether work is allowed. A runtime **incarnation** identifies one lifetime of a process. “Pane chrome” means terminal status decorations, not task output. Stage `072` means returning an existing PR to its contributor for repair, not starting a new issue. ## Basic setup @@ -38,10 +28,27 @@ requires no host GitHub or provider CLI installation. ### From source -From a checkout of this repository: +Use this route to run the relay from a **`hivecommons/hive` checkout**, not from the documentation-site repository. The `justfile` is at the Hive repository root. + +Before registering, have: + +- Git and [`just`](https://just.systems/) installed, plus GitHub CLI (`gh`) and a GitHub account you can sign in to. +- Your selected [coding backend](#choosing-a-cli-backend) and its provider authentication ready. The host preflight checks the host CLI/login; container mode runs the image's copy, so also check that the image supports that backend. +- A running Docker or Podman for the recommended container route. Native `local` mode instead needs host tools including Node and tmux and the backend-specific confinement/consent requirements below; it is not equivalent to a container. +- A hive chosen from the [Hive Hub](https://hive.hivecommons.dev). Open **that hive's `/contribute` page** for its current address and backend-specific setup instructions. + +If you do not already have a Hive checkout: + +```bash +git clone --branch v5 https://github.com/hivecommons/hive.git +cd hive +``` + +From that checkout's root, replace `hive.example.com` with the host from the chosen hive's `/contribute` page. It is only a placeholder. This example uses Claude; choose your backend before running setup: ```bash export HIVE_HUB=wss://hive.example.com/contribute +just contribute-check claude just contribute-setup claude just contribute-hive ``` @@ -50,15 +57,6 @@ just contribute-hive `contribute-setup` is one-time per hive: it registers you (your GitHub identity plus a registration token stored in `${HOME}/.config/hive/contributor.env`), authenticates `gh`, and verifies the CLI backend you chose. Every hive also serves a landing page at **`https:///contribute`** with live queue stats and copy-paste setup commands tailored to the CLI you pick. -Operators can publish a short **Help & community** link list with -`contribute.help_links` (also editable from Governor → Hub and `/contribute` -Management). The dashboard shows those links on Onboarding and Operations, and -the hub includes them in `auth_ok` so the relay prints them once when it -connects. Use it for contributor docs, Discord/Slack invites, or a maintainer -issue queue. Discord `https://discord.com/channels//` URLs only -work for people already in that server; use `https://hivecommons.dev/discord` if -new contributors need to join the Hive Commons Discord. - `contribute-hive` starts the relay in one of two modes: ```bash @@ -85,14 +83,6 @@ the corresponding cgroup controller. These overrides affect the `just contribute-hive` container only; Kubernetes keeps the resource requests and limits rendered in its generated manifest. -Run-stage work uses per-stage git worktrees instead of sharing a dirty checkout -between concurrent stages. The hub keeps a shared source clone and creates -worktrees under the workspace root as `runs//-`, -starting each from the target branch. The default live-worktree cap is eight -(`runs.max_worktrees`); a ninth concurrent run-stage kick is refused and audited -rather than reusing another stage's tree. Reclaiming or completing a stage -removes its worktree. - Use `just contribute-check ` before registering to catch missing CLIs or obvious auth gaps. ### Homebrew @@ -158,8 +148,65 @@ Start the relay from the directory you want to use as its workspace: hive-contribute ``` +## Choosing a model + +Set the model before starting the relay: + +```bash +export AGENT_MODEL=claude-sonnet-4-6 # or gpt-4o, gemini-2.5-pro, … +just contribute-hive +``` + +(`GOOSE_MODEL` is honored for goose.) The model is declared to the hive when the relay connects. If the hive's Model Filter rejects it, the relay prints the hive's accepted patterns and exits — switch models and reconnect: + +```text +This hive accepts the following models: + - claude-opus* + - claude-sonnet* +Set your model: export AGENT_MODEL= +``` + +For model detection and OMP advisor details, see [Model reporting details](#model-reporting-details). + +## Check your quota protection + +The quota guard checks your provider's remaining allowance **before accepting new work**. Its default reserve is 20%; it is not a guarantee that a task cannot exhaust a window or spend paid credits. Protection requires a usable reading for the correct provider/account. + +| Backend/source | Protection you can rely on | +| --- | --- | +| Automatic-reader candidates `claude`, `codex`, `agy`, `gemini`, `kiro` | A working publisher, installed provider CLI, matching credentials/account, and usable reading are required. This is the guard's reader set, **not** a promise that every candidate is a contributor backend (Gemini, for example, has no relay launch wiring). | +| `pi` | **No built-in compatible reader**, including `openai-codex`, `openrouter`, and `anthropic` models. Supply an explicit reading for the selected Pi provider/account; Claude/Codex credential stores are not substitutes. | +| Other backend or custom reader | Supply `HIVE_CONTRIBUTOR_QUOTA_READING_FILE` or `_JSON` as documented in [Provider adapter sources](#provider-adapter-sources). A provider adapter existing elsewhere does not mean the relay automatically reads it. | + +Read the relay's startup/hold diagnostics, not only its connected status: + +- `unprovisioned` means there is no usable route to a reading: **work is admitted without quota protection**, with a warning. +- A configured reading that is missing, malformed, `unknown`, or `stale` **holds** work. A fresh publisher marker can also make a missing automatic reading hold. +- A low reading names the window/reserve; a held relay retries automatically. An explicit contributor pause still wins when headroom returns. + +With an explicitly configured shared pool, `just contribute-quota status` inspects its scoped controls; use the **same pool/account/backend configuration** as the running relay. It is not proof of provider headroom by itself. Do not select `continue-*` or turn the guard `off` just to make setup look successful. See [shared-pool setup](#sharing-one-quota-reserve-across-those-relays), [guard policy](#the-contributor-quota-guard-holds-before-the-provider-refuses), and [publisher mechanics](#how-the-reading-reaches-the-guard-hivecommonshive6967) for reserves, consent, markers, and mixed-version rules. + +## What happens on a task + +1. A successful connection logs `Connected to …`, followed by `Authenticated with … as … (tier: …)`. Authentication is not yet a task assignment. +2. The hive assigns an issue that fits your trust tier and its filters. If it says `No task assigned … reason: no_matching_work`, the relay is connected and waiting; it retries. Other reasons may require the hive operator, not another registration. +3. The relay prepares the checkout, injects a short-lived GitHub token, and drives your coding CLI. In interactive mode, use the **attach command printed by your launch** to watch the tmux session. Container mode prints the Docker/Podman form; native mode prints `tmux attach`. Headless backends have no interactive pane. +4. Progress is reported every 2 minutes; completion/PR metadata is reported when the CLI finishes. Check the linked PR and its checks, not just a local “success” line. PRs retain the task's base branch, required hold gates, and DCO sign-off (`git commit -s`). +5. To stop your foreground relay, press **Ctrl-C** in the terminal running it; detaching from tmux is not stopping the relay. The relay cleans up its connection. If work is in flight, it is not thereby completed: inspect the PR/worktree and the hive's recorded task state before deleting local work or starting another relay. + +Completed tasks that open a PR count toward automatic trust-tier promotion and the public `/leaderboard`. Contributors receive short-lived task credentials, not long-lived repository credentials. [Task execution reference](#task-execution-reference) explains checkout, base-branch, and recovery safeguards. + +## Operator reference + +The first-task route ends above. The following sections cover custom launch settings, multiple sessions/hives, queue administration, and failure recovery; the wire protocol is separated below. + +Operators can publish a short **Help & community** list with `contribute.help_links` (Governor → Hub and `/contribute` Management). Onboarding and Operations show it, and `auth_ok` sends it for the relay to print once. Use joinable community links: Discord `https://discord.com/channels//` URLs require existing server membership; `https://hivecommons.dev/discord` lets newcomers join. + ## Docker Compose workflow +
+Direct Compose, environment variables, and launch-boundary reference + The containerized path is `src/compose-contributor.yaml` plus `src/Dockerfile.contributor`; the `just contribute-hive` recipe wraps it. From the repository root you can also run Compose directly after `just contribute-setup` has written `${HOME}/.config/hive/contributor.env`: ```bash @@ -204,7 +251,7 @@ Important environment variables: | `HIVE_SESSION` | backend name (`AGENT_BACKEND`) | Optional session label for running multiple relays under one GitHub account (see [Running multiple backends under one account](#running-multiple-backends-under-one-account)). Relays with distinct labels get independent session-scoped identities (`ContributorID#session`) on the hub, so their task leases, assignment cooldowns, failure streaks, and ownership fences do not collide. Auth, trust tier, model admission, and rate-limit accounting stay per-account. Sanitized on the hub: only `[A-Za-z0-9._-]` survive, capped at 32 bytes; a label that sanitizes to empty counts as unset. Set it to the **empty string** to opt out — the relay then declares no session and keeps the bare per-account identity (the historical single-session behavior). | | `HIVE_CONTRIBUTOR_TEAM_METADATA` | unset | Opt in to the lightweight team-structure metadata used by `/api/leaderboard/teams` and the Leaderboard tab's team leagues. When set to `1`, `true`, `yes`, or `on`, the relay sends only distro/OS family (`/etc/os-release` ID, NAME, VERSION_ID, ID_LIKE on Linux), kernel release (`uname -r`), and agent backend. It never sends hostnames, local usernames, IPs, or hardware IDs. | | `HIVE_TEAM_OS_FAMILY` / `HIVE_TEAM_OS_ID` / `HIVE_TEAM_OS_NAME` / `HIVE_TEAM_OS_VERSION_ID` / `HIVE_TEAM_OS_ID_LIKE` / `HIVE_TEAM_KERNEL_RELEASE` / `HIVE_TEAM_AGENT_BACKEND` | auto-detected when team metadata is enabled | Optional overrides for the opt-in team declaration. Use these when a container should represent the host distro, a WSL relay should declare Windows/WSL, or an operator wants to join a cultural team without exposing exact release text. | -| `HIVE_CONTRIBUTOR_QUOTA_GUARD` | `ask` | Contributor-local subscription quota guard mode. `ask` and `pause` hold new work when a normalized quota window is at or below the configured reserve; `off` is the explicit launch-time opt-out for this relay session. Headless/no-response sessions wait safely rather than spending the last quota headroom. The guard can only act when a reading source is available — either `HIVE_CONTRIBUTOR_QUOTA_READING_FILE` / `HIVE_CONTRIBUTOR_QUOTA_READING_JSON`, or, for a **supported subscription backend** (`claude`, `pi`, `codex`, `agy`, `gemini`), the reading the Go rotation probers publish — into `HIVE_CONTRIBUTOR_QUOTA_POOL_DIR` when that is set, otherwise the per-install derived pool directory, so publishing is default-on (hivecommons/hive#6967, hivecommons/hive#6987). The publisher no longer requires provider rotation to be enabled: when `governor.rotation.enabled` is false (the default), the spoke runs a publish-only prober loop that publishes readings without rotating anything, so any host running `hive` gets a publisher. A host running **only** the relay (no local `hive` process) gets its publisher from the standalone contributor launch paths instead (`hive-quota-publisher`, hivecommons/hive#10299, below); with that opted out or unavailable it stays on this guard's no-source behaviour. With none of those it has nothing to read, logs that it is not guarding anything, and admits work. | +| `HIVE_CONTRIBUTOR_QUOTA_GUARD` | `ask` | `ask` and `pause` hold new work at or below the effective reserve **when a reading source exists**. `off` is explicit session opt-out, not protection. No-source `unprovisioned` admits with a warning. See the [reader support table](#check-your-quota-protection) and [publisher mechanics](#how-the-reading-reaches-the-guard-hivecommonshive6967); Pi needs an explicit reading. | | `HIVE_CONTRIBUTOR_QUOTA_MIN_REMAINING_PCT` | `20` | Default remaining-percentage reserve for every quota window, **including kinds this build does not recognize** — an exhausted unfamiliar window holds work rather than being skipped, because providers add window kinds over time (`weekly_scoped` was one). A *healthy* unrecognized window still admits. Valid range is `0`–`100`; invalid values fail relay startup with a message naming the bad variable. The reserve reduces the chance of consuming paid/extra usage but cannot guarantee a task will finish within a provider window. | | `HIVE_CONTRIBUTOR_QUOTA_SHORT_MIN_REMAINING_PCT` | unset | Optional short-window reserve override for normalized `session`/`five_hour` quota windows; inherits `HIVE_CONTRIBUTOR_QUOTA_MIN_REMAINING_PCT` when unset. | | `HIVE_CONTRIBUTOR_QUOTA_WEEKLY_MIN_REMAINING_PCT` | unset | Optional weekly reserve override for normalized `weekly` and `weekly_scoped` quota windows; inherits `HIVE_CONTRIBUTOR_QUOTA_MIN_REMAINING_PCT` when unset. | @@ -341,6 +388,8 @@ To change hubs for direct Compose, run `hivectl hives use ` (see [Named pr Backend credentials stay local to the contributor container. For example, `AGENT_BACKEND=bob` needs `BOBSHELL_API_KEY` in the container environment, while LiteLLM-style backends need their endpoint/key variables (`HIVE_LITELLM_ENDPOINT`, `HIVE_LITELLM_API_KEY` — exported locally, never sent to the hive). +
+ ## Choosing a CLI backend The relay speaks to whatever backend you set up — pass it to `contribute-setup` and (in host mode) to `contribute-hive`: @@ -411,7 +460,7 @@ Relays that resolve to the same opaque pool key then share one guard state throu ### How the reading reaches the guard (hivecommons/hive#6967) -The guard evaluates a reading; something has to produce it. The Go rotation probers already normalize each provider's usage into windows (`kind`, `pct_remaining`, `resets_at`). The hive process publishes that normalized reading into the pool directory as `.reading.json`, written atomically (temp file + rename). A **supported** subscription backend (`claude`, `pi`, `codex`, `agy`, `gemini`) with no explicit `HIVE_CONTRIBUTOR_QUOTA_READING_FILE` / `_JSON` then reads its guard reading from that pool-keyed path automatically — the same pool key on both sides, so a relay always finds the file written for its own pool. +The guard evaluates a reading; something has to produce it. The Go rotation probers normalize provider usage into windows (`kind`, `pct_remaining`, `resets_at`). The hive process publishes readings into the pool directory as `.reading.json`, written atomically (temporary file + rename). The relay's automatic-reader set is `claude`, `codex`, `agy`, `gemini`, and `kiro`; with no explicit `HIVE_CONTRIBUTOR_QUOTA_READING_FILE` / `_JSON`, those candidates use the pool-keyed path. A reader candidate is not necessarily a launchable relay backend. **Pi is excluded**: it needs an explicit source for its actual provider/account, as described in [Provider adapter sources](#provider-adapter-sources). **Publishing is default-on for supported backends (hivecommons/hive#6987, satisfying #6967 criterion 1).** The pool directory no longer has to be hand-configured. When `HIVE_CONTRIBUTOR_QUOTA_POOL_DIR` is unset, both the Go publisher (`rotation.DefaultContributorPoolDir`) and the JS relay (`defaultContributorPoolDir`) derive the same per-install directory: `$XDG_CONFIG_HOME` (honoured explicitly first, exactly as the hivectl session cache does, because Go's `os.UserConfigDir` ignores it on darwin) or the platform user-config dir, joined with `hive/contributor-quota`. The two derivations must stay byte-for-byte identical or the publisher writes where the relay never reads — the same parity the shared pool-key vectors pin (`TestDefaultContributorPoolDir_XDGParity` on the Go side, `#6987 defaultContributorPoolDir matches Go under XDG_CONFIG_HOME` on the JS side). An explicit `HIVE_CONTRIBUTOR_QUOTA_POOL_DIR` still overrides the location. @@ -428,7 +477,7 @@ The publisher **starts and stops with the contributor**, so a stopped contributo - `HIVE_CONTRIBUTOR_QUOTA_PUBLISH` is `0`/`false`/`off`/`no`: the explicit opt-out. Anything else (including unset) publishes. - `HIVE_CONTRIBUTOR_QUOTA_GUARD=off`: nothing would read the reading, so nothing is probed. - `HIVE_CONTRIBUTOR_QUOTA_READING_FILE` or `_JSON` is set: the operator has declared where readings come from, and a second publisher would compete with it for the same pool. -- The backend is not one of the guard-supported subscription backends (`claude`, `pi`, `codex`, `agy`, `gemini`, `kiro`): it is named as unsupported at startup rather than left waiting for a reading that can never be produced. +- The backend is not one of the guard-supported automatic-reader candidates (`claude`, `codex`, `agy`, `gemini`, `kiro`): it is named as unsupported at startup rather than left waiting for a reading that can never be produced. This includes Pi. In local mode a host with neither an installed binary nor a Go toolchain keeps the previous no-publisher behaviour and prints a note pointing here; nothing about the guard's own semantics changes in that case. @@ -455,34 +504,13 @@ just contribute-quota status # show the relay's current hold and Every override is narrowly scoped and expires mechanically, so none silently becomes a standing authorization to spend: `continue-once` is consumed after exactly one admitted assignment; `continue-until-reset` and `pause-until-reset` expire the moment that exact window reports a new reset epoch; `disable-session` expires when the session process exits. An override only ever authorizes spending below *your own* configured reserve — it never bypasses an unknown/unreadable quota (that still holds), and it never enables paid credits or changes any provider billing setting. `pause` mode holds the same way but offers no override path; `off` disables the guard for the session. -## Choosing a model - -Set the model before starting the relay: - -```bash -export AGENT_MODEL=claude-sonnet-4-6 # or gpt-4o, gemini-2.5-pro, … -just contribute-hive -``` - -(`GOOSE_MODEL` is honored for goose.) The model is declared to the hive when the relay connects. If the hive's Model Filter rejects it, the relay prints the hive's accepted patterns and exits — switch models and reconnect: - -```text -This hive accepts the following models: - - claude-opus* - - claude-sonnet* -Set your model: export AGENT_MODEL= -``` +### Model reporting details When `AGENT_MODEL` is unset, the relay reports the model the CLI is actually running where the CLI records one locally — claude, copilot and bob from their session transcripts ([#4117](https://github.com/hivecommons/hive/issues/4117)), and omp from its own config and session records ([#7760](https://github.com/hivecommons/hive/issues/7760)). omp chooses its models in `~/.omp/agent/config.yml` rather than from a flag, so an omp contributor rarely sets `AGENT_MODEL` at all; the relay reads `modelRoles.default` (and the newest session's `model_change` record, so a mid-task `/model` switch is reflected on the next progress tick), splits the `:level` suffix off into the reasoning effort, and reports the primary as `provider/model`. When omp's `--advisor` is on — `advisor.enabled: true`, or an `__advisor.jsonl` sidecar beside the session — the advisor's `modelRoles.advisor` selection is reported too, as `advisor_model` / `advisor_reasoning_effort`, so a contributor whose work is done by one model and reviewed by another shows both: `openai-codex/gpt-5.6-terra (medium) + advisor anthropic/claude-opus-5 (high)` in the fleet view, the activity rail, the run rows, and the `— hive:` trailer on the PRs it opens (`… model=openai-codex/gpt-5.6-terra effort=medium advisor=anthropic/claude-opus-5 advisor_effort=high`). `AGENT_MODEL` / `AGENT_REASONING_EFFORT` still win for the primary when set; the advisor has no env var and is always what omp records. A bare omp with no advisor, or any other single-model backend, reports exactly what it did before — the advisor fields are omitted, not empty. One caveat ([#7922](https://github.com/hivecommons/hive/issues/7922)): omp writes no session until its first turn, so until then `modelRoles.default` is the only source, and it says what omp is *set* to run, not what it resolved — an omp whose stored credential for that provider has been disabled (a revoked OAuth refresh token) quietly resolves some other provider's model instead. The relay therefore checks the credential store omp runs against: when the configured provider's credential is disabled, no model is reported and the relay withholds `ready` (logging the cause omp recorded and the fix — sign in again on the host and restart) rather than advertise `claude-sonnet-5` for a container that would work tasks on a local fallback model. A mid-task `Error: No API key found for . Use /login …` in the pane is classified as blocked on a human, the same as claude's `Please run /login`. -## What happens on a task - -1. The hive assigns an issue that fits your trust tier's rate limits and passes the admin's filters. -2. The relay writes the task context, injects a short-lived GitHub token, and drives your CLI in a tmux session (attach to it to watch — or intervene). -3. Progress is reported back every 2 minutes; the result (PR opened, success/failure) is reported when the CLI finishes. -4. Completed tasks that open a PR count toward automatic tier promotion — and toward the hive's public `/leaderboard`. +## Task execution reference -Contributors never hold long-lived repo credentials: the relay receives short-lived GitHub tokens per task, and API keys for the contributor's own model provider never leave their machine. +Run-stage work uses per-stage git worktrees instead of sharing a dirty checkout between concurrent stages. The hub keeps a shared source clone and creates worktrees under the workspace root as `runs//-`, starting each from the target branch. The default live-worktree cap is eight (`runs.max_worktrees`); a ninth concurrent run-stage kick is refused and audited rather than reusing another stage's tree. Reclaiming or completing a stage removes its worktree. ### The checkout path reaches the agent as a literal, not as `$HIVE_WORKSPACE_DIR` @@ -986,22 +1014,77 @@ The generated Secret contains the registration token and `GH_TOKEN` as Kubernete Owners and read-write operators can use the Operations page's **Message** action on a contributor card (or after a run-history lookup) to send a short note to exactly that contributor ([#8461](https://github.com/hivecommons/hive/issues/8461)). The hub stores the note on the recipient's contributor profile until the contributor acknowledges it, shows it as a banner on their signed-in `/contribute` Operations/Profile pages, and pushes it to every live relay connection for that same contributor identity. The relay prints the note as "Message from the hive operator" (reverse video on a TTY unless `NO_COLOR` is set) and strips terminal control characters before output; the text is never passed to the agent CLI as input. Acknowledgement, and an optional short reply, are recorded back on the profile so operators can see whether the message was delivered and read. +## Protocol and implementation reference + +This section is for operators diagnosing admission and authors maintaining a compatible relay. It is not a second setup procedure. Practical [repository selection](#contributor-repository-scope) is above; the later [repository-scope wire reference](#contributor-repository-scope-1) describes messages and compatibility. + +## How it fits together + +```mermaid +sequenceDiagram + participant H as Hive
(Governor Config → Hub tab
curates the work queue) + participant R as Contributor machine
(contributor relay + your CLI/model,
tmux session) + + R->>H: connect wss:///api/contribute/ws
(registration token, CLI backend, model) + H-->>R: accept — or reject if the model
fails the Model Filter + H->>R: task assign (queued issue + short-lived GitHub token) + loop while task runs + R->>H: progress (every 2 min) + heartbeat (30 s) + end + R->>H: result (PR opened / success / failure) +``` + +- The **work queue** includes monitored-repository candidates that pass disabled-repository, hold, cooldown, in-flight, dependency, assignment, and title/author/label gates. `GET /api/contribute/status` reports the offerable total as `actionable_items` and the raw scanner population as `candidate_items`. `GET /api/contribute/queue` returns bounded ordered rows, uncapped `queue_total`, and separate `held_total`. +- The **relay** authenticates with its registration token and renews heartbeats every 30 s, reconnecting with exponential backoff. No forward progress for 30 minutes abandons a task; an absolute 4-hour backstop also applies. A task GitHub token lasts 55 minutes and is re-minted before expiry, so the task may outlive one token; see [token renewal](#the-github-token-outlives-the-task-because-the-hub-re-mints-it). +- A **trust tier** controls per-tier rate limits; see [trust tiers and delegated roles](https://github.com/hivecommons/hive/blob/v5/src/docs/contributor-trust-and-roles.md). +- Hives advertise small, well-specified issues with `good first issue` and `help wanted` labels and a welcome link (`/contribute?issue=/%23`). A label is not a reservation: claim before starting, sign the PR with DCO, and use `Fixes #n`. See [Hive-curated good first issues](https://github.com/hivecommons/hive/blob/v5/src/docs/good-first-issue.md). + ## How the hub picks work for contributors -Two admission behaviors are worth knowing when your relay seems idle: +A claim means Hive has evidence that an issue is already being worked on or may already be fixed. **PR-evidence claims** and **worker ownership claims** are separate ledgers, with different lifetimes. + +### Current PR-evidence behavior (v5) + +The contributor queue and resident-agent enumeration use the evidence differently. Do not treat “visible to a resident agent for verification” as “available to a contributor for another implementation.” + +| Evidence class | Contributor queue | Resident-agent enumeration | End/recovery | +| --- | --- | --- | --- | +| Open hive-authored closing PR | Withheld while the ledger reports coverage | Suppressed unless the required-check red+stale release applies | An authoritative scan removes a PR that closes unmerged; a maintainer should inspect the linked PR rather than start another fix. | +| Open external PR | Withheld while the ledger reports coverage; the live open-PR-link guard can also catch links newer than the ledger | Suppressed unless red+stale | A still-open PR refreshed by scans is **not guaranteed to release after 72h**. Resolve the linked PR or ask a maintainer what remains. | +| Open hive-authored non-closing reference (`Refs #N`) | A retained ledger record still withholds the contributor item | Kept visible with linked-PR context for verification | It is not a trusted assertion that the whole issue is finished. Closing/removing the live evidence lets authoritative reconciliation drop it. | +| Strong merged claim or verified `no_work_needed` settlement | Retained and withheld while the issue keeps being enumerated open; after 7 days the reason is `merged_claim_stale` | Merged evidence stays visible as verification context rather than a blanket suppression | Ask a maintainer to close the issue or identify remaining work. Retention is 30 days **since last seen open**, not 72h since merge. A reopen after the merge voids that merged claim. | +| Weak merged claim (reference-only or external-author evidence) | Withheld while its ledger record remains | Kept visible with context | No indefinite settled-claim carry-forward: the recent-merge scan covers 72h, and ordinary unrefreshed ledger records have a 72h TTL. This is a scan/record bound, not a promise of an exact release instant during scan failures. | + +“Strong” here means the ledger's settled predicate: a merged claim that is neither reference-only nor external-author, or a verified verdict settlement. Text alone never establishes a verified settlement. + +**Why older 72h guidance differs:** the current contributor hook is `ClaimLedger.Lookup`; it does not apply the historical weak-deferral timer. The current `FilterClaimedIssues` path also distinguishes merged evidence and weak hive references from suppressed open coverage. The legacy `weakDeferExpired` helper is not called by either dispatch path. Do not bypass these gates by assuming a timer elapsed. This is a description of the current implementation, not a new policy or behavior change. + +### Worker ownership and other admission gates + +Worker claims instead expire on their configured per-kind TTL, renew with task ownership, and release on completion, abandonment, revocation, or lease expiry. They are described below with ranking and fencing. Other gates (holds, dependencies, repository access, churn, scope, trust, and model limits) still apply after PR evidence clears. + +
+PR-claim migration history and evidence-validation details + +The notes below record the evolution of claim scanning, verified verdicts, prose parsing, and settled retention. Their earlier “72h deferral/expiry” descriptions are historical, **not the current dispatch rules**; use the table above for today's operator decision. - **Issues already claimed by an open PR — or settled by a recently-merged one — are skipped.** The hub's claim ledger records every open PR that references an issue with a closing keyword (`fixes #N`, `closes owner/repo#N`, …) — including PRs from external authors, not just hive agents ([#3792](https://github.com/hivecommons/hive/pull/3792)). Since [#6867](https://github.com/hivecommons/hive/issues/6867) the same scan also covers **recently-merged** PRs: a fix that merged *without* a closing keyword leaves its issue open, and its claim used to vanish the moment the PR left the open set, so the settled issue went straight back to contributors (and agent dispatch) whose only possible verdict was "already resolved on `main`" — measured downstream at ~34% of contributor sessions. Merged claims are graded by the same evidence tiers as open ones and suppress identically; across tiers, evidence wins, so a merged `Fixes #N` outranks an open `Refs #N`. A claimed issue is silently dropped from the contribute candidate set; if nothing else is admissible the relay receives `task_unavailable` with reason `no_matching_work` (there is no per-issue "claimed by PR #N" message). External claims — like the weaker non-closing `Refs #N` references — now DEFER the hive's own agents for a bounded 72h window, then release the issue even while the PR stays open ([#4929](https://github.com/hivecommons/hive/issues/4929)). They previously never suppressed agent work at all, which let an agent that cannot check for existing PRs re-implement an issue a live PR already covered. Nothing is frozen: the window is a bound — anchored at first observation for an open claim, and at the **merge** for a merged one, so a merged `Refs #N` still releases an epic's remainder — and a red+stale claiming PR defers nothing. - **A `no_work_needed` verdict's citation becomes a verified claim.** The merged-PR scan above only sees PRs that *reference* the issue; a fix that landed without mentioning it is invisible, and on one hosted spoke 5 of 7 tasks on a contributor ended `no_work_needed` re-discovering settlements the previous agent had already found ([#7871](https://github.com/hivecommons/hive/issues/7871)). The agent does name what settled the issue in its `verdict_reason` ("already merged via #532", "covered by merged PR #867", "already in upstream/main (e6d3de3)"), so the hub now parses that reason for `#N`, `owner/repo#N`, pull URLs and 7–40 hex SHAs (the task's own issue number excluded, at most six candidates), checks each against GitHub, and records the **first that holds up** in the same claim ledger, exactly as the scan would have: a PR merged into the task repo *before the task was dispatched* — or a commit reachable from the default branch — is a strong merged claim; an open PR in the task repo by someone else is a weak external claim — *someone else* is enforced: the hub compares the PR's author to the reporting contributor's GitHub login (case-insensitively) and drops a self-authored open PR, so the least-trusted write path cannot defer an issue by citing its own unrelated PR ([#7890](https://github.com/hivecommons/hive/issues/7890)); a merged PR is a fact whoever authored it. The text alone is never trusted: a reference the API cannot confirm (wrong repo, closed-unmerged, not on `main`, merged after dispatch, or simply fabricated) records nothing and today's cooldown applies. What the API check does *not* establish is relevance — a real but unrelated ref passes, since a settling PR by definition never referenced the issue; that residual is bounded by the claim TTL and voided by newer activity on the issue. Verdict-recovered claims carry `source: "verdict"` and survive the authoritative scan that cannot see their PR, until the ordinary 72h TTL retires them or stronger live evidence for the issue replaces them. The check runs off the contributor's read loop and requires a wired claim ledger and GitHub client; a hive without either behaves as before. - **A closing keyword written as prose counts.** The claim parser used to require GitHub's own trailer shape, `keyword #N` (optionally with a colon), so a merged PR whose body read *"Resolves architect issue #1232 (first incremental step)"* produced **no claim at all** ([#7995](https://github.com/hivecommons/hive/issues/7995)). Since that issue the closing tier accepts the same bounded run of prose the non-closing reference tier already did — at most 40 characters, no `.`, newline or `#` — so `Resolves architect issue #1232` and `Fixes the bug in #12` are closing claims. GitHub will still not auto-close on those, and hive does not pretend it will: a claim here is about whether the **work landed**, and a merged PR that says it resolves an issue is the strongest evidence the hub gets, so it suppresses rather than being released for re-verification after every merge. The prose gap must begin with a space or tab, which is what keeps a Conventional Commits type prefix (`fix:`, `fix(scope):`) from claiming the first issue number in a title. The closing tier remains single-issue, matching GitHub's one-keyword-per-number rule; only the reference tier reads lists. - **A merged fix does not expire on a clock.** A strong claim from a merged PR — or a verified `no_work_needed` verdict — used to leave the ledger 72 hours after the merge, because the settle scan looks back 72h and the ledger TTL matched it. The PR was still merged; only the clock had moved. So the issue went straight back into the offer pool, an agent re-verified "already fixed on main", and the verdict claim it left sat on the same 72h clock — one wasted task cycle every three days for as long as nobody closed the issue ([#8003](https://github.com/hivecommons/hive/issues/8003): projectbluefin/chairlift#55, fixed by #133, re-offered three times with two "please close" agent comments on it). Settled claims are now carried forward across scans for as long as the issue stays open — the 30-day retention bound counts from the last enumeration pass that listed the issue as open, not from the merge, so it only prunes claims whose issue has since closed ([#11580](https://github.com/hivecommons/hive/issues/11580)); a merged *weak* claim (a `Refs #N`, or an external author's PR) is not — it never asserted it finished the issue, and is still released with context as before. And because the hold has by then outlasted every automatic bound, after **7 days** the contribute queue stops describing it as "an open pull request already claims this issue" and withholds it under `merged_claim_stale`, whose prose is the question a maintainer has to answer: *Fixed by merged PR #133 4 days ago; the issue is still open — close it or say what remains.* + +
+ - **An issue that keeps consuming pull requests is withheld for a maintainer.** The claim ledger answers "is somebody on this right now?"; it could not answer "has this issue already cost seven pull requests?" ([#7995](https://github.com/hivecommons/hive/issues/7995)). projectbluefin/documentation#1232 — an incremental architecture issue — went three merged and four closed PRs deep and was still NEXT UP: every cycle an agent found remaining work, shipped the next slice, and the issue came back after the merge, because only a human can decide that an incremental issue is *done*. So the same two PR listings the claim scan already pages through now also feed a cumulative **churn history**: which pull requests have been observed against each issue, and how each one ended. A closed-without-merge PR still claims nothing — the issue stays released for work — it only counts. Once an issue reaches **2 merged** or **2 closed-unmerged** pull requests, the contribute queue stops offering it and withholds it with reason `issue_churn`, on the same operator-visible Withheld surface as an open-PR claim, carrying the counts and the PR numbers a maintainer needs in order to answer the question. Nothing is closed, commented on, or relabelled by the guard. It lapses on its own: records age out 14 days after a pull request was last seen (deliberately longer than the 72h settle scan, because the pattern plays out over a week or more), and a maintainer who has triaged the issue can clear the guard immediately by adding the label `hive: churn-triaged`. - **An issue somebody has *claimed* is not offered — and a clanker already on it is pulled off when a higher rank claims it.** The PR-claim ledger above only knows about work that has reached a pull request. Since [#8380](https://github.com/hivecommons/hive/issues/8380) the hub also keeps a **worker-claim ledger**: who is on an issue *right now*, ranked **human > agent > contributor > external**. A person claims from the terminal (`hivectl claim owner/repo#N`) or the API (`POST /api/claims/{owner}/{repo}/{number}`); a governor kick *lists* each issue it hands one of the hive's own agents — no GitHub comment, no claim, just a 30-minute hold that keeps your session and other agents off it while the kick is live — and the hub records the **agent** claim on the agent's first start signal on that issue (its own comment, label or claim request through `hive-open-issue`, or a `hive-open-pr` request naming it; [#10527](https://github.com/hivecommons/hive/issues/10527) — a comment that is an explicit *deferral* (see the [recognized forms](https://github.com/hivecommons/hive/blob/v5/src/docs/hive-open-issue.md#comment)) is posted but records no claim, so a parked issue is not shown in progress for two hours after its blocker lands; [#12387](https://github.com/hivecommons/hive/issues/12387)); and the relay records a **contributor** claim for your session the moment it leases you a task, releasing it when the task completes, is abandoned, is yanked or its lease expires. `selectTask` excludes every issue another holder claims exactly as it excludes leased items, and the scheduler withholds them from kicks under *In Flight*. Precedence is enforced on write: a higher rank **takes over** and the displaced holder is told to stop — for a relay session that means the hub yanks that one task (`task_revoke`, generation bumped so a late completion is fenced) and hands the session its next admissible item in the same call, leaving your other sessions alone; for an agent or an external bot it means a `🔁` comment addressed to it plus a `preempted:` label on the issue. Same rank warns unless forced; a lower rank is refused. Claims lapse on a per-kind TTL (`claims.human_ttl_s` 4h, `agent_ttl_s` 2h, `contributor_ttl_s` 30m — the relay lease length — capped by `max_ttl_s` 24h) and `claims.enabled: false` turns the whole mechanism off. Every transition is mirrored onto the issue as a comment carrying a `` marker (or `` on takeover) and a `claimed` label, so a relay that only reads GitHub can still see it was preempted. -- **Claims expire.** Ledger entries live 72 hours — refreshed while the PR stays open, or anchored at the merge for a merged claim, so a settled issue is suppressed for 72h after its fix lands and nothing is stranded forever. An **open** claiming PR that goes red on a required check and stale releases the issue back to the queue; merged claims never take that valve — a fix already on `main` cannot go red. +- **Do not use one expiry rule for all claims.** The current table distinguishes PR evidence, settled retention, and worker TTLs. The resident-agent red+stale valve applies to open PRs, never merged ones; it is not an unconditional contributor-queue override. - **A repository the App cannot mint a token for is excluded, not fatal.** Since C4 the `task_assign` token is scoped to the chosen item's repository, so GitHub's `422 There is at least one repository that does not exist or is not accessible to the parent installation` means *that repo* — renamed, deleted, or removed from the installation — and nothing about the tier or the App key. It used to fail the whole selection with `token_mint_failed`, and because selection is deterministic the same doomed item was chosen on every 30 s retry: one stale entry in the project repo list (a renamed repo) wedged a hive for every contributor while `actionable_items` sat at 19 ([#7869](https://github.com/hivecommons/hive/issues/7869)). Now the claim is rolled back, the repo is excluded from selection for `mintFailureRepoCooldown` (10 min, so the fleet is not re-discovering it every retry, but the operator's fix takes effect without a restart), and the *same* call selects again from the remaining candidates (bounded at three such skips). If nothing else is admissible the reason is `repo_unmintable` rather than `no_matching_work` or `token_mint_failed`, and the hub log names the repo with a pointer at the repo list. Non-repo mint failures (5xx, bad key, an unaccepted permission) keep the `token_mint_failed` contract and exclude nothing — they would recur for any candidate. - **An App with no installation says so.** When `github.installation_id` is `0` — the App is not installed on the hive's org, or discovery never found it — no token can be minted for any repository. The hub answers `task_unavailable` with reason `app_not_installed` and a `message` naming the org and the App install link, without calling GitHub and without excluding any repo ([#14002](https://github.com/hivecommons/hive/issues/14002)). Before this, GitHub's 404 for installation `0` was read as a repo-scope failure and contributors saw `repo_unmintable`, which points at the repo list rather than the missing installation. The relay prints the message under the reason line; the fix is the operator's (install the App on the org), never the contributor's. ## Contributor repository scope +**Wire protocol reference for relay implementers.** For choosing repositories as a contributor, use the earlier [repository-scope setup](#contributor-repository-scope); the frames below are not commands to paste into a shell. + A contributor can narrow which of a hive's repositories it is offered work from ([#12805](https://github.com/hivecommons/hive/issues/12805), part of RFC [#12570](https://github.com/hivecommons/hive/issues/12570) §4). The scope can only **narrow**: disabled repos, holds, cooldowns, claims, trust tiers, model filters, quotas and task-token scoping all still run unchanged, so eligible work is the intersection of operator admission and the contributor's scope. - **Discovery.** `GET /api/contribute/repositories` (public, unauthenticated, like `/api/contribute/status`) lists the contribution-eligible repositories — the hive's monitored repos minus `hub.disabled_repos`, with the same matching rule selection uses: @@ -1990,12 +2073,17 @@ new hubs treat an absent field as not reported rather than false. ## Priority PR-fix scheduling groundwork (#12436) -The hub accepts optional `capabilities.parallel_sessions` on `auth_response`. -It counts **all** sessions, including the primary: omitted/zero or one means +**Design history, not an availability warning.** The scheduling-primitive notes below describe the earlier #12436 groundwork. Current v5 has stage reconciliation, task delivery, relay parallel/preempt handling, and capability advertisement; use [fix-pr tasks](#fix-pr-tasks) for the shipped contract and [operator visibility](#what-the-operator-sees-operations--connected-contributor-agents) to verify delivery. A relay that does not advertise `fix_pr_interrupt_v1` still does not receive mid-task interrupts. + +
+Original groundwork contract and implementation checklist + +The groundwork accepted optional `capabilities.parallel_sessions` on `auth_response`. +That proposal counted **all** sessions, including the primary: omitted/zero or one meant single-session; three means one primary plus at most two parallel fixes. Declarations are advisory, bounded to 0–64, and do not override server-side concurrency limits or credential/acceptance gates. This field alone does **not** -opt a relay into interrupts. No `fix-pr` server capability is advertised yet. +opt a relay into interrupts. No `fix-pr` server capability was advertised at that stage; current capability negotiation is described in [fix-pr tasks](#fix-pr-tasks). `pkg/contributefix` supplies the scheduling primitive for the stage-072 adapter: @@ -2027,15 +2115,11 @@ opt a relay into interrupts. No `fix-pr` server capability is advertised yet. cover multiple PRs). Every new-work claim boundary must consult `canClaimNew`; pending, in-flight, or not-yet-resumed work prevents taking new issues. -This is groundwork, not end-to-end delivery: the queue is in memory and is not -wired into stage reconciliation or task selection yet. Before enabling it, the -adapter must persist/recover reservations, apply presence and grace settings, -log enqueue/dequeue, publish profile/dashboard counts, send idempotent GitHub -nudges, and adopt expired work through the gated takeover path. The in-repository -relay (`bin/contributor-relay.js`) still needs parallel launch/park/resume handling -and heartbeat capability updates. Stage mirrors, legacy writer retirement, and -Settings/config parity also remain tracked by #12436. Do not advertise interrupt -support or suppress fresh claims until that integration is complete. +At the groundwork stage the queue was in memory and not wired into stage reconciliation or task selection. Its implementation checklist covered persistence/recovery, presence/grace settings, enqueue/dequeue logs, profile/dashboard counts, idempotent GitHub nudges, gated takeover, relay parallel launch/park/resume, heartbeat capabilities, stage mirrors, legacy-writer retirement, and Settings/config parity (#12436). + +That checklist is design history, not a statement that today's relay lacks delivery. The current binding in `pkg/dashboard/contribute_fixqueue.go` and relay handlers in `bin/contributor-relay.js` implement the shipped dispatch modes above. Verify the deployed peer's advertised capabilities and Operations view rather than inferring delivery from this old proposal. + +
## Custom stylesheets diff --git a/docs/content/hive/copilot-permissions-comparison.md b/docs/content/hive/copilot-permissions-comparison.md index 5b3ebecd..bd32e37b 100644 --- a/docs/content/hive/copilot-permissions-comparison.md +++ b/docs/content/hive/copilot-permissions-comparison.md @@ -9,6 +9,11 @@ This page says what that feature is, what Hive does in the same space, and where each does something the other does not. It is a comparison, not a ranking. The two tools answer different questions. +**Terms:** ACMM = AI Codebase Maturity Model, Hive's autonomy levels. +PR = pull request; CI = continuous integration (automated checks). +**Crux** is Hive's agent runtime. A **shadow gate** records what it would +block without blocking; an enforcing gate acts on that decision. + ## What Copilot assisted permissions is Source: the GitHub changelog entry of 2026-10-26, @@ -41,8 +46,25 @@ show a prompt. It does not know about pull requests, merges, or repositories. Hive runs fleets of agents against repositories without a person at the keyboard. Its controls are about what reaches GitHub, not about prompts. +At a glance: + +- The ACMM level sets how much work may be delegated, from observation to + eligible unattended merges at L6. +- Network and credential controls restrict agent writes outside the model. +- CI, holds, branch rules and configured review gates decide whether a + particular PR can merge. Pausing an agent is not a universal merge stop. + +Use the [comparison table](#comparison) for the short version. Maintainers can +expand the mechanism/evidence layer below; it preserves implementation details +and the limits of the observations. + +
+Hive mechanisms and observed evidence (technical reference) + - **Trust levels (ACMM L1-L6).** The level decides which agents run and in - which policy mode. Advisory agents write nothing to GitHub. Measured agents + which policy mode. Ordinary advisory agents write nothing to GitHub; the + reviewer has a separate comment/review-only `converse` capability from L2. + Measured agents may open issues. Hold-gated agents may open PRs, and every PR carries a `hold` label a human must remove. Full agents may merge on green CI. L1 and L2 are advisory, L3 and L4 add issues and hold-gated PRs, L5 opens PRs under @@ -68,12 +90,16 @@ keyboard. Its controls are about what reaches GitHub, not about prompts. makes a same-head approval required at L6. See [review swarm](https://github.com/hivecommons/hive/blob/v5/src/docs/review-swarm.md) and [running at level 6](/docs/hive/running-at-level-6). - **Hold and approval.** Below L6 every agent PR gets `hold`; a human removes - it. `needs-human` parks a PR for a person. At L6 a `reject` or - `changes_requested` verdict still needs a fix or a human merge. See + it. `needs-human` is a triage signal, not a universal merge stop. At L6 a + `reject` or `changes_requested` verdict needs a fix, a trusted human's + exact-head GitHub Approve override of the enforcing sweep gate, or a direct + human merge. Other merge requirements remain. See [labels and control signals](/docs/hive/labels-and-control-signals). - **Shadow gates.** `governor.review_gate.mode: shadow` (the default) and `intent.shadow` evaluate a gate and record what it would have held, and never - block. The record is in each evidence bundle under `shadow`. The study that + block **by virtue of the shadow setting**. `review.require_approval: true` + still forces review enforcement; a shadow setting cannot weaken it. + The record is in each evidence bundle under `shadow`. The study that would turn those records into an accuracy figure is planned and not yet running ([ablation plan](https://github.com/hivecommons/hive/blob/v5/src/docs/research/ablation-plan-2026-10.md)). Enforcement from a shadow result is a config switch, not a separate feature. @@ -81,6 +107,8 @@ keyboard. Its controls are about what reaches GitHub, not about prompts. published with n and 95% intervals. See [evidence](https://github.com/hivecommons/hive/blob/v5/src/docs/evidence.md) and [benchmarks](https://github.com/hivecommons/hive/blob/v5/src/docs/benchmarks/README.md). +
+ ## Comparison | Dimension | Copilot assisted permissions | Hive | diff --git a/docs/content/hive/dashboard-glossary.md b/docs/content/hive/dashboard-glossary.md index 08331ec9..d0cf4870 100644 --- a/docs/content/hive/dashboard-glossary.md +++ b/docs/content/hive/dashboard-glossary.md @@ -2,12 +2,40 @@ # Dashboard glossary and sidebar IA -This glossary records the operator-facing names used by the dashboard. The ADR-0018 IA/naming pass is implemented. +Use this glossary when a dashboard word is unfamiliar. “Sidebar IA” means information architecture: how the navigation is grouped. The [sidebar map](#sidebar-map) helps you find a destination; [UI naming reference](#ui-naming-reference) is for people maintaining the interface. For a plain-language explanation of every dashboard section — what it shows, how its numbers are worked out, and what to do about them — see [Dashboard sections explained](/docs/hive/dashboard-sections). Each section title's **?** mark opens its entry there. ## Terms +| Term | What it means for a reader | +| --- | --- | +| Hive | The service that coordinates work, agents and policy for a set of repositories. | +| Hub / spoke | A hub coordinates shared services or discovery for Hives. A spoke is a Hive connected to a hub; its dashboard may still have its own access rules. | +| Agent | A running automation process or configured role that plans, scans, reviews or does other work. | +| Contributor | A person or GitHub account participating through the contributor portal. | +| Contributor agent | The contributor's worker, connected through a relay that requests work and reports results. ClankeR is the relay's product name; `author/clanker` is an exact label, not a different kind of person. | +| Stage | The item's current pipeline step, such as actionable, claimed, review or merge gate. A stage is not permission to bypass a hold or policy. | +| Bead | A record in Hive's work ledger. It can track an issue, a finding or other work; it is not itself a GitHub issue or an approved knowledge entry. | +| ACMM | AI Codebase Maturity Model: levels L1–L6 describe how much the Hive may do on its own. The dashboard also calls this the autonomy level. See the [policy matrix](/docs/hive/acmm-policy-matrix). | +| Governor | The policy engine controlling cadence, autonomy, budgets and merge/apply gates. | +| Fleet | The agents and contributor agents being monitored together. | +| Lane | A named worker or processing path, such as an agent lane or an auto-merge lane. A lane can have its own admission checks. | +| Sentinel | The suspicious-activity check. A `sentinel-alert` flags a PR for maintainer attention; the label name can be configured. | +| Adopted | The Hive has taken responsibility for repairing a contributor-agent PR after the hand-back process. It may create a superseding PR; adoption does not allow rewriting a human author's work or lifting their holds. | +| Ratchet | A gate that records an existing baseline and rejects increases, rather than requiring every old problem to be fixed first. | +| Head | The current commit at the tip of a PR branch. Reviews and approvals may apply to that exact commit, not later pushes. | +| Verdict / dwell / soak | A verdict is a review result. Dwell is time at a stage before it is considered stalled. Soak is an admitted PR's waiting period before merge. | +| Swarm | Several reviewers working on the same review. Their results still pass through the merge policy. | +| Re-home | Continue work in a replacement PR owned by the appropriate author; do not silently rewrite the original author's commits. | +| Issue band / PR band | A display group in Projects, not a scheduler or merge permission. See the exact groups below. | + +For exact stage labels, repair ownership and hold rules, see [Labels and control signals](/docs/hive/labels-and-control-signals). For commands that inspect beads, see [`hivectl bead`](/docs/hive/hivectl#bead--work-items). + +## UI naming reference + +The ADR-0018 information-architecture/naming pass is implemented. The table below records names and presentation rules for UI authors; it is not a second set of operator controls. + | Term | Meaning | Use in operator UI | | --- | --- | --- | | Agent | Runnable automation process or configured role that can plan, scan, review, or otherwise work on hive tasks. | Use for dashboard automation and agent detail pages. | diff --git a/docs/content/hive/dashboard-sections.md b/docs/content/hive/dashboard-sections.md index c305482d..a2719585 100644 --- a/docs/content/hive/dashboard-sections.md +++ b/docs/content/hive/dashboard-sections.md @@ -33,6 +33,16 @@ These words have a special meaning in Hive. Each entry explains them again the f - **Needs-human:** waiting on a person, for example for a decision or a review. It is also the name of a label. - **Merge-eligible:** a pull request that passed every check Hive uses before it may merge it. +**Who is who in the activity monitor** ([#15394](https://github.com/hivecommons/hive/issues/15394)). Every hover, menu and caption uses these five nouns and no others: + +- **Agent:** any automated worker — one of Hive's own agents or a contributor's connected agent. Hover text says *the author's agent* for the latter; the product noun **clanker** appears only where it names the contributor relay itself (the Contributors page, presence chips). +- **Contributor:** a person outside the maintainer team whose issue or pull request Hive is tracking. +- **Author:** whoever opened the pull request — a person, an agent or Hive. A **trusted author** is one Hive may merge for without asking. +- **Reviewer:** a person or agent that reviews a pull request; Hive's own review swarm is *the reviewer*. +- **Merge:** the one word for landing a pull request. *Let hive merge* (the lead) is you approving so Hive merges through its own App on the next tick once CI is green; *Merge now* is you merging at once as maintainer. + +Hover text follows one budget: one sentence of state in plain words, at most 40 visible words, one recommended action, and everything technical (config keys, stage numbers, how to change a setting) behind a single collapsed **Details**. The same sentence is never shown twice on one surface. The per-builder word counts live in [dashboard-copy-inventory.md](https://github.com/hivecommons/hive/blob/v5/src/docs/dashboard-copy-inventory.md). + **Dialogs on a phone.** Any dialog with a long body — the **What changed** release notes after an upgrade, alerts, the export viewer, the Level 6 auto-merge notice, settings bodies — fills the whole screen on a phone: title and a ✕ at the top, the text scrolls in the middle, and the buttons stay fixed at the bottom. A soft fade at the bottom edge means there is more to read; it disappears when you reach the end. Esc, the ✕, the buttons and tapping the backdrop close it. On a desktop the same dialogs keep their usual size and only gain the fade and a thin scrollbar. See [Long-content modals](https://github.com/hivecommons/hive/blob/v5/src/docs/dashboard-design-system.md#long-content-modals-modal-scroll-and-the-mobile-sheet) for the convention. ## Overview @@ -100,7 +110,7 @@ How busy Hive thinks your projects are right now, and how often it wakes its wor - The Governor picks a mode by comparing the amount of actionable work with three thresholds. Actionable work is work Hive could do now, with nothing waiting on a person. - The **actionable issues** and **actionable PRs** tiles use the same count as the Overview's Actionable now tile. The two always agree. - The **hold** list names every held item. Held means someone parked it with a hold label. -- The compact strip at the top of the Agents view also shows **running** — how many workers are mid-round right now, and the estimated spend the whole fleet has accrued in the current clock hour (`3 · $1.20 this hour`). The hour figure is the rise in the cumulative estimate since the top of the hour; `$–` means the hive has not yet taken a reading this hour. +- The compact strip at the top of the Agents view and the Governor grid also show **running** — how many workers are mid-round right now, and the fleet's estimated spend, which rotates through four windows every ~4 seconds: `3 · $1.20 this hour` → `$9.80 today` → `$41 this week` → `$130 this month`. The worker count stays fixed; only the amount and window phrase crossfade, the tile reserves the width of its widest phrase so nothing shifts or wraps, the rotation pauses while you hover (the hover lists all four values) or while the tab is hidden, and it swaps instantly when your system asks for reduced motion. The hour figure is the rise in the cumulative estimate since the top of the hour; today / this week / this month are the cost ledger summed from 00:00 UTC today, Monday 00:00 UTC (ISO week) and the 1st of the month 00:00 UTC, plus the rise since the ledger's last reading. `$–` means the hive has not yet taken a reading for that window. - The **cadence table** shows, for each worker, how often it runs in each mode. Continuous means it runs again as soon as it finishes. - The **budget** shows how much of the AI spending allowance for the current period has been used. - The **next kick** estimate follows the eval tick, which is longer while GitHub webhooks are trusted (`/api/status.webhooks.mode` reads `webhook`) and drops back to `governor.eval_interval_s` when they degrade (`polling`). How that decision is made is in [webhooks.md](https://github.com/hivecommons/hive/blob/v5/src/docs/webhooks.md#fallback-when-webhooks-degrade). @@ -119,21 +129,27 @@ How busy Hive thinks your projects are right now, and how often it wakes its wor ## PRs by model -Which AI models wrote the pull requests Hive opened, and how often each model's work was merged without extra fixes. +Which AI models wrote the pull requests Hive opened, how well each model's work landed, and how the models rank against each other. -**What it tells you.** This part of the Governor section compares the AI models your workers use. It shows how many pull requests each model wrote and how they ended. +**What it tells you.** This part of the Governor section compares the AI models your workers use. It shows how many pull requests each model wrote, how they ended, and a rank that favours models with a long, clean record over models with a short, lucky one. **How the numbers are worked out.** -- Each row is one model. The bar splits its pull requests into merged, still open, and closed without merging. -- **First-pass rate** is the share of merged pull requests that needed no follow-up fixes. -- **Failure rate** and **nothing to ship** count runs that failed or finished without a pull request. -- A model gets a **rank** only after it has at least 5 merged pull requests in the window. With fewer, the sample is too small to compare. +- Each row is one model. Model ids are normalised so one model gets one row: a provider prefix (`openai-codex/gpt-6.1-sol`), a `:variant` suffix (`gpt-5.6-sol:high`) and a dash between version digits (`claude-opus-5-5`) are folded into `gpt-6.1-sol`, `gpt-5.6-sol` and `claude-opus-5.5`. The backends that drove the model appear as chips under its name; hover the row to see the raw ids and how many pull requests each contributed. +- The bar splits a model's pull requests into merged, still open, and closed without merging. +- **Merged** is the number of merged pull requests in the window. +- **1st pass** is the share of merged pull requests that merged without a review-requested fix round. +- **PR runs** is the share of recorded task runs (from the contributor run log) that ended with a verified pull request. +- **Fail** is the share of recorded task runs that failed: crashed, timed out, or exited non-zero. +- **No ship** is the share of recorded task runs that completed but opened no pull request. +- **Rank** orders models by a score that combines those columns and penalises small samples: `score = Wilson 95% lower bound(1st-pass merged ÷ merged) × (1 − Fail) × (1 − No ship)`. The Wilson lower bound is the pessimistic end of the confidence interval for the first-pass rate, so 5 of 5 (lower bound 0.57) scores below 21 of 22 (0.78) and well below 203 of 313 (0.60 after the bound, but with no failures). A model with no recorded runs keeps its bound as the score. +- A model gets a rank only after it has at least 5 merged pull requests in the window. With fewer, the sample is too small to compare and the row is listed without a rank. +- Rows whose pull requests carry no model id are shown last, muted, as **unattributed**. They are counted but never ranked. - You can show the last 7 days, the last 30 days, or all time. You can sort by rank or by count. -**What it is good for.** Use it when choosing which model a worker should use. A model with a low first-pass rate costs more review time. +**What it is good for.** Use it when choosing which model a worker should use. A model with a low first-pass rate or a high failure rate costs more review and retry time; the rank already weighs both. -**Example.** Model A has 40 pull requests and a 70% first-pass rate. Model B has 6 pull requests and a 30% rate. Model A is the safer default. +**Example.** Model A has 40 merged pull requests, 28 of them first pass, and 2% failed runs. Model B has 5 merged pull requests, all first pass, and 51% failed runs. A scores about 0.54 and B about 0.28, so A ranks higher even though B shows 100% first pass. **When it appears.** Inside the Governor section, so at autonomy level L2 and above. @@ -301,35 +317,95 @@ How much text the AI models read and wrote for Hive recently, broken down by mod What Hive's use of AI models would cost at public per-token list prices; an estimate, not a bill. -Copilot and Claude subscription seats and self-hosted inference are not billed per token, so real spend can be far lower. +Read this as a **list-price estimate, not a bill**. Copilot and Claude subscription seats and self-hosted inference are not billed per token, so actual spend can be much lower. -**What it tells you.** It turns token counts into money, so you can see roughly what Hive's model use is worth. +### Read the cost card -**How the numbers are worked out.** +1. Read **Estimated spend at list price — since · tokens × public per-token price · not a bill**. This is the accumulated estimate for the recorded history. +2. Compare **Cost / closed issue** and **cost / merged PR**. Both divide that same estimate by a different count; do not add them together. +3. Check **counts as of