Substrate
A Python runtime that coordinates models and anything else you want through a single append-only log. Replay, diff, and trace every run.
The pieces
PRODUCER · BUS · TRIGGERA Producer takes typed input and streams typed Events. LLM, ML model, deterministic transform, subprocess, parser — anything of that shape.
Events land on the Bus: one totally-ordered append-only log per run. Producers coordinate only through it.
A Trigger starts a new Producer when its Predicate holds over the log. After the initial Producers, Triggers are the only way new ones appear.
A Python 3.12+ runtime for running many computations together. You hand it model calls, transforms, subprocesses, parsers, simulators — anything that takes typed input and emits typed events. It runs them concurrently and coordinates them through one append-only log. Every event, and every runtime decision about what to start next, lands on that log. You replay the log, diff it, or inspect any point.
You hand the runtime a topology: a Python function that declares which computations can run and what starts them. Nine names carry the design — Producer, Event, Bus, View, Predicate, Trigger, Route, TerminationPolicy, and the run record itself (framed, CRC-protected JSONL, canonically encoded).


Every topology is a short Python program. code_review runs several cheap models on the same task, has a stronger model adjudicate, and cancels the losing runs when the verdict lands. coding_flow streams code from a writer Producer while a checker Producer fires on each complete declaration as it arrives — writer and checker run at the same time. The check is real: ruff, mypy --strict, pytest on the code the writer produced.
debate puts two model Producers on opposite sides of a claim; the run ends on a convergence condition. adversarial_pair runs a writer and an attacker streaming from t=0. A planner-and-solver topology emits subtasks that each start solvers that can themselves emit more subtasks.
Every computation reads the log and writes typed events back to it. Producers never call each other. The log is the coordination surface, and it is the only one.
The set of running Producers is not fixed. You write conditions over the log — "once three answers are in", "when this step fails" — and when a condition holds, the runtime starts another Producer. A run's shape grows as it unfolds. Recursion is a Producer that starts more of itself. Every event and every runtime decision lands on the log; you read back what happened and why, and replay at any point.
