Gauntlet loop — grind a throwaway prototype until it beats a real reference
Purpose
Stage: standalone · cross-cutting — it takes no place in the artifact chain: no gate waits on it, it blocks nothing, /orchestrate is untouched, and it reads no intent.md and writes no prd.md, acceptance.md, plan.md, or qa.md.
The fast path for a proof of concept (POC). A gauntlet loop names one real artifact from outside this
repository that the work has to beat — the bar — splits the goal into the smallest pieces that can be
judged on their own, and on each piece runs a builder against a separate critic that puts the two
side by side without being told which is which. The loop ends when the critic picks ours.
Production work uses the lifecycle skills. This one is for the throwaway: a spike, a demo, the thing you
build to find out whether the idea is worth specifying at all.
Everything it produces lands in .gauntlet/<slug>/, a directory the repository ignores. The fetched bar,
the per-piece work, the progress page, the output. src/ is not touched and there is nothing to commit.
What that ignore line does, exactly: it stops a commit. An ordinary git add cannot sweep a POC into the
tracked tree, and that much holds whether or not anyone reads this file. It is also the whole of what it does.
It does not stop someone copying a file out — nothing does — so the prohibition is written down too, under
Rationalizations. And it is not a sandbox: a bar you install and run is ordinary code with ordinary reach,
and git declining to track a directory confines none of it. Step 6 is where that is gated, and the gate is you.
The ignore line is not assumed. Nothing is written until .gauntlet/ is in the target repository's
.gitignore — the Process says where that check sits, and the prompt this skill emits carries the same
requirement into whatever session runs it. Where the line is absent, say so and ask before adding it:
.gitignore belongs to the human, as project-setup also holds. A human who declines it has declined the
loop, so say that and stop rather than running a throwaway build into a tracked tree.
frontend-design gets its throwaway screens ignored the same way.
Loop-until-win is legal here, and only here. doubt-driven-development and the orchestrator each bound
their cycles, each states its own bound, and this skill does not lift either. Those bounds exist because a
production run has a retry budget, a frozen acceptance.md, and a wave of other slices waiting on it. A
gauntlet loop has none of the three, so its exit can be the outcome itself: the critic picks ours.
When to use / when to skip
Use when the output is meant to be thrown away and the point is to find out how good the idea can get: a
spike, a demo, a prototype, a bake-off against something that already exists. Use it when someone says
"gauntlet this", "loop until it beats X", "run the gauntlet", or asks for a gauntlet prompt to paste into a
fresh session.
Skip when any part of the output will ship. What decides is whether the result gets thrown away, and the
human decides it — by naming the gauntlet outright, or by picking this path when using-agent-skills sets
the two side by side. An ask that merely sounds fast decides nothing; the Offering the fast path section
of using-agent-skills says why, and that is where to read it rather than re-deriving it here.
| You want… |
Reach for |
Where the work lands |
What ends it |
| a throwaway build pushed until it beats a named outside reference |
gauntlet-loop (this skill) |
.gauntlet/<slug>/, ignored by the repository |
the critic picks ours, blind |
| anything that will ship |
the lifecycle, /ideate through /ship |
the repository |
the signed contracts, the gates, a human merge |
| a confident in-flight decision cross-examined during a run |
doubt-driven-development |
the run's own artifacts |
that skill's own stop conditions |
Inputs
- The goal, in one line — what to build, write, or measure.
- The bar, when the human named one. When they did not, you offer two or three candidates and stop; the
human picks. Never pick for them: the bar decides everything the loop is worth.
- The measurable half — the part of the goal a number settles instead of a judgement, where the goal has
one: load time, token cost, benchmark score, word count, pass rate. Name it beside the bar; taste plus a
number beats taste alone.
- A slug for the run, which names its scratch directory
.gauntlet/<slug>/. Create it on first use.
- Optional: tool names the goal genuinely needs (image or video generation, a browser, a deploy target),
and a budget ceiling — only when the human named one. There is no default cap.
No upstream artifact is required. An empty repository is a valid input.
Process
Two modes share the first two steps. The default output is the prompt — one block the human pastes into a
fresh session — because a loop that may grind for hours belongs in a session of its own. Running it here is
the offer, not the assumption.
Read the goal. Restate it in one line to yourself. Do not put the restatement on screen.
Set the bar. Supplied → use it. Not supplied → offer two or three candidates, one line each, and
stop. Wait for the pick. That is where the turn ends: candidates and nothing else. Never write a prompt
with [BAR] still in it, and never pick for the human. Put whichever they choose through the three tests
below; a candidate that fails one is not a bar, and you say so rather than proceeding with it.
Write the prompt. One paste-ready block: no preamble, no headings inside it, no narration after it.
Its shape and fill rules are below.
Offer to run it. One flat line under the block — "I can run this here." Not a question. If the human
says run it, this session runs the loop itself: you follow the prompt you just wrote, and steps 5 to 12 are
what that means.
Clear the scratch directory before writing. .gauntlet/ in the target repository's .gitignore is the
precondition for every write that follows. Present → carry on. Absent → say so and ask; the human's yes
adds the one line, and their no ends the run here.
Show what you are about to fetch, and wait for a yes. Before anything is cloned, installed, or run,
put the thing itself on screen — the URL, the package name and version, the repository — and say which of
the three you intend, because downloading a file, installing a package, and executing it are three
different asks. Then stop and wait. A bar is code and content from outside this repository, picked for
being good rather than for being safe, and running it gives it whatever this session can already reach.
The human's yes is the only thing between those two facts, so it is asked for by name and per bar: a
yes for this bar is not a yes for the next one, and a yes to downloading is not a yes to executing. A no
ends the run here — say so and stop, rather than quietly substituting a bar nobody agreed to or falling
back to comparing against a description.
What it does not get, whatever the answer. No credentials and no environment secrets — this session's
API keys, tokens, and .env contents go nowhere near the install, the build, or the run, and nothing
under .gauntlet/ is a place to copy them to. No repository contents beyond what the comparison needs:
the bar is judged beside our output for one piece, so it gets that output, not the tree. No network reach
the comparison does not need, and a build step that wants to authenticate somewhere is a stop rather than
a prompt to go find it a credential. Where the goal genuinely needs one of these — a private repository,
a licensed dataset — name it to the human at this step and let them decide it along with the rest.
Get the real thing. With the yes in hand, fetch the bar into .gauntlet/<slug>/bar/ — the screenshot
at the stated viewport, the published piece, the cloned repository, the footage. Compare against
the artifact, never against a description of it: a critic handed a description invents the comparison. If
it cannot be obtained on this machine it was never fetchable and it is not a bar — say what failed and go
back to step 2.
Split into pieces small enough to judge alone. A piece is something one critic can look at and call
better or worse — the hero, the motion, the type, the opening paragraph, the flag parsing, the benchmark
run. A piece that needs two judgements is two pieces, and the first critic to hedge is how you find that
out; split then rather than arguing the sizing up front.
Fan out a builder and a separate critic per piece, in parallel, each with fresh context. The critic is
code-cold: it never sees the builder's reasoning, and it must not know how hard the builder tried.
Judge blind and loop. Blind is something you build, not something you ask for. Produce both sides under
the same conditions — same fixture, same viewport, same width, same length — hand them over as a and b
in an order chosen at random, with no filename, path, or caption saying which is ours, and give the critic
one job: pick one, then name the single biggest remaining gap. Where the piece has a measurable
half, the two numbers go over with the pair and count toward the pick. Where the reference is recognizable
on sight — a house style, a signature border, a byline — say so to the human instead of calling the
comparison blind when it was not. The gap goes back to that piece's builder. Repeat per piece until the
critic picks ours. No round count, and no score standing in for the pick; the failure modes are in
Rationalizations.
Surface a stall. A piece whose critic keeps returning the same gap is not converging, and a fresh
critic carries no memory of that — so you keep the count. Say it on the progress page and tell the human.
You still do not invent a round cap: stopping the run is the human's move.
Stop and report. Say where the POC lives and what the last critic said about each piece. The next
action is the human's.
The bar is the whole trick
Everything else is scaffolding. The loop only produces quality when the thing it compares against is real and
already better. A bar passes three tests or it is not a bar:
- Named. A specific artifact, not a category. "Stripe's pricing page" is a bar. "Award-winning SaaS
sites" is not.
- Fetchable. The critic can actually obtain it — screenshot the live page, read the published piece, run
the binary, open the repository, watch the footage. What cannot be obtained gets invented. A bar the human
will not let you run is not fetchable for this purpose, which step 6 settles.
- Comparable. Both can sit side by side and a judge can pick one. If you cannot picture the A/B, there is
nothing to judge.
| Goal |
A bar that works |
| Website, app, UI |
the live site of a named best-in-class product, screenshotted at the same viewport |
| Game, 3D, visual |
real footage or screenshots from a named shipped title |
| Writing |
a specific published piece by a named author or publication, same length and format |
| Code, tooling |
a named repository's implementation, plus its benchmark or test suite as the measurable half |
| Research, analysis |
a named analyst report, or a paper's methods section, judged on rigour and coverage |
| Deck, document, deliverable |
a real artifact from a firm known for it, same page count |
Offer the hardest bar the agent can genuinely reach. A bar set low enough to clear exits on round one and
proves nothing.
The paste-ready prompt
Adapt the wording every time. Fill the brackets, keep it short, keep the last lines. The block closes on two
Claude Code features — /loop, which reruns a prompt on an interval or lets the model pace itself, and
ultracode, which opts the turn into multi-agent orchestration. Portability below says what to write in
their place on any other agent.
Run a gauntlet loop on this: build [GOAL].
The bar is [BAR]. Get the real thing first and compare against it directly, not against a description of it.
Before you clone, install, or run anything to get it, show me exactly what you are about to fetch and wait for
my yes, and ask again for every new one. Do not hand it my credentials or environment secrets, and do not give
it more of the repository than the comparison needs.
All work goes in .gauntlet/[SLUG]/ and nothing is written outside it. This is a throwaway proof of concept,
so put .gauntlet/ in .gitignore before you write anything, and ask me first if it is not already there.
Break this into the smallest pieces that can be improved and judged on their own. For each piece, fan out a
builder and a separate critic with fresh context. The critic inspects the actual output, puts it next to the
bar blind with the labels stripped, says which one is better, and names the single biggest remaining gap.
Then it goes back to the builder.
The critic should be a harsh critic. Praise is not useful. If ours does not win, it keeps going.
/loop on each piece until the critic picks ours blind. Do not stop before that.
Keep a live progress page in .gauntlet/[SLUG]/ updating as the work evolves so I can watch it.
Fan out subagents and ultracode.
What you fill in, and what stays out:
- Bake the bar in as a concrete, fetchable thing — a URL, a product name, a repository, a title.
- Name the measurable half beside the reference when the goal has one.
- Add a budget or cost ceiling only when the human named one. No default cap.
- Add tool names only when the goal needs them.
- Everything else stays out: no architecture, no file layout, no decomposition, no round count, no stack
choice the human did not demand. The agent decides those after it has seen the bar; a specification written
before the work started was written without it.
Length and voice. Short. The template above runs 239 words unfilled, and a filled one lands near two
hundred and fifty. The count is not the test: if it needs a heading to stay readable, it is too long. Plain
sentences, no bullets inside the block. It should read like someone naming the standard and refusing anything
under it.
Portability. On any agent without /loop and ultracode, swap the last two lines for: "Keep looping
until the critic picks ours. Run the builders and critics as parallel subagents." The structure carries over
unchanged.
Rationalizations
Stop signals disguised as good reasons:
- "'Award-winning SaaS sites' is close enough to a bar." → It is the most common way a gauntlet loop fails.
A category cannot be fetched, so the critic invents the comparison and approves everything.
- "I will describe the reference to the critic instead of fetching it." → The same failure one step later.
The critic judges the artifact, or it judges its own imagination.
- "The builder can grade its own piece — it knows it best." → Knowing how hard it tried is exactly what
disqualifies it. The critic is a separate agent with fresh context.
- "A score out of ten shows progress better than a pick." → Scores drift upward every round; that drift is
the thing bars exist to replace. A binary pick, or nothing.
- "Three rounds is plenty, I will call it done." → The exit is winning the comparison, or the human stopping
the run. A round count is another skill's bound and it stays there.
- "An easier bar would let us finish." → A bar set low enough to clear proves nothing. Raise the work, not
the floor.
- "I will specify the layout and the stack so the builder does not wander." → Every extra instruction is one
fewer decision made with the agent's own judgement, after it has seen the bar.
- "They said yes to the last bar, so this one is covered." → The yes was about a named thing. A new URL, a
new package, or a move from downloading to executing is a new ask. Treating one yes as standing permission
is how a consent step decays into a formality.
- "This piece came out well — I will move it into
src/." → Nothing leaves .gauntlet/. One critic's blind
pick is not a signed contract, a code-cold review, or a Verify pass, and code nobody else has to maintain is
held to a different standard than code they do.
- "The tree has unrelated changes in it, so I will stash them to get a clean check." → Never. Those changes
are somebody's work in progress and none of this run's business. The check is over the files this run wrote,
not over the whole tree.
Red flags
Stop and fix before continuing if any are true:
- The bar is a category, a style, or an adjective rather than one named artifact.
- The reference was never obtained, so the critic is comparing against a description.
- One agent both built and judged a piece, or the critic saw the builder's reasoning or its effort.
- The pair reached the critic under names, paths, an order, or conditions that said which one was ours.
- A judgement came back as a score, a percentage, or a rubric instead of a pick plus one gap.
- An exit was taken on a round count rather than on the critic's pick.
- A clone, an install, or an execution happened before the human saw what was being fetched; or one yes was
stretched to cover a second bar, or a yes to downloading was read as a yes to running; or credentials,
environment secrets, or repository contents beyond the piece under comparison reached the fetched bar, or a
build that asked to authenticate got a credential instead of a stop.
- A write happened while
.gauntlet/ was not in the target repository's .gitignore, or the line was added
without asking, or any file landed outside .gauntlet/<slug>/.
- The
.gitignore line was treated as though it confined what the fetched bar could run, read, or reach.
- The prompt carries headings, or specifies architecture, stack, or decomposition the human never asked for.
- A piece is big enough to need two judgements.
Verification (ending criteria)
Prompt mode is done when one paste-ready block exists — short, no headings inside it, the bar baked in as
a named fetchable thing, the gauntlet named in its first line, and both the scratch-directory requirement
and the ask-before-you-fetch requirement carried inside the block, because the session that runs it is the
one that does the fetching and a gate left behind in this file gates nothing there — and the offer to run it
sits under the block on one flat line. A turn that offered candidate bars and stopped is not an unfinished
prompt mode; it is step 2 ending correctly, and the block comes after the pick.
Run mode is done when ALL hold:
- Every piece's final critic picked ours, blind — or the human stopped the run, and the report says that
rather than claiming a win.
- Every bar was named on screen — the URL, the package, the repository — and agreed to before it was cloned,
installed, or run, with a fresh yes for each one. No credential, no environment secret, and no repository
content beyond the piece under comparison was handed to it. A run the human declined stopped there and
said so.
- The bar was obtained as an artifact and sat beside ours for every judgement.
- Each piece had a builder and a separate code-cold critic; no agent judged what it built.
- Each pair went out under neutral names in a random order, produced under the same conditions. Where the
reference was recognizable on sight, the report says so.
- Every judgement was a pick plus the single biggest remaining gap; no critic returned a score in place of a
pick.
- No exit was taken on a round count, and any piece that stalled was named to the human.
.gauntlet/ was in the target repository's .gitignore before the first write — already there, or added
after the human said yes. git status --short lists nothing this run created, and at most that one-line
.gitignore change. Everything else already in the tree stays exactly as it was.
- The report says where the POC lives and what the last critic said for each piece.
Outputs & handoff contract
- Emits: in prompt mode, one paste-ready prompt block, in-conversation. In run mode, the proof of concept
itself under
.gauntlet/<slug>/ — the fetched bar, the per-piece work, the live progress page, the output —
plus an in-conversation report of where it lives and what the last critic said.
- Writes nowhere else. Not
src/, not docs/features/<slug>/, not STATE.md, not CONTEXT.md — the one
exception is the .gauntlet/ line in .gitignore, added with the human's yes before the first write where
the repository lacks it. A finished run leaves the tracked tree otherwise untouched.
- Reads no upstream artifact. It holds no place in the chain
intent.md → research.md → prd.md → acceptance.md → environment.md → architecture.md → plan.md → qa.md, and nothing downstream consumes it.
- Next action: the human's. The run reports and stops.
- Standalone: no lifecycle gates, nothing blocks,
/orchestrate untouched.
1---2name: gauntlet-loop3description: Grinds a throwaway prototype until it beats a real outside reference — name one fetchable bar, split the goal into independently judgeable pieces, and run a builder against a separate blind critic on each until the critic picks ours. Emits a paste-ready prompt for a fresh session, and runs the loop here when asked. The fast path for a proof of concept; anything that will ship uses the lifecycle skills. Use when someone types /gauntlet-loop or says "gauntlet this", "loop until it beats X", "run the gauntlet", or asks for a gauntlet prompt. An ask that merely sounds fast never selects it — quick is a tone, not a scope, so using-agent-skills offers this path beside the full loop and the human picks. Needs a person in the session: fetching a bar can mean running code from outside the repository, and every fetch waits for your yes. Standalone — no lifecycle gates, nothing blocks, /orchestrate untouched.4---56# Gauntlet loop — grind a throwaway prototype until it beats a real reference78## Purpose910**Stage: standalone · cross-cutting** — it takes no place in the artifact chain: no gate waits on it, it blocks nothing, `/orchestrate` is untouched, and it reads no `intent.md` and writes no `prd.md`, `acceptance.md`, `plan.md`, or `qa.md`.1112The **fast path for a proof of concept** (POC). A gauntlet loop names one real artifact from outside this13repository that the work has to beat — the **bar** — splits the goal into the smallest pieces that can be14judged on their own, and on each piece runs a **builder** against a separate **critic** that puts the two15side by side without being told which is which. The loop ends when the critic picks ours.1617**Production work uses the lifecycle skills.** This one is for the throwaway: a spike, a demo, the thing you18build to find out whether the idea is worth specifying at all.1920**Everything it produces lands in `.gauntlet/<slug>/`, a directory the repository ignores.** The fetched bar,21the per-piece work, the progress page, the output. `src/` is not touched and there is nothing to commit.2223**What that ignore line does, exactly: it stops a commit.** An ordinary `git add` cannot sweep a POC into the24tracked tree, and that much holds whether or not anyone reads this file. It is also the whole of what it does.25It does not stop someone copying a file out — nothing does — so the prohibition is written down too, under26*Rationalizations*. And it is not a sandbox: a bar you install and run is ordinary code with ordinary reach,27and git declining to track a directory confines none of it. Step 6 is where that is gated, and the gate is you.2829The ignore line is not assumed. Nothing is written until `.gauntlet/` is in the target repository's30`.gitignore` — the Process says where that check sits, and the prompt this skill emits carries the same31requirement into whatever session runs it. Where the line is absent, say so and **ask** before adding it:32`.gitignore` belongs to the human, as `project-setup` also holds. A human who declines it has declined the33loop, so say that and stop rather than running a throwaway build into a tracked tree.34`frontend-design` gets its throwaway screens ignored the same way.3536**Loop-until-win is legal here, and only here.** `doubt-driven-development` and the orchestrator each bound37their cycles, each states its own bound, and this skill does not lift either. Those bounds exist because a38production run has a retry budget, a frozen `acceptance.md`, and a wave of other slices waiting on it. A39gauntlet loop has none of the three, so its exit can be the outcome itself: the critic picks ours.4041## When to use / when to skip4243**Use** when the output is meant to be thrown away and the point is to find out how good the idea can get: a44spike, a demo, a prototype, a bake-off against something that already exists. Use it when someone says45"gauntlet this", "loop until it beats X", "run the gauntlet", or asks for a gauntlet prompt to paste into a46fresh session.4748**Skip** when any part of the output will ship. What decides is whether the result gets thrown away, and the49human decides it — by naming the gauntlet outright, or by picking this path when `using-agent-skills` sets50the two side by side. An ask that merely *sounds* fast decides nothing; the *Offering the fast path* section51of `using-agent-skills` says why, and that is where to read it rather than re-deriving it here.5253| You want… | Reach for | Where the work lands | What ends it |54|---|---|---|---|55| a throwaway build pushed until it beats a named outside reference | **gauntlet-loop** (this skill) | `.gauntlet/<slug>/`, ignored by the repository | the critic picks ours, blind |56| anything that will ship | the lifecycle, `/ideate` through `/ship` | the repository | the signed contracts, the gates, a human merge |57| a confident in-flight decision cross-examined during a run | `doubt-driven-development` | the run's own artifacts | that skill's own stop conditions |5859## Inputs6061- **The goal**, in one line — what to build, write, or measure.62- **The bar**, when the human named one. When they did not, you offer two or three candidates and stop; the63 human picks. Never pick for them: the bar decides everything the loop is worth.64- **The measurable half** — the part of the goal a number settles instead of a judgement, where the goal has65 one: load time, token cost, benchmark score, word count, pass rate. Name it beside the bar; taste plus a66 number beats taste alone.67- **A slug** for the run, which names its scratch directory `.gauntlet/<slug>/`. Create it on first use.68- **Optional:** tool names the goal genuinely needs (image or video generation, a browser, a deploy target),69 and a budget ceiling — only when the human named one. There is no default cap.7071No upstream artifact is required. An empty repository is a valid input.7273## Process7475Two modes share the first two steps. The default output is **the prompt** — one block the human pastes into a76fresh session — because a loop that may grind for hours belongs in a session of its own. Running it here is77the offer, not the assumption.78791. **Read the goal.** Restate it in one line to yourself. Do not put the restatement on screen.802. **Set the bar.** Supplied → use it. Not supplied → offer **two or three** candidates, one line each, and81 **stop**. Wait for the pick. That is where the turn ends: candidates and nothing else. Never write a prompt82 with `[BAR]` still in it, and never pick for the human. Put whichever they choose through the three tests83 below; a candidate that fails one is not a bar, and you say so rather than proceeding with it.843. **Write the prompt.** One paste-ready block: no preamble, no headings inside it, no narration after it.85 Its shape and fill rules are below.864. **Offer to run it.** One flat line under the block — "I can run this here." Not a question. If the human87 says run it, this session runs the loop itself: you follow the prompt you just wrote, and steps 5 to 12 are88 what that means.895. **Clear the scratch directory before writing.** `.gauntlet/` in the target repository's `.gitignore` is the90 precondition for every write that follows. Present → carry on. Absent → say so and ask; the human's yes91 adds the one line, and their no ends the run here.926. **Show what you are about to fetch, and wait for a yes.** Before anything is cloned, installed, or run,93 put the thing itself on screen — the URL, the package name and version, the repository — and say which of94 the three you intend, because downloading a file, installing a package, and executing it are three95 different asks. Then stop and wait. A bar is code and content from outside this repository, picked for96 being good rather than for being safe, and running it gives it whatever this session can already reach.97 The human's yes is the only thing between those two facts, so it is asked for by name and **per bar**: a98 yes for this bar is not a yes for the next one, and a yes to downloading is not a yes to executing. A no99 ends the run here — say so and stop, rather than quietly substituting a bar nobody agreed to or falling100 back to comparing against a description.101102 **What it does not get, whatever the answer.** No credentials and no environment secrets — this session's103 API keys, tokens, and `.env` contents go nowhere near the install, the build, or the run, and nothing104 under `.gauntlet/` is a place to copy them to. No repository contents beyond what the comparison needs:105 the bar is judged beside our output for one piece, so it gets that output, not the tree. No network reach106 the comparison does not need, and a build step that wants to authenticate somewhere is a stop rather than107 a prompt to go find it a credential. Where the goal genuinely needs one of these — a private repository,108 a licensed dataset — name it to the human at this step and let them decide it along with the rest.1091107. **Get the real thing.** With the yes in hand, fetch the bar into `.gauntlet/<slug>/bar/` — the screenshot111 at the stated viewport, the published piece, the cloned repository, the footage. Compare against112 the artifact, never against a description of it: a critic handed a description invents the comparison. If113 it cannot be obtained on this machine it was never fetchable and it is not a bar — say what failed and go114 back to step 2.1158. **Split into pieces small enough to judge alone.** A piece is something one critic can look at and call116 better or worse — the hero, the motion, the type, the opening paragraph, the flag parsing, the benchmark117 run. A piece that needs two judgements is two pieces, and the first critic to hedge is how you find that118 out; split then rather than arguing the sizing up front.1199. **Fan out a builder and a separate critic per piece**, in parallel, each with fresh context. The critic is120 **code-cold**: it never sees the builder's reasoning, and it must not know how hard the builder tried.12110. **Judge blind and loop.** Blind is something you build, not something you ask for. Produce both sides under122 the same conditions — same fixture, same viewport, same width, same length — hand them over as `a` and `b`123 in an order chosen at random, with no filename, path, or caption saying which is ours, and give the critic124 one job: **pick one**, then name the **single biggest remaining gap**. Where the piece has a measurable125 half, the two numbers go over with the pair and count toward the pick. Where the reference is recognizable126 on sight — a house style, a signature border, a byline — say so to the human instead of calling the127 comparison blind when it was not. The gap goes back to that piece's builder. Repeat per piece until the128 critic picks ours. No round count, and no score standing in for the pick; the failure modes are in129 *Rationalizations*.13011. **Surface a stall.** A piece whose critic keeps returning the same gap is not converging, and a fresh131 critic carries no memory of that — so you keep the count. Say it on the progress page and tell the human.132 You still do not invent a round cap: stopping the run is the human's move.13312. **Stop and report.** Say where the POC lives and what the last critic said about each piece. The next134 action is the human's.135136## The bar is the whole trick137138Everything else is scaffolding. The loop only produces quality when the thing it compares against is real and139already better. A bar passes three tests or it is not a bar:140141- **Named.** A specific artifact, not a category. "Stripe's pricing page" is a bar. "Award-winning SaaS142 sites" is not.143- **Fetchable.** The critic can actually obtain it — screenshot the live page, read the published piece, run144 the binary, open the repository, watch the footage. What cannot be obtained gets invented. A bar the human145 will not let you run is not fetchable for this purpose, which step 6 settles.146- **Comparable.** Both can sit side by side and a judge can pick one. If you cannot picture the A/B, there is147 nothing to judge.148149| Goal | A bar that works |150|---|---|151| Website, app, UI | the live site of a named best-in-class product, screenshotted at the same viewport |152| Game, 3D, visual | real footage or screenshots from a named shipped title |153| Writing | a specific published piece by a named author or publication, same length and format |154| Code, tooling | a named repository's implementation, plus its benchmark or test suite as the measurable half |155| Research, analysis | a named analyst report, or a paper's methods section, judged on rigour and coverage |156| Deck, document, deliverable | a real artifact from a firm known for it, same page count |157158Offer the hardest bar the agent can genuinely reach. A bar set low enough to clear exits on round one and159proves nothing.160161## The paste-ready prompt162163Adapt the wording every time. Fill the brackets, keep it short, keep the last lines. The block closes on two164Claude Code features — `/loop`, which reruns a prompt on an interval or lets the model pace itself, and165`ultracode`, which opts the turn into multi-agent orchestration. *Portability* below says what to write in166their place on any other agent.167168```169Run a gauntlet loop on this: build [GOAL].170171The bar is [BAR]. Get the real thing first and compare against it directly, not against a description of it.172Before you clone, install, or run anything to get it, show me exactly what you are about to fetch and wait for173my yes, and ask again for every new one. Do not hand it my credentials or environment secrets, and do not give174it more of the repository than the comparison needs.175176All work goes in .gauntlet/[SLUG]/ and nothing is written outside it. This is a throwaway proof of concept,177so put .gauntlet/ in .gitignore before you write anything, and ask me first if it is not already there.178179Break this into the smallest pieces that can be improved and judged on their own. For each piece, fan out a180builder and a separate critic with fresh context. The critic inspects the actual output, puts it next to the181bar blind with the labels stripped, says which one is better, and names the single biggest remaining gap.182Then it goes back to the builder.183184The critic should be a harsh critic. Praise is not useful. If ours does not win, it keeps going.185186/loop on each piece until the critic picks ours blind. Do not stop before that.187188Keep a live progress page in .gauntlet/[SLUG]/ updating as the work evolves so I can watch it.189190Fan out subagents and ultracode.191```192193What you fill in, and what stays out:194195- Bake the bar in as a concrete, fetchable thing — a URL, a product name, a repository, a title.196- Name the measurable half beside the reference when the goal has one.197- Add a budget or cost ceiling **only when the human named one**. No default cap.198- Add tool names only when the goal needs them.199- Everything else stays out: no architecture, no file layout, no decomposition, no round count, no stack200 choice the human did not demand. The agent decides those after it has seen the bar; a specification written201 before the work started was written without it.202203**Length and voice.** Short. The template above runs 239 words unfilled, and a filled one lands near two204hundred and fifty. The count is not the test: if it needs a heading to stay readable, it is too long. Plain205sentences, no bullets inside the block. It should read like someone naming the standard and refusing anything206under it.207208**Portability.** On any agent without `/loop` and `ultracode`, swap the last two lines for: "Keep looping209until the critic picks ours. Run the builders and critics as parallel subagents." The structure carries over210unchanged.211212## Rationalizations213214Stop signals disguised as good reasons:215216- *"'Award-winning SaaS sites' is close enough to a bar."* → It is the most common way a gauntlet loop fails.217 A category cannot be fetched, so the critic invents the comparison and approves everything.218- *"I will describe the reference to the critic instead of fetching it."* → The same failure one step later.219 The critic judges the artifact, or it judges its own imagination.220- *"The builder can grade its own piece — it knows it best."* → Knowing how hard it tried is exactly what221 disqualifies it. The critic is a separate agent with fresh context.222- *"A score out of ten shows progress better than a pick."* → Scores drift upward every round; that drift is223 the thing bars exist to replace. A binary pick, or nothing.224- *"Three rounds is plenty, I will call it done."* → The exit is winning the comparison, or the human stopping225 the run. A round count is another skill's bound and it stays there.226- *"An easier bar would let us finish."* → A bar set low enough to clear proves nothing. Raise the work, not227 the floor.228- *"I will specify the layout and the stack so the builder does not wander."* → Every extra instruction is one229 fewer decision made with the agent's own judgement, after it has seen the bar.230- *"They said yes to the last bar, so this one is covered."* → The yes was about a named thing. A new URL, a231 new package, or a move from downloading to executing is a new ask. Treating one yes as standing permission232 is how a consent step decays into a formality.233- *"This piece came out well — I will move it into `src/`."* → Nothing leaves `.gauntlet/`. One critic's blind234 pick is not a signed contract, a code-cold review, or a Verify pass, and code nobody else has to maintain is235 held to a different standard than code they do.236- *"The tree has unrelated changes in it, so I will stash them to get a clean check."* → Never. Those changes237 are somebody's work in progress and none of this run's business. The check is over the files this run wrote,238 not over the whole tree.239240## Red flags241242Stop and fix before continuing if any are true:243244- The bar is a category, a style, or an adjective rather than one named artifact.245- The reference was never obtained, so the critic is comparing against a description.246- One agent both built and judged a piece, or the critic saw the builder's reasoning or its effort.247- The pair reached the critic under names, paths, an order, or conditions that said which one was ours.248- A judgement came back as a score, a percentage, or a rubric instead of a pick plus one gap.249- An exit was taken on a round count rather than on the critic's pick.250- A clone, an install, or an execution happened before the human saw what was being fetched; or one yes was251 stretched to cover a second bar, or a yes to downloading was read as a yes to running; or credentials,252 environment secrets, or repository contents beyond the piece under comparison reached the fetched bar, or a253 build that asked to authenticate got a credential instead of a stop.254- A write happened while `.gauntlet/` was not in the target repository's `.gitignore`, or the line was added255 without asking, or any file landed outside `.gauntlet/<slug>/`.256- The `.gitignore` line was treated as though it confined what the fetched bar could run, read, or reach.257- The prompt carries headings, or specifies architecture, stack, or decomposition the human never asked for.258- A piece is big enough to need two judgements.259260## Verification (ending criteria)261262**Prompt mode** is done when one paste-ready block exists — short, no headings inside it, the bar baked in as263a named fetchable thing, the gauntlet named in its first line, and both the scratch-directory requirement264and the ask-before-you-fetch requirement carried inside the block, because the session that runs it is the265one that does the fetching and a gate left behind in this file gates nothing there — and the offer to run it266sits under the block on one flat line. A turn that offered candidate bars and stopped is not an unfinished267prompt mode; it is step 2 ending correctly, and the block comes after the pick.268269**Run mode** is done when ALL hold:270271- Every piece's final critic picked ours, blind — or the human stopped the run, and the report says that272 rather than claiming a win.273- Every bar was named on screen — the URL, the package, the repository — and agreed to before it was cloned,274 installed, or run, with a fresh yes for each one. No credential, no environment secret, and no repository275 content beyond the piece under comparison was handed to it. A run the human declined stopped there and276 said so.277- The bar was obtained as an artifact and sat beside ours for every judgement.278- Each piece had a builder and a separate code-cold critic; no agent judged what it built.279- Each pair went out under neutral names in a random order, produced under the same conditions. Where the280 reference was recognizable on sight, the report says so.281- Every judgement was a pick plus the single biggest remaining gap; no critic returned a score in place of a282 pick.283- No exit was taken on a round count, and any piece that stalled was named to the human.284- `.gauntlet/` was in the target repository's `.gitignore` before the first write — already there, or added285 after the human said yes. `git status --short` lists nothing this run created, and at most that one-line286 `.gitignore` change. Everything else already in the tree stays exactly as it was.287- The report says where the POC lives and what the last critic said for each piece.288289## Outputs & handoff contract290291- **Emits:** in prompt mode, one paste-ready prompt block, in-conversation. In run mode, the proof of concept292 itself under `.gauntlet/<slug>/` — the fetched bar, the per-piece work, the live progress page, the output —293 plus an in-conversation report of where it lives and what the last critic said.294- **Writes nowhere else.** Not `src/`, not `docs/features/<slug>/`, not `STATE.md`, not `CONTEXT.md` — the one295 exception is the `.gauntlet/` line in `.gitignore`, added with the human's yes before the first write where296 the repository lacks it. A finished run leaves the tracked tree otherwise untouched.297- **Reads no upstream artifact.** It holds no place in the chain `intent.md → research.md → prd.md →298 acceptance.md → environment.md → architecture.md → plan.md → qa.md`, and nothing downstream consumes it.299- **Next action:** the human's. The run reports and stops.300- **Standalone:** no lifecycle gates, nothing blocks, `/orchestrate` untouched.