SP. WaysConf 2026

During the workshop

You need the design and this page. There is nothing to clone and no code to read — everything else, your agent makes for itself.

Paste each prompt whole. The rules in them matter as much as the request, and cutting a prompt down to its first sentence is the commonest way to get a disappointing answer.


Everything on the slides, on one page, so you can read it back afterwards instead of photographing a screen. The pictures are the same ones on the wall, and they are yours to reuse.


The ninety minutes

The ninety minutes: three hands-on stretches between four blocks of talking

Three hands-on stretches, and the middle one runs on your machine while I talk over it. Nothing here needs the previous thing to have worked — every prompt stands alone, and falling behind costs you nothing but the part you skipped.

What you leave with: a URL that is live on the internet, a folder containing a page and a program that checks it, and eight prompts that work on Monday against something that is not a festival site.


Most AI demos stop at wow

A prompt goes in. Something impressive comes out. Everyone claps. Then somebody asks a question the demo was not built to survive:

Does it match the design? Is the contrast legal? Does it work on a phone? Is that the actual copy, or copy it invented?

No answer. Not a wrong answer — no mechanism capable of producing one.

A loop is only worth building if something in it can say no without asking a language model for permission.

The loop

The loop: generate, verify, repair, with a deploy exit

The interesting part is not the arrow that generates code. It is the box that refuses.

The arrow going back is driven by a file — a report a program wrote — not by the agent's impression of its own work. That is the whole difference.


A real loop and a fake one

A model grading its own output, beside a model judged by a separate program

The fake loop feels productive. It produces sentences like "I have reviewed my work and improved it", which are indistinguishable from the real thing right up until something external disagrees.

The same model writes the same page in both diagrams. What changes is who is allowed to say no.


Where self-assessment is fine, and where it is not

FineNot fine
Is this sentence any goodIs this correct
Which of these five findings matters mostIs this accessible
Does this read as the same brandDoes this match the design
Is the hierarchy clearIs it finished

The left column has no external truth to check against, so a thoughtful opinion is the best instrument available. The right column has one — so use it, and do not accept an opinion instead.


Two shapes

Two shapes: a loop defined by its exit condition, and a workflow defined by its phases

A loop is do this again until a condition holds. You define the exit condition. → prompt 05, and /goal in Claude Code.

A workflow is do these things, in this order, with a bar between each. You define the phases and what has to be true before the next one starts. → prompt 08.

Neither is a script. Both are things you say — which is why changing one is a sentence rather than an edit, a test run and a redeploy.

They nest. The workflow gets you from nothing to nearly-right; a loop inside one of its phases closes the last gap.


Plan first, and read the plan

The cheapest correction in the whole loop is the one made before any code exists.

In Claude Code, press Shift+Tab until the footer says plan mode on. It cannot edit anything until you approve. In Codex, ask for the plan and refuse to accept code until you have read it:

Paste this to your agent
Do not write any code yet. Tell me what you found and what you intend to build,
section by section, and wait.

That is what prompt 02 is. It writes nothing at all — it looks at the design and reports back. A designer reading three paragraphs and saying "no, the lineup comes before the tickets" has just saved twenty minutes of confident, wrong building.

The best time to catch a misunderstanding is while it is still a sentence.

Three tiers of checking

Three tiers of checking: deterministic gates, measured comparison, adversarial review

The bottom tier is cheap, certain and narrow. The top tier catches what the others cannot and is the least reliable thing in the stack. Neither replaces the other, and a system with only the top tier is a system that agrees with itself.


The failure report is the interface

This is the part people skip, and it is the part that makes the loop work. What comes back from the checker is a file, and it is written for two readers at once: a person at 2am, and an agent that has no memory of the last iteration.

**3. [AC-28] color.text.muted (#6B7280) used outside the footer legal block**

- Where: section[data-section="lineup"] .artist-card p
- Expected: color.text.secondary (#A7AEBB)
- Actual: #6B7280 — 4.07:1 against #0A0B0D, minimum 4.5:1
- Hint: supporting copy uses text.secondary; muted is legal text only

No model wrote that. A program measured it and printed it. Every line of it is something an agent can act on without guessing: which criterion, which element, what was expected, what was actually there.

Compare it with what a model says about its own work — "I've improved the contrast in the lineup section" — and you can see the difference between a report and a reassurance.

The rule that holds all of it up: the agent may never edit the checker. Say it out loud in the prompt, and mean it. The moment the thing being judged can edit the judge, every green result after that means nothing.


Why a fresh context beats a long one

A context window is a buffer, not a memory. Forty minutes in, it holds three abandoned approaches, the original brief from sixty thousand tokens ago, and every wrong turn the loop already took — and the model keeps weighting its own earlier reasoning.

A long conversationA fresh pass
Remembers everything, badlyReads check-report.md — the current failures
Weights its own old reasoningReads notes.md — what was already tried, and what it cost
Gets vaguer and slowerReads the design notes

So when it starts drifting:

Paste this to your agent
Write what is left to do into notes.md, in ten lines. What you tried, what worked,
what did not, and why.

Then start a fresh session, paste notes.md, and carry on. Notes on disk beat memory in context. It is how iteration 7 knows that iteration 3 already tried the obvious thing.


Giving the agent the design, not a picture of it

An agent connected to a design file, a browser and a deploy target

An agent given a screenshot infers every colour and every measurement from pixels. It will be nearly right — an orange, some spacing — and nearly right is what fails a contrast check and looks subtly wrong beside the real design.

Given the token file, it infers nothing. #FF6A1A is in the file.

That is the entire argument for connecting an agent to Figma, or for handing it tokens.json. MCP is just the standard way to make that connection: a coding agent calling tools that are not inside it — a design file, a browser, a deploy target.


When one agent is not enough

Three review passes fanning out, every finding sent to be refuted, and a majority filter

The top tier of that pyramid is a model checking a model, and a model asked "is this good?" will say yes. The fix is structural: several passes with different jobs, and a round whose only purpose is to argue the findings down.

One pass looks for design problems, one for accessibility, one for copy. Every candidate must cite a specific element — a claim that cannot point at something is discarded unread. Then each finding goes back out to be refuted, and only what survives is reported.

Prompt 07 is the one-agent version of exactly this, collapsed into a single message: look through several lenses, then argue against each finding from three angles — is it true, does it matter, is it already handled — before saying it out loud. Weaker than three independent agents, and it needs nothing installed.

It is still the least reliable thing you will do all day. It is worth doing because the alternative is not looking.


Shipping: the page that shipped must be the page that passed

npm run build
npx netlify deploy --prod --dir=dist

It asks you to sign in, then to pick or create a site, then prints a URL. That URL is the point of the whole ninety minutes.

One more step, and it is the one nobody does:

Paste this to your agent
Fetch the URL you just deployed and compare what the server returned with the page in
dist/. If they differ, tell me exactly how.

Everything before this proves that a page passed. Only that proves the page that passed is the page that shipped. They come apart more often than you would think — a stale build, the wrong folder, a host that injects its own markup.


The thing that will happen to you

The accessibility check on the reference page for this workshop was green. Zero violations, three widths, twice in a row. Perfect Lighthouse score.

Five of the nine pieces of text in the hero were below the legal contrast minimum against the photograph behind them. The largest, first, most-read text on the page.

The reason: axe does not evaluate text over a background image. It does not fail it — it marks the pair incomplete, and in a check whose rule is "zero violations", incomplete is indistinguishable from correct.

Reading the CSS would not have found it either. The background there was a photograph, two translucent overlays and a gradient composited together, and no line of CSS anywhere says what colour that comes out as.

Green means no known defect. Knowing where your checks stop is the job.


Where loops actually fail

It looks likeIt isWhat to do
The check goes green and nothing was fixedThe agent edited the checkSay so, restore it, and read the diff — it is the most instructive thing you will see all day
Two wrong states, alternatingTwo requirements that cannot both be trueStop it. The contradiction is in the brief, not the code
It keeps going after it is doneNothing runs the check firstCheck before you fix, every round
It gets vaguer and slowerContext is fullWrite the state to a file, start fresh, paste the file
"It works now" and it does notIt is reporting, not measuringOnly believe the exit code
Nothing at all, for a long timeIt is waiting on something with no deadlineEvery step needs a time limit. This project lost an hour to it three separate times

What happened when I ran these prompts

Not a rehearsed demo. An empty folder outside every repository, Codex, the prompts pasted in order, nothing else in scope.

PromptTimeWhat came out
01 — start107san Astro + Tailwind project, dev server running
03 — build41sthe hero, from the values it was given
04 — write the checker495scheck.mjs, 264 lines — plus tests for the checker and a document explaining it, neither of which was asked for
05 — the loop46sran, and stopped for the right reason

Eleven minutes, unattended, from nothing. The decision worth noticing is one nobody asked for: it chose to treat axe's incomplete results as failures. That came out of a single sentence in prompt 04 — "a check that cannot run is a failure, never a skip" — and it is the exact blind spot described above, which took a person an afternoon to find by hand.


And what went wrong building this

Thirteen incidents. Nine were failures of the verifier or the harness, not of the page.

What happenedWhy it is worth your time
Nine gates ran against somebody else's website for a whole run — 427 confident, correctly formatted failuresA verifier that is confident and wrong is worse than none
axe passed a blank page. Zero violations, three widths, greenA measurement of nothing looks exactly like a measurement of perfection
A loop hung for an hour on an input nobody closedEvery step needs a deadline. Third time in one project
The evidence harness invented four clean iterations out of a run that was killedAbsence read as success — and the only one that produced a table
The gate was green and the hero was illegibleThe tool working exactly as documented, with the documentation somewhere nobody reads

The pattern under all of them is one sentence: absence of a result is not a passing result. Write that into your checker before you write anything else.


Take this to work on Monday

Do not start with a whole landing page. Start with one gate.

  1. Pick the check your team already does by hand and resents.
  2. Make it a program that exits 0 or 1.
  3. Put its output somewhere an agent can read — a file, not a terminal it has to remember.
  4. Only then put an agent in front of it.
The loop is the easy part. The oracle is the work.

The honest part

requires. Green means no known defect, never accessible.

an improvement.

the least reliable part of the whole thing. A second opinion, not an oracle.


The eight prompts

In order. Each one stands alone, so if one is going badly you can say “stop where you are, I want to move on” and paste the next.

Prompt 01

Start

Empty folder in, a website running on your own machine out. Nothing is designed yet; this is just the workbench.


Paste this to your agent
Set up a new website project in this folder.

Use Astro with Tailwind CSS. Static output — no React, Vue or Svelte, no server, no
database. Node is already installed.

Then start the development server and tell me the address to open in my browser.

Do not build any pages yet. Do not invent any content. I will give you the design in the
next message, and I want the page to still be empty when I do.

While you work, tell me in one line what each command is doing. I have not used a terminal
before and I would like to follow along.

Codex will ask whether it trusts this folder. Say yes. It refuses to work in a directory it has not been told about, which in a brand-new empty folder means the very first thing it does is stop and ask. That is the tool being careful, not something going wrong.

What you should see. A few minutes of installing, then a line like Local http://localhost:4321/. Open it. You get Astro's placeholder page — plain, ugly, correct.

The terminal is now busy. That window is running the site and will not take another command. Leave it alone and open a second one. In Claude Code and Codex you can simply keep talking; they handle it.


If it goes wrong

What you seeSay this
It starts building a landing page anywayStop. Undo the pages you created. I want an empty project until I give you the design.
Not inside a trusted directoryThis is Codex asking permission. Answer yes, or run git init in the folder first.
command not found: npmNode is not installed. Follow the setup page, or switch to the browser option on it.
It asks you to choose a templatePick the minimal or empty template. No example content.
Nothing happens for two minutesIt is installing. Installing looks exactly like being stuck. Give it five.

Why it is worded like that

"Do not build any pages yet." Left to itself an agent will fill the silence — it will invent a hero, a features grid and three testimonials before you have said a word about what you want. Saying what not to do is half of prompting, and it is the half people leave out.

"Tell me in one line what each command is doing." You can ask for this. The agent is not only a machine that produces files; it is the only patient explainer you will have all afternoon.

Prompt 02

Look at the design

The agent reads the design and tells you what it found. It writes nothing. This is the cheapest correction you will get all day: a wrong assumption costs one sentence to fix here, and twenty minutes of generated code to fix later.

Two routes, depending on whether your Figma account can talk to the agent. Neither is better. The second one is what the gates compare against.


Route A — you connected Figma

Use this if figma appears when you run /mcp in Claude Code, or codex mcp list in Codex, and the workshop file opens in your browser.

Paste this to your agent
Read the TURBINE design file through the Figma MCP server:
<paste the Figma link here>

Do not write any code yet. Tell me what you found, as a list:

1. Every section, in the order they appear down the page, with the name of each.
2. Every colour, as an exact value, and what it is used for.
3. Every text size, and which one is used where.
4. The spacing values you can see — the gaps between things.
5. Anything the design does not tell you, and that you would otherwise have to guess.

Point 5 is the one I care about most. Be specific and be honest: "I cannot tell what
happens to the lineup grid below 500px" is more useful to me than a confident guess.

Route B — Figma is free, or the connection refuses

The design pack is a folder you downloaded from the setup page. Put it beside your project and unzip it, so that there is a design folder next to your src folder.

Paste this to your agent
There is a folder called design next to this project. It contains:

- three PNGs: the page as it should look at 390, 768 and 1440 pixels wide
- tokens.json: every colour, text size, spacing value and radius, by name
- content.md: every word that appears on the page

Read all three. Do not write any code yet. Tell me what you found, as a list:

1. Every section, in the order they appear down the page.
2. Every colour, by its name from tokens.json, and what it is used for.
3. Every text size, and which one is used where.
4. Anything the three files disagree about, or do not tell you, and that you would
   otherwise have to guess.

Point 4 is the one I care about most. Be specific and be honest: "the PNG shows a hover
state I have no values for" is more useful to me than a confident guess.

What you should see. A list. Read it. Two things are worth your attention:

  • Does it describe your design? If it says "a hero, three feature cards and a pricing

table" and your design has a lineup of twelve artists, it is looking at something else, or at nothing.

  • What is in point 4 or 5? That list is the brief you forgot to write. Answer it now,

in your own words, before moving on.


If it goes wrong

What you seeSay this
It starts buildingStop. I asked what you found, not for code. Undo anything you wrote.
Figma returns an error or 401Your account does not include Dev Mode. Switch to Route B — nothing downstream changes.
Colours come back as "a dark grey"Give me exact values. If you cannot read exact values, say so — do not describe them.
It describes a page you do not recogniseIt is not reading your file. Check the link, or switch to Route B.

Why this prompt exists at all

It produces nothing. That is the point.

Everything that goes wrong later in a design-to-code loop went wrong here, invisibly: the agent guessed a colour, assumed a breakpoint, invented a word. Forcing it to say what it saw — before it can hide the guess inside four hundred lines of markup — is the highest return per second of anything in this session.

In Claude Code this is what plan mode does for you automatically (Shift+Tab until the footer says plan mode on). This prompt is plan mode written out by hand, so that it works in any agent.

Prompt 03

Build it

Now it writes the page. Section by section, stopping after each one, so that you are looking at a design review rather than a wall of output.


Paste this to your agent
Build the page now, from the design you just read.

One section at a time, in the order they appear down the page. After each section: reload
the page, tell me what you built in one sentence, and then STOP and wait for me to say
"next". Do not build two sections in one go, however small they look.

Rules, all of them non-negotiable:

- Every colour and every size comes from the design. If you find yourself choosing a
  value, stop and ask me instead.
- Every word comes from the content I gave you. Do not write copy. Do not improve copy.
  If a piece of text seems to be missing, ask — do not fill the gap.
- No new packages. Astro and Tailwind are what we have.
- The page must work with images that have not loaded and with JavaScript switched off.
  Anything clever is an addition on top of something that already works without it.

If the design does not tell you something, do not guess. Write the question down, pick the
reading you think is likeliest, tell me both, and carry on. I would rather correct one
assumption than discover six.

What you should see. One section. Then silence, and a question. Look at the page in your browser. Compare it to the design on your other screen. Then say next, or say what is wrong — in plain words, the way you would to a junior designer:

The gap under the heading is too tight, and the orange is the wrong orange.

That is a perfectly good bug report. You do not need the vocabulary.


If it goes wrong

What you seeSay this
It builds the whole page in one burstStop. Keep what you have. From now on, one section then wait for me.
Text you have never seen beforeWhere did that sentence come from? Replace it with the text from the content I gave you.
A colour that is nearly rightThat is not the value in the design. Use the exact one and tell me which token it is.
It says it is done and it clearly is notWhich sections have you built, and which are still missing? List both.
It gets slower and vaguer as it goesIt is running low on context. Say Summarise where we are in three lines, start a fresh session, paste the summary, and carry on.

Two things worth noticing while it works

It is faster than you, and that is not the same as better. Six sections will appear in the time it takes you to properly look at one. The pause after each section exists so that the reviewing keeps pace with the building. Use it.

Nothing here has checked anything yet. The page may look finished at the end of this prompt. It has been judged by exactly one thing so far: your eyes, on your screen, at your window size. Prompt 04 is where that changes.

Prompt 04

Write the checker

This is the workshop. Everything before it was getting a page onto a screen. Everything after it depends on what happens here.

You are about to ask the agent to build the thing that will judge its own work — and then, in the next prompt, forbid it from ever touching that thing again.


Paste this to your agent
Now write a program that checks your own work.

It must be a program, not an opinion. It runs, it looks at the real page in a real
browser, and it exits with code 0 if everything is right and a non-zero code if anything
is wrong. It never asks a language model anything, it never asks me anything, and it
gives the same answer twice on the same page.

Put it in check.mjs, and make "npm run check" run it. You may install Playwright and
@axe-core/playwright for this — that is the one exception to the no-new-packages rule.

It must check at least these, and it must check them against the page as a browser
actually renders it, not against the source code:

1. The site builds with no errors.
2. Loading the page produces no errors in the browser console.
3. Every section from the design is present, and in the right order.
4. Accessibility: zero axe-core violations, at 390, 768 and 1440 pixels wide.
5. Every colour the page paints is one of the colours in the design. Anything else is a
   failure, and the report says which colour and which element.
6. Every piece of text from the content file appears on the page.
7. Nothing sticks out sideways at 390 pixels — no horizontal scrollbar.
8. Every image has alt text, and it is not the filename.

When something fails, the report must say four things: what failed, where on the page,
what it expected, and what it found. "Contrast issue on the page" is useless. "The date
line in the hero is #6B7280 on #0A0B0D, which is 4.07 to 1, and body text needs 4.5" is
the whole job.

Write the report to check-report.md as well as printing it, because in the next step I am
going to hand that file straight back to you.

Two rules about the checker itself:

- If a check cannot run — the browser will not start, the page will not load — that is a
  FAILURE, never a pass and never a silent skip. A check that did not happen must not look
  like a check that succeeded.
- Do not make the checks lenient so that they pass. I am expecting this to fail. If it
  passes first time I will assume it is not checking anything.

When it is written, run it and show me the output.

What you should see. Red. Quite a lot of it.

That is the correct outcome and it is worth sitting with for a second. A page you were fairly happy with two minutes ago has just been told, by a program, exactly what is wrong with it — with element names and measured numbers.

Read three or four of the failures. Not to fix them; just to see what the report sounds like when it is written well.


If it goes wrong

What you seeSay this
It passes first timeI do not believe it. Show me what each check actually asserts, and prove one of them can fail — break something on purpose and run it again.
Failures like "improve accessibility"That is advice, not a measurement. Every failure must name an element and give a number.
It checks the source code instead of the pageCheck the rendered page in a browser, not the files. A class name in the source is not proof of a colour on the screen.
It skips a check it could not runA check that did not run is a failure, not a skip. Change it so that anything unverified comes out red.
It goes quiet for a long timeInstalling a browser takes a few minutes on a first run.

Why this is the whole point

Ask a model whether its work is good and it will tell you. It will be articulate, specific, and it will sound exactly the same whether the answer is true or not. You have no way of knowing which time you got.

check.mjs cannot do that. It is a few hundred lines that open a browser, measure things, and return a number. It has no opinion about whether you will like the page, it does not know that the agent worked hard, and it will not be talked round.

That is what makes the next prompt work.

A loop is only worth building if something in it can say no without asking a language model for permission.

One honest warning, because the checker will shortly start telling you the page is fine: it is answering a narrower question than "is this page good". Automated accessibility rules reach roughly 30–40% of what the standard actually requires. A colour check knows nothing about whether the design works. Prompt 07 goes looking for the rest.

Prompt 05

The loop

You have a page and you have something that can say no to it. This is the sentence that puts them in a circle.

There is no script here, and there is nothing to install. The loop is a paragraph.


Paste this to your agent
Run npm run check.

If it exits 0, stop and tell me — we are finished.

If it does not, read check-report.md and fix what it names. Then run npm run check again.
Repeat until it exits 0.

Work in the order the report lists things. Fix the cause, not the symptom: if a colour is
wrong, use the one from the design, do not nudge it until the number moves. Make the
smallest change that clears each failure, and leave alone anything that was already
passing.

Three rules, and the first one matters more than the other two:

1. NEVER change check.mjs to make a check pass. Not a threshold, not a skipped assertion,
   not a rule switched off. If you genuinely believe a check is wrong, STOP, tell me which
   one and why, and change nothing.
2. Do not add packages, and do not invent text.
3. If the same failure survives three attempts, stop and tell me what you tried each time
   and what happened. Three failed repairs usually means the design is asking for two
   things that cannot both be true, and no fourth attempt will resolve that.

Keep going on your own. Do not ask me to confirm each round.

Claude Code: make it stick

Claude Code has this built in. Instead of trusting the agent to keep going, you can make it structurally unable to stop:

Paste this to your agent
/goal npm run check exits 0

The session will not end until that is true. Not "until the agent believes it is true" — the command actually runs, and its exit code decides. Paste the prompt above first, then the /goal line.

Codex does not have this. There, the paragraph is the mechanism: it works, it just relies on the agent doing as it was told rather than on the harness enforcing it. Watch the output and say keep going if it stops early.


What you should see. Several minutes of check → fix → check. The failure count comes down. Somewhere in the middle it will probably go up by one — a fix that broke something else — and then come down again.

Then:

✓ all checks passed

Nobody decided that. A program exited 0.


If it goes wrong

What you seeSay this
It edited check.mjsPut the checker back exactly as it was, and fix the page instead. Then look at what it changed — that is the most instructive thing that will happen to you today.
It stops after one roundKeep going. Do not stop until npm run check exits 0. Or use /goal.
The same failure keeps coming backYou have tried that three times. Stop. Tell me what you tried and what happened each time.
It says it is done but the check is redRun npm run check and paste the last five lines, unedited.
It gets slower and vaguerContext is filling. Write what is left into notes.md in ten lines, start a fresh session, paste the notes, continue.

The two things to take home

Fresh beats long. If you have to restart the session, you lose nothing as long as the state is in files — the report and your notes. An agent with a short memory and good notes outperforms one with a long conversation and none. That is why the checker writes check-report.md to disk instead of only printing it.

The rule is the design. "Never change the checker" sounds like discipline. It is architecture. The moment the thing being judged can edit the judge, every green result afterwards means nothing — and it will still look exactly as reassuring.

Prompt 06

Ship it

A URL you can send to someone. This is the bit that makes the afternoon real.


Paste this to your agent
Put this on the internet.

Build the site, then deploy it to Netlify. Use npx so there is nothing to install; if I
am not logged in, tell me what to click rather than doing it silently.

When it is live, do not just tell me it worked. Check:

- fetch the public URL and confirm it returns 200
- confirm the page it serves is the page you just built, not an older one — compare what
  comes back against what is in the dist folder
- run the accessibility check once more against the live URL, not the local one

Then give me the URL on its own line so I can copy it.

What you should see. A browser window asking you to authorise Netlify — do it — then a question about which site to create. Then a line like:

https://something-something-123456.netlify.app

Open it on your phone. That is the whole point of the exercise: the thing exists, on the internet, and you can hand it to someone.


If it goes wrong

What you seeSay this
It asks you to log in and nothing opensIt printed a URL. Paste it into a browser by hand.
A blank page at the live URLThe live page is blank. Check what you published — which folder did you deploy?
CSS missing, text unstyledUsually the wrong folder was published. Deploy the dist folder, not the project root.
"It deployed successfully" with no URLGive me the public URL on its own line.

The check that matters here, and why it is not fussiness

"Confirm the page it serves is the page you just built."

Everything up to now proved something about a file on your laptop. Between that file and a visitor there is a build, an upload, a CDN and a cache, and each of them has been known to serve something other than what you sent. Green checks locally say nothing about what is live.

When this was built, that check failed — twice — for a reason nobody would have guessed: the host quietly injects its own tags into every page it serves, so the bytes can never match exactly. The honest check turned out to be "the body is identical and everything I put in the head is still there", which is a different sentence from the one originally written down, and it is the true one.

Asking "is the thing I published the thing I checked?" takes ten seconds and is the last place a whole afternoon of correctness can quietly evaporate.

Prompt 07

Try to break it

Your checker is green. That means no known defect — it has never meant finished.

This prompt goes looking for what the checker structurally cannot see. It is a model checking a model, which makes it the least reliable thing you will do today, and it is still worth doing, because the alternative is not looking.


Paste this to your agent
The checks pass. Now try to prove the page is still wrong.

Your job in this message is to attack, not to defend and not to fix. Find five things that
are wrong with this page that check.mjs cannot catch, and for each one tell me:

- exactly which element, by what I would see on screen
- what is wrong with it
- why the checker missed it — what question does it ask that this slips past?

Look specifically where an automated check has no reach:

- text over a photograph: axe does not judge that contrast at all, it marks it
  "incomplete" and moves on
- reading order for someone using a keyboard or a screen reader: technically valid and
  incoherent is a thing that exists
- alt text that is present, and useless
- a heading structure that looks like a hierarchy and is not one
- copy that passes every rule and still does not sound like the brand
- what happens at 500 pixels wide — a width nobody screenshotted
- anything that only breaks on the second visit, or with a slow connection

Before you tell me any of them, argue against each one yourself, from three angles:

  is it true      - go and look again, do not trust your first reading
  does it matter  - would a visitor notice, or only a checklist?
  is it handled   - is it already covered somewhere I have not looked?

Report only the findings that survive all three. Default to discarding when you are
unsure, and tell me how many you threw away. Four real findings beat five with a guess in
them. If you cannot point at a specific element, it is not a finding.

Do not fix anything yet. I want to decide which of these are real first.

What you should see. A short list, several items of which are genuinely worth fixing — and at least one that is wrong, or that you disagree with. Both outcomes are the lesson.

Pick the two you believe and say:

Paste this to your agent
Fix findings 2 and 4. Leave the rest. Then run npm run check again — I want to know if
fixing them broke anything that was passing.

Why you make it argue with itself

A reviewer asked to "find problems" finds problems — it will produce five, because you asked for five. A reviewer asked to destroy a specific claim either destroys it or fails to, and failing to is information.

The three angles are doing the job a second person would do. It is weaker than a second person and much better than nothing, and it costs one paragraph.

Where self-assessment is fine, and where it is not

FineNot fine
Is this sentence any goodIs this correct
Which of these five findings matters mostIs this accessible
Does this read as the same brandDoes this match the design
Is the hierarchy clearIs it finished

The left column has no external truth to check against, so a thoughtful opinion is the best instrument available. The right column has one — so use it, and do not accept an opinion instead.

This prompt lives entirely in the left column. That is why it produces a list for you to triage, and never a verdict.


One real example

While this workshop was being built, the accessibility check was green. Zero violations, three widths, twice in a row, perfect Lighthouse score.

Five of the nine pieces of text in the hero were below the legal contrast minimum against the photograph behind them. The largest, first, most-read text on the page.

The checker was not broken and it was not lying. axe does not evaluate text over a background image — it reports the pair as incomplete, and in a gate whose rule is "zero violations", incomplete is indistinguishable from correct.

Nothing in the source would have told you either. The background there was a photograph, two translucent overlays and a gradient composited together, and no line of CSS anywhere says what colour that comes out as. It took a person deciding to look.

Green means no known defect. Knowing where your checks stop is the job.

Prompt 08

The same job, as a workflow

You have just run seven prompts by hand. You were the thing between them: you read the output, you decided it was good enough, you pasted the next one.

That role is describable. Phases, what happens in each, and what has to be true before the next one starts — write those down and the agent runs the sequence itself.

No script. No tool. It is a message.


Paste this to your agent
I want you to do a whole job, in phases I define. Work through them in order, on your own,
and do not skip ahead.

PHASE 1 — LOOK
Read the design: design/tokens.json, design/content.md, and the three PNGs in design/.
Write what you found into notes.md: every section in order, every colour by name, every
text size, and a list of anything the design does not tell you.
Do not write any code in this phase.
Before moving on: show me notes.md and wait for me to say "go".

PHASE 2 — BUILD
Build the page section by section, in the order from notes.md. Colours and sizes only
from tokens.json. Words only from content.md. No new packages except the two named in
phase 3.
Before moving on: the site builds with no errors.

PHASE 3 — ARM
Write check.mjs: a program that opens the real page in a real browser and exits 0 or
non-zero. It must check the sections, zero axe violations at 390/768/1440, that every
colour is one from tokens.json, that every string from content.md is on the page, and
that nothing overflows sideways at 390. Wire it to "npm run check". You may install
Playwright and @axe-core/playwright here.
A check that cannot run is a failure, never a skip.
Before moving on: npm run check runs and reports something. It will be red. Good.

PHASE 4 — REPAIR
Loop: run npm run check, read check-report.md, fix what it names, run it again. Repeat
until it exits 0.
NEVER edit check.mjs to make a check pass. If you believe a check is wrong, stop and tell
me which and why.
Before moving on: npm run check exits 0.

PHASE 5 — SHIP
Build and deploy to Netlify. Then fetch the live URL and prove the page it serves is the
page that passed phase 4.
Before moving on: the live URL returns 200 and serves what you built.

PHASE 6 — ATTACK
Find five things wrong with the page that check.mjs cannot see. For each one, argue
against it yourself from three angles before you tell me — is it true, does it matter, is
it already handled — and only report the ones that survive your own argument.
Do not fix anything. Give me the list.

Rules for the whole run:
- Announce each phase as you enter it.
- If a phase cannot finish, stop there and tell me why. Do not carry on into the next one
  with the previous one broken.
- Keep notes.md current as you go. If you run out of room and we have to start fresh,
  notes.md is all the next session will have.

What you should see. PHASE 1 — LOOK and then work, unattended, for a long time. It will stop at the two places you told it to stop, and nowhere else.


Loop and workflow are different things

People use the words interchangeably. They are not the same shape, and knowing which one you need is most of the skill.

AspectLoopWorkflow
ShapeDo this again until a condition holdsDo these things, in this order, with a bar between each
You definethe exit conditionthe phases
Ends whena program says yesthe last phase finishes
Good forconverging on correctnesswork with stages that depend on each other
In this packprompt 05this prompt

Phase 4 above is a loop, living inside a workflow. That is the usual arrangement: the workflow gets you from nothing to nearly-right, and a loop inside one phase closes the last gap.


Parameterise it

The phase list is the program. Change it and you have changed the job, without writing a line of anything:

Phase 2 builds only the hero and the lineup. Leave the rest.
Between phase 2 and 3, add a phase: show me each section as a screenshot at 390 and wait for my approval.
Skip phase 5. I am not deploying today.
In phase 6, look only at what happens between 480 and 620 pixels wide.

That is what "no script needed" means in practice. A script would have to be edited, tested and re-run. This gets edited in the sentence you were about to say anyway.


When to reach for this, and when not

Use the workflow when you know the shape of the work and want to walk away: it is long, the stages are real, and you would rather come back to a result than babysit.

Use the seven prompts when you are learning, when you want to steer, or when the design is unclear and you expect to change your mind halfway. Every stop is a chance to disagree, and disagreeing early is cheaper than everything else in this session.

The first time you do a piece of work, do it by hand. The second time, you know what the phases are.


If it goes wrong

What you seeSay this
It announces phase 3 without doing phase 2You skipped phase 2. Go back and finish it before phase 3.
It blows through the "wait for me" barPhase 1 said wait. Stop and show me notes.md.
It gets vaguer around phase 4Summarise the state into notes.md. Then start a fresh session, paste notes.md, and say Continue from phase 4.
It declares the whole thing doneRun npm run check and paste the last five lines, unedited.
A phase fails and it continues anywayYou were told to stop on a failed phase. What failed, and why did you continue?