product-interview
Helps you figure out exactly what to build and how it should work before you start coding.
Installation
Paste this into Claude Code, Cursor, or any agent that can run commands.
SKILL.mdShow the author's original SKILL.md
---
name: product-interview
description: "Define WHAT to build — product scope and UX — before technical design. TRIGGER when: user asks for a product interview or to design a new feature; product scope or UX is unclear; an external PRD needs transcribing into the canonical spec. SKIP when: product/UX is settled; the change is trivial; only implementation is unclear; user says 'just do it'."
---
# Product Interview
## Protocol
### Input
- **Feature:** a feature name/description or an existing `meta/specs/NNN-slug/` path.
- **Match first:** before writing, match the feature against existing folder slugs in `meta/specs/`. Never mint a new NNN before this check.
- **Exactly one match:** use that folder; Step 5 updates its spec in place.
- **Several plausible matches:** list them via `AskUserQuestion`; never glob-and-pick.
- **No match:** resolve the next number plus a slug from the feature name as the new `NNN-slug`.
- **Stable home:** resolve `NNN-slug` here so a mid-interview `generate-mockups` call has a destination.
- **Lazy creation:** whichever writes first creates the folder — mockups at Step 2 or spec.md at Step 5.
### Resumability — check before Step 0
On re-entry to an existing feature, read what exists on disk first; the spec encodes where a prior session stopped — resume there rather than re-interviewing settled ground:
- **No folder / no `spec.md`** (per the Input check) → nothing written; run Steps 0–1, start fresh.
- **`spec.md` exists but core sections are missing or placeholder** → an interrupted prior session; re-read what's there and rejoin the interview (Step 2) at the gaps — resume from the file, don't reconstruct from memory.
- **Spec complete but the Gate anchor greps hit** (`Status: open` decisions / clarification markers) → a parked investigation, not damage; resume Step 2 at the open branches or markers only.
- **`### Files touched` present and plan.md's `Base SHA:` is set** → keep the outline frozen; handle the change in the active `execute-plan` session.
- **`### Files touched` present and plan.md is absent or its `Base SHA:` is unset** → `tech-design` already designed on this WHAT; confirm the reopen, revise any affected locked decision per the template's Revising rule, and apply Step 5's header flip.
Step 0 still runs on every re-entry — the lens loads per session.
### Step 0 — Load the job lens
Invoke the `jtbd` skill via the Skill tool. Use its lens — the job-story format and job-fit judgment — to frame every product/scope question; skip its Steps and Job-frame output.
### Step 1 — Read context first
Before asking anything, silently explore:
- Root `CLAUDE.md` and any product or design documents it says to read for this task
- Existing UX in the affected area (screens, flows, components)
- Related features and any prior spec this feature builds on
- Use shipped specs as decision history; verify current behavior in code
- A light possibility scan: what the target surface/platform allows *at all*, and what data the codebase already carries — possibility only, never how-to-build, never current code as a ceiling (see the *Codebase is context* rule)
Don't ask what current code or the active spec already answers. Treat project conventions as constraints to follow, not decisions to re-litigate.
### Step 2 — Interview: product, then UX
Resolve the **product** layer before the **UX** layer *as the default*, but treat them as one decision tree: when a UX branch blocks or would overturn a product choice, resolve that branch first (the dependency rule below governs). A UX answer that overturns an already-locked product choice follows the reversal rule below. Surface what the user is assuming, not just what they request. When the Step-1 read surfaces a load-bearing question the user didn't ask — an existing feature this overlaps, a UX pattern to reuse or deliberately diverge from — raise it, saying it came from the codebase; route technical finds to Open Questions tagged `(for tech-design)`. Draft the job-story as the product layer resolves — it anchors UX option scoring and the spec's Background. A slot you can't fill is a question to ask, not a blank to guess.
Manage the decision space as follows:
- **Start the tree:** once you can name two or more branches, show a compact nested list and ask, "Here's what I think we need to figure out — does this match?"
- **Format each node:** `- [branch] — [resolved: choice] | [open] | [deferred: why] | [blocked by branch]`, followed by `[hard|ask|ours]` when applicable.
- **Order:** list blocking branches first and resolve one branch at a time.
- **Maintain:** update the tree inline as branches split, collapse, or resolve.
- **Finish:** continue until every branch is resolved or explicitly deferred.
- **Flat interview:** for one or two flat questions, skip the tree and ask directly.
- **Unknown branches:** ask open-ended questions until you can name the branches; aim to show the tree within 2–3 rounds.
- **Long interview:** summarize current clarity and offer to continue or proceed.
**Run each branch explore → stretch → verify (in order)** — name the ideal before checking what's real, so a constraint never caps a choice the user hasn't reached for yet.
- **Explore / stretch:** for a non-trivial or ambiguous UX branch, name and score 2+ options by job-fit before locking; an obvious single-UX branch skips this. Escalate to parallel subagents (and any available design skills) only for high-stakes or high-ambiguity UX.
- **Sketch, then gate visual review:** for every feature that changes a user-facing screen, component, interaction, or visual state, sketch each UI branch or option in ASCII, then ask once via `AskUserQuestion` before Step 2 ends: "How should we validate this UI before locking the UX?" The user chooses; recommend one option and state why:
- **Missing design reference:** before asking, check for `meta/DESIGN.md`. When it is missing, explain:
- Keep ASCII can proceed without it.
- Preview or Compare invokes `generate-mockups`, which invokes `map-design-language` before rendering an established UI or offers to invoke `frontend-design` for a blank canvas.
- **Keep ASCII** — use the sketches without a rendered artifact. Recommend this when one obvious direction follows an established pattern and the sketches make its behavior clear.
- **Preview with `generate-mockups`** — render the one preferred direction across the relevant screens or states. Recommend this when the direction is settled but a new or complex UI is easier to judge visually.
- **Compare with `generate-mockups`** — render 2+ viable directions for one unresolved visual choice side by side, then ask the user to pick. Recommend this when the directions have meaningful layout, hierarchy, or interaction tradeoffs.
- **Run mockups:** on Preview or Compare, **invoke the `generate-mockups` skill via the Skill tool** with the matching PREVIEW or COMPARE intent, the resolved `meta/specs/NNN-slug/mockups/` path, and the design context you know. It derives High or Approximate fidelity after grounding; don't promise High fidelity in the question.
- **Record the result:** at Step 5, record `ASCII (user-approved)`, or the reviewed mockup link plus the approved preview or comparison result, in the UX section.
- **Skip:** omit this checkpoint only when the feature changes no user-facing UI.
- **Verify (just-in-time):**
- **Trigger:** when an unchecked claim could invalidate the agreed scope if false, dispatch a subagent to verify it against the source of truth (code, docs, or SDK). A claim that would only redirect the branch does not qualify.
- **Scope:** verify only whether the product surface can support the agreed behavior.
- **Route:** put implementation and capacity questions in Open Questions tagged `(for tech-design)`.
- **Hit a wall? Tag it.** `[hard]` = outside our control (external SDK / platform) → law; stamp its assumption (e.g. "given the SDK has no programmatic redirect") so it reopens if the dependency changes. `[ask]` = cross-team, movable by request. `[ours]` = our code, we change freely. `[hard]` is a real constraint; `[ask]`/`[ours]` are guidance — if either forces a worse UX, challenge it (or flag the ask) first, then record the user's final call and move on.
- **Don't lock a UI pattern whose surface feasibility is unverified** — verify possibility first, or lock it "pending feasibility."
Completeness lens (verify nothing is missing — these are a lens, not a required structure):
- **Product / scope** — the job to be done, in the jtbd job-story format (loaded at Step 0); who it's for; what's in, what's out; success criteria.
- **UX and behavior** — happy path, error states, empty states, user flows, the surfaces/screens touched.
- **Acceptance criteria** — observable, testable conditions for "done."
- **Constraints** — compatibility, platform limits, dependencies, boundaries.
- **Clarity** — resolve remaining ambiguity or contradictions.
When a load-bearing assumption surfaces, test it once ("Does this constraint actually exist?" / "What's the simplest version still worth shipping?"). Challenge the framing, not the person. If a stated requirement seems materially wrong (product value, UX harm), say so with reasoning; record the user's final call, not yours.
If a later answer or feasibility finding overturns a choice the user already locked this session, re-confirm via `AskUserQuestion` and record the overturned choice in the surviving decision's Rejected field, citing what killed it — the why must reach the record.
Record each resolved choice as a **`D-NNN-XX` decision block** (see the Spec.md template — it defines the id format) with Status, Chosen, Rejected, Rationale. Classify anything unresolved by exactly one rule:
- A framed-but-unresolved **decision** → a `D-NNN-XX` block with `Status: open`.
- A blocking unknown inside any section → an inline `[NEEDS CLARIFICATION: ...]` marker.
- Non-blocking notes → Open Questions (these do NOT block the gate).
Deferring a decision is itself a decision: propose it, the user confirms, and it lands as a **locked** `D-NNN-XX` whose Chosen is the deferral (alternatives marked *deferred* in Rejected) — a confirmed deferral never blocks the gate.
The lock gate greps exactly two forms — see **Gate anchors** below. Anything blocking must carry one of them, or it will not block.
### Step 3 — Pre-confirm verification gate
Once Step 2's branches are resolved or deferred, and before the Step-4 summary, run this required gate over the resolved UX elements that are **load-bearing** (an AC, another decision, or user-facing behavior rests on them) — two passes, two grains. The gate always runs; on a trivial feature it may be near-empty (nothing load-bearing beyond the Existing-patterns check) — record that and move on.
**Pass 1 — per element.** For each load-bearing element:
- **States** — error / empty / edge: what happens when data is missing, the call fails, or a value hits a boundary?
- **Expectation-Fidelity** — does what the element implies (its label, control, default, or placement) match what actually happens? Flag every mismatch.
- **Surface-Obligations** — any obligation the surface itself imposes (e.g. accessibility/compliance on a regulated surface), where it demands it.
**Pass 2 — the assembled whole.** Do the cleared elements coexist and work together on the real surface(s)? Check combination-possibility + cross-element interference, and re-verify the load-bearing facts the interview leaned on. Surface/platform possibility is validated here — launch subagents in parallel, one per applicable area below (Existing-patterns always runs), each carrying the flows it must validate:
| Area | When relevant | Verify |
|---|---|---|
| UI components | Feature uses specific components/libraries | Component exists, supports the interaction, composition constraints |
| External data/APIs | UX depends on external data | Data is available, fields exist |
| Platform constraints | Feature rides a platform (Shopify, extension, etc.) | The UX is permitted by the platform |
| Existing patterns | Always | The affected area's existing UX patterns and conventions |
Scope: possibility, not capacity. Constraint depth — rate limits, quotas, throughput, batch caps — is `tech-design`'s constraint recon (its Step 2B); don't duplicate it here.
Handle verification results in order:
1. **Receive:** each subagent returns `exists` (yes/no), capabilities, gotchas, and **`blocks: <the decision or flow it invalidates> | none`**. `none` is valid.
2. **Record:** put each load-bearing possibility verdict in the relevant `D-NNN-XX` Rationale or the Constraints section, not only in conversation.
3. **Resolve:** feed every Pass-1 miss or Pass-2 `blocks` hit back into the tree. Re-explore it with the user; never narrow the UX silently.
4. **After one follow-up round:** proceed with each resolved finding. Classify each remaining finding by Step 2's rule as an open decision, clarification marker, or Open Question, then move on.
### Step 4 — Pre-write summary
Before writing, summarize the contract in chat in this exact shape — enough to spot a wrong turn without reproducing every AC:
```
**Contract summary (pre-write):**
- Scope: [one line]
- Decisions: D-NNN-XX [title] → [Chosen] (one line per decision)
- Visual review: [not applicable — no UI change | ASCII (user-approved) | mockups: path — review outcome]
- Constraints: [one line each]
- ACs: [n] ([x] code-gated, [y] human-gated)
- Step-3 gate: [clean | each finding and how it resolved]
**Assumptions I'm carrying (never discussed):**
- [assumption] — [what rests on it]
```
(Write `None — everything load-bearing was discussed` when the assumptions list is empty.) Then use `AskUserQuestion` to collect the choice: "Write the draft" / "Adjust first" / "Find gaps first". Recommended: write the draft. The full verbatim contract — the numbered AC list with gating tags and every `D-NNN-XX` block — belongs in the file, not chat: Step 5 writes it as `Status: Draft` for the user to review. Reviewers verify diffs against that AC text, so it must be exact in the file.
On **Find gaps first** — opt-in, at most once, for a complex feature or when you lack the domain depth to spot missing cases — invoke the `find-gaps` skill over the assembled contract. Absence-hunting only: its lens is **what the contract never mentions** — missing scope, AC-coverage holes; never re-check verdicts the Step-3 gate settled (checkers verify what's written; find-gaps hunts what's not). Product/UX gaps only — not a technical-gap hunt (`tech-design`'s job); fence every lens to the WHAT layer and send technical gaps to Open Questions tagged `(for tech-design)`. Applied gaps re-enter Step 2; a new flow on an external surface re-runs the Step-3 gate on the delta. Then re-summarize and re-ask without the Find-gaps option — it runs at most once.
### Step 5 — Write / update the spec
Write the spec in this order:
1. **Path:** use `meta/specs/NNN-<topic-slug>/spec.md` with the `NNN-slug` resolved at Input. Create the folder unless a Step-2 mockup already created it.
2. **Existing spec:** if Input resolved an existing spec, update it in place. Append or modify sections and revise decisions per the template's Revising rule.
3. **Counters:** continue both counters. The next `D-NNN-XX` uses the highest existing `XX` across product and technical decisions plus 1; new ACs continue their counter likewise.
4. **Reopen:** before plan.md's `Base SHA:` is set, a decision or AC edit on a spec with `### Files touched` resets the header to `Status: Draft`. The existing outline was verified against the old WHAT, and the Draft header routes `tech-design` through a scoped redesign.
5. **Handoff:** tell the user the path and ask them to review the file. The spec remains `Status: Draft` and uncommitted; Step 6 owns revisions and commit.
This skill writes the WHAT sections; `tech-design` later appends technical Decisions + the Structure Outline (and appends to Constraints / Accepted risks what its recon proves); `execute-plan` appends the Completion record at ship. For the full file shape, see the **Spec.md template** at the end of this file.
### Step 6 — Review, commit, route
Stop here once every product/UX branch is resolved or deferred and the spec is written. Step 5 sent the user to read the file — this step turns that review into approval, then handles commit and routing as two tightly-coupled `AskUserQuestion` rounds.
**Q1 — Draft look right? If so, commit?**
- **Ask:** offer "Commit now" (recommended) / "Skip commit for now" / "Adjust the draft first".
- **Approve:** either Commit or Skip approves the draft; proceed to Q2.
- **Adjust:** edit the Draft in place and re-ask Q1. If the edit overturns a locked decision or changes an AC on a spec with a populated outline, apply Step 5's header-flip rule.
- **Commit:** stage only spec.md; the commit is the durable trace of approval:
```
git add meta/specs/NNN-slug/spec.md && git commit -m "spec(NNN-slug): discovery — product/UX decisions + ACs"
```
- **Folder guard:** use the slug resolved at Input. If `git status --porcelain meta/specs/NNN-slug/` shows another changed file, leave it unstaged and tell the user.
- **Skip commit:** leave spec.md uncommitted and say so. `tech-design` Step 6 will stage it; re-offer the commit at every session boundary before then.
**Q2 — Where next?**
- **`tech-design`** — default: the WHAT is locked and the feature needs implementation decisions before sequencing.
- **`grill-me`** — if `Status: open` decisions or clarification markers remain, or a load-bearing assumption wasn't pressure-tested.
- **`write-plan`** directly — only for a trivial change with one obvious implementation.
The WHAT must be locked (both Gate anchor greps clean) before `tech-design` will proceed.
## Rules
- **One question per round.** Tightly coupled follow-ups are fine; shotgunning unrelated questions is not. Presenting/updating the tree counts as part of the round.
- **Always use `AskUserQuestion` for questions with distinct choices** — with your recommendation and why. Plain text only for genuinely open-ended questions.
- **Product + UX only.** Technical approach, data shapes, and file layout are `tech-design`'s job — route them to Open Questions tagged `(for tech-design)` and move on — tech-design reads them at its discovery step.
- **Codebase is context, not constraint.** Existing code shows what IS, not what MUST BE; the user may intentionally diverge. A wall is **law** only when it's outside our control (external SDK / platform) — tag `[hard]`, stamp its assumption; anything we or a teammate can change (`[ours]` our code, `[ask]` cross-team) is **guidance** — challenge it before it narrows the vision.
- **Proportional effort — load-bearing only.** Spend a subagent, verification, or UX-exploration round only where a decision rests on the answer; skip passing mentions and obvious single-UX branches. Match effort to stakes.
- **Anchor questions in what you read.** When a source raises a question, name its actual file or symbol and the claim that needs confirmation.
- **Play back concrete scenarios, not abstract questions.** Confirm behavior by walking one specific case in the shape `[trigger]: [what happens] — right?` ("Save fails offline: the draft stays and a retry shows — right?") — a wrong detail draws the correction an abstract question won't.
- **Keep project conventions out of the spec.** Loaded project instructions own them; record a `D-NNN-XX` only for a feature-specific choice that is costly to reverse.
- **The spec is the feature's build contract + record** — it settles at ship; post-ship product/UX evolution belongs to future specs and durable docs, not retroactive edits here.
- **Only spec.md and plan.md mint ids.** spec.md mints `D-NNN-XX`/`AC-NNN-XX`; plan.md mints `F-NNN-XX` (execute-plan's job; format in write-plan's Plan anchors). All other artifacts — interview notes, triage/backlog files, research — cite existing ids and never mint their own.
---
## Spec.md template
Other skills inline only their own sections and point here:
```markdown
# SPEC-NNN: [Feature name]
- **Status:** Draft <!-- Draft → Locked → Shipped. Set Draft: product-interview; → Locked: tech-design Step 6 (iff lock greps clean); → Shipped: execute-plan ship gate. The trivial route (product-interview → write-plan directly) skips tech-design and legitimately ships from Draft. Locked = zero open decisions and zero clarification markers. The lock gates grep per-decision markers, not this line; write-plan's stale-outline gate is the one gate that reads it (see Gate anchors). -->
- **Created:** [YYYY-MM-DD]
- **Source:** [origin — roadmap item, request, prior spec it builds on]
## Background
[Who needs this and why. The one-line job, in the jtbd job-story format (loaded at Step 0). The layer/scope boundary in a sentence. One short paragraph.]
## Requirements
[The WHAT, as observable rules — the densest, most load-bearing content. Enumerate edge cases per rule. No IDs: nothing downstream cites requirements — ACs are the citable contract.]
- [the rule] — edge cases: [list]
- [the rule] — edge cases: [list]
## UX
[Flows and states: happy path, error, empty. Surfaces/screens touched. Low fidelity is fine — ASCII mocks or bullet flows. Record the visual/structural options explored, not just the chosen one — keep each rejected layout/flow (mock or one line) with why it lost. When `generate-mockups` produced a page, link it (`mockups/…`) with any notes and stamp it *directional, not final*; the design system / `meta/DESIGN.md` wins if they disagree. Backend-only features: the externally observable contract — which fields/behavior a consumer sees; field types, nullability, and shapes belong to tech-design's outline, which takes precedence.]
## Out of scope
[Only Out-of-scope — don't restate In-scope (that duplicates Requirements). Annotate coupling.]
- [excluded item] — [coupling note]
## Acceptance Criteria
[Observable, testable "done" conditions — the contract an independent reviewer checks the diff against; the implementer never self-certifies.
**Numbering & rigor:** ids are `AC-NNN-XX` — `NNN` = this spec's folder number, `XX` = a zero-padded two-digit counter starting 01; plan tasks and tests cite the ids; scale rigor to scope.
**Gating tag (MANDATORY):** every AC carries exactly one — code-gated (machine-checkable against the diff) or human-gated with the concrete how (routed to Post-ship verification at ship). Tags are provisional at discovery; tech-design confirms or flips each once the approach is chosen — a tag-only edit, exempt from the supersession protocol.
**Revising:** ACs are the live contract — revise in place. While plan.md is absent or its Base SHA unset: a plain edit to final shape, no marker (if plan.md exists, the Revising rule's stale-plan route applies). Once Base SHA is set: add a trailing *(revised per D-NNN-XX)* marker — its presence always means changed mid-build; the why lives in the superseding decision.
**One physical line per AC:** ID, behavior, gating tag, and any *(revised per D-NNN-XX)* marker all on that line; the gates select by line.]
- **AC-NNN-01:** [observable behavior] — [code-gated]
- **AC-NNN-02:** [observable behavior] — [human-gated: how to verify, concretely]
## Decisions
[Inline, atomic `D-NNN-XX` blocks — the durable why.
**Id format:** `NNN` = this spec's folder number; `XX` = a zero-padded two-digit counter starting 01 — ONE counter per spec, shared by product (this skill) and tech (tech-design) decisions. Ids are unique across the repo (the folder number guarantees it) and never renumbered.
**Type marker:** each heading carries `[product]` or `[tech]` after the colon — advisory for readers and routing, no gate greps it.
**Citing:** cite the full id (`per D-NNN-07`), never a line number.
**Revising:** while plan.md is absent or its `Base SHA:` is unset (planning stage — anchor form in Plan anchors, `skills/write-plan/SKILL.md`), edit blocks in place to their final shape — fold an overturned Chosen into Rejected with what killed it, so the why survives in the one block; if plan.md already exists, tell the user the plan may be stale and route through write-plan's existing-plan guard. Once Base SHA is set (build started), supersede, never edit the body. Another spec's block is always superseded, never edited, at any stage.]
### D-NNN-01: [product] [decision title]
- **Status:** locked <!-- open | locked | superseded — lowercase, load-bearing (see Gate anchors). Unresolved decision = open; any open blocks downstream. -->
- **Chosen:** [the choice]
- **Rejected:** [alt — why it lost]; [alt — *deferred*, not rejected forever — why]
- **Rationale:** [the constraint that drove it; cite a verified fact if load-bearing]
- **Supersedes:** —
- **Superseded-by:** — <!-- set when Status flips to superseded; the ONLY edits ever made to a superseded block are Status + this line -->
## Structure Outline
<!-- WRITTEN BY tech-design — leave empty at discovery. Design snapshot: written `Status: Draft` for review, FROZEN once `Status: Locked`; before build, replaced only by a tech-design re-run. During build, deviations live as [Implementation] entries in plan.md's Execution Log; after ship, code is the source of truth for structure. -->
<!-- Section format lives in skills/tech-design/SKILL.md (Step 3); it ends with a "### Files touched" heading — load-bearing: write-plan's outline-present gate greps it (see Gate anchors below). -->
## Constraints
[Fixed boundaries: compatibility, performance, platform limits, dependencies. Append-by-both: discovery seeds it; tech-design appends the load-bearing numbers its recon proves. Tag each wall `[hard]` (outside our control — stamp the assumption) · `[ask]` (cross-team, movable) · `[ours]` (our code) — advisory annotations, no gate greps them.]
- [constraint] — `[hard|ask|ours]`
## Accepted risks (knowingly carried)
[Append-by-both: discovery seeds it; tech-design appends the risks the user accepts.]
- [risk we choose to live with] — [why acceptable]
## Open Questions
[NON-BLOCKING notes only — this section does not block the lock gate; blockers must be open-status decisions or inline clarification markers (see Gate anchors). Implementation questions for tech-design land here, tagged `(for tech-design)`. Omit this section entirely when empty.]
- [non-blocking question] — [why it can wait]
---
## Completion record
<!-- WRITTEN BY execute-plan at the ship gate — leave absent until then. Settles the spec: outcome stamped onto the contract. -->
**Shipped:** [date] · **Status:** Complete | Partial
### Criteria results
| AC | Result |
|---|---|
| AC-NNN-01 | PASS / PARTIAL / FAIL — [1-line evidence] |
### Post-ship verification
<!-- WRITTEN BY execute-plan at ship: manual test cases for the whole feature; each `- [ ]` as steps → expected result, human-gated ACs led by `AC-NNN-XX:`. "None — nothing manually observable" if none. -->
- [ ] [steps] → [expected result]
- [ ] AC-NNN-XX: [steps] → [expected result]
### Deferred / what this does NOT close
- [deferred debt or known limitation, with severity] — or "None"
### Review filter stats
<!-- one line aggregating the Wave Reviews tallies: review findings the fix-verify-loop pre-gate dropped + findings demoted, across all waves — so what the filter rejected stays visible -->
- [N dropped by pre-gate, M demoted, across all waves] — or "None"
```
### Gate anchors (load-bearing — exact forms matter)
These live OUTSIDE the template so they are never copied into a spec instance. Downstream gates (tech-design Step 1, write-plan Step 1) block on:
```
grep -nE '^[[:space:]]*-[[:space:]]*\*\*Status:\*\*[[:space:]]*open' spec.md # any hit ⇒ blocked
grep -n '\[NEEDS CLARIFICATION:' spec.md # any hit ⇒ blocked
grep -n '^### Files touched' spec.md # write-plan Step 1 only: no hit ⇒ outline missing
grep -nE '^[[:space:]]*-[[:space:]]*\*\*Status:\*\*[[:space:]]*Draft' spec.md # write-plan Step 1 only: + outline present ⇒ stale outline (reopened)
```
Rules that keep these greps sound — breaking any of them silently breaks the pipeline:
1. **POSIX ERE only** (`[[:space:]]`, never `\s`) — gates run through varying grep builds.
2. **Case split is load-bearing**: header Status values are Capitalized (`Draft/Locked/Shipped`); decision Status values are lowercase (`open/locked/superseded`). That asymmetry is what keeps the header line out of the decision-gate regex. Never normalize one to the other.
3. **Clarification markers are always written with the colon** (`[NEEDS CLARIFICATION: ...]`). The ban is by location, not intent: the colon form must NEVER appear in the canonical template body, or any text destined for a spec instance, where the gate would catch it; an illustrative `: ...` placeholder in this rules block or interview prose, as here, is fine — the gate reads spec.md, never SKILL.md.
4. **Each AC is ONE physical line** — `- **AC-NNN-XX:** behavior — [tag]`, keeping any `*(revised per D-NNN-XX)*` marker on that same line (a long AC stays on one line; the gates care about line *count*, not length). Both AC selections (execute-plan Step 4 / Seat A code-gated, Step 5.3 human-gated) grep the AC line, then filter for the tag — a tag wrapped onto a continuation line silently drops the AC from review or post-ship verification.
5. plan.md-side anchors (typed log tags, promotion marker, deferred tags) are defined beside the canonical plan template in `skills/write-plan/SKILL.md`.
Mirrored from the author's public source. Install counts from the open skills registry.