Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/content/crux/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ refuses to start without a token. Set `CRUX_TOKEN` instead of passing
[`crux serve`](https://github.com/hivecommons/hive/blob/v5/src/docs/crux-serve.md)
page; the Go client lives in `github.com/hivecommons/crux/api`.

When a running service misbehaves (`/v1/health` fails, an agent is stuck,
a release has to be withdrawn), start from the
[runbooks index](https://github.com/hivecommons/crux/blob/main/runbooks/README.md).

## How it fits with Hive

Hive is a system that runs a whole team of agents against a set of
Expand Down
23 changes: 21 additions & 2 deletions docs/content/hive/agent-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ spec omits `launch_cmd`, Hive still builds the backend command normally.
# kick_failed_repeatedly self-report is filed
# only if kicks still fail after that restart
max_turn_duration: 0s # optional visibility-only Working ceiling; 0 disables
session_recycle: # optional override of the fleet agents.session_recycle
max_rss_mb: 1536 # policy: recycle this agent's CLI session (a normal
max_age: 6h # restart) once idle at the prompt and over the RSS
min_idle: 2m # or age budget; enabled: false turns it off
restart_strategy: immediate # how to bring a dead session back
beads_dir: /data/beads/scanner # work-record (bead) storage; default per-agent
replicas: 3 # materialize scanner, scanner-2, scanner-3 (max 5)
Expand Down Expand Up @@ -655,6 +659,7 @@ backends:
Names compare case-insensitively; an empty `backend:` (the hive default) is always allowed. The list is enforced where placements are decided:

- **ACMM pack apply** never places an agent on a disallowed backend. A pack agent whose pack backend is disallowed gets the first allowed `allow` entry instead (or the hive default when `allow` is empty), without the pack's model, so the replacement backend uses its own default model. A pack-owned agent already on a now-disallowed backend is moved the same way on the next apply. Backends an operator explicitly chose (operator-owned) are left alone.
- **ACMM pack agents follow the hive's inference gateway** ([#14678](https://github.com/hivecommons/hive/issues/14678)). When every backend you picked yourself (operator-owned — and any inference backend or gateway name with no `backend_owner`, e.g. one written straight into `hive.yaml`, since a pack never writes one) names the same inference backend or configured gateway, and more than half of the other enabled agents already run on it, a pack agent whose pack backend is a subscription CLI is placed on that gateway instead, with no `model:` so the gateway's default model applies. This applies to agents a level creates and, on every apply (each restart), to existing agents whose backend is still pack-owned — so after an upgrade the L2 `supervisor`/`brainstorm` may move from `copilot` onto your LiteLLM gateway alongside the new `reviewer`. An operator-owned `backend:` or a legacy `backend:` without an owner is never moved, a hive with an operator-picked CLI agent or with only a minority of agents on a gateway is left as is, and a pack that itself names a gateway or whose backend the `backends:` list replaced is not redirected.
- **`PUT /api/config/agent/{name}/models`** rejects a placement onto a disallowed backend with `400` and a message naming it.

### Changing backend and model together: use the atomic endpoint
Expand Down Expand Up @@ -779,7 +784,7 @@ You don't have to design a roster. Hive ships six **ACMM packs** (`level-1.yaml`
| L5 | Semi-Autonomous (Semi-Automated) | issues **and** PRs; PRs are gated by literal `hold`; humans batch-approve |
| L6 | Autonomous | auto-merge on green CI; no level hold, except cross-repo outreach PRs (target repo not managed by this hive) remain held |

Applying a level **reconciles the whole roster**, not just the diff: missing agents are created (as overlay files in `/data/agent-configs/`), existing agents are merged — pack values fill blanks, but your explicit `backend:`, `model:`, and `enabled: false` always win — and the level's `kick_template`, `mode` and `on_demand` are updated so the agent's *policy* matches the level (an `on_demand` you toggled yourself in the agent's settings dialog is operator-owned and left alone; leaving on-demand starts the agent, entering it stops it). A failed agent doesn't abort the rest; the level is only recorded as cleanly applied when every agent reconciled.
Applying a level **reconciles the whole roster**, not just the diff: missing agents are created (as overlay files in `/data/agent-configs/`), existing agents are merged — pack values fill blanks, but your explicit `backend:`, `model:`, and `enabled: false` always win — and the level's `kick_template`, `mode` and `on_demand` are updated so the agent's *policy* matches the level (an `on_demand` you toggled yourself in the agent's settings dialog is operator-owned and left alone; leaving on-demand starts the agent, entering it stops it). One exception to "pack values fill blanks": a `backend:` the pack itself wrote may be moved onto the hive's inference gateway, as described under [Disabling a backend spoke-wide](#disabling-a-backend-spoke-wide) ([#14678](https://github.com/hivecommons/hive/issues/14678)). A failed agent doesn't abort the rest; the level is only recorded as cleanly applied when every agent reconciled.

The L5 roster is the canonical worked example — twelve agents, nine on the governor timer, two opt-in agents paused in every governor mode, plus one on demand:

Expand Down Expand Up @@ -935,7 +940,7 @@ An empty allowlist denies every repo even with `allow_github_prompt: true` — t

A fetched file is capped at 512 KiB (`maxDefinitionBytes`, `defsrc.go:43`); an oversized file is truncated (and likely then fails to parse) rather than consuming unbounded memory.

The per-agent `prompt_source` (a kick template fetched from GitHub by `pkg/promptsrc`) has a tighter, token-oriented cap and a stricter failure mode ([#12130](https://github.com/hivecommons/hive/issues/12130)): 64 KiB by default (`promptsrc.DefaultMaxPromptBytes`, >2× the largest shipped template; `HIVE_PROMPT_SOURCE_MAX_BYTES` overrides), and a body over it is **rejected whole, never truncated**. The kick falls back to the last successfully fetched copy, then to the normal `kick_template` chain, with a logged warning naming the repo, path, size and cap; the dashboard's save/bake flow fails with the same message instead of writing a cut-off policy. See [operator-reference.md](https://github.com/hivecommons/hive/blob/v5/src/docs/operator-reference.md#notable-fields).
The per-agent `prompt_source` (a kick template fetched from GitHub by `pkg/promptsrc`) has a tighter, token-oriented cap and a stricter failure mode ([#12130](https://github.com/hivecommons/hive/issues/12130)): 96 KiB by default (`promptsrc.DefaultMaxPromptBytes`, >2× the largest shipped template; `HIVE_PROMPT_SOURCE_MAX_BYTES` overrides), and a body over it is **rejected whole, never truncated**. The kick falls back to the last successfully fetched copy, then to the normal `kick_template` chain, with a logged warning naming the repo, path, size and cap; the dashboard's save/bake flow fails with the same message instead of writing a cut-off policy. See [operator-reference.md](https://github.com/hivecommons/hive/blob/v5/src/docs/operator-reference.md#notable-fields).

### Validating a source before saving it

Expand Down Expand Up @@ -1028,6 +1033,7 @@ Semantics:
- An issue must carry **at least one** required label to be eligible. Matching is case-insensitive and **exact** (a prefix like `approved-for-agents-maybe` does not satisfy `approved-for-agents` — prefix matching would over-admit through an approval gate).
- **Exempt wins on conflict**: an issue carrying both an exempt label and a required label stays excluded. There is deliberately no separate `exclude_labels` field — the exempt list *is* the exclusion mechanism, applied first.
- PRs and the Hold list are unaffected: open PRs are in-flight work, and held issues still appear under On Hold.
- PRs have their own, separate allow-list for **reviews**: `review.require_labels` (Settings → Features → Review Gate → "Only review labelled PRs") keeps the hive from reviewing a PR until it carries an approval label; see [review-swarm.md](https://github.com/hivecommons/hive/blob/v5/src/docs/review-swarm.md#only-review-labelled-prs-reviewrequire_labels). Use a distinct label from the issue gate if the two approvals mean different things to your maintainers.

Both polarities are enforced at **enumeration** — the point where GitHub issues become the hive's actionable set — not in the prompt. A filtered issue never enters the queue, never appears in a kick, never triggers plan-from-label, and cannot be re-selected by a confused (or prompt-injected) agent re-listing the repo. Kick prompts additionally state the active require policy so agents know the list is intentionally short. Both lists are edited on the Labels tab; an active require gate is also noted read-only under **Projects**, and hub-managed hives can receive `issue_filter` with their project config over the heartbeat.

Expand All @@ -1053,6 +1059,19 @@ github:
- **Merge.** A PR whose rationale (its closing or referencing links, or the request's declared issue list) traces to an untrusted reporter's issue without any `untrusted_require_labels` acceptance label receives `hold` at **every** ACMM level, including L6, together with a marked notice naming the issue reporter (not the PR author). Any one unaccepted untrusted citation holds. A configured acceptance label supplies maintainer sign-off, so accepted issues do not trigger a new reporter-trust PR hold. A human removes the label; Hive never auto-releases a reporter-trust hold — the level-hold release path recognises the notice and leaves the label, and holdguard re-holds on a new head SHA. `github.reporter_trust_hold` follows `reporter_trust.enabled` unless set explicitly; `project.repo_policies[].reporter_trust_hold` overrides per repo; `HIVE_REPORTER_TRUST_HOLD` locks it from the environment, exactly like the #5117 knobs.
- **Where you see it.** Both halves are edited in the dashboard: **Settings → Labels → Reporter trust** (the switch, the association checkboxes, extra logins, triage labels) and **Settings → Repos** (the hold, with the same all-repos default / per-repo override / inherit rows as #5117). An active gate is stated in the read-only note under **Projects**, and each repo card counts issues **needs triage** separately from generic filter refusals. The issue itself carries `needs-triage` while waiting when Hive had to add it. Holds carry the reason in the PR notice and in the `agent_pr_created` audit entry (`reporter_trust_held`, `reporter_login`, `reporter_association`).

### Tracking and archive issues

Some issues are never meant to be worked or closed: a standing report archive that a workflow appends to every week, a long-lived checklist, a "Keep this issue open" status thread. Mark them with **any one** of the label `hive/tracking`, the body marker `<!-- hive:tracking -->`, or the literal sentence "Keep this issue open" in the body, and the hive treats the issue as a tracking issue.

Issues managed by [GitHub Agentic Workflows](https://github.com/github/gh-aw) (`[aw] Detection Runs`, the weekly research archives, …) are detected **automatically**, with no hive label needed: any `<!-- gh-aw-… -->` body marker (`gh-aw-detection-runs`, `gh-aw-expires: …`), gh-aw's boilerplate sentences ("automatically managed by GitHub Agentic Workflows", "Do not close this issue manually", "Do not assign to an agent", case-insensitive), or the `agentic-workflows` label on an `[aw]`-prefixed title all count (`skip:tracking:gh-aw-<marker|managed|label>`). Either way the hive treats the issue as a tracking issue:

- **Not advertised.** The good-first-issue picker scores it `skip:tracking:<label|marker|keep-open|gh-aw-marker|gh-aw-managed|gh-aw-label>` and never adds `good first issue` / `help wanted`; a tracking issue that already carries those labels has them withdrawn on the next sweep.
- **Not actionable.** Enumeration and the webhook patch sideline it into the `filtered` bucket with reason `tracking` (counted as `tracking` in the repo breakdown), so it never enters the queue, a kick, or the stage engine (it derives to *outside the pipeline*).
- **Never auto-closed.** Every Hive close path goes through the central `CloseIssue`, which refuses a tracking issue; close-on-merge records `tracking_issue` as its skip reason, and the already-done, stale, and advisory sweeps inherit the same refusal. Only an owner closing the item from the dashboard overrides it.
- **Closing keywords are nudged.** A hive-authored PR whose body says `Closes`/`Fixes #<tracking>` has the reference downgraded to `Refs` with an inline note; a PR created through the hive gets one marked reviewer comment explaining that the issue is an archive and the keyword would be ignored. GitHub itself still honours a `Closes #N` written by a human on a PR the hive does not own — the owning workflow is expected to recreate its tracking issue in that case.

The `hive/tracking` label also satisfies the tracker-issue check used by `/contribute`, so a tracking issue is never handed to an external contributor either.

**Not the same thing as the contribute filters.** `hub.contribute_labels_mode` + its label list gate which issues are *handed out to external contributors* over `/contribute` — they have never gated the hive's **own** agents, so an operator who allow-listed a queue label there (a common setup for routing labeled issues to contributors) still had a hive whose own scanner could work every other open issue. `project.issue_filter.require_labels` is the agent-side gate; configure both if you want the same label to govern both lanes.

## When to add what
Expand Down
3 changes: 3 additions & 0 deletions docs/content/hive/contributor-relay.md
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ The agent can now say it explicitly, the same way it says `no_work_needed`:
- **Relay: the label.** When the hub's `auth_ok` `permissions` include `issues:write` (every tier from `newcomer` up) and the task is a GitHub issue, the relay runs `gh issue edit <issue> --add-label blocked` with the task credential *before* dropping it at task exit — the same ordering as the #7879 PR comment. If the repository does not define the label, the relay creates it once and retries once; any further failure costs a log line, never the completion. Without `issues:write` (an `advisor`-tier credential, an older hub that sends no `permissions`), the cooldown above is the whole hold. **Lifting the label stays human**: the relay never removes it, so the admission gate holds the issue past the cooldown until someone who knows the dependency has cleared says so.
- **Prompt: the comment.** The assignment prompt now asks the agent, before printing either `no_work_needed` or `blocked`, to leave one comment on the issue naming exactly what covers or blocks it — the open or merged PR, the commit, or the external dependency — signed with the same `— hive: …` attribution line as a PR body. That comment is what puts the finding on GitHub rather than only in this hub's ledger: it creates the PR→issue cross-reference nobody had made (fsdk-containers#299 was correctly `no_work_needed` for open PR #289 with no text ref, no sidebar link and an empty cross-reference timeline, so the merge could not close it and the next cycle had to re-verify), and it tells a human why the `blocked` label appeared. The prompt also fixes a boundary: the agent must never edit someone else's PR body to add `Fixes #N` — if that PR's merge should close the issue, it says so in a comment on the PR, noting that only a maintainer editing the body makes the merge close it.
- **Not blocked: the contributor's own tooling.** A `blocked` whose reason describes the *contributor's* environment failing — the push to the fork rejected, a token without the `workflow` scope, a credential or permission error, the `gh`/`git` wrappers, a stale fork — is not blocked on anything outside the repository ([#11775](https://github.com/hivecommons/hive/issues/11775), [#11776](https://github.com/hivecommons/hive/issues/11776): two issues sat `blocked` fleet-wide with no PR after exactly that). The relay demotes it (`isToolingFailureBlockedReason`): no label, and the wire carries the `verdict_reason` but no verdict, so the hub books an idle completion on the short cooldown and re-offers the issue. The hub applies the same classifier to what it receives (`reclassifyToolingBlockedVerdict`, for relays older than this), and when it demotes one it removes the `blocked` label the relay applied and leaves a single `<!-- hive:blocked-released kind=tooling -->` comment saying why. The prompt also tells the agent outright that its own environment failing is never a `blocked` issue.
- **Not complete: the agent's environment is broken.** A verdict under any token except `wrong_base` whose reason says the agent's own runtime cannot run commands — "environment failure", "Bash tool broken", "every command fails", `apply-seccomp`, `/proc/self/setgroups` (`ENVIRONMENT_FAILURE_REASON_PATTERNS`) — is classified `blocked` with `environmentFailure` set, labels nothing, and is reported as `task_failed` with `failure_kind: environment` instead of `task_complete` ([#14832](https://github.com/hivecommons/hive/issues/14832): on Ubuntu's AppArmor user-namespace restriction every sandboxed command failed and the agent's `HIVE_VERDICT: complete — environment failure: …` was booked as a finished task). A PR this task opened still overrides the verdict.

### A maintainer-decision verdict is labelled until a human answers

Expand Down Expand Up @@ -1262,6 +1263,8 @@ That last line types a fresh prompt into a pane whose CLI is still mid-turn, int

**A blip is not an abandonment until the grace window says so.** The re-adoption check above is zero-width for a `1006`: the hub processes the dead socket the instant its read fails, while the relay does not even start redialing for `BASE_RECONNECT_DELAY_MS` (1 s). So on a real network blip the release always won the race, and every blip wrote an `abandoned_disconnect` run row plus a "released: connection lost" activity row for a task that resumed one second later — 11 phantom rows across 17 completed tasks in one 3.5-hour run ([#7838](https://github.com/hivecommons/hive/issues/7838)). The visible booking now waits `HIVE_CONTRIBUTE_DISCONNECT_GRACE` (default 5 s); at the deadline the hub re-runs the re-adoption check and also asks whether a completion/failure row has since been written for the task id, and writes nothing if either is true. The short release cooldown — the double-assign hedge — is still booked immediately and still withdrawn by the resume, so the window is covered either way.

**Who wrote the PR does not change the stand-in rule.** Clanker PRs are adoptable on disconnect regardless of the owner's repo role: once the nudge window passes with the contributor's hive gone, the hub's hive adopts a maintainer's `author/clanker` PR exactly as it adopts anyone else's (`governor.labels.stage.adoption.maintainer_policy`, default `adopt`; `ask` parks it for an owner's Adopt, `never` opts out).

**The lease has to outlive the hub process.** Leases used to live only in the hub's memory, so a restart — which self-upgrade rolls ([#5391](https://github.com/hivecommons/hive/issues/5391)) make routine rather than rare — emptied the registry while every relay carried on working. After the roll *no* in-flight resume could match, and each one produced the same four lines above, this time for a reason the relay could do nothing about ([#5681](https://github.com/hivecommons/hive/issues/5681)). Observed 2026-09-02: revoked at 14:24:40, the same issue reassigned to the same relay at 14:24:44, discarding two and a half minutes of a turn that was progressing normally. The registry is now written to `/data/contributors/task-leases.json` (owner-only) on every assignment, renewal and release, and read back at startup, so a restart is just a longer-than-usual disconnect.

This does not loosen who may claim what. The restored record is one the *hub itself* wrote, and a resume is matched against it exactly as before; a lease whose window has already passed is dropped at startup rather than restored.
Expand Down
Loading
Loading