Expand description
Cloud push subscription — replaces per-agent polling with a single sidecar-level WebSocket to muxbus-ws.agentmux.ai.
When MUXBUS_TOKEN is present, the subscriber:
- Opens wss://muxbus-ws.agentmux.ai with the bearer token.
- Listens for { type: “inject_available” } broadcast wake signals (zero metadata).
- On each signal, pulls pending injections for every locally-registered agent: one POST /reactive/pending-batch for all of them, or one GET /reactive/pending/:id per agent on a relay without the batch route.
- Claims all pending injections via REST POST /reactive/ack (atomic pending->delivered transition server-side) before delivering — only ids this call actually won the claim on get delivered via ReactiveHandler. A claimed injection that fails local delivery is released back to pending via REST POST /reactive/release so it’s retried, rather than silently dropped.
- Reconnects with exponential back-off on any disconnect.
The server broadcasts to ALL connected sidecars on every injection, so a subscriber cannot correlate the signal to any particular agent, account, or timing.
Agents register/unregister via add_agent()/remove_agent(). No MUXBUS_TOKEN → subscriber stays idle.
Modules§
- delivery 🔒
- Claim → verify → deliver for one agent’s pulled injections: the half of a
pull that comes after the relay answered, shared by the single pull
(
sync_agent_reactive) and the batch pull (sync_agents_batched).
Structs§
Enums§
- Agent
Sync 🔒Outcome - Client
Msg 🔒 - CtrlMsg 🔒
- Relay
Release 🔒 - Drop
agentfrom the relay subscription and release its WAN lease, awaiting the release (theRemoveAgentarm’s is fire-and-forget) — for a Take over, whose requester claims the lease right after.falseif it wasn’t subscribed.id_storeis where muxbus credentials live. What a Take over’s relay release did. - Server
Msg 🔒
Constants§
- BROKER_
SWEEP_ 🔒INTERVAL_ SECS - CATCH_
UP_ 🔒EVERY - How often the subscriber pulls for every registered agent whether or not a
wake signal arrived. The relay’s wake is best-effort (a lost one is
meant to be caught by the client’s own poll), but this client had no
poll interval, so a jekt that reached the relay before its agent was
subscribed waited for the next unrelated wake: 8m46s on 2026-09-30. The
lease is already renewed every
super::wan_lease::RENEW_EVERY, so a catch-up costs about one pending GET per agent: roughly 0.5 requests a minute per agent at this interval. - CLIENT_
PING_ 🔒INTERVAL_ SECS - MAX_
RECONNECT_ 🔒DELAY_ SECS - MUXBUS_
REST_ 🔒URL - MUXBUS_
WS_ 🔒URL - Fallback when the cloud publishes no settings (
discovery::ws_url). - REAGENT_
SIG_ 🔒MAX_ AGE_ SECS - RECONNECT_
DELAY_ 🔒SECS - STALE_
RECHECK_ 🔒SECS
Statics§
Functions§
- agents_
to_ 🔒seed - The agents to put in the subscription when it is created: every locally
registered agent that a live pane still holds, lowercased and deduplicated.
Registered agents used to be missed. On an isolated channel the subscriber
is created lazily at
muxbus.login, with an empty set, and an agent that registered earlier (while there was no subscriber to tell) joined only on its next input turn, so nothing reached it until then. - catch_
up 🔒 - Pull pending injections for every registered agent now. The same work an
InjectAvailablewake does, run on connect, when an agent is added, and on a timer (CATCH_UP_EVERY) so a missed wake costs minutes at worst. Returns true when the session should reconnect (the shared token expired). - classify_
refresh_ 🔒token_ error - Classify a
pkce::refresh_tokenfailure for the broker’sRefreshErrorKind—NoRefreshToken/Rejectedin the 4xx range mean the credential itself is the problem (only a freshmuxbus.loginfixes it) except 408/429, which mean the request itself was throttled or timed out, not that the refresh_token was rejected — treating those as permanent would strand the credential inNeedsReauthpast a temporary rate limit (reagent P2 on #2275). Everything else (network blips, 5xx, response parse failures) is worth retrying on the next sweep tick. - connect_
and_ 🔒run - drop_
cloud_ 🔒subscription_ on_ exit - Whether a spawn’s exit drops its agent from the cloud subscription.
registration_was_ours: its own nonce matched. That alone was the old rule, and a registration already gone (false) read as “a newer spawn owns it” — so the agent stayed subscribed, and the lease tick renewed its WAN lease for as long as the srv ran, fencing it on every other instance (charlie, 2026-09-26). Keep it only while a live block holds it. - fresh_
shared_ 🔒token - The shared account token for an HTTP call made during a connection: loaded
fresh (
fresh), the same waywan_publishandrelay::relay_tokenload theirs. Not the connection’stoken: that one is loaded once at connect, a desktop (PKCE) access token lives 15 minutes and a connection up to 2 hours, so after minute 15 every call made with it is a 401. For the W3-S key directory that turned every same-account WAN jektnetwork-claimed; for a lease release it left the lease held until it expired. The connection’s token is only the fallback when no fresh one can be loaded, and otherwise only authenticates the WebSocket handshake. - get_
global_ subscriber - handle_
server_ 🔒msg - Handle a message from the cloud server. The WS wake signal carries zero metadata — the sidecar polls all its registered agents via REST to find pending injections, so a compromised subscriber gains nothing.
- is_
credential_ 🔒rejected - Does
statusmean “this credential is not accepted for this request,” regardless of the specific reason? 401 = expired/invalid token. 403 = the cloud’s agent-binding check rejected it (this credential is bound to a different agent_id than the one it’s being used for). Both mean the SAME thing operationally for a poller CURRENTLY USING A PER-AGENT CREDENTIAL: that credential can’t be used for this agent, so invalidate-and-retry-with-the-shared-token applies identically to either status. Before this, only 401 triggered that recovery path — a 403 fell into the generic non-2xx branch, silently stalling that agent’s WAN delivery for the rest of the poll cycle with no retry and no user-visible error. Once the retry has fallen back to the SHARED token itself, 401 and 403 diverge again — seeshared_token_rejection_outcome, which is what actually decides that case, not this function. - is_
subscribed 🔒 - Is
agentin the relay subscription?truewhen there is no subscriber (tests), so a lease check fails open as before. - load_
valid_ 🔒token - Load a valid (non-expired) access token via the broker, refreshing first
if the stored credential is missing/stale. Returns None if no credentials
are stored, the token is expired and refresh fails, or the refresh_token
is absent —
ensure_fresh’s own single-flight guard means this can run concurrently with the broker’s background sweep for the same credential without either one duplicating the other’s refresh attempt. - orphaned_
subscriptions 🔒 - Subscribed agents no live block holds. Every way into the subscription
(
add_agent) runs with a live registration, so one without is a leak from a teardown that missed it; renewing its WAN lease would fence the agent everywhere else for as long as this srv runs. - reagent_
sig_ 🔒is_ fresh - Is
ts_secs(a reagent signature’s claimed signing time) withinREAGENT_SIG_MAX_AGE_SECSofnow? Extracted as a pure function (takesnowexplicitly rather than callingnow_unix_secs()itself) so it’s unit-testable without mocking the system clock.ts_secs <= 0is never fresh — a zero/negative timestamp only happens for a malformed or missing claim, never a genuine signature. - refreshed_
same_ 🔒account - Whether a refresh came back for the account the saved sign-in names. A torn set could pair a refresh token with another account’s row; a row with no account recorded (an older sign-in) can’t be checked.
- release_
agent_ 🔒now - run_
loop 🔒 - shared_
token_ 🔒now fresh_shared_tokenagainst the broker andmstore(the store muxbus credentials live in —CloudSubscriber::init_global’sid_store).- shared_
token_ 🔒rejection_ outcome - What to do when the SHARED account-level token itself (not a per-agent
credential — that case is already handled by the invalidate-and-retry
branch above) is rejected. 401 and 403 are NOT interchangeable here even
though both satisfy
is_credential_rejected: - sync_
agent_ 🔒reactive - One registered agent’s full pending-fetch → claim → deliver cycle for an
InjectAvailablebroadcast. Extracted from the loop body it used to be sohandle_server_msgcan run every agent’s sync concurrently viajoin_allinstead of sequentially — see the call site’s own comment. - sync_
agents_ 🔒batched - Every agent in
registeredpulled in one request (POST /reactive/pending-batch) instead of oneGET /reactive/pending/:agenteach, then claimed and delivered exactly assync_agent_reactivedoes, for each agent with messages. The relay answers each agent as its single route would; this is what keeps an install’s relay traffic from growing with every open agent. - take_
over_ 🔒lease_ now - Take over’s relay step on the requester (
super::wan_lease::take_over), with a fresh shared token.Unknown(fail open) when this instance has no MuxBus session or no token can be loaded. - usable_
or_ 🔒refreshable - A loaded sign-in that can be used now or refreshed: a valid access token,
or a refresh token (all a torn sign-in keeps, see
storage::muxbus). - wait_
for_ 🔒sign_ in - Park until a sign-in (
ReloadToken) orrecheckelapses, whichever comes first. AddAgent/RemoveAgent drain without waking it: they already updated theagentsset the next connection subscribes from.