sim.pflow.xyz

Show me the math: from a description to a model you can check

Your AI describes it.
The engine decides.

Describe a decision to your AI assistant. It builds the model, and a seeded simulation, not the assistant, works out what each change is worth, with its spread. The same question always gets the same answer. Or open a model right here, free and with no sign-up.

Separate from the engine’s numbers: a model is only worth trusting if it matches what it came from, so we test that in the open. Each day an AI assistant reads a published paper, builds a model of the mechanism it describes, writes down what the model predicts, and only then compares that with the paper's own numbers. It calls each paper one of: agree; agree but unblinded (they match, but the paper's numbers were seen before the prediction was written, so the answer may have leaked into the model); split (some of the paper's claims match and some don't); or disagree. Those calls are the assistant's judgement, not something this tool reports yet, and a split is where a person has to look. What the tool does today is check the model itself: it ranks every knob by what one more is actually worth, and has found capacity that does nothing (an autoscaler's instance ceiling, a bank's reserves, a baggage hall's extra sorters).

From the shared commons

Real incidents, replayed with the dice shown

Each of these models was built from a real outage, attack or story, with the page's own numbers wherever it gave them and every guessed rate marked as a guess in the model's description. Open one, change a knob, and see which lever the incident was actually waiting on. The figures below are from the automatic check every model gets: 8 hours, 24 seeded runs per measurement, seed 7.

attackcold-chain-defrost-attack

An attacker forces a supermarket's freezers into defrost. How many technicians does it take to win?

At 20 technicians, about 13 cases are lost to spoilage. At 33 it is about 1; from 53 it is none. One more technician is not enough: 21 reads inside the noise.

Noise ±2.0 cases. The attacker keeps re-defrosting cases that were reset, so every reset races the spoilage clock and the finite crew at once. The check found the spoilage rate is the one single knob that clears the noise.

Open the cold-chain attack →
What the model describes
  1. Case forced into defrost
  2. Warms against the spoilage clock
  3. Technician resets it (finite crew)
  4. Restored, or discarded
  5. ↺ the attacker re-defrosts reset cases

The loop is why a crew that is just short loses far more than just short: each reset case can be hit again.

airportbaggage-hall

A new airport’s baggage system, and conveyors that didn’t line up

Raising belt health from 3 to 7 cuts missed bags from about 191 to 13 in a day. More sorters don’t move it.

Noise ±8.8 bags. Built from a Hacker News story of 2026-09-26. Belt health is a speed curve, not headcount, and the check says so.

Open baggage-hall →
cloudautoscaler

Does scaling out rescue a traffic spike, or does cold start eat it?

Keeping 5 instances warm instead of 2 cuts timed-out requests from about 64 to 42. The instance ceiling of 8 never binds.

Noise ±10.3 requests. The one elastic pool in the commons: instances spawn with the backlog and pay a cold-start delay.

Open the autoscaler →
outagebyoip-cleanup-withdrawal

A cleanup job withdraws 1,100 customer prefixes. Which recovery lane saves the day?

Two lanes race: customers re-advertise from a dashboard, engineers restore the bindings the job destroyed. The engineers on standby move the outcome; the advertised count does not.

Timeline from Cloudflare’s 2026-02-20 postmortem; the recovery and abandonment rates are estimates, and the description says which. Noise ±1.6 on its objective.

Open the Cloudflare outage →
financebank-run outbreak

A bank run is an epidemic. Same net, retold in finance.

From 2 nervous depositors among 200, three staff reassuring them leave about 85 withdrawals; eleven leave about 8. Reserves of 120 don’t change that.

Noise ±14.5. The check flags this one honestly: no single knob clears the noise at the base setting, and staff is a speed curve, not headcount. Fear spreads and reassurance recovers exactly as in the outbreak model.

Open bank-run →
Same mathematics, two stories
  1. Calm depositor (susceptible)
  2. Spooked by a nervous one (infected)
  3. Reassured by staff, or withdraws

Open outbreak beside it and compare the nets.

From a flow to a decision

Four steps between “should I?” and a number you can check

Most decisions are about something that flows: customers through a counter, errands through a week, features through a team. Write the flow down once, and the same question always gets the same answer.

  1. The decision A question, one more barista, splitting into two options: two baristas or three. One more barista? 2 baristas 3 baristas

    Start with the question

    In your own words, with the prices you actually pay. No modelling vocabulary needed.

  2. The flow The flow: customers wait, a free barista serves them and comes back, and anyone who waits too long walks out. waiting served serve baristas gives up walked out

    Write down how it moves

    Who waits, what they wait for, how often things happen per hour, and what a loss costs.

  3. The runs A sketch of single runs of walkouts over an eight-hour day: the two-barista runs climb to about 97, the three-barista runs to about 50. ≈97 ≈50 walkouts 0 h 8 h 2 baristas 3 baristas

    Run it many times, same dice

    Every option gets the same seeded runs, so the difference you see is the barista, not luck.

  4. The answer What one more is worth: a third barista saves about 47 walkouts; customers in one queue giving up 1.5 times faster add about 5; both clear the noise band of plus or minus 2.9. noise ±2.9 a 3rd barista −47 giving up 1.5× faster, one queue +5

    See what one more is worth

    Every knob is ranked by measured effect. Inside the noise it says “no measurable effect”, never a made-up decimal.

Café, 8 hours, 24 seeded runs per measurement. At two baristas, 97 of about 267 customers walk out. A third barista saves about 47 of them (noise ±2.9). Step 3 is a sketch of single runs; the numbers in step 4 and here are measured. Re-measure them yourself: open the café and press Measure influence.

It checks “add more” instead of assuming it

The everyday ones, where the obvious fix was wrong

Each of these is a stored model anyone can open. The feature-lab and ward-flow findings came from the same automatic check every model gets, not from code written for that model; the second-car cost comes from comparing one car and two on the same seeded runs.

householdsecond-car

Is a second car worth it, or would ride-share cover the gap?

A second car costs $22 a week more than the ride-shares it replaces.

±$2.6 standard error over 12 independent comparisons of 64 runs each. How long a trip waits for the car: no measurable effect (noise ±$12 at 64 runs).

Open second car, free, no sign-up →
softwarefeature-lab

Does hiring another engineer help the backlog, or just add noise?

In one run of the automatic check, adding engineers past a point lowered the declared score.

That model's cost meter is being rebuilt, so treat this as unconfirmed.

Open feature-lab →
hospitalward-flow

More emergency bays, or more ward beds?

Two more emergency bays don't move the outcome.

The same automatic check, run on the shared catalog. Open it and press Measure influence to see what one more of each is worth; the knobs inside the noise say so.

Open ward-flow →

Not sure where to start?

Ask something like…

Hand any of these to your AI assistant once it's connected below, or describe your own in the browser (that needs a Google sign-in). No modelling vocabulary required: the model gets built from the conversation. The second-car question already has a model: open it and turn the knobs, free and with no sign-up.

Two ways to use it

In your browser, or through your AI assistant

Same models, same answers. Pick whichever fits where you already are.

In the browser

free · no sign-up
  1. Open a model. Start with the second car, or pick one from the catalog at the bottom of this page.
  2. Turn the knobs. Change how many you start with and how often things happen, or drop in a disruption: a rush, a closure, something breaking.
  3. Compare side by side on the same seeded runs, and press Measure influence to rank what one more of each is worth.

Describing a brand-new model in the browser uses the builder, which needs a Google sign-in: open the builder.

Connect an MCP client

any AI assistant

Point any MCP-capable AI assistant at the hosted server — no install, no API key to copy. Public tools (sim_list_models, sim_get_model, sim_scenario, sim_diagnose, sim_dataset, sim_verify, …) work signed out, and so does creating a model (sim_create_model), but a model created signed out belongs to nobody, for good: sign in first to own it. Licensing, calibrating or publishing a model opens PFlow OAuth 2.1 with PKCE the first time you use one.

{
  "mcpServers": {
    "sim": {
      "type": "http",
      "url": "https://sim.pflow.xyz/mcp"
    }
  }
}

Then just describe the decision: "My team's feature backlog is gated by cost-benefit review — tell me whether adding engineers actually helps."

Streamable HTTP, OAuth 2.1 with dynamic client registration — full tool list and the guide at /llms.txt and /llms-full.txt.

For developers

Bring your own model

A model is a stored data item, not a deployment. POST a Petri-net JSON and the id that comes back — the content hash, stable forever — carries the whole API. Nothing to register, no routes to code.

# store a model
curl -X POST https://sim.pflow.xyz/api/models \
  -H 'Content-Type: application/json' -d @model.json
# → {"id":"…","url":"/api/models/…"}

# ask it a hypothetical (pure read, seeded)
curl -X POST https://sim.pflow.xyz/api/models/$ID/scenario \
  -d '{"hours":8,"realizations":16,"seed":7,
       "marking":{"staff":3}}'

Every model answers the same six endpoints:

GET  /api/models/$ID            the model
GET  /api/models/$ID/rates      declared knobs
POST /api/models/$ID/scenario   one hypothetical
POST /api/models/$ID/scenario/compare
                                seeded side-by-side
GET  /api/models/$ID/dataset    synthetic event log
                                (?seed=&cases=&format=csv|jsonl)
POST /api/models/$ID/publish    → your Google Sheets

How it works

Petri nets, honestly enforced. Places hold tokens, transitions fire, and the engine honors what most simulators quietly relax: read arcs gate without consuming, inhibitors block above thresholds, capacities bound post-firing, and a queue is a prerequisite — never an accelerant.
Seeded stochastic comparison. Scenarios in one comparison share one seed, enforced server-side — so the difference you see is the staffing, not the dice. Contended-time accounting names what the run actually waited on, classified structurally.
Datasets that survive mining. The synthetic event logs replay cleanly against their own generating net, and process-mining them recovers the rates the model declared — data, not decoration.
Sheets as a first-class surface. A published spreadsheet carries the model itself, the scenario trajectory, contention analysis, native charts — and, for models honest to solve in cells, a live formula tab you can re-solve by editing a rate.

The catalog

Browse the model catalog

Every model built so far, including the ones behind the examples above. Most people get here by asking their assistant a question, not by browsing — this is for exploring what other decisions have already been modeled, or poking at the raw Petri net behind one.

Loading…

Fetching /api/catalog.