CtrlK
BlogDocsLog inGet started
Tessl Logo

spec-driven-development/spec-as-source

Spec-driven development on OpenSpec, with mechanical spec-as-source enforcement: a custom 'spec-as-source' OpenSpec schema adds file-ownership (targets) and test-verification ([@test]) metadata to every capability spec, three scripts (link check, ownership check, manifest build) keep code and specs from drifting apart, plus requirement-gathering, spec-writer, work-review, and a session-handoff skill with a proactive context-warning hook.

68

Quality

85%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

SKILL.mdskills/prompt-loop/

name:
prompt-loop
description:
Refines an incoming prompt through a bounded score → interview → lock → rewrite loop until it is mechanically good enough (rubric score ≥ 9/10) to feed the SDD workflow. Trigger — automatically before openspec-propose when the request is non-trivial development work; explicitly on: refine this prompt, prompt loop, score my prompt, is this prompt ready.

Prompt Loop

Turn "is this prompt ready?" into a mechanical check. The loop scores the incoming prompt against a fixed rubric (templates/SCORING_RUBRIC.md), interviews the user on the weakest dimensions, locks confirmed answers, rewrites the prompt, and re-scores — repeating until the score crosses the threshold — with every block of the coverage gate answered — or the round cap is hit. The output is a refined prompt of verified quality, confirmed by the user and handed as a file to prompt-engineer, which turns it into the input of openspec-propose or openspec-explore.

The loop is human-in-the-loop by nature: the user is present in every round. It never runs headless and it never produces downstream artifacts (proposal, spec, code) while refinement is still in progress.

Phase state machine

Each round moves through these phases in order. A phase is entered only when its entry condition holds and left only when its exit condition holds — no skipping except where a condition explicitly says so.

  1. Analyze
    • Entry: an incoming prompt exists (the user's request, quoted verbatim).
    • Work: read the prompt as-is; identify its objective, stated scope, constraints, and every slot that would require inventing a fact.
    • Exit: the prompt is understood well enough to score — no rewriting, no questions yet.
  2. Score
    • Entry: analyze is complete, or a rewrite from a previous round exists.
    • Work: score the current prompt revision against the five rubric dimensions in templates/SCORING_RUBRIC.md, quoting evidence for every score above 0, and total the result.
    • Exit: a total 0–10 exists and the rubric's decision tree maps it to the next action. Total ≥ 9 with the coverage gate closed exits the loop entirely (see Stop criterion); otherwise continue to interview.
  3. Interview
    • Entry: the last score is below 9, or a block of the coverage gate is still uncovered, and the round cap is not reached.
    • Work: ask the user questions derived from the lowest-scoring dimensions of this round, then from the uncovered blocks.
    • Exit: the open questions of this round are answered (or the user declines to answer, which is itself recorded — never filled in).
  4. Lock
    • Entry: the user answered an interview question or confirmed a summary line.
    • Work: record each confirmed decision so no later round can reopen it.
    • Exit: every answer from this round's interview is locked.
  5. Rewrite
    • Entry: this round's answers are locked.
    • Work: produce a new prompt revision that integrates the answers and carries every locked decision forward unchanged. Missing information is marked n/a or left as an open question — never invented.
    • Exit: a complete new revision exists.
  6. Re-score
    • Entry: a new revision exists.
    • Work: return to phase 2 (Score) with the new revision; this closes the round and increments the round counter.
    • Exit: same as Score.

Stop criterion (mechanical)

The loop stops on the first of these, never on a feeling of "good enough":

  • Threshold reached — a scoring round totals 9 or more out of 10 and the coverage gate is closed: exit refinement and produce the output contract. A high score alone is not enough — see the Coverage gate.
  • Round cap reached — the round count hits the maximum (default 5) with the total still below 9 or with blocks still uncovered: the loop MUST stop. On cap-out, report the residual gaps — which dimensions remain below 2 and why, and which uncovered blocks remain — and ask the user whether to proceed anyway with the best revision so far or abort. Never continue past the cap and never silently proceed as if the threshold had been met.

First-round pass

If the very first scoring of the incoming prompt totals 9 or more and the incoming prompt already answers every block of the coverage gate (each answer locked as the user's own words), skip the interview and rewrite phases entirely and go straight to the output contract. A prompt that is already good does not get five rounds of ceremony.

Coverage gate

The rubric measures how good the prompt's text is. The coverage gate measures something else: whether every block that prompt-engineer needs has been answered. prompt-engineer runs in a fresh-context subagent with no channel to the user, so whatever this loop does not ask is lost for good — it could only come back downstream as n/a, which is exactly the gap the engineering step exists to close. The questions have to happen here.

The gate covers eight blocks:

  1. Objective — the outcome the work must produce.
  2. Context and source priority — the environment, and which source wins when two disagree.
  3. Scope — in scope, out of scope, and what must not change.
  4. Tools policy — when to use which tool, and when not to.
  5. Action boundaries — what proceeds autonomously, what needs approval.
  6. Verification — how the result is checked.
  7. Output — what the final deliverable contains.
  8. Stop condition — the observable point at which the work ends.

A block is covered only when a lock entry holds either the user's answer for it or the user's explicit statement that the block does not apply. Track the gate in the session document as a table, block → lock id; a block without a lock id is uncovered. Never mark a block "does not apply" on the user's behalf: if it seems not to apply, ask — the user's "no tools here" is a lock, your guess is not.

The gate is independent of the rubric score. A round totalling 9 or 10 does not cover an uncovered block, and the rubric itself keeps its five dimensions: the gate is not a sixth one, so a high score can never mask a block nobody asked about.

Interview phase: the requirement-gathering discipline

The interview phase absorbs the discipline of the requirement-gathering skill. Its hard rules are restated here in full so this skill is self-sufficient even when installed alone; consult requirement-gathering for question craft, but the rules below are binding on their own:

  1. ONE question at a time. Ask exactly one question per message. Never bundle several questions together, never present a questionnaire.
  2. Wait for the answer. Do not ask the next question until the user has answered the current one. If the user declines to answer, record the decline — the slot stays open or becomes n/a; it is never filled in.
  3. No downstream artifacts before the loop completes. While refinement is in progress, never run openspec-propose, never write a spec, and never write code. The loop must reach its stop criterion — and the user must confirm the output contract — before any downstream step starts.

Deriving the questions

Questions come from the rubric, not from generic checklists. After each scoring round:

  • Sort the five dimensions by score, lowest first.
  • Formulate questions only for the dimensions that scored below 2, starting with the lowest-scoring one. The evidence lines recorded during scoring say exactly what is missing or ambiguous — turn those gaps into questions.
  • Then turn to the coverage gate: one question per uncovered block, in the gate's order. Each such question MUST quote what the prompt already says about the block, or state that it says nothing — the user answers faster when they see the gap.
  • Rubric gaps first, coverage gaps second: the weakest dimension's question comes before any coverage question, and the uncovered blocks follow one at a time.
  • Do not ask about dimensions already at 2, and never re-ask anything the user already answered (see the lock semantics).

Session document: the loop's state

The loop's state lives in a session document, not in conversation memory. At the start of a session, instantiate templates/PROMPT_SESSION.md and keep it current from then on — it is what makes locks enforceable and rounds auditable. The document is an artifact of the conversation (kept in the change-planning area or scratch space), not a repo deliverable.

Record every round in it as it happens:

  • the original prompt, quoted verbatim once at the top and never edited;
  • per round: the prompt revision (full text), the per-dimension scores with verbatim evidence quotes, and the open questions derived from the low-scoring dimensions;
  • earlier rounds are never rewritten or deleted — they are the audit trail.

Lock semantics

The ## Locked register in the session document is the loop's memory of what the user has decided. Its rules:

  1. Locks are verbatim. When the user answers an interview question or confirms a summary line, record the exact answer or approved line under ## Locked — not a paraphrase.
  2. Locks are carried forward unchanged. Every rewrite MUST reproduce every locked decision in the new revision exactly as locked, and later interview questions MUST NOT reopen or contradict a lock.
  3. Only the user can override a lock. If the user spontaneously contradicts a previously locked decision, record the new decision as a new lock marked as superseding the old one, and keep the old entry struck-through (~~old text~~ — superseded) for audit. Never delete a lock, and never treat your own reinterpretation as an override.

Anti-invention invariant (every phase)

Always active, in every phase of the loop — analyze, score, interview, lock, rewrite, re-score, and the final output contract alike:

Any information the loop needs but does not have is marked n/a or turned into an interview question — never invented, never assumed, never filled with a plausible default.

Concretely: a rewrite that would need a fact the user never provided marks the slot n/a or queues the fact as the next question; a score is never propped up by imagined context; an output-contract section with nothing confirmed to put in it says n/a rather than something plausible. When in doubt whether something was actually stated or confirmed, it was not — ask.

Output contract: the final phase

Entered only when the loop has stopped — the threshold was reached (or the first-round pass fired), or the round cap was hit and the user chose to proceed anyway. This phase turns the session into the artifact the SDD workflow consumes:

  1. Instantiate templates/REFINED_PROMPT.md and fill every section from the session document: the final prompt revision verbatim, objective, context and source priority, scope in/out/do not change, core behavior, edge cases, constraints, tools policy, action boundaries, output, stop condition, capabilities touched, verification expectations, the coverage table (each of the eight blocks with the lock id that covers it), the final rubric score per dimension with its evidence quotes, and the complete lock register copied verbatim (superseded entries kept struck-through). A section with nothing confirmed to put in it says n/a — the anti-invention invariant applies here as everywhere.
  2. Present the document to the user for explicit confirmation. Show the filled document and ask the user to confirm it. This confirmation is a gate, not a courtesy: no downstream step runs until the user has explicitly approved the output contract. If the user requests changes, apply them (locking any new decisions) and present again.
  3. Hand off downstream. Once confirmed, the document is saved as a file (in the change-planning area or scratch space) and you hand its path to prompt-engineer, which runs in a subagent and writes ENGINEERED_PROMPT.md next to it; that engineered prompt becomes the input of openspec-propose (or openspec-explore when the user wants to think first). Hand the refined prompt directly to openspec-propose only when the user explicitly chooses to skip engineering, and say that the step was skipped. The lock register travels with the document precisely so that downstream steps never re-ask a locked decision — everything the user already decided is settled; downstream questions may only cover genuinely new ground.

README.md

tile.json