Inspiration
System design is part of my daily job as a software engineer. I built Backpressure first, for the same reason: I wanted to see how a design behaves under load without waiting for production to tell me. Saturate is the version I wrote for OpenAI's WebMCP challenge. Different codebase with a small version of the engine engine.
What it does
You drop components on a canvas, wire them up, and push load through. The example I used: 40 inbound requests, 12 tool calls each, is 480 calls dumped on a pool of 4 workers. Queue cap is 50. Parallel fills that queue and the run dies. Serialize the loop (one tool at a time) and the same 480 drain.
I see nodes, heat, ERROR on the wires. ChatGPT sees queue depth, utilization, a verdict. We edit the same session.
How we built it
Vite, React, TypeScript. The sim is a deterministic tick engine in the tab: no API, no auth. Burst -> Agent -> Pool (plus whatever you drag) compiles to { burst, fanout, mode, poolSize, queueCap }. The buttons and the WebMCP tools call the same handlers.
Tools register on document.modelContext when it exists. Always-on: get_board, run. State-gated: list_parts, add_component, set_burst, set_agent, then apply_fix and explain_verdict after a collapse. Eight tools, and serialize / widen pool / batch only exist when the board is actually dead. Cloudflare Pages hosts it. The header that made modelContext exist is Origin-Agent-Cluster: ?1. Skip origin isolation and the API never shows up, flag or not.
Challenges we ran into
The integration itself was the easy part. I already had MCP running on my machine, so once I found the right browser (the ChatGPT desktop app's built-in one, ⌘⇧B, Terra) the tools registered and got called on the first try.
The real work was cutting Backpressure down. The original has a full component library, a general system design mode, and an LLM serving model with TTFT and KV-cache math. None of that fits a single-board demo where the point is watching an agent fix one bottleneck. Deciding what to delete took a few hours, and most of that was resisting the urge to bring one more node type along.
Two things did catch me. document.modelContext never appears without Origin-Agent-Cluster: ?1, so origin isolation is a hard requirement and the failure is silent. And after a held run the card printed 0, because it was reading the last tick's empty queue. The number that matters is completed: 480.
Accomplishments that we're proud of
Eight tools, same path as the UI, gated on board state. The agent and I hit identical handlers, so there is no separate agent surface to drift out of sync with the buttons.
Same board plus same load always gives the same result, which means a fix the agent suggests is actually verifiable rather than a plausible-sounding guess.
What we learned
I over-registered on the first pass. Gating tools on board state came out of that: an agent offered apply_fix on a healthy board will reach for it.
The WebMCP surface is narrower than the spec reads. Origin isolation and the right browser are both hard requirements, and neither failure mode announces itself.
What's next for Saturate
The loop I wanted is working (read the board, run it, watch it collapse, serialize, run again). Before adding node types I want that loop to hold under boards the agent builds itself rather than ones I hand it.
Backpressure is already live and in use, with the full component library, general system design, and the LLM serving model. Saturate was the small board I needed to prove the WebMCP surface out on. Now that the eight tools work against the same handlers the UI uses, the plan after the challenge is to bring that WebMCP into Backpressure, where there is a lot more for an agent to actually reason about.
Built With
- react
- typescript
- vite
Log in or sign up for Devpost to join the conversation.