Start here
sim.pflow.xyz answers what-if questions about an operation: a clinic, a café, a build farm, a ferry dock. Each model is a Petri net — places hold tokens (people, staff, stock), transitions move them — and the engine plays the net forward with a fixed random seed, so the same question always gets the same answer.
- Pick a model from the catalog and click Open console. No sign-in needed.
- Drag a control. The chart, the net and the results update instantly — that is a local preview.
- Click Run to have the server confirm the number. Click Compare +1 to see what one more unit of each resource is worth.
- Read the results with the caveats underneath. They say what the model could and could not enforce.
- Optionally sign in with Google to publish the run into your own spreadsheet, or to build a model of your own.
The catalog
The catalog on the front page lists the curated models (vet clinic, café, predator–prey) followed by every model that a user has dedicated to the commons under CC0 or CC-BY. Each card offers:
- Open console — the generic what-if console, read off the model's own structure.
- Open app — a published stand-alone app for that model, when one exists.
- Dataset — a synthetic event log (CSV) generated by the model, seeded, suitable for process mining.
- Publish to Sheets — runs the default scenario and builds a workbook in your Google Drive (sign-in required).
Models are content-addressed: the id in the URL is a hash of the model itself, so a link to a model never changes meaning. Editing a model produces a new id and the old one stays reachable.
The what-if console
The console at /whatif/?id=… is the same page for every
model. Nothing on it is hand-written per model: the controls, disruptions,
drawing and result rows are all derived from the net, and a model's own
About this model notes appear at the top when it carries any.
Controls
Every slider comes from a role the net's structure declares:
| Control | Where it comes from | What moving it means |
|---|---|---|
| Pool (e.g. baristas, exam rooms) | A place whose tokens are borrowed and returned — a resource. | How many of that resource are on shift. |
Source /hour | A transition that creates tokens from nothing — arrivals. | Demand rate. |
Patience /hour | A transition that drains a queue without serving it — walkouts, abandonments. | How quickly people give up waiting. |
| Horizon | The run itself. | How many hours to simulate. Disruptions are timed as fractions of it. |
A model may caption and group its controls, but it may never hide one. A knob worth nothing at today's setting can be the decisive one once the current bottleneck is relieved, so the console keeps every knob visible and lets Measure influence rank them instead.
Disruptions
One-click hypotheticals derived from the same roles: a pool unavailable for part of the run, an arrival wave, a queue with a backlog at open, a source closed. A model can add named disruptions of its own. Each one is only a marking, a rate or a schedule the scenario API already accepts, so nothing here can ask a question the API could not.
Run, Compare +1, Measure influence
| Button | What it does | Cost |
|---|---|---|
| Run | Sends the current controls and disruptions to the server as one scenario and shows the confirmed result. | One request, sub-second. |
| Compare +1 | Runs the current scenario beside "each pool plus one" (up to two pools), all on one shared seed, so the difference between columns is the staffing and not the dice. | One request. |
| Measure influence | Runs the model many times to measure what each control is actually worth, then reorders the controls by that measurement and reports the model's fitness gates and discovered parameter classes. | Tens of runs; a few seconds. Never runs on load. |
| Publish to Sheets | Publishes the current scenario to a new Google Sheet in your Drive. | Sign-in required. |
| Export comparison | Publishes the exact ladder that Compare +1 produced, with the scenario JSON on a hidden tab so the workbook can re-run itself. | Enabled after a Compare. Sign-in required. |
| Download dataset | 500 synthetic cases as a seeded CSV event log. | Free, no sign-in. |
Preview vs. confirmed
The badge next to the buttons tells you which engine produced what you are looking at:
live preview — drag more, or Run to confirm
Computed in your browser by the same firing rule the server uses, so it
follows every tick of a drag. It is a preview, never a quote: a
number you quote, export or act on should come from a Run.
server-confirmed
The last Run or Compare answered by the server. Moving any control returns you to preview.
live preview unavailable here (…)
This model uses a feature the browser engine does not support yet; the
reason is in the brackets. Every button still works — only the instant
preview is missing.
The net
The drawing is the model itself, laid out from its structure. Circles are places, bars are transitions, the numbers are the marking at the time on the scrubber below the drawing.
- a normal arc: the transition consumes from or produces into the place.
- a read arc: the transition needs the token present but does not take it (a prerequisite, not an accelerant).
- an inhibitor: the transition is blocked while the place holds tokens at or above the threshold.
Drag the scrubber, or hover the chart, and both views move together: the drawing shows the marking at that moment and the chart shows where it sits on the run. After a Compare, the time views show the first column's run — a scrubber averaging several scenarios would show a run that never happened.
Results
One column per scenario, one row per outcome the net declares:
- Terminal places (served, walked out, …) — the count at the end of the run, averaged over the realizations.
- Queue — typical (sum) — the time-weighted mean queue length across all queues.
- Queue — worst 5%, top three — the 95th-percentile length of the three worst queues, where trouble shows first.
- Waiting on — which resource the run was actually contended on and for what share of the run, classified from the net's structure.
Below the table, the caveats are constraints the model declares that this run could not enforce, and the assumptions are what the method itself takes for granted (exponential service times, asserted classes taken on faith, …). Both are the engine's own words. Read them before quoting a number.
Refused scenarios
The server refuses a scenario rather than bending the model to fit it: a negative pool, a rate on a transition the model does not have, a marking over a declared capacity. The refusal names the constraint. Fix the control and run again; the message clears on the next run.
Build a model
Build turns a plain-language description of your operation into a validated model, in a guided session. Sign in with Google, describe what flows through the system and what it contends for (the page gives an example), and follow the steps: the canvas on the right shows the net as it takes shape, the summary pane shows counts, validation and a preview report, and the finish step stores the model under your account and opens its console.
Models you build are private to you until you license them into the commons, at which point they appear in the public catalog. The builder has a daily quota; when it is exhausted the page says so.
You can also skip the builder entirely and POST model JSON to
the API. The full model format, including the optional
simulation.objective, parameters, stages
and schedule blocks, is in the full reference.
Google Sheets
Publishing builds a workbook in your own Drive: the model, the scenario trajectory, contention analysis, native charts and, for models simple enough to solve honestly in cells, a live formula tab you can re-solve by editing a rate. The front page lists your published sheets once you are signed in. Sign-in asks for Drive access to create files it owns; it does not read anything else.
API and MCP
Everything the console does is an HTTP call you can make yourself. Every model answers the same endpoints:
GET /api/models/$ID the model (Accept: application/ld+json wraps it)
GET /api/models/$ID/rates declared knobs
POST /api/models/$ID/scenario one hypothetical, seeded
POST /api/models/$ID/scenario/compare
GET /api/models/$ID/dataset ?seed=&cases=&format=csv|jsonl
GET /api/models/$ID/diagnose what Measure influence calls
POST /api/models/$ID/publish to your Google Sheets (signed in)
The same surface is exposed as an MCP server at
https://sim.pflow.xyz/mcp (Streamable HTTP, OAuth 2.1, dynamic
client registration) so an agent can list models, run scenarios, calibrate
against an event log, classify a model's parameters and publish — the tool
list is in the full reference. Machine-readable
summaries live at /llms.txt.
Glossary
| Term | Meaning |
|---|---|
| Place | A container of tokens: a queue, a pool of staff, a stock, an outcome bucket. |
| Transition | An event that consumes tokens from some places and produces into others, at a rate. |
| Marking | The token count in every place at one moment. The initial marking is the model's starting state. |
| Read arc | An arc that requires a token without consuming it. Dashed in the drawing. |
| Inhibitor | An arc that blocks its transition while the place is at or above a threshold. Red in the drawing. |
| Capacity | An upper bound on a place; a firing that would exceed it is refused. |
| Seed | The random-number starting point. Same model, scenario and seed → the same trajectory, byte for byte. |
| Realizations | How many seeded runs were averaged for one number. |
| Horizon | The simulated duration, in hours. |
| Caveat | A constraint the model declares that this run could not enforce. |
| Assumption | A claim the method makes regardless of the model, such as exponential durations. |
| Fungible class | Controls the net cannot tell apart and an experiment found interchangeable; the console shows them as one control. |
| Calibration | Fitting a model's rates to a real event log, producing a new model with a lineage link to the original. |
| Commons | A model its owner has dedicated under CC0 or CC-BY, which lists it in the public catalog. |
The complete machine-readable vocabulary, including every diagnosis and classification term, is served at /ns/v1.