Generate FRS
Module-batched orchestrator. One classifier subagent resolves modules and operations. Drafting and validation run inline — no per-FRS subagent dispatch. Only the syncer ever touches GitLab. FRS content lives only as GitLab issues — no local files.
Announce at start: "I'm using the generate-frs skill to classify your sources, parse them into modules, generate business-language FRS, and sync approved specs to GitLab."
User Gate Protocol — Read This Before Phase 1
Every user-facing decision point in this skill is an AskUserQuestion call. The tool name is literal — use it exactly. Plain-text questions to the user are forbidden — they look natural but they break the structured-input contract callers depend on. If you find yourself writing "Confirm, or...", "Disposition for...", "Continue / halt?" as prose, STOP and use the tool instead.
The pattern (verified schema):
AskUserQuestion(questions=[
{
question: "<one line, business-readable, ends with '?'>",
header: "<≤12 char chip label>",
multiSelect: false,
options: [
{ label: "<1–5 word label>", description: "<what happens if chosen>" },
{ label: "...", description: "..." }
]
}
])
Required per question: question, header (≤12 chars), multiSelect, options (2–4 items). Each option requires label AND description. The harness automatically appends an "Other" choice — never include "Other" in the options array yourself. Up to 4 questions per call when batching (used at Phase 4b for the OQ batch).
Schema note: verified against current Claude Code. Do NOT pass
optionsas bare strings — they must be{label, description}objects. Do NOT add anOtheroption — the harness adds it. UsemultiSelect: trueonly when choices are not mutually exclusive (rare in this skill's gates).
The runbook (references/phase-runbook.md) is the canonical home for every gate template — module confirmation, initials collision, closed-milestone, cross-session FRS-ID, OQ batch, spot-check (4d.0), module disposition (4d.1), inter-module checkpoint, and others. They live at the point of execution in the runbook, not duplicated here. If a phase needs a gate, read the runbook section for that phase.
If a gate isn't in the runbook, that's a bug — file it rather than improvising.
Three Context-Discipline Moves
The orchestrator is designed to fit 20+ FRS in one session. The architecture trades the previous "render every FRS inline" pattern for three rules that keep the main context lean:
- Move 1 — FRS bodies never render inline. Drafted bodies stream straight into the syncer's
descriptionfield. The user reads them in GitLab. The main session keeps only(FRS-ID, issue link, brief metadata)per FRS. Spot-check at Phase 4d.0 lets the user request one inline body on demand — that's the controlled escape hatch, not a default. - Move 2 — Open Questions batch at module entry, not per FRS. All inferred OQs across all FRS in a module are surfaced once via
AskUserQuestionafter the module's outline pass — including every[inferred from code]item the classifier propagated across BR / EC / Exception Flows / Actors / Form Fields validation. Drafting then runs straight through, no per-FRS OQ ceremony. - Move 3 — Disposition gates at module boundary. No per-FRS Approve / Change / Skip. After all FRS in a module are drafted, validated inline, and synced, a single module-summary gate (Phase 4d.1) lets the user approve the module or flag specific FRS for revision.
These three moves together reclaim ~50–60k tokens per 9-FRS run vs the per-FRS gating pattern.
Anti-Pattern: "This FRS Is Simple Enough To Skip The Constraint"
You will be tempted on small operations like "log out" to ship an FRS with one rule, one edge case, or no exception flow. The Skill Constraint (≥2 rules, ≥2 edge cases, ≥1 exception) is a baseline, not a target. Simple operations still have unstated policy rules — infer them. The inline validator pass will reject anything below the floor.
When to Use
Use when the user wants requirements written, modules broken out, GitLab issues created from rough input, or a feature brief / UI prototype formalised. Accepts prose, React/TS code, uploaded .docx / .pdf / .md / .txt, or any combination.
Do NOT use for: reviewing existing FRS (skill:review-frs), technical design (skill:tech-spec), Agile user stories.
Checklist
Complete in order:
- Preflight — verify
gitlab_project_idinCLAUDE.md, GitLab MCP connectivity, the four plugin-owned shared references in.claude/shared/exist (frs-template.md,frs-validation-rules.md,frs-code-extraction-rules.md,gitlab-frs-conventions.md), the two project-owned references resolved fromCLAUDE.md(glossary_pathdefaulting todocs/glossary.md,cross_cutting_pathdefaulting todocs/cross-cutting-concerns.md) exist, two subagents present in.claude/agents/(frs-source-classifier,gitlab-frs-syncer), and build thepolicypayload fromgitlab-frs-conventions.mdplus snapshot the resolved glossary and cross-cutting-concerns files (Phase 0e — capturing the conventions the syncer applies and the glossary / cross-cutting versions stamped into every Validation Log's audit reproducibility set). - Source Classification — dispatch
frs-source-classifiersubagent to buildsource_manifest. Verify the traversal guardrail. Redirect on existing-FRS structural match. - Parse & Module Resolution — scope gate (>3 modules / >12 FRS), confirm modules via
AskUserQuestion. - Manifest & Milestones — initials (collision gate via
AskUserQuestion), cross-session FRS-ID collision check, build manifest, dispatchgitlab-frs-synceronce per module for milestones using a pre-rendered description; milestone payloads do not carrypolicy. - Module Loop (per module) — see
references/phase-runbook.mdfor the four-step batch: outline (4a) → batch OQs (4b — including all[inferred from code]items) → per-FRS draft+validate+sync producing a compact validation log per FRS (4c) → spot-check sub-gate (4d.0) → module disposition (4d.1) → revision sub-loop (4e) if needed. - Inter-module checkpoint — between modules, brief continue/halt gate via
AskUserQuestion. - Final Output — summary table or Halt Resume Block.
Process detail (load on demand)
| Topic | File |
|---|---|
| Phase-by-phase runbook + inline drafter/validator guidance | references/phase-runbook.md |
| End-to-end flow diagram | references/process-flow.dot |
| GitLab sync, retry, halt-resume, labels | references/gitlab-sync.md |
Read on demand. The runbook embeds the drafter and validator guidance.
Honest framing. The runbook is ~640 lines — most exposition from the previous monolithic SKILL.md moved here intact. The architecture moved cognitive surface from preload to load-on-demand; total surface didn't shrink. What did shrink is what the orchestrator carries in working memory at any one moment.
Shared references (read at module-loop start; do NOT re-read per FRS)
| Reference | Purpose | When to Read |
|---|---|---|
.claude/shared/frs-template.md |
The canonical section list and template body — the single source for "what sections an FRS contains, in what order" | Once at the start of each module's draft loop (Phase 4) |
.claude/shared/frs-validation-rules.md |
Self-Review checklist + validation log format (with schema versioning), Skill Constraint, NFR Rubric, Bundling Detection, Severity Guide, AC↔FR traceability rule, OQ tag taxonomy | Once at the start of each module's draft loop (Phase 4) |
<glossary_path> (project-owned; default docs/glossary.md) |
Project-wide domain term definitions; FRS Section 4 references but never restates. Curated by agent:glossary-curator (NOT dispatched at runtime — the orchestrator snapshots the file at Phase 0e). |
Snapshotted ONCE at Phase 0e (version captured); accessible during the run |
<cross_cutting_path> (project-owned; default docs/cross-cutting-concerns.md) |
Project-wide NFRs, audit defaults, session policy; FRS Sections 7 / 18 / 19 reference but never restate. Curated by agent:cross-cutting-curator (NOT dispatched at runtime — the orchestrator snapshots the file at Phase 0e). |
Snapshotted ONCE at Phase 0e (version captured); accessible during the run |
.claude/shared/gitlab-frs-conventions.md |
Approved labels, FRS-ID pattern, milestone format, conditional label rules | Once at Phase 0e to build the policy payload that travels with every issue-write syncer dispatch (create-issue, update-issue). The syncer does NOT load this file itself. |
.claude/shared/frs-code-extraction-rules.md |
Code-source signal-to-FRS mapping, traversal guardrail, [inferred from code] propagation, logical source names |
Read by frs-source-classifier subagent only — orchestrator does not load |
These are plain markdown files, NOT skills. They are loaded by Read, not by skill-invocation. The path .claude/shared/ is sibling to .claude/skills/ and .claude/agents/.
For maintainer touch-points (when changing a section, adding a Self-Review item, retiring a glossary term, etc.), see .claude/shared/MAINTAINING.md.
Subagent Context Budget
| Subagent | mcpServers |
Dispatched |
|---|---|---|
frs-source-classifier |
[] |
once per run |
gitlab-frs-syncer |
[gitlab] |
1 scan-frs-ids (Phase 3c.1) + M create-milestone (Phase 3d) + N create-issue (Phase 4c.iv) + R update-issue (Phase 4e revisions, R ≥ 0) |
Inline drafting + inline validation in the orchestrator means: no per-FRS subagent overhead. Shared references load once at the start of each module's draft loop, not per FRS. Dispatch-prompt references load once at module entry.
Note: agent:glossary-curator and agent:cross-cutting-curator exist for maintenance of docs/glossary.md and docs/cross-cutting-concerns.md respectively. They are NEVER dispatched during a generate-frs run — the orchestrator snapshots both files at Phase 0e and uses those snapshots for the run's lifetime. The curators are surfaced here for maintainer awareness only; invoke them directly outside of generate-frs runs.
Common Mistakes
❌ Treating React code as prose → run frs-source-classifier first.
❌ Accepting traversed_imports: [] from the classifier when the source has relative imports → that's the regression mode; re-dispatch.
❌ Rendering an FRS body to the user "just to confirm before syncing" → that's the old pattern; sync first, offer spot-check at 4d.0.
❌ Resolving Open Questions one FRS at a time → batch them per module, including every [inferred from code] item.
❌ Asking the user a question in prose → use AskUserQuestion. Always.
❌ Skipping the validation log emission at 4c.ii because "the FRS looks fine" → the log IS the audit trail; without it, the spot-check gate has nothing to show.
❌ Dispatching the syncer for create-issue or update-issue without the policy field "to save tokens" → the policy is what saves the tokens; the syncer no longer reads conventions itself. (create-milestone is the explicit exception.)
❌ Loading gitlab-frs-conventions.md, the resolved glossary file, or the resolved cross-cutting-concerns file mid-run "to double-check" → re-read Phase 0e. The snapshot taken there is authoritative for the run.
❌ Restating cross-cutting-concerns content in an FRS Section 18 or 19 → reference, don't copy. Self-Review item baseline-not-duplicated will catch it (mnemonic preserved for backward compatibility).
❌ Restating glossary definitions in an FRS Section 4 → list term names only; the glossary file owns definitions. Self-Review item glossary-resolves checks both directions.
Red Flags
Never:
- Skip Source Classification, even when input is "obviously" prose.
- Bundle multiple operations into one FRS (see Bundling Detection in
frs-validation-rules.md). - Sync a flagged-for-revision FRS without applying the revision.
- Use a label outside the
policy.approved_labelsset built at Phase 0e. - Re-introduce per-FRS user gates "for safety". The module gate (4d.1) plus the spot-check (4d.0) is the safety.
- Write a question to the user as prose. Always
AskUserQuestion. - Render an FRS body inline outside the 4d.0 spot-check path. Move 1 has one and only one escape hatch.
- Hardcode the FRS section count anywhere —
frs-template.md's Canonical Section List is authoritative.
If a user gate response is ambiguous, re-present with clarifying options.
Integration
Required before: gitlab_project_id in CLAUDE.md, live GitLab MCP, the four plugin-owned shared references in .claude/shared/ (frs-template.md, frs-validation-rules.md, frs-code-extraction-rules.md, gitlab-frs-conventions.md), the two project-owned references resolved from CLAUDE.md (glossary_path defaulting to docs/glossary.md, cross_cutting_path defaulting to docs/cross-cutting-concerns.md), and the two subagents in .claude/agents/ (frs-source-classifier and gitlab-frs-syncer).
vs. skill:review-frs: this skill writes new FRS. review-frs audits existing ones. Both share frs-validation-rules.md as canonical contract — never duplicate it.
CLAUDE.md additions: surface only gitlab_project_id: <id> and GitLab MCP server: <name>. Labels, FRS-ID format, paths are owned by the shared references.