Protocol and API reference¶
This page is the compact reference for the control-plane API and data-plane transport. Use Runtime model first if you want the conceptual flow.
Control plane¶
| Purpose | Route or command |
|---|---|
| Health | GET /api/v1/health, GET /api/v1/ready |
| Jobs | POST /api/v1/jobs, GET /api/v1/jobs, GET /api/v1/jobs/{job_id} |
| Job status | POST /api/v1/jobs/{job_id}/status |
| Job metrics | GET /api/v1/jobs/{job_id}/metrics/stream |
| Cancel job | DELETE /api/v1/jobs/{job_id} |
| Checkpoint | POST /api/v1/jobs/{job_id}/checkpoint |
| Workers | GET /api/v1/workers, DELETE /api/v1/workers/{fellow_id} |
| Worker heartbeat | POST /api/v1/workers/register, POST /api/v1/workers/heartbeat |
| Worker management | POST /api/v1/workers/release, POST /api/v1/workers/update |
| Worker logs | GET /api/v1/workers/{fellow_id}/logs/stream |
| Cluster view | GET /api/v1/cluster/nodes[?pool=], GET /api/v1/cluster/devices |
| Signals | WS /ws/signals/{fellow_id} (node credential, see auth) |
| Bootstrap | GET /api/v1/bootstrap/manifest.json, GET /api/v1/bootstrap/fellow.sh, POST /api/v1/bootstrap/join-sessions |
| Community numbers | GET /api/v1/public/stats (public, aggregate, cached) |
| Your contribution | GET /api/v1/me/contribution (session; measured totals, no currency) |
| Signup attribution | GET /api/v1/admin/users/signup-intents (admin; which landing door converted) |
| Public pages | GET / (en), GET /de (de), GET /en (301 to /), /robots.txt, /sitemap.xml, /llms.txt |
| Pools | GET/POST /api/v1/pools, GET/PATCH/DELETE /api/v1/pools/{id} |
| Pool health | GET /api/v1/pools/{id}/metrics, …/metrics/stream (SSE), …/metrics/history?metric= |
| Pool timeline | GET /api/v1/pools/{id}/events |
| Node roles | POST /api/v1/pools/{id}/nodes/{fellow_id}/role |
| Buckets | GET/POST /api/v1/buckets, GET/PATCH /api/v1/buckets/{id}, …/datasets |
| Model catalog | GET /api/v1/models, GET /api/v1/models/{id}, …/status, GET /api/v1/serving |
| Model serving | POST /api/v1/models/{id}/load, …/unload |
| Inference | POST /api/v1/chat/completions (and /v1/chat/completions, OpenAI-compatible) |
| Inference transport | GET /api/v1/infer/requests/{fellow_id}, POST /api/v1/infer/responses/{request_id} |
| Web UI | GET /dashboard, /pools/{id}, /buckets, /ops/join-v2, /ops/inference, /profile |
Every route is classified in leader/route_policy.py; anything not listed there
is denied by default, so a new endpoint is unreachable until it is classified.
Control signal values¶
ControlSignal.signal supports:
STARTPAUSECHECKPOINTSTOPRECONFIGUREUPDATEPURGEPING— a control-plane round-trip probe. Only sent to fellows that advertised thepingcapability at registration: an older fellow treats an unknown signal as a protocol error and reconnects, so an unnegotiated ping would knock a running cluster into a reconnect loop.
Registration and heartbeat¶
sequenceDiagram
participant Fellow
participant Leader
Fellow->>Leader: POST /api/v1/workers/register
Leader-->>Fellow: RegisterResponse (node_token)
Fellow->>Leader: WS /ws/signals/{fellow_id}<br/>Authorization: Bearer node_token
loop every heartbeat interval
Fellow->>Leader: POST /api/v1/workers/heartbeat<br/>status, step, loss, bytes, live hardware
Leader-->>Fellow: HeartbeatResponse
end
Heartbeats include live GPU hardware telemetry when available. The leader uses
that payload to refresh per-GPU free VRAM in /api/v1/cluster/nodes and
/api/v1/cluster/devices, so the Ops UI shows current VRAM utilization instead
of only the registration-time inventory.
/api/v1/cluster/nodes reports each node's pool_id and accepts ?pool=<id>
to narrow the list to one pool — the same filter /api/v1/ops/join-graph takes,
so the ops console's table and graph always describe the same set of nodes.
Heartbeats may also carry a telemetry block (NodeTelemetry): per-GPU
utilization, temperature and power, the round trip the fellow observes talking
to the leader, round trips to its pipeline peers, and monotonic OOM / error /
restart counters. Every field is optional — a fellow built before the block
still registers and heartbeats, and consumers render its missing signals as
unknown rather than zero.
Server-rendered navigation¶
Pages are full server renders, so anything the browser has to fill in is rebuilt on every navigation. The sidebar used to be exactly that: a skeleton, an identity fetch, then a swap — visible on each click.
leader/web/nav_render.py renders it server-side instead. The page builders stay
free of request state (the same reason the CSP nonce is substituted late): the
template carries tokens — __NAV_USER__, __NAV_POOL_NAME__,
__NAV_STATE_<key>__, __NAV_ADMIN_HIDDEN__, __USER_NAME__ — and the HTTP
middleware substitutes them once per response, where the session cookie is
available. The active pool comes from the swarm_pool cookie, so the server
renders the same chip the user selected. Every value that originates with a
user (display name, pool name) is HTML-escaped there.
auth_header.js no longer fetches identity or pools on load; it only wires the
menus and the drawer, and loads the pool list lazily when the switcher is
opened.
Pool telemetry¶
PoolTelemetry (leader/telemetry/pool_telemetry.py) keeps a bounded in-memory window of
health signals per fellow and rolls them up per pool. Nothing polls a fellow;
every input is something the leader already receives:
flowchart LR
HB[heartbeat handler] -->|availability, step rate, node telemetry| PT[PoolTelemetry]
WS[signal WS hub] -->|ping/pong RTT, disconnects| PT
REG[register route] -->|flap counter| PT
CHAT[chat completions + broker] --> SM[ServingMetrics]
SM -->|tokens/s, TTFT, queue wait, errors| PT
PT --> API["/api/v1/pools/{id}/metrics (+ SSE)"]
Design rules that the implementation holds to:
- The request path never blocks on telemetry. Recording a generation is a
few dict writes and
perf_counter()reads into a bounded deque; a telemetry failure can never fail a generation (the broker's dispatch hook swallows its own exceptions). - One clock. Every duration is a delta of leader-side
perf_counter()reads, or a delta the fellow measured about itself. No metric depends on leader and fellow clocks agreeing. - Bounded memory. Each node keeps at most ~1024 samples (≈1 h at the 5 s heartbeat interval); released nodes are forgotten so they stop skewing pool roll-ups.
- Unknown is not zero. A signal that was never reported is
null, so a node that simply cannot measure something is not penalised for it.
Availability is received heartbeats ÷ expected heartbeats over the window, so
a node cannot hide an outage by reconnecting; it stays null until a node has
been observed for at least two intervals.
The rest of leader/telemetry/ builds on that snapshot:
| Module | Turns the snapshot into |
|---|---|
grades.py |
one explainable 0-100 score and an A-F band per node, with hysteresis so a band does not churn |
pool_metrics.py |
stored history (minute resolution for 7 days, hourly for 90) and the pool event timeline |
vram_budget.py |
what a serving stage needs — weights plus the KV cache its layers will allocate — which gates model loads |
replacement.py |
the decision to quarantine a failing node and promote a standby, guarded by dwell times and a cooldown |
notify/alerts.py turns the resulting events into email/webhook notifications.
The operator-facing description of all of this — grading rules, the replacement
triggers and their guards, the VRAM arithmetic — is in the
Pools guide.
Data plane¶
Direct fellow-to-fellow traffic uses ZeroMQ multipart messages:
flowchart LR
F0[Fellow i] -- activation PUSH :5557 --> F1[Fellow i+1]
F1 -- gradient PUSH :5558 --> F0
Each packet carries metadata plus raw tensor bytes. The relay path uses the same multipart semantics over leader HTTP endpoints:
| Relay route | Purpose |
|---|---|
POST /api/v1/relay/{job_id}/{channel}/push |
Push encoded frames into a channel. |
GET /api/v1/relay/{job_id}/{channel}/pop |
Pop encoded frames, optionally blocking. |
Transport selection is controlled with SWARM_PIPELINE_TRANSPORT=auto|tunnel|p2p.
Authentication notes¶
- The
swarmCLI can sendAuthorization: Bearer <token>via--tokenor config. - Bootstrap downloads can require a pool/invite token when
SWARM_BOOTSTRAP_REQUIRE_TOKEN=1— viaX-Bootstrap-Tokenheader or?token=query param. The script is HTTPS-only and the manifest publishessource_archive_sha256/script_sha256for verification (see bootstrap). - Production deployments should enforce broader authentication at the leader or ingress layer.