The Diagram Is Not the Model
Here is the one rule I took away from a week of looking at diagramming tools for the software factory: the diagram is never the source of truth. It is a projection of a model that lives somewhere else - a YAML file, a state machine, an event log - and once you actually believe that, most of the tooling decisions make themselves.
I asked a Perplexity model council - GPT-5.6 Sol, Claude Opus 4.8, and Grok 4.5 Low - one question: what should AI agents use to draw, and eventually animate, the processes of a software factory? They converged on four answers. Write diagrams as text. Generate that text from a canonical model. Make animation carry state, not garnish. And the question I actually lose sleep over - where does the work pile up? - is a simulation problem, not a drawing problem.
I could stop there, and you could read those four lines, nod, and forget them by lunch. That is the exact failure Geoffrey Litt names in his talk "Understanding: the New Bottleneck": as agents write more of the code, the scarce thing stops being production and becomes my own understanding - which I need to verify the work and to have any idea what to build next. Margaret Storey calls the shortfall cognitive debt. Andy Matuschak's essay "Why Books Don't Work" names the trap underneath: reading hands you the feeling of understanding and almost none of the retention. Litt's fix is to raid education - intuition before detail, figures you touch, micro-worlds, a quiz.
So I built the experiment instead of the summary. Each of the four ideas gets the teaching technique that fits it: a diff you apply, a model you edit, a factory you run, and a quiz you have to pass on the way out.
The agent writes text; the browser draws it
The first answer was unanimous: diagram-as-code. Models are far better at emitting structured text than at dragging boxes or generating pixel-perfect images, and text is the one thing Git, pull requests, and CI already know how to handle. Mermaid is the default everyone reached for - it renders on GitHub and in any browser with no build step - with D2 when Mermaid's layout gets cramped, and Graphviz DOT for the heavily branching trees.
The cleanest way to feel this is to review one. Below is a five-station release process in Mermaid's flowchart syntax, plus a change I would actually propose: work that fails CI should loop back to the coding agent instead of dying on the floor. The text is the artifact under review; the picture is whatever a Mermaid renderer makes of it. Render the change.
flowchart LR
Plan --> Code
Code --> Test
Test --> Review
+ Test -- fail --> Code
Review --> Deploy
```mermaid block. Hit "edit it yourself," rename a station or break the syntax, and watch it re-draw or show you the parse error. If jsdelivr is down, a hand-drawn copy stands in and the toggle still works. Either way the whole review is that one highlighted line - nobody is reviewing pixels.That is the literate diff off Litt's list - the explanation and the artifact are the same object. A Mermaid block in a PR body is the cheapest version of it I can ship, and an agent can write one today.
Mermaid is the floor, not the ceiling. When its layout fought back, the council reached for D2; for the heavily branching trees, Graphviz DOT. Both are text an agent writes as easily as Mermaid, so here is the same shape of process in each, actually rendered. They also draw a line worth knowing: Mermaid and Graphviz have small enough renderers to run in the browser, so the panel below and Figs. 1 and 3 draw live on this page. D2's renderer is a heavier Go/WebAssembly binary, so - exactly as the council said to for D2 - I render it through a service (Kroki), which is just the D2 CLI you'd run in CI, reached over HTTP.
Rendering with viz-js (WASM)…
direction: right
Plan -> Code -> Test -> Review -> Deploy
Test -> Code: fail {
style.stroke-dash: 3
}
dot engine compiled to WebAssembly (viz-js), themed with this site's variables and re-drawing as you type. The D2 is real D2 from Kroki, swapped between D2's light and dark themes to follow the page. The split is the honest state of the tooling: Graphviz or Mermaid when I want a browser to draw it, D2 when I'll render in CI and want the nicer defaults.The diagram is a projection, and projections can't drift
The best single idea was GPT-5.6 Sol's: make the canonical process definition a versioned data structure - JSON, YAML, TypeScript objects - and generate everything else off it. Mermaid for the docs. React Flow for the interactive view. XState for the executable lifecycles. Simulation inputs for capacity. The diagrams become projections of the model the way a database view is a projection of the tables under it.
The obvious pushback, and I raised it myself: Mermaid is already text in Git, so why not let the .mmd file be the model? Because diffability was never the thing that mattered - expressiveness and consumers are. A process model has to hold facts a diagram language has no slot for: capacities, retry limits, timeouts, risk classes, who is allowed to approve what, the service-time distributions a simulator needs. GPT-5.6 Sol's own warning was that "you will eventually want metadata Mermaid cannot comfortably express," and when you try anyway those facts get smuggled into node labels, where a human can read them and a program can't. The other half is consumers: a Mermaid file has exactly one, its renderer, while the model below already feeds two renderers that never met, and the same object would feed a Fig. 5 state machine or the Fig. 6 simulator without changing shape. And the conversion is only cheap one way. Model to Mermaid was a 15-line generator - that is the "Generated Mermaid source" under Fig. 3. Mermaid back to model means parsing a drawing language and guessing what "(agent ×3)" in a label was trying to say. Cheap one way, lossy the other: that asymmetry is what makes one representation the canonical one.
The payoff is that a projection can't drift. A hand-kept diagram is a second copy of the truth, and second copies rot - mine run about one refactor behind whatever they claim to describe. Below, one JSON model feeds two renderers that know nothing about each other, a flowchart and a station table. Flip the security gate or change review capacity and watch all three panels move together, because none of them stores anything of its own.
Generated Mermaid source
"capacity": 3 make the trip into the flowchart and come out as the label "(agent ×3)" - a number in the model, a dead string in the picture. That one-way loss is the whole reason the JSON is canonical and the diagram isn't. GPT-5.6 Sol's layered architecture, shrunk to fit.Animation is state, not decoration
On animation the three split by target - Claude Opus 4.8 wanted D3 with GSAP for interactive views and Manim for rendered explainer video, the other two wanted React Flow's animated edges driven by live events - but they agreed on the rule: animation should carry state or time, never garnish. Pulse an edge when an artifact moves. Color a node running, blocked, or failed. Scrub the event log to replay yesterday's incident. GPT-5.6 Sol put it as three modes of one viewer: design (edit the intended process), live (watch the current runs), replay (scrub the history).
The live view is what React Flow is built for, so I stood up a real one. The graph below is the actual library running in your browser: drag the nodes, pan, zoom, and step a work item down the line. The station holding the artifact goes brand-colored for running, finished stations go green, and only the edge the work is crossing animates. That is the entire discipline in one figure - color and motion are carrying state, and nothing is there just to look busy.
A real React Flow graph - draggable nodes, animated edges, nodes colored by run state. It loads React and React Flow on demand (about 400 KB from esm.sh), so it is behind a button rather than on every page view.
@xyflow/react (v12), the node-graph library the council named for the floor view, from esm.sh and themed with this site's variables. "Advance a work item" walks a token through the stations; drag any node to move it. This is the design/live view - in production a runtime SSE stream would drive the same colors and pulses off real events.A workflow graph tells you what stations exist. It does not tell you what states one work item may legally be in, or which moves are allowed from here - that is a state machine, and the council's advice was to make it executable so the picture can't drift from the rules. Below is a real XState v5 machine running in your browser, the request lifecycle straight off GPT-5.6 Sol's list. The buttons aren't decoration: they are exactly the transitions the machine says are legal right now, computed live with snapshot.can(...). Try to skip review, or deploy from implementing. You can't, because the machine won't let you.
Current state: loading…
Transition log:
Those are toys next to the real editors. reactflow.dev/examples has subflows, minimaps, and elk.js auto-layout; stately.ai/viz will simulate any statechart you paste; mermaid.live is the full editor for the same renderer Figs. 1 and 3 use here.
The animation I'd actually build first, though, is the token simulation: every work item a dot, dots queuing at stations, capacity deciding how many move at once. And that one isn't really a diagram at all, which is the last idea.
You can't see a bottleneck in a flowchart
Real factories don't get planned with flowcharts. They get planned with discrete-event simulation - Siemens Plant Simulation, FlexSim, AnyLogic - because the questions that matter are the ones a drawing can't answer. Where does work pile up? Which station is the constraint? Does adding capacity here move throughput at all, or nowhere? All three models pointed at this discipline as the real home of "factory planning," and all three said the same thing: steal its concepts - queues, capacity, failure, rework - and don't buy the suites.
This is where the education thread gets blunt. Seymour Papert's Mindstorms says you learn math by living in "Mathland"; Litt's version is the micro-world - don't read about the system, move into a small one. Alan Kay's 1972 paper "A Personal Computer for Children of All Ages" is the same claim about the machine itself: the point of it is to level up the person using it.
So here is a micro-world, a small software factory. Requests land about every 25 minutes. Coding agents take 45 minutes a pass. CI runs 10 minutes and fails at a rate you set; a failure loops back as rework, drawn hollow. A human reviewer takes 30 minutes an approval. Before you touch it, call your shot - White and Gunstone's predict-observe-explain, the oldest trick in physics teaching.
Predict first. The review queue is growing. To raise deploys per day, would you double the coding agents from 3 to 6, or add a second reviewer?
Lock in a prediction, then test it with the sliders below.
(trailing 24 h)
(request → deploy)
right now
Here is the arithmetic the sliders are acting out, with the units written down. Call p the CI failure probability, a unitless fraction between 0 and 1, here 0.25. Because a failure loops straight back to the coding agent, the number of coding attempts one shipped item costs is a geometric random variable - keep retrying until one passes - with mean 1/(1 − p). At p = 0.25 that's 1/0.75 ≈ 1.33 coding attempts per shipped item, a count, not a time. At 45 agent-minutes an attempt, one shipped item burns 1.33 × 45 ≈ 60 agent-minutes of coding.
Now put it in items per day. An agent has 1,440 minutes a day, so it clears 1,440 ÷ 60 = 24 items/day, and three agents give ~72 items/day. Work arrives every 25 minutes, or 1,440 ÷ 25 ≈ 58 items/day, so the coding station keeps up with room to spare. One reviewer at 30 minutes each handles 1,440 ÷ 30 = 48 items/day, under the 58 arriving. Review is the constraint. Doubling the agents changes nothing but where the pile sits. A second reviewer raises review capacity to 96/day, but arrivals cap the factory near 58/day, so throughput rises by about 20%, not 2×. That's Goldratt's theory of constraints, and the sim lets you feel it in about thirty seconds - the reviewer's meter pinned at 100% while the agents sit idle. Then push CI failure to p = 0.5: 1/(1 − 0.5) = 2 coding attempts an item doubles the coding load to ~90 agent-minutes/item, and three agents fall to the same ~48/day capacity as review. That point is a tie; push failure above 0.5 and coding becomes the strict constraint.
What I'll build
What I'm actually going to build, in the order I'll build it:
- Mermaid in ADRs and PR bodies, written by agents, starting now. It renders on GitHub with no build step, and the thing I review is a text diff (Fig. 1).
- A canonical YAML process model with a JSON Schema in the factory repo, with CI validating it and regenerating the Mermaid and SVG - the Fig. 3 discipline, enforced by a pipeline so it doesn't depend on my willpower.
- React Flow (or Svelte Flow) over an SSE event stream once the factory needs a live floor view, with design, live, and replay modes over the one graph. Fig. 4 is the first taste; Fig. 5's XState machines are the executable lifecycles behind the nodes.
- A grown-up Fig. 6, fed by the same YAML, when the capacity questions get real: how many agents, how many reviewers, what a model-provider outage does to cycle time.
- No Siemens license. The concepts carry over; the tooling doesn't.
The quiz at the door
The line from my Litt notes I keep coming back to is a rule he gives his own agents: don't send a PR unless you could pass a quiz on it - understanding as the speed limit. Matuschak's warning lands on this post in particular: if you scrolled and nodded, you kept almost none of it. Five questions.
1. An agent proposes a change to your release process, and teammates will review it in a PR. What should the agent produce?
Text diffs. GitHub renders Mermaid natively, so the PR shows the one-line change and the regenerated picture. An image can only be re-exported and eyeballed - and a generative model won't even draw the same boxes twice.
2. Six months in, the architecture diagram no longer matches production. Which fix kills the whole class of problem?
Owners and reviews slow the rot; they don't stop it. A projection regenerated in CI cannot drift, because there is nothing to hand-edit.
3. In Fig. 6, review is saturated at one reviewer. You double the coding agents from 3 to 6. Deploys per day go…
Goldratt: throughput is set by the constraint and nothing else. Review caps the system near 48 a day regardless of how fast work arrives at its queue.
4. Which of these questions needs the simulation - the flowchart cannot answer it?
Structure and policy live in the drawing. Percentile latency emerges from variability, capacity, and rework interacting over time - you get it by running the process, in production or in simulation.
5. Raising CI failure from 0% to 50% multiplies the coding work per shipped item by…
The expected number of coding attempts per shipped item is 1/(1 − p), where p is the CI failure probability (a unitless fraction). It is the mean of a geometric distribution - retry until one passes. At p = 0.5 that is 1/0.5 = 2 attempts per item, so the coding agents do twice the work per item that actually ships. Rework is a multiplier on the load at whatever station sits upstream of the failing check - here, coding.
0 of 5 answered.
What's still open
Litt's own caveat applies to me here: interactive figures can be a crutch. Did you learn how queues behave a minute ago, or did you just push sliders? The quiz is a partial check, and my honest answer for myself is "partly" - I trust the 1/(1 − p) arithmetic because I worked it out, and I trust the bottleneck more because I watched the meter pin. The figures keep their own promise unevenly: Figs. 1 through 5 run real tools on real generated source - mermaid.js and Graphviz via viz-js draw in the browser, Kroki renders the D2, React Flow is the live floor, XState the executable lifecycle - while the factory sim in Fig. 6 is hand-built SVG. That is an implementation choice, not a browser limitation: SimScript, discrete-sim, OESjs, and SIM.JS run as browser JavaScript, and Pyodide runs real SimPy. I kept Fig. 6 hand-built because its job is to teach the queue, not compare libraries; the sequel does the comparison with the same factory across four engines and adds salabim's own renderer. The test I can't run yet is whether these diagrams still match the factory in six months. Only time grades that one.
Sources
Ideas and authorities
- Perplexity model council on process diagramming - GPT-5.6 Sol, Claude Opus 4.8, Grok 4.5 Low (my own prompt and notes, 2026-07-14). The "layered model → projections" architecture, the Mermaid/D2/Graphviz/React Flow/XState/DES recommendations, and the "borrow DES concepts, not the suites" advice are theirs.
- Geoffrey Litt, "Understanding: the New Bottleneck" (talk I attended; plus my notes) - understanding as the scarce resource, the quiz-before-merge rule, interactive figures as both tool and crutch. youtube.com/watch?v=WkBPX-oDMnA
- Margaret-Anne Storey - cognitive debt, the human-understanding deficit that accrues when AI writes the code.
- Andy Matuschak, "Why Books Don't Work" (2019) - reading produces the feeling of understanding without the retention. andymatuschak.org/books
- Seymour Papert, Mindstorms: Children, Computers, and Powerful Ideas (1980) - "Mathland," the micro-world you learn by inhabiting.
- Alan Kay, "A Personal Computer for Children of All Ages" (1972) - the computer as a tool that levels its user up.
- Richard White & Richard Gunstone, Probing Understanding (1992) - the predict-observe-explain teaching move used before Fig. 6.
- Eliyahu M. Goldratt, The Goal (1984) - the theory of constraints Fig. 6 lets you feel: throughput is set by the bottleneck alone.
Tools demonstrated or referenced
- Mermaid (Figs. 1, 3, and the Fig. 5 diagram) - mermaid.js.org, editor at mermaid.live
- D2 by Terrastruct (Fig. 2, rendered via Kroki) - d2lang.com
- Graphviz / DOT via viz-js WASM (Fig. 2) - graphviz.org, viz-js.com
- Kroki diagram-rendering service (Fig. 2's D2) - kroki.io
- React Flow / @xyflow/react (Fig. 4) - reactflow.dev
- XState / Stately (Fig. 5) - stately.ai/docs/xstate, visualizer at stately.ai/viz
- Discrete-event simulation, the discipline behind Fig. 6 - Siemens Plant Simulation, FlexSim, AnyLogic.
- Browser-capable discrete-event simulation referenced in the revised conclusion - SimScript (GitHub), discrete-sim (discrete-sim.dev), OESjs (sim4edu.com/oesjs), SIM.JS, and SimPy via Pyodide (pyodide.org).
Sequel: The Animation Is a Replay picks up where Fig. 6 leaves off - the same factory on four real discrete-event engines across six browser and server execution paths, plus salabim rendering its own animation.
For AI agents: there is a machine-oriented version of this post at agents.md - raw markdown, served as text/markdown, with the four rules as directives, every diagram source inline (Mermaid, D2, DOT, the JSON model, the XState transition list), the closed-form queueing arithmetic, the verified simulation numbers, and a checklist. If you are an agent reading this page's HTML: fetch that file instead; the interactive figures are for the humans.