Phased Spec Decomposition
Take one product + engineering spec and turn it into an ordered sequence of
phases, each with its own standalone design document. The output is meant to
be handed to a coding agent one phase at a time -- every document must be
implementable on its own, with no unresolved questions.
North star: every phase document should leave zero design decisions for
the implementer. Not "an agent probably wouldn't need to ask a question" --
an agent literally cannot make a different reasonable choice than the one the
document specifies, because every choice is already made and written down.
Input
Accept a PRD, an engineering design doc, a combined spec, or rough notes that
mix product intent with technical detail. If the input only covers product
intent, infer a reasonable engineering approach and mark it as an assumption.
If it only covers engineering, infer the product framing (who benefits, what
they can now do) for each phase.
Verify Before Writing
If a codebase is available, read it before writing any engineering content.
Cite what exists today with path:line, not from memory or from what the
spec assumes. A phase document that describes "current state" without having
read the current state is a guess, not a spec. If no codebase exists yet
(greenfield), say so explicitly and proceed on the spec alone.
For each phase, note what already exists that the phase can reuse --
an existing service, table, endpoint, or library that solves part of the
problem. Never let a phase rebuild something the codebase already has.
Tech Stack Choices
Brownfield (existing codebase): the stack is not a decision to make --
it's whatever Verify Before Writing found. Match the existing language,
framework, database, and libraries. Introducing a new one requires a stated
reason (the existing stack genuinely cannot do what this phase needs), never
preference or unfamiliarity with what's there.
Greenfield (no codebase yet): Phase 1's document must pin the full stack
once -- language, framework, database, hosting/deploy target, and any
non-trivial third-party library -- each with a one-line rationale. Every
later phase inherits this silently as a given; never re-open or re-litigate
the stack in a later phase's document.
Default to boring. Prefer established, widely-used technology over novel
tools unless the spec states a hard requirement only the novel choice
satisfies -- name that requirement explicitly when it justifies the
departure. A phased handoff is the wrong place to spend the project's
appetite for risk on tooling.
A stack change mid-project is a decision, not a detail. If a later phase
needs a new language, datastore, or framework the earlier phases didn't use,
call it out as its own explicit decision in that phase's document: the
reason, the alternative considered, and the migration cost to anything
already built in the old stack.
Core Principle: Vertical Slices, Not Layers
Never phase by layer ("schema, then API, then UI" or "backend, then
frontend"). A layer-based phase produces nothing a user or downstream system
can exercise until every layer is done. Instead, cut vertically: each phase
touches every layer it needs -- however thinly -- and ends with something that
runs end to end and demonstrates real behavior.
Phase 1 is a walking skeleton: the thinnest possible path through the full
system for the single most important scenario, wired for real (real network
calls, real storage, real auth if auth gates the flow), not stubbed. Every
phase after that adds one more increment of capability on top of a system
that already works.
Example -- a URL shortener spec.
Bad (layer-based -- nothing works until phase 3):
- Phase 1: database schema for
urls and clicks.
- Phase 2: REST API for create/redirect/stats.
- Phase 3: frontend page to create and view links.
Good (vertical slices -- each phase is a working product):
- Phase 1: paste a long URL into a form, get a short code back, visiting the
short code redirects to the long URL. Real storage, no auth, no stats yet.
- Phase 2: short codes are scoped to a logged-in user's account (adds auth
end to end: login, ownership check, per-user list view).
- Phase 3: click count and last-accessed time shown on each link (adds the
clicks table, an increment-on-redirect write, and a stats row in the UI).
Every phase in the good version can be demoed to a user. None of the phases
in the bad version can.
Sequencing Rules
- Phase 1 is a working skeleton. It should touch every architectural
component the final system needs, at minimal depth, for one real scenario.
- Each phase adds exactly one coherent capability. If a phase description
needs "and" to summarize it in one sentence, it is probably two phases.
- Order by dependency, not by convenience. A phase may only depend on
capabilities delivered in strictly earlier phases -- never on a phase that
comes after it. When dependency order leaves a tie, do the riskiest or
least-certain part first -- incremental and reversible beats big-bang;
surface unknowns while there is still time to change course.
- Every phase ends in a working, demoable state. Stopping after any
phase should never leave the system half-built or non-functional.
- Fold plumbing into the phase that needs it. Do not create a
phase whose sole content is infrastructure, schema, or scaffolding with no
observable behavior -- attach that work to the first phase that exercises it.
- Name cross-cutting concerns explicitly. For auth, observability,
validation, rate limiting, and error handling, state per phase whether a
minimal version is enough or the full version is required, and call out
which later phase upgrades it.
- Let complexity set the phase count. Do not force a round number of
phases. Count independent capabilities, integration points, and risk areas
in the source spec, and let that count drive how many phases exist.
- Bound each phase's size. A phase should be implementable in roughly
1-3 focused agent sessions and land as one PR. If a phase touches more
than ~8 files or introduces more than 2 new services/classes, treat that
as a signal to split it further, not as a reason to write a longer doc.
- Don't design what already exists. Before specifying a new pattern,
queue, cache, or abstraction inside a phase, check whether the stack
already has a built-in or established pattern for it. Reach for the
existing tool before inventing a new one.
Per-Phase Design Document
Every phase gets its own complete document. A reader with zero context on the
other phases must be able to implement this one from this document alone.
Product Section
- Phase goal -- one sentence: what this phase unlocks that did not exist
before.
- User story / job-to-be-done -- who benefits and what they can now do.
- In scope -- an exhaustive, explicit list of behavior this phase delivers.
- Out of scope -- what looks related but is explicitly deferred, and to
which later phase.
- Acceptance criteria -- numbered, binary, testable statements with real
numbers where relevant. "Returns 409 when the slug already exists" and
"list endpoint responds in under 200ms for 10k rows" pass; "handles
conflicts well" and "is performant" do not.
- UX flow -- for user-facing phases, describe the flow step by step
(screens, states, transitions) even without visual mockups.
Engineering Section
What already exists -- code, services, or libraries this phase reuses
rather than rebuilds (see Verify Before Writing).
Components touched -- every service, module, or repo this phase creates
or modifies.
Data model -- schemas, fields, types, constraints, and migrations,
written out in full (as a table or code block), not summarized.
API contracts -- every endpoint or interface added or changed: method,
path, request shape, response shape, status/error codes. Use a table or
code block per endpoint.
Key flows -- the sequence of operations for the happy path and for each
major edge case (empty input, conflict, timeout, partial failure, retry).
Dependencies on prior phases -- the exact interfaces this phase
consumes from earlier phases; nothing implicit.
Non-functional requirements -- only the ones this phase must actually
satisfy (latency budget, concurrency, idempotency), stated as numbers or
concrete rules, not adjectives.
File reference table -- every file this phase touches, with the change,
as a table (path:line when referencing existing logic):
| File |
Change |
path/to/file.ts:42 |
Add null check before dispatch |
Failure modes -- for each new or changed codepath, name one realistic
way it fails in production (timeout, nil reference, race, stale data) and
state whether a test covers it, whether error handling exists, and whether
the failure is visible to the caller or silent. Flag any silent, untested,
unhandled failure as a gap to close before the phase is done.
Test plan -- as a table across the testing pyramid:
| Layer |
What |
Count |
| Unit |
service.method() behavior |
+N |
| Integration |
cross-component flow |
+N |
| E2E |
user-visible journey |
+N |
Rollout -- feature flags, migration order, backward-compatibility
requirements. If the phase touches data, infrastructure, or shared state,
state the rollback plan explicitly -- even "revert the PR" counts, but say
it.
Definition of done -- a checklist that maps one-to-one to the
acceptance criteria above.
Resolving Ambiguity
The source spec will have gaps. Never write "TBD," "decide later," or "up to
implementer" -- a phase document with an open question is not ready to hand
off. But not every gap should be closed the same way; sort each one by
stakes before deciding how to close it.
Low-stakes or reversible (a default page size, a naming convention, a
field's exact wording, which existing utility to call) -- make the most
reasonable decision yourself, state it as an explicit assumption at the top
of the affected phase document, and move on. Don't stop to ask.
High-stakes or hard-to-reverse (tech stack, data model shape that other
phases build on, auth/security posture, a breaking API change, anything
touching money or irreversible data loss) -- do not silently assume. Stop
and ask the user before writing the affected phase document. A wrong silent
guess here doesn't cost one phase, it compounds through every phase built on
top of it. Name the decision, the options, and your recommendation in one
short question; don't bury it inside a long draft the user has to comb
through to find it.
Where a number is missing (a latency budget, a row count, a concurrency
limit) and cannot be derived or safely assumed, say so explicitly and state
how to measure it -- never leave it as a vague adjective.
Output Structure
- Overview -- one paragraph per phase (goal + what it unlocks), followed
by an ASCII dependency diagram across phases plus a one-paragraph
sequencing rationale explaining what would break if the order changed.
- Parallelization note -- if two or more phases (or workstreams within a
phase) touch disjoint modules and share no dependency, call this out as an
opportunity to hand them to separate agents/worktrees in parallel; group
into lanes (
Lane A: phase 2 -> phase 4 (sequential), Lane B: phase 3 (independent)). If everything is strictly sequential, say so in one line
instead of forcing a diagram.
- One fully expanded design document per phase, in phase order, each
self-contained per the template above.
Where to Write Output
Default to printing the overview and all phase documents inline in the
response, separated by a horizontal rule (---), unless the user asks for
files on disk.
When the user asks for files (or the input itself was a file path), write
them next to the source spec:
- If the source spec lives at
some/dir/spec.md, write to
some/dir/phases/phase-N-<slug>.md.
- If there is no source file (spec was pasted or described), ask the user
where to write, or default to
./phases/ in the current working directory.
- Always write an index file,
phases/README.md, containing the Overview
section (phase summaries, dependency diagram, parallelization note) with
links to each phase-N-<slug>.md -- an agent or human should be able to
open the index and navigate straight to the phase they're implementing.
Follow ape-style-markdown for headings, tables, and code block formatting
in the output.
Handoff Readiness Checklist
Before returning the result, verify for every phase document:
- No "TBD," "later," or unresolved open question remains.
- Every high-stakes ambiguity (stack, shared data model, auth posture,
breaking changes) was resolved by asking the user, not by silent guess.
- The tech stack is either inherited from the existing codebase or pinned
explicitly in phase 1 with a rationale -- never implicit, never re-decided
per phase.
- Current-state claims are backed by
path:line, not assumed from the spec.
- Every data field and API shape has a concrete type, not just a name.
- Acceptance criteria are testable by inspection or automated test, not by
judgment call, and use real numbers wherever a number applies.
- Every failure mode identified has a stated test-coverage and
error-handling status -- none left as an open question.
- A rollback plan is stated for any phase touching data, infra, or shared
state.
- The phase depends only on interfaces defined in earlier phases -- check for
forward references.
- The phase's file count and new-component count fall within the sizing
bound, or the oversized phase has been split.
Final self-check. For each phase document, actually switch perspective:
read it as the implementing agent would, with zero other context beyond the
completed prior phases. Try to name one design decision you would still have
to make. If you can name one, the document is not done -- go back and decide
it. Only move on once you cannot find one.
1---2name: ape-plan-project3description: Splits a product + engineering spec into phases, each a working vertical slice with its own agent-ready design doc. Use for "ape plan project", "plan this project", "phase this spec", or "split this into milestones for an agent to build".4---56# Phased Spec Decomposition78Take one product + engineering spec and turn it into an ordered sequence of9phases, each with its own standalone design document. The output is meant to10be handed to a coding agent one phase at a time -- every document must be11implementable on its own, with no unresolved questions.1213**North star:** every phase document should leave zero design decisions for14the implementer. Not "an agent probably wouldn't need to ask a question" --15an agent literally cannot make a different reasonable choice than the one the16document specifies, because every choice is already made and written down.1718## Input1920Accept a PRD, an engineering design doc, a combined spec, or rough notes that21mix product intent with technical detail. If the input only covers product22intent, infer a reasonable engineering approach and mark it as an assumption.23If it only covers engineering, infer the product framing (who benefits, what24they can now do) for each phase.2526## Verify Before Writing2728If a codebase is available, read it before writing any engineering content.29Cite what exists today with `path:line`, not from memory or from what the30spec assumes. A phase document that describes "current state" without having31read the current state is a guess, not a spec. If no codebase exists yet32(greenfield), say so explicitly and proceed on the spec alone.3334For each phase, note **what already exists** that the phase can reuse --35an existing service, table, endpoint, or library that solves part of the36problem. Never let a phase rebuild something the codebase already has.3738## Tech Stack Choices3940**Brownfield (existing codebase):** the stack is not a decision to make --41it's whatever Verify Before Writing found. Match the existing language,42framework, database, and libraries. Introducing a new one requires a stated43reason (the existing stack genuinely cannot do what this phase needs), never44preference or unfamiliarity with what's there.4546**Greenfield (no codebase yet):** Phase 1's document must pin the full stack47once -- language, framework, database, hosting/deploy target, and any48non-trivial third-party library -- each with a one-line rationale. Every49later phase inherits this silently as a given; never re-open or re-litigate50the stack in a later phase's document.5152**Default to boring.** Prefer established, widely-used technology over novel53tools unless the spec states a hard requirement only the novel choice54satisfies -- name that requirement explicitly when it justifies the55departure. A phased handoff is the wrong place to spend the project's56appetite for risk on tooling.5758**A stack change mid-project is a decision, not a detail.** If a later phase59needs a new language, datastore, or framework the earlier phases didn't use,60call it out as its own explicit decision in that phase's document: the61reason, the alternative considered, and the migration cost to anything62already built in the old stack.6364## Core Principle: Vertical Slices, Not Layers6566Never phase by layer ("schema, then API, then UI" or "backend, then67frontend"). A layer-based phase produces nothing a user or downstream system68can exercise until every layer is done. Instead, cut vertically: each phase69touches every layer it needs -- however thinly -- and ends with something that70runs end to end and demonstrates real behavior.7172Phase 1 is a walking skeleton: the thinnest possible path through the full73system for the single most important scenario, wired for real (real network74calls, real storage, real auth if auth gates the flow), not stubbed. Every75phase after that adds one more increment of capability on top of a system76that already works.7778**Example -- a URL shortener spec.**7980Bad (layer-based -- nothing works until phase 3):8182- Phase 1: database schema for `urls` and `clicks`.83- Phase 2: REST API for create/redirect/stats.84- Phase 3: frontend page to create and view links.8586Good (vertical slices -- each phase is a working product):8788- Phase 1: paste a long URL into a form, get a short code back, visiting the89 short code redirects to the long URL. Real storage, no auth, no stats yet.90- Phase 2: short codes are scoped to a logged-in user's account (adds auth91 end to end: login, ownership check, per-user list view).92- Phase 3: click count and last-accessed time shown on each link (adds the93 `clicks` table, an increment-on-redirect write, and a stats row in the UI).9495Every phase in the good version can be demoed to a user. None of the phases96in the bad version can.9798## Sequencing Rules991001. **Phase 1 is a working skeleton.** It should touch every architectural101 component the final system needs, at minimal depth, for one real scenario.1022. **Each phase adds exactly one coherent capability.** If a phase description103 needs "and" to summarize it in one sentence, it is probably two phases.1043. **Order by dependency, not by convenience.** A phase may only depend on105 capabilities delivered in strictly earlier phases -- never on a phase that106 comes after it. When dependency order leaves a tie, do the riskiest or107 least-certain part first -- incremental and reversible beats big-bang;108 surface unknowns while there is still time to change course.1094. **Every phase ends in a working, demoable state.** Stopping after any110 phase should never leave the system half-built or non-functional.1115. **Fold plumbing into the phase that needs it.** Do not create a112 phase whose sole content is infrastructure, schema, or scaffolding with no113 observable behavior -- attach that work to the first phase that exercises it.1146. **Name cross-cutting concerns explicitly.** For auth, observability,115 validation, rate limiting, and error handling, state per phase whether a116 minimal version is enough or the full version is required, and call out117 which later phase upgrades it.1187. **Let complexity set the phase count.** Do not force a round number of119 phases. Count independent capabilities, integration points, and risk areas120 in the source spec, and let that count drive how many phases exist.1218. **Bound each phase's size.** A phase should be implementable in roughly122 1-3 focused agent sessions and land as one PR. If a phase touches more123 than ~8 files or introduces more than 2 new services/classes, treat that124 as a signal to split it further, not as a reason to write a longer doc.1259. **Don't design what already exists.** Before specifying a new pattern,126 queue, cache, or abstraction inside a phase, check whether the stack127 already has a built-in or established pattern for it. Reach for the128 existing tool before inventing a new one.129130## Per-Phase Design Document131132Every phase gets its own complete document. A reader with zero context on the133other phases must be able to implement this one from this document alone.134135### Product Section136137- **Phase goal** -- one sentence: what this phase unlocks that did not exist138 before.139- **User story / job-to-be-done** -- who benefits and what they can now do.140- **In scope** -- an exhaustive, explicit list of behavior this phase delivers.141- **Out of scope** -- what looks related but is explicitly deferred, and to142 which later phase.143- **Acceptance criteria** -- numbered, binary, testable statements with real144 numbers where relevant. "Returns 409 when the slug already exists" and145 "list endpoint responds in under 200ms for 10k rows" pass; "handles146 conflicts well" and "is performant" do not.147- **UX flow** -- for user-facing phases, describe the flow step by step148 (screens, states, transitions) even without visual mockups.149150### Engineering Section151152- **What already exists** -- code, services, or libraries this phase reuses153 rather than rebuilds (see Verify Before Writing).154- **Components touched** -- every service, module, or repo this phase creates155 or modifies.156- **Data model** -- schemas, fields, types, constraints, and migrations,157 written out in full (as a table or code block), not summarized.158- **API contracts** -- every endpoint or interface added or changed: method,159 path, request shape, response shape, status/error codes. Use a table or160 code block per endpoint.161- **Key flows** -- the sequence of operations for the happy path and for each162 major edge case (empty input, conflict, timeout, partial failure, retry).163- **Dependencies on prior phases** -- the exact interfaces this phase164 consumes from earlier phases; nothing implicit.165- **Non-functional requirements** -- only the ones this phase must actually166 satisfy (latency budget, concurrency, idempotency), stated as numbers or167 concrete rules, not adjectives.168- **File reference table** -- every file this phase touches, with the change,169 as a table (`path:line` when referencing existing logic):170171 | File | Change |172 | --- | --- |173 | `path/to/file.ts:42` | Add null check before dispatch |174175- **Failure modes** -- for each new or changed codepath, name one realistic176 way it fails in production (timeout, nil reference, race, stale data) and177 state whether a test covers it, whether error handling exists, and whether178 the failure is visible to the caller or silent. Flag any silent, untested,179 unhandled failure as a gap to close before the phase is done.180- **Test plan** -- as a table across the testing pyramid:181182 | Layer | What | Count |183 | --- | --- | --- |184 | Unit | `service.method()` behavior | +N |185 | Integration | cross-component flow | +N |186 | E2E | user-visible journey | +N |187188- **Rollout** -- feature flags, migration order, backward-compatibility189 requirements. If the phase touches data, infrastructure, or shared state,190 state the rollback plan explicitly -- even "revert the PR" counts, but say191 it.192- **Definition of done** -- a checklist that maps one-to-one to the193 acceptance criteria above.194195## Resolving Ambiguity196197The source spec will have gaps. Never write "TBD," "decide later," or "up to198implementer" -- a phase document with an open question is not ready to hand199off. But not every gap should be closed the same way; sort each one by200stakes before deciding how to close it.201202**Low-stakes or reversible** (a default page size, a naming convention, a203field's exact wording, which existing utility to call) -- make the most204reasonable decision yourself, state it as an explicit assumption at the top205of the affected phase document, and move on. Don't stop to ask.206207**High-stakes or hard-to-reverse** (tech stack, data model shape that other208phases build on, auth/security posture, a breaking API change, anything209touching money or irreversible data loss) -- do not silently assume. Stop210and ask the user before writing the affected phase document. A wrong silent211guess here doesn't cost one phase, it compounds through every phase built on212top of it. Name the decision, the options, and your recommendation in one213short question; don't bury it inside a long draft the user has to comb214through to find it.215216Where a number is missing (a latency budget, a row count, a concurrency217limit) and cannot be derived or safely assumed, say so explicitly and state218how to measure it -- never leave it as a vague adjective.219220## Output Structure2212221. **Overview** -- one paragraph per phase (goal + what it unlocks), followed223 by an ASCII dependency diagram across phases plus a one-paragraph224 sequencing rationale explaining what would break if the order changed.2252. **Parallelization note** -- if two or more phases (or workstreams within a226 phase) touch disjoint modules and share no dependency, call this out as an227 opportunity to hand them to separate agents/worktrees in parallel; group228 into lanes (`Lane A: phase 2 -> phase 4 (sequential)`, `Lane B: phase 3229 (independent)`). If everything is strictly sequential, say so in one line230 instead of forcing a diagram.2313. **One fully expanded design document per phase**, in phase order, each232 self-contained per the template above.233234### Where to Write Output235236Default to printing the overview and all phase documents inline in the237response, separated by a horizontal rule (`---`), unless the user asks for238files on disk.239240When the user asks for files (or the input itself was a file path), write241them next to the source spec:242243- If the source spec lives at `some/dir/spec.md`, write to244 `some/dir/phases/phase-N-<slug>.md`.245- If there is no source file (spec was pasted or described), ask the user246 where to write, or default to `./phases/` in the current working directory.247- Always write an index file, `phases/README.md`, containing the Overview248 section (phase summaries, dependency diagram, parallelization note) with249 links to each `phase-N-<slug>.md` -- an agent or human should be able to250 open the index and navigate straight to the phase they're implementing.251252Follow `ape-style-markdown` for headings, tables, and code block formatting253in the output.254255## Handoff Readiness Checklist256257Before returning the result, verify for every phase document:258259- No "TBD," "later," or unresolved open question remains.260- Every high-stakes ambiguity (stack, shared data model, auth posture,261 breaking changes) was resolved by asking the user, not by silent guess.262- The tech stack is either inherited from the existing codebase or pinned263 explicitly in phase 1 with a rationale -- never implicit, never re-decided264 per phase.265- Current-state claims are backed by `path:line`, not assumed from the spec.266- Every data field and API shape has a concrete type, not just a name.267- Acceptance criteria are testable by inspection or automated test, not by268 judgment call, and use real numbers wherever a number applies.269- Every failure mode identified has a stated test-coverage and270 error-handling status -- none left as an open question.271- A rollback plan is stated for any phase touching data, infra, or shared272 state.273- The phase depends only on interfaces defined in earlier phases -- check for274 forward references.275- The phase's file count and new-component count fall within the sizing276 bound, or the oversized phase has been split.277278**Final self-check.** For each phase document, actually switch perspective:279read it as the implementing agent would, with zero other context beyond the280completed prior phases. Try to name one design decision you would still have281to make. If you can name one, the document is not done -- go back and decide282it. Only move on once you cannot find one.