Skip to main content

Module fleet

Module fleet 

Source
Expand description

Fleet control — select, broadcast, and bulk-act on many agents at once. See docs/specs/SPEC_MULTI_AGENT_FLEET_CONTROL_2026_08_20.md.

fleet.broadcast/fleet.bulk-stop are thin server-side loops over the EXISTING single-target primitives (ReactiveHandler::inject_message, agent_io::stop_one_agent_block) — no new transport is invented, and every action returns FleetActionResult (succeeded/failed per target), never a single bool, per the spec’s §3 finding that silent partial failure is the single most commonly-cited fleet-ops UX failure mode.

fleet.broadcast is deliberately WS-RPC-only (the human/Swarm-UI path), not exposed over HTTP to agentmux-mcp. It is NOT a jekt: a broadcast is the human typing once to several panes, so each target gets a message routed the way an inter-agent message is (bootstrap::route_agent_message: persistent, ACP and App Server on their own channel, a subprocess or unspawned agent via run_agent_turn) with a one-line [BROADCAST:FROM=user VIA=swarm ...] header from reactive::broadcast_turn_message, instead of a self-declared jekt from unknown. See docs/specs/SPEC_SWARM_BROADCAST_AS_USER_MESSAGE_2026_10_01.md. The turn is BROADCAST_TURN_ORIGIN (User): a broadcast is the human’s own message, with the same powers as typing it into each pane, including authorizing an agent’s self-quit (owner decision 2026-10-06, spec §6 q2). That adds no power to anything holding the pane key, which could already send any pane a plain User turn through agent.input (spec §2 finding 7, §4.2). srv, not the text, still decides: the label comes from this module only. A target running on another channel on this machine is reached over loopback, the way a stop is (forward_broadcast_to_channel): the sender passes only the target block, the body, the MSGID and the RECIPIENTS count, and the receiving instance builds the header and starts the turn itself (deliver_forwarded_broadcast). Agents on other machines are not reachable this way: nothing on the LAN proves who is asking (docs/specs/SPEC_SWARM_REMOTE_AGENTS_PLATFORM_TAG_AND_SELECTION_2026_10_03.md §6). The forward uses the same loopback auth as the stop forward, and reaches only what that channel’s own fleet.broadcast already does. An AGENT-initiated broadcast instead loops the EXISTING signed single-target SendMessage MCP tool path client-side (see agentmux-mcp’s FleetBroadcast tool) — only the calling agent’s own process holds its AGENTMUX_JEKT_KEY, so per-message signing can only happen there, never in a server-side batch RPC. fleet.bulk-stop has no such constraint (a controller stop involves no jekt signing at all, same as agent.stop today) and IS exposed over HTTP (POST /api/v1/fleet/bulk-stop) for FleetBulkStop.

Structs§

BroadcastForward 🔒
What a forwarded broadcast carries. No header text: the receiving instance writes the header, so a caller on loopback cannot supply its own.
BroadcastOutcome 🔒
What happened to one target of a broadcast.

Enums§

BroadcastAction 🔒
What to do with one target, given how its controller routes a message.
BroadcastRoute 🔒
How one broadcast target is reached.
Forwarded 🔒
What asking another instance’s user came to.

Constants§

BROADCAST_CONCURRENCY 🔒
Turns started at once. Delivery is not rate-limited the way inject_message was (which is why the old 10-per-second chunking is gone), but a pane’s turn can spawn a CLI, so a broadcast to a large selection is bounded rather than starting every turn in the same instant.
BROADCAST_TURN_ORIGIN 🔒
Every broadcast turn is attributed here, and only here: User — see the module doc. A test pins both this value and that run_broadcast hands it to the delivery function. It was Automated until 2026-10-06.
FLEET_BROADCAST_AUDIT_ACTION 🔒
FLEET_BULK_STOP_AUDIT_ACTION 🔒
NO_REGISTERED_AGENT 🔒

Functions§

broadcast_action 🔒
Maps route_agent_message’s answer to an action. A PTY-based target is refused rather than typed into: a broadcast is prose, and keystrokes into a shell prompt would run it as a command.
deliver_broadcast_turn 🔒
Delivers one broadcast text to one block the way an inter-agent message reaches it (route_agent_message_from): structured controllers (persistent, ACP, App Server) take it on their own channel, which also steers a turn already running; a subprocess or not-yet-spawned persistent agent gets a turn started with origin. Either way the turn is labelled with origin where the controller tracks provenance at all (persistent and subprocess, the same agents a typed message can authorize a self-quit on).
deliver_forwarded_broadcast 🔒
The receiving end of forward_broadcast_to_channel: builds the header here, from the target’s own agent id, and delivers it as any broadcast turn (BROADCAST_TURN_ORIGIN). Audited on this side too, naming where it came from.
exceeds_fail_threshold 🔒
batch_failures / batch_len (as a percentage) exceeds max_pct. Cross-multiplies instead of computing a truncated integer percentage first — batch_failures * 100 / batch_len rounds DOWN before comparing, so e.g. 1 failure in a batch of 3 (33.3%) reads as 33 and never exceeds max_pct = 33, silently missing the threshold it was meant to catch (Codex P2, PR #2687 review). batch_failures * 100 > max_pct * batch_len is the same inequality with no rounding.
fleet_broadcast_impl 🔒
fleet_bulk_stop_impl 🔒
fleet_bulk_stop_with_override 🔒
FleetBulkStop from an agent (the HTTP path; the Swarm UI’s own fleet.bulk-stop is the user and stops at once): every target running on this instance waits for its user’s 15 s override, all windows in parallel (docs/specs/SPEC_AGENT_SELF_QUIT_2026_09_24.md §6.5). A target running on another instance on this machine is asked there, in that instance’s own window (forward_stop_pending). Targets running nowhere go through fleet_bulk_stop_impl as before, staged included.
forward_broadcast_to_channel 🔒
Asks the instance at local_url (another channel on this machine, its auth_key from the shared registry, same user) to deliver one broadcast. A channel from before the route answers 404 and is named as such, for that target only.
forward_stop_pending 🔒
A cross-channel FleetBulkStop target: ask ITS instance’s user (/agentmux/agent/stop-pending), whose banner, chime and Keep running are the ones that user sees. The request’s status is served from there; pending_shutdown::remember_remote lets this instance proxy it. An instance without that route (404) gets the plain forward it always did.
forward_stop_to_shared_channel 🔒
Stops targets (block ids) via the existing single-target stop_one_agent_block, one call per target, and — unlike that single-target primitive, which involves no jekt signing and so was never audited — records one AuditLogEntry per target via ReactiveHandler::log_fleet_action_audit, so Warden’s Audit tab sees every fleet-initiated stop (SPEC_MULTI_AGENT_FLEET_CONTROL_2026_08_20.md §6; reagent/Codex P2, PR #2687 review — this was missing entirely). Without staged, runs every target as a single batch (still returns full per-target detail, never a bool). With staged, targets are stopped batch_size at a time; if the failure rate WITHIN a completed batch exceeds max_fail_percentage, remaining targets are recorded as failed (untried) and aborted_early is set — caps blast radius on a bad selection rather than plowing through every remaining target. aborted_early is only ever set when targets were genuinely left unattempted — tripping the threshold on the LAST batch (nothing left to skip) must not report “aborted early” when the full list actually ran (reagent P2, same review). Look up block_id in the shared cross-channel registry (this host, other channels — same registry server/reactive.rs’s inject cascade tier-2b already reads) and forward a stop request over loopback HTTP to that channel’s own srv (/agentmux/agent/stop), using its own auth_key from the registry entry — identical trust model to the inject cascade’s own cross-channel forward (same host, same user).
register
register_fleet_broadcast 🔒
register_fleet_bulk_stop 🔒
register_fleet_group_create 🔒
register_fleet_group_delete 🔒
register_fleet_group_list 🔒
register_fleet_group_update 🔒
run_broadcast 🔒
The broadcast logic, with srv’s two touch points passed in so it can be tested without an AppState: resolve maps a block id to its agent id, and deliver starts one turn (block id, full text, origin).
shared_channel_for 🔒
The shared cross-channel registry entry for block_id on ANOTHER instance on this machine: loopback only, never this instance itself.