Agent Skills: create-gather-build-verify-prompts

Explicit workflow for creating or regenerating the gather-build-verify build-loop prompts under project/loops. Use only when the user explicitly invokes this skill or clearly asks to create or regenerate the gather/build/verify loop prompts.

UncategorizedID: mgreenly/ikigai/create-gather-build-verify-prompts

Install this agent skill to your local

pnpm dlx add-skill https://github.com/mgreenly/ikigai/tree/HEAD/.agents/skills/create-gather-build-verify-prompts

Skill Files

Browse the full folder contents for create-gather-build-verify-prompts.

Download Skill

Loading file tree…

.agents/skills/create-gather-build-verify-prompts/SKILL.md

Skill Metadata

Name
create-gather-build-verify-prompts
Description
Explicit workflow for creating or regenerating the gather-build-verify build-loop prompts under project/loops. Use only when the user explicitly invokes this skill or clearly asks to create or regenerate the gather/build/verify loop prompts.

First use the project-local $ikispec skill (the project/ artifact contracts), then proceed.

Create the three-prompt build loop an unattended harness (ralph) re-invokes with a fresh context every turn to build the project one phase at a time: project/loops/gather.md, project/loops/build.md, and project/loops/verify.md. These three prompts share the ephemeral project/loops/brief.md seam. This workflow also writes project/loops/run — the executable operator wrapper — and project/loops/README.md — the author-facing overview of the installed loop (see the last section).

Assume the project/ structure already exists, in the shapes ikispec defines: the product doc, optional research, the split, addressable design (spine + INDEX.md manifest + one self-contained DNN.md per Decision, each ending in minted R-XXXX-XXXX Verification ids), and the split, addressable plan (static rules + the STATUS.md manifest — the only home of the / markers — + one phase-NN.md body per phase). This workflow only writes the loop files under project/loops/; it does not build anything and never edits the spec.

The loop's shape (what you are emitting)

A gather → build → verify sequence driven by project/loops/run, whose contents are exactly:

#!/bin/bash

exec ralph project/loops/gather.md project/loops/build.md project/loops/verify.md

The wrapper must be executable. It hands ralph the three prompt paths, and ralph runs from the service root (its working directory), so every workspace path the prompts reference is service-root-relative (project/…). The loop cycles on a two-terminal-status contract — the final message of each turn is either NEXT (advance to the next prompt, wrapping verify → gather) or DONE (stop). CONTINUE never terminates a turn or drives the loop; it is the non-terminal status a streaming model (e.g. gpt-5.5 under codex, which coerces every streamed message into the schema) tags the progress messages it emits before its terminal message, so ralph — which reads only the last message — advances on the terminal NEXT/DONE alone.

  • gather — the only prompt that reads the big docs. Greps STATUS.md for the first phase; if none, returns DONE (the sole end of the loop). Otherwise, if a brief for that same phase already exists it is left untouched (the phase is mid-flight — its contract and any verify feedback are preserved) and gather returns NEXT without opening a big doc; only when no brief exists, or the existing brief is for a different (already-done) phase, does gather read that one phase-NN.md, resolve its Decision(s) via INDEX.md, read only those DNN.md, and write a fresh project/loops/brief.md — a self-contained contract (phase id; the full design prose of each realized Decision — its Decision statement, shape/signatures, and rejected alternatives — copied verbatim from its DNN.md but excluding that Decision's Verification list; the ids to coveronly the ids the phase lists, each with its full requirement text copied verbatim from the Decision's Verification list, and never the phase's-out-of-scope ids from the same Decision; files to touch; dependency interface signatures; done bar) with an empty feedback region. Returns NEXT. Writes nothing else; commits nothing.
  • build — reads only project/loops/brief.md, never the big docs. Reads the whole brief including any verify feedback region; if that region lists open gaps it addresses those first. Does a bounded, idempotent turn of the brief's remaining work — as much as cleanly fits one fresh context, ideally the whole phase (build package, write id-tagged tests, run suite, gofmt) — commits the code, leaves the marker , does not touch the brief. Always returns NEXT.
  • verify — the independent gate and only prompt that flips a marker or deletes the brief. Reads the brief (including its own prior feedback) + runs the suite + checks coverage, re-deriving current truth independently (it never trusts build's claims or its own past feedback as input). Pass → flip that phase's ⬜→✅ in STATUS.md, commit, and delete the brief. Gap → leave untouched, change no source, and overwrite the brief's feedback region with only the currently-open gaps (each tied to its R-id and grounded in the exact command/output that fails) — the brief is not deleted, so the next build sees the feedback. Always return NEXT.

Why this is human-free and converges: verify can neither halt nor advance a phase on a gap, so an incomplete phase just stays and the loop re-attacks it next cycle — now with verify's grounded feedback in front of build, and without gather re-reading the big docs each cycle (it no-ops on the in-flight brief). The persisted feedback also gives verify cross-cycle memory: it can tell slow convergence (the open-gap id set shrinking/changing) from a true stall (the same gap ids unsatisfied for ≥3 consecutive attempts with no new build commit). On a true stall it does a trajectory reset — discards the accumulated brief (delete it, leave , log the stall) so the next gather rebuilds the contract fresh from spec; this stays inside the "verify never halts / never advances on a gap" invariant. The only exit is still gather → DONE, which requires zero markers — so the run ends only when every phase is verified green (or a ralph budget rail trips).

How to work

  1. Read the design spine project/design/README.md and project/design/INDEX.md (pull individual project/design/DNN.md files as needed), plus project/plan/README.md and project/plan/STATUS.md (and project/product/README.md for intent; a phase body or two from project/plan/ for a concrete example). The design spine is the single source of truth for the toolchain — make no assumptions; take the commands from design's Conventions section. Extract the concrete specifics the loop bakes in:
    • the build/typecheck command, the test command, and what "the suite is green" concretely means (all from design's Conventions);
    • the source/test layout and any architectural seams the design mandates (e.g. pure-core / impure-shell, determinism seams) — including the test-placement rule: where unit tests live relative to the code they exercise (package-local, named for the behavior) and the single home for cross-package integration tests, so the generated prompts forbid per-phase/root-level test files;
    • the status marker tokens for not-started vs. done (/ in project/plan/STATUS.md) and the next-phase lookup: grep -nE '^- Phase .* ⬜' project/plan/STATUS.md | head -1 (phase lines are Markdown bullets prefixed with - );
    • the id resolution path: a Decision → its DNN.md via project/design/INDEX.md; an individual id via grep -n R-XXXX-XXXX project/design/INDEX.md.
  2. Define the coverage convention and the "done" bar yourself — design mints the R- ids but deliberately does not own how coverage is measured. Use a greppable default: a Verification id counts as covered only when named in a // R-XXXX-XXXX comment in a test file that genuinely asserts the behavior (never a bare literal) and that test actually runs under the suite's real invocation; a phase is done when every id it owns is so covered and the suite is green. Reachability is part of "covered": a tagged test held out of the run by an env flag, build tag, or skip condition that nothing in the repo sets or satisfies is unreachable and counts as uncovered, no matter how genuine its assertion reads; likewise a test that converts a real failure signal (non-zero exit, unparseable output) into a skip launders a gap into green and counts as uncovered. A skip is never acceptable green for a requirement test — it means that requirement was not verified. A structural phase carries no ids and is proven by the green build plus any integration smoke it names. Carry design's test-placement rule into the convention too — design owns where tests live (its testing strategy / seam model) and the plan defines a phase as one package, so the convention must say tests are co-located with the code they exercise and named for the behavior, never gathered into a per-phase or root-level test file. State the concrete placement (the package-local *_test.go path for unit tests, and the single designated home for the few cross-package integration tests) extracted from design, and require both gather (in the brief's done bar) and build (in its procedure and conventions) to enforce it.
  3. Every exit condition the loop checks must be deterministic — a mechanically-evaluable pass/fail predicate that is reproducible on identical repo state and whose passing state is actually reachable (a green test/suite, a command's exit code, an exact match count). Before writing verify.md, confirm each phase's done bar reduces to such conditions. A bar that rests on a subjective judgment ("states the truth", "documents adequately", "reads clearly") or on an unsatisfiable / self-referential check — classically a grep for a phrase that the phase's own project/ planning/prompt docs also contain, so it can never return empty — is not deterministic and will make the loop spin forever (verify never goes green, the phase stays , gather re-attacks it every cycle). If the design genuinely does not state how to build or test clearly enough to write concrete commands, or any phase's exit conditions cannot be made deterministic, terminate: do not emit the loop, and surface the specific phase + condition that must be fixed upstream (in the plan/design) rather than guessing or baking in a gate that can never converge. Only when every phase's bar is deterministic do you write the three files in one shot.
  4. Write project/loops/gather.md, project/loops/build.md, and project/loops/verify.md in the shapes below (substitute the real commands/conventions extracted from design — no placeholders), write project/loops/run exactly as shown in "The loop's shape" and make it executable, write project/loops/README.md (the last section), and report the paths.

The project/loops/brief.md contract (gather emits it)

The brief is the seam that keeps build's context scoped to one phase — the complete and only input build and verify consume, so neither opens design or plan. It is self-contained: it carries the realized Decision's full design prose and the full requirement text of the phase's ids, so build never needs to read a big doc to know what to build or why. It is never committed (add project/loops/brief.md to .gitignore), single-phase (it only ever describes one phase at a time), and phase-scoped, not per-cycle: it is created by gather when a phase first becomes the active phase, persists across cycles while that phase stays , and is deleted by verify only when the phase passes (or on a stall reset). It is region-owned by a single writer each, so the two writers never clobber each other:

  • a gather-owned contract region — the phase identity, the full design prose of each realized Decision (Verification list excluded), the ids to cover with the full requirement text of only the phase-listed ids, files to touch, dependency interface signatures, and done bar. Written once when the phase becomes active; verify never writes here.
  • a verify-owned feedback regionverify's currently-open gaps. gather never writes here; on its no-op for the in-flight phase it leaves this region untouched.

Give it a strict, grep-able schema. The contract region carries, at minimum: the phase id + one-line objective; the realized Decision id(s); the Decision file paths; the full design prose of each realized Decision — its Decision statement, shape/signatures, and rejected alternatives copied verbatim from the DNN.md, but with that Decision's Verification list omitted (build must not see the ids the phase does not own); the ids to coveronly the ids the phase's body/Done when lists, one id per line, each line in the exact form R-XXXX-XXXX — <full requirement text copied verbatim from the Decision's Verification list> (the id at line-start, an em-dash, then that id's complete requirement prose on the same line — never a bare id with no text, and never the text on a separate line). This format stays grep-able for the denominator: grep -oE '^R-[A-Z0-9]{4}-[A-Z0-9]{4}' project/loops/brief.md extracts just the matched id substring per line (via -o) and ignores the trailing text, so it still yields exactly this phase's id set and never miscounts an id quoted inside prose elsewhere in the file. Use an explicit "(none — structural phase)" line when the phase owns no ids.; the files to touch; the dependency interface signatures copied in (so build never opens a design file); and the done bar. The feedback region is a single ## Verify feedback — attempt N heading carrying a per-attempt counter, the build commit verify observed, a stall-streak counter, and a checklist of only the open gaps — each line tied to one R-id and grounded in the exact failing command/output (never free prose), so build gets a localized, mechanically-satisfiable target. gather writes this region empty when it authors a fresh brief; verify overwrites it (never blindly appends — an append duplicates on a re-run and stacks stale gaps) with the open gaps each gap cycle, and build reads but never writes it.

Output shape of the prompt files

Each prompt is self-contained (read in a fresh, isolated context — it cannot rely on the other prompts being read) and autonomous (one iteration per invocation, no internal loop, all state in the workspace, default to progress over questions). Each ends with a short "Reporting the result" section that binds the turn to the loop's status/message contract at the semantic layerwhich status to report and what the message says — and never prescribes a transport.

Frontmatter is entirely an operator option — never add any. This workflow never writes a frontmatter block of its own, on any prompt, for any reason; which keys a prompt carries (harness:/model: backend routing, max-retries:, anything else ralph accepts) is the operator's choice alone. The workflow's only frontmatter duty is preservation: if a prompt being replaced carries a frontmatter block, copy it over verbatim into the regenerated prompt — regeneration must never strip or alter the operator's keys.

Do not tell the model to emit a literal JSON object in its reply, to call a named tool, or to set "structured-output fields." The harness supplies the {status, message} schema out of band and reads it back itself — ralph injects it per backend (codex via --output-schema, writing the final message to -o; claude via --json-schema, surfaced to the model as a synthetic StructuredOutput tool) — so a prompt that hard-codes one transport is wrong on the other harness. Describe only the contract, generically, and have every prompt present all three status values so the model always has the right one to hand. This matters because codex coerces every streamed message into the schema: a model that narrates progress mid-turn tags each message with a status, so it needs a non-terminal value (CONTINUE) for those and a terminal value (NEXT/DONE) for the last — ralph reads only the terminal (last) message and advances on that. Write each prompt's closing section in this shape, listing all three statuses:

Reporting the result

Report this run's result as a status and a one-sentence message:

  • CONTINUEnon-terminal: any progress message you stream before the turn's final message. You are still working; this never advances the loop.
  • NEXTterminal: this turn's work is done; hand off to the next prompt.
  • DONEterminal: the whole job is complete; the loop stops. (this form of the line is for gather.md only — see below for the build/verify form)
  • message — one short, plain sentence describing what happened, e.g. <example>.

<the prompt's own terminal rule — see below>. Keep message a single plain sentence — not a JSON object or code block.

In build.md and verify.md, do not use the DONE line above; write their DONE line verbatim as:

  • DONEterminal — never yours to report: ending the run is never yours — finishing this phase completely, green suite and all open gaps closed, is still NEXT; only gather, finding no phase left, ever reports DONE.

The terminal rule per prompt: gather ends the turn on DONE when the step-1 grep finds no phase, otherwise NEXT. build and verify always end on NEXT — their reporting sections must carry the verbatim build/verify DONE line given above, copied exactly, never paraphrased or trimmed. This wording is load-bearing: the observed failure mode is a build model that closes the phase's last gap with a green suite and reaches for DONE because "the work feels finished" — the annotation must preempt exactly that inference. CONTINUE is available to every prompt as the non-terminal progress status but is never a turn's terminal value.

project/loops/gather.md

  • Framing — the only prompt that reads the big docs; owns the brief's contract region for exactly one phase; writes no code, runs no tests, commits nothing. It preserves an in-flight brief rather than regenerating it every cycle.
  • Procedure — grep STATUS.md for the first phase → if none, return DONE (the only end of the loop). Otherwise check for an existing project/loops/brief.md and read its # Brief — Phase NN header: if it names this same phase, the phase is mid-flight — leave the brief exactly as is (contract and verify feedback regions untouched), open no big doc, and return NEXT. Only when there is no brief, or the existing brief is for a different (now-) phase, author a fresh brief: read only that phase-NN.md, resolve its Decision(s) via INDEX.md and read only those DNN.md, determine the ids to cover (only the ids the phase's body/Done when lists — a slice of a Decision's Verification ids, never all of them), copy the full design prose of each realized Decision (its Decision statement, shape/signatures, and rejected alternatives) verbatim minus that Decision's Verification list, copy each covered id's full requirement text verbatim from the Decision's Verification list (and no out-of-scope ids), extract the dependency packages' public interface signatures, and write project/loops/brief.md to the schema with an empty feedback region. Return NEXT.
  • Boundaries — read only the one phase file + the realized Decision file(s) + dependency interfaces; never build/test/commit; never write the feedback region or touch an in-flight brief; the contract region of a fresh brief is the only output.

project/loops/build.md

  • Framing — reads only project/loops/brief.md, never the big docs; does a bounded, idempotent turn of the remaining work and commits it; does not decide completeness and does not flip markers.
  • Procedure — read the whole brief, contract region and feedback region both (if the brief is missing/empty, make no changes and return NEXT); if the ## Verify feedback region lists open gaps, treat those as this turn's priority — they are the exact, command-grounded items the independent gate found unsatisfied last cycle, so close them first. Do as much of the brief as cleanly fits this turn — ideally complete the whole phase so verify can pass it next cycle — preferring fewer, fuller turns over many thin increments (an incomplete phase is just re-attacked next cycle). See what already exists (grep -rn "R-XXXX-XXXX" --include=*_test.go; run the suite to read failures); build the named package(s) consuming dependencies only through the brief's copied interface signatures; write id-tagged asserting tests co-located with the code they exercise and named for the behavior, never in a per-phase or root-level test file; gofmt; commit this turn's increment (no empty commit) with a phase-naming message and the repo trailer. Always return NEXT.
  • Project conventions — inline the real toolchain, "suite is green" definition, test styles, determinism seams, and the test-placement rule (co-locate tests with the code they exercise, named for the behavior; the designated home for cross-package integration tests; never a per-phase or root-level test file) from design.
  • Boundaries — never read design/plan/product; never edit STATUS.md or flip a marker; never delete/edit the brief (including its feedback region — build reads it but never writes it); always return NEXT (build hands off every turn; it is never the step that ends the run).

project/loops/verify.md

  • Framing — the independent gate; the only prompt that flips a marker or deletes the brief; never halts and never advances a phase on a gap; writes no production code. It re-derives current truth from scratch every run — it never trusts build's claims or its own prior feedback as input; its prior feedback is read only to measure progress, not believed.
  • Procedure — read the brief, contract region and its own prior ## Verify feedback region both (if the brief is missing/empty, return NEXT); every coverage check below is a deterministic command with a defined pass criterion (a green test/suite, an exit code, an exact match count), and any grep-style check is scoped to exclude project/ so it can never match the workspace/prompt docs that quote the pattern (a self-referential check that can never reach its passing state is the classic infinite-loop bug — and by construction such a bar never reaches verify, because the author terminated at write time per How to work step 3); run the full suite (all green checks) and confirm no R-XXXX-XXXX-tagged test reported SKIP (a skipped requirement test is a gap); for every id in the brief confirm a genuinely-asserting // R-XXXX-XXXX tagged test that actually runs under the suite's real invocation — statically trace the run (the test command plus every skip/build-tag/env gate guarding that test) and treat a test gated behind a flag nothing in the repo sets, or one that turns a real failure into a skip, as uncovered (structural phase → green + named smoke instead). Collect the set of open gaps (each an uncovered/failing id with the exact command + observed output that proves it open).
    • Pass (no open gaps) → flip only this phase's ⬜→✅ in STATUS.md, commit the one-line flip with the trailer, and rm -f project/loops/brief.md. Return NEXT.
    • Gap → leave , change no source. Measure progress against the prior feedback region: read its attempt counter N, its recorded build commit, and its prior open-gap id set. Capture the current build commit (git rev-parse HEAD). No progress this cycle means the current open-gap id set is a subset of the prior one and the build commit is unchanged (build committed nothing new); increment the stall streak when there is no progress, else reset it to 0.
      • Stall reset — when the streak reaches 3 (the same gaps unsatisfied across three consecutive no-progress attempts): the accumulated brief is not converging, so discard it — append one line to ~/.ralph/verify.log (<date> Phase NN STALLED after N attempts: <gap ids>), then rm -f project/loops/brief.md, leave the marker , and return NEXT. The next gather rebuilds the contract fresh from spec. (This never halts the loop and never advances the phase — it only resets a stuck trajectory; the ralph budget rails remain the sole hard stop.)
      • Otherwiseoverwrite (never append) the ## Verify feedback — attempt N region with attempt N+1, the captured build commit, the stall streak, and a checklist of only the current open gaps, each line R-id + the exact failing command + observed output (+ file:line when known). Do not delete the brief. Return NEXT.
  • Boundaries — never write/fix production code; never write the contract region; never flip on anything short of green + full coverage; never read the big docs to re-derive the checklist (the brief is the checklist); when uncertain a test really asserts, treat the id as uncovered; treat a skipped or statically-unreachable id test as uncovered — a skip is never acceptable green; always return NEXT (verify hands off every turn, on a pass and on a gap; it is never the step that ends the run).

project/loops/README.md — the installed loop's overview (this workflow writes it)

Alongside the three prompts and executable project/loops/run wrapper, write project/loops/README.md: the human/author-facing overview of the loop as installed, kept beside the prompts it describes so it can never describe a different loop than the one on disk. It carries: the project/loops/run invocation and the exact ralph project/loops/gather.md project/loops/build.md project/loops/verify.md command it wraps; the status contract (terminal NEXT/DONE — only gather → DONE, build and verify always NEXT — plus CONTINUE as the non-terminal status a streaming model tags its mid-turn progress messages with); the per-step reads/writes/commits/flips table; the brief lifecycle (gather authors the contract once per phase and no-ops while it's in flight; build consumes it; verify passes→delete or gaps→write feedback, persisting across cycles until pass or stall reset); why the loop converges; and the full project/loops/brief.md schema (contract region + verify-feedback region). project/README.md (the workspace map, owned elsewhere) only points here — never restate the spec shapes in this overview, and never write loop mechanics anywhere but here. Ensure project/loops/brief.md is listed in .gitignore.