From f22791b7a46cdccb3f56976a46c8a8e3844f3413 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 9 Sep 2026 20:30:15 +0200 Subject: [PATCH 1/5] docs: clear the remaining error-level vale lints Per #4128 (mara: allow-everywhere false positives go in a central list, otherwise fix in source). Testing surfaced better fixes than the plan posted on the issue: - 5x Microsoft.Contractions 'that is' idiom false positives: adding the missing comma ("that is, ...") both reads better and satisfies the rule's own negative-lookahead, so no suppression is needed at all. Fixed in docs/integrations/forge.md, docs/tools/forge.md, docs/tools/hivectl.md, docs/web-ui/dashboard.md, and swarmctl-cli.md's generated source (swarmctl/src/main.rs, doc comment regenerated via markdown-docs). - persistence.md's 'is not' matching inside 'is nothing': reworded to 'there'\''s nothing' rather than add any exception -- dodges the trap and is a genuine contraction besides. - ca.md's 'it is' matching inside the already-correct 'it isn'\''t': tried a central .vale.ini TokenIgnores entry first per the allow-everywhere framing, but testing against the real file (not just a synthetic snippet) found it silently fails to suppress whenever markdown emphasis syntax appears earlier in the same file -- an offset-drift bug in how Vale applies TokenIgnores, not a config mistake. Reworded to "it'\''s not" instead, same fix shape as persistence.md. - config.md's 3 genuine Microsoft.Avoid 'backend' exceptions (already flagged and accepted on #4139 -- an actually-pluggable LLM API provider, matching the nix option's own name, not one internal system to name): scoped inline vale suppression around just that section, since this one really is context-specific rather than a rule bug. Verified: fresh 'vale docs/ --minAlertLevel=error' is 0 errors AND 0 warnings (was 10 errors). nix fmt 0 changed beyond the edits themselves. pre-push lints (tracker-tag/comment-block/doc-pointer) clean. cargo clippy -p swarmctl -- -D warnings clean. Diffed the regenerated swarmctl-cli.md against the old copy to confirm only the intended line moved. --- docs/agent-lifecycle/persistence.md | 2 +- docs/integrations/forge.md | 2 +- docs/swarm/ca.md | 2 +- docs/tools/forge.md | 4 ++-- docs/tools/hivectl.md | 2 +- docs/tools/swarmctl-cli.md | 2 +- docs/turn-loop/config.md | 8 ++++++++ docs/web-ui/dashboard.md | 2 +- swarmctl/src/main.rs | 4 ++-- 9 files changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/agent-lifecycle/persistence.md b/docs/agent-lifecycle/persistence.md index 59bf920d..521556eb 100644 --- a/docs/agent-lifecycle/persistence.md +++ b/docs/agent-lifecycle/persistence.md @@ -479,7 +479,7 @@ so it survives restarts and redeploys. with. **Keep it.** It's handed to Forgejo when swarm-controller registers a hook, so replacing the file means every subsequent delivery fails verification until the hook is re-registered with the new value. It's - generated automatically on first start; there is nothing to configure. + generated automatically on first start; there's nothing to configure. If the file is unreadable at startup the daemon still starts and logs `webhook secret unavailable`; the webhook endpoint then answers 503 diff --git a/docs/integrations/forge.md b/docs/integrations/forge.md index f8bdff76..3604d609 100644 --- a/docs/integrations/forge.md +++ b/docs/integrations/forge.md @@ -279,7 +279,7 @@ to `closed_at` that `state_change_is_current` returns `true` — so it takes the state-change path, dropping its body. Best of both worlds: on the merge/close path `forge_notify` fetches the `latest_comment_url` comment and, when its `created_at` is strictly **after** the subject's `closed_at` -(`comment_is_after_close`) — that is it raced the merge rather than being the +(`comment_is_after_close`) — that is, it raced the merge rather than being the pre-merge last comment the subject keeps — append it as a `comment by : ` block before the meta suffix (`fresh_post_close_comment_tail`). The wake carries **both** `[PR merged]` diff --git a/docs/swarm/ca.md b/docs/swarm/ca.md index 9ed6c9f1..2f3239ec 100644 --- a/docs/swarm/ca.md +++ b/docs/swarm/ca.md @@ -179,7 +179,7 @@ Two consumers, and only one of them is fine: The consumption differs per runtime and is the part worth knowing. tuwunel links no openssl, which makes `SSL_CERT_FILE` look inapplicable - — it isn't: its rustls-based TLS stack still resolves trust through the + — it's not: its rustls-based TLS stack still resolves trust through the platform certificate store on Linux, and that store honors `SSL_CERT_FILE`, so the env var takes effect the same way it would for an OpenSSL-linked binary. diff --git a/docs/tools/forge.md b/docs/tools/forge.md index 218fc059..8799e549 100644 --- a/docs/tools/forge.md +++ b/docs/tools/forge.md @@ -257,8 +257,8 @@ to discover valid label names before triaging or to audit the label set. ## Notes - **Read-before-comment guard:** `comment` refuses to post when forge still - has an unread notification for the thread (that is someone commented since you - last read it). This prevents accidentally replying to old activity without + has an unread notification for the thread (that is, someone commented since + you last read it). This prevents accidentally replying to old activity without seeing the new context. Read the thread with `hive-forge view ` or `hive-forge comments ` (which mark the notification read and clear the block), or pass `--force` to skip the guard. diff --git a/docs/tools/hivectl.md b/docs/tools/hivectl.md index e3f8d79a..9ee1c99a 100644 --- a/docs/tools/hivectl.md +++ b/docs/tools/hivectl.md @@ -240,7 +240,7 @@ Bare `choom` starts a fresh blank session. `--resume ` passes through as `claude --resume ` to rejoin a prior session by its session id — the flag name deliberately matches the claude flag it maps to. (choom never uses claude's `--continue`: that's a bare flag that -takes no argument and resumes the cwd's _latest_ session, that is the +takes no argument and resumes the cwd's _latest_ session, that is, the harness's; a value after it would be consumed as the first prompt, silently poking the live harness session.) A value is required when the flag is given. Either way choom never collides with the harness's live diff --git a/docs/tools/swarmctl-cli.md b/docs/tools/swarmctl-cli.md index bc70f6a2..e1449840 100644 --- a/docs/tools/swarmctl-cli.md +++ b/docs/tools/swarmctl-cli.md @@ -25,7 +25,7 @@ swarm-level operator CLI ###### **Options:** * `--authelia-bin ` — authelia binary used to hash passwords. The argon2 parameters must match the verifier's, so this has to be the *configured* package rather than whatever is on `PATH` -* `--users-file ` — Host-side path of authelia's users database — that is the path inside the container, prefixed with the container's root. +* `--users-file ` — Host-side path of authelia's users database — that is, the path inside the container, prefixed with the container's root. This is the only user store: it's read before every change and written in place, and `swarm-authelia-bridge` writes the same file. diff --git a/docs/turn-loop/config.md b/docs/turn-loop/config.md index 363d2b13..49a0be20 100644 --- a/docs/turn-loop/config.md +++ b/docs/turn-loop/config.md @@ -240,6 +240,12 @@ It leaves non-compile subcommands (`new`, `add`, third-party Set to `false` for agents that parse cargo's JSON output programmatically and don't pass `--message-format json` themselves. + + + ## API-key backend (`useApiKey` / `backendEnvironmentFile`) ```nix @@ -300,3 +306,5 @@ Switching an already-provisioned OAuth agent to `useApiKey` leaves cleaned up automatically. Cost shape also changes: subscription pricing → per-request billing with no built-in monthly cap, worth knowing before pointing a busy agent at a metered backend. + + diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md index c6684faa..f0a1743e 100644 --- a/docs/web-ui/dashboard.md +++ b/docs/web-ui/dashboard.md @@ -454,7 +454,7 @@ named buckets of MCP tools; each agent starts with a role default `ToolGroup::AGENT_DEFAULT`; hive-c0re seeds the root agent to `ToolGroup::MANAGER_DEFAULT` — `messaging`, `meta`, `inbox`, `lifecycle`, `approvals`, `scheduling`, `diagnostics`, `execution`, -that is every group except `forge` and `web_tools`). Checking / +that is, every group except `forge` and `web_tools`). Checking / unchecking stages which groups are active for the agent; the page-level **save all** button (below) commits it. Columns come from `GET /api/tool-groups`. hive-c0re queues a rebuild so `HIVE_TOOL_GROUPS` diff --git a/swarmctl/src/main.rs b/swarmctl/src/main.rs index 6e8a54e4..5d32de7a 100644 --- a/swarmctl/src/main.rs +++ b/swarmctl/src/main.rs @@ -58,8 +58,8 @@ struct PathArgs { /// rather than whatever is on `PATH`. #[arg(long, value_name = "PATH")] authelia_bin: Option, - /// Host-side path of authelia's users database — that is the path inside - /// the container, prefixed with the container's root. + /// Host-side path of authelia's users database — that is, the path + /// inside the container, prefixed with the container's root. /// /// This is the only user store: it's read before every change and /// written in place, and `swarm-authelia-bridge` writes the same file. From 397c0a9c7a11a3042c9b0eae2ede5d11cf4d7dc9 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 9 Sep 2026 20:50:54 +0200 Subject: [PATCH 2/5] docs: fix invalid -- inside an HTML comment body (argus nit on #4146) Em dash to match house style everywhere else, plus HTML comment bodies can't contain a literal --. --- docs/turn-loop/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/turn-loop/config.md b/docs/turn-loop/config.md index 49a0be20..6d027c01 100644 --- a/docs/turn-loop/config.md +++ b/docs/turn-loop/config.md @@ -242,7 +242,7 @@ programmatically and don't pass `--message-format json` themselves. From 3ca81d388ccbb07e435fa702b8f50e49662020c5 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 9 Sep 2026 21:01:46 +0200 Subject: [PATCH 3/5] docs: reword away from 'backend' instead of whitelisting it (mara, #4146) mara disagreed with exempting this section from #4041's ruling. 'Backend' here meant 'which LLM API provider', and the doc already uses 'provider' for the same concept a few lines down ('provider- specific model string') - so reword to that instead of carving out an exception. Drops the inline vale suppression comment entirely. --- docs/turn-loop/config.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/turn-loop/config.md b/docs/turn-loop/config.md index 6d027c01..ebc14000 100644 --- a/docs/turn-loop/config.md +++ b/docs/turn-loop/config.md @@ -240,13 +240,7 @@ It leaves non-compile subcommands (`new`, `add`, third-party Set to `false` for agents that parse cargo's JSON output programmatically and don't pass `--message-format json` themselves. - - - -## API-key backend (`useApiKey` / `backendEnvironmentFile`) +## API-key provider (`useApiKey` / `backendEnvironmentFile`) ```nix hyperhive.useApiKey = true; # default: false @@ -255,7 +249,7 @@ hyperhive.backendEnvironmentFile = hyperhive.model = "anthropic/claude-3.5-sonnet"; # provider-specific model string ``` -Runs this agent's `claude` against an API-key backend (for example OpenRouter) +Runs this agent's `claude` against an API-key provider (for example OpenRouter) instead of a Claude subscription via OAuth. Two options, paired — each is a no-op without the other: @@ -305,6 +299,4 @@ Switching an already-provisioned OAuth agent to `useApiKey` leaves `~/.claude/credentials.json` in place but unused — harmless, not cleaned up automatically. Cost shape also changes: subscription pricing → per-request billing with no built-in monthly cap, worth knowing before -pointing a busy agent at a metered backend. - - +pointing a busy agent at a metered provider. From c13499c8397e44a8e90f71e816522257c4835f1e Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 9 Sep 2026 21:08:31 +0200 Subject: [PATCH 4/5] ci: split an error-only vale check out of the full prose-lint job mara, on #4128: add a CI step (separate from the existing one) that only flags error-level vale hits, so it can be made a required check without also gating merges on the pre-existing warning/suggestion backlog. The full job stays as-is, advisory, for that backlog. Also brought docs/scheduler/ci.md's CI-checks table back in sync with reality (it was missing the doc-pointer lint job already; now lists both vale jobs and their required-check status). --- .forgejo/workflows/ci.yml | 31 +++++++++++++++++++++++++------ docs/scheduler/ci.md | 26 +++++++++++++++++--------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index beece01f..3e0adf91 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -80,10 +80,29 @@ jobs: # `Packages` line) are fetched fresh from the Vale Package Hub each # run rather than vendored, so this job always lints against # upstream's current rules. Failing red on a hit is intentional -- - # the existing docs/ tree has a real backlog against these rules - # (663 hits as of this writing), so this job starts out red on - # unrelated PRs until that backlog is worked down. Not (yet) wired - # into branch protection as a required check, so a red result here - # doesn't block a merge -- opting it into required-check status is - # a separate, later call. + # the existing docs/ tree has a standing backlog of warning- and + # suggestion-level rule hits, so this job stays red on unrelated + # PRs until that backlog is worked down (tracked separately from + # #4128, which was scoped to error-level hits only). Not wired + # into branch protection -- see the sibling job below for the + # error-only slice that is. run: XDG_DATA_HOME="$PWD/.vale-data" nix shell nixpkgs#vale --command sh -c 'vale sync && vale docs' + + prose-lint-errors: + name: prose lint (vale, errors) + runs-on: [hive-ci] + # Own `vale sync` rather than reusing the sibling job's: each job gets + # a fresh checkout/environment, so there is nothing to share between + # them without an artifact-upload step this doesn't need. + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: lint + # The error-level-only slice of the sibling job above. + # `--minAlertLevel=error` changes what vale both reports AND exits + # non-zero on, so this job's pass/fail tracks only error-severity + # rule hits, not the warning/suggestion backlog the sibling job + # carries. Split out (#4128) so this one alone can be a required + # check (forge branch protection) without blocking merges on the + # pre-existing backlog the sibling job still surfaces. + run: XDG_DATA_HOME="$PWD/.vale-data" nix shell nixpkgs#vale --command sh -c 'vale sync && vale --minAlertLevel=error docs' diff --git a/docs/scheduler/ci.md b/docs/scheduler/ci.md index 64f617b2..420f9610 100644 --- a/docs/scheduler/ci.md +++ b/docs/scheduler/ci.md @@ -31,16 +31,24 @@ writeup. ## CI checks -Three jobs run on every PR (and on `workflow_dispatch` for manual re-triggers), -defined in [`.forgejo/workflows/ci.yml`](../../.forgejo/workflows/ci.yml). All -three are required checks (forge branch protection) — a hit on any of them -blocks merge. +Several jobs run on every PR (and on `workflow_dispatch` for manual +re-triggers), defined in +[`.forgejo/workflows/ci.yml`](../../.forgejo/workflows/ci.yml). The first four +below are required checks (forge branch protection) — a hit on any of them +blocks merge. The two vale jobs split a single check in two (#4128): the +error-only one exists so it _can_ become a required check without also +gating on the full job's standing warning/suggestion backlog, but flipping +that switch on the forge is a separate operator action, not something this +table can assert ahead of it happening. -| Job | What it runs | -| ---------------------- | --------------------------------------------------------------------------------- | -| **nix flake check** | treefmt formatting, `cargo clippy -D warnings`, `cargo test`, module evaluation | -| **tracker-tag lint** | flags `#NNN` issue tags in source and comments (`scripts/check-issue-refs.sh`) | -| **comment-block lint** | flags contiguous comment blocks over 30 lines (`scripts/check-comment-blocks.sh`) | +| Job | What it runs | Required? | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------- | +| **nix flake check** | treefmt formatting, `cargo clippy -D warnings`, `cargo test`, module evaluation | yes | +| **tracker-tag lint** | flags `#NNN` issue tags in source and comments (`scripts/check-issue-refs.sh`) | yes | +| **comment-block lint** | flags contiguous comment blocks over 30 lines (`scripts/check-comment-blocks.sh`) | yes | +| **doc-pointer lint** | flags `docs/…md` paths and relative markdown links that no longer resolve (`scripts/check-doc-refs.sh`) | yes | +| **prose lint (vale, errors)** | vale, `docs/` tree, error-severity rule hits only | not yet — intended to be | +| **prose lint (vale)** | vale, `docs/` tree, full severity range (warnings + suggestions too) | no — advisory, standing backlog | `hive-forge ci-rerun --pr N` dispatches a `workflow_dispatch` retrigger without an empty commit. From 00b7f5063a786705e08546f6c2fbad6f95ea2881 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 9 Sep 2026 21:16:57 +0200 Subject: [PATCH 5/5] ci: drop bare issue tags from ci.yml comments (mara, #4146) hive-rules.md: no #NNN tags in code, prose only. The two mentions in the new prose-lint-errors job's comments were exactly that -- reworded to describe the split without a ticket number. --- .forgejo/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 3e0adf91..60535005 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -82,10 +82,10 @@ jobs: # upstream's current rules. Failing red on a hit is intentional -- # the existing docs/ tree has a standing backlog of warning- and # suggestion-level rule hits, so this job stays red on unrelated - # PRs until that backlog is worked down (tracked separately from - # #4128, which was scoped to error-level hits only). Not wired - # into branch protection -- see the sibling job below for the - # error-only slice that is. + # PRs until that backlog is worked down (tracked separately, as a + # follow-up to the error-only work below). Not wired into branch + # protection -- see the sibling job below for the error-only slice + # that is. run: XDG_DATA_HOME="$PWD/.vale-data" nix shell nixpkgs#vale --command sh -c 'vale sync && vale docs' prose-lint-errors: @@ -102,7 +102,7 @@ jobs: # `--minAlertLevel=error` changes what vale both reports AND exits # non-zero on, so this job's pass/fail tracks only error-severity # rule hits, not the warning/suggestion backlog the sibling job - # carries. Split out (#4128) so this one alone can be a required - # check (forge branch protection) without blocking merges on the + # carries. Split out so this one alone can be a required check + # (forge branch protection) without blocking merges on the # pre-existing backlog the sibling job still surfaces. run: XDG_DATA_HOME="$PWD/.vale-data" nix shell nixpkgs#vale --command sh -c 'vale sync && vale --minAlertLevel=error docs'