For operators

Run a worker.

A worker is what turns a machine with GPUs into a peer on the network. It's one container, it needs no GPU access of its own, and there's no application or approval queue — start it and you're serving.

Before you start

What you need on the box.

The worker doesn't hold models and doesn't touch your GPUs. It speaks to an inference server you already run, over HTTP.

Docker

Or a Rust toolchain, if you'd rather build from source. Linux is the smoothest path.

vLLM, for text

Any OpenAI-compatible endpoint. Typically 127.0.0.1:8000.

ComfyUI, for images

Optional. Point at it and every checkpoint installed is served. Export a workflow instead when your pipeline has a shape of its own.

Quickstart

Serving in about ten minutes.

Build the image

From a clone of the repository.

build
$ git clone https://github.com/rootmodeai/rootmode
$ cd rootmode
$ docker build -f docker/Dockerfile.worker -t rootmode-worker .

Point it at your inference server

The container talks to vLLM over HTTP, so it needs no GPU access itself. --network host is the simplest thing that works on Linux.

run
$ docker run -d --name rootmode-worker --restart unless-stopped \
    --network host \
    -v rootmode-worker:/var/lib/rootmode \
    -e ROOTMODE_VLLM=http://127.0.0.1:8000 \
    rootmode-worker
Keep the volume.

/var/lib/rootmode holds the node's key, and that key is its identity. Lose it and your peer id changes — every client that pinned you stops recognising the node.

Check what it says

On first start it writes a worker.toml from the environment and prints it, then advertises exactly what the box actually serves.

docker logs -f rootmode-worker
INFO rootmode worker v0.1.0
INFO peer_id=ef9084b8a01c18be4b75fb7e0b72b7b4d57b5be9…
INFO listening on ws://0.0.0.0:9944
INFO caps: [llm]  max_concurrent: 2
INFO   meta-llama/Llama-3.1-8B-Instruct (llm)
INFO this node is its own entry point — give a client one of:
INFO   /ip4/192.168.1.50/tcp/4101/p2p/12D3KooWR3Tjk…

Connect a client to it

On the same network, the desktop app finds it on its own — it appears on the peers screen marked discovered. From elsewhere, add ws://<host>:9944 by hand, and paste the peer id into the public key field to pin it.

To check a node without the desktop app at all:

smoke test
$ cargo run -p rootmode-worker --example submit -- \
    ws://127.0.0.1:9944 "what is a peer?"

Configuration

The settings worth knowing.

Set as environment variables, or mount your own worker.toml at /etc/rootmode/worker.toml and none of these apply.

VariableDefaultWhat it does
ROOTMODE_VLLMOpenAI-compatible endpoint for text
ROOTMODE_COMFYUIComfyUI endpoint for images
ROOTMODE_BOOTSTRAPEntry points to join, comma-separated
ROOTMODE_P2P_EXTERNALAddress to advertise, if not what it binds
ROOTMODE_LABELhostnameThe name clients see
ROOTMODE_LISTEN0.0.0.0:9944WebSocket address
ROOTMODE_MAX_CONCURRENT1Jobs to run at once
ROOTMODE_REQUIRE_SIGNATUREfalseRefuse unsigned submissions
ROOTMODE_ALLOW_PEERSOnly these client peer ids may submit
ROOTMODE_RELAYtrueAsk for a relay slot — needed behind NAT

Behind NAT, or publishing ports instead of using host networking? Set ROOTMODE_P2P_EXTERNAL to the address other peers should dial — otherwise they discover the node and then can't reach it.

Your machine, your rules

What a client can and can't do to your box.

Nothing a client sends is executed A job picks a workflow you declared and fills parameters you declared. That is the entire surface — no job field reaches a process spawn.
You choose the models on offer The worker holds none of its own. It advertises what your inference server actually serves, and nothing else can be requested.
You can restrict who submits at all Require signed submissions, or list the exact client peer ids allowed. Everything else is refused before it runs.
For images, a prompt and a checkpoint — nothing else A client picks one of the checkpoints you have installed and sends words. It can't send a graph, add a node, or reach a setting you didn't offer. Export a workflow and even the checkpoint is fixed.
Stop means stop docker stop and the node is off the network. There's no notice period and nothing to cancel.
You're responsible for what your node serves.

Workers run models the operator chose, on hardware the operator owns. Local law and acceptable use are yours to observe.

Going further

When one node becomes several.

A lone worker is its own entry point — a client pointed at it discovers what it serves. Once several nodes need to find each other, run a bootstrap node and point them all at it. It's an entry point and a relay for NAT'd nodes, never a registry, never an authority, and never in the path of a job.

bootstrap node
$ docker build -f docker/Dockerfile.bootstrap -t rootmode-bootstrap .
$ docker run -d -p 4001:4001 -v rootmode-bootstrap:/var/lib/rootmode \
    rootmode-bootstrap --announce /ip4/<this host>/tcp/4001

Run several. Any node can be one. docker compose up brings up a bootstrap node and a worker together.