The dial-out model
A node is never dialled into. It opens an outbound connection to the engine and registers itself, so a node needs only outbound UDP/443 and no inbound ports, no public address, and no port forwarding. This is why a laptop behind NAT and a rack box are enrolled the same way. The engine —mod_compute — owns the session. It holds the heartbeat
clock, tracks which nodes are currently registered, and decides where a
workload is placed. Nothing in the console places work directly.
Enrolling a node
compute.nodes.enroll creates the node record and mints its credential
in one call. The enroll form on the Compute screen collects:
nodeId must match ^[a-z0-9][a-z0-9-]*$: lowercase letters, digits and
dashes, starting with a letter or a digit.
The one-time credential
compute.nodes.enroll returns { node, token }. The token is returned
exactly once. Only its hash is stored, so there is no later
procedure that can hand it back; the console keeps it in component state
until you dismiss the panel, and re-fetching the node list will not
reproduce it. If you lose it, revoke the node and enroll again.
Start the agent with the credential:
Once registered, the node reports a manifest. The console reads
cpu_millis, mem_mb and runtimes out of it for the Capacity column.
Trust tiers and the workload opt-in
A node is either secure — hardware you operate — or community — somebody else’s hardware, running other people’s code. The tier is one half of a pair:- Every node shows its tier (
SECURE/COMMUNITY). - Every function and machine shows whether it opted in
(
SECURE ONLY/COMMUNITY OK).
allowCommunity flag on
compute.functions.deploy, surfaced in the Placement column. A fleet
where you cannot see which machines are yours is a fleet where the
opt-in means nothing, which is why the screen always shows both halves
side by side.
compute.nodes.setTrustTier({ orgId, id, trustTier }) flips a node
between the two tiers. It takes effect on the node’s next REGISTER
— it does not evict what is already running there.
Node liveness and last seen
The node list is polled every 15 seconds and shows a Last seen column derived fromlast_seen_at. Treat that column as advisory
only. Liveness belongs to the engine: mod_compute holds the
heartbeat clock and decides what may receive work. A recent last seen
is not permission to place.
A failed list request is not an empty fleet. The screen distinguishes
“couldn’t load nodes” (with the error message) from “no nodes enrolled”,
and keeps polling.
Draining and revoking
Drain first when you want to take hardware out of rotation without
interrupting in-flight work.
Deploying a WASM function
A function is a WASM component that is submitted and collected: the component bytes travel inline to the node, base64-encoded, so nodes need no registry credential and make no outbound fetch of their own. The deploy form reads the file in the browser, checks the first bytes for the WebAssembly magic (00 61 73 6d, in a file of at least 8 bytes),
and base64-encodes it. The engine checks the magic too and refuses a bad
module at deploy time rather than at first invoke — the browser-side
check exists only so the person who picked the file finds out while they
are still looking at it.
compute.functions.deploy takes:
Resource requests
The deploy form validates these as integers in JavaScript on submit — HTMLmin/max on a number input is advisory, and an emptied field
reads as 0, so the bounds are enforced in code:
The function list renders these back as cores and MB, alongside the
component size in KB and the
region when one is set on the record.
Invoking a function
compute.functions.invoke({ orgId, name }) runs a deployed function.
The Run button on each row calls it and renders the result:
Machines
Machines are microVM workloads, declared per org and listed on the Machines tab. They carry the same community opt-in as functions, shown per machine, and the same trust-tier rule applies to placement. Because a microVM is a stronger isolation boundary to hand to contributed hardware, the agent enforces the pairing itself: a node started with--community refuses to boot microVMs unless --jailer is
also set. A community node without the jailer can still take WASM
functions.
Tenant scoping
The console shell is operator-global.inference.* procedures take no
org, but every compute.* procedure is org-scoped and takes an
orgId. The Compute screen therefore uses the org the operator selected
on the portal, and says so plainly when none is selected.
It does not substitute a placeholder org. A fabricated tenant renders an
empty fleet, and “this tenant has no nodes” is a very different fact
from “no tenant is selected”.
The compute API surface
Node records expose
id, node_id, label, contributor,
trust_tier, region, draining, last_seen_at and the reported
manifest (cpu_millis, mem_mb, runtimes). Function records expose
id, name, size_bytes, cpu_millis, mem_mb, allow_community
and region.
Related
- Authentication — API keys and org scoping for control-plane calls
- Telemetry — metrics and traces emitted by the platform

