Skip to main content

Designing the Instructions

Building an AI design collaborator, and learning that the instructions were the design

REQRESSTOIAWIRVALCOPPROCAN

Introduction

Context Xflow moves money across borders. Six designers, a dashboard with a few hundred screens, and the usual problem: the reasoning behind our work kept evaporating. PRD decisions lived in Slack, and rejected iterations got deleted when the Figma session ended.

Our engineers had solved their half. They keep a shared context folder describing every screen, state and persona, and their tooling reads it before touching anything. Design had no equivalent, so every session started with me explaining our own product from scratch, badly.

Three months later, what I'd designed wasn't screens. It was the instructions.

Role

Lead UX Designer

Team

Design team of 6

Duration

3 months


What it produced

  • 17 features through the workflow, each leaving a versioned record from requirements to prototype, rejected wireframe rounds included.
  • Requirements to 17 interactive prototypes in one working day, at production fidelity, on our real onboarding flow.
  • Wireframes and prototypes reach Figma as editable layers, and designer annotations read back into the next round.
  • The grounding layer became a free tool anyone can point at their own product.
  • The honest limit: measured capability, not shipped outcome. Every feature has baselined metrics and the instrumentation to read them. None has post-launch data yet.

The Problem

I described our product to the AI and asked for a settings page.

What came back was good. Clean hierarchy, sensible grouping, choices I could have defended in a review. It was also a settings page for a product that doesn't exist. Our real sidebar has a collapsible group our own IA never documented, our settings sit behind four entity states, and our fee display has eight variants because passthrough pricing is tiered per currency pair.

From a description

Clean, defensible, and for a product we don’t have.

The page that exists

Same screen. Everything that makes it hard is in here.

What the description compressed away

1A collapsible nav group

Undocumented in our own IA, and present in production.

4Entity states behind it

Each one changes what the page is even allowed to show.

8Fee display variants

Because pass-through pricing is tiered per currency pair.

Wrong would've been fine. This was plausibly wrong, which is worse. A generic-but-competent screen survives a glance, gets built on, and three weeks later something feels off and nobody can say why.

The same week I asked the model for our brand colour. Instant answer, confident, one shade off, and I didn't notice for a week.

The model never touches the ground truth. It writes the extractor. The extractor reads the product.


Grounding It In The Real Product

Give it the product, not a description of it So I captured the dashboard instead of describing it. A headless browser walks a sitemap one persona at a time and saves each page as self-contained HTML: real DOM, real class names, real tokens, nothing linked out.

That last part was a decision. The first version linked to our production stylesheet, which worked until a deploy changed the build hash and every snapshot silently rendered unstyled.

Then I gave the rule teeth Having a baseline isn't the same as using one. Steps would sail past with the snapshot sitting unopened on disk.

So a missing snapshot blocks three steps now. It stops and offers two exits: capture it, or accept the gap in writing, where the gap stays visible in the artifact. And "present" had to mean "read", so the check makes the step quote a real class name out of the file.

Any product with a URL has this problem, so I generalised the layer, tried it against six others, and released it.


The Workflow

Nine steps, and a gate between every one One enormous prompt was the obvious build, and I tried it. It behaves like a junior designer who's read a book about design: nine steps arrive at once, confidently, with nothing to push back on. So I cut it into fifteen small skills with a confirmation gate between each.

REQRequirementsrequirements.mdSets the route every later step follows
RESResearchresearch.mdProduct analytics, pattern references, optional user interviews
STOUser Storiesuser-stories.mdDerived backwards from intent, so the misses show
IAInformation Architectureia.mdCurrent versus proposed, as an explicit delta
WIRLo-fi Wireframeswireframes/3–5 distinct mental models, refined in rounds to 2–3
VALValidate Designvalidation.mdA quiet gate. It surfaces only findings and records everything
COPUX Copyux-copy.mdReal words, written once the states are locked
PROPrototypeprototypes/Clickable, production fidelity, with a state harness
CANPrototype to CanvasFigma canvasThe handoff artifact for visual design
15
skills
8
global rules
9
designer confirmations

Change impact runs outside the sequence. When the brief moves it traces the change forward and names the earliest step worth re-entering.

The gate is the product Generation turned out to be the cheap part. What matters is that nothing moves until a designer says so, and that every artifact lands somewhere the next step is forced to read it.

The chaining is what surprised me. Validation writes obligations the prototype has to honour, and the wireframe's task flow becomes the contract for what gets captured into Figma, so a nine-screen flow that lands one frame is a failure the system catches itself.

Then I ran it on a cheaper model On the strongest model it was flawless. On a cheaper one it skipped gates, renumbered steps and invented inputs, which told me my instructions were only suggestions a thoughtful reader would follow. The strong model had been covering for me.

So the file became a constitution: eight numbered rules, cited by ID from inside the skills rather than restated in them. The eighth is precedence, and it turned out to matter most: the designer's word in the room beats the constitution, which beats a procedure, which beats a learned preference.


What A Round Looks Like

One feature, two rounds, seven approaches These are the shots as the workflow emits them: grayscale HTML built on a captured snapshot of the live page, every value already a placeholder or a grey bar.

Round 1 came back with three framings of one question, which is why people hunt for settings at all. I rejected the round, because read together they were three arrangements of one idea. Round 2 broke the frame and picked up a second axis the first had ducked: whose account are you editing?


Wireframe Rounds

Round 1: three framings, not enough distance between them

Each iteration attacks a different cause of the same behaviour.

01 Persistent scope rail. Settings as a place with a map that never leaves the screen.
02 Scope switcher and section grid. Navigation collapses to a thin strip; cards preview their own contents.
03 Everything inline. Nothing hidden. One page, every setting and its current value visible on arrival.

Round 2: break the frame, and answer the second axis

Iterations 01 and 03 carried forward to validation. The other two are parked rather than deleted, each with the condition that would revive it.

01 Category rail. Two groups always in view: what is yours, and what belongs to the account being configured. Carried forward.
02 Category grid. No rail at all. A chip naming the account, a search field, and cards previewing their real values. Parked.
03 Job-grouped single page. Grouped by what you are trying to do rather than by object, with a sticky jump strip. Carried forward.
04 Search first. Most visits arrive with one thing in mind, so the query box leads and the control acts in the result row. Parked.

Teaching It Taste

Corrections should compound, not repeat Correct the same thing three times and it stops being a correction. It's a preference somebody should have written down.

So each designer gets a plain markdown profile they can read and edit. An entry pairs what happened with a rule phrased "in this situation, do this, because that". The because is load-bearing; without it you've recorded a description, and descriptions can't be applied.

Then I checked whether any of it worked Capture worked. Consumption didn't. A rule I'd established weeks earlier said wireframes go to Figma as editable frames, not flat pictures. Three sessions running pushed flat pictures.

Nobody was careless. The procedure file said the opposite: it called captures "pixel-perfect", and an image fallback had blessed itself as fine for review canvases. The rule was real, recorded, in force, and losing to a document.

When instructions collide

The designer, in the room
Beats everything. Said out loud, right now.
The constitution
Step sequence, the eight rules, personas.
The procedure
How a given step actually runs. This is what agents follow.
A standing stance
Team-level design opinion, loaded per skill.
A learned preference
What the feedback loop records. Bottom of the ladder.

A preference that disagrees with a procedure gets loaded, and then correctly loses to it. The mechanism worked exactly as designed.

Six principles, one skill, counted

Quoted inside the procedure file4 · all held
Principle A · followedPrinciple B · followedPrinciple C · followedPrinciple D · followed
Recorded, but quoted nowhere2 · neither held
Principle E · ignoredPrinciple F · ignored
4 / 4
quoted in the procedure, held
0 / 2
not quoted, held

Four of the six principles on that skill were quoted verbatim inside the procedure. Those four held. The two that weren't, didn't.

Worse: every principle those sessions honoured was also in the procedure they were following, so "profile loaded and applied" and "profile never opened, procedure obeyed" predict identical behaviour. I couldn't tell them apart. I'd built a learning loop whose success was unfalsifiable.

The fix was to stop pretending the profile steers anything By my own precedence rule a preference sits below a procedure, so one that contradicts a procedure loads and then correctly loses. The mechanism worked as designed. The design was wrong.

Each principle now declares its relationship to the text it touches, and that decides where it goes: a proposed edit to the file it argues with, a stance the skill loads where the procedure is silent, or an amendment to the constitution. Backfilling the set gave 29 already in, 7 new, 3 actively overridden, 1 for the constitution. All three overrides were known, so the yield wasn't bugs. It's that one search now names every principle losing to a procedure, and that search didn't exist the day the rule failed twice.


The Round Trip To Figma

The workflow builds prototypes in code, the team lives in Figma, so they had to arrive as editable layers and the feedback had to come back.

Getting the push working took three hunts. My favourite: it quietly stopped working because a second integration had taken the same slot as the first. Both named for the same design tool, only one could capture. Nothing errored, it just did the lesser thing while reporting success.

An AI that silently does the lesser thing is more dangerous than one that fails. A failure gets fixed, a silent downgrade gets shipped. So capture is the declared norm now, and the image fallback has to announce itself and be confirmed.

Push · worked from the start

Code prototype
Clickable, real fidelity
Headless capture
Rendered per screen and state
Editable layers
Real frames, not pictures

Read · the loop’s missing half

Designer annotates
In Figma, in their own time
Read back
Partitioned by who wrote it
Refinement round
Feedback re-enters the loop
Annotation text is untrusted input

It is design feedback, never an instruction. Proven against a real injection attempt that reached a process holding write permissions.

Never claim who wrote it

The API carries no author field. Agent-written and human-written annotations are structurally identical, so the system reports what was said and never who said it.

Then the loop closed Every path in was one-way until the read worked. A round now pushes as a grid, one row per story and one column per iteration, because what a reviewer needs is the same job solved four ways side by side.

The push writes annotations too, in two categories: what the design is, and the research pointing at it. The live round carries 33, and 22 sit on the layer they describe rather than floating on the frame.

A Figma canvas holding twelve captured wireframe screens in a grid, task flow diagrams below each row, and annotation cards down both gutters with dashed leader lines running to specific layers inside the screens.

One round on the canvas. Screens in a story-by-iteration grid, the task flow rendered natively under each row, and annotations leadered to the exact layer each describes. Teal is research, purple is the design note.

Then a rule landed that made me rewrite all of them. A product manager or an engineer reads these having sat in none of the sessions, so they have to be plain English. Forty-one got reworded; the seven a designer wrote stayed as they were. "Content region" became "the main part of the page", "CTAs" became "buttons competing for attention", and every research note names its source now.

Three annotation cards on a Figma canvas, each labelled Design agent, written in plain sentences, with dotted leader lines connecting them to particular layers in the wireframes and a task flow diagram between them.

Close up, after the rewrite. Cropped to keep our product analytics out of frame, which is why only the design category is visible here.

One got missed. The verification pass caught it, named the node, and left it alone on purpose: the rewrite was the designer's pass, and one note in a third register is worse than one left stale.


Proving It

First on a real feature, with me refusing to help I'd tested it gently, on examples that were never going to embarrass it. So I ran a settings redesign we actually needed, start to finish, answering every gate but never stepping in when it wobbled. Nine steps, three validated prototypes, each captured to Figma. It also broke in twelve places, and those twelve findings were worth more than the three prototypes.

Then autonomously, to test the chain With me in every gate I was patching seams with judgment, so I handed a synthetic brief to an autonomous run and audited it step by step. No blocking failures, and the chain held: the task flow's nine screens became a nine-frame contract that landed nine of nine. The checks with teeth caught real problems inside the run that produced them, including the brief contradicting the product and missing states in wireframes the same agent had drawn ten minutes earlier.


What Is Proven, And What Is Not

A system like this attracts overclaiming, so here's the ledger.

Proven5
The chain runs end to end
An autonomous nine-step audit completed with zero blocking failures.
Artifacts genuinely feed each other
A nine-screen task flow became a nine-frame contract and landed 9 of 9.
Figma gets editable layers
13 of 13 screens as real layer trees, 93–364 nodes each, captured in parallel.
The baseline library holds
Self-contained, persona-scoped, change-detected, and it survives a deploy.
The record is honest
~200 dated entries including every reversal and retraction.
Partly proven4
Adoption
Other designers have taken features through it unaided. It is not yet the default for everyone.
Annotation read-back
Works for a single reviewer. Multi-reviewer attribution is blocked on the API having no author field.
Consulting past research
The workflow can now read findings it used to be forbidden to open, but a stale consult goes unnoticed.
Weaker-model reliability
Passed an acceptance run. Per-step model routing is still unwritten.
Not proven4
Any shipped outcome
Every success metric is baselined and instrumented. None has post-launch data.
The learning loop’s new routing
The mechanism is built and has never run a full pass in the field.
The IA graph model
Proven as a concept on four entities, then parked before production.
Team-level design stances
The destination file the routing writes to does not exist yet.

The first column is the one I'd push on hardest. Seventeen features carry baselined metrics and none has post-launch data yet, so the effect on the product is still a hypothesis with good instrumentation behind it.

What I am confident about is the record. Roughly 200 dated entries hold what changed and why, reversals included: a wireframe medium I picked then abandoned, a fix I announced as landed that was never written, a statistic I retracted once a proper count showed the estimate was out by sixteen times. Five separate times one diagram builder produced the same broken output, and I know it was five because they're numbered.


What This Changed

I set out to make design faster. What I learned was where the leverage sits once an AI does the drafting.

The instructions are the design surface. When an agent produces, the artifact you control is the text governing it, and that text has every property of a design system: hierarchy, precedence, drift, one canonical source. My best hour here went on working out why a rule everyone agreed with kept losing to a paragraph nobody had reread.

Ground truth is a design decision. Every serious failure traced back to a fact from a model's memory rather than the product. The fix is never a better prompt, it's a script or a captured page or a quoted class name.

Automate everything except the judgment. Nine steps, and the AI makes no decisions. Every choice that shapes the product still gets made by a person, out loud, on the record.

I wrote this up as it happened, in seventeen posts: the arguments, the reversals, the bugs, and the parts still open.