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:
parent
3606de1c23
commit
5db38a596e
29 changed files with 62 additions and 62 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ The summary depends on the room's unread state:
|
|||
|
||||
- **One unread message**: `[matrix] <sender> in <room>: <body> —
|
||||
use read_room to view, mark_read to clear`
|
||||
- **Several unread messages**: `[matrix] N unread in <room> —
|
||||
- **Multiple unread messages**: `[matrix] N unread in <room> —
|
||||
use read_room to view, mark_read to clear`
|
||||
|
||||
**Multi-account prefix**: when the daemon serves more than one account
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ renders it says so. Read the diff and the gate output regardless.
|
|||
parent that polls `status` sees the block without reading anything else.
|
||||
`continue` is how you answer it.
|
||||
|
||||
## Is it working, or is it wedged?
|
||||
## Telling working from wedged
|
||||
|
||||
`status` reporting **running** says the daemon tracks a process, which a
|
||||
wedged subagent satisfies as fully as a busy one. A running answer therefore
|
||||
|
|
@ -209,7 +209,7 @@ an age climbing into the minutes means it's stuck. That one number
|
|||
replaces inferring the same thing from `ps` output and CPU-time deltas.
|
||||
It resets at each turn's spawn, so on a goal run it describes the turn in
|
||||
flight rather than the run — which is what you want, since a run that's
|
||||
making progress spends several perfectly healthy minutes.
|
||||
making progress spends a few perfectly healthy minutes.
|
||||
|
||||
Every line the subagent's `claude` process writes bumps the timestamp —
|
||||
stream-json events, plain stdout chatter and stderr alike — and what the
|
||||
|
|
@ -432,7 +432,7 @@ worktree switching.
|
|||
|
||||
One rule worth knowing before editing any of this: **the daemon never
|
||||
emits an empty `--tools` value**, and asserts rather than doing so. Not
|
||||
because of what an empty value does — that's exactly the point. Our own
|
||||
because of what an empty value does — that's exactly the point. The hive's own
|
||||
measurement and the installed `claude --help` disagree about whether
|
||||
`--tools ""` means "no tools" or reads as the flag being absent, and the
|
||||
answer belongs to whichever claude release the system has installed
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ Each agent gets its own scoped credentials, never shared:
|
|||
|
||||
_Its own_ account's scope bounds a compromised/confused agent's reach on the
|
||||
forge or matrix, not the swarm's. This is the main thing standing
|
||||
between "one agent does something dumb" and "the whole hive is affected."
|
||||
between "one agent does something unwise" and "the whole hive is affected."
|
||||
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ services.hyperhive.agent.claudePluginsAutoUpdate = false; # defaul
|
|||
|
||||
- **`claudePluginsAutoUpdate`** — when `true`, runs
|
||||
`claude plugin marketplace update` before installing plugins to pull
|
||||
the latest index. Disabled by default to keep boot times short and
|
||||
the latest index. Off by default to keep boot times short and
|
||||
plugin versions pinned.
|
||||
|
||||
## `cargo.shortMessages`
|
||||
|
|
@ -265,7 +265,7 @@ is a no-op without the other:
|
|||
consolidated harness state file so the operator dashboard also stops reading this
|
||||
agent's empty `~/.claude/` as "needs login." An api-key agent that hits
|
||||
a real 401 (the key itself is bad) still surfaces `needs_login` — the
|
||||
harness skips only the boot-time "have I ever logged in" check, not
|
||||
harness skips only the boot-time check for an earlier login, not
|
||||
the auth-failure path.
|
||||
- **`backendEnvironmentFile`** points at an operator-managed file
|
||||
(outside the nix store, one `KEY=value` per line, systemd
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ JS renders — no full-page reloads.
|
|||
motion, theming, error-UX, and component-first principles for the
|
||||
swarm-level Preact app specifically (not this page's dashboard/agent
|
||||
UIs). `/components` on a running swarm-ui is the companion living
|
||||
demo of every primitive it references.
|
||||
demo of every building block it references.
|
||||
|
||||
### Implementation reading paths
|
||||
|
||||
|
|
@ -115,6 +115,6 @@ touching the code rather than using the UI:
|
|||
[`agent.md`](agent.md) (Terminal-embedded prompt).
|
||||
- **"What are the per-agent HTTP endpoints?"** →
|
||||
[`agent.md`](agent.md) (Per-agent endpoints).
|
||||
- **"Which CSS variable do I use / where are colours defined?"** →
|
||||
- **"Which CSS variable to use / where are colours defined?"** →
|
||||
[`css-vars.md`](css-vars.md) (Palette, single-source `base.css`
|
||||
rule).
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ and scrolls behind the fixed header + footer.
|
|||
`.agent-main`**, not in `log.parentElement = .terminal-wrap`:
|
||||
`.terminal-wrap` applies `backdrop-filter: blur` for the frost
|
||||
effect, which creates a CSS stacking context — anchoring the
|
||||
pill inside that context would trap its `z-index` below the
|
||||
pill inside that context would confine its `z-index` below the
|
||||
fixed composer in the root stacking context, and it'd never
|
||||
float. `.agent-main` has no backdrop-filter (no stacking-context
|
||||
creators), so the pill's `z-index` reaches the root and properly
|
||||
|
|
@ -259,8 +259,8 @@ Unknown `/foo` shows an error row instead of being silently sent.
|
|||
## Per-agent endpoints
|
||||
|
||||
Successful POSTs return 200 (no 303 redirects). Error responses
|
||||
use semantic status codes: **400** for missing/invalid input
|
||||
(`body` required, unknown model name, invalid effort level),
|
||||
use semantic status codes: **400** for missing/malformed input
|
||||
(`body` required, unknown model name, unrecognised effort level),
|
||||
**409** for retryable state conflicts (turn in flight when
|
||||
`/compact` fires), **500** only for genuine server/transport
|
||||
failures. The matching
|
||||
|
|
@ -358,7 +358,7 @@ shaped).
|
|||
dimensions; enabled once the server advertises the
|
||||
`ExtendedDesktopSize` pseudo-encoding (`-308` rect in the header).
|
||||
Fit-mode state persists in `localStorage` (`screen-fit`); default
|
||||
is on. `sendPointer` rescales pointer coordinates so clicks
|
||||
is on. `sendPointer` rescales pointer coordinates so presses
|
||||
land on the right pixel regardless of CSS scale.
|
||||
- `GET /screen/ws` — raw RFB byte relay: proxies WebSocket
|
||||
frames to the weston VNC server at `127.0.0.1:<vnc_port>`.
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ on the `openDialog` core:
|
|||
button takes focus). Selecting the backdrop and `Esc` both cancel.
|
||||
- `themedToast(message, { type, ... })` — a non-blocking toast (top-right,
|
||||
`info` / `error` / `ok`) for transient validation + action
|
||||
failures, so an error doesn't trap the operator behind a modal.
|
||||
failures, so an error doesn't lock the operator behind a modal.
|
||||
Single-action errors autodismiss; bulk / partial-failure
|
||||
summaries are sticky (select to dismiss) so they aren't missed.
|
||||
|
||||
|
|
@ -493,7 +493,7 @@ frosted-mauve bar slides up from the bottom of the viewport
|
|||
<!-- vale write-good.Passive = NO -->
|
||||
- **Count + names** — "N agents selected · name1, name2, …"
|
||||
- **Bulk action buttons** — only enabled when ALL selected agents
|
||||
support the action; disabled with a tooltip naming the blockers
|
||||
support the action; greyed out with a tooltip naming the blockers
|
||||
when the selection is mixed:
|
||||
- `↺ R3ST4RT` — running agents only
|
||||
- `■ ST0P` — running agents only
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ dashboard, which has its own older visual language). This doc is the
|
|||
_why_: the principles behind how swarm-ui looks and behaves, and the
|
||||
concrete rules that follow from them. It deliberately doesn't show what
|
||||
things look like — that's `ComponentsPage` (`/components`), the living,
|
||||
always-current demo of every primitive in `src/ui/`. Code can't go stale
|
||||
always-current demo of every building block in `src/ui/`. Code can't go stale
|
||||
the way a doc's screenshots can, so treat `ComponentsPage` as the source
|
||||
of truth for appearance and this doc as the source of truth for intent.
|
||||
Colour variables specifically are `docs/web-ui/css-vars.md`'s job, not
|
||||
|
|
@ -145,7 +145,7 @@ just bare column headers floating over nothing.
|
|||
|
||||
## Component-first design
|
||||
|
||||
Build the `src/ui/` primitive before or alongside the first real page
|
||||
Build the `src/ui/` building block before or alongside the first real page
|
||||
that needs it, not after a contributor styles it inline and leaves it
|
||||
for later — a page reaching for a component that's already there has ready-made
|
||||
blocks to build with, instead of the next contributor duplicating
|
||||
|
|
@ -157,10 +157,10 @@ option in a form uses `CheckboxField`, which sizes its row like the other
|
|||
fields, rather than a bare `<input type="checkbox">`.
|
||||
|
||||
**Every new `ui/` component gets a demo section on `/components` the
|
||||
same day it lands** — no primitive without a place to see it. One
|
||||
same day it lands** — no building block without a place to see it. One
|
||||
deliberate exception exists today: `FormField`, the internal label+
|
||||
control wrapper `TextField`/`SelectField` share, isn't itself a
|
||||
primitive a page reaches for directly, so it has no demo of its own —
|
||||
building block a page reaches for directly, so it has no demo of its own —
|
||||
a considered exception, not an oversight this rule missed.
|
||||
|
||||
## Attention
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ regardless, for example message-bearing tool_use, are unaffected either way).
|
|||
|
||||
**Sticky-bottom + snap animation.** `stickToBottom` is the
|
||||
operator's intent: true means "keep snapping to bottom on every
|
||||
mutation," false means "I scrolled up, leave me alone." The flag
|
||||
mutation," false means "the operator scrolled up, leave them alone." The flag
|
||||
flips when a scroll event lands further than `NEAR_BOTTOM_PX = 48`
|
||||
from the bottom. New rows then either snap to bottom (when sticky)
|
||||
or bump the unseen-count and surface the "↓ N new" pill. The snap
|
||||
|
|
|
|||
Loading…
Reference in a new issue