Commit graph

4,541 commits

Author SHA1 Message Date
iris
74fb07c052 agent: fix non-interactive badges losing their pill shape in the status row 2026-09-13 19:33:55 +02:00
iris
e1858b277a swarm-ui: extend neon glow to the swarm brand name 2026-09-13 19:19:26 +02:00
iris
fefeaecbbf swarm-ui: neon glow on panel titles + the active nav tab
Ports the subtle text-shadow glow @hive/agent's and the dashboard's own
headline rule already use (both independently converged on
`text-shadow: 0 0 Npx color-mix(color, transparent)`), not their whole
uppercase+letter-spacing headline typography -- that's those UIs' own
look, swarm-ui never adopted it and this issue only asked for the glow.

- Panel titles: `currentColor`-based, since a panel title has no one
  fixed accent (some are dynamic, e.g. an agent's own name) -- a fixed
  --purple glow on plain --fg text would read as a mismatched halo.
- Active nav tab: each item's own `accent` (NAV_ITEMS), the same value
  its underline already uses, so the glow and the underline read as
  one accent rather than two that happen to agree.
2026-09-13 19:19:26 +02:00
damocles
16f86d24e7 ci: daily nix flake update workflow 2026-09-13 19:14:10 +02:00
damocles
6271d5db13 nix: inline the tls alias instead of a local let-binding 2026-09-13 18:55:19 +02:00
damocles
f09a942395 nix: point three modules' tlsCfg alias at the current hive-controller path 2026-09-13 18:55:19 +02:00
iris
9f8df505c6 swarm-ui: widen the agents page's shell body cap, same as issue report
AgentsPage's table view (and its list+detail split) hits the same
60em readable-line-length cap the issue report's wide table already
opts out of via shell-body-wide. Adds /agents to WIDE_BODY_ROUTES --
the allowlist's own comment already anticipated this, a future wide
page reaches for the same class rather than inventing its own cap.
2026-09-13 18:44:59 +02:00
iris
c43a457752 term_stream: drop hive from the URL, resolve it from agent_status
mara's review point on #4351: an agent isn't pinned to a hive forever
(it can move), so a URL naming one would go stale the moment it did.
Resolve the hive at request time from the agent-status bucket instead
-- the same source AgentStatusRow.hive already comes from -- rather
than trusting a caller-supplied value. Route is now
GET /api/agents/{name}/term/stream; a never-reported agent now answers
404 (no hive on record) instead of silently guessing.
2026-09-13 18:08:33 +02:00
iris
1d902a0992 swarm-controller: add GET /api/agents/{hive}/{name}/term/stream
hive-agent already publishes classified TermMsg rows to the core NATS
subject $SWARM.term.{hive}.{agent} -- live only, no retention, by
design. This endpoint subscribes that subject per request and relays
each row over SSE, opaque to this daemon (no TermMsg dependency, same
pass-through shape crate::status already uses for hive snapshots).

No replay/history: the publish side never grew JetStream retention, and
this route's own job (a live tail) never needed it.
2026-09-13 18:08:33 +02:00
damocles
77c3c656b2 subagents: add effort param, default to medium, document in skill 2026-09-13 17:45:42 +02:00
damocles
95898338fc hive-c0re: validate cascade agent names in meta_update_cascade_agents' fanout path too
extract validate_agent_names() and use it for both the parsed
agent-<name> inputs and run_meta_lock's pre-computed fanout list, so a
malformed name can't reach the new fast_forward_applied_main / lock_update
filesystem+git+forge-URL operations regardless of which of the two
sources it came from
2026-09-13 17:33:58 +02:00
damocles
c45d679a32 hive-c0re: fast-forward applied/<name>/main too, not just the one-shot relock
argus + mara (PR #4339 review): the previous commit's per-agent lock
relock is a one-shot effect on the single rebuild the cascade triggers
- applied/<name> never moves, so the next relock=true rebuild trigger
(the boot sweep, most notably) re-locks against applied/<name> and
reverts straight back to whatever it was stuck on. The fix didn't
outlive the transaction it ran in.

New forge::fast_forward_applied_main(name), sibling to the existing
reseed-only fetch_config_main_into_applied: for an applied repo that
already has a .git and just needs to catch up, force-set rather than
fast-forward-gated since there's no PR to review on this path either.
Called per cascade agent right after the relock, best-effort so one
unreachable agent repo doesn't block the others.

Once applied/<name>/main has actually moved, lock_update_for_rebuild's
override (always reads current applied/<name>/main, no ?rev pin)
naturally stays in sync on any later relock=true rebuild instead of
reverting.
2026-09-13 17:33:58 +02:00
damocles
f0ddbe49d0 hive-c0re: pull each meta-update cascade agent's own config-repo main
mara (hyperhive#4271): "whatever is on main is trusted and should be
pulled. dont make it periodic, just add it to the meta update when
choosing the agent."

A meta-input bump previously rebuilt every affected agent against
whatever applied/<name> was already locked to. Normally current, but
silently stale forever if a past deploy failed and nothing since
retried it — the manual meta-input trigger never special-cased that
either, since nothing wired it to check the config repo's live main at
all.

run_meta_lock now relocks each cascade agent's own input alongside the
originally-requested ones, against the input's declared source (the
forge URL) rather than the local applied/<name> mirror prepare_deploy
uses for a reviewed deploy — there's no PR to review on this path, so
nothing to gate. One combined lock_update call for the whole cascade:
simpler than per-agent isolation, at the cost of one broken/unreachable
agent repo failing the whole cascade relock rather than just that
agent (the separate top-level input bump above it is unaffected).

Known gap, not fixed here: applied/<name>'s own main/deployed/* tags
never advance from this path, only a real MergeConfigPr deploy does
that — so the audit trail stays as accurate as today, it just stops
being what actually got built.
2026-09-13 17:33:58 +02:00
atlas
e588b1803e hive-forge: comments total comes from the comments endpoint, not the issue object
fetch_total read issue_get_issue's comments field, Forgejo's running
counter on the Issue object that also increments for several
non-prose event kinds (review_request, issue_ref, comment_ref,
pull_push, ...) that issue_get_comments never returns. Diffing that
count against a fetched window reported drift that was never real: a
comment that would never be shown at any window size. Live repro on
PR #4333 (damocles's diagnosis on the issue): more_after: 2, both
events non-prose.

Fix: read the total straight off issue_get_comments's own
X-Total-Count header instead — the same endpoint that produces the
window, so the two populations can never drift apart again. Mirrors
timeline.rs's own fetch_total, which made the same move for its
endpoint first. fetch_head now captures the header from the request
it already makes (one fewer round trip in the --limit path); the
--tail/default path still probes once via page_size=1, same shape as
before but now scoped to the endpoint that actually produces the
window.

This also fixes the more serious half: fetch_tail derives its
pagination offset (which page holds the tail) from the same total, so
an inflated total didn't just skew the trailer's count, it could send
the offset math reaching for a page beyond the real thread's end,
returning fewer rows than requested or none at all when fetch_tail's
empty-page guard tripped. New test pins this against fetch_tail's
existing pagination-plan helper.

Refs #4335
2026-09-13 17:12:16 +02:00
iris
8464e50f3a swarm-grafana: surface subagent cost/turns on the agents dashboard
hive-subagent-mcp already stamps a subagent=<name> resource attribute
(alongside the parent's own agent=<name>) on every claude_code.* sample
a spawned subagent turn emits -- the label already existed, it just
wasn't plotted anywhere. Adds five panels: subagent cost, subagent
turns, subagent cost share (of all cost), cost by subagent name, and
cost by parent agent. No backend changes needed.
2026-09-13 16:40:20 +02:00
iris
ff97503367 swarm-grafana: add cost/tokens-by-agent panels to the claude usage dashboard
The dashboard already templated an $agent variable and broke turns and
active-time out by agent, but cost and token totals only split by
model, effort and query_source -- there was no panel answering "how
much did each agent spend/use", the aggregate-by-agent view mara asked
for.
2026-09-13 16:38:47 +02:00
damocles
3fad315ac3 hive-bash-mcp: drop the redundant output-path line from status's description
Same principle as the enum-enumeration fix, mara caught it in review:
the description said where full output lives, but format_task's own
answer already names the exact path when output was actually
truncated — the description doesn't need to say it too.
2026-09-13 15:56:10 +02:00
damocles
a54f711cc5 hive-bash-mcp: explain the status when returning it, not up front
Mirrors #4333's split on the sibling hive-subagent-mcp surface (mara's
ruling there, quoted on #4336: "dont explain all the possible states
that can be returned in the tool description. instead explain the
status when returning it").

status_explanation() carries what each TaskStatus means and what to do
about it, appended to every format_task answer. The status tool's
description shrinks to what it's for; a caller only ever sees one
state at a time and now learns what it means without cross-referencing
anything else.
2026-09-13 15:48:28 +02:00
atlas
ae84174e3a subagent daemon: explain the status when returning it, not up front
The `status` tool description enumerated all five states it can report, so
every caller paid for four answers it didn't get and read the explanation
in the wrong place. The description now states only what the tool is for
and that it costs nothing to call; each answer it returns carries its own
meaning and the caller's next move instead — running, starting and idle
were terse, the not-found error terser still, and they had been leaning on
the enumeration to be legible. The killed answer and the end-of-turn todo
are unchanged. `continue`'s description keeps its killed-resume sentence:
that describes what the tool does, not a state it might hand back.

Refs #4326
2026-09-13 15:23:25 +02:00
atlas
0bdee751b9 subagent daemon: address review on the killed-session docs
argus's review on #4333 flagged one real vale error (Microsoft.Contractions):
"did not" in the new "A killed turn" section reads as "didn't" instead. The
rest of the diff's new prose (docs/tools/subagent.md and the tool
descriptions in hive-subagent-mcp/src/mcp.rs) has no other instance of the
same expansion, confirmed both by a local `vale --minAlertLevel=error` run
(clean) and by grepping the added lines. Also tidies session.rs's module doc:
the two `//!` runs split to dodge the 30-line comment-block lint had a bare
trailing `//!` right before the blank separator; dropped so the first run
ends on content.

Refs #4326
2026-09-13 15:15:38 +02:00
atlas
f817e27d4c subagent daemon: report a killed session as killed, not idle
A subagent whose claude process died on a signal — the kernel's OOM
killer, a stopped unit, an `interrupt` — was indistinguishable from one
that finished its turn: its entry left the `running` map, `status` fell
through to "a session exists on disk" and answered `idle`, and the
end-of-turn todo said the subagent had "finished". The usual next move
on that reading is `continue`, which resumes work that was cut mid-turn
with nothing having recorded that it was cut.

The driver already preserves how the child ended — `RunningClaude::wait`
returns `Error::Exit` carrying the `ExitStatus`, whose `signal()` is the
whole answer — so this reads it rather than having to recover it:
`classify_end` turns the outcome into `Complete` / `Killed { signal }` /
`Failed`, and `State::finish_turn` remembers a kill against the name
(cleared by the next confirmed spawn under it).

What an agent sees as a result:

- `status` reports the session killed, naming the signal, instead of idle;
- the todo the daemon pushes without being asked says the subagent was
  KILLED mid-turn rather than that it finished;
- `continue` still resumes such a session, but its reply says the
  previous turn was killed, so no caller carries on from cut-off work
  believing it was complete.

Refs #4326
2026-09-13 14:58:45 +02:00
atlas
fde4a36b93 module-eval: pin the log store's machine query route and its absences
Three cases beside the existing ingest ones, since the read route has the
same trap and one property of its own.

- the route exists and carries `auth_request`;
- it has no login fallback — with the browser location as the positive
  control, so a pass means the two routes differ rather than that
  `error_page` and the login host are absent from the whole vhost;
- it injects no filter, on `extraConfig` and on `proxyPass` both, because
  VictoriaLogs takes its filters as request parameters and those ride an
  upstream URI as easily as a directive. A filter arriving later is then a
  visible diff here rather than a quiet change of rule.

Each absence arm leads with a clause that proves the location resolved and
that `hasInfix` finds what is really in that string, so "not there" cannot
be read off an unreadable path.

Refs #3870
2026-09-13 14:36:15 +02:00
atlas
d275238dc4 swarm-victorialogs: add a machine-facing query location on the gateway
An agent can reach the log store only through the gateway, and the only
location that exists for a reader is `/`, which is the operator's browser
route. That route ends in `error_page 401 =302`, and an unauthenticated
caller which follows the redirect gets authelia's login page as HTTP 200
with an HTML body — so a client that checks the status code records a query
that succeeded and matched no logs. Measured on the live gateway; it is the
root cause behind four operator round-trips already.

So the query API gets its own location, `^~ /select/logsql/`, with bare
`auth_request` and no login fallback: an unauthenticated caller gets a 401
it cannot mistake for an empty result. `^~` keeps it ahead of the `/`
catch-all and of any regex location added later, and it stops short of
`/select/vmui/`, which is the browser UI and stays on the browser route.

The query is forwarded unmodified — no filter parameter is injected, so any
authenticated caller reads the whole swarm's logs. That is the rule mara
set: read permissions are a later thing, and this location is where one
attaches when it exists.

Refs #3870
2026-09-13 14:36:15 +02:00
atlas
053340128b term_msg: carry the source event's time on every row
A terminal row published on `$SWARM.term.<hive>.<agent>` goes out bare,
with no envelope around it and no server-side stamp, so a subscriber had
nothing to place the row in time with beyond its own receipt clock —
wrong by the queue's latency and meaningless for anything read later
than live.

`TermMsg` gains `ts`, ISO 8601 UTC. `classify` takes the event's own
unix-seconds stamp and applies it to every row that event expands into,
so a row replayed out of sqlite says when it happened rather than when
it was read, and a row that sat in a lagging subscriber's buffer does
not lie about its time. The oversize degrade keeps it; only the body is
ever spent.

`TermEnvelope` stops duplicating `ts` and keeps `seq`: the dedup counter
is a real transport concern, the event's time is not, now that it rides
on the row. Nothing in the frontend read `envelope.ts` — only the type
declared it.

Refs #4321
2026-09-13 14:23:11 +02:00
damocles
349f7096ba subagents: fold hive-extra-mcp into hive-agent-sock per mara's rescoping 2026-09-13 13:57:53 +02:00
damocles
670e0ccad3 docs: drop the auto-injected hyphen vale flags 2026-09-13 13:57:53 +02:00
damocles
16eec3c314 subagents: add availableToSubagents opt-in toggle for extraMcpServers 2026-09-13 13:57:53 +02:00
atlas
33aa2bdbc8 subagent daemon: scope an OOM kill to the session that lost the draw
systemd's default OOMPolicy=stop tears the whole unit down the moment the
kernel kills any process in its cgroup, so a single over-large subagent
takes the daemon and every sibling session with it — measured on a live
agent, both units show OOMPolicy=stop today, which is exactly the "every
live subagent session was cut mid-turn" symptom.

That blast radius is also what would make the preceding commit a bad
trade: deliberately putting this unit first in the OOM queue is only an
improvement if losing one subagent isn't losing all of them. OOMPolicy=
continue scopes the loss to the process the kernel actually chose, and
leaves the daemon alive to report the kill instead of vanishing and being
restarted with an empty session map.

Refs #4316
2026-09-13 13:05:17 +02:00
atlas
d249468db2 agent: make the OOM killer prefer a subagent over the agent's own turn
Both units ran at OOMScoreAdjust=0, so under container memory pressure the
kernel picked purely on footprint — and the agent's own claude is often
the fattest process in the container, which means the session supervising
the work died before the work did.

The sign is the load-bearing part and is easy to invert: a HIGHER
OOMScoreAdjust means MORE likely to be killed, because the kernel adds it
to the badness score it derives from the process's memory footprint and
then kills the highest scorer. So hive-subagent-daemon gets +500 (first in
line) and hive-agent gets -500 (last in line). Written backwards this
makes the reported bug worse rather than better, so module-eval pins the
order as an inequality.

Both values are inherited by the nested claude each unit spawns as a
child, so ordering the units orders the sessions underneath them. -500
rather than -1000 on the harness: fully exempting it would leave the
kernel nothing to kill in a container whose only large process is the
harness.

Refs #4316
2026-09-13 13:04:45 +02:00
atlas
4daab7efe4 subagent daemon: throttle at two thirds of the container's memory
The daemon spawns every nested claude as a plain child, so its cgroup is
already the "all subagents" cgroup — but it ran with MemoryHigh=infinity
and MemoryMax=infinity, so nothing slowed a subagent down before the
kernel's OOM killer stopped the unit and cut every live session with it.

MemoryHigh= and not MemoryMax=: a soft ceiling reclaims and stalls the
cgroup past two thirds of the container's cap, which turns a silent kill
into a visible throttle, while still letting a single subagent exceed its
share when the container has memory free. A hard per-agent cap would make
overprovisioning impossible, which is not wanted — most of the time
nothing in these sessions is compiling.

The fraction is taken from hyperhive.claudeMemoryMaxBytes, the container's
own effective MemoryMax= that meta.rs already bakes in per agent. When
that is null (an `infinity` or percentage cap) the unit renders no ceiling
rather than a fabricated constant, and module-eval pins both arms.

Refs #4316
2026-09-13 13:04:00 +02:00
atlas
d5d77e34b7 devshell: carry vale, so the CI prose lint is a local gate too
nix/devshell.nix didn't carry vale, so
 docs/README.md
 16:51  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 53:49  warning  'Multiple' is too wordy.                   write-good.TooWordy
 60:33  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 62:14  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 74:12  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson
 88:12  warning  Use first person (such as 'I') sparingly.  Microsoft.FirstPerson

 docs/agent-lifecycle/agent-hierarchy.md
 5:59    warning  'are meant' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 6:24    warning  'is finished' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 7:1     warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 23:36   warning  Consider 'stops responding' instead of 'hangs'.                                                                                                 Microsoft.BiasFree
 23:59   warning  'is built' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 35:53   warning  'is required' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 68:15   warning  'are approved' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 104:12  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 107:47  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 126:3   warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 135:15  warning  'be gated' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 144:26  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 153:31  warning  'is planned' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 157:32  warning  'is handled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 217:58  warning  'be owned' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive

 docs/getting-started/setup.md
 15:17   warning  'is generated' may be passive voice. Use active voice if you can.                                                                                                                     write-good.Passive
 51:38   warning  Consider using 'the app froze', 'the app stopped responding', 'the app stopped responding to events', or 'the app became unresponsive' instead of 'hang' (which may be insensitive).  alex.Suicide
 127:25  warning  'usually' is a weasel word!                                                                                                                                                           write-good.Weasel
 134:7   warning  'whether or not' is too wordy.                                                                                                                                                        write-good.TooWordy
 148:20  warning  'it was' is too wordy.                                                                                                                                                                write-good.TooWordy
 148:23  warning  'was minted' may be passive voice. Use active voice if you can.                                                                                                                       write-good.Passive
 160:23  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 163:40  warning  'is bound' may be passive voice. Use active voice if you can.                                                                                                                         write-good.Passive
 165:51  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 177:19  warning  'is issued' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 183:36  warning  'is tracked' may be passive voice. Use active voice if you can.                                                                                                                       write-good.Passive
 200:31  warning  'are gated' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 291:26  warning  'is stored' may be passive voice. Use active voice if you can.                                                                                                                        write-good.Passive
 297:22  warning  'is authenticated' may be passive voice. Use active voice if you can.                                                                                                                 write-good.Passive

 docs/integrations/github.md
 16:79  warning  'is needed' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/integrations/knowledge.md
 17:58  warning  'is read' may be passive voice. Use active voice if you can.     write-good.Passive
 56:61  warning  'is needed' may be passive voice. Use active voice if you can.   write-good.Passive
 94:3   warning  'is stopped' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/integrations/forge.md
 35:24   warning  'sufficient' is too wordy.                                                                                                                                     write-good.TooWordy
 109:54  warning  'are shared' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 160:19  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 171:1   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 331:1   warning  'subsequent' is too wordy.                                                                                                                                     write-good.TooWordy

 docs/integrations/matrix.md
 34:47   warning  'be changed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 76:16   warning  'are minted' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 172:67  warning  'is restricted' may be passive voice. Use active voice if you can.                                                                                            write-good.Passive
 200:61  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 202:22  warning  'is trusted' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 207:61  warning  'maximum' is too wordy.                                                                                                                                       write-good.TooWordy
 221:17  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 226:28  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 231:26  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 233:27  warning  'is required' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive

 docs/agent-lifecycle/persistence.md
 7:27    warning  Use first person (such as 'I') sparingly.                                                                                                       Microsoft.FirstPerson
 16:46   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 23:15   warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 26:62   warning  'however' is too wordy.                                                                                                                         write-good.TooWordy
 32:33   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 92:13   warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 127:17  warning  'was meant' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 177:23  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 185:6   warning  'modify' is too wordy.                                                                                                                          write-good.TooWordy
 249:38  warning  'is wedged' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 249:65  warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 278:5   warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 349:12  warning  'is read' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 356:11  warning  'be confused' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 359:55  warning  'are unrelated' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 413:43  warning  'been removed' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 415:59  warning  'be deleted' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 442:9   warning  'is automigrated' may be passive voice. Use active voice if you can.                                                                            write-good.Passive
 454:58  warning  'be removed' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 480:37  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 487:19  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 494:18  warning  'be started' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 582:51  warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 591:28  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive

 docs/agent-lifecycle/approvals.md
 34:36   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 141:43  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 150:42  warning  'is overloaded' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 174:44  warning  'Subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 190:27  warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 295:23  warning  'however' is too wordy.                                                                                                                         write-good.TooWordy
 500:47  warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy
 579:9   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 615:55  warning  'previously' is too wordy.                                                                                                                      write-good.TooWordy
 618:18  warning  'was cleared' may be passive voice. Use active voice if you can.                                                                                write-good.Passive

 docs/networking/network.md
 4:20    warning  'is enabled' may be passive voice. Use active voice if you can.    write-good.Passive
 10:52   warning  'were removed' may be passive voice. Use active voice if you can.  write-good.Passive
 18:61   warning  'is untouched' may be passive voice. Use active voice if you can.  write-good.Passive
 84:33   warning  'monitor' is too wordy.                                            write-good.TooWordy
 197:50  warning  'is unchanged' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/process/pr-review-gate.md
 44:1   warning  Use first person (such as 'I') sparingly.                          Microsoft.FirstPerson
 45:36  warning  'are expected' may be passive voice. Use active voice if you can.  write-good.Passive
 50:13  warning  'be armed' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/networking/snapshot-store.md
 126:49  warning  'being enabled' may be passive voice. Use active voice if you can.  write-good.Passive
 127:9   warning  'being set' may be passive voice. Use active voice if you can.      write-good.Passive
 131:15  warning  'sufficient' is too wordy.                                          write-good.TooWordy
 164:43  warning  'is discovered' may be passive voice. Use active voice if you can.  write-good.Passive
 178:5   warning  Reconsider using 'trap', it may be profane.                         alex.ProfanityMaybe
 178:67  warning  'being called' may be passive voice. Use active voice if you can.   write-good.Passive
 194:53  warning  'is wanted' may be passive voice. Use active voice if you can.      write-good.Passive
 200:1   warning  'therefore' is too wordy.                                           write-good.TooWordy
 201:5   warning  'is tracked' may be passive voice. Use active voice if you can.     write-good.Passive
 207:1   warning  'is bounded' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/scheduler/ci.md
 34:1     warning  'Several' is a weasel word!                                        write-good.Weasel
 37:7     warning  'are required' may be passive voice. Use active voice if you can.  write-good.Passive
 69:27    warning  'is stuck' may be passive voice. Use active voice if you can.      write-good.Passive
 131:98   warning  'validate' is too wordy.                                           write-good.TooWordy
 146:33   warning  'is set' may be passive voice. Use active voice if you can.        write-good.Passive
 186:55   warning  'therefore' is too wordy.                                          write-good.TooWordy
 188:422  warning  'is dropped' may be passive voice. Use active voice if you can.    write-good.Passive
 193:60   warning  Reconsider using 'attack', it may be profane.                      alex.ProfanityMaybe
 193:87   warning  'eliminate' is too wordy.                                          write-good.TooWordy
 249:58   warning  'however' is too wordy.                                            write-good.TooWordy

 docs/networking/gateway.md
 22:92    warning  'is misconfigured' may be passive voice. Use active voice if you can.                                                                                          write-good.Passive
 37:518   warning  'is closed' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 105:40   warning  When referring to a person, consider using 'careless', 'heartless', 'indifferent', or 'insensitive' instead of 'blind to'.                                     alex.Ablist
 140:44   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 142:4    warning  'subsequent' is too wordy.                                                                                                                                     write-good.TooWordy
 154:38   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 169:14   warning  'is configured' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 170:48   warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 177:15   warning  'is covered' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 182:9    warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 190:12   warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 206:122  warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 212:153  warning  'is named' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 224:185  warning  'be wired' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 226:235  warning  'terminate' is too wordy.                                                                                                                                      write-good.TooWordy
 230:150  warning  'validate' is too wordy.                                                                                                                                       write-good.TooWordy
 230:261  warning  'be added' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 232:165  warning  'is undisturbed' may be passive voice. Use active voice if you can.                                                                                            write-good.Passive
 234:199  warning  'is wired' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 238:36   warning  Try to avoid using first-person plural like 'Let's'.                                                                                                           Microsoft.We
 276:68   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 292:49   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.                 alex.Ablist
 299:41   warning  'is privileged' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 300:30   warning  'be exposed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 307:19   warning  'was removed' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 311:40   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 358:25   warning  'is left' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive
 361:11   warning  'are opened' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 363:52   warning  'is needed' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 393:40   warning  'requirement' is too wordy.                                                                                                                                    write-good.TooWordy
 501:13   warning  'is broken' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 513:68   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 528:1    warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 532:26   warning  'is exposed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 550:19   warning  'is required' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 586:18   warning  'therefore' is too wordy.                                                                                                                                      write-good.TooWordy
 592:24   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 620:7    warning  'is encrypted' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive

 docs/scheduler/jobq.md
 44:24  warning  'is done' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/process/conventions.md
 81:55   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist
 139:40  warning  'be handled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 140:8   warning  'is set' may be passive voice. Use active voice if you can.                                                                                     write-good.Passive
 189:31  warning  'are scoped' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 248:13  warning  'be shown' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 274:24  warning  'are kept' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 326:17  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 327:41  warning  'are pushed' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 394:55  warning  'Implement' is too wordy.                                                                                                                       write-good.TooWordy
 432:1   warning  'sufficient' is too wordy.                                                                                                                      write-good.TooWordy
 434:12  warning  'are factored' may be passive voice. Use active voice if you can.                                                                               write-good.Passive

 docs/process/gotchas.md
 18:46   warning  'are ignored' may be passive voice. Use active voice if you can.    write-good.Passive
 76:27   warning  'be started' may be passive voice. Use active voice if you can.     write-good.Passive
 93:3    warning  'enumerate' is too wordy.                                           write-good.TooWordy
 98:13   warning  'it was' is too wordy.                                              write-good.TooWordy
 98:16   warning  'was written' may be passive voice. Use active voice if you can.    write-good.Passive
 117:37  warning  'is needed' may be passive voice. Use active voice if you can.      write-good.Passive
 141:17  warning  Reconsider using 'trap', it may be profane.                         alex.ProfanityMaybe
 148:26  warning  'be wrapped' may be passive voice. Use active voice if you can.     write-good.Passive
 150:9   warning  'is expected' may be passive voice. Use active voice if you can.    write-good.Passive
 160:25  warning  'be reclaimed' may be passive voice. Use active voice if you can.   write-good.Passive
 161:28  warning  'are gone' may be passive voice. Use active voice if you can.       write-good.Passive
 180:36  warning  Use first person (such as 'my') sparingly.                          Microsoft.FirstPerson
 256:18  warning  'subsequent' is too wordy.                                          write-good.TooWordy
 324:46  warning  'are unused' may be passive voice. Use active voice if you can.     write-good.Passive
 355:59  warning  'was checked' may be passive voice. Use active voice if you can.    write-good.Passive
 425:29  warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 438:27  warning  Use 'select' instead of the input-specific verb 'click'.            Microsoft.UIVerbs
 484:23  warning  'is rooted' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/swarm/ca.md
 55:59   warning  'is expected' may be passive voice. Use active voice if you can.       write-good.Passive
 56:9    warning  'be ignored' may be passive voice. Use active voice if you can.        write-good.Passive
 65:60   warning  'are distributed' may be passive voice. Use active voice if you can.   write-good.Passive
 74:10   warning  'is issued' may be passive voice. Use active voice if you can.         write-good.Passive
 100:1   warning  'terminate' is too wordy.                                              write-good.TooWordy
 110:26  warning  'is allowed' may be passive voice. Use active voice if you can.        write-good.Passive
 145:31  warning  'is misconfigured' may be passive voice. Use active voice if you can.  write-good.Passive
 164:31  warning  'is assembled' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/scheduler/coordinator.md
 19:15   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.                                                             alex.Race
 20:61   warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 21:1    warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Special'.  alex.Ablist
 22:43   warning  'is expressed' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 23:21   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.                                                             alex.Race
 38:13   warning  'be written' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 81:268  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 81:354  warning  'is typed' may be passive voice. Use active voice if you can.                                                                                   write-good.Passive
 93:68   warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 102:17  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 112:25  warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 209:51  warning  'is satisfied' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 220:31  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 235:40  warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 241:1   warning  'exclusively' is too wordy.                                                                                                                     write-good.TooWordy
 244:5   warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 248:34  warning  'requirement' is too wordy.                                                                                                                     write-good.TooWordy
 256:51  warning  'acquire' is too wordy.                                                                                                                         write-good.TooWordy
 259:19  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 280:39  warning  'is tracked' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 343:24  warning  'be kept' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 399:67  warning  'finalize' is too wordy.                                                                                                                        write-good.TooWordy
 419:25  warning  'minimum' is too wordy.                                                                                                                         write-good.TooWordy
 424:71  warning  'subsequent' is too wordy.                                                                                                                      write-good.TooWordy
 476:21  warning  'is left' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 500:66  warning  'multiple' is too wordy.                                                                                                                        write-good.TooWordy
 558:40  warning  'is left' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 561:3   warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy

 docs/swarm/secrets.md
 3:23    warning  'are generated' may be passive voice. Use active voice if you can.  write-good.Passive
 7:23    warning  'all of' is too wordy.                                              write-good.TooWordy
 17:37   warning  'is published' may be passive voice. Use active voice if you can.   write-good.Passive
 32:42   warning  'is responsible for' is too wordy.                                  write-good.TooWordy
 38:106  warning  'is generated' may be passive voice. Use active voice if you can.   write-good.Passive
 46:110  warning  'is set' may be passive voice. Use active voice if you can.         write-good.Passive
 57:139  warning  'is set' may be passive voice. Use active voice if you can.         write-good.Passive
 70:78   warning  'is made' may be passive voice. Use active voice if you can.        write-good.Passive
 80:10   warning  'is made' may be passive voice. Use active voice if you can.        write-good.Passive
 80:36   warning  'is enabled' may be passive voice. Use active voice if you can.     write-good.Passive
 81:47   warning  'is registered' may be passive voice. Use active voice if you can.  write-good.Passive
 88:67   warning  'is fed' may be passive voice. Use active voice if you can.         write-good.Passive
 120:39  warning  'are required' may be passive voice. Use active voice if you can.   write-good.Passive
 167:44  warning  'is wanted' may be passive voice. Use active voice if you can.      write-good.Passive
 187:36  warning  'be fetched' may be passive voice. Use active voice if you can.     write-good.Passive
 207:34  warning  'therefore' is too wordy.                                           write-good.TooWordy
 212:24  warning  'is built' may be passive voice. Use active voice if you can.       write-good.Passive

 docs/swarm/README.md
 6:5     warning  'additional' is too wordy.                                          write-good.TooWordy
 6:51    warning  'multiple' is too wordy.                                            write-good.TooWordy
 21:24   warning  'be qualified' may be passive voice. Use active voice if you can.   write-good.Passive
 43:67   warning  'is enabled' may be passive voice. Use active voice if you can.     write-good.Passive
 50:10   warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 130:62  warning  Use first person (such as 'my') sparingly.                          Microsoft.FirstPerson
 131:1   warning  'is derived' may be passive voice. Use active voice if you can.     write-good.Passive
 158:34  warning  'was removed' may be passive voice. Use active voice if you can.    write-good.Passive
 168:10  warning  'be listed' may be passive voice. Use active voice if you can.      write-good.Passive
 171:52  warning  'is tracked' may be passive voice. Use active voice if you can.     write-good.Passive
 274:1   warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 278:48  warning  'is documented' may be passive voice. Use active voice if you can.  write-good.Passive
 293:66  warning  'is installed' may be passive voice. Use active voice if you can.   write-good.Passive
 377:41  warning  'is opened' may be passive voice. Use active voice if you can.      write-good.Passive
 388:39  warning  'been given' may be passive voice. Use active voice if you can.     write-good.Passive
 413:27  warning  'are expected' may be passive voice. Use active voice if you can.   write-good.Passive

 docs/scheduler/observability.md
 40:23   warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 60:24   warning  'all of' is too wordy.                                                                                                                          write-good.TooWordy
 64:48   warning  'be read' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 75:60   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 148:51  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 193:19  warning  'is needed' may be passive voice. Use active voice if you can.                                                                                  write-good.Passive
 205:22  warning  'therefore' is too wordy.                                                                                                                       write-good.TooWordy
 215:8   warning  'additional' is too wordy.                                                                                                                      write-good.TooWordy
 221:11  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 243:51  warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 251:11  warning  'is unauthenticated' may be passive voice. Use active voice if you can.                                                                         write-good.Passive
 256:11  warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                 write-good.Passive
 283:18  warning  'is measured' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 284:13  warning  'are measured' may be passive voice. Use active voice if you can.                                                                               write-good.Passive
 286:33  warning  'is gone' may be passive voice. Use active voice if you can.                                                                                    write-good.Passive
 311:49  warning  'equivalent' is too wordy.                                                                                                                      write-good.TooWordy
 351:59  warning  'be repeated' may be passive voice. Use active voice if you can.                                                                                write-good.Passive
 391:67  warning  'is unaffected' may be passive voice. Use active voice if you can.                                                                              write-good.Passive
 396:38  warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.  alex.Ablist

 docs/tools/README.md
 45:56  warning  'multiple' is too wordy.  write-good.TooWordy

 docs/swarm/ui.md
 45:63  warning  'were supposed' may be passive voice. Use active voice if you can.  write-good.Passive
 80:61  warning  'is scoped' may be passive voice. Use active voice if you can.      write-good.Passive

 docs/swarm/services.md
 20:61    warning  'be set' may be passive voice. Use active voice if you can.         write-good.Passive
 49:55    warning  'be set' may be passive voice. Use active voice if you can.         write-good.Passive
 79:1     warning  'are created' may be passive voice. Use active voice if you can.    write-good.Passive
 102:1    warning  'be restarted' may be passive voice. Use active voice if you can.   write-good.Passive
 123:48   warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 148:170  warning  'being written' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/bash.md
 26:61   warning  'is created' may be passive voice. Use active voice if you can.    write-good.Passive
 33:36   warning  'is created' may be passive voice. Use active voice if you can.    write-good.Passive
 58:53   warning  'is expected' may be passive voice. Use active voice if you can.   write-good.Passive
 128:40  warning  'is rendered' may be passive voice. Use active voice if you can.   write-good.Passive
 136:26  warning  'been removed' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/swarm/sso.md
 5:8     warning  'is declared' may be passive voice. Use active voice if you can.     write-good.Passive
 31:62   warning  'been enabled' may be passive voice. Use active voice if you can.    write-good.Passive
 70:21   warning  'multiple' is too wordy.                                             write-good.TooWordy
 98:61   warning  'is tabulated' may be passive voice. Use active voice if you can.    write-good.Passive
 118:14  warning  'is built' may be passive voice. Use active voice if you can.        write-good.Passive
 127:26  warning  'is broken' may be passive voice. Use active voice if you can.       write-good.Passive
 241:23  warning  'was verified' may be passive voice. Use active voice if you can.    write-good.Passive
 241:60  warning  'was introduced' may be passive voice. Use active voice if you can.  write-good.Passive
 257:42  warning  'are created' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/tools/lifecycle.md
 16:32  warning  'is preserved' may be passive voice. Use active voice if you can.  write-good.Passive
 55:1   warning  'Subsequent' is too wordy.                                         write-good.TooWordy

 docs/tools/forge.md
 21:8     warning  'is assumed' may be passive voice. Use active voice if you can.      write-good.Passive
 28:36    warning  'validate' is too wordy.                                             write-good.TooWordy
 35:18    warning  'be seen' may be passive voice. Use active voice if you can.         write-good.Passive
 35:43    warning  'is stated' may be passive voice. Use active voice if you can.       write-good.Passive
 40:3     warning  'are removed' may be passive voice. Use active voice if you can.     write-good.Passive
 45:22    warning  'validate' is too wordy.                                             write-good.TooWordy
 137:1    warning  'Multiple' is too wordy.                                             write-good.TooWordy
 144:144  warning  'are merged' may be passive voice. Use active voice if you can.      write-good.Passive
 154:51   warning  Use first person (such as 'I') sparingly.                            Microsoft.FirstPerson
 158:8    warning  'are read' may be passive voice. Use active voice if you can.        write-good.Passive
 178:61   warning  'be run' may be passive voice. Use active voice if you can.          write-good.Passive
 313:38   warning  'are structured' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/scheduling.md
 23:1   warning  'is set' may be passive voice. Use active voice if you can.      write-good.Passive
 25:45  warning  'multiple' is too wordy.                                         write-good.TooWordy
 33:8   warning  'are left' may be passive voice. Use active voice if you can.    write-good.Passive
 34:54  warning  'previously' is too wordy.                                       write-good.TooWordy
 46:31  warning  'is removed' may be passive voice. Use active voice if you can.  write-good.Passive
 96:16  warning  'minimum' is too wordy.                                          write-good.TooWordy

 docs/tools/matrix.md
 6:9     warning  'is configured' may be passive voice. Use active voice if you can.  write-good.Passive
 31:35   warning  'is inferred' may be passive voice. Use active voice if you can.    write-good.Passive
 32:34   warning  'is sent' may be passive voice. Use active voice if you can.        write-good.Passive
 46:20   warning  'enumerate' is too wordy.                                           write-good.TooWordy
 63:43   warning  'been invited' may be passive voice. Use active voice if you can.   write-good.Passive
 70:4    warning  'Multiple' is too wordy.                                            write-good.TooWordy
 74:64   warning  'is keyed' may be passive voice. Use active voice if you can.       write-good.Passive
 111:18  warning  'multiple' is too wordy.                                            write-good.TooWordy
 113:5   warning  'Multiple' is too wordy.                                            write-good.TooWordy
 130:51  warning  'was dropped' may be passive voice. Use active voice if you can.    write-good.Passive
 141:1   warning  'is cleared' may be passive voice. Use active voice if you can.     write-good.Passive
 149:39  warning  'additional' is too wordy.                                          write-good.TooWordy

 docs/tools/subagent.md
 44:11  warning  'are meant' may be passive voice. Use active voice if you can.   write-good.Passive
 44:24  warning  'be bounded' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/hivectl.md
 46:24   warning  'is created' may be passive voice. Use active voice if you can.   write-good.Passive
 100:53  warning  'is needed' may be passive voice. Use active voice if you can.    write-good.Passive
 136:67  warning  'is hoisted' may be passive voice. Use active voice if you can.   write-good.Passive
 157:38  warning  'equivalent' is too wordy.                                        write-good.TooWordy
 205:46  warning  'previously' is too wordy.                                        write-good.TooWordy
 222:1   warning  'requirement' is too wordy.                                       write-good.TooWordy
 224:12  warning  'were added' may be passive voice. Use active voice if you can.   write-good.Passive
 231:1   warning  'therefore' is too wordy.                                         write-good.TooWordy
 244:35  warning  'be consumed' may be passive voice. Use active voice if you can.  write-good.Passive
 245:52  warning  'is required' may be passive voice. Use active voice if you can.  write-good.Passive
 246:6   warning  'is given' may be passive voice. Use active voice if you can.     write-good.Passive

 docs/tools/swarmctl-cli.md
 70:62   warning  'multiple' is too wordy.                                            write-good.TooWordy
 119:19  warning  'was generated' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/hivectl-cli.md
 250:118  warning  'is created' may be passive voice. Use active voice if you can.     write-good.Passive
 506:331  warning  'is required' may be passive voice. Use active voice if you can.    write-good.Passive
 506:357  warning  'is given' may be passive voice. Use active voice if you can.       write-good.Passive
 644:9    warning  'is staged' may be passive voice. Use active voice if you can.      write-good.Passive
 907:19   warning  'was generated' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/tools/forge-cli.md
 146:68    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 176:192   warning  'is created' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 246:161   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 284:48    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 296:37    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 345:51    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 351:54    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 351:90    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 352:47    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 363:43    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 363:79    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 371:37    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 401:51    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 407:87    warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 418:40    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 461:159   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 483:78    warning  'are left' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 490:72    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 654:67    warning  'are left' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 706:161   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 744:48    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 756:37    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 805:55    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 811:54    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 811:90    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 812:47    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 823:43    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 823:79    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 831:37    warning  'is blocked' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 861:51    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 867:87    warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 878:40    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 921:159   warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 980:94    warning  'is given' may be passive voice. Use active voice if you can.                                                                                                      write-good.Passive
 988:84    warning  'be cloned' may be passive voice. Use active voice if you can.                                                                                                     write-good.Passive
 1041:76   warning  'in addition' is too wordy.                                                                                                                                        write-good.TooWordy
 1041:123  warning  'is set' may be passive voice. Use active voice if you can.                                                                                                        write-good.Passive
 1042:23   warning  'Maximum' is too wordy.                                                                                                                                            write-good.TooWordy
 1139:240  warning  When referring to a person, consider using 'correct', 'adequate', 'sufficient', 'consistent', 'valid', 'coherent', 'sensible', or 'reasonable' instead of 'sane'.  alex.Ablist
 1402:19   warning  'was generated' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive

 docs/trust-boundary/boundary.md
 5:32    warning  'is tracked' may be passive voice. Use active voice if you can.   write-good.Passive
 52:64   warning  'are served' may be passive voice. Use active voice if you can.   write-good.Passive
 58:61   warning  'be bound' may be passive voice. Use active voice if you can.     write-good.Passive
 60:62   warning  'is treated' may be passive voice. Use active voice if you can.   write-good.Passive
 99:27   warning  'is shared' may be passive voice. Use active voice if you can.    write-good.Passive
 112:13  warning  'is declared' may be passive voice. Use active voice if you can.  write-good.Passive
 122:46  warning  'therefore' is too wordy.                                         write-good.TooWordy
 124:15  warning  'all of' is too wordy.                                            write-good.TooWordy
 131:21  warning  'be opened' may be passive voice. Use active voice if you can.    write-good.Passive
 151:53  warning  'is added' may be passive voice. Use active voice if you can.     write-good.Passive
 157:4   warning  'equivalent' is too wordy.                                        write-good.TooWordy

 docs/web-ui/README.md
 107:17  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 131:28  warning  Use first person (such as 'I') sparingly.                                            Microsoft.FirstPerson

 docs/turn-loop/config.md
 107:8   warning  'additional' is too wordy.                                                                                                                                     write-good.TooWordy
 205:33  warning  'evaluate' is too wordy.                                                                                                                                       write-good.TooWordy
 219:21  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 263:42  warning  Use first person (such as 'I') sparingly.                                                                                                                      Microsoft.FirstPerson
 292:66  warning  'is documented' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive

 docs/trust-boundary/security.md
 13:1    warning  'is trusted' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 16:25   warning  'is privileged' may be passive voice. Use active voice if you can.                                               write-good.Passive
 17:61   warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 25:64   warning  'be stopped' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 39:35   warning  When referring to a person, consider using 'foolish', 'ludicrous', 'speechless', or 'silent' instead of 'dumb'.  alex.Ablist
 39:35   warning  Don't use 'dumb', it's profane.                                                                                  alex.ProfanityLikely
 39:61   warning  'is affected' may be passive voice. Use active voice if you can.                                                 write-good.Passive
 82:17   warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 91:57   warning  'equivalent' is too wordy.                                                                                       write-good.TooWordy
 196:24  warning  'therefore' is too wordy.                                                                                        write-good.TooWordy
 212:62  warning  'is tracked' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 226:49  warning  'be steered' may be passive voice. Use active voice if you can.                                                  write-good.Passive
 280:26  warning  'is scoped' may be passive voice. Use active voice if you can.                                                   write-good.Passive

 docs/turn-loop/mcp.md
 117:34  warning  'equivalent' is too wordy.                                                                                                                                     write-good.TooWordy
 143:3   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 219:8   warning  'is disallowed' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive

 docs/turn-loop/claude-invocation.md
 116:54  warning  'is gone' may be passive voice. Use active voice if you can.      write-good.Passive
 237:8   warning  'is shared' may be passive voice. Use active voice if you can.    write-good.Passive
 245:32  warning  'is set' may be passive voice. Use active voice if you can.       write-good.Passive
 247:30  warning  'are mounted' may be passive voice. Use active voice if you can.  write-good.Passive

 docs/web-ui/css-vars.md
 36:12   warning  'all of' is too wordy.  write-good.TooWordy
 141:35  warning  'all of' is too wordy.  write-good.TooWordy

 docs/web-ui/design-guide.md
 8:30    warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 18:24   warning  'multiple' is too wordy.                                                             write-good.TooWordy
 19:41   warning  'multiple' is too wordy.                                                             write-good.TooWordy
 34:30   warning  'minimize' is too wordy.                                                             write-good.TooWordy
 49:67   warning  'is hidden' may be passive voice. Use active voice if you can.                       write-good.Passive
 94:56   warning  'is hidden' may be passive voice. Use active voice if you can.                       write-good.Passive
 131:61  warning  'minimum' is too wordy.                                                              write-good.TooWordy
 145:21  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 149:55  warning  'consolidate' is too wordy.                                                          write-good.TooWordy
 155:26  warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race
 158:1   warning  Consider using 'simple', 'indigenous', or 'hunter-gatherer' instead of 'primitive'.  alex.Race

 docs/web-ui/shape.md
 41:17   warning  'is sanitized' may be passive voice. Use active voice if you can.    write-good.Passive
 127:51  warning  'are unaffected' may be passive voice. Use active voice if you can.  write-good.Passive
 131:46  warning  Use first person (such as 'me') sparingly.                           Microsoft.FirstPerson
 184:1   warning  'multiple' is too wordy.                                             write-good.TooWordy
 195:66  warning  'is sanitized' may be passive voice. Use active voice if you can.    write-good.Passive
 230:7   warning  'is hidden' may be passive voice. Use active voice if you can.       write-good.Passive
 232:32  warning  'are reused' may be passive voice. Use active voice if you can.      write-good.Passive
 247:43  warning  'is gone' may be passive voice. Use active voice if you can.         write-good.Passive
 253:1   warning  Use 'select' instead of the input-specific verb 'swipes'.            Microsoft.UIVerbs
 301:28  warning  'is set' may be passive voice. Use active voice if you can.          write-good.Passive

 docs/web-ui/agent.md
 49:62   warning  'multiple' is too wordy.                                                                                                                                      write-good.TooWordy
 75:21   warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 78:34   warning  Use 'select' instead of the input-specific verb 'click'.                                                                                                      Microsoft.UIVerbs
 95:59   warning  'are typed' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 131:34  warning  Reconsider using 'trap', it may be profane.                                                                                                                   alex.ProfanityMaybe
 135:43  warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 176:36  warning  'been removed' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 270:48  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 271:39  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'invalid'.  alex.Ablist
 273:12  warning  'is called' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 335:3   warning  'subsequent' is too wordy.                                                                                                                                    write-good.TooWordy
 367:35  warning  'minimum' is too wordy.                                                                                                                                       write-good.TooWordy
 377:56  warning  Use 'select' instead of the input-specific verb 'clicks'.                                                                                                     Microsoft.UIVerbs

 docs/web-ui/dashboard.md
 61:51    warning  'be confused' may be passive voice. Use active voice if you can.                                                                                               write-good.Passive
 183:32   warning  'equivalent' is too wordy.                                                                                                                                     write-good.TooWordy
 251:46   warning  'is checked' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 261:35   warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 314:25   warning  'is unchanged' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 342:29   warning  'is tooltipped' may be passive voice. Use active voice if you can.                                                                                             write-good.Passive
 386:13   warning  'however' is too wordy.                                                                                                                                        write-good.TooWordy
 447:50   warning  'is written' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 451:65   warning  'are named' may be passive voice. Use active voice if you can.                                                                                                 write-good.Passive
 466:22   warning  When referring to a person, consider using 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'special'.                 alex.Ablist
 524:29   warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'Disabled'.  alex.Ablist
 537:33   warning  'originally-active' doesn't need a hyphen.                                                                                                                     Microsoft.Hyphens
 763:29   warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 771:48   warning  'is enabled' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 778:14   warning  'all of' is too wordy.                                                                                                                                         write-good.TooWordy
 798:22   warning  'is stopped' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 830:3    warning  'multiple' is too wordy.                                                                                                                                       write-good.TooWordy
 856:16   warning  'exclusively' is too wordy.                                                                                                                                    write-good.TooWordy
 951:33   warning  Reconsider using 'trap', it may be profane.                                                                                                                    alex.ProfanityMaybe
 1016:23  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 1017:22  warning  'is mixed' may be passive voice. Use active voice if you can.                                                                                                  write-good.Passive
 1027:22  warning  When referring to a person, consider using 'turned off', 'has a disability', 'person with a disability', or 'people with disabilities' instead of 'disabled'.  alex.Ablist
 1028:63  warning  'satisfy' is too wordy.                                                                                                                                        write-good.TooWordy
 1038:9   warning  'multiple' is too wordy.                                                                                                                                       write-good.TooWordy
 1075:47  warning  'is set' may be passive voice. Use active voice if you can.                                                                                                    write-good.Passive
 1077:57  warning  'be created' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1109:50  warning  'is focused' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1256:17  warning  'is written' may be passive voice. Use active voice if you can.                                                                                                write-good.Passive
 1272:3   warning  'is sent' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive
 1273:15  warning  'previously' is too wordy.                                                                                                                                     write-good.TooWordy
 1286:3   warning  'is untouched' may be passive voice. Use active voice if you can.                                                                                              write-good.Passive
 1391:27  warning  'is gone' may be passive voice. Use active voice if you can.                                                                                                   write-good.Passive

✖ 0 errors, 493 warnings and 0 suggestions in 50 files. failed
with "vale: not found" even though hive-rules says to gate locally with
the devshell — a builder had to reconstruct CI's incantation by hand.

Local command: XDG_DATA_HOME=$PWD/.vale-data nix develop -c sh -c 'vale sync && vale docs'
2026-09-13 12:25:47 +02:00
atlas
cb2c90f32e swarm: present tense + no-queue-coordinates wording
The queue's payload ceiling was justified by what the queue was about to
carry; it carries it now, so the comment says so.

The other two sites say "a hive with no queue configured". The swarm has
exactly one queue and a hive cannot lack it — only its coordinates, its
credential, or its ability to reach it. That wording is already used
everywhere else the absence is named; these two predate it.

The docs section on the agents' queue coordinates stopped at delivering
them and never said what the connection is for. It now names the subject
and the degrade rule, which is the part an operator reading an agent's
terminal at the swarm needs.

Refs #3805
2026-09-13 12:01:58 +02:00
atlas
2cdd7f2ff1 hive-agent: publish the agent terminal to the swarm queue
The harness has had its queue coordinates since the credential reached
the container, but nothing used them. This offers each terminal row
upward on `$SWARM.term.<hive>.<agent>`, so a swarm-level terminal can
render an agent without reaching into the hive that hosts it.

It publishes the same `TermMsg` the web UI is handed rather than a
second model of the same events, so a new tool or a reclassified event
changes both surfaces together. It subscribes to the event bus rather
than to the SSE handler: the handler classifies per connected browser,
so hanging this off it would mean an agent nobody is watching publishes
nothing. That also means its own long-lived `ClassifyCtx`, since a
publisher restarting its correlation state would lose the `tool_use` →
name mapping a `tool_result` needs to render.

The hive in the subject is derived from the queue client id, not from
the harness's hive display name. Those come from different sources with
no rule tying them together, and the responder builds its grant from the
client id — so deriving it from the display name yields a publish the
broker refuses, reaching an operator as a terminal that is merely empty.
The prefix and suffix that bracket the hive are the responder's flags,
which the agent is not told; it restates their defaults, and the symptom
of a deployment retuning one without changing this is every publish
refused rather than a wrong subject accepted.

Oversize rows degrade in the publisher. Exceeding `max_payload` is not a
truncation: the server refuses the message and closes the connection, so
an oversize publish costs the row, the connection, and the rows racing
behind it through the reconnect. The body is the only unbounded field —
summaries are already trimmed at classification — so it is the field
spent, and the row keeps its icon, level, summary and coalesce key. A
row that does not fit even then is logged and dropped rather than sent.
The limit is read off the connection, so `8388608` stays spelled once in
the queue's own module; size is measured by serializing, because JSON
escaping separates character count from wire length by an unbounded
factor on exactly the rows already near the limit.

Best-effort throughout: no queue, an unparseable client id and a failed
connect each disable the publisher with one log line, and a failed
publish loses its row and nothing else. The turn loop and the web UI
never block on the queue.

Refs #3805
2026-09-13 11:59:55 +02:00
atlas
da7fbd20b8 swarm-queue-client: expose the announced payload limit
A publisher of variable-size rows has to size them against the server's
limit before it publishes, because exceeding it is not a truncation: the
server answers `Maximum Payload Violation` and closes the connection, so
the row is lost and the client reconnects.

The limit belongs to the queue's NixOS module, which is the only place
that chooses it. Reading it off the connection rather than restating it
as a constant keeps it spelled once — a client-side copy would be a
second opinion about a number it does not own, and would go stale the
day an operator raised the real one.

No test: the value comes from the server's INFO line, so anything
asserted about it without a running server would only be re-asserting
async-nats's own pre-connect default.

Refs #3805
2026-09-13 11:51:18 +02:00
atlas
767a863cf1 swarm-nats: grant agents their hive's terminal subject
The responder has had an agent arm since the principal was minted, but
no deployment ever passed `--agent-publish-subject`, and an empty list
is a refusal by design: `Policy::permissions` returns `None` rather than
a grant that can do nothing, so every agent was turned away at CONNECT.
The subject itself is the one this thread settled on, `$SWARM.term`
namespaced per hive.

The value has to reach the responder with a literal dollar. systemd
substitutes `$NAME` in `ExecStart` whether or not the word is quoted,
so a single dollar expands `SWARM` — unset, therefore empty — and the
responder is handed `.term.{hive}.>`. That grant validates (it carries
the `{hive}` placeholder), is accepted, and matches nothing any agent
publishes to, so the failure surfaces as an authorization violation far
from its cause. `$$` in the unit text is the escape for one dollar.

The module-eval case reads the rendered unit rather than the module
source, because the single-dollar version renders perfectly well; the
doubled dollar is the only thing that distinguishes them before deploy.

The grant is per-hive, not per-agent: an agent's identity names its
hive, so any agent in a hive can publish as another. That is the
tradeoff ruled acceptable for now, tracked separately for tightening.

Refs #3805
2026-09-13 11:45:37 +02:00
atlas
2989c5ccdb swarm: say "no queue coordinates", never "a hive with no queue"
The swarm always has exactly one queue; a hive can only lack its
address. Reworded every prose site this PR added that stated or
implied the opposite, to name what is actually absent (coordinates,
credential, or address) instead of the queue itself.

Refs #3805
2026-09-13 11:13:17 +02:00
atlas
86652f051a swarm: wire the agents' queue coordinates and credential through the modules
The host end: `HIVE_C0RE_AGENT_QUEUE_CREDENTIAL_DIR` tells the daemon
where the reader unit put the files, and a new
`deploy.hive-controller.queue.agentNatsUrl` says where the queue is as an
agent *container* reaches it. That address defaults to the bridge one and
never to loopback — `statusPublish.natsUrl` beside it is loopback and
correct, because hive-c0re shares the host netns and an agent does not.
Paired with the swarm's token endpoint, gated together, and forwarded by
`hive_c0re::meta` as both an env var and an agent option: the harness
reads the variable at runtime, its unit is built from the option.

The agent end: `nix/agent-modules/queue.nix` declares that option pair
and, when set, has the harness unit inherit the two credentials by name.
Bare-id `LoadCredential=` is the terse form documented for inheriting
what the service manager received, and is non-fatal when the credential
is absent — which a hive whose publisher has not run yet needs.

No `HIVE_AGENT_OIDC_CA_FILE`: the meta flake already embeds the hive CA
and the swarm root into each container's trust store at build time, and
reqwest's rustls backend verifies against it.

Refs #3805
2026-09-13 11:13:17 +02:00
atlas
353cdd9264 swarm: carry the agent queue credential from the host into the harness
hive-c0re stats the two files `swarm-bao-queue-agent` lands and forwards
them into every agent container as systemd credentials, and the harness
resolves a `QueueConfig` out of them at boot. Nothing connects yet.

A credential and not a bind mount, and the mode is what forces it: the
secret is root:0600 and the harness runs as the unprivileged agent user,
so a bind would deliver a file that user cannot open. nspawn's
`--load-credential` is read by the container manager as root and
re-exposed under the consuming unit's own `User=`. hive-c0re never reads
the bytes either way, which is just as well — it runs as `hive-core`.

Absent files stay legal and become visible rather than silent: the
publisher lives on the authelia host and mints on its first boot, so
"nothing at that path" is the ordinary early state of a swarm. c0re
forwards nothing and logs why; the harness logs that it has no queue.

The client id comes out of the delivered file rather than being rebuilt
from `hiveName` in nix, which is the agreement `swarm-secret-client`
states. `QueueConfig::from_env` wants it as a value, so the harness reads
the file itself — assigning the variable instead would need
`std::env::set_var` in a process that has already spawned threads.

Refs #3805
2026-09-13 11:12:19 +02:00
atlas
f8dd737456 swarm: run the agent queue credential reader before hive-c0re
Ruled: swarm-bao-queue-agent.service must run before hive-c0re.service
and be wanted (not required) by it, so no agent container renders
ahead of the reader's attempt at its credential. An unreachable store
delays hive-c0re's start by the reader's own start-limit window rather
than failing it outright.

Refs #4314
2026-09-13 11:10:00 +02:00
iris
8a4c613e4e swarm-ui: drop the redundant outer dialog card, move close into the panel header
Dialog and Panel both drew their own bordered/backgrounded card in the
same --bg-elev, so a Panel-based dialog (create-agent, link-matrix-account)
rendered as two concentric cards with a floating close button on the
outer one and no purpose to it.

Give Dialog a "plain" mode that drops its own card chrome (border,
background, padding) and floating close button, and give Panel an
optional onClose that renders a close button at the end of its own
header row instead. AgentsPage's two Panel-backed dialogs now use
plain + Panel's onClose, so the Panel is the dialog's only visible
card. ConfirmDialog (no Panel of its own) is unaffected — plain
defaults to false, unchanged card + floating close button.

Added a ComponentsPage sample demonstrating the plain + onClose
pairing. Verified both dialog modes via a real headless-chromium
screenshot (plain dialog: single card, close button in the header
bar; default dialog: unchanged floating close button).
2026-09-13 00:58:53 +02:00
atlas
09d502ea34 swarm-nats: set max_payload to 8 MiB explicitly
The swarm queue's rendered settings never named max_payload, so it ran
on nats-server's upstream default of 1 MiB. That default is about to
be too small: the broker is going to carry agent terminal rows
(whole TermMsg bodies) published as complete messages rather than
split, and a publish over the limit does not truncate — the server
answers -ERR 'Maximum Payload Violation' and closes the connection,
dropping the row.

Set max_payload = 8388608 explicitly in the settings merge, with a
comment on what it bounds and what bounds it (max_pending, which
nats-server refuses to start past). Add a module-eval case that reads
the rendered container config so a future edit that drops or shadows
the key fails eval instead of surfacing as a dropped row in
production.

Refs #3805
2026-09-12 21:40:36 +02:00
atlas
235ef64958 docs/swarm/secrets: satisfy the prose lint on the second-reader paragraph
Fixes Microsoft.Contractions (x2, 'that is'/'do not') and
write-good.ThereIs ('There is no local fallback...') per CI.

Refs #3805
2026-09-12 21:29:09 +02:00
atlas
b8157cb08e swarm: read the agent queue credential out of the store onto the hive host
The publisher on the authelia host has been writing
`secret/swarm/hives/<hive>/queue/agent` — the OIDC client secret agent
containers present to the swarm queue, plus the client id it belongs to —
and nothing read it. This is the reader: a oneshot `swarm-bao-queue-agent`
that logs in with the host's certificate and lands the two fields as two
files under `deploy.hive-controller.queue.agentCredentialDir`, the secret
`0600` and the client id `0644`.

Two files rather than one because that is the consumer's shape:
`swarm_queue_client::QueueConfig::from_env` takes the secret as a path and
the client id as a value, so the split here is what keeps the next slice
from parsing anything.

Same shape as the store's first reader, `glue-matrix-bao-token.nix` — a
cert login that fails loudly under `Restart=on-failure` because every state
it fails on is one a retry fixes, then reads that degrade quietly because no
retry turns "no value there" into a value. Unlike the matrix token there is
no local fallback and none is possible, so absent files mean this hive's
agents do not connect, which is the ordinary state of a swarm before the
publisher has run.

Nothing consumes the files yet and this unit is ordered `Before=` nothing.
The next slice bind-mounts them into agent containers through hive-c0re and
adds the ordering edge along with them.

Refs #3805
2026-09-12 21:05:52 +02:00
atlas
14305255f0 swarm: put the matrix registration token where the reader is granted
`swarm-bao-matrix-token` reads `secret/swarm/matrix/registration-token`
and is refused with `Code: 403 — permission denied`, measured on this
host at 16:17:49Z after a successful cert login.

path.rs makes every swarm path `swarm/<kind>/<name>/…` where Kind is a
closed set of four: agents, hives, services, controller. `matrix` sits
where a kind belongs, so policy.rs's read document — which emits exactly
`swarm/agents/*` and `swarm/hives/<hive>/*` — cannot cover it. The
module's own doc predicted this: "a misspelled kind is a 403 at provision
time rather than anything a compiler sees".

Moves the token to `swarm/hives/<hive>/matrix/registration-token`, built
through principal_prefix(Kind::Hive, …) like its per-hive sibling
queue::agent_client_path. The policy is untouched: render already grants
that prefix. mara chose this over widening the namespace.

The nix reader interpolates hyperhiveCfg.hiveName, with the no-fallback
reasoning glue-bao-tls.nix already gives at its own use of it.

path.rs's MOUNT doc justified itself by citing the old literal, which
this commit deletes; rewritten to cite the nix reader instead.

Scope: this makes the read reachable, not the value present. Nothing
writes that path yet, and a 403 says nothing about presence — the two
are separate findings and only the first is fixed here. No migration:
nothing ever wrote the old path and no read ever succeeded.

Gate: cargo fmt 0, cargo test -p swarm-secret-client 0 — 32 passed
against a 29-passed baseline with the change stashed, so the three new
tests are accounted for rather than assumed.

Refs #4308
2026-09-12 19:46:04 +02:00
atlas
2a02c76ad5 hive-c0re: name an agent container after its machine, not "nixos"
Every agent container reports the hostname `nixos`, so every log line it
ships carries that as its `_HOSTNAME`. Measured: host `muede-lpt2`,
`hive-matrix` (declared as `containers.hive-matrix`) `hive-matrix`, and
`h-atlas` `nixos`.

nixpkgs sets the hostname in the merge function of the
`containers.<name>.config` option (nixos-containers.nix:524), so it reaches
a guest evaluated through that option and nothing else. Agent containers are
`nixos-container create --flake meta#<name>` — an independent `nixosSystem`
off the meta flake, which never evaluates that submodule.

nspawn also names a container's hostname after the machine by default; that
is ruled out as the source here, because `h-atlas`'s machine name is
`h-atlas` and it reports `nixos`.

The machine name rather than the logical one: `stats/otel_metrics.rs:345`
already labels metrics `container.name = "h-<name>"`, so the logical name
would make logs say `atlas` while metrics say `h-atlas` — a prefix transform
on every join between the two signals. Declarative containers and nspawn
both use the machine name too, so this is one rule with no exception for
agents.

The emission sits next to `hyperhive.user.name = name;`, which already
derives the container's unix user from the agent name; the hostname was the
one identity attr nobody wired.

Also drops the prose in swarm-otel.nix and module-eval.nix that explained
`_MACHINE_ID` by "every container is `nixos`" — that motivating example is
what this commit removes, and the argument for `_MACHINE_ID` never depended
on it.

Checked before editing: nothing in the tree assumes the hostname is
"nixos" (0 hits across *.rs and *.nix), and nothing reads the hostname at
runtime.

Gate: cargo fmt 0, clippy -D warnings 0, cargo test -p hive-c0re meta::
0 (23 run, 22 passed, 1 ignored), nix fmt 0 changed.

Refs #4304
2026-09-12 18:19:18 +02:00
atlas
4db746a22c glue-matrix-bao-token: do not assert what the Before= ordering does
The retry comment claimed "every retry is time the homeserver may spend
waiting". That is the conservative reading, not a measured one, and argus
is right that it is probably wrong: systemd ordering typically resolves
once a unit's first start job completes, success or failure, and an
auto-restart after that is not a new ordering-relevant job.

If that holds, the container proceeds after the first failed attempt --
same timing as today -- and what the retries buy is the token file being
correct within ~60s for whatever starts next, rather than this boot's
race getting a second chance.

Both readings justify the same tight bound, for different reasons, so the
comment now says the ordering behaviour is unverified instead of picking
one. An agent container cannot reach a systemd manager to settle it.

Refs #4303
2026-09-12 16:10:45 +02:00
atlas
35c3f724f1 glue-matrix-bao-token: retry a failed login, keep degrading on an empty read
The unit treats every failure as permanent: it prints why and `exit 0`s,
with no `Restart=`, so one bad moment costs the whole boot. Two of its
failure modes deserve that and one does not.

`bao login` fails when the store is unreachable, sealed, or has not been
given this host's cert-auth role yet. All three are transient. Measured
on this morning's rebuild:

  11:24:05  Started Container 'swarm-bao'
  11:24:06  could not log in to swarm-bao with this host's certificate
  11:24:07  Success! Data written to: auth/cert/certs/swarm-secret-publisher

It lost by one second, and stayed degraded for the boot. The publisher
next to it hit the same race and recovered on its first retry, because it
has `Restart=on-failure`.

`bao kv get` returning nothing is the opposite: the store answered, and
holds no token at that path. A retry cannot improve it, so that branch
keeps `exit 0` and the local token.

The bound is sized for this race, not for an unseal.
`swarm-bao-controller-policy` waits 2880 x 30s because a shamir unseal is
a human action and that unit blocks nothing. This one is `Before=` the
homeserver's container, so every retry is time the homeserver may spend
waiting -- 4 x 15s covers a container-start race with margin, and a store
still sealed after it degrades exactly as it does today.

`StartLimit*` are `[Unit]` settings and are ignored under `[Service]`, so
they are top-level attrs here. The module-eval case asserts the window
outlasts `RestartSec x burst`, since a burst that cannot be reached is a
unit that looks like it retries and does not.

Refs #4303
2026-09-12 16:10:45 +02:00
atlas
57aedc82ae swarm-otel: say what is measured about _HOSTNAME, not a mechanism that is wrong
The previous commit's comments explained `_HOSTNAME` being `nixos` with
"no container sets `networking.hostName`", read off a `git grep` of this
tree. That grep answers a question about our source; the default is
nixpkgs': `nixos/modules/virtualisation/nixos-containers.nix` sets
`networking.hostName = mkDefault name` for every `containers.<name>`
guest, which is how every swarm service container here is declared.

So the stated cause is wrong, and why the default does not reach these
guests is still open. What is measured is narrower: an agent container
reports `nixos`, and `_MACHINE_ID` is per-machine by construction. The
comments now claim only that, and say the rest is unresolved.

The code is unchanged — `_MACHINE_ID` in `_stream_fields` is correct
regardless of which explanation turns out to be true.

Refs #4304
2026-09-12 14:38:35 +02:00
atlas
bb38e1967c swarm-otel: key the log stream by machine, not by a hostname every container shares
`_stream_fields=_HOSTNAME,_SYSTEMD_UNIT` was chosen to give "one stream
per unit per machine", which is what the comment above it claims. It does
not: no container sets `networking.hostName`, so `_HOSTNAME` is the NixOS
default `nixos` in every one of them, and every container's stream for a
given unit name merges into a single series.

Measured from inside an agent container:

  journalctl -n1 -o json -> "_MACHINE_ID":"5d1427ea…", "_HOSTNAME":"nixos"
  cat /etc/machine-id    ->  5d1427ea…
  git grep -i hostname -- nix/  -> 20 hits, all public vhost names,
                                   zero `networking.hostName =`

`_MACHINE_ID` is written by journald per machine and is already on every
entry, so adding it to the stream key makes the partition what its own
comment says it is. That merge is also why the host collector and the
containerised one were one series: both log to
`opentelemetry-collector.service`, and the field meant to separate them
was a constant.

The second comment touched here asserted a reader "can still tell the
origins apart" from `_HOSTNAME`/`_SYSTEMD_UNIT`/`_MACHINE_ID`. True only
of the last one; it now says so.

Not a full fix for attribution: `_MACHINE_ID` is opaque hex and nothing
maps it to a container name. Naming is the other half and is a separate
change.

Refs #4304
2026-09-12 14:14:11 +02:00
iris
3c6c2ed272 ci: add .mjs to check-comment-blocks.sh + check-issue-refs.sh's scope
mara: "add mjs to the lint and fix it in this pr". Both lints scope their
git ls-files scan to a fixed extension list that never included .mjs, so
all three frontend build.mjs files (swarm-ui, dashboard, agent) were
completely invisible to both -- not merely under the limits, outside the
scan entirely.

check-comment-blocks.sh: added '*.mjs' to the ls-files glob and to the
mode_of regex (same slash-comment treatment .js/.ts/.tsx already get --
.mjs is the same comment syntax, argus's exact proposed fix). check-issue-refs.sh:
added '*.mjs' to its glob list, no regex change needed.

Fixing the scope immediately surfaced real, pre-existing violations in
the other two build.mjs files (swarm-ui's own is already handled by this
PR's earlier commits):
- dashboard/build.mjs: 49-line comment block (trimmed to 15 -- redundant
  per-file output-layout table cut, the code below already names every
  output path) plus three bare tracker tags (#448 x2, #453) in the
  stream-worker comment, reworded to prose
- agent/build.mjs: two bare tracker tags (hyperhive#3685 x2), reworded

No logic changes anywhere -- comment-only edits plus the two lint
scripts. Closes #4300 and (independently filed, consolidated into that
one) #4299.
2026-09-12 13:04:01 +02:00