The loop
Getting started takes you from nothing installed to one page carried through the design loop once. This chapter is what changes the second time, and why: you already know the shape of decide, spec, mockup, make and critique from running each once. Here you learn each one in depth: what it asks, why, what stops it, and what to do about it. You also learn tweak, which Getting started never needed, and the gate, which held your agent at the end of every step in Getting started without this chapter yet saying what it is. Finish this chapter and you can run the loop on any page in your own project without asking for help again.
Nothing here forks by path. Getting started’s 2 paths, a new project or one already in use, differ up through Set the project up and Check where you stand; past that point the loop is the same regardless of how you arrived. So this chapter carries forward only the Agent switch: only it governs whether a step below is shown as a command your agent recognises by name or in plain language, and it is the choice you already made, wherever you last made it.
Before you start
This chapter assumes Getting started is already done on this project: init has run and DECISIONS.md has been written with substance, beside the token layer. init sets a project up once, and the loop below starts only after it: decide’s own procedure says as much, “init comes first, because this file sits beside the token files init writes.” If either has not happened yet, that is not this chapter: go to Getting started first, and come back once it is.
The agent you chose in Getting started is already selected here, and changing it here changes it on every chapter too.
Agent:Claude CodeCodexCursoropencodeGemini CLIAny other agent
decide, in full
You ran decide once already, in Getting started, to get a project’s worth of decisions written down. This section is where you learn what it actually asked and why, since the next time you reach for decide is the day a decision needs to change, not the day the project starts.
Product-wide, not per-screen. Everything decide asks holds on every screen; what one screen contains, who arrives at it, what it defers, is spec’s question, asked once per page rather than once per project. The test for which is which: could this be derived from a token, the project’s mode, or one of Jig’s own numbered rules? If yes, it is already written down somewhere better than a paragraph here would be.
The rounds, in order, and why each exists. Round 1 asks what the product is and who it is for, in real comparisons rather than adjectives: closer to one named product than another, never “bold” or “premium” on its own. Round 1b asks 2 questions that set the direction every later argument is settled against: the north star (if this product works, what can someone do that they could not before, in one sentence, checkable against a design) and the tiebreaker (when two good options conflict, which side wins: fast over complete, plain over clever, whatever the team actually holds to). Round 1c asks about the product’s personality through the 4 things that produce it, one question each: type, colour, corners and language, each becoming a token or a voice rule, not a mood board. Round 2 asks where the brand colour is and is not allowed, and what earns emphasis. Round 3 asks what the team has already argued about or reversed, the decision most worth writing down, because it is the one most likely to be re-made wrongly, and, by name, whether anything is still undecided.
All 3 main rounds run, every time, not stopped early because round 2’s answers already look complete: round 3 is where a decision with a history, and an open item nobody would have volunteered unprompted, actually surface.
How a decision is written. A name you can cite in review, the decision itself in the project’s own words, and a **Why:** that quotes you directly, in quotation marks, exactly as said, or reads not given if none was offered. Never an invented reason: a reason recorded as yours that was not is worse than no reason, because it is weighed as settled when it never was. What the agent works out from your reason, or carries over from something you said elsewhere, goes in its own paragraph, **Why (inferred):**, marked as the agent’s own reading rather than yours. The north star and the tiebreaker are written the same way, as decisions like any other, and judged against every page the same way too.
The Unresolved section. What you have not yet settled, named at the end of the file: what is undecided, between which options, and what it is waiting on. Not a placeholder, and it does not fail the gate: an honest “not decided yet” is real information. spec reads it, and when a page touches an item listed there, asks you about it directly rather than choosing on its own.
Changing a decision later. A small change to one decision, on a page already built, is tweak’s own first step (below): recorded in DECISIONS.md the way decide writes one, the owner’s words, dated, and what it changes. A change to the shape of several decisions at once runs decide again, whose finish accounts for every answer you gave and traces every Why back to something you said.
/jig decideAsk your agent, in your own words, to run Jig's decide step: the skill still loads, so plain words work.
spec, in depth
spec says exactly what is being built: its own smallest useful version, at every screen size. It refuses to guess where the record it needs is missing.
What it asks, and why in this order. Structure, never appearance: colour, type and density were settled at init and live in the token layer, so re-deciding them per screen would create a second place for values Jig exists to centralise in one. It asks in 3 rounds: what the page is for and who arrives, scoped down hard into a smallest useful version with everything else named in later:; its content and states across a realistic range, from nothing to a lot; and what is still unresolved about how you get there and where you go next. Each question carries its own example answer, so there is something to react to rather than decode. The phone composition is written first, and in full, because it is both the most common screen and the one most likely to be squeezed out of a desktop layout rather than designed on its own.
Its last question decides who critiques this page, and when. Round 3 ends by asking whether to critique it after each build, or leave it for ship. Skip the question only where you have already said, for this page or in asking for the spec; where a page sets up what later pages reuse, a header or a card, each is usually worth it, since a finding in it found late is fixed in every page built on it. Whatever you answer is written into the spec itself, as critique: each or critique: at-ship, and it wins over whatever the project defaults to.
Every movement gets a reason. motion: lists each one the page has, or none: what moves, what sets it off (something you did, a state change, or, on an editorial page, arrival or ambient motion), and what it tells you. One that cannot say what it tells you is cut before it is built. You are not asked this as a question; it is written from the composition and read back to you on the confirmation sheet, beside states:. make builds exactly the motion the list names and no other, and critique judges the page against it, and with no motion: line at all, the motion rules alone judge it.
Its own refuse conditions, and what to do about each:
- No token layer yet (
jig.config.jsonmissing). Runinitfirst. Without it there is no mode and nothing for a spec to be specific to. - No
DECISIONS.mdwith substance. Rundecidefirst. A spec implements a project’s decisions and cannot check itself against ones that are not written down. - Nothing named. Say which page, feature or functionality.
specwith no argument is not a request to invent one.
Describing a page that already exists, rather than designing one from nothing, is the same case you met once in Getting started if you came in on the existing-project path, generalised here to any page you revisit later: your agent reads what is there and writes the regions, hierarchy and navigation as built, asking you only what the page itself does not answer, then shows it back to confirm or correct. Not a redesign: a region arranged differently is still recorded as it stands, with any argument for changing it belonging to a critique instead. And not a rubber stamp either: a page that contradicts your project’s own decisions is described accurately, with the contradiction said plainly.
Checked before you are asked. Before spec asks you to confirm, a reader who did not write it checks the draft: each quotation it gives as yours against what you actually said, and each fact, how your product, an API, an existing page or a tool works, against the source it names. What that reader finds is a sheet, .jig/specs/<name>.checked.json, shown alongside the spec: your words and where you said them, each fact and its source, the copy the page will show as written, your conditions next to the lines that carry them, and what is left open for you to decide.
With the Stop hook, the spec is not put to you with a quotation you never said, a fact its reader found false, or a sheet of an earlier version of the spec. And if no second reader was available to check it, the confirmation says so plainly: nobody else checked it.
A second check, asked again after you request a change, covers only what changed, not the whole spec again. You get the earlier record alongside the spec’s own diff since it: a quotation or a fact on a line neither the spec nor its source has touched carries over as already checked, and only the changed lines, the new ones, and any fact whose source moved are opened again.
What to check before you say yes. The sheet makes it quick; it does not make it automatic. Read the spec itself for these, before you say yes:
- Your words are yours. Every quotation it gives as yours is something you said, and nothing reads as your ruling that you did not give. What the agent worked out for itself is labelled as its own.
- Every fact holds up at its source. Where the spec says how something works (your product, an API, an existing page, a tool you depend on), open the source and check. One habit of your project stated as a general rule is a fact nobody decided.
- Words the page will show are words you would ship. Headings, labels and any copy the spec writes out are built as written. Read them as the person arriving would. A sentence about how the page works (what a control costs to use, where a choice is stored) is a note for the builder, not copy.
- Conditions you gave are there, as you gave them. “Three columns from 1280 up” is written as 1280, not moved to a width that was easier to build.
- V1 is small, and later holds what you cut. Everything named in
later:stays there; nothing you set aside has come back in. - Every size says what you expect to see. The phone is written in full, first. Each same-as: gives a reason that is true, and nav: at every size is the navigation you would expect there.
- States cover what the page will meet. Empty, one, a lot, loading, failure: whichever the page can be in.
- Everything that moves has a reason. Each line of
motion:names what moves, what sets it off, and what it tells you. Cut any line that cannot say, and expect nothing on the page to move that the list leaves out. - Open questions were asked, not answered for you. A spec touching an item under Unresolved in
DECISIONS.mdcarries your answer, and a field readingunspecified: make chooses one it can defendis one you can decide now. - A page that exists is described as built. Its regions are the ones on the page today, and anywhere it contradicts your decisions is said plainly.
When something fails, say what is wrong. The spec is revised and shown to you again; nothing builds until you confirm it.
Handing the check to an agent. You can ask your agent to check a spec and confirm it on your behalf. It works from the same sheet and confirms only what it checked itself, opening every source marked unchecked, reading copy as the person arriving would, holding each condition to your own words, and names what it could not check rather than confirming it. An agent’s yes is still yours to stand behind.
/jig spec <page>Ask your agent to spec the page or feature, in your own words: the skill still loads, so plain words work.
mockup, and its 3 ways of drawing
mockup draws the confirmed spec at low fidelity: grayscale, structure only, no tokens, at every size it names, for you to look at before any code exists. It draws one spec’s own V1, never the whole product, and never anything left in later:.
The choice is yours, 3 ways, asked every time:
- 1.
HTML. Your agent draws it as a file, in the project’s own
.jig/mockups/, outside what ships and outside what check scans. Needs nothing connected. - 2.
Figma. Drawn on a Figma canvas, through Figma’s official Model Context Protocol (MCP) server: one frame per named size, grey fills and strokes only, no library styles from the project’s own design system.
- 3.
Google Stitch. Generated through Stitch’s own MCP server, connected with a Stitch API key, asked for a low-fidelity grayscale wireframe at each size, with the spec’s own regions and real labels. Asked again if what comes back looks finished rather than a wireframe.
If you choose Figma or Stitch and that tool’s server is not connected, your agent says so plainly and names how to connect it: Figma’s through its official MCP server, Stitch’s with a Stitch API key. Then it waits. It does not switch to HTML on your behalf. Only once you say it is connected does drawing begin.
Its own refuse conditions: no confirmed spec (run spec first); a spec that exists but is not yet confirmed (ask for confirmation, then stop); a request to mock up more than one page, or “the app,” or “the site” (mockup draws one specified surface, and your agent offers to spec it first).
A mockup is the confirmed spec, drawn: one page, at every size the spec names, in grey. So the first thing to check, before you approve it, is that it matches the spec. With the Stop hook, a drawing is held back from you until every region and each size’s navigation is labelled in its frame; what a label check cannot see is whether each is drawn the way the spec says, and that is yours to check.
You get the drawing with a sheet, size by size: the spec’s own line beside what the frame shows. Read it for these before you approve:
- Every size matches its line in the spec. The order of the regions, what comes first, what sits with what, where each one is. A region that is present but in the wrong place is not a match.
- The navigation at each size is what the spec’s
nav:says. - Nothing extra. No region the spec does not list, and nothing from
later:. - The spec’s states are drawn where one changes the layout: empty, error, a lot.
- What a drawing cannot show is named, from your spec. If your spec says a part stays in place on scroll, or opens and closes, the sheet names it so you approve that too. If your spec says nothing of the kind, there is nothing to name.
- Now that you see it, the spec is still what you want. If it is not, the spec changes first and the drawing is redrawn from it, so the two never disagree.
- A condition you attach is written into the spec, in your own words, before the approval is recorded.
makebuilds from the spec, not from the conversation. - You are not approving colour, type or exact spacing. Those come from the tokens; a grey drawing settles none of them.
Handing the check to an agent. You can ask your agent to check the drawing and approve it on your behalf. It renders every frame, compares each with its line in the spec, and approves only what it checked itself, naming to you what it could not.
Every change you make in review goes back into the spec first, then a redraw. Never the drawing alone, or it quietly becomes the real specification nothing else agrees with.
Your approval is recorded in your own words, mockup: approved, and with the Stop hook it cannot be recorded in words you did not say.
Skipping the mockup. A mockup is not required. Say so, to mockup, to make, or when you confirm the spec, and it is recorded as mockup: skipped, in your own words. make then builds from the spec alone, critique compares the page to the spec alone, and nothing waits on a drawing. What make will not do is decide for you: on a spec whose mockup nobody has approved or skipped, it asks which. With no drawing, the spec is all there is to build from, so the check before you confirm it carries all the weight.
/jig mockupAsk your agent for a mockup of the confirmed spec, and say how you want it drawn: the skill still loads, so plain words work.
make, in depth
make builds the real page from its confirmed spec and its approved drawing: the project’s real tokens, components and copy, matching the drawing’s structure at each size, without pasting its markup. It starts from the phone composition and adds what wider sizes change, never the reverse.
Its own refuse conditions: no confirmed spec (say so and run spec first, never write a quick one to satisfy the check in the same breath); confirmed: false (ask for confirmation and stop); mockup: pending (nobody has said whether to draw it. Unless you already said to skip it in asking for make, it asks once: draw it with mockup, or skip it? If you skip it, mockup: skipped is written into the spec, in your own words, and it builds from the spec alone). make never decides that for you, and it does not finish with the spec still pending: the gate holds a make session that does.
Recording what building revealed. A spec being slightly wrong once real building starts is normal; the failure is leaving it wrong silently. Every place the build had to depart from the spec is appended to deviations:, with what changed and why.
What “finished” requires, every run, not treated as optional: check passing, with every warning either fixed or waived by name and reason (no mechanical finding is ever “non-blocking”); the build matching the approved drawing region by region at every named size, or, where mockup: skipped, matched against the spec alone; and every field of the confirmed spec accounted for, size by size, not only at desktop.
/jig makeAsk your agent to make the page from the confirmed spec and approved drawing: the skill still loads, so plain words work.
critique, in depth
critique is not a second check. check reads files and decides what a machine can decide; critique also looks at the rendered page and reads the source against the judgment rules no detector can reach, which is most of the corpus. It is how the largest group of Jig’s own rules gets enforced by something other than the building agent’s memory.
Check still runs every time; critique can wait. check runs on every make and every tweak regardless: mechanical, seconds long, catching a hard-coded colour before it spreads. critique is the judgment half, and it can wait: a page judged once, as it stands, gets the verdicts it would have got straight after it was built. Critique a page after each build, after a batch of pages, or only before you ship. The one page worth judging early is one that sets up what later pages reuse, a header or a card: a finding in it found late is fixed in every page built on it.
The default it waits on is set once, when you set the project up. init asks when pages should be critiqued: after every build, left for ship, or decided page by page, the default, which writes nothing and leaves each page’s own spec to ask instead. A run with nobody there to answer, the same footing --yes and continuous integration (CI) put a project on, leaves that question unasked too, so the default stands until a page’s own spec says otherwise. And a page’s own spec always can: its last question (above) writes critique: each or critique: at-ship for that page alone, and that answer wins over whatever the project defaults to.
What comes back. Findings, ordered by severity and cited by rule id: never a summary to skim, since severity, not position, says which matter. Separately, the project’s own DECISIONS.md entries, each judged once against the built page: a page can satisfy every numbered rule and still contradict what the project itself chose, and this is the only place that gets checked.
It reads in both directions. The spec against the page is the familiar one: does what you confirmed actually render. The other direction matters just as much: any section, paragraph, control or claim the page carries that no line of the spec asks for is a finding too, however accurate it reads, because it is content you never confirmed. What no numbered rule names is filed under differences in the verdict files rather than invented as a rule id, and counts as a finding all the same.
Its own refuse conditions: no DECISIONS.md with substance (run decide first, since critique judges a page against a project’s decisions as well as its rules); nothing named (ask which page or feature); no spec file for the page at all, .jig/specs/<surface>.spec.md missing (continue rules-only, and say so plainly in the report, rather than writing a spec from the page after the fact and comparing it to itself).
What a finding means. Not a verdict to argue with on the spot. It is a report handed to make, which fixes each one and runs its own finish again; then critique runs once more. This repeats until the report carries no errors or warnings, or you have accepted, by name, in your own words, each one left standing. Moving on to the next page or feature with findings still open means the next one gets built on top of this one’s problems, and nobody returns for them.
Waiting is tracked, not forgotten. The verdict lock records the page each critique judged, so Jig knows every page that changed since, every tweak that left its re-judge for later, and every page never judged.
Shipping is where none of it is optional. ship runs check --all --ci and seo, and names every page that owes a critique: one with none, one that changed since its last, one whose tweak deferred its re-judge, one whose verdicts are not yet complete, or one carrying a finding you have not yet ruled on. A spec not yet confirmed is not held against it, and neither is one another spec has replaced: superseded_by: <spec> in its front matter leaves that page to the spec that replaced it, once ship has checked the named spec exists. Each is critiqued in full, by readers that have not seen this conversation, and every finding goes to you: fixed, or ruled on in your own words. It runs until jig ship says ready=yes. ship does not deploy anything, and it is not a security review: Jig has no rules for security, performance or what a real screen reader does, and its report says so on every run.
/jig critiqueAsk your agent to critique what was built: the skill still loads, so plain words work.
tweak, for a small change to a built page
A page that is already built, reviewed and drawn sometimes needs a small change its approved drawing does not show: a word, a colour or its contrast, a weight, spacing inside a region, how text wraps, a focus ring. tweak is one pass that does what the full loop would, without redoing the parts nothing moved: it decides, if the change is a decision; brings the spec’s own lines in line, if they now read wrong; builds the change; and re-judges only what the change could actually affect.
Its own refuse conditions, and what each means for you:
- No confirmed spec for the page, or its
mockup:still pending. This is a page being made, not one being changed; the route isspec,mockup, thenmake. - No critique record for the page yet: nothing has been judged, so there is nothing yet to re-judge; run
critiquefirst, unless you defer the re-judge (below), in which case the page’s first critique judges it whole. - The change adds, removes, reorders or regroups a region, changes the navigation at any size, or would make the approved drawing wrong. This is not a tweak. The route is
spec, thenmockup, thenmake, and the gate checks this regardless of what you decide: the page’s own regions must still match what they were at its last critique, and its drawing must be untouched since then. - What you want is unclear. Your agent asks one question, then stops, rather than guessing.
If the change is a decision, or changes one already recorded (a colour for a mark, how a number is written), it is recorded in DECISIONS.md the way decide writes one: your own words, dated, and what it changes. If the change only applies a rule, or answers a finding the rules already settle, there is nothing to decide, and none is invented.
And it covers the whole page, not only the instance that raised it. You rule on one case, this apostrophe, curly, and the decision states a kind, every apostrophe, curly. Before building, your agent looks through the page, and the chrome it shares, for every other instance of that same kind and brings each in line in the same change, naming them in its report.
If the spec now reads wrong, its lines are amended and a dated entry is added quoting you, with the regions and the drawing left exactly as they were. A tweak’s own instruction is the confirmation; it is not asked for twice.
What gets re-judged. Only the rules and decisions the change could actually move, named up front before anything is re-checked (a colour change names the contrast and emphasis rules it touches and the decision it applies, not the whole index), and re-judged by a reader who did not make the change, working from the page, the named ids and each rule’s own text alone. A finding that comes back from that re-judgment goes to you: fixed by another tweak, or by make if it needs more than one pass can carry.
The re-judge can wait. Where the page’s own spec already says critique: at-ship, or says nothing and the project’s own default does, it is recorded as deferred outright, no request needed: the ids the change could move stay named for whoever judges it, and the verdicts already on file are left alone. Anywhere else, it waits only when you say so, in your own words, and those words are what get recorded. Either way, the page then owes a critique, and ship will not pass until one has judged it. Your agent never defers this on its own account: the gate refuses a deferral you did not give.
/jig tweak <the change>Ask your agent to tweak the page, describing the small change in your own words: the skill still loads, so plain words work.
The gate
Every step above can be held at its own finish line by the Stop hook, if your agent has it installed (install --hook, Claude Code only, off unless asked). This section is not another step in the loop. It is what governs all 6.
What it is. One entry in Claude Code’s own settings, added once, running the CLI’s own gate command every time your agent tries to finish.
What it checks. Not only a check error or warning on a file your agent changed, and not only a critique’s or a tweak’s verdict files failing verdicts. Anything the /jig command you just ran left incomplete counts too: a spec that is prose, a critique with no verdict files, a review that never rendered the page. Only what this session actually touched: never a scan of the whole project, and never an older page’s older critique you are not currently working on.
Since 0.21.0, one more hold after a critique or a tweak. The gate writes a critique’s or a tweak’s verdicts to a lock file, .jig/critique/<surface>/verdicts.lock, whenever such a session stops, whatever it found, once you have committed. So once you have committed, the gate holds you once more, for exactly one more commit, to get the lock itself committed too. The next attempt to finish, once that commit exists, passes. It is not a second review of the same work; it is the record of the review you already did, arriving one commit after the work it records.
How many times it holds. Up to 3 refusals in one session. Each time, it hands back exactly what is still failing, for your agent to fix. After a 3rd refusal it lets your agent stop regardless. What that means is not “done”: your agent must say, plainly, that the work is unfinished and name what is still failing, not report it as done because the hook stopped objecting.
Waiving a warning. A warning you are sure is right as it stands, where the detector’s guess is wrong for this one case, is waived on its own line, in the file’s own comment syntax: jig-allow <ID>: <why>. The reason is required and is what a later reader of the file sees; every waiver is printed on every later check run, so a waiver list cannot grow quietly. An error cannot be waived this way. Waiving a warning that a real fix was available for is exactly the failure the gate exists to catch.
Without the hook: on the other 5 agents, or on Claude Code with --hook never asked for, nothing holds you at all. Nobody refuses to let you stop, and nothing here changes that: the hook is Claude Code’s alone, and install offers it rather than adding it unasked, on any agent. What the hook would have caught is still worth catching; it is only no longer automatic. Run it yourself, the same commands this chapter has already named, before calling a step finished: check --all for the mechanical half; critique for the judgment half; verdicts <surface> to confirm a critique’s or a tweak’s own verdict files actually hold up. Nothing else will catch what the hook otherwise would, so treat “the loop said this step is done” as true only once one of these has actually run.
When the gate asks for a page to be probed again, its verdicts taken on a render older than the page now is, the command that does it:
npx jig-ui@0.25.0 verdicts <surface> --reprobe