# Product Interview

> 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'.

- Skill: `preetamnath/product-interview` (Agent Skill)
- Install (CLI): `npx skillmds@latest add preetamnath/product-interview`
- Raw SKILL.md: https://api.skillmd.com/api/skills/preetamnath/product-interview/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: preetamnath (https://skillmd.com/u/preetamnath)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/preetamnath/product-interview

---


# 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:
  - **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 rendered 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 rendered directions** — 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`.

