SKILL.md
build-loop
Drive an explicit, verifiable goal to completion, one criterion per iteration, with external verification and hard budgets. The loop never decides what done means: goal-capture did that. The loop only implements, verifies, and halts honestly.
Preconditions
.lovable/goal.jsonexists and matches the schema in the goal-capture skill (see its references/goal-schema.md). If missing, run goal-capture first. Never infer the goal.- Every criterion has a
roadmap_idpointing at an existing roadmap item. - The user explicitly asked the loop to run. Never auto-trigger.
Step 0: Preview and confirm (mandatory)
Never enter the loop cold. Read .lovable/goal.json and print a compact summary: the one-sentence goal, numbered criteria (id, description, verify clause, current passes, attempts used), non-goals, guardrails (do_not_touch, ask_before), and budget (max_iterations, max_attempts_per_criterion, ask_on_ambiguity).
Then ask one confirmation question with three options: Start loop, Edit goal (hand back to goal-capture, then re-preview), Cancel (halt, zero iterations). Do not iterate until the user picks Start loop. Re-run this step any time the goal changes mid-loop.
The loop
read .lovable/goal.json
loop:
if every criterion passes === true: STOP, declare done
if iteration_count >= budget.max_iterations: HALT, summarize remaining, ask user
pick next = lowest-priority-number criterion where passes === false
if next.attempts >= budget.max_attempts_per_criterion: HALT, surface failure, ask user
set roadmap[next.roadmap_id].status = in_progress
smoke-test current build (catch regressions before blaming this iteration)
implement ONE criterion (small, reversible edits)
verify END-TO-END against next.verify, as written
if pass:
set passes = true in goal.json
set roadmap status = done
write iteration log
else:
increment next.attempts
write one-line reflexion to next.last_failure (what failed + what to try next)
if attempts >= max: HALT, ask user
loopHard rules
- Verification is external to the implementer's claim. Run the
verifyclause exactly as written. "I checked, it works" is not acceptance. - One criterion per iteration. Never batch. Iterations are the unit of reflection.
- Roadmap mirrors goal.json in the same turn. Never let them drift.
- Reversibility. Small edits the user can undo between iterations. Never bundle unrelated changes.
- No acceptance-loosening. If a criterion fails, fix the code or halt. Never rewrite
verifyto be more permissive. Never delete tests. - Honor workspace gates. rls-security-gate, money-path-halt-go, supabase-schema-discipline, and any other active gate skills stay in force inside the loop.
- Reflexion before retry. Write
last_failurebefore retrying, it prevents oscillating between two wrong fixes. - The loop only writes `passes`, `attempts`, `last_failure`. Goal and criteria text belong to goal-capture.
Stop conditions
| Condition | Action |
|---|---|
| All criteria pass | STOP, announce, suggest publish |
| Iteration budget exhausted | HALT, ask whether to extend |
| One criterion failed max attempts | HALT, surface the failure trace |
| Destructive action needed (drop column, rotate secret, paid API) | HALT, ask user |
| Criterion meaning ambiguous | HALT, ask with concrete options |
| A workspace gate fires | HALT, defer to that skill |
| User picks Cancel at preview | STOP, zero iterations |
What to surface
Loop start: goal, criteria count, budget. Each iteration: one line (criterion, pass/fail, attempts left). Halt: which condition fired and what decision is needed. Completion: criteria with evidence, publish suggestion. Keep chatter tight, the loop's log is its own output.
Good vs bad
Bad: criterion "checkout completes" fails twice, so the loop edits verify from "end-to-end purchase succeeds" to "checkout page renders" and marks it passed.
Good: after the second failure, last_failure reads "webhook signature mismatch, try raw-body middleware next", attempt 3 fixes the middleware, the original verify clause passes end-to-end.
Verification
After any iteration marks a criterion passed, re-run its verify clause from a clean state (fresh page load or fresh session). Expect the same pass. If it fails clean, the pass was environmental: revert passes to false, increment attempts, log the reflexion.
Completion checklist
- [ ] Step 0 preview shown and user picked Start loop before iteration 1
- [ ] Every passed criterion verified by running its verify clause, not by claim
- [ ] goal.json and roadmap in sync at every transition
- [ ] No verify clause weakened, no test deleted, at any point
- [ ] Every failure has a last_failure reflexion line
- [ ] Halt reasons reported honestly with the pending decision
Any box unchecked: not done. Fix or say so.
Footguns
- Entering the loop without preview. The user discovers a wrong goal 8 iterations in. Fix: Step 0 is unskippable.
- Batching two criteria "because they're related". A joint failure is undebuggable. Fix: one per iteration, always.
- Retrying without reflexion. The loop ping-pongs between the same two wrong fixes. Fix: write last_failure first.
- Counting a smoke-test regression against the current criterion. Fix: smoke-test before implementing, so regressions are attributed to the past.
Red flags
Halt if you catch yourself saying:
- "The verify clause is stricter than it needs to be"
- "This basically passes"
- "I'll mark it done and circle back"
- "These two criteria are really one change"
- "The user probably meant something looser"
Every one of these is acceptance-loosening in disguise. The clause runs as written or the loop halts and asks.