Contributing
Testing
Which tests run on any machine, which need a GPU and model files, and what CI checks.
Unit tests and browser tests (headless Chromium on SwiftShader, a software GPU) run on any machine and cover most room, Code mode and Serve API changes. GPU tests need WebGPU in Deno and the model files.
No GPU needed
Section titled “No GPU needed”npm test # unit tests (Deno), 84 test files in tests/unitnpm run check # type-check the engine, syntax-check everything elsetests/run.sh selftest # proves the GPU runner fails on a printed FAILThe browser tests need npm install first, for Playwright and the peer signaling server:
npm run e2e:code # Code mode end to end: two tabs, a real room, a scripted model builds and fixes Tetrisnode tests/e2e/preview_browser.mjs # the Code mode preview sandboxnode tests/e2e/room_synth.mjs # the real engine and room on a tiny synthetic modelnode tests/e2e/signal_fallback.mjs # signaling fallback: cloud down, one server down, all down, a drop mid-roomharness_tetris.mjs (behind e2e:code) and room_synth.mjs take --port and --signal-port when the default ports are busy.
The Serve API bridge has its own Node tests:
npm ci --prefix clinode --test cli/test/*_test.mjs # drives the bridge with the official openai and anthropic SDKsWith a GPU
Section titled “With a GPU”You need a GPU with WebGPU and Deno 2. Put the model files under models/ (it is git-ignored):
models/ qwen/ model.gguf (Qwen3 0.6B Q8_0), model-q4.gguf, tokenizer.json, config.json qwen17/ model.gguf, tokenizer.json, config.json # Qwen3 1.7B, Code mode's small model q38/ model.gguf (Qwen 3.8 27B Q4_0) q36moe/ Qwen_Qwen3.6-35B-A3B-Q4_0.gguf # for tests/test_moe.js model/ SmolLM2-135M: model.safetensors, tokenizer.json, config.jsonRun the suites through tests/run.sh:
| Command | What it runs | Needs |
|---|---|---|
npm run test:gpu (run.sh quick) |
Golden tests on Qwen3 0.6B and SmolLM, streams, batching, splits | The small models. About a minute. |
npm run test:q38 (run.sh q38) |
The 27B suites, including speculative decoding equal to plain, one process per file | About 16 GB of GPU memory. The reference run before you land. |
npm run test:q38once |
The same 27B checks in one process with one weight upload | About a minute once the cache is warm. |
tests/run.sh extra |
MoE, sharding, splits, the full 27B: GPU tests no other suite covers | The MoE and 27B files. |
npm run test:all |
quick plus q38 |
A test fails if it exits nonzero or prints FAIL/FAILED. STRICT=1 also fails on SKIP; ONLY=test_mtp,test_ctx runs a subset of q38once.
To run one test on its own:
cd tests && deno run --unstable-webgpu --allow-read --allow-env test_qwen.jsThe converted-weights cache
Section titled “The converted-weights cache”The 27B and MoE tests keep converted tensors in ~/.cache/swarmllm-weights (about 16 GB and 20 GB), so a warm load takes seconds instead of converting the GGUF again.
| Variable | Effect |
|---|---|
WEIGHT_CACHE=0 |
Turn the cache off. |
WEIGHT_CACHE=<dir> |
Keep the cache somewhere else. |
WEIGHT_CACHE_VERIFY=1 |
Also check each entry’s checksum (about 1.5 times the warm load time). |
WEIGHT_CACHE_PRUNE=1 |
Delete directories left over from older loader versions. |
Any edit to engine/gguf.js starts a new cache directory. npm run test:cache checks the cache is byte-identical.
Rooms on one machine
Section titled “Rooms on one machine”Real rooms between headless Chromium tabs on your machine. GPU needed; run by hand.
| Command | What it checks |
|---|---|
npm run e2e -- --phone |
Host, worker and a phone-shaped tab. --wire off|slice|stripeN picks the transport. |
node tests/e2e/room_chaos.mjs --devices 3 --plan net |
Latency, loss and freezes (no root). Other plans: death, signal, join, turn. |
node tests/e2e/room_drop.mjs --devices 3 |
A silent device is noticed in 3 to 5 s; a bad network is not mistaken for one. |
node tests/e2e/room_resume.mjs |
Lock, reload or kill a device mid-answer; the text must match an uninterrupted run. |
node tests/e2e/room_latency.mjs --model qwen3.6-35b-moe --devices 2 --lat 0,5,20 |
Speed against emulated latency. |
node tests/e2e/serve.mjs |
pooled serve against a real 1.7B room with the official SDKs; --codex, --claude run an agent turn. |
Real devices
Section titled “Real devices”Rigs for two machines (tests/e2e/xroom_pair.sh, xroom_report.mjs) and a USB-attached iPhone (xroom_phone.mjs, xroom_cluster.sh, resume_phone.mjs) are described in docs/testing-fast.md. The phone must open an https page, and all devices must run the same commit.
What CI runs
Section titled “What CI runs”Every pull request and every push to main runs two jobs on GitHub’s Ubuntu runners:
node --checkon every engine, room, harness, site, test, benchmark and script file.- The unit tests,
deno test --parallel --allow-read tests/unit, with a JUnit report. - The
pooled servebridge tests (node --test cli/test/*_test.mjs). - A sanity check of the kernel generator (
tests/unit/generator_smoke.js). scripts/check-test-report.mjs, which fails the run on zero tests, or on a skipped test that isn’t on its allowed list.tests/run.sh selftest.
Runs tests/e2e/preview_browser.mjs in Playwright’s Chromium. Allowed to fail for now.
CI has no GPU, so say in your PR which GPU tests you ran, and on which GPU.