Tolquane Web
Draw, run, debug and schedule parallel Python flows
multiprocessing boilerplate, queues that fill up, and the one bug everybody has met at least once, the program that stops without saying why. Tolquane is my answer to that, and it comes in two parts: a library of composable building blocks that never hangs, and a browser editor where a flow is drawn, run, debugged and scheduled in a few clicks.
Try the editor right now, nothing to install, sign in as demo with the password tolquane:
https://huggingface.co/spaces/robtacconelli/tolquane
>> is a pipeline, a farm copies a worker
That is the whole vocabulary. Here is a complete program:
import tolquane as tq
@tq.source
def numbers():
yield from range(1, 101)
@tq.node
def double(x: int) -> int:
return x * 2
@tq.sink
def show(x: int) -> None:
print(x)
tq.run(numbers >> tq.farm(double, workers=4, ordered=True) >> show)
tq.farm runs four copies of double, and ordered=True puts the results back in input order. Return tq.SKIP to drop an item, yield from a node to emit several, take a ctx argument to route items yourself. Beyond farms there are comb (fuse two nodes on one thread), all2all (two farms joined worker to worker), feedback (loops that terminate by rule, no hand-written protocol), and a farm can hold any block as its worker, a pipeline, another farm, a loop.
The vocabulary is the one of the FastFlow building blocks, the C++ library from the Universities of Pisa and Turin that has been running on many-cores and clusters for fifteen years. Tolquane keeps the ideas and puts a Python face on them.
The graph never changes. Only the runtime argument does.
| Runtime | Nodes run as | Pick it when |
|---|---|---|
threads |
one thread per node | I/O-bound stages, numpy and C extensions, full parallelism on free-threaded 3.14t |
processes |
farm workers in child processes | CPU-bound pure Python on a GIL build |
| async nodes | coroutines on an event loop, a farm of them as one pool | hundreds of requests in flight on one thread |
| distributed | groups on hosts, TCP between them, from one deploy file | two or more machines |
sync |
one node at a time, deterministic | tests and debugging |
Measured on a 16-thread machine, a farm of eight CPU-bound Python workers: 0.9× on threads with the GIL, 5.5× with processes, 5.6× on free-threaded 3.14t. A million items over loopback TCP take 3.5 s. tolquane launch deploy.toml flow.py starts every host over ssh from one terminal.
Every channel is bounded. Every node waits in one place. End of stream is a message that cannot be lost or raced. An error in any node cancels the run and names the node. A graph that cannot make progress raises a DeadlockError that names the nodes and what each one waits for, on threads with a watchdog, on the sync runtime at the exact instant. Feedback loops close themselves when the outside input has ended and nothing is in flight. Fifteen such rules are written down in the design document, each with the bug it closes and the test that pins it.
tq.optimize(graph) is the other half of the deal: it fuses a stage before a farm into the farm's emitter, drops collectors the next stage can do without, and flattens farms of farms, so the natural way of writing a flow costs no extra threads.
The file stays the artifact. The editor reads flow.py into a model, shows it as block cards on a canvas, farms and loops as containers, and writes it back in the same style when you edit on the canvas. Switch to Code and edit the Python directly: the canvas follows. Every node's body is editable in the properties panel. Nothing you write is ever rewritten by a generator; positions live in a sidecar file. A flow made here runs anywhere with python flow.py and the library alone.
Run and debug. A run is a child process that streams events. Cards colour by state, counters and busy time move, edges show their queue depth, and Taps show the last items that crossed any edge. The drawer holds the console, the report (busy, wait-in, wait-out per node, with the bottleneck named), and the problems, each pointing at its card. A deadlock lands on the canvas as a report, not as a frozen page.
The AI builder. Describe the flow in one sentence in the side panel. It writes the file in the house style, checks the wiring, runs it on a sample, fixes what fails, and hands you a flow card with a diff and an Apply button. Ask it to make a flow faster, or to add a stage, and the same loop runs on your open file. You bring a Claude or GPT key; it never leaves the server.
And the rest of a working tool. Parameters on build() become typed fields in the run popover and in schedules. Schedules use cron presets with a live preview of the next times, and tell you how a run went by webhook or mail, with retries. A git history of every flow: versions, diffs, restore, save with a message. Accounts with admin and member roles for a shared server. Settings for the interpreter, the workspace environment, keys and notifications.
pip install "tolquane[web]" then tolquane web opens the editor on your own workspace; the library alone is pip install tolquane, pure Python, no dependencies.Apache-2.0, Python 3.11 and newer. Next on the list: divide-and-conquer and parallel-for helpers, a deploy editor to drag cards onto hosts and launch a cluster from the canvas, and an examples gallery. Try it, break it, and tell me what you would build with it. A ⭐ on the repository helps others find it.
Draw, run, debug and schedule parallel Python flows