Watch
0
0
Fork
You've already forked hyperhive
0

docs: rephrase the vale warnings that have a better wording

Words the alex and Microsoft styles flag where a plainer one reads as well:
disabled/special/invalid as a state, primitive, trap, hang, several, click,
first-person FAQ questions, hyphenated adverb pairs. Left as they are: Let's
Encrypt, quoted UI labels and phrases, the generated forge CLI reference, and
the middle-click gesture.
This commit is contained in:
iris 2026-10-26 18:11:03 +01:00 • committed by mara
commit 5db38a596e
29 changed files with 62 additions and 62 deletions

View file

@ -13,7 +13,7 @@ declarations.
- **Bringing a fresh swarm online?** → [`getting-started/setup.md`](getting-started/setup.md)
(the hand steps after the first switch).
- **What does the dashboard look like, and how do I use it?** →
- **What does the dashboard look like, and how to use it?** →
[`web-ui/`](web-ui/README.md) — the operator-facing starting point;
its own sub-pages ([`shape`](web-ui/shape.md),
[`dashboard`](web-ui/dashboard.md), [`agent`](web-ui/agent.md),
@ -57,9 +57,9 @@ declarations.
- **How do I give an agent a GitHub account (`gh` + `git push`)? how's
the PAT injected?** → [`integrations/github.md`](integrations/github.md)
(operator content up top; the `gh`/git-push + notification-poller
mechanics are in a collapsed "Implementation" section at the bottom).
mechanics are in a collapsed section on how it is implemented at the bottom).
- **What's `/knowledge`? How does the swarm-wide knowledge repo sync,
and how do I contribute a document?** → [`integrations/knowledge.md`](integrations/knowledge.md).
and how to contribute a document?** → [`integrations/knowledge.md`](integrations/knowledge.md).
- **What does `hivectl` do? Provisioning, gateway users, container
shells?** → [`tools/hivectl.md`](tools/hivectl.md) (the curated guide);
[`tools/hivectl-cli.md`](tools/hivectl-cli.md) for the exhaustive,
@ -71,7 +71,7 @@ declarations.
discovery work?** → [`networking/gateway.md`](networking/gateway.md).
- **How does DNS resolution work in agent containers? What's the
bridge network for?** → [`networking/network.md`](networking/network.md).
- **How do I connect two hives into a swarm?** → [`swarm/`](swarm/README.md)
- **How are two hives connected into a swarm?** → [`swarm/`](swarm/README.md)
(peer hives, TLS trust).
- **Where do agent snapshots go? How does the swarm's `btrfs receive`
endpoint authenticate a pushing hive?** →
@ -86,18 +86,18 @@ declarations.
sealed?** → [`swarm/bao.md`](swarm/bao.md).
- **How does an agent get a prompt at set times, and why doesn't it fire
twice after downtime?** → [`swarm/schedules.md`](swarm/schedules.md).
- **How do I set an agent's model or effort from the swarm, and what happens
- **How to set an agent's model or effort from the swarm, and what happens
to its own pick?** → [`swarm/inference.md`](swarm/inference.md).
- **How will a PR get checked against its repo's own yes/no rules before
a full review?** → [`swarm/review-classifier.md`](swarm/review-classifier.md)
(planned, not implemented yet).
- **Does an agent config PR build before it's merged?** →
[`swarm/builder.md`](swarm/builder.md).
- **How do I create an agent from a ready-made set of permissions and
- **How to create an agent from a ready-made set of permissions and
settings?** → [`swarm/archetypes.md`](swarm/archetypes.md).
- **How long do CI runs take, per repo and PR, and where does the board get
it?** → [`swarm/ci-metrics.md`](swarm/ci-metrics.md).
- **How do I log an agent in to claude from the swarm UI, and why doesn't a
- **How to log an agent in to claude from the swarm UI, and why doesn't a
stale stored copy log it out again?** →
[`swarm/claude-login.md`](swarm/claude-login.md).
- **How does an agent get a todo when someone assigns it an issue, and lose it
@ -111,7 +111,7 @@ declarations.
queue sources, scheduler internals?** → [`scheduler/coordinator.md`](scheduler/coordinator.md).
- **How does the CI runner work? How does it register?** →
[`scheduler/ci.md`](scheduler/ci.md).
- **How do I export Claude Code metrics (tokens, cost, tool calls) to
- **How are Claude Code metrics (tokens, cost, tool calls) exported to
Prometheus/Grafana?** → [`scheduler/observability.md`](scheduler/observability.md).
## Crate reference

View file

@ -66,7 +66,7 @@ system-level facts live.
degrades safely to "no agents" (covers a fresh install that hasn't
synced yet).
- **Reconcile** — runs alongside the periodic meta/flake regeneration.
Adds newly-spawned agents, drops removed ones. Reconcile keeps agents
Adds newly spawned agents, drops removed ones. Reconcile keeps agents
whose config repo exists but that haven't spawned yet, so the gap until
the container appears doesn't churn the file.
@ -118,7 +118,7 @@ state dirs work as for every other agent.
permissions alone, the same mechanism for every agent
([`docs/turn-loop/mcp.md`](../turn-loop/mcp.md)). Ruth's permissions
are the default plus `manage_root_agent`, stored for her like any grant.
- **State dirs** — _not_ special-cased: `HYPERHIVE_STATE_DIR` is
- **State dirs** — _not_ treated as an exception: `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.

View file

@ -68,7 +68,7 @@ target hive to deploy it.
An agent created from an [archetype](../swarm/archetypes.md) gets no
config repo: its hive builds it from the archetype's module.
Changing what the template seeded isn't a special case: like every
Changing what the template seeded isn't an exception: like every
later change, it's a PR on that config repo, made from a clone and
merged by an operator on the forge (see [Config changes](#config-changes)).
@ -376,7 +376,7 @@ Differences from sub-agents:
authoritative applied repo (see "Root-agent view of applied" below).
- Its socket comes from the generic per-agent registration, in the same
per-agent runtime dir as any other agent (`/run/hyperhive/agents/ruth/`),
not a special manager-only path.
not a separate manager-only path.
**Migration note** (for older hosts): drop any `containers.root =
{ ... }` block from your host NixOS config, and any `services.hyperhive.ruthless`
@ -406,7 +406,7 @@ and nothing in the tree constructs it; this removal dropped the push path
genuinely needs to interrupt an agent's turn loop, not because
anything live uses it today.
**A previously-running container crashing** used to be exactly that
**A previously running container crashing** used to be exactly that
case (`ContainerCrash`, routed to the root agent via
`Coordinator::notify_manager`) — it no longer drives any agent turn at
all. `crash_watch` now only `tracing::warn!`s `"container crash

View file

@ -4,7 +4,7 @@ Where state lives, what survives what, and how it's bounded.
## For operators
The short answer to "will I lose anything": **destroying an agent
The short answer to "does anything disappear": **destroying an agent
keeps its state, purging it doesn't.**
- **`DESTR0Y`** (the default action) stops and removes the container

View file

@ -57,7 +57,7 @@ What the granter is, why it's root-equivalent, and the store's TLS:
## 2 · Your SSO account
_On the host running authelia._ Until this runs, `auth.<swarm.domain>` serves
a login page that refuses everyone: its only subject is a disabled placeholder.
a login page that refuses everyone: its only subject is an inactive placeholder.
```bash
swarmctl user add mara --display-name Mara --email mara@example.com --group admins
@ -95,7 +95,7 @@ settings. Leave it empty and agents refer to you by name only.
## 4 · Ruth
hive-c0re creates no agent at startup. You create ruth, the manager agent,
like any other: open the swarm UI start page and click the paperclip, which
like any other: open the swarm UI start page and select the paperclip, which
opens the create form with `ruth` filled in and the `manage_root_agent`
permission checked: that permission mounts the other agents into her
container so she can recover them. The form declares her, creates her

View file

@ -204,7 +204,7 @@ read directly without a delivery — same `mark_read` call, no wake.
### Activation gates (graceful no-ops)
The poller starts disabled and stays that way for any of:
The poller starts switched off and stays that way for any of:
- `HIVE_FORGE_URL` not set or not parseable as a URL (a hand-run
harness; hive-c0re sets it from `swarm.forge.domain` on every hive).
@ -215,7 +215,7 @@ The poller starts disabled and stays that way for any of:
best-effort enrichment fetches of server-provided subject URLs;
both unlikely; treated as fatal-to-the-task only).
Disabled = the spawned task returns immediately. All other failure
Switched off = the spawned task returns immediately. All other failure
modes (HTTP errors, parse errors, mark-read failures) are
best-effort: logged at debug/warn and retried next tick.

View file

@ -400,7 +400,7 @@ surprising behaviour:
- **`services.hyperhive.swarm.matrix.gatewayHost != ""`** — same footgun as `forge.domain`:
empty string renders `.<hive>`-shaped garbage in both nginx
`server_name` (treated as wildcard catch-all, surprising) and
`/etc/hosts` (invalid entry). `null` is the right opt-out shape;
`/etc/hosts` (malformed entry). `null` is the right opt-out shape;
a config assertion rejects empty string explicitly.
SSO is unconditional, so the three below are requirements of running a
homeserver at all rather than of a setting:

View file

@ -42,7 +42,7 @@ The catch-all `_` vhost answers any other `Host` with `444` (connection closed,
Only the host that **runs** authelia declares `auth.<swarm>`; a hive that merely uses SSO knows `swarm.authelia.url` but doesn't answer for that name. The server name must be exactly `swarm.authelia.domain` — authelia checks that `authelia_url` sits inside its session cookie domain at startup, and refuses to boot otherwise. The vhost carries no `auth_request` (that would put the login page behind the login it serves) and passes `X-Forwarded-{Proto,Host,Uri,For}`, because authelia decides by the original request.
⚠️ `auth.<swarm>` answering with the **sso unavailable** page means authelia isn't answering at all — check `journalctl -M swarm-authelia -u authelia-swarm`. While the user set is empty, a disabled placeholder user keeps authelia's user store non-empty, so it boots fine and serves a login page that refuses everyone; add the first account with `swarmctl user add …` ([`setup.md`](../getting-started/setup.md)).
⚠️ `auth.<swarm>` answering with the **sso unavailable** page means authelia isn't answering at all — check `journalctl -M swarm-authelia -u authelia-swarm`. While the user set is empty, an inactive placeholder user keeps authelia's user store non-empty, so it boots fine and serves a login page that refuses everyone; add the first account with `swarmctl user add …` ([`setup.md`](../getting-started/setup.md)).
Per-agent UIs stay sub-path; forge and matrix get sub-domains → [Sub-domain shape](#sub-domain-shape-rationale).

View file

@ -183,7 +183,7 @@ Which makes it the highest-value target in the swarm by a wide margin,
and means it should get the treatment a backup host gets --- restricted
access, and a decision (rather than an omission) on encryption at rest.
The trap is the label: this box holds backup-grade data while nobody
The pitfall is the label: this box holds backup-grade data while nobody
calls it a backup, so it can end up with backup-grade _exposure_ and
non-backup-grade _controls_. Nobody puts a migration staging area on
the access-review list.

View file

@ -88,7 +88,7 @@ namespace, not the wire surface.
## Recipient sentinels
The broker reserves a few recipient names, which have special
The broker reserves a few recipient names, which have a fixed
meaning that ordinary agent labels can never collide with — agent
name validation rejects any character outside `[a-z0-9_-]`, so the
angle-bracket and asterisk shapes below are structurally safe.

View file

@ -156,7 +156,7 @@ an input only because a docs tree has no runtime dependencies.
<!-- vale write-good.Passive = NO -->
The `storePath` trap is worth spelling out, because it's not confined
The `storePath` pitfall is worth spelling out, because it's not confined
to options the operator writes: **any** option of type `package` fed a
store-path _string_ coerces through `lib.toDerivation`, i.e.
`builtins.storePath`. `environment.systemPackages` and
@ -465,7 +465,7 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
Same reasoning as the best-effort oneshots in `docs/process/conventions.md`.
- **`[core] idle-time=0`**: disables weston's 300-second idle
timeout. Without it the VNC desktop fades to black and
desktop-shell shows its click-to-unlock screen — useless for an
desktop-shell shows its unlock screen — useless for an
agent desktop viewed over `/screen`. `idle-time=0` updates the
idle timer with a 0ms delay, which
`wl_event_source_timer_update` treats as "disarm," so the

View file

@ -40,7 +40,7 @@ internals, container design, and the full security writeup.
<!-- vale write-good.Passive = NO -->
Several jobs run on every PR (and on `workflow_dispatch` for manual
The 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
@ -270,7 +270,7 @@ A malicious `default.nix` or build script in a PR can therefore:
No forge admin token enters the container: swarm-controller holds it and publishes only the registration token, which only `swarm-ci-runner-register.service` loads, so a job step can't read it. A build process can still reach the forge over the network, and it runs as the runner's own user, so it can read `.runner` and act as this runner; it can't issue admin API calls.
Note: `nix flake check --no-build` (eval-only) reduces the attack surface but doesn't eliminate it — `builtins.fetchGit`, `builtins.fetchurl`, and import-from-derivation can reach the network and filesystem during evaluation. The CI workflow's `nix flake check` job builds every check derivation, which is the higher-risk path.
Note: `nix flake check --no-build` (eval-only) reduces the exposure but doesn't eliminate it — `builtins.fetchGit`, `builtins.fetchurl`, and import-from-derivation can reach the network and filesystem during evaluation. The CI workflow's `nix flake check` job builds every check derivation, which is the higher-risk path.
### Mitigation

View file

@ -16,11 +16,11 @@ resource/lease semantics).
hive-c0re submits every container operation (rebuild, first-spawn, power
changes) to the global job-DAG queue (`hive-c0re/src/job_queue/`)
as a **DAG of primitive nodes**. One scheduler task drives all DAGs;
as a **DAG of basic nodes**. One scheduler task drives all DAGs;
concurrency comes from the resource classes below, not from multiple workers.
Special cases like graceful stop, deferred starts, and the boot sweep
Exceptions like graceful stop, deferred starts, and the boot sweep
need no bespoke code paths — each takes the shape of a DAG built
from the same primitive nodes.
from the same basic nodes.
### Two levels: DAG and node

View file

@ -273,13 +273,13 @@ X" string to set, so mapping every level takes one rule each. A level button
then filters on `level` **or** the matching `severity_text`, and the store
answers the second half. Each enabled rule appends an `OR
<field>:<op>"<value>"` term to the query a level button emits, beside the
`level:…` term that matches nothing here. Clicking "info" goes from
`level:…` term that matches nothing here. Selecting "info" goes from
```
level:contains_common_case("info","information","informational","notice")
```
to that OR `severity_text:="INFO"`, which our rows do match.
to that OR `severity_text:="INFO"`, which the rows here do match.
`Unspecified` is deliberately left out of those rules. It's VictoriaLogs' own
rendering of an absent severity, and it's what the **Log rows with no
@ -684,6 +684,6 @@ unaffected either way; gauges have no temporality. The hive-tier collector
runs a `deltatocumulative` processor ahead of export, so a delta
`hive-metric` counter still lands in VictoriaMetrics as a cumulative
series — the standard `rate()`/`increase()` idioms work on it exactly like
any other counter in this system, no special query needed.
any other counter in this system, no extra query needed.
<!-- vale write-good.Passive = YES -->

View file

@ -436,7 +436,7 @@ them, and the notification router, not the controller, decides what they mean.
A `config-pr` delivery reporting a PR merged into `main` queues a deploy
of its `merge_commit_sha` on the one hive whose wanted state places the
agent; with no such hive, or several, the controller deploys nothing. See
agent; with no such hive, or more than one, the controller deploys nothing. See
[config-changes.md § Config changes](../agent-lifecycle/config-changes.md#config-changes).
A merge whose `closed` delivery never arrives deploys nothing either; the
operator recovers by redelivering that delivery from the forge hook page,

View file

@ -91,7 +91,7 @@ constrain what a policy says. What bounds it:
restart, with the keys `init` printed.
⚠️ **A sealed store still answers.** The container is up and the port
responds while every read times out — the failure looks like a hang, not like
responds while every read times out — the failure looks like a stall, not like
a store that was never initialised.
## TLS

View file

@ -72,7 +72,7 @@ A flow is a graph of nodes joined by edges: one `source` node naming the forge
event types it starts from, `match` nodes that pass when every condition
holds, `todo` nodes that emit one todo op per recipient, and `request_reviewer`
nodes that ask for a review. A match node can have more than one child, and
each one runs, so one event can reach several leaves. A flow must be a tree:
each one runs, so one event can reach more than one leaf. A flow must be a tree:
one source, one parent for every other node, every node reachable, no children
under a `todo` or a `request_reviewer`. The most is 64 nodes, 16
levels deep, and 100 custom flows. A `todo` node sends to the agents an event

View file

@ -128,7 +128,7 @@ publishes it as
It answers only swarm-controller's OIDC client
(`swarm.controller.queueClientId`) and refuses every other token `403`.
On first boot this module seeds the users database with a disabled placeholder subject, so authelia has a non-empty store to start against before any real account exists (`swarm-authelia.nix:873`). Authelia generates session and storage keys in the container on
On first boot this module seeds the users database with an inactive placeholder subject, so authelia has a non-empty store to start against before any real account exists (`swarm-authelia.nix:873`). Authelia generates session and storage keys in the container on
first boot and never rotates them automatically; replacing one
invalidates data already written (sessions, the encrypted store), so
that's an operator action.

View file

@ -13,10 +13,10 @@ sign-out pages; the hive dashboard and the per-agent page have the same menu.
Every dropdown (a form's select, the refresh interval, the history window) opens a
list in the swarm UI's own theme, not the browser's, and works the same in every
current browser. Open it with a click, or with the arrow keys, **Enter** or
current browser. Open it with a press, or with the arrow keys, **Enter** or
**Space** while it has focus. Then the arrow keys, **Home**, **End**, **Page Up**
and **Page Down** move through the options, and **Enter**, **Space** or a click take
the highlighted one. **Escape**, **Tab** or a click elsewhere shut the list without
and **Page Down** move through the options, and **Enter**, **Space** or a press take
the highlighted one. **Escape**, **Tab** or a press elsewhere shut the list without
changing anything. Typing the start of an option's name picks it, also with the list
shut. A dropdown inside a dialog opens above the dialog and the dialog doesn't cut it off.
@ -29,7 +29,7 @@ shut. A dropdown inside a dialog opens above the dialog and the dialog doesn't c
| `/alerts` | the alerts the swarm's Grafana holds now: the firing ones, with a button for the pending, no-data and error ones and a link to Grafana's own alert list; read through the controller with a Viewer service-account token |
| `/jobs` | the controller's job graph — where agent creation and credential mints show progress |
| `/schedules` | the scheduled prompts: add, edit, pause, resume and remove |
| `/messages` | the swarm-wide message feed: every message between agents, and to them from the operator, reminders and compaction, with a history window and a filter on sender or recipient; a folded **broadcast** card above the feed sends one message to several agents at once |
| `/messages` | the swarm-wide message feed: every message between agents, and to them from the operator, reminders and compaction, with a history window and a filter on sender or recipient; a folded **broadcast** card above the feed sends one message to more than one agent at once |
| `/notifications` | the notification router's flows: a switch for each built-in, every flow drawn as a graph, and an editor for custom flows |
| `/issues` | a cross-repo issue report |
| `/review` | the review classifier: its recent runs, a try-out on a real PR, and its settings |
@ -488,7 +488,7 @@ its newest 100 builds, so a link to an older one shows a note instead.
The messages page (`/messages`) has a **broadcast** card above the message list. It
starts folded; select its header to open it. The card holds a composer that sends one message
to several agents at once, and the messages show up in the list below as they
to more than one agent at once, and the messages show up in the list below as they
go. Folding it again keeps what you typed and ticked. Pick the
agents from a grid of their icons. **running** shows the agents that report
themselves running and **all** shows every agent; the browser keeps the choice.

View file

@ -146,7 +146,7 @@ distinct output shape — pick by what you need:
Rule of thumb: **`view` first** when you're about to act on a thread (it
shows everything and clears the unread guard so your follow-up `comment`
isn't rejected); the JSON verbs (`issue`/`pr`) when a script needs one
field; `pr status` when the only question is "can I merge it."
field; `pr status` when the only question is whether it can merge.
### Contributing to a read-only repo (`clone` + `pr create --agit`)

Some files were not shown because too many files have changed in this diff Show more