groom · git:20260907.450260a · 2026-09-07 · sha256 c08939d4872f9650
groom git:20260907.450260aA
Immutable. This exact content is served forever at /api/v1/blob/c08939d4872f9650.
---
name: groom
description: Turn a rough idea into a scoped, labeled GitHub issue ready for the delivery pipeline. Use when the owner wants to capture a todo, feature, or bug as a real backlog item with scope, acceptance criteria, and a priority. Refines the idea over as many rounds as it takes — each round a fresh `product-manager` that has read the code, asking at most three questions, one at a time, each with a stated recommended default — and ends the loop only when every acceptance criterion is testable as written. Verifies bug reports read-only before scoping them, and offers a type:docs fast-track label for documentation-only work. First stage of the flow delivery workflow (see docs/workflow.md).
argument-hint: [rough idea — a todo, feature, or bug]
---
# groom — rough idea → scoped GitHub issue
You are the PM/lead in the main session. Turn the owner's rough idea into one well-scoped
GitHub issue, labeled and ready for `/spec-flow:activate`. This is interactive: you draft, the owner
refines. Stay in the foreground — no worktrees, no implementation.
## Steps
1. **Read the idea — ask only what round 1 can't start without.** Two things, at most:
- **What is this?** Only if the description is genuinely unreadable as a unit of work. A rough,
under-specified idea is the normal input here, not a problem to solve before proceeding.
- **Is this one piece of work or several?** A bundle of two ideas becomes two issues, and the
refinement loop can't sharpen both at once.
Ask them one at a time, each with your own recommended answer stated alongside it — a default
they can accept in one word ("this reads like two issues to me: X, and Y for later — split it?").
**Write whatever the owner answers into the refinement record before you spawn round 1** (step 4
defines the record and its `## Before round 1` entries). The record is the only channel these
answers have: round 1 receives the raw idea verbatim, so an idea the owner just split in two
still reaches the agent whole, and nothing else in the prompt carries the correction.
**Everything else waits for step 4.** The deep interview happens there, asked by an agent that
has read the code, which is most of what makes a question worth asking. Don't resolve
shape-defining ambiguity here and don't hold the refinement back for it: that's what the loop is
for, and asking here as well puts the owner through two interviews with two different bars.
2. **For bug reports: verify before you draft.** If the idea describes something not working
(symptoms, expected vs. actual behavior), don't draft acceptance criteria from an unconfirmed
report. `groom` stays foreground with no worktree and makes no code changes (see **Rules**), so
verification here is strictly **read-only** — run the reporter's described repro steps (a
command, an existing test, a specific input) directly in the primary checkout and observe
whether the symptom actually occurs:
- **Reproduces** → note the confirmed repro (command + observed output) in the eventual Notes/
context section; proceed.
- **Doesn't reproduce** → say so plainly, with what you tried and what actually happened, and
ask the owner what's missing (one question — e.g. "what environment/version does this need?")
before drafting AC from a report you couldn't confirm.
- **No repro steps given at all** → ask for them (one question, with a guessed default if you
have one — "I'm guessing this happens when X — is that right, or what actually triggers it?")
before attempting anything.
- **Not practically verifiable here** (needs a live external service, specific hardware, a
production-only condition) → say so, and proceed with the report as given, flagged
**unverified** in Notes/context — so the architect consult at `activate` treats the premise as
unconfirmed, not settled fact.
Matters most for a report you didn't personally observe — an externally filed bug, or one
relayed secondhand — where nothing has actually confirmed it's real yet.
3. **Docs-only? Offer the fast track.** If the idea is purely documentation — README, a docs/
mdBook tree, comments, no behavior change — say so and offer to label it `type:docs` (recommend
yes; a low-stakes default the owner can accept in one word). `activate` and `implement` both
skip most of their heavyweight machinery for a `type:docs` issue — no architect design consult,
no design-choice stop, no review panel, and (for most content-only docs work — the label
alone doesn't decide this; `activate` step 5 judges it from the issue's own scope) no OpenSpec
spec generated at all — while still stopping at both owner seams as normal; see **Docs fast
path** in `docs/workflow.md`. Not sure it's docs-only, or it touches behavior at all (even
indirectly — e.g. a config example that has to stay in sync with real defaults)? Leave it
unlabeled; the full pipeline is the safe default. Record the owner's answer the same way step 1
records its own, under `## Before round 1` — whether this is documentation-only changes what a
round should ask about, and the refinement record is the only thing that carries it there.
4. **Refine in rounds.** One `product-manager` pass produces whatever depth a single reading
reaches; everything it couldn't settle becomes a guess made later, by `architect` or
`tdd-developer`, without the owner in the room. So run it as a loop. **You drive the loop and
you decide when it ends** — the agent never decides that for you.
**A round.** Spawn a **fresh** `product-manager` subagent. Its prompt carries three runtime
values and nothing else:
- the owner's **raw idea, verbatim** — plus the step-2 verification verdict if this is a bug;
- the **refinement record** in full (below);
- the **previous round's refinement** — the owner's edited copy wherever they edited it, not the
agent's original. Round 1 has none.
Don't restate the agent's mandate in the prompt; it has its own definition, and a restatement
there only competes with it. Send runtime values, the way `implement` does.
The round returns a refinement — problem statement, in/out scope, testable WHEN/THEN acceptance
criteria, open questions, context — and up to three questions. Show the refinement to the owner,
relay the questions (below), append everything to the record, then judge the refinement against
the readiness bar. Bar met → step 5. Bar unmet → run another round.
**The refinement record.** Keep it in a file, `.spec-flow/groom-<slug>.md` in the primary
checkout, where `<slug>` is a short kebab-case name for the idea (`.spec-flow/` is already
gitignored; if this repo's isn't, add it — and if a record with that slug already exists from
another idea, pick a different slug rather than writing over it). Not in your conversation. You
run inside `project-manager`'s session, which compacts; a record held in context degrades to a
paraphrase, and a later round would receive softened owner constraints while you still believed
you had passed on their exact words. Append to it as the round happens, one entry per thing the
owner did:
```markdown
## Before round 1
- **Q:** <a step-1 or step-3 question, exactly as you asked it>
**A:** <the owner's answer, verbatim>
## Round 2
- **Q:** <the question exactly as you asked it>
**A:** <the owner's answer, verbatim>
- **Edit:** <the scope line or criterion the owner rewrote, in the owner's wording>
- **Deletion:** <the line the owner removed>
- **Direction:** <owner technical direction, verbatim — see below>
- **Dropped:** <a question the round asked with no stated default, returned unasked>
```
**Write the file with the Write tool, never with a shell command** — the record holds the
owner's prose verbatim, which can contain `$(...)` or backticks, and an unquoted heredoc body
would execute them. Appending with the Write tool means writing the file out again with the new
entry on the end, every earlier entry copied through unchanged. If a shell append genuinely
can't be avoided, quote the delimiter — `<<'EOF'` — which suppresses both substitutions.
Four properties make the record worth keeping:
- **Verbatim.** Copy what the owner wrote. Don't tidy it, summarize it, or turn it into a
criterion — that's the next round's job, in the open.
- **Append-only.** Never rewrite an earlier entry. Where two entries contradict, **the later
one wins**: an answer given in round 2 and reversed in round 4 is settled by round 4.
- **Every answer keeps its question.** "No" and "the second one" mean nothing on their own, and
a later round can't resolve the referent from the answer alone.
- **Edits and deletions are entries too.** An owner who deletes an acceptance criterion and says
nothing has said something. Record the deletion, so the next round doesn't re-add the line.
**The readiness bar — yours to apply, not the agent's.** A round is ready when all three hold:
- **(a)** every acceptance criterion is testable as written;
- **(b)** the unhappy paths are covered — errors, limits, empty or oversized input, conflicts;
- **(c)** no **behavioral** assumption is left for a downstream agent to guess at.
Item (c) is scoped to behavior deliberately. **Design assumptions don't hold the loop open** —
data models, interfaces, algorithms, libraries all belong to `architect` at the design stop, and
chasing them here both duplicates that work and gives the loop no fixed point.
A round that asks no questions has not thereby met the bar, and a round that asks three has not
thereby failed it. Read the refinement and judge it. **A small idea meeting the bar in round 1
is a normal, expected outcome** — converging fast isn't a sign you applied the bar too loosely.
**Unsourced concreteness is not readiness.** A criterion that is testable *only* because it
names a value nobody gave — a size limit, a timeout, a retry count, a specific error code — is
not ready. Rewarding it would make inventing a number the cheapest route to convergence. Treat
that value as the next round's question, with your recommended default.
**Relaying questions.** One at a time, at most three per round.
- **One at a time** — the owner can't usefully answer a batch. Ask the second only after the
first is answered.
- **Every question carries a stated recommended default**, so the owner can accept in one word.
A question that arrives without one **is not relayed at all**, and the round is treated as not
having asked it. **Don't supply the default yourself for a question the agent asked** — step
1's own two questions are yours and carry your defaults, but these aren't: the point of the
default here is that the agent that read the code committed to an answer, and a default you
invent is a line with no antecedent wearing the owner's question as cover. **Record the drop**
as a `**Dropped:**` entry, so the next round can see the question already came back once and
either supply a default this time or convert it to a stated assumption. Without that entry the
next round has identical inputs and returns the same defaultless question.
- **Order dependent questions before what depends on them.**
- **More than three candidates?** Relay the three that most change the shape of the work. The
rest stay in that round's refinement under **Open questions / assumptions**, which the next
round's prompt carries as the previous refinement.
**The loop ends** when any one of these is true:
- the **readiness bar is met**;
- the **owner ends it** — "that's enough", "just file it", or anything else that plainly means
stop;
- **a round has nothing new to ask** — every question it would ask is already answered in the
record. A further round has the same inputs and returns the same thing.
There's no round cap. The owner is present at every round, so a long loop is visible and one
word ends it.
**The closing pass.** When the loop ends for any reason *other* than the bar being met, run one
more round, and only one. Honour "stop" immediately — the closing pass is what you do next, not
another round of questions. Its prompt is the usual three values, including the owner's final
answers, plus the instruction that it asks **nothing**: it returns a refinement, and it converts
everything still open into explicitly stated assumptions, each marked as traceable to the record
or as the agent's own.
This is why the closing pass still runs after the no-new-questions stop, which ended the loop on
the grounds that a further round has the same inputs. The closing pass differs by **instruction**,
not by input: it asks nothing and converts what's open into marked assumptions, which is work no
earlier round did.
**Confirming the assumptions — one screen, split by provenance.** Present the closing pass's
assumptions to the owner in a single pass, in two groups:
- **Traceable to something the owner said** — confirmable in **bulk**, one answer for the group.
Each confirmed item becomes an ordinary Scope or Acceptance criteria line.
- **Never raised by the owner** — each needs its own explicit yes or no. **A bulk yes never
promotes one of these.** Promotion makes an agent-authored line indistinguishable from one the
owner wrote, and the moment of least attention is the wrong moment to grant that.
This bulk confirmation is a **deliberate, scoped exception** to the one-question-at-a-time rule
above, and the only one. It applies to the traceable group at the closing pass, nowhere else:
the loop's questions each shape the work, while these are already-stated positions being
confirmed as a set at the end.
Anything the owner leaves unresolved is neither promoted nor dropped — it goes into the issue's
own assumptions section (step 5).
**Owner technical direction.** The owner may state technical direction at any round —
architecture, performance characteristics, implementation guidelines, constraints. Record it
**verbatim**, under `**Direction:**` in the record, and carry it into the drafted issue
unchanged. Never reword it into a behavioral criterion, and never drop it for being design:
`product-manager`'s "stay out of design" rule binds the agent, not the owner. If a round returns
owner direction restated as an acceptance criterion, don't accept the rewording — the direction
stands as the owner wrote it.
5. **Draft the issue body** from the final refinement. Write each section under the literal `##`
heading given here, exactly as spelled — downstream steps match on the heading string, so a
bolded line or an `###` reads to them as no section at all:
- `## Scope` — what's in, and explicitly what's out.
- `## Acceptance criteria` — a checklist of observable outcomes (these become the spec's
scenarios later, when a spec gets generated at all — see the Docs fast path exception below —
so make them testable).
- `## Technical direction` — the owner's own words, verbatim, exactly as recorded. Include this
section only if the owner stated any. `activate` step 3 matches this exact heading and passes
what's under it to the `architect` verbatim; anything else there reaches nobody.
- `## Assumptions` — the closing pass's items the owner left unresolved. Include this section
only if there are any.
- `## Notes / context` — links, constraints, related code (`file:line`), related issues, and —
for a bug — the step-2 verification verdict (confirmed repro, or flagged unverified/couldn't
reproduce).
Keep it tight. A full spec usually comes later in `/spec-flow:activate` (a content-only
`type:docs` issue skips that artifact — see **Docs fast path** in `docs/workflow.md` — but still
reviews this same scope + acceptance criteria at Seam 1); either way, this is the contract for
*what* and *why*, not *how*.
6. **Set priority.** Propose a priority and confirm with the owner. Exactly one of
`P0` (drop everything) / `P1` (high) / `P2` (normal) / `P3` (low/someday) — never zero,
never two.
7. **Create the issue.** Put the title and the body in two plain files, then let a tool build the
request payload from them. `<slug>` is the kebab-case slug from step 4.
- `.spec-flow/groom-<slug>-title.txt` — the title, on one line.
- `.spec-flow/groom-<slug>-body.md` — step 5's drafted body exactly as it should read in the
issue: every line as written, every `##` heading at the start of its line.
**Write both files with the Write tool, never with a shell command** — a title can contain
`$(...)` or backticks, and an unquoted heredoc body would execute them. Then build the payload
and post it:
```bash
jq -n \
--rawfile title ".spec-flow/groom-<slug>-title.txt" \
--rawfile body ".spec-flow/groom-<slug>-body.md" \
'{title: ($title | rtrimstr("\n")), body: $body, labels: ["<P0|P1|P2|P3>", "status:ready"]}' \
> ".spec-flow/groom-<slug>-issue.json"
gh api --method POST "repos/{owner}/{repo}/issues" \
--input ".spec-flow/groom-<slug>-issue.json" --jq '.number, .html_url'
```
If the owner accepted the docs-fast-track offer at step 3, add `"type:docs"` to the labels
array. Title and body reach the issue as JSON string values that `jq` wrote from the files, so
the body's line breaks survive and each `##` heading still starts a line. `rtrimstr("\n")`
drops the newline the Write tool puts at the end of the title file; the body's trailing newline
is harmless and stays.
**If `jq` is unavailable or the command fails, stop and tell the owner.** Don't compose the
payload yourself to get past it — that is the one action this step forbids, and a failure here
is exactly the moment it looks reasonable.
**Never write the payload by hand.** `--rawfile` reads a file as one raw string and `jq` emits
it already escaped, so a `"` in the body stays a quote character instead of closing the string
and turning the rest of the body into further payload fields — which is how a drafted line could
otherwise append its own `labels`, and this pipeline routes on labels. The safety here comes
from `jq` producing the escaping, not from JSON being a specified format: a payload you type
yourself is exactly as dangerous as the shell string this replaced, and the body is not purely
the owner's words — the refinement sources some of it from repo reading and the duplicate
search.
The call prints the number and the URL. Rename the refinement record to
`.spec-flow/groom-<N>-<slug>.md` with that number, so the record of how the scope was reached is
findable from the issue number.
8. **Verify and report.** With `<N>` from step 7's response, confirm the issue's labels are
**exactly** the set you asked for — one `P?`, `status:ready`, and `type:docs` only if the owner
accepted the fast track:
```bash
gh issue view <N> --json number,title,labels
```
Check for strays, not only for the labels you expect. `gh issue create --label` used to refuse
an unknown label before sending; `gh api` does not, so a typo in the payload creates a new label
and succeeds. Report the issue number and the URL step 7 printed. Suggest
`/spec-flow:activate <N>` when the owner wants to start it.
## Rules
- Exactly one priority label. If the owner doesn't pick, recommend one and confirm before creating.
- **Every line traces back to the owner.** A scope boundary or acceptance criterion goes in the
issue only if the owner said it, or you showed it to them and they kept it. Reading the code
tells you what a criterion *could* be; it never authorises adding one. When your repo reading
turns up something the owner did not raise — a config path to honour, a test harness to extend,
a concrete example value — name it as a proposal in the draft review and mark it as yours, so
they can cut it in one word. Silence is not agreement. An issue that carries rules nobody asked
for sends the whole pipeline off building them. **Running more rounds never relaxes this**: four
rounds of refinement must leave no scope line or criterion without an antecedent in the record
or an explicit confirmation from the owner.
- Don't groom the same idea twice — search open issues first (`gh issue list --search`) if it
might already exist.
- Acceptance criteria are the seed of the spec's `#### Scenario:` blocks (when a spec gets
generated at all — see the Docs fast path exception above) — write them as observable WHEN/THEN
outcomes where you can.
- Keep titles concrete and short — the OpenSpec change name is `issue-<N>` (deterministic, not
derived from the title), so the title only has to be a good title, not double as a slug source.
- When you cite an issue or PR, always write it as `<number>: <title>`, on its own line with a `-`
prefix — the owner does not track raw numbers. Never run several together inline in a sentence.
- **Bug verification (step 2) is read-only, always.** No worktree, no file writes, no commits —
run existing commands/tests and observe; if verifying would require changing anything, that's
past `groom`'s scope, not a reason to skip verification (fall back to "not practically verifiable
here" instead).
- **`type:docs` is conservative by default.** Only offer it when the idea is unambiguously
documentation-only; when genuinely unsure, don't offer it — the full pipeline (architect consult,
full review panel) is always safe to run on a docs change, just slower. The fast path is an
opt-in speedup, never something inferred without asking.