How I Use a Graph to Evolve My UI Design in Claude Code
Graph engineering went viral this summer as a rename for agent orchestration. Here's how I actually use one, in Claude Code, to evolve a UI design over rounds.
In mid-July, a one-liner from Peter Steinberger split AI Twitter: “Are we still talking loops or did we shift to graphs yet?” Harrison Chase, who built the framework everyone points to, gave the skeptical read: “so i didn’t really know what graph engineering is, and i still don’t really… but it’s basically just langgraph?” Naming has been on a treadmill for years, prompt engineering to context engineering to loop engineering to graph engineering, and every rename earns eye-rolls from some and a scramble from others. What actually went viral underneath the label is orchestration: agents as nodes, dependencies between them as edges. He’s not wrong that most of it is a rename of patterns people already shipped, but the shape is worth showing, not arguing about.
I built a Claude Code skill called /options on exactly that shape, and the afternoon that tested it started with something as ordinary as asking for twelve versions of a landing-page hero.
Ask Claude Code to build twelve hero variants for a landing page and it hands them back before lunch. Twelve real routes, twelve real components, wired into the real app. Generating options used to be the hard part of a design pass. Now it’s the fast part.
Then I opened all twelve and started clicking through them, and by the sixth one I couldn’t tell you which was good and which was just familiar. My taste had evaporated somewhere around option four. I’d generated more work than I could actually judge, and doing it in an afternoon instead of a week didn’t make me any better at judging it.
AI made competent free. The judgment to use it well didn’t get cheaper.
The System
/options runs two different kinds of graph, and the difference between them is the whole reason this counts as graph engineering instead of a renamed pipeline.
The persistent layer is an org graph: a lead builder, one reviewer per persona, a best-practices researcher, all named roles that survive across rounds. The ephemeral layer is a work graph: variant builders that spin up for a single round, build exactly one option, and disappear the moment the round closes. An org graph with no disposable workers can’t generate twelve real routes before lunch. A pile of disposable workers with no persistent reviewers can’t tell you which of the twelve is worth keeping.
None of this is worth building for a single, well-scoped task with a clear pass/fail check. A loop is enough there, and a graph is overhead you don’t need. /options earns the extra shape because it’s judging taste across rounds, not passing a test once.
The work-graph half greps the codebase for how the component actually gets called, pulls the richest set of props off a real call site, and renders each variant inside production’s actual wrapper chain, so a variant can’t quietly render at a width the app could never ship. Every option is a real page at a real URL, wearing the site’s real CSS.
That solves generation. It does nothing about judgment, and judgment was the thing costing me time.
So before it hands variants back, the org-graph half assembles a review panel. It looks for persona docs already sitting in the repo, the ICP writeups that describe who actually buys the thing, and if none exist it asks for two personas with opposing failure modes: one that punishes burying the facts, one that punishes overselling. A single reviewer just tells you what it likes. Two reviewers who fail in opposite directions tell you where the actual tension is.
Each persona gets the same screenshots of every variant and the same manifest notes describing what each one was going for, and returns a strict verdict. LIKE means it would ship exactly as-is. Anything short of that is PASS, and every PASS carries exactly one flip change, the single highest-leverage edit that would move it to LIKE. Not a punch list. One thing.
{
"by": "A",
"verdict": "PASS",
"flip_change": "surface the company + title above the quote, not below",
"note": "I read the quote before I know who said it. Attribution should lead."
}
Every verdict folds straight into the manifest and renders inline next to its variant in the feed, no separate report to go read.
The Loop
A round is never one pass and done. Whatever gets zero likes gets killed, and deciding what should grow in its place is the researchers’ job, not the lead’s. I built that job one researcher at a time, and each addition fixed exactly the failure the last one exposed.
The first researcher I gave the loop was the feedback integrator. It checks the manifest for every outstanding flip-change and owner direction and makes sure a brief exists for each one. That’s all it does, so the loop could only ever build what the two reviewing personas had already asked for. It does exactly what it’s told, which means it can never propose anything nobody requested, and it converges on whatever the personas already wanted instead of on something good.
Adding the best-practices researcher fixed the badness and traded it for sameness. It grounds each proposal in a real source and moves a proven variant ten to twenty percent further, and that raised the floor. But it’s contractually capped at low or medium variance and has to parent something already working, so by construction it refines toward what’s already known to work. Everything a round produced came out competent and interchangeable. Best practices are, definitionally, what everyone else is already doing.
The bold designer put the variance back. It’s the only lane allowed high variance, the only one that can start from nothing instead of from a parent, and every proposal it makes has to name the premise it’s rejecting. It’s also the only one permitted to challenge the reviewing personas themselves rather than the design, and it’s the only agent in the loop running on Opus. It has no web access on purpose, so its divergence comes from principles instead of from looking at what competitors already shipped. Feedback alone builds what it’s told, best practices builds what everyone already does, and bold is the only seat that can build something nobody asked for.
Continuity is the optimization everywhere else in this loop, but that one seat inverts it. The best-practices researcher persists so its research compounds across rounds, while the bold designer gets spawned fresh every round, because a persistent one starts anchoring on its own prior swings. The builder that implements its brief is spawned fresh too, so a premise-rejection can’t inherit the parent builder’s frame. It’s a permanent seat filled by a new occupant every time. The feedback integrator still runs after both and can’t close the round while a single gap remains.
The next round breeds from whatever the researchers hand back, and that lineage is the actual graph the design travels along. Every variant carries a parent, and when two survivors get combined into one, a merge_of:
{ "id": "v9", "parent": "v3", "merge_of": ["v3", "v5"] }
That pointer is why round four looks like it grew out of round one instead of just being a different set of guesses.
The page itself is also a control surface. I get my own Like, Pass, Kill, and Champion buttons right on each card, and the terminal folds my calls into the manifest as a third reviewer alongside the personas. But mine never counts toward the persona tally, and it can’t be outvoted by one either. The personas can push a champion star around all afternoon. The pin that decides what actually ships is mine.
Try It Yourself
The full skill is more machinery than most people need: framework detection, a production wrapper chain measured at multiple viewports, a manifest schema, a kill/regen cycle, an org graph and a work graph both running at once. If your app isn’t already on Astro or Next, or you’re not ready to add a React island just to run a design loop, that overhead isn’t worth taking on for one page.
The part worth stealing is two things, not one: the reviewer setup, and the three researcher tempers that decide what gets tried next. Two personas with opposing failure modes, a strict LIKE or PASS with no in-between, exactly one flip change per PASS. Then feedback integration, best practices, and the bold swing, covering what was asked for, what’s proven, and what nobody thought to ask for. Neither half needs a graph. Both run on a screenshot you paste into a chat just as well as they run on a scaffolded route.
The first time I ran this against a batch of my own variants, both personas agreed on the same champion I would have picked eventually, just faster and for reasons I hadn’t fully articulated to myself yet. The second time they split, and the split was the useful part. It told me exactly which tradeoff I was actually making by picking one over the other, instead of me discovering it three weeks later from a confused visitor.