Watch
0
0
Fork
You've already forked hyperhive
0

docs: the handbook follows the three layers: swarm, hives, agents

The handbook's sections were agent-lifecycle, integrations, swarm, tools,
trust-boundary and web-ui, which do not follow how the system is built, so a
reader could not tell which layer a page is about. Its pages now sit in
swarm/, hives/ and agents/, with the accounts an agent can hold outside the
system in external-accounts/.

- swarm/: forge, matrix and the knowledge repo join the swarm pages, and so
  does the swarmctl reference.
- hives/: the dashboard, hivectl and its reference, and the operator/agent
  boundary, with a README that takes over the old web-ui and tools pages.
- agents/: the roster, persistence, config changes, the agent's own web page
  (was web-ui/agent) and the security model, with a README.
- external-accounts/: GitHub and GitLab.

Pages are moved whole; none is split yet. Every reference follows: relative
links in the docs, `docs/2-handbook/...` paths in code comments, the nix
checks that regenerate the CLI references and the ignore list, and docs/README.md,
whose handbook section is now by layer.
This commit is contained in:
iris 2026-11-07 11:20:48 +01:00 • committed by mara
commit 0e84fe8bc4
4 changed files with 393 additions and 363 deletions

View file

@ -14,7 +14,7 @@ self-echo filter, the comment / review / new-item / state-change
wrapper formats, body-excerpt truncation, and the assigned-issue
rollup all live in `notify.rs`. The behaviour contract — activation
gates, filtering rules, the review-request override — is documented in
[`docs/2-handbook/integrations/forge.md`](../docs/2-handbook/integrations/forge.md), "Notification poller".
[`docs/2-handbook/swarm/forge.md`](../docs/2-handbook/swarm/forge.md), "Notification poller".
## Shape

View file

@ -5,7 +5,7 @@
//!
//! Takes no arguments. `HYPERHIVE_STATE_DIR` holds the PAT
//! (`github-token`, fetched from the swarm secret store by
//! `nix/agent-modules/github-token.nix` — see `docs/2-handbook/integrations/github.md`)
//! `nix/agent-modules/github-token.nix` — see `docs/2-handbook/external-accounts/github.md`)
//! and `HIVE_AGENT_SOCKET` is the harness's todo socket.
//! Having a PAT *is* the opt-in: with no token the poller logs why and
//! exits 0, so deploying this unit to an agent that never gets one costs a

View file

@ -13,7 +13,7 @@ use hive_forge_notify::notify::UNREAD_FETCH_LIMIT;
use hive_forge_notify::source::Source;
use tracing::{debug, warn};
/// GitHub's REST base. `docs/2-handbook/integrations/github.md` scopes the integration to
/// GitHub's REST base. `docs/2-handbook/external-accounts/github.md` scopes the integration to
/// github.com only — the same constraint the `gh` wrapper and the git
/// credential helper already carry — so this is a constant rather than
/// another operator-entered URL.

View file

@ -18,12 +18,12 @@
//! **Multi-source**: always the internal Forgejo, plus github.com when the
//! agent has a PAT. Each source polls independently behind
//! [`Source`]; everything below is shared. Rationale
//! + host differences: `docs/2-handbook/integrations/github.md::Notifications`.
//! + host differences: `docs/2-handbook/external-accounts/github.md::Notifications`.
//!
//! Activation gates, self-notification filtering, body excerpt +
//! truncation + heading escape, wrapper formats (comment / review /
//! new-item / state-change), meta suffix, and review-request override
//! all live in `docs/2-handbook/integrations/forge.md::Notification poller`.
//! all live in `docs/2-handbook/swarm/forge.md::Notification poller`.
use std::collections::{HashMap, HashSet};
use std::fmt::Write as _;
@ -85,7 +85,7 @@ where
/// a `new <kind>` label. Later activity that lands on the state-change
/// path because it carries no `latest_comment_url` (e.g. a bodiless
/// review submission) fires well outside this window, so we must not
/// claim it's "new" — see docs/2-handbook/integrations/forge.md, "new vs activity on".
/// claim it's "new" — see docs/2-handbook/swarm/forge.md, "new vs activity on".
const NEW_ITEM_TOLERANCE_SECS: i64 = 120;
/// Fetch the account's own login for self-notification filtering.
@ -133,7 +133,7 @@ fn notif_type_label(t: Option<NotifySubjectType>) -> &'static str {
/// Escape strict-ATX markdown headings in a body before embedding it
/// inside the forge-notify wrapper, so a leading `## title` line
/// doesn't blow into an h2 in the dashboard render. See
/// `docs/2-handbook/integrations/forge.md::Body excerpt + truncation + heading escape` for
/// `docs/2-handbook/swarm/forge.md::Body excerpt + truncation + heading escape` for
/// the strict-ATX-vs-`#tag` rationale and the `split_inclusive`
/// trailing-newline contract.
fn escape_md_headings(body: &str) -> String {
@ -218,7 +218,7 @@ fn is_username_byte(b: u8) -> bool {
/// `@username` mention AND aren't already present (as a substring) in
/// `included_excerpt`. Surfaces tags that fell outside the truncation
/// window so addressed agents never silently miss a mention on a long
/// body. See `docs/2-handbook/integrations/forge.md::Body excerpt + truncation + heading
/// body. See `docs/2-handbook/swarm/forge.md::Body excerpt + truncation + heading
/// escape` for the truncate-before-escape ordering rule.
fn extract_truncated_mention_lines<'a>(full_body: &'a str, included_excerpt: &str) -> Vec<&'a str> {
full_body
@ -275,7 +275,7 @@ fn review_state_label(state: &str) -> Option<&str> {
/// Build a human-readable wake message for one Forgejo notification,
/// or `None` for a self-echo the caller should mark-read without
/// delivery. Wrapper format table + meta-suffix shape + number/repo
/// extraction live in `docs/2-handbook/integrations/forge.md::Wrapper format` +
/// extraction live in `docs/2-handbook/swarm/forge.md::Wrapper format` +
/// `::Meta suffix`.
async fn format_notification<S: Source>(
client: &reqwest::Client,
@ -327,7 +327,7 @@ async fn format_notification<S: Source>(
// Always fetch subject detail for assignee/reviewer metadata so
// the meta suffix can show current ownership without a follow-up
// fetch (see `docs/2-handbook/integrations/forge.md::Meta suffix`).
// fetch (see `docs/2-handbook/swarm/forge.md::Meta suffix`).
let subject = if subject_api_url.is_empty() {
None
} else {
@ -417,7 +417,7 @@ async fn format_notification<S: Source>(
/// that comment was genuinely posted AFTER the close - a comment
/// racing the merge inside the state-change tolerance window - it is
/// appended so it isn't lost (best of both worlds; see
/// `docs/2-handbook/integrations/forge.md::Merge racing a comment`). The ordinary
/// `docs/2-handbook/swarm/forge.md::Merge racing a comment`). The ordinary
/// pre-merge last comment (created before `closed_at`) is left off.
/// The earlier-updates count is the same widened marker as the comment
/// path; both are fetched here because `format_state_change_notification`
@ -463,7 +463,7 @@ struct NotifMeta<'a> {
/// Build the `\nassignee: ...` (and optionally `\nreviewer: ...`)
/// suffix appended to every wrapper. Shape + presence rules live in
/// `docs/2-handbook/integrations/forge.md::Meta suffix`.
/// `docs/2-handbook/swarm/forge.md::Meta suffix`.
fn build_meta_suffix(subject: Option<&serde_json::Value>, is_pr: bool) -> String {
let assignees: Vec<&str> = subject
.and_then(|s| s["assignees"].as_array())
@ -725,7 +725,7 @@ fn format_state_change_notification(
// time. A review submitted with no body carries no
// `latest_comment_url`, so it lands here instead of on the comment
// path — and its event time is well after `created_at`. Labeling
// that "new PR" is misleading (see docs/2-handbook/integrations/forge.md, "new vs activity
// that "new PR" is misleading (see docs/2-handbook/swarm/forge.md, "new vs activity
// on"): agents dismiss it as a
// duplicate of the original open notification. When we can't confirm
// creation, fall back to a neutral "activity on" label.
@ -757,7 +757,7 @@ fn format_state_change_notification(
// Review-request override: Forgejo doesn't reliably set
// `reason == "review_requested"` (often null), so we check the
// subject payload's `requested_reviewers` list directly. See
// `docs/2-handbook/integrations/forge.md::Review-request override`.
// `docs/2-handbook/swarm/forge.md::Review-request override`.
let is_review_request = is_new
&& *is_pr
&& !own_login.is_empty()
@ -801,7 +801,7 @@ fn format_state_change_notification(
/// `created_at`: within `NEW_ITEM_TOLERANCE_SECS` ⇒ creation. When
/// either timestamp is missing or unparseable we default to `true`,
/// preserving the prior "new" behavior rather than masking a genuine
/// new item behind the neutral fallback. See docs/2-handbook/integrations/forge.md, "new vs
/// new item behind the neutral fallback. See docs/2-handbook/swarm/forge.md, "new vs
/// activity on".
fn notification_is_creation(
event: Option<OffsetDateTime>,