From 39b95c2ede6b7216c26fbc3bc926d593219291a1 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 2 Sep 2026 14:29:33 +0200 Subject: [PATCH] treefmt: apply prettier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure `nix fmt` output from the commit before this one — no hand edits. 203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs. Reproduce with `nix develop -c nix fmt` on the parent commit; the result should be byte-identical to this tree. None of the 13 `.prettierignore` entries appears here — verified by intersecting the changed-file list against the ignore file, with a control proving the intersection finds a match when one exists. --- .../base/skills/claude-subagents/SKILL.md | 6 +- .../base/skills/forge-issue-filing/SKILL.md | 6 +- .../plugins/base/skills/forge-triage/SKILL.md | 11 +- .../base/skills/headless-screenshot/SKILL.md | 6 +- .../plugins/base/skills/pr-review/SKILL.md | 2 +- docs/agent-lifecycle/agent-hierarchy.md | 24 +- docs/getting-started/setup.md | 2 +- docs/integrations/forge.md | 18 +- docs/integrations/github.md | 8 +- docs/integrations/knowledge.md | 2 +- docs/networking/network.md | 34 +- docs/networking/snapshot-store.md | 24 +- docs/process/gotchas.md | 10 +- docs/process/pr-review-gate.md | 6 +- docs/scheduler/ci.md | 18 +- docs/scheduler/coordinator.md | 124 +- docs/scheduler/jobq.md | 20 +- docs/scheduler/observability.md | 94 +- docs/swarm/README.md | 48 +- docs/swarm/ca.md | 18 +- docs/swarm/secrets.md | 66 +- docs/swarm/services.md | 31 +- docs/swarm/sso.md | 16 +- docs/swarm/ui.md | 20 +- docs/tools/README.md | 2 +- docs/tools/bash.md | 6 +- docs/tools/hivectl.md | 6 +- docs/tools/lifecycle.md | 2 +- docs/tools/swarmctl-cli.md | 65 +- docs/trust-boundary/boundary.md | 18 +- docs/trust-boundary/security.md | 32 +- docs/turn-loop/claude-invocation.md | 29 +- docs/turn-loop/config.md | 14 +- docs/turn-loop/mcp.md | 3 +- docs/web-ui.md | 2 +- docs/web-ui/README.md | 4 +- docs/web-ui/design-guide.md | 10 +- frontend/packages/agent/build.mjs | 60 +- frontend/packages/agent/src/Root.tsx | 197 +- frontend/packages/agent/src/agent.css | 318 +++- .../src/components/ExpandDetailsSetting.tsx | 11 +- .../packages/agent/src/components/Header.tsx | 19 +- .../agent/src/components/HeaderPill.tsx | 18 +- .../agent/src/components/InboxPanel.tsx | 50 +- .../agent/src/components/LiveStream.tsx | 176 +- .../agent/src/components/LoginFlow.tsx | 57 +- .../packages/agent/src/components/MetaNav.tsx | 42 +- .../packages/agent/src/components/Row.tsx | 51 +- .../agent/src/components/SidePanel.tsx | 27 +- .../agent/src/components/StatusChips.tsx | 54 +- .../agent/src/components/TermInput.tsx | 138 +- .../agent/src/components/TodosPanel.tsx | 39 +- frontend/packages/agent/src/css.d.ts | 2 +- .../packages/agent/src/hooks/useAgentState.ts | 12 +- .../packages/agent/src/hooks/useLiveStream.ts | 110 +- frontend/packages/agent/src/hooks/useTodos.ts | 10 +- frontend/packages/agent/src/index.html | 33 +- .../packages/agent/src/lib/dashboardBase.ts | 4 +- frontend/packages/agent/src/lib/format.ts | 10 +- frontend/packages/agent/src/lib/linkify.tsx | 14 +- .../packages/agent/src/lib/loginAction.ts | 37 +- frontend/packages/agent/src/lib/markdown.ts | 15 +- .../packages/agent/src/lib/modelEffort.ts | 34 +- .../packages/agent/src/lib/pauseAction.ts | 12 +- .../packages/agent/src/lib/termActions.ts | 41 +- frontend/packages/agent/src/lib/termMsg.ts | 4 +- .../packages/agent/src/lib/useConfirmClick.ts | 2 +- frontend/packages/agent/src/main.tsx | 6 +- frontend/packages/agent/src/screen.html | 1672 ++++++++++------- frontend/packages/agent/src/stats.html | 114 +- frontend/packages/agent/src/stats.js | 377 ++-- frontend/packages/agent/src/types.ts | 10 +- frontend/packages/dashboard/build.mjs | 88 +- .../src/agent-menu/hive-agent-menu.js | 190 +- frontend/packages/dashboard/src/builds.css | 4 +- frontend/packages/dashboard/src/builds.html | 132 +- frontend/packages/dashboard/src/builds.js | 550 ++++-- frontend/packages/dashboard/src/call.js | 345 ++-- frontend/packages/dashboard/src/common.css | 342 +++- frontend/packages/dashboard/src/common.js | 402 ++-- frontend/packages/dashboard/src/core.css | 13 +- frontend/packages/dashboard/src/core.html | 102 +- frontend/packages/dashboard/src/core.js | 414 ++-- .../packages/dashboard/src/credentials.css | 117 +- .../packages/dashboard/src/credentials.html | 347 ++-- .../packages/dashboard/src/credentials.js | 455 +++-- frontend/packages/dashboard/src/dashboard.css | 441 +++-- .../packages/dashboard/src/dashboard.html | 421 +++-- frontend/packages/dashboard/src/flow.css | 16 +- frontend/packages/dashboard/src/flow.html | 88 +- frontend/packages/dashboard/src/flow.js | 261 +-- frontend/packages/dashboard/src/home.css | 8 +- frontend/packages/dashboard/src/home.js | 58 +- frontend/packages/dashboard/src/index.html | 186 +- frontend/packages/dashboard/src/logs.css | 71 +- frontend/packages/dashboard/src/logs.html | 158 +- frontend/packages/dashboard/src/logs.js | 159 +- .../packages/dashboard/src/permissions.js | 285 +-- frontend/packages/dashboard/src/schedules.js | 1060 +++++++---- frontend/packages/dashboard/src/stats.html | 94 +- frontend/packages/dashboard/src/stats.js | 143 +- .../packages/dashboard/src/stream-worker.js | 41 +- frontend/packages/dashboard/src/swarm.js | 703 ++++--- .../dashboard/src/system-sections.css | 66 +- frontend/packages/dashboard/src/tabs.js | 205 +- frontend/packages/dashboard/src/util.js | 37 +- .../src/api-error-panel/ApiErrorPanel.tsx | 20 +- frontend/packages/shared/src/api-error.ts | 18 +- frontend/packages/shared/src/badge/Badge.css | 10 +- frontend/packages/shared/src/badge/Badge.tsx | 25 +- frontend/packages/shared/src/base.css | 12 +- frontend/packages/shared/src/chrome.css | 4 +- frontend/packages/shared/src/colors.css | 4 +- frontend/packages/shared/src/dom.js | 4 +- .../packages/shared/src/dropdown/Dropdown.css | 2 +- .../packages/shared/src/dropdown/Dropdown.tsx | 36 +- frontend/packages/shared/src/forms.js | 55 +- .../packages/shared/src/hive-btn/hive-btn.css | 12 +- .../packages/shared/src/hive-btn/hive-btn.js | 16 +- .../shared/src/hive-dialog/hive-dialog.css | 31 +- .../shared/src/hive-dialog/hive-dialog.js | 79 +- .../shared/src/hive-menu/hive-menu.css | 13 +- .../shared/src/hive-menu/hive-menu.js | 62 +- .../shared/src/hive-toast/hive-toast.css | 21 +- .../shared/src/hive-toast/hive-toast.js | 18 +- .../shared/src/hive-warn/hive-warn.css | 9 +- .../shared/src/hive-warn/hive-warn.js | 8 +- frontend/packages/shared/src/index.js | 2 +- .../shared/src/jobq-graph/JobqGraph.tsx | 138 +- .../shared/src/jobq-graph/jobq-graph.css | 52 +- .../shared/src/jobq-rollup/JobqRollup.tsx | 35 +- .../shared/src/jobq-rollup/jobq-rollup.css | 8 +- frontend/packages/shared/src/modal.js | 118 +- frontend/packages/shared/src/prefs.ts | 6 +- .../shared/src/settings/SettingsMenu.tsx | 51 +- .../shared/src/settings/motion-apply.ts | 18 +- .../shared/src/settings/settings-storage.ts | 12 +- .../shared/src/settings/theme-apply.ts | 18 +- frontend/packages/shared/src/shadow-css.js | 4 +- .../shared/src/side-panel/hive-side-panel.css | 21 +- .../shared/src/side-panel/hive-side-panel.js | 137 +- .../shared/src/tabs/hive-tab-strip.js | 38 +- frontend/packages/shared/src/tabs/tabs.css | 4 +- frontend/packages/shared/src/tabs/tabs.js | 22 +- .../packages/shared/src/terminal/terminal.css | 131 +- .../packages/shared/src/terminal/terminal.js | 249 ++- frontend/packages/shared/src/theme.css | 18 +- .../shared/src/warn-banner/WarnBanner.css | 9 +- .../shared/src/warn-banner/WarnBanner.tsx | 18 +- frontend/packages/swarm-ui/build.mjs | 44 +- frontend/packages/swarm-ui/src/App.tsx | 16 +- frontend/packages/swarm-ui/src/css.d.ts | 2 +- frontend/packages/swarm-ui/src/index.html | 28 +- frontend/packages/swarm-ui/src/main.tsx | 6 +- .../swarm-ui/src/pages/AgentsPage.tsx | 74 +- .../swarm-ui/src/pages/ComponentsPage.tsx | 134 +- .../swarm-ui/src/pages/CreateAgentForm.tsx | 94 +- .../packages/swarm-ui/src/pages/HivesPage.tsx | 62 +- .../swarm-ui/src/pages/IssueReportPage.tsx | 233 ++- .../packages/swarm-ui/src/pages/JobsPage.tsx | 23 +- .../packages/swarm-ui/src/shell/LinksMenu.css | 6 +- .../packages/swarm-ui/src/shell/LinksMenu.tsx | 27 +- .../packages/swarm-ui/src/shell/Shell.css | 12 +- .../packages/swarm-ui/src/shell/Shell.tsx | 67 +- .../packages/swarm-ui/src/shell/UserMenu.css | 6 +- .../packages/swarm-ui/src/shell/UserMenu.tsx | 71 +- .../swarm-ui/src/ui/button/Button.tsx | 14 +- .../swarm-ui/src/ui/dialog/Dialog.tsx | 17 +- .../swarm-ui/src/ui/form-field/FormField.tsx | 4 +- .../packages/swarm-ui/src/ui/panel/Panel.tsx | 4 +- .../ui/refresh-interval/RefreshInterval.tsx | 27 +- .../src/ui/relative-time/RelativeTime.tsx | 12 +- .../src/ui/select-field/SelectField.tsx | 2 +- .../packages/swarm-ui/src/ui/table/Table.tsx | 6 +- .../swarm-ui/src/ui/text-field/TextField.tsx | 4 +- frontend/packages/swarm-ui/src/util.ts | 13 +- hive-agent-sock/README.md | 6 +- hive-agent/prompts/system.md | 2 +- hive-core-agent-sock/README.md | 4 +- hive-forge-notify/README.md | 2 +- hive-forge/README.md | 2 +- hive-jobq/README.md | 8 +- hive-priv/README.md | 18 +- hive-screen-mcp/README.md | 14 +- hive-sh4re/README.md | 4 +- hive-sock-client/README.md | 4 +- .../hive-forge/theme-catppuccin-vibec0re.css | 561 ++++-- .../swarm-grafana/dashboards/agents.json | 29 +- .../swarm-grafana/dashboards/authelia.json | 31 +- .../swarm-grafana/dashboards/bao.json | 31 +- .../dashboards/claude-usage.json | 53 +- .../swarm-grafana/dashboards/forge.json | 70 +- .../swarm-grafana/dashboards/logstore.json | 15 +- .../swarm-grafana/dashboards/metricstore.json | 7 +- .../swarm-grafana/dashboards/queue.json | 27 +- swagger-ui-theme/hyperhive-theme.css | 4 +- swagger-ui-theme/index.html | 24 +- swagger-ui-theme/swagger-initializer.js | 20 +- swarm-authelia-bridge/README.md | 4 +- swarm-controller/README.md | 8 +- swarm-nats-auth/README.md | 12 +- swarm-queue-client/README.md | 4 +- swarmctl/README.md | 20 +- 203 files changed, 10075 insertions(+), 6070 deletions(-) diff --git a/claude-plugins/plugins/base/skills/claude-subagents/SKILL.md b/claude-plugins/plugins/base/skills/claude-subagents/SKILL.md index e5f5e2a7..4305eae2 100644 --- a/claude-plugins/plugins/base/skills/claude-subagents/SKILL.md +++ b/claude-plugins/plugins/base/skills/claude-subagents/SKILL.md @@ -33,7 +33,7 @@ claude --name --model --dangerously-skip-permissi by name for follow-ups. - **`--model `** - think about which model the task actually needs; don't spend a bigger model's tokens than your own on - mechanical work a cheaper one handles fine. Never use a *bigger* model + mechanical work a cheaper one handles fine. Never use a _bigger_ model than yourself for a sub-agent - if the task needs that much capability, it's not the "mechanical batch" case this skill is for. - **`--dangerously-skip-permissions`** - required in headless (`-p`) @@ -68,7 +68,7 @@ work while the sub-agent grinds. cases: "leave it as-is where genuinely unclear; do not guess." - **Ask for a report file** - per-item results + anything skipped and why, so you can verify without re-deriving. -- **Tune on ONE item first**, eyeball the result, fix the prompt, *then* +- **Tune on ONE item first**, eyeball the result, fix the prompt, _then_ turn it loose on the full batch. A prompt bug replicated across 100 items is 100 cleanups. @@ -98,7 +98,7 @@ running at once instead of handing the whole thing to one. loop. - **Mind the container's memory cap before picking N.** Your whole container shares one `MemoryMax` (a few GB by default) with every - subagent you spawn *and* your own process. A `claude` process plus its + subagent you spawn _and_ your own process. A `claude` process plus its MCP servers can hold several hundred MB to ~1GB depending on the task; spawning a dozen at once on a small container doesn't just slow things down, it can OOM the whole container — taking your own diff --git a/claude-plugins/plugins/base/skills/forge-issue-filing/SKILL.md b/claude-plugins/plugins/base/skills/forge-issue-filing/SKILL.md index deef37d5..641eec13 100644 --- a/claude-plugins/plugins/base/skills/forge-issue-filing/SKILL.md +++ b/claude-plugins/plugins/base/skills/forge-issue-filing/SKILL.md @@ -15,7 +15,7 @@ steps in the right order. ## 1. Check for a duplicate before filing `hive-forge list` has a server-side full-text `--search` flag that covers -title *and* body - use it before writing anything: +title _and_ body - use it before writing anything: ```sh hive-forge list --search "keyword or two" --state all @@ -43,8 +43,8 @@ Prefer naming the broken behavior or missing capability over a specific error string or one-off symptom - "hive-forge list has no way to filter by milestone" beats "list command confusing" or "can't find issues for milestone 11 easily". If you're not sure which framing is more durable, -lean toward whatever a colleague hitting the *same underlying gap* through -a *different* symptom would still recognize. +lean toward whatever a colleague hitting the _same underlying gap_ through +a _different_ symptom would still recognize. ## 3. Body: what's wrong, not how to fix it diff --git a/claude-plugins/plugins/base/skills/forge-triage/SKILL.md b/claude-plugins/plugins/base/skills/forge-triage/SKILL.md index 267f0d20..d0dec39e 100644 --- a/claude-plugins/plugins/base/skills/forge-triage/SKILL.md +++ b/claude-plugins/plugins/base/skills/forge-triage/SKILL.md @@ -20,7 +20,7 @@ dimension directly. hardcoded, so check `repo-labels` first if you don't already know the scopes in use. - **PRs with no formally requested reviewer** - `hive-forge lint - no-reviewer` flags PRs with zero requested reviewers at all; add +no-reviewer` flags PRs with zero requested reviewers at all; add `--reviewer ` to instead flag PRs where that specific person isn't among the requested reviewers. This checks the forge's actual reviewer-request state, not a text `@name` mention anywhere in the @@ -42,12 +42,13 @@ dimension directly. Run the checks relevant to what you're verifying rather than assuming one covers everything - "is triage caught up" usually means unassigned -+ unlabeled at minimum, with no-reviewer added if reviews matter for -your workflow. Each verb supports `--json` if you want to fold the -results into something else instead of reading the human-readable output. + +- unlabeled at minimum, with no-reviewer added if reviews matter for + your workflow. Each verb supports `--json` if you want to fold the + results into something else instead of reading the human-readable output. This is reactive/on-demand coverage checking, not a scheduled rollup or -historical trend - if you need to track compliance *over time* (was +historical trend - if you need to track compliance _over time_ (was triage worse last week than this week), that's a different, bigger ask than running these checks - don't build that unprompted just because the checks exist. diff --git a/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md b/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md index cfe15be1..93b1baf7 100644 --- a/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md +++ b/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md @@ -6,7 +6,7 @@ description: Take a real screenshot of an HTML/CSS page from inside a container # Headless Screenshot "No browser in this container" usually means no browser is -*pre-installed*, not that one is unreachable. `nixpkgs#chromium` is a +_pre-installed_, not that one is unreachable. `nixpkgs#chromium` is a `nix shell` away, and a single headless invocation renders a page and writes a PNG without a running server, a display, or any scripted interaction library. @@ -65,7 +65,7 @@ peer agent's GUI-testing capability, try rendering it yourself first: This is a static render, not a browser automation tool. Verifying an interaction (a click, a hover state, a form submission) needs puppeteer/playwright or similar - reach for those only when the -question is genuinely about *behavior*, not appearance. A missing +question is genuinely about _behavior_, not appearance. A missing emoji/glyph rendering as a box in the screenshot is usually a font availability artifact of the headless environment, not a real bug - don't mistake one for the other when reporting results. @@ -80,7 +80,7 @@ judge icon/glyph layout, not just to note "there'd be an icon here"). - **Tofu boxes instead of emoji.** Plain `nixpkgs#chromium` has no color-emoji font, so any 🖥/📡/🔨-style glyph renders as an empty box. Add `nixpkgs#noto-fonts-color-emoji` to the `nix shell` - but a - `FONTCONFIG_FILE` that lists *only* the emoji dir throws away the + `FONTCONFIG_FILE` that lists _only_ the emoji dir throws away the base fonts and blanks all normal text instead, which is its own false alarm. Merge, don't override: ``` diff --git a/claude-plugins/plugins/base/skills/pr-review/SKILL.md b/claude-plugins/plugins/base/skills/pr-review/SKILL.md index 17e5e394..5ef618d9 100644 --- a/claude-plugins/plugins/base/skills/pr-review/SKILL.md +++ b/claude-plugins/plugins/base/skills/pr-review/SKILL.md @@ -10,7 +10,7 @@ work in your own style. That framing should hold throughout. ## Before you start -1. **Read the linked issue/task** - understand *why* the change exists, +1. **Read the linked issue/task** - understand _why_ the change exists, not just what it does. 2. **Check CI status first.** A failing build or test suite is an automatic block - don't write a detailed review of code that doesn't diff --git a/docs/agent-lifecycle/agent-hierarchy.md b/docs/agent-lifecycle/agent-hierarchy.md index a949eb28..425ef6d0 100644 --- a/docs/agent-lifecycle/agent-hierarchy.md +++ b/docs/agent-lifecycle/agent-hierarchy.md @@ -28,7 +28,7 @@ requester-as-parent edge written at its `init_config` approval (so agent, including the bootstrap container (`ruth`) — it's just another root. The manager is reparentable like any other agent; there's no "structurally root" carve-out. Its privileges live on its MCP socket, -not its tree position (see *Manager special-casing today* below). +not its tree position (see _Manager special-casing today_ below). ### Reparenting @@ -88,15 +88,15 @@ umount-old / mount-new / restart-cascade step. ## Planned topology semantics (once ancestor-based enforcement lands) -| operation | who can do it | -| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -| `kill` / `start` / `restart` / `update` (any descendant) | any ancestor | -| `request_init_config` (spawn a new child) | any agent, child added under self | -| config change via forge PR (any descendant's config) | any ancestor | -| `get_logs` (any descendant) | any ancestor | -| moderate reminders (cancel any open thread of a descendant) | any ancestor | -| `send` / `recv` routing | parent ↔ same-parent siblings ↔ self ↔ descendants; explicit allow-list for anyone else | -| `request_update_meta_inputs` (bump meta lock) | root agents only (today: just `manager`) | +| operation | who can do it | +| ----------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `kill` / `start` / `restart` / `update` (any descendant) | any ancestor | +| `request_init_config` (spawn a new child) | any agent, child added under self | +| config change via forge PR (any descendant's config) | any ancestor | +| `get_logs` (any descendant) | any ancestor | +| moderate reminders (cancel any open thread of a descendant) | any ancestor | +| `send` / `recv` routing | parent ↔ same-parent siblings ↔ self ↔ descendants; explicit allow-list for anyone else | +| `request_update_meta_inputs` (bump meta lock) | root agents only (today: just `manager`) | "Ancestor" walks `ContainerView.parent` chains; cycles are guarded by a visited-set at dispatch time (a malformed `topology.json` can't lock @@ -138,11 +138,11 @@ other agents don't: capability. - **Prompt/tools** — the system prompt uses `` / `` marker blocks, and a `Flavor::{Agent, - Manager}` switch picks the MCP tool allow-list claude sees. Both are +Manager}` switch picks the MCP tool allow-list claude sees. Both are already parametrised on a single flavour value, so the planned per-capability-group version (`cap:` prompt blocks + a matching tool allow-list) is additive rather than a rewrite. -- **State dirs** — *not* special-cased: `HYPERHIVE_STATE_DIR` is +- **State dirs** — _not_ special-cased: `HYPERHIVE_STATE_DIR` is injected uniformly via `systemd.globalEnvironment` for every container including the manager, so all token/state paths resolve through it the same way everywhere. diff --git a/docs/getting-started/setup.md b/docs/getting-started/setup.md index 49911e8b..802adbab 100644 --- a/docs/getting-started/setup.md +++ b/docs/getting-started/setup.md @@ -114,7 +114,7 @@ Nothing to run — it is served on the swarm apex decide whether you can actually open it: - **You are in `admins`** (step 3). The gateway asks authelia whether - you have a session; the rule that makes it mean *operator* wants the + you have a session; the rule that makes it mean _operator_ wants the group. Without it you log in and still get bounced. - **The name resolves to this host.** It is published to the hive's own resolver and to `/etc/hosts` when `gateway.localHostsEntry` is on; from diff --git a/docs/integrations/forge.md b/docs/integrations/forge.md index 43fd8488..10c15f01 100644 --- a/docs/integrations/forge.md +++ b/docs/integrations/forge.md @@ -112,7 +112,7 @@ On a **successful** broker delivery, `forge_notify` marks the thread read on forge straight away (`PATCH /notifications/threads/{id}`). The broker inbox is the durable work queue now — each delivered wake is a sqlite row with its own ack lifecycle — so the forge unread flag no -longer needs to track whether the agent has *processed* a +longer needs to track whether the agent has _processed_ a notification. Clearing it on delivery keeps forge's unread set **tiny by construction**: at rest it holds only threads that failed to deliver plus whatever arrived since the last 30s poll. @@ -132,19 +132,19 @@ own read-state is the only durable record this design needs. **Read-before-comment guard doesn't block a fresh wake.** hive-forge's read-before-comment guard (which keys off forge unread-state) does not force the agent to view a thread before commenting on it: the broker -wake already carries the notification body, so *delivery is the read*. +wake already carries the notification body, so _delivery is the read_. An agent that wants the full thread still runs `hive-forge comments` / `view`. **In-process dedupe (tiny, ephemeral).** A single-process map (thread id → last-delivered `updated_at`) guards the narrow window where a -mark-read call *transiently fails* and the thread reappears unread in +mark-read call _transiently fails_ and the thread reappears unread in the next poll before its `updated_at` bumps — so a flaky PATCH doesn't re-fire the wake. It is **not persisted** and resets on restart (forge read-state covers the durable case). Each poll prunes it to the ids in the single `limit=UNREAD_FETCH_LIMIT` (50) fetch page, so it can never exceed that many entries (a debug assertion pins the invariant; the -fetch limit and the bound are the same constant). A failed *delivery* +fetch limit and the bound are the same constant). A failed _delivery_ is left unread and out of the map, so it resurfaces next tick. Self-echo notifications (the agent's own writes, see below) are marked @@ -225,13 +225,13 @@ lookahead. Five shapes, distinguished by the notification's classification: -| Trigger | Wrapper | -| ----------------------------------- | --------------------------------------------------------------------------------- | +| Trigger | Wrapper | +| ----------------------------------- | ------------------------------------------------------------------------------ | | Comment on issue / PR | `[comment on PR #N owner/repo] title\nurl: ...\n\nauthor: body\nassignee: ...` | | Review submission | `[PR approved #N owner/repo] title\nurl: ...\n\nauthor: body\nassignee: ...` | -| New issue / PR | `[new PR #N owner/repo] title\nurl: ...\nassignee: ...` | -| Later activity (open, not creation) | `[activity on PR #N owner/repo] title\nurl: ...\nassignee: ...` | -| State change | `[PR merged #N owner/repo] title\nurl: ...\nassignee: ...` | +| New issue / PR | `[new PR #N owner/repo] title\nurl: ...\nassignee: ...` | +| Later activity (open, not creation) | `[activity on PR #N owner/repo] title\nurl: ...\nassignee: ...` | +| State change | `[PR merged #N owner/repo] title\nurl: ...\nassignee: ...` | The issue/PR's own description is deliberately never embedded here (only a comment/review body is — that's the actual new content a notification diff --git a/docs/integrations/github.md b/docs/integrations/github.md index 45a79996..04603978 100644 --- a/docs/integrations/github.md +++ b/docs/integrations/github.md @@ -109,7 +109,7 @@ Forgejo's notifications API is modelled on GitHub's, so one tolerant parse serves both: `id`, `repository.full_name`, `subject {title,url,latest_comment_url}` and `updated_at` line up field for field. The two real differences are absorbed by lenient -deserializers — GitHub sends the thread id as a *string* where Forgejo +deserializers — GitHub sends the thread id as a _string_ where Forgejo sends a number, and says `PullRequest` where Forgejo says `Pull`. Todo keys are prefixed `gh:` so a github thread id cannot collide with a forge one. @@ -118,16 +118,16 @@ Two host differences worth knowing before touching this code: - **Auth scheme, not just value.** Forgejo takes `Authorization: token `; GitHub wants `Bearer ` plus `Accept: - application/vnd.github+json`, `X-GitHub-Api-Version` and a +application/vnd.github+json`, `X-GitHub-Api-Version` and a `User-Agent`. Sending Forgejo's form to GitHub does not error — it - authenticates as *nobody* and silently drops to the unauthenticated + authenticates as _nobody_ and silently drops to the unauthenticated rate limit. The cheap way to tell the two apart is the rate-limit header: `x-ratelimit-remaining` near 5000 is an authenticated user, near 60 is anonymous. - **GitHub sets the cadence.** It returns `X-Poll-Interval` (60s in practice, slower than our own tick) and rate-limits callers who ignore it, so the loop re-arms to the server's interval whenever that is - *slower* than ours. A hint faster than our own tick is not a reason to + _slower_ than ours. A hint faster than our own tick is not a reason to poll harder. ⚠️ **This needs the `notifications` scope on the PAT.** A token minted diff --git a/docs/integrations/knowledge.md b/docs/integrations/knowledge.md index 604ad8be..12b1df16 100644 --- a/docs/integrations/knowledge.md +++ b/docs/integrations/knowledge.md @@ -42,7 +42,7 @@ hive-c0re maintains the local clone at `internal/knowledge` (see `docs/swarm/README.md` § Swarm-wide forge webhooks). On any push to main, including merge commits, it sends an event to every hive over the swarm queue and each hive runs `git - pull`, so agents see the new content on their next turn. +pull`, so agents see the new content on their next turn. A hive that is offline when the event is sent does not get it on reconnect — the periodic pull below is what closes that gap. So one diff --git a/docs/networking/network.md b/docs/networking/network.md index 653e264b..a8366ff5 100644 --- a/docs/networking/network.md +++ b/docs/networking/network.md @@ -43,13 +43,13 @@ untouched by any of it. └─────────┘ └─────────┘ └─────────┘ ``` -| container | netns | IPv4 | listens / reached via | -| -------------- | ----------------------- | -------------------- | -------------------------------------------------------------------------------------------- | -| `hive-gateway` | host (shared) | host addresses | nginx `:80`/`:443` (every vhost); dnsmasq `bridgeIp:53` + DHCP `:67` on the bridge | -| `hive-forge` | host (shared) | host addresses | forgejo `:3000` http, `:2222` git-ssh; fronted by the `forge.` vhost | -| `hive-matrix` | host (shared) | host addresses | tuwunel `:8008` (+ optional federation port); fronted by the matrix vhost | -| `hive-ci` | private, veth on bridge | DHCP pool | outbound only (runner → forge); no inbound surface | -| `h-` | private, veth on bridge | DHCP pool | web UI via UDS `/run/hive-agent/` → nginx sub-path; in-container UI port hashed 8100–8999 | +| container | netns | IPv4 | listens / reached via | +| -------------- | ----------------------- | -------------- | ----------------------------------------------------------------------------------------------- | +| `hive-gateway` | host (shared) | host addresses | nginx `:80`/`:443` (every vhost); dnsmasq `bridgeIp:53` + DHCP `:67` on the bridge | +| `hive-forge` | host (shared) | host addresses | forgejo `:3000` http, `:2222` git-ssh; fronted by the `forge.` vhost | +| `hive-matrix` | host (shared) | host addresses | tuwunel `:8008` (+ optional federation port); fronted by the matrix vhost | +| `hive-ci` | private, veth on bridge | DHCP pool | outbound only (runner → forge); no inbound surface | +| `h-` | private, veth on bridge | DHCP pool | web UI via UDS `/run/hive-agent/` → nginx sub-path; in-container UI port hashed 8100–8999 | The flows, end to end: @@ -57,7 +57,7 @@ The flows, end to end: host firewall (udp 67 hole) → dnsmasq pool → lease + router option. - **DNS** — agents and the service containers query `bridgeIp:53`; hive zones are answered authoritatively with the bridge IP, everything else - forwards to the host's resolvers (see *Resolver behaviour* below). Each + forwards to the host's resolvers (see _Resolver behaviour_ below). Each container points its own `resolv.conf` there, and one that instead inherits the host's resolves no swarm name at all — those records exist only on the bridge. @@ -169,7 +169,7 @@ agent containers. The **host** firewall is the only firewall. The shared-netns infra containers (gateway, forge, matrix) set `networking.firewall.enable = false`: a NixOS firewall inside a -shared-netns container runs against the *host* ruleset — at container +shared-netns container runs against the _host_ ruleset — at container boot its `firewall-start` flushes the `nixos-fw` chains, rebuilds them from the container's (empty) port list, and deletes the host's `nixos-nat-*` chains without recreating them, silently wiping the @@ -183,7 +183,7 @@ By default agents can only reach the host on 80/443 (+53 DNS), so a host-side service on another port — e.g. a dev OTLP collector you want agents to reach directly — is unreachable. (hyperhive's own telemetry needs none of this: `otel.enable` opens its collector's port itself, and -`otel.endpoint` is the *upstream*, which no agent ever dials. See +`otel.endpoint` is the _upstream_, which no agent ever dials. See `docs/scheduler/observability.md`.) `services.hyperhive.network.exposeHostPorts = [ 4318 ];` opens each @@ -206,12 +206,12 @@ Each agent container runs in a private network namespace with a dedicated veth pair attached to the bridge. The following table summarises what the nix side sets up unconditionally: -| effect | mechanism | -| -------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| IP forwarding | `boot.kernel.sysctl."net.ipv4.ip_forward" = 1` | -| Internet NAT | `networking.nat { enable = true; internalInterfaces = [ bridgeName ]; }` — MASQUERADE on packets leaving via any external NIC | -| Loopback DROP | `networking.firewall.extraInputRules` — drops bridge-subnet → `127.0.0.0/8` traffic; defence-in-depth against routing table leaks | -| Gateway access | `networking.firewall.interfaces..allowedTCPPorts = [ 80 443 ]` — lets isolated agents (private netns, veth on bridge) reach nginx on the host | +| effect | mechanism | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| IP forwarding | `boot.kernel.sysctl."net.ipv4.ip_forward" = 1` | +| Internet NAT | `networking.nat { enable = true; internalInterfaces = [ bridgeName ]; }` — MASQUERADE on packets leaving via any external NIC | +| Loopback DROP | `networking.firewall.extraInputRules` — drops bridge-subnet → `127.0.0.0/8` traffic; defence-in-depth against routing table leaks | +| Gateway access | `networking.firewall.interfaces..allowedTCPPorts = [ 80 443 ]` — lets isolated agents (private netns, veth on bridge) reach nginx on the host | | c0re signal | `HIVE_NETWORK_BRIDGE`, `HIVE_NETWORK_SUBNET` in `systemd.services.hive-c0re.environment` — both **required**; `hive-c0re` refuses to start without them | `HIVE_NETWORK_SUBNET` is the host-side bridge IP + prefix (e.g. @@ -262,7 +262,7 @@ wiring is runtime: **Why isolation is safe**: hive-c0re's control-plane sockets are unix domain sockets bind-mounted into containers, not network listeners — see -the *Control plane (no network)* bullet under [Network +the _Control plane (no network)_ bullet under [Network map](#network-map) above. `PRIVATE_NETWORK=1` has no effect on a path that never touches the network stack. diff --git a/docs/networking/snapshot-store.md b/docs/networking/snapshot-store.md index f15d6e55..8584fe13 100644 --- a/docs/networking/snapshot-store.md +++ b/docs/networking/snapshot-store.md @@ -43,8 +43,8 @@ Note that the mesh is gated on `swarm.wireguard.enable`, **not** on ## Pointing a hive at it -The block above configures the host that *receives*. Every hive that -*pushes* separately needs to be told where the store is: +The block above configures the host that _receives_. Every hive that +_pushes_ separately needs to be told where the store is: ```nix services.hyperhive.swarm.snapshotStore = { @@ -65,9 +65,9 @@ inconsistency: Note the option lives under `swarm.*` while the receiving host's lives under `services.hyperhive.snapshotStore`. That is the distinction the -two namespaces carry throughout: `swarm.*` describes *the swarm* as seen -from this host, and a bare `services.hyperhive.` describes *a -role this host performs*. A store host sets both --- one to run the +two namespaces carry throughout: `swarm.*` describes _the swarm_ as seen +from this host, and a bare `services.hyperhive.` describes _a +role this host performs_. A store host sets both --- one to run the receiver, one only if it also runs a hive that pushes. With it set, `hivectl agent subvol snapshot push