webrender-worker
The paired local worker — the box side of WebRender's local rung. Install it on a machine you own (a Mac mini, a Linux box, a NAS), pair it once to your WebRender account, and it runs your jobs at home — unlimited, private, and free at the point of use. No third-party AI provider ever sees your text.
Two job kinds today:
- read-aloud TTS — renders audio with Kokoro;
- handwriting recognition — reads rendered ink with a local vision model via
Ollama (default
qwen2.5vl:7b-16k; override withWEBRENDER_OLLAMA/WEBRENDER_OLLAMA_MODEL).
The poll declares which kinds this daemon supports, so an older daemon is never handed work it cannot run.
It makes only outbound HTTPS calls (no inbound ports, works behind NAT), holds one revocable account-scoped token, and imports nothing from the WebRender server — this package is the whole box side. Licence: AGPL-3.0-or-later; the wheel is pure Python, so the source you are running is the source in the package.
How it works
CLOUD (WebRender) YOUR BOX (this daemon)
preprocess text, enqueue a job
← poll GET /worker/jobs (outbound)
job → render each segment with Kokoro
← MP3 POST …/result (framed upload)
store MP3 (same store as a paid gen)
player serves it → you listen, any device
The box never sees the document — only the per-segment spoken text the cloud already preprocessed. It renders each segment to an MP3, keyed by the segment's global index, and uploads the batch; the cloud reassembles it into the exact artifact a paid generation would produce. A recognition job mirrors that line one step further: the box sees rendered ink pixels and a server-supplied prompt, never the document.
Install
Python (recommended on macOS)
Requires Python 3.10–3.13 (the Kokoro stack has no 3.14 wheels yet) and ffmpeg on
PATH (the MP3 encoder).
# ffmpeg: macOS → brew install ffmpeg · Debian/Ubuntu → sudo apt install ffmpeg
pip install 'webrender-worker[render]' # or: uv pip install 'webrender-worker[render]'
The render extra is the Kokoro TTS stack. Plain pip install webrender-worker gives
only the daemon skeleton — useful if you are implementing against the protocol, not for
actually rendering audio. The first render downloads the Kokoro model weights (~a few
hundred MB, cached).
⚠ On Linux, pip install pulls the default PyPI PyTorch wheel, which drags several GB
of CUDA libraries a CPU rung never loads. Either install CPU-only torch first
(pip install torch --index-url https://download.pytorch.org/whl/cpu) or use the Docker
image below, which does exactly that for you.
Docker (Linux / WSL2 / NAS)
No Python or ffmpeg on the host, and CPU-only by design:
docker run --rm -it -v webrender-worker:/data \
ghcr.io/josephnhopkins/webrender-worker pair # open the printed link
docker run -d --restart unless-stopped --name webrender-worker \
-v webrender-worker:/data ghcr.io/josephnhopkins/webrender-worker
Logs: docker logs -f webrender-worker. The webrender-worker named volume holds the
pairing token and the Kokoro model cache, so it survives container recreation.
On macOS, run the daemon natively instead — Docker on a Mac is a hidden Linux VM: it taxes RAM and cannot use Apple-silicon acceleration.
Use
webrender-worker pair # prints a link; open it signed in to WebRender
webrender-worker run # start rendering (leave it running)
webrender-worker status # build, host + paired state
webrender-worker status --json # the same, machine-readable
webrender-worker unpair # revoke this box + forget the token
Pairing is a device flow: the daemon prints a one-time link, you open it in a browser where you are already signed in to WebRender, and the box receives its token. Nothing inbound, and no password ever reaches the box.
The token lives in ~/.webrender-worker/config.json (mode 0600). You can also disconnect
the box from your WebRender account page — the kill-switch — and the daemon then stops
with a "re-pair" message on its next poll.
pair and run accept --host URL to point at a different WebRender deployment (a
self-hosted one, or a dev server). You do not need it for the hosted service.
status --json
The machine-readable contract — parse this rather than the text face, and paste it into any support conversation. It never contains the pairing token.
{
"version": "0.1.0",
"host": "https://magic-box.co.uk",
"paired": true,
"account": "you@example.com",
"doorbell": true,
"config_path": "/home/you/.webrender-worker/config.json"
}
doorbell reports whether the wake-free transport is configured. When it is, the daemon
sleeps between jobs instead of polling on a timer — which is what lets both your box and
the cloud idle. A build old enough to lack it falls back to a 5-second HTTP poll, so
keep the daemon reasonably current (pip install -U webrender-worker, or re-pull the
image). The daemon reports its version to the cloud on every call so that a future release
can tell you when an update matters.
Resilience
- Sleep-wake / dynamic IP / NAT: the loop only dials out, so it resumes cleanly after the box wakes; network blips and cloud cold-starts are retried with backoff.
- Crash mid-render: the cloud reclaims a job whose heartbeat goes stale and re-queues it, so a job is never lost — the box just re-renders it on the next poll.
- More than one box: the protocol tolerates N workers on one account; claims are atomic, so whichever box polls first takes a given job.
Licence
AGPL-3.0-or-later. It is a component of the AGPL WebRender system.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file webrender_worker-0.1.0.tar.gz.
File metadata
- Download URL: webrender_worker-0.1.0.tar.gz
- Upload date:
- Size: 35.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c438a8df97f90fe5ce43d29801a0a3d1b129af5b0af7f273b0369562733a1741
|
|
| MD5 |
af07441a5ff443552daa890cc9fe12d7
|
|
| BLAKE2b-256 |
a01d45e8a414e6212aeede2d2b0cdb792d62e89e08a7a9628e6dae5437cb9467
|
File details
Details for the file webrender_worker-0.1.0-py3-none-any.whl.
File metadata
- Download URL: webrender_worker-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3407976680f30724b133e7b4a50ca39f1245d760fd57a79a94f653f373d0e18
|
|
| MD5 |
08925dfd114583783b435cf9b6abdbc1
|
|
| BLAKE2b-256 |
691bd744f1b760a8df5c2bf3decf54e908eb22c8b88362cbf9bdcd6e744b635a
|