Build multi-agent applications.
DisSysLab is a Python library and a set of skills that AI assistants — Claude Cowork, Codex, Gemini CLI — can use to build distributed applications in which many agents run concurrently. Some of these applications monitor data sources such as news, sensors, and social media, and respond by sending messages to actuators, consoles and files. Other applications process data sets such as historic stock and weather records.
An AI assistant builds an application by assembling components from the library. The library contains the machinery for concurrent computation - messages, agents, termination detection, checkpointing, crash recovery. The primitives in the library have been tested and have clear specifications. An AI assistant can also build an application without the library; however, it then has to generate the concurrency machinery from scratch for each new app.
A distributed system is represented by an office in which everyone works remotely. Each agent - worker - in the office receives messages from its inboxes and puts messages in its outboxes. An agent cannot communicate in any other way. The office network specifies connections from outboxes to inboxes. The distributed system machinery removes a message from an outbox and sends copies of the message to each inbox to which it is connected. Offices are described in detail below.
Here are two examples of building distributed apps. The first is for a pre-teen who likes learning about space, and the second is for a finance "quant" who develops stock-trading strategies.
An adult installs Claude Cowork on Su's laptop and chooses on your computer rather than in the cloud when given that option. Now Su builds a distributed app for herself.
1. Start a task, on your computer.
2. Say:
The project is at https://github.com/kmchandy/DisSysLab. Install its Python package
dissyslabfor me, then rundsl doctor.
3. Say:
Install the
office-builderskill from that repository, then rundsl doctoragain.
dsl doctor's Skills section names the skill and its version, or
says it is not installed and lists where it looked. Do not ask the
assistant which version it has — an assistant that never loaded the
skill will answer anyway. Where a skill lives is a question about the
filesystem.
4. Now talk. Everything below is Su, one sentence at a time.
Give me an office with Dan and Jay.
# Office: draft
Agents:
Dan is unassigned.
Jay is unassigned.
Two agents, no jobs yet. Still to do: Dan and Jay have no job; nothing comes in; nothing goes out; nothing is connected.
She has not said what they do and she was not asked. Nothing was invented for her, and what is missing is a list rather than an error.
Dan reads the space news and keeps only the ones about Mars.
Dan is a relevance_filter.
Alongside it the assistant writes roles/relevance_filter.md — the
library's version of that role with its criteria rewritten to say
"about Mars". Dan's job is a paragraph of English she can read and
edit.
Jay writes one sentence about each one Dan keeps. Show me them on the screen.
# Office: mars_watch
Sources: nasa_news(max_articles=10)
Sinks: console_printer, discard
Agents:
Dan is a relevance_filter.
Jay is a summarizer.
Connections:
nasa_news's destination is Dan.
Dan's keep is Jay.
Dan's discard is discard.
Jay's out is console_printer.
No gaps. Your office runs.
Three sentences. Dan and Jay are separate agents that share nothing and can only send each other messages; the office keeps running and checks for new stories on its own; and when there is nothing left to do it works that out and stops. Su wrote none of that and can read all of it.
Su picked space. The same three sentences build the same office around
anything that publishes a feed — a game's update notes, a football
club, a webcomic — by pointing it at the address:
rss(url="...", name="patch_notes").
1. Start a task, on your computer.
2. Say:
The project is at https://github.com/kmchandy/DisSysLab. Install its Python package
dissyslabwith the market extra, then rundsl doctor.
The market extra carries the price downloader and the spreadsheet
writer. dsl doctor reports whether both arrived.
3. Say:
Make me a copy of the
mac_speed_suitebacktester in a folder calledmy_backtest, then download ten years of prices for the tickers it uses.
That runs dsl init and then dsl fetch-prices --office my_backtest,
which reads the basket out of the office's own source line, skips
anything already downloaded, and finishes by loading each ticker back
through the office to confirm it can read what was just written.
Nothing in this repository ships market data. The vendor's terms do not permit redistributing it, so every user fetches their own — which is why the downloader lives in an extra you install deliberately.
4. Ask for what you want to see:
Show me the working for the Donchian 20 strategy on NVDA.
You get an Excel workbook: one row per trading day, every quantity the strategy computed on the way to its decision — not just the signal but the upper and lower channel — and a sentence at the end of each row saying which rule fired. "close 121.8 > upper 119.4 — go long."
Each computed quantity appears twice: once as the number the Python
produced, and once as a live Excel formula over the price cells, with
a column comparing the two. Click a shaded cell and the formula bar
reads =MAX(C2:C21) — the channel is built from the twenty rows
above this one, not this one. A boundary convention that is
ambiguous in English, invisible in a chart, and decides whether a
backtest was honest. If it is not your rule, edit the cell and watch
the signal column move.
To be straight about what that does and does not give you: both columns are one person's reading of the rule, written twice. If the rule was misread, both are wrong together. What the formula gives you is a specification you can read without reading Python.
| Watching the world | news briefings, an arXiv radar, a competitor watch, a weather monitor |
| Your own day | a morning page, inbox triage, a wardrobe assistant |
| Money and markets | a ticker read in plain English, a backtester, a paper trader |
| Work and operations | job matching, ticket routing, lead qualification, shipment release |
| The physical world | bird calls from recordings, animals in camera-trap photos, room climate, a loudness alarm |
| Learning and argument | an adaptive tutor, a structured debate |
dsl list shows all forty — 31 applications and 9 smaller examples —
and course/START_HERE.md describes each one.
The quickest way to something you want is to start from the nearest
one and say what should be different.
course/SETUP.md is the same path at more length, with what to do when a step misbehaves. Students begin at course/START_HERE.md. Contributors begin at CONTRIBUTING.md.
Everything an application needs in order to keep running and pass
messages, written once and tested: agents as threads with named
inboxes and outboxes, the network that connects them, distributed
termination detection, the Chandy–Lamport global snapshot for
checkpoint and resume, and a library of sources, sinks and roles to
build from. dsl list shows the shipped offices; dsl check reads an
office and reports its structural faults without running it;
dsl draw renders it; dsl doctor checks an installation.
A skill is a folder of instructions an assistant loads — an open
format, the same SKILL.md in Claude Code, Codex and Gemini CLI.
DisSysLab has two kinds.
The basic skills know how to build an office: the grammar, the
role library, the sources and sinks, and the check-and-fix loop.
office-builder covers offices in general and
sensor-office-builder covers the shape where a model classifies a
signal.
Domain skills add a field's components and, more to the point, a field's characteristic mistakes as checks that run against code the check's author never saw. Trading is the one that exists. Before a strategy is traded on, three mechanical checks run: that it produces one finite signal per bar, that it is deterministic, and that it does not use tomorrow's prices to make today's decision — the last verified by recomputing on truncated history and failing if any earlier decision moves once later bars are added.
Look-ahead bias is not a concurrency bug. It is a finance bug, and only someone who knows finance knows to check for it. That is the pattern the project is exploring: a domain expert contributes their field's parts and their field's suspicions, and inherits the concurrency. One domain exists. One instance is not evidence that a pattern generalises.
An office is a network of agents, each with one job. Sources fetch from the world, agents transform the stream, sinks act on the result. The office below reads three news feeds, removes duplicates, extracts four kinds of information in parallel, waits for all four, and writes a briefing.
flowchart LR
bbc_world[bbc_world]
npr_news[npr_news]
al_jazeera[al_jazeera]
Sasha[Sasha<br/>deduplicator]
Eve[Eve<br/>entity_extractor]
Sam[Sam<br/>severity_classifier]
Tom[Tom<br/>topic_tagger]
Greta[Greta<br/>geolocator]
Sync[Sync<br/>synchronizer]
Riley[Riley<br/>writer]
intelligence_display[intelligence_display]
jsonl_recorder_briefing[jsonl_recorder_briefing]
bbc_world --> Sasha
npr_news --> Sasha
al_jazeera --> Sasha
Sasha --> Eve
Sasha --> Sam
Sasha --> Tom
Sasha --> Greta
Eve -->|entities| Sync
Sam -->|severity| Sync
Tom -->|topic| Sync
Greta -->|location| Sync
Sync --> Riley
Riley --> intelligence_display
Riley --> jsonl_recorder_briefing
classDef src fill:#dbeafe,stroke:#1d4ed8
class bbc_world,npr_news,al_jazeera src
classDef sink fill:#fef3c7,stroke:#92400e
class intelligence_display,jsonl_recorder_briefing sink
That diagram was produced by dsl draw, from the office's
office.md below, which is the whole program:
# Office: situation_room
Sources: bbc_world(max_articles=3), npr_news(max_articles=3), al_jazeera(max_articles=3)
Sinks: intelligence_display, jsonl_recorder_briefing(path="briefings.jsonl")
Agents:
Sasha is a deduplicator(by="url").
Eve is an entity_extractor.
Sam is a severity_classifier.
Tom is a topic_tagger.
Greta is a geolocator.
Sync is a synchronizer(inboxes=["entities", "severity", "topic", "location"]).
Riley is a writer.
Connections:
bbc_world's destination is Sasha.
npr_news's destination is Sasha.
al_jazeera's destination is Sasha.
Sasha's out is Eve, Sam, Tom, Greta.
Eve's out is Sync's entities.
Sam's out is Sync's severity.
Tom's out is Sync's topic.
Greta's out is Sync's location.
Sync's out is Riley.
Riley's out is intelligence_display, jsonl_recorder_briefing.
You do not write this file. You read it. It is the record of what was built, and reading it is how you check that what the assistant understood is what you meant. It is also what you revise: you say what should change, and the assistant changes the file.
Each agent's job is either English in roles/<name>.md, run by a
language model, or Python in roles/<name>.py, which is deterministic
and costs nothing. An office is itself a black box with inboxes and
outboxes, so an office may contain offices.
dsl check my_officedsl check reports an office's structural faults before it runs: an
inbox nothing writes to, an agent nothing can reach, work that reaches
no sink, a sink nothing feeds, a role with no file behind it, a source
or sink name in no registry with the nearest real name suggested, a
sub-office whose folder is not there, a feedback loop with no gate.
That is why office.md has a narrow grammar. The language is small
not so that a person can write it, but so that a checker can catch
what a language model got wrong before anything runs. A more
expressive language would be pleasanter to write by hand and would
have less of it checkable.
An office still being described is a draft — some agent's job is
undecided — and then the same findings are reported as remaining work
rather than faults, and dsl check exits 0. An unfinished office is
not a broken one.
The check is structural, and it stops where structure stops. An office whose diagram is correct can still deadlock, because whether a message is ever readable can depend on execution history rather than on the graph. That boundary is one of the subjects the course teaches.
The library is free and so is running it. Offices that use only Python
cost nothing at all. Where an agent needs a language model you have
two choices, and the assistant will set up either: a model on your own
machine through Ollama, free and accountless but wanting a reasonably
recent laptop; or a hosted model, a few cents a day for a typical
morning brief. Agents in one office can use different models —
Eve's AI is ollama. alongside Riley's AI is claude. — so an
application need not be uniformly expensive.
Every office in this repository stops after a few cycles by default, so that nobody meets this project by way of a bill. Most are designed to run indefinitely and you can say so. docs/LANGUAGE_MODELS.md has the details.
Not a recommendation. A record of what we actually did, because the interesting part is which skill supplied what.
He asked for a backtest of several trend-following rules, ranked.
The office-builder skill turned that into an office: one price
source, a validation gate, a market-context agent, four strategy
families fanning out to eleven backtester instances, a synchronizer
joining them, and an evaluator ranking the results. Adding a twelfth
variant is an agent line and two connection lines. Nothing about that
office is specific to trading — it is the same fan-out and fan-in as
the news briefing above.
The trading skill supplied the parts that are about markets. The strategy contract — a function from bars and parameters to one signal per bar, where the signal is a position fraction rather than a direction — and the three checks, look-ahead among them. Those checks run against strategies their author never saw.
Then he told us the thing we had not thought of. He could read the ranking but could not tell whether the code implemented the rule he had in his head, and he was not going to read Python to find out. So we added a third thing: a per-bar trace, written as a spreadsheet, with every intermediate quantity shown twice — once as the number and once as a live Excel formula. That was not in either skill. It came from a tester saying what he could not see.
What we would do differently, stated plainly. The office assumed a git clone for eighteen months without anyone noticing, because we only ever ran it from one. The look-ahead check is offered as a script rather than run as part of building the office, so an eleven-agent fan-out can contain a strategy nobody checked. And ranked output — "show me the top 10" — is what he asked for next, and is not built.
The second half of the point. A student builds something they care about, and then finds out what was holding it up.
- Termination detection. How does an office know that no agent will ever send another message, when no agent can see the whole system? It does this every time it exits cleanly.
- Global snapshots. The Chandy–Lamport distributed snapshot is implemented; dissyslab/gallery/apps/recovery_demo/ interrupts an office mid-run and resumes it.
- Causal order.
dsl run --tracerecords what every agent did, anddsl explain-tracemerges the per-agent logs into one sequence ordered by logical timestamp. Reading it is how you see that "before" in a distributed system is not the same as "earlier on the clock".
The formal treatment behind the course is Parallel Program Design: A Foundation, K. Mani Chandy and Jayadev Misra (Addison-Wesley, 1988). Algorithm notes are in docs/algorithms/.
Stated plainly, so that nobody infers a promise the software does not keep.
- Single machine. An office runs in one process, each agent in a thread. Per-agent process parallelism does not work, so eleven backtesters running concurrently is concurrency and not speed. The intended unit is a whole office, which is designed and not built (docs/internals/design/process_per_office_design.md).
- Checkpoint-recovery is opt-in. An office has it where the author
of a stateful agent has written
save_stateandload_state. - Deadlock detection does not exist.
dsl checkfinds structural faults only. - Domain checks are not proofs. They catch the mistakes a field knows it makes. They do not establish that what was built is what you meant. The conversation does that, and you stay in it.
- One domain library exists. Trading. No others.
- No first-party web interface. Offices produce files: HTML, JSONL, text.
- Platforms. Linux and macOS are supported and in CI. Windows runs and is in CI, with setup notes in docs/WINDOWS.md.
The library stands on its own.
pip install dissyslab
dsl init periodic_brief my_brief
cd my_brief && dsl run .No API key, no account, no model download. After ten to twenty seconds the office has written a styled HTML brief from live news headlines and current weather.
This is not the intended way to use the library; it is here as evidence that the machinery is real and runs without an assistant.
Sense-and-respond systems have belonged to large institutions for decades. Militaries formalised them as the OODA loop; Stephan Haeckel introduced "sense and respond" as a business methodology in 1992; in 2009 Roy Schulte and I published Event Processing: Designing IT Systems for Agile Companies (Morgan Kaufmann). I worked on two startups building such systems, and helped build earthquake-warning and radiation-detection systems — see Community Sense and Response Systems: Your Phone as Quake Detector, CACM, July 2014.
They belonged to institutions because only institutions had the expertise and the compute. That is what has changed. A person can now describe an office in plain English and lean on tested machinery for the parts that are hard to get right.
I am using this to teach distributed algorithms to undergraduates, first-year students included. The measure I hold it to is one sentence: a first-year builds an application they care about, and then studies the algorithms underneath it.
| Path | Contents |
|---|---|
| skills/ | Skills an assistant loads to build offices |
| course/ | The course: setup, what you build, the catalogue |
| docs/ | Reference: components, backends, algorithms, internals |
| dissyslab/ | The library and the gallery |
| tests/ | The suite; CI runs it on Python 3.10–3.14 |
| archive/ | Dated documents, kept but not maintained |
git clone https://github.com/kmchandy/DisSysLab.git
cd DisSysLab
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
dsl doctor && pytest tests/ -qNote the [dev]: a plain pip install -e . runs offices but omits
the test tools. Market-data offices need
pip install "dissyslab[market]". For offices with language-model
agents, choose a backend and export its credentials — see
docs/API_KEY_SETUP.md and
docs/LANGUAGE_MODELS.md.
MIT; see LICENSE.

