Feature Request → Feature Requirement Document
Turn a raw user request into a document a developer can build from without coming back with questions. Works for any SaaS product — the product-specific parts live in one config file the user creates on first run.
The failure mode this exists to prevent: a plausible-looking spec built on guesses. A developer cannot tell which lines came from the user and which were invented, so an invented line costs more than a missing one. When something is unknown, ask. When it stays unknown, it goes in Open Questions — never into a requirement.
Loading references (read only what the current step needs)
| File | Load when |
|---|---|
references/setup.md |
No product config exists yet (Step 0 only) |
references/sources.md |
The request link fails to fetch, or is on Slack/Linear/Jira/Notion/Intercom |
references/question-bank.md |
Entering Step 3, once |
references/writing-guide.md |
Entering Step 5, once |
references/quality-checklist.md |
Entering the final gate in Step 4, once |
Each is small and self-contained. Don't load all of them upfront, and don't re-read one you've already loaded in this conversation.
Step 0 — Product config (first run only)
Everything product-specific — the docs to search, the feature inventory, plan names, who reads the FRD — lives in a single product config file. Without it there is no way to check whether a feature already exists.
Look for it, in this order, and stop at the first hit:
product-config.mdin the current working directory or project root.claude/product-config.mdproduct-config.mdinside this skill's directory- A product config pasted into this conversation, project instructions, or memory
If one is found, read it once and continue to Step 1. Don't mention it or re-read it.
If none is found, this is a first run: load references/setup.md and follow it. It's a
short interview that produces the config file, and it happens once — every later run reads
the saved file and goes straight to work.
Never invent product facts to skip this step. A duplicate check against an imagined feature list is worse than no duplicate check.
Step 1 — Get the actual request
Read the request verbatim; the user's own wording carries information a paraphrase loses.
Try fetching the link directly first. Most request tools sit behind a login, so a failure
here is normal, not an error worth apologizing for. If the fetch fails, returns a login
page, or returns something that clearly isn't the request, load references/sources.md —
it covers connector-based retrieval (Slack, Linear, Jira, Notion, Intercom and others) and
the paste fallback. Never reconstruct what a request "probably" said.
Extract and hold onto:
- The verbatim quote of what the user asked for
- Who asked — name/handle, plan tier, account size, tenure, whatever the source shows
- When it was posted, plus upvotes, "+1"s, or duplicate reports
- The job behind the request, separated from the solution the user proposed
That last split matters. Users write solutions ("add a dropdown to pick the tone") when they mean problems ("my posts come out in the wrong voice for LinkedIn"). Capture both and specify against the problem. A better solution to the same problem is still a win; a faithful build of the wrong solution is not.
Step 2 — Check whether this already exists
Before writing anything, find out whether the product already does this or something close. This is often where the request ends — a feature people can't find is a discoverability problem, not a build.
Search in this order, stopping as soon as you have a confident answer:
- The feature inventory in the product config
- The help center / docs URLs in the config
- The changelog or release notes — recently shipped features are the ones users haven't noticed yet, and the top source of false "doesn't exist" verdicts
- Marketing and pricing pages — the capability may exist but be gated to a plan the requester isn't on, which is a completely different fix
Search for the capability, not the user's phrasing. Users invent names for things: "bulk export" is also "download all," "CSV export," "batch download."
Budget: three to five searches. Fetch a full page only when a snippet is ambiguous, and pull the relevant section rather than the whole page. If five searches produce nothing, "no match found" is the honest answer — say which sources you checked.
Post a short verdict in chat. A few lines, not a document:
Duplicate check: [Already exists / Partially exists / Adjacent feature only / No match found]
[1–3 sentences on what exists today and how it relates to the request]
Link: [URL]
Gap: [what the request still asks for that today's feature does not cover]
- Only link to pages you actually retrieved. A fabricated help-center URL is worse than "no match found" — it sends the user chasing a 404 and quietly poisons the verdict.
- Partially exists is the most common and most useful verdict. Name the gap precisely; it usually shrinks the work from a new feature to an extension of an existing one.
- Stop and wait for a reply. The user knows the product better than any doc and may kill, redirect, or confirm the request right here.
Step 3 — Ask until you can actually specify it
Draft the FRD against assets/frd-template.md, then find the holes. Every section with an
unknown becomes a question.
Ask in batches of 3–6 grouped, numbered questions, highest-impact first. One question per message is slow and burns a turn each time; twenty at once gets skimmed and half-answered.
Two things make questions answerable in seconds instead of minutes:
- Offer a default. "I'm assuming this applies to all plan tiers — correct?" beats "Which plans should this apply to?"
- Ask for a decision, not an essay. "Should an over-limit export fail, or truncate with a warning?" beats "How should limits be handled?"
Answer what you can yourself first. If an answer implies something obvious downstream, carry it forward and confirm it as an assumption rather than spending a question on it. Skip anything the source request or the config already answers — re-asking signals you didn't read them.
Load references/question-bank.md once here for questions grouped by section and by request
type. Pull from it rather than improvising, but only ask what's genuinely missing.
Step 4 — Gap loop: re-check before handing it over
This is the step that gets skipped, so make it explicit. After each round of answers, run a completeness pass over the whole draft — not just the parts just discussed.
For every template section ask: could a developer who has never seen this conversation implement it without guessing?
Flag anything that is:
- Empty, or "TBD" outside the Open Questions section
- Vague in a way that hides a decision ("handle errors gracefully," "should be fast")
- An assumption made but never confirmed
- A requirement with no way to verify it was met
- A dependency, permission, limit, or plan gate introduced but never pinned down
If anything is flagged, ask the next batch and loop. Typically 2–4 rounds — one is almost always too few, and past four the remainder are usually genuine unknowns that belong in Open Questions rather than more questions.
Then run references/quality-checklist.md line by line and report the result honestly:
which sections are solid, what stayed open. Remaining unknowns aren't failures — they're the
loop working.
Step 5 — Write the FRD
Use assets/frd-template.md exactly: same sections, same order. Consistency is what lets a
developer skim to the part they need.
Follow references/writing-guide.md for wording — that's what keeps the doc buildable rather
than merely tidy.
Write it to a markdown file named FRD-[YYYY-MM-DD]-[short-slug].md and hand it over. If no
file tools are available, output it in chat.
Don't restate the document in chat afterwards. Close with four lines: what's being built, the duplicate-check verdict, what's still open, and a rough S/M/L size read with the reason.
Requirement quality bar
Every functional requirement is independently testable. If you can't describe how a developer would demonstrate it working, it isn't a requirement yet.
- Weak: "Export should be fast and handle large accounts."
- Strong: "FR-4: Exports of up to 500 items complete within 30 seconds. Above 500, the export runs in the background and the user is emailed a download link."
Label every assumption inline with [ASSUMPTION] so a reviewer can scan for them. An
unconfirmed assumption that reads like a confirmed fact is the most expensive line in the
document.
Separate what the user said from what the team decided. The Problem section holds the user's words; the Solution section holds the team's decisions. Never let a decision drift into Problem as though the user asked for it.
Cover the unhappy paths. Empty, loading, failure, permission denied, limit exceeded, and what users on non-eligible plans see. Most rework comes from these, not the happy path.
Say what is out of scope. Explicit non-goals prevent scope creep more reliably than anything else, at one line each.
Staying cheap
Long conversations cost more than long documents, and re-reading costs more than either.
- Read each reference file at most once per conversation, only at its step.
- Batch questions — every extra round re-sends the whole conversation.
- Quote the parts of a fetched page you need; don't paste pages into the doc or the chat.
- Once the config is read, don't re-read or re-summarize it.
- Deliver the FRD as a file and summarize in four lines. Reprinting a three-page document into chat roughly doubles the cost of the whole run for no benefit.