Optimist helps teams design large systems and find what constrains them.
A design is a graph of typed components — clients, load balancers, queues, compute pools, datastores — wired together and annotated with the properties an engineer can measure. Optimist solves that graph with uncertainty carried through it and reports which resource limits the design is closest to exhausting.
A design is a directory of YAML files that belongs in the same repository as the system it describes, so answering a capacity question is a local operation and can run in the same continuous integration that builds the thing being designed.
Important
Optimist is under active development. The modelling, solving, and ranking core is usable today, and the Vue workbench, HTTP API, and CLI all run against it. Authentication is not implemented.
- Component-centric models: components adopt a type, relationships wire them together, and behaviours on those relationships express retries, timeouts, caches, batching, fan-out, and shedding.
- Component types as data: properties, channels, ports, and constraints are declared in YAML manifests. Adding a kind of component means writing a manifest, not changing the engine, and a design may define its own.
- Uncertainty carried through the solve: every value is a Squiggle expression evaluated over aligned draws, so each draw settles on its own fixed point and the spread of a result is a genuine mixture.
- Fixed-point solving: relaxation toward a steady state, or transient integration through time when a design's memory is the question.
- Bottleneck ranking: constraints ordered by the share of draws in which demand meets or exceeds the limit, per scale unit.
- Interventions and comparison: a proposal rebinds named quantities and the design is solved again exactly as it stands, so a difference in the result is attributable.
- Queueing and reliability laws built in: Little's Law, M/M/1, M/M/c, Erlang B and C, bounded queues, retry amplification, deadline races, and error budgets.
- Collaborative editing: a server over a directory of designs, with a mutation feed over WebSocket and a Vue workbench.
- Agent-friendly interfaces: table, JSON, and JSONL CLI output plus a typed HTTP API.
Serve a directory of designs and open it in a browser. The diagram, what each component is sized against, and whether the design solves are all on one screen.
optimist serve --designs ./examplesComponents are coloured by what they are closest to exhausting. Stopping on one names that constraint, draws how loaded it is, and says what saturating it means.
A proposal rebinds named quantities and the design is solved again exactly as it stands, with the baseline drawn on the same axes so the distance between the two lines is the answer.
Constraints are ranked by BINDS, the share of draws in which demand met or
exceeded the limit:
Ranking by that rather than by mean utilisation puts the constraint most exposed to a bad draw at the top, which is the one worth spending on.
On macOS and Linux, install with Homebrew:
brew install sierrasoftworks/tap/optimistOtherwise download a binary for your platform from the
latest release.
Binaries are published for Windows, Linux, and macOS in both amd64 and arm64
variants.
Put it on your PATH and run it directly:
optimist serve --designs ./examplesA released binary embeds the workbench, so nothing else is needed to serve one. To build from a checkout instead, with Rust 1.96 or newer and Node 20.19+ or 22.12+:
npm --prefix workbench ci
npm --prefix workbench run build
cargo build --release # target/release/optimistThe same engine is available as a command-line tool for continuous integration and automation:
optimist check examples/checkout # load and validate, without solving
optimist catalogue examples/checkout # what component types are available
optimist solve examples/checkout # the quantities flowing through it
optimist bottlenecks examples/checkout # what it is closest to exhausting
optimist compare examples/checkout warm-cache╭─ Constraints ────────────────────────────────────────────────────────────────╮
│ COMPONENT CONSTRAINT LOAD MEAN P90 BINDS HEADROOM │
│ orders volume ████████████ 7.01 9.56 99.9% -3.006e12 │
│ api capacity ████████████ 2.92 4.82 87% -1046.4185 │
│ browsers success_objecti… ████████████ 52.48 101 86% -0.2574 │
│ browsers latency_objecti… █████░░░░░░░ 0.4525 0.7744 3% 0.4106 │
╰──────────────────────────────────────────────────────────────────────────────╯
Use --output json or --output jsonl for automation, and --seed,
--samples, --horizon, --step, and --transient to control the solve.
Releases also carry an installer for a desktop application: the same workbench
in a native window, with everything it needs already inside it. Each release
publishes optimist-darwin-amd64.dmg and optimist-darwin-arm64.dmg,
optimist-windows-amd64.msi and optimist-windows-amd64.exe, and
optimist-linux-amd64.deb, .rpm, and .AppImage.
optimist # or double-click the application
optimist app --designs ./designs # open a particular folder for this launchThe installers are not code-signed, so each platform refuses them once before letting you say otherwise:
- macOS — open the application, dismiss the warning, then allow it under
System Settings → Privacy & Security → Open Anyway. Removing the flag by hand
works too:
xattr -d com.apple.quarantine /Applications/Optimist.app. - Windows — SmartScreen offers More info → Run anyway.
- Linux — the AppImage needs
chmod +xbefore it will run. The.deband.rpminstall without complaint.
The first launch says that designs are going in ~/Documents/optimist and
offers somewhere else to put them; the answer is remembered, and the folder in
the title bar changes it again at any time without restarting.
There is no server and no port. The window reaches the same handlers serve
puts behind HTTP through Tauri's IPC, which nothing outside the process can
speak, so a design open in the application is not exposed to anything else
running on the machine.
To build one from a checkout, with the Tauri CLI installed:
npm --prefix workbench run build # the window reads this build
cargo run --features desktop # the window, over that build
cargo tauri build # installers under target/release/bundleoptimist serve --designs ./designsThe server opens a directory of designs, applies typed mutations, streams every change over a WebSocket, and solves designs on request. Clients patch their local copy from the feed rather than refetching, so an edit made by somebody else does not clobber a field you are typing into.
Edits are held in memory and written back to the design directory after a short
quiet period and again on shutdown, in canonical form, so a session produces a
clean git diff.
Browser routes fall back to index.html; generated files under /assets use a
one-year immutable cache while HTML revalidates on every load. /api and every
/api/* path remain JSON-only and never fall back to the application.
A released binary embeds the frontend; a build from a checkout looks for
workbench/dist beside the repository. Point elsewhere with --web-root or
OPTIMIST_WEB_ROOT. Rust builds do not invoke Node; without a valid web root the
server remains API-only.
For frontend work, run Vite's dev server, which proxies /api including the
WebSocket upgrade:
npm --prefix workbench run dev # http://127.0.0.1:5173| Concept | Purpose |
|---|---|
| Component | One part of the system, adopting a component type. |
| Component type | Declares properties, channels, ports, and constraints. Data, not code. |
| Relationship | A wire between two components. Requests travel out, responses back, and work waits on it. |
| Signal | A named quantity travelling along a relationship: rate, latency, success, capacity, occupancy, cancellation, payload. |
| Behaviour | A rule about how work travels, attached to a relationship: retry, timeout, cache, batch, fan-out, load-shed. |
| Scratchpad | Quantities shared across the design, stated once. |
| Scale unit | A boundary within which components are replicated together; constraints are evaluated per unit. |
| Constraint | A demand paired with the limit it consumes. Every bottleneck is one of these. |
| Intervention | A proposed change, expressed as rebindings of shared quantities. |
examples/checkout/
_system.yaml name, shared quantities, scale units, interventions
components/<id>.yaml one component and the relationships leaving it
component-types/<id>.yaml types this design defines for itself (optional)
mutators/<id>.yaml behaviours this design defines for itself (optional)
The full VuePress documentation lives in docs.
cd docs
npm ci
npm run devBuild the static site with npm run build.
Useful starting points:
- Getting started
- Designing a system
- Writing component types
- Uncertainty
- Solving and bottlenecks
- The workbench and shared editing
- CLI reference
- HTTP and WebSocket API
- Design directory format
- Shipped catalogue
Five designs ship in examples, all covered by tests that assert the conclusions they claim to teach:
saturation— where saturation comes from, and why retrying past the fold lowers the share of requests that succeed rather than protecting it.queued-collapse— a queue makes the design second order: a ten-second surge costs seventy seconds of recovery, and leaves it in a second steady state that persists once the backlog has gone.deadlines— a timeout bounds what the caller waits for; only a propagated one withdraws the work. Failing to propagate leaves the failure rate unchanged and doubles what the dependency is holding.checkout— a shop front where the binding constraint is the one nobody watches, and neither proposed fix addresses it.metastable— two steady states at one level of demand, built entirely from shipped component types.
cargo nextest run
cargo nextest run --features comprehensive_tests
cargo test --doc
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps
cargo clippy --all-targets -- -D warnings
cargo fmt --check
npm --prefix workbench test
npm --prefix workbench run build
cd docs && npm ci && npm run buildThe nested fuzz workspace can be checked with:
cargo +nightly check --manifest-path fuzz/Cargo.toml --bins
cargo +nightly clippy --manifest-path fuzz/Cargo.toml --all-targets -- -D warnings- The on-disk schema is at version two. Version one described the causal graph this tool was built around before it became a system design tool; the two share no structure, so a version one directory is refused rather than converted.
- Editing is last-write-wins over whole entities. There are no revisions, no conflict resolution, and no merge.
- There is no authentication or authorisation. Anyone who can reach the port can read and edit every design in the workspace.
- The solver reports the fixed point reachable from rest. Where a design is bistable, the congested branch exists and is not searched for; a wide converged distribution is the signal that the design is near the fold.
- Unit annotations are validated for syntax but are not yet used to reject a property supplied in the wrong dimension.
No licence has been selected in this repository yet. Treat the code as source-available for evaluation until a licence file is added.


