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)
|
- **Bringing a fresh swarm online?** → [`getting-started/setup.md`](getting-started/setup.md)
|
||||||
(the hand steps after the first switch).
|
(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;
|
[`web-ui/`](web-ui/README.md) — the operator-facing starting point;
|
||||||
its own sub-pages ([`shape`](web-ui/shape.md),
|
its own sub-pages ([`shape`](web-ui/shape.md),
|
||||||
[`dashboard`](web-ui/dashboard.md), [`agent`](web-ui/agent.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
|
- **How do I give an agent a GitHub account (`gh` + `git push`)? how's
|
||||||
the PAT injected?** → [`integrations/github.md`](integrations/github.md)
|
the PAT injected?** → [`integrations/github.md`](integrations/github.md)
|
||||||
(operator content up top; the `gh`/git-push + notification-poller
|
(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,
|
- **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
|
- **What does `hivectl` do? Provisioning, gateway users, container
|
||||||
shells?** → [`tools/hivectl.md`](tools/hivectl.md) (the curated guide);
|
shells?** → [`tools/hivectl.md`](tools/hivectl.md) (the curated guide);
|
||||||
[`tools/hivectl-cli.md`](tools/hivectl-cli.md) for the exhaustive,
|
[`tools/hivectl-cli.md`](tools/hivectl-cli.md) for the exhaustive,
|
||||||
|
|
@ -71,7 +71,7 @@ declarations.
|
||||||
discovery work?** → [`networking/gateway.md`](networking/gateway.md).
|
discovery work?** → [`networking/gateway.md`](networking/gateway.md).
|
||||||
- **How does DNS resolution work in agent containers? What's the
|
- **How does DNS resolution work in agent containers? What's the
|
||||||
bridge network for?** → [`networking/network.md`](networking/network.md).
|
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).
|
(peer hives, TLS trust).
|
||||||
- **Where do agent snapshots go? How does the swarm's `btrfs receive`
|
- **Where do agent snapshots go? How does the swarm's `btrfs receive`
|
||||||
endpoint authenticate a pushing hive?** →
|
endpoint authenticate a pushing hive?** →
|
||||||
|
|
@ -86,18 +86,18 @@ declarations.
|
||||||
sealed?** → [`swarm/bao.md`](swarm/bao.md).
|
sealed?** → [`swarm/bao.md`](swarm/bao.md).
|
||||||
- **How does an agent get a prompt at set times, and why doesn't it fire
|
- **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).
|
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).
|
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
|
- **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)
|
a full review?** → [`swarm/review-classifier.md`](swarm/review-classifier.md)
|
||||||
(planned, not implemented yet).
|
(planned, not implemented yet).
|
||||||
- **Does an agent config PR build before it's merged?** →
|
- **Does an agent config PR build before it's merged?** →
|
||||||
[`swarm/builder.md`](swarm/builder.md).
|
[`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).
|
settings?** → [`swarm/archetypes.md`](swarm/archetypes.md).
|
||||||
- **How long do CI runs take, per repo and PR, and where does the board get
|
- **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).
|
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?** →
|
stale stored copy log it out again?** →
|
||||||
[`swarm/claude-login.md`](swarm/claude-login.md).
|
[`swarm/claude-login.md`](swarm/claude-login.md).
|
||||||
- **How does an agent get a todo when someone assigns it an issue, and lose it
|
- **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).
|
queue sources, scheduler internals?** → [`scheduler/coordinator.md`](scheduler/coordinator.md).
|
||||||
- **How does the CI runner work? How does it register?** →
|
- **How does the CI runner work? How does it register?** →
|
||||||
[`scheduler/ci.md`](scheduler/ci.md).
|
[`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).
|
Prometheus/Grafana?** → [`scheduler/observability.md`](scheduler/observability.md).
|
||||||
|
|
||||||
## Crate reference
|
## Crate reference
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ system-level facts live.
|
||||||
degrades safely to "no agents" (covers a fresh install that hasn't
|
degrades safely to "no agents" (covers a fresh install that hasn't
|
||||||
synced yet).
|
synced yet).
|
||||||
- **Reconcile** — runs alongside the periodic meta/flake regeneration.
|
- **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
|
whose config repo exists but that haven't spawned yet, so the gap until
|
||||||
the container appears doesn't churn the file.
|
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
|
permissions alone, the same mechanism for every agent
|
||||||
([`docs/turn-loop/mcp.md`](../turn-loop/mcp.md)). Ruth's permissions
|
([`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.
|
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
|
injected uniformly via `systemd.globalEnvironment` for every
|
||||||
container including the manager, so all token/state paths resolve
|
container including the manager, so all token/state paths resolve
|
||||||
through it the same way everywhere.
|
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
|
An agent created from an [archetype](../swarm/archetypes.md) gets no
|
||||||
config repo: its hive builds it from the archetype's module.
|
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
|
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)).
|
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).
|
authoritative applied repo (see "Root-agent view of applied" below).
|
||||||
- Its socket comes from the generic per-agent registration, in the same
|
- Its socket comes from the generic per-agent registration, in the same
|
||||||
per-agent runtime dir as any other agent (`/run/hyperhive/agents/ruth/`),
|
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 =
|
**Migration note** (for older hosts): drop any `containers.root =
|
||||||
{ ... }` block from your host NixOS config, and any `services.hyperhive.ruthless`
|
{ ... }` 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
|
genuinely needs to interrupt an agent's turn loop, not because
|
||||||
anything live uses it today.
|
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
|
case (`ContainerCrash`, routed to the root agent via
|
||||||
`Coordinator::notify_manager`) — it no longer drives any agent turn at
|
`Coordinator::notify_manager`) — it no longer drives any agent turn at
|
||||||
all. `crash_watch` now only `tracing::warn!`s `"container crash
|
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
|
## 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.**
|
keeps its state, purging it doesn't.**
|
||||||
|
|
||||||
- **`DESTR0Y`** (the default action) stops and removes the container
|
- **`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
|
## 2 · Your SSO account
|
||||||
|
|
||||||
_On the host running authelia._ Until this runs, `auth.<swarm.domain>` serves
|
_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
|
```bash
|
||||||
swarmctl user add mara --display-name Mara --email mara@example.com --group admins
|
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
|
## 4 · Ruth
|
||||||
|
|
||||||
hive-c0re creates no agent at startup. You create ruth, the manager agent,
|
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`
|
opens the create form with `ruth` filled in and the `manage_root_agent`
|
||||||
permission checked: that permission mounts the other agents into her
|
permission checked: that permission mounts the other agents into her
|
||||||
container so she can recover them. The form declares her, creates 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)
|
### 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
|
- `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).
|
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;
|
best-effort enrichment fetches of server-provided subject URLs;
|
||||||
both unlikely; treated as fatal-to-the-task only).
|
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
|
modes (HTTP errors, parse errors, mark-read failures) are
|
||||||
best-effort: logged at debug/warn and retried next tick.
|
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`:
|
- **`services.hyperhive.swarm.matrix.gatewayHost != ""`** — same footgun as `forge.domain`:
|
||||||
empty string renders `.<hive>`-shaped garbage in both nginx
|
empty string renders `.<hive>`-shaped garbage in both nginx
|
||||||
`server_name` (treated as wildcard catch-all, surprising) and
|
`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.
|
a config assertion rejects empty string explicitly.
|
||||||
SSO is unconditional, so the three below are requirements of running a
|
SSO is unconditional, so the three below are requirements of running a
|
||||||
homeserver at all rather than of a setting:
|
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.
|
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).
|
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
|
and means it should get the treatment a backup host gets --- restricted
|
||||||
access, and a decision (rather than an omission) on encryption at rest.
|
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
|
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
|
non-backup-grade _controls_. Nobody puts a migration staging area on
|
||||||
the access-review list.
|
the access-review list.
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ namespace, not the wire surface.
|
||||||
|
|
||||||
## Recipient sentinels
|
## 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
|
meaning that ordinary agent labels can never collide with — agent
|
||||||
name validation rejects any character outside `[a-z0-9_-]`, so the
|
name validation rejects any character outside `[a-z0-9_-]`, so the
|
||||||
angle-bracket and asterisk shapes below are structurally safe.
|
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 -->
|
<!-- 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
|
to options the operator writes: **any** option of type `package` fed a
|
||||||
store-path _string_ coerces through `lib.toDerivation`, i.e.
|
store-path _string_ coerces through `lib.toDerivation`, i.e.
|
||||||
`builtins.storePath`. `environment.systemPackages` and
|
`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`.
|
Same reasoning as the best-effort oneshots in `docs/process/conventions.md`.
|
||||||
- **`[core] idle-time=0`**: disables weston's 300-second idle
|
- **`[core] idle-time=0`**: disables weston's 300-second idle
|
||||||
timeout. Without it the VNC desktop fades to black and
|
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
|
agent desktop viewed over `/screen`. `idle-time=0` updates the
|
||||||
idle timer with a 0ms delay, which
|
idle timer with a 0ms delay, which
|
||||||
`wl_event_source_timer_update` treats as "disarm," so the
|
`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 -->
|
<!-- 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
|
re-triggers), defined in
|
||||||
[`.forgejo/workflows/ci.yml`](../../.forgejo/workflows/ci.yml). The first four
|
[`.forgejo/workflows/ci.yml`](../../.forgejo/workflows/ci.yml). The first four
|
||||||
below are required checks (forge branch protection) — a hit on any of them
|
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.
|
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
|
### Mitigation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ resource/lease semantics).
|
||||||
|
|
||||||
hive-c0re submits every container operation (rebuild, first-spawn, power
|
hive-c0re submits every container operation (rebuild, first-spawn, power
|
||||||
changes) to the global job-DAG queue (`hive-c0re/src/job_queue/`)
|
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.
|
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
|
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
|
### 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
|
then filters on `level` **or** the matching `severity_text`, and the store
|
||||||
answers the second half. Each enabled rule appends an `OR
|
answers the second half. Each enabled rule appends an `OR
|
||||||
<field>:<op>"<value>"` term to the query a level button emits, beside the
|
<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")
|
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
|
`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
|
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
|
runs a `deltatocumulative` processor ahead of export, so a delta
|
||||||
`hive-metric` counter still lands in VictoriaMetrics as a cumulative
|
`hive-metric` counter still lands in VictoriaMetrics as a cumulative
|
||||||
series — the standard `rate()`/`increase()` idioms work on it exactly like
|
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 -->
|
<!-- 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
|
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
|
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).
|
[config-changes.md § Config changes](../agent-lifecycle/config-changes.md#config-changes).
|
||||||
A merge whose `closed` delivery never arrives deploys nothing either; the
|
A merge whose `closed` delivery never arrives deploys nothing either; the
|
||||||
operator recovers by redelivering that delivery from the forge hook page,
|
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.
|
restart, with the keys `init` printed.
|
||||||
|
|
||||||
⚠️ **A sealed store still answers.** The container is up and the port
|
⚠️ **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.
|
a store that was never initialised.
|
||||||
|
|
||||||
## TLS
|
## 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
|
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`
|
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
|
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
|
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
|
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
|
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
|
It answers only swarm-controller's OIDC client
|
||||||
(`swarm.controller.queueClientId`) and refuses every other token `403`.
|
(`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
|
first boot and never rotates them automatically; replacing one
|
||||||
invalidates data already written (sessions, the encrypted store), so
|
invalidates data already written (sessions, the encrypted store), so
|
||||||
that's an operator action.
|
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
|
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
|
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**
|
**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
|
and **Page Down** move through the options, and **Enter**, **Space** or a press take
|
||||||
the highlighted one. **Escape**, **Tab** or a click elsewhere shut the list without
|
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
|
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.
|
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 |
|
| `/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 |
|
| `/jobs` | the controller's job graph — where agent creation and credential mints show progress |
|
||||||
| `/schedules` | the scheduled prompts: add, edit, pause, resume and remove |
|
| `/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 |
|
| `/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 |
|
| `/issues` | a cross-repo issue report |
|
||||||
| `/review` | the review classifier: its recent runs, a try-out on a real PR, and its settings |
|
| `/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
|
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
|
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
|
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
|
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.
|
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
|
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`
|
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
|
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`)
|
### 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> —
|
- **One unread message**: `[matrix] <sender> in <room>: <body> —
|
||||||
use read_room to view, mark_read to clear`
|
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`
|
use read_room to view, mark_read to clear`
|
||||||
|
|
||||||
**Multi-account prefix**: when the daemon serves more than one account
|
**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.
|
parent that polls `status` sees the block without reading anything else.
|
||||||
`continue` is how you answer it.
|
`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
|
`status` reporting **running** says the daemon tracks a process, which a
|
||||||
wedged subagent satisfies as fully as a busy one. A running answer therefore
|
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.
|
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
|
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
|
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 —
|
Every line the subagent's `claude` process writes bumps the timestamp —
|
||||||
stream-json events, plain stdout chatter and stderr alike — and what the
|
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
|
One rule worth knowing before editing any of this: **the daemon never
|
||||||
emits an empty `--tools` value**, and asserts rather than doing so. Not
|
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
|
measurement and the installed `claude --help` disagree about whether
|
||||||
`--tools ""` means "no tools" or reads as the flag being absent, and the
|
`--tools ""` means "no tools" or reads as the flag being absent, and the
|
||||||
answer belongs to whichever claude release the system has installed
|
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
|
_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
|
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 -->
|
<!-- vale write-good.Passive = YES -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ services.hyperhive.agent.claudePluginsAutoUpdate = false; # defaul
|
||||||
|
|
||||||
- **`claudePluginsAutoUpdate`** — when `true`, runs
|
- **`claudePluginsAutoUpdate`** — when `true`, runs
|
||||||
`claude plugin marketplace update` before installing plugins to pull
|
`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.
|
plugin versions pinned.
|
||||||
|
|
||||||
## `cargo.shortMessages`
|
## `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
|
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
|
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
|
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.
|
the auth-failure path.
|
||||||
- **`backendEnvironmentFile`** points at an operator-managed file
|
- **`backendEnvironmentFile`** points at an operator-managed file
|
||||||
(outside the nix store, one `KEY=value` per line, systemd
|
(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
|
motion, theming, error-UX, and component-first principles for the
|
||||||
swarm-level Preact app specifically (not this page's dashboard/agent
|
swarm-level Preact app specifically (not this page's dashboard/agent
|
||||||
UIs). `/components` on a running swarm-ui is the companion living
|
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
|
### Implementation reading paths
|
||||||
|
|
||||||
|
|
@ -115,6 +115,6 @@ touching the code rather than using the UI:
|
||||||
[`agent.md`](agent.md) (Terminal-embedded prompt).
|
[`agent.md`](agent.md) (Terminal-embedded prompt).
|
||||||
- **"What are the per-agent HTTP endpoints?"** →
|
- **"What are the per-agent HTTP endpoints?"** →
|
||||||
[`agent.md`](agent.md) (Per-agent 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`
|
[`css-vars.md`](css-vars.md) (Palette, single-source `base.css`
|
||||||
rule).
|
rule).
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ and scrolls behind the fixed header + footer.
|
||||||
`.agent-main`**, not in `log.parentElement = .terminal-wrap`:
|
`.agent-main`**, not in `log.parentElement = .terminal-wrap`:
|
||||||
`.terminal-wrap` applies `backdrop-filter: blur` for the frost
|
`.terminal-wrap` applies `backdrop-filter: blur` for the frost
|
||||||
effect, which creates a CSS stacking context — anchoring the
|
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
|
fixed composer in the root stacking context, and it'd never
|
||||||
float. `.agent-main` has no backdrop-filter (no stacking-context
|
float. `.agent-main` has no backdrop-filter (no stacking-context
|
||||||
creators), so the pill's `z-index` reaches the root and properly
|
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
|
## Per-agent endpoints
|
||||||
|
|
||||||
Successful POSTs return 200 (no 303 redirects). Error responses
|
Successful POSTs return 200 (no 303 redirects). Error responses
|
||||||
use semantic status codes: **400** for missing/invalid input
|
use semantic status codes: **400** for missing/malformed input
|
||||||
(`body` required, unknown model name, invalid effort level),
|
(`body` required, unknown model name, unrecognised effort level),
|
||||||
**409** for retryable state conflicts (turn in flight when
|
**409** for retryable state conflicts (turn in flight when
|
||||||
`/compact` fires), **500** only for genuine server/transport
|
`/compact` fires), **500** only for genuine server/transport
|
||||||
failures. The matching
|
failures. The matching
|
||||||
|
|
@ -358,7 +358,7 @@ shaped).
|
||||||
dimensions; enabled once the server advertises the
|
dimensions; enabled once the server advertises the
|
||||||
`ExtendedDesktopSize` pseudo-encoding (`-308` rect in the header).
|
`ExtendedDesktopSize` pseudo-encoding (`-308` rect in the header).
|
||||||
Fit-mode state persists in `localStorage` (`screen-fit`); default
|
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.
|
land on the right pixel regardless of CSS scale.
|
||||||
- `GET /screen/ws` — raw RFB byte relay: proxies WebSocket
|
- `GET /screen/ws` — raw RFB byte relay: proxies WebSocket
|
||||||
frames to the weston VNC server at `127.0.0.1:<vnc_port>`.
|
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.
|
button takes focus). Selecting the backdrop and `Esc` both cancel.
|
||||||
- `themedToast(message, { type, ... })` — a non-blocking toast (top-right,
|
- `themedToast(message, { type, ... })` — a non-blocking toast (top-right,
|
||||||
`info` / `error` / `ok`) for transient validation + action
|
`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
|
Single-action errors autodismiss; bulk / partial-failure
|
||||||
summaries are sticky (select to dismiss) so they aren't missed.
|
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 -->
|
<!-- vale write-good.Passive = NO -->
|
||||||
- **Count + names** — "N agents selected · name1, name2, …"
|
- **Count + names** — "N agents selected · name1, name2, …"
|
||||||
- **Bulk action buttons** — only enabled when ALL selected agents
|
- **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:
|
when the selection is mixed:
|
||||||
- `↺ R3ST4RT` — running agents only
|
- `↺ R3ST4RT` — running agents only
|
||||||
- `■ ST0P` — 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
|
_why_: the principles behind how swarm-ui looks and behaves, and the
|
||||||
concrete rules that follow from them. It deliberately doesn't show what
|
concrete rules that follow from them. It deliberately doesn't show what
|
||||||
things look like — that's `ComponentsPage` (`/components`), the living,
|
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
|
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.
|
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
|
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
|
## 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
|
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
|
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
|
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">`.
|
fields, rather than a bare `<input type="checkbox">`.
|
||||||
|
|
||||||
**Every new `ui/` component gets a demo section on `/components` the
|
**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+
|
deliberate exception exists today: `FormField`, the internal label+
|
||||||
control wrapper `TextField`/`SelectField` share, isn't itself a
|
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.
|
a considered exception, not an oversight this rule missed.
|
||||||
|
|
||||||
## Attention
|
## Attention
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ regardless, for example message-bearing tool_use, are unaffected either way).
|
||||||
|
|
||||||
**Sticky-bottom + snap animation.** `stickToBottom` is the
|
**Sticky-bottom + snap animation.** `stickToBottom` is the
|
||||||
operator's intent: true means "keep snapping to bottom on every
|
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`
|
flips when a scroll event lands further than `NEAR_BOTTOM_PX = 48`
|
||||||
from the bottom. New rows then either snap to bottom (when sticky)
|
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
|
or bump the unseen-count and surface the "↓ N new" pill. The snap
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue