docs/concepts/spec-of-specs.md
When a feature is too large to run through a single
/speckit.specify → /speckit.plan → /speckit.tasks → /speckit.implement
cycle without the model losing track mid-implementation, you can break it into a
roadmap of smaller, independently-specified sub-features. This is the "spec of
specs" approach: one up-front pass decomposes a massive feature into self-contained
specs, and each of those runs through its own specify/plan/tasks/implement cycle.
When to reach for this. Decomposition adds the most overhead of any strategy in Handling Complex Features. Use it only when the lighter options there are insufficient — first try limiting how many tasks run per
/speckit.implementinvocation, then sub-agent delegation, then a combination. Reach for a spec of specs only when even a single phase is too large to handle in one run.
The rest of this page describes how to do it with the tools you already have. No new commands or extensions are required.
Before writing any sub-spec, do a single decomposition pass to produce a roadmap. Treat this as a lightweight planning conversation with your agent, not a full spec:
The roadmap is deliberately shallow: it names and orders the sub-features but does
not design them. The design happens when each slice runs through its own
/speckit.specify.
The roadmap is an ordinary Markdown file you author and keep under version control — there is no special tooling behind it. Put it where the sub-specs can find it:
specs/<epic-slug>/roadmap.md.ROADMAP.md.Each roadmap entry carries a stable id (used later for linking), a name, its intent, its scope boundary, its dependencies, a status, and — once the sub-spec exists — a link to it. A minimal template:
# Roadmap: <epic name>
<One or two sentences: what the epic is and why it is being decomposed.>
**Status legend**: planned · in-progress · done
| ID | Sub-feature | Intent | Scope boundary | Depends on | Status | Sub-spec |
|----|-------------|--------|----------------|-----------|--------|----------|
| R1 | <name> | <one line> | <in / deferred> | — | planned | — |
| R2 | <name> | <one line> | <in / deferred> | R1 | planned | — |
| R3 | <name> | <one line> | <in / deferred> | R1 | planned | — |
Keep the ID column immutable once a sub-spec references it — it is the anchor for
traceability. Fill in the Sub-spec column with the path to each sub-feature's spec
directory as you create it, and update Status as work progresses.
With the roadmap in hand, work through the entries one at a time using the normal Spec Kit flow — nothing new to learn:
done (or have none)./speckit.specify for just that slice, describing only its intent and scope
from the roadmap entry. Because the slice is bounded, its spec, plan, and tasks
stay well within the context window./speckit.plan, /speckit.tasks, and /speckit.implement for that slice as
usual.done and move to the next one.Each slice is a complete, independent Spec Kit feature with its own
spec.md/plan.md/tasks.md. The roadmap is what ties them together.
To keep scope and intent from drifting across separate runs, every sub-spec references its roadmap entry, and the roadmap links back — a simple, greppable, bidirectional convention:
Sub-spec → roadmap. In the sub-feature's spec.md, name the parent roadmap
and entry id in the Input / summary line, for example:
**Input**: Parent roadmap: `specs/<epic>/roadmap.md` → entry **R3**. <feature description>
Roadmap → sub-spec. In the roadmap table, set the entry's Sub-spec column to
the sub-feature's directory, e.g. specs/<epic>-part-3/.
Because both directions are plain text, you can trace any sub-spec back to its place in the epic (and find its siblings) with a quick search — no tooling, no metadata schema.
The roadmap is a living document. As you learn more, keep it and the sub-specs aligned:
Suppose the epic is "Add a self-service billing portal" — far too large for a single cycle. The roadmap pass breaks it into three independently-specifiable slices.
specs/billing-portal/roadmap.md:
# Roadmap: Self-service billing portal
Let customers view invoices, manage payment methods, and change plans without
contacting support. Too large for one cycle, so it is split into independent slices.
**Status legend**: planned · in-progress · done
| ID | Sub-feature | Intent | Scope boundary | Depends on | Status | Sub-spec |
|----|--------------------|------------------------------------------|---------------------------------------------|-----------|---------|----------|
| R1 | Invoice history | Customers view and download past invoices | Read-only; no payment actions | — | done | specs/billing-invoices/ |
| R2 | Payment methods | Add, remove, and set a default card | No plan changes; assumes invoices exist | R1 | in-progress | specs/billing-payment-methods/ |
| R3 | Plan changes | Upgrade/downgrade the subscription plan | Uses R2's default payment method | R1, R2 | planned | — |
Each slice is then specified on its own. For example, the R2 sub-feature's
spec.md opens with a back-reference:
# Feature Specification: Billing — payment methods
**Input**: Parent roadmap: `specs/billing-portal/roadmap.md` → entry **R2**.
Let customers add, remove, and set a default payment method in the billing portal.
From here a reader can trace R2 back to the roadmap, see that it depends on
R1 (invoice history, already done), and see that R3 (plan changes) is
waiting on it. Building R1, then R2, then R3 keeps every run small while the roadmap
preserves the shape of the whole epic.
If you would rather automate roadmap capture and consistency checks than maintain the file by hand, the community-maintained Spec Roadmap extension explores that direction. It is a third-party extension and is not required — the manual convention above is enough on its own.