When you tell the techdiagrams.net copilot "food delivery platform with async order processing", an LLM designs the architecture. But before a single box lands on your canvas, a second model from a different company reads the design against your requirement and files objections:
- The payment path has no failure handling.
- The queue has a producer but no consumer.
- You asked for 99.9% availability; this has a single-region database.
The designer gets one revision pass to answer the critique. Only then is the architecture drawn — and the objections that shaped it appear in the chat as design notes, so you see not just the design but the argument behind it.
Why two vendors, not one model reviewing itself
We tried self-review first. It's better than nothing, but it has a ceiling: a model reviewing its own output shares its own blind spots. If the designer believes a retry without idempotency is fine, its self-critique tends to believe it too — the review reads what the model meant, the way you proofread your own essay.
A different vendor's model was trained differently, has different failure-mode instincts, and — crucially — has no attachment to the draft. In our current setup, Gemini designs and Claude judges. The judge's job description is one line: be the skeptical staff engineer this design will eventually meet anyway. Better it meets one before you've built anything.
Two disciplines keep this from becoming an expensive ping-pong match:
- One revision round, hard cap. Designer → judge → one revision → ship the proposal. Critique loops past round one burn tokens and mostly reshuffle words.
- Structured findings, visible to the user. The judge returns typed findings, not prose. The ones that caused changes are shown. Advice you can't see is advice you can't trust.
The rule underneath it all: the AI never writes to the document
This is the part I'd defend in any design review. Neither model — designer or judge — ever touches the diagram. They emit a small intermediate representation:
{
"nodes": [{ "id": "api", "type": "k8s", "label": "Order API" }],
"edges": [{ "from": "web", "to": "api", "kind": "sync",
"patterns": ["retry", "timeout"] }]
}Deterministic code does everything that matters: validates the JSON against a schema (with exactly one repair round-trip on failure), resolves "type" hints through a fuzzy icon index, runs the layout, and writes real document objects. Edits work the same way — the model proposes bounded operations (add_node, update_edge, …) against the live document, and an applier that checks every reference executes them.
The consequences of this boundary are the whole product experience:
- The model physically cannot corrupt your work. The worst possible output is a rejected proposal, never a broken document.
- Every AI change is a diff. Additions render green, modifications amber, and nothing applies until you press Keep. Discard restores the exact previous state.
- Your edits always win. Each chat turn re-reads the live canvas, so the diagram — not a chat transcript — is the conversation memory. Rename a service by hand and the AI sees it next turn.
The pattern, if you're building something similar
Most AI-feature failures I see come from letting the model write directly into the source of truth. Flip it: models propose in a narrow, validatable language; deterministic code disposes. Add a second model as an adversary rather than an echo, cap the argument at one round, and show the user what the argument was.
The AI becomes a colleague with strong opinions and no commit access — which, if you think about it, is exactly the seniority model that works for humans too.
The copilot is free with a local model (LM Studio/Ollama) or your own API key — your key never touches our servers. Describe a system and watch it argue with itself.