@pooled/openclaw
v0.3.2
Published
Peer-to-peer inference engine for your claw: run one model across your own devices, each holding part of it on its GPU.
Maintainers
Readme
What it does
Your OpenClaw gateway joins a Pooled room and runs part of the model on its own GPU. Your other computers, browser tabs and phones hold the rest, so together they run a model none of them could run alone. No API key, no cloud model, no account.
Install
openclaw plugins install clawhub:@pooled/openclawAlso on npm: openclaw plugins install @pooled/openclaw.
Quick start
Onboard. Run
openclaw onboard.Pick Pooled. Choose More… → Pooled. Onboarding shows this GPU and how much it can lend.
Start a room, or join one. Start a room and pick the Qwen3.6 35B MoE (recommended): onboarding prints the room code and an invite link. A second device joins with
npx @pooled/cli join "<invite link>"or opens the link in Chrome or Safari, or picks Pooled → Join a room in its own OpenClaw. Type
/pooledin any OpenClaw chat to see the room.
In the demo
Each token crosses the network twice (PC → Mac → PC), only a few kilobytes per hop.
What to expect
The first answer is slow: the room reads OpenClaw's prompt (about 18,700 tokens of instructions and tools) once, then keeps it.
| Turn | Time | |---|---| | First answer | about 3 min | | Next question, same chat | 14 s | | Same task in a new chat | 46 s |
Qwen3.6 35B MoE, two devices on one DGX Spark, OpenClaw 2026.9.6. Other GPUs differ.
/pooled shows the room in any chat:
Which model
| Model | For OpenClaw | |---|---| | Qwen3.6 35B MoE | Recommended. About 23 GB across the room, 128k context. | | Qwen3.8 27B | Works. About 20 GB across the room, 64k context. | | Qwen3 1.7B | Not recommended: small (about 5.5 GB), but slow on OpenClaw's long prompt and loops on its tools. |
Onboarding preselects the MoE when this device can hold it, and the 27B when only that fits. A room can
hold more than any one device: it waits for more devices. A pooled join device (@pooled/cli 0.4.0 or
newer) with a discrete GPU can make up a short room by keeping some of the MoE's experts in system RAM
(--ram), more slowly; the gateway holds its layers whole. The Qwen3.5 122B MoE is in pooled host,
not in OpenClaw's onboarding.
Requirements
- OpenClaw 2026.9.6 or newer, Node 22 or newer.
- A GPU: Linux with a Vulkan driver and glibc 2.38 or newer (like Ubuntu 24.04), macOS 26 or newer, or Windows with an NVIDIA GPU (Direct3D 12).
- Tested on OpenClaw 2026.9.6 to 2026.9.8 on Linux (DGX Spark, GB10), macOS 27 (M5 Max) and Windows 11 (RTX 5070, the gateway hosting the room).
- The plugin bundles Pooled's engine and installs
node-datachannel(WebRTC),peerjs(signaling) and, as an optional dependency,webgpu(Dawn, about 95 MB). Ifwebgpudidn't install, the gateway says how to add it when it needs the GPU.
Security
Every device holding layers sees the conversation and can steer the answer, tool calls included: use rooms of your own devices and keep OpenClaw's approvals on. Details: security model and privacy.
What it does on your machine
OpenClaw shows these capabilities and asks you to accept them at install.
- Runs native GPU code in the gateway: Dawn (npm
webgpu, a nativedawn.node) and the WebRTC librarynode-datachannelload into the gateway process, which runs the model's layers. - Opens network connections when the gateway starts. Devices find each other through the public
PeerJS server (
0.peerjs.com;signalsets your own PeerServer) and Google's STUN servers (stun.l.google.com), then talk directly over WebRTC. - Downloads models from Hugging Face into
~/.pooled/models(shared withpooled pull): 1.8 GB for the 1.7B, 16 GB for the 27B, 21 GB for the MoE. Downloads resume, are checked against their SHA-256, and only one process writes a model at a time. Don't download reads the layers with range requests at each start instead;modelDirpoints at local copies. - Runs a background service,
pooled-room, that keeps the room open while the gateway runs and, on a host, warms up OpenClaw's system prompt and tools when the room comes online. - Writes files in
~/.openclaw/pooled/(mode 0600), never inopenclaw.json:room.json(the room's invite key and the passes it gave out, or a joined room's key and pass),status.json(the room as the gateway sees it) andprewarm.json(the last system prompt and tool list). Like every room node, it also saves prompt state in~/.pooled/cache/ckpt/(folder 0700, files 0600, at most 4 GB;POOLED_CKPT_GB,POOLED_CKPT_DIR,POOLED_CKPT_DISK=0turns it off): the attention cache of OpenClaw's system prompt and tools. It is derived from your prompts (their text can be roughly recovered from it), stays on each machine that holds layers, and is safe to delete. - Reads environment variables: the
POOLED_*variables in the config table below, andPOOLED_DEBUG. - Runs one helper program:
nvidia-smiduring onboarding (without a shell, when installed), to read the GPU's memory for the default pledge. - Changes two global OpenClaw settings only if you ask. For a small model, onboarding offers (off
unless you pick it) to turn off tool search (
tools.toolSearch = false) and the memory flush (agents.defaults.compaction.memoryFlush.enabled = false). They apply to every model and agent and stay when you switch; undo them withopenclaw config unset tools.toolSearchandopenclaw config unset agents.defaults.compaction.memoryFlush.enabled. With the 1.7B, the agent gets OpenClaw's file tools only (read,write,edit,ls). - Nothing else: no API key or account, no shell, no OpenClaw hooks, no tools of its own, no telemetry.
Who can see what
- Getting in. A hosted room asks before new devices join. The invite link's key gets a device in;
a code alone waits for
/pooled allow; a device you let in keeps a pass. With Anyone with the code, anyone who has or guesses the code gets in. - Proofs, not keys. Devices prove the invite key or pass on each link instead of sending it, and
the host proves it back. A device waiting for
/pooled allowshows a six-digit code that the gateway's log shows beside its request; if they match, nobody sits in the middle. A device on an older Pooled is markedan older Pooled: it can't prove the invite key. - Screens. A hosting gateway opens its room with visibility
asker: other devices' room pages show "answering…", never OpenClaw's prompts, answers or tool calls. - Devices holding layers see the conversation anyway: each gets the hidden states of every token, which carry the prompt (files OpenClaw read, tool results).
- Devices holding layers can steer the answer: a device can send back any hidden states it likes, which lets it choose the model's output, including the tool calls OpenClaw then runs on the gateway machine. The call grammar only keeps the calls well formed.
- Join mode trusts the room's host with everything: it sends OpenClaw's whole context to the host
and runs the tool calls it gets back. It is flagged as a dangerous setting
(
plugins.entries.pooled.config.mode=join): the gateway logs a security warning at startup, andopenclaw security auditlists it. - Guests in the room can ask their own questions, which queue with OpenClaw's.
allowApiClients: falsekeeps API clients out.
More
openclaw onboard → Pooled → Start a room:
- How much of this GPU's memory to lend (the default is what
pooled hostpicks). - The model: each row shows the memory it needs across the room and whether it's downloaded (or its download size).
- If it isn't downloaded: Download now (with a progress bar, speed and time left), When the gateway starts, or Don't download (stream this machine's layers from Hugging Face at each start).
- How many devices to wait for, and who can join: Invite link only (a device with only the code waits for your Allow) or Anyone with the code.
It prints the room code (4TK-G9P) and the invite link (https://pooled.run/r/4TKG9P#k=…). The
room opens when the gateway starts and keeps its code and link across restarts. If onboarding
couldn't start the gateway, run openclaw gateway run. Onboarding's own AI check (OpenClaw's live
test completion) is answered at once with the room's state, so it passes even while the room waits
for its other devices; no --skip-health is needed.
While a model downloads, a question gets an answer like Qwen3 1.7B is downloading for room 4TK-G9P:
42% · 734 MB of 1.7 GB · 48 MB/s · 18s left. Devices can join meanwhile.
openclaw onboard → Pooled → Join a room, then paste the invite link (or type the code) and
say how much memory to lend. Onboarding connects right away (no GPU needed for that):
- with the invite link, it's let in at once;
- with the code alone, it shows
Waiting for <host> to let this device in · 0:08until the host allows it.
Either way it keeps the pass the host gives it, so the gateway (and every restart) gets straight back in. It also learns the host's model and context.
OpenClaw's own instructions and tools are about 12k tokens, so the room needs at least a 16k context.
pooled host qwen3-1.7b opens at 16k from @pooled/cli 0.3.2; with 0.3.0 or 0.3.1 its host should run
pooled host qwen3-1.7b --ctx 16384 (the 1.7B's longest). Onboarding says so when it sees a shorter one, and so does /pooled.
A room short of memory for 16k (under about 5.5 GB across the room) opens the 1.7B at 8k, the plugin's own room too: then
/pooled warns that OpenClaw needs 16k, and onboarding shows fits on this machine alone at 8k (OpenClaw needs 16k).
In an OpenClaw chat (the TUI, the Control UI, a messaging channel), for the gateway's owner. They need
OpenClaw's operator.admin scope, so openclaw agent --message and gateway call chat.send can't
run them.
| Command | What it does |
|---|---|
| /pooled | The room: invite link, each device's GPU, what it lends and the layers it holds, the memory, who is waiting, the download |
| /pooled allow [n\|all] | Let a waiting device in (the first one, the n-th, or all) |
| /pooled deny [n] | Turn one away |
| /pooled link | The invite link |
| /pooled pledge <GB> | Lend another amount of this machine's GPU memory |
Room problems show in the chat as a short note that starts with Pooled, the room code and what
happened: waiting for devices, not enough memory, downloading the model, a device left, and so on.
They are not part of the conversation the model sees. The
bundled pooled-room skill tells the agent what they mean.
Onboarding writes plugins.entries.pooled.config. Each key can be overridden by its variable.
| Key | Variable | Meaning |
|---|---|---|
| mode | POOLED_MODE | host or join |
| code | POOLED_CODE | The room code (6 characters; 4 for rooms opened before six) |
| — | POOLED_LINK | A room's invite link (join; non-interactive setup) |
| model | POOLED_MODEL | The model a host starts: qwen3.6-35b-moe (recommended), qwen3.8-27b, qwen3-1.7b |
| pledgeGB | POOLED_PLEDGE_GB | GPU memory this device lends |
| minDevices | POOLED_MIN_DEVICES | Devices to wait for before dealing the layers (default 1) |
| waitSeconds | POOLED_WAIT_S | How long a question waits for devices or the host's model (default 120) |
| ask | POOLED_ASK | Host: a device with only the code waits for /pooled allow (default on) |
| allowApiClients | POOLED_ALLOW_API | Host: answer other devices' API asks (another OpenClaw in join mode, pooled serve; default on) |
| pull | POOLED_PULL | Host: download a missing model (default on); off streams it at each start |
| prewarm | POOLED_PREWARM | Host: warm up OpenClaw's system prompt and tools when the room comes online (default on) |
| modelDir | POOLED_MODELS | Models folder (default ~/.pooled/models) |
| ctx | POOLED_CTX | Context to ask for (default the model's largest: 1.7B 16k, or 8k when the room is short of memory for 16k; 27B 64k, MoE 128k) |
| name | POOLED_NAME | This device's name in the room (default <hostname> (OpenClaw)) |
| signal | POOLED_SIGNAL | A PeerServer host:port (default the public PeerJS server pooled.run uses) |
Non-interactive: openclaw onboard --non-interactive --auth-choice pooled with POOLED_MODE=host
and POOLED_MODEL=qwen3.6-35b-moe (without POOLED_MODEL it starts the 1.7B), POOLED_PLEDGE_GB, …,
or POOLED_LINK="<invite link>" to join.
- The gateway's
pooled-roomservice opens the room at startup. A host deals the layers once the room hasminDevicesdevices and enough memory, then replays the last system prompt and tools once (a one-token answer), so the first question after a restart starts from their checkpoint. - OpenClaw's model calls go through a custom StreamFn, with no HTTP hop. The room's host renders the
chat template and constrains tool calls with a grammar; the answer is checked as
pooled servechecks it and streamed as OpenClaw's events. - A joined gateway asks the room's host over WebRTC (the
pooled servebridge), showing the host this device's pass, so the host sees one device, not two join requests.
Known gaps:
- Reading the prompt is the slow part: OpenClaw's prompt is 14-19k tokens. Each device keeps its part
of the pinned system prompt + tools on disk (
~/.pooled/cache/ckpt/), so after a gateway restart the room reads it back when it comes online and the warm-up reads only the last few tokens. Only when the room is exactly the same (model file, layer split, engine settings, context): any change, or a device without its copy, means the full read once, then the cache is filled again. The very first start still reads the whole prompt; answer and turn checkpoints live in GPU memory only. - A room hosted in a browser tab has no turn checkpoints yet, so OpenClaw re-reads more per tool call there than with a Node host.
- Checkpoints are not part of the memory split: at 50k tokens one is about 1 GB across the room (MoE).
- Windows has been tried only with NVIDIA GPUs. With OpenClaw 2026.9.8 on Windows, the Control UI's
chat works only at
/chat/main.
Design notes, results and limits: docs/openclaw.md.
From a checkout of github.com/Nehanth/pooled:
cd packages/openclaw && npm install && npm run build # dist/index.js: the bundle that ships
openclaw plugins install --link --force --accept-capabilities "$PWD" # rebuild after edits
npm test # unit tests: no GPU, no network, no OpenClaw
sh test/pack_install.sh # npm pack, install the tarball into a clean OpenClaw, onboardnpm run build bundles index.js and what it imports from the repo's room/, engine/, harness/,
cli/lib/ and packages/room-node/ into dist/index.js (esbuild); openclaw, webgpu,
node-datachannel and peerjs stay external.
Links
- Guide: pooled.run/docs/kits/openclaw
- Reference: pooled.run/docs/openclaw
- Security: pooled.run/docs/internals/security
- Demo video: pooled.run/docs/media/openclaw-demo.mp4
- Source: github.com/Nehanth/pooled
- Issues: github.com/Nehanth/pooled/issues
MIT license.
