End-to-end project planning toolkit: converts requirements into structured phased implementation plans, groups phases into dependency-ordered waves for parallel subagent execution, and decomposes large branches into focused pull requests.
90
90%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
How to build a task dependency DAG and assign tasks to waves.
List every task with:
T1.1, P0, phase-3, etc.)If dependencies are not stated in the source document, infer them:
| Signal in source | Inferred dependency |
|---|---|
| "after X is done" / "once X lands" | task depends on X |
| "requires X to exist" | task depends on X |
| Test task for feature F | depends on F implementation |
| Merge / cleanup task | depends on all tasks being merged |
| Validation task | depends on all implementation tasks |
| Deployment task | depends on validation task |
| Tasks touching the same file | sequential dependency on earlier task |
| Tasks touching independent files | no dependency (can be parallel) |
| Infrastructure task removes a resource (config value, secret, permission grant, env var, queue) that the live application still reads at runtime | both the infrastructure removal and the consumer code removal must land together — flag for Step 5 |
| New code requires a resource (env var, schema column, API endpoint) that does not yet exist in the deployed environment | both the resource-creation task and the consumer code task must land together, or the resource-creation wave must precede the consumer wave — flag for Step 5 |
| A task changes an interface (API contract, event schema, DB column type) in a way that is incompatible with existing consumers | use expand-contract sequencing: Wave N adds the new alongside the old, Wave N+1 migrates consumers, Wave N+2 removes the old — flag for Step 5 |
Represent the graph as an adjacency list:
T1.1 → [] (no dependencies)
T1.2 → []
T2.1 → [T1.1] (depends on T1.1)
T2.2 → [T1.2]
T3.1 → [T2.1, T2.2]Check for cycles — a cycle means the requirements are contradictory. Surface this to the user before proceeding.
Wave(task) = 1 if task has no dependencies
Wave(task) = 1 + max(Wave(dep) for dep in dependencies)All tasks with the same wave number can execute concurrently.
Example:
T1.1 deps=[] → Wave 1
T1.2 deps=[] → Wave 1
T1.3 deps=[] → Wave 1
T2.1 deps=[T1.1] → Wave 2 (1 + max(1) = 2)
T2.2 deps=[T1.1, T1.2] → Wave 2
T3.1 deps=[T2.1] → Wave 3
T3.2 deps=[T2.1, T2.2] → Wave 3
T4.1 deps=[T3.1, T3.2] → Wave 4Give each wave a short descriptive label:
| Pattern | Example label |
|---|---|
| Diagnostics / audits | "Diagnostics & Design" |
| Setup / scaffolding | "Bootstrap & Extract" |
| Core implementation | "Fix & Build" |
| Tests / coverage | "Coverage & Validation" |
| Integration / merge | "Integration & Wrap-up" |
| Pre-requisites | "Pre-work" |
| Final checks / PR | "Wrap-up" |
A wave is parallel when:
A wave is sequential when:
A wave is must land together when:
How to detect it: For every wave boundary, ask: "If this wave deploys and the next has not landed yet, does any existing functionality break?" If yes, tasks on both sides must be in the same must land together wave. Three patterns trigger this:
| Pattern | Broken intermediate state | Fix |
|---|---|---|
| Stranded consumer | A resource (config, env var, permission, queue) is removed in Wave N; code that still reads it is only removed in Wave N+1 | Merge both tasks into one must-land-together wave |
| Premature consumer | Code that requires a new resource (env var, schema column, API endpoint) ships in Wave N; the resource is created in Wave N+1 | Create the resource first (earlier wave), or merge into must-land-together |
| Breaking contract | An API, event schema, or DB column changes incompatibly in Wave N; consumers that rely on the old contract are only updated in Wave N+1 | Use expand-contract sequencing: add new alongside old → migrate consumers → remove old |
Common triggers:
Note: the code-level dependency graph will NOT catch these. Runtime dependencies have no source imports, so a naive topological sort assigns the tasks to different waves. You must reason about the deployed runtime state, not the source tree.
For parallel waves, assign one branch per workstream:
<type>/<scope>-<slug>Examples:
refactor/scripts-lib-httpfeat/phase-3-clean-lambdatest/baselineci/deployment-automationFor sequential waves, one branch covers the whole wave:
<type>/<wave-label-slug>Emit in the Dependency Graph section of the wave document:
Wave 1 (parallel)
T1.1 <description> ─┐
T1.2 <description> ─┤─► Wave 2
T1.3 <description> ─┘
Wave 2 (parallel, unblocked after Wave 1)
T2.1 <description> (← T1.1) ─┐
T2.2 <description> (← T1.2) ─┤─► Wave 3
T2.3 <description> (← T1.3) ─┘
Wave 3 (sequential)
T3.1 <description> (← all Wave 2)Rules:
─┐, ─┤, ─┘ for parallel merges.(← X) to annotate the specific dependency.─► to show the wave that unblocks.If T1.1 is a prerequisite for 10 tasks, those 10 tasks are still all Wave 2 — they just all depend on T1.1. Do not create an intermediate wave just to "stage" them.
Surface to user:
ERROR: Circular dependency detected: T2.1 → T3.1 → T2.1
Cannot assign wave numbers until this is resolved.
Suggested fix: [description of how to break the cycle]When a task says "depends on the above" without specifying, treat it as depending on all tasks earlier in the same phase/section.
Split large parallel waves into sub-groups by semantic domain, keeping them in the same wave number. Use phase rows in the table to separate the groups visually.
The naive topological sort assigns waves based on code-level imports. It cannot detect runtime dependencies. Three patterns produce an unsafe intermediate state; all require manual correction.
When a wave removes an infrastructure resource AND a later wave removes the consumer code that still references it, deploying the first wave alone breaks the live service.
Fix: merge both tasks into the same must-land-together wave. They can be worked in parallel worktrees but must deploy together.
Example (decommissioning a third-party SDK):
WRONG — separate waves:
Wave 2: remove config parameter, permission grant, env var (infrastructure)
Wave 3: remove SDK client & dead code paths (application code)
→ Deploying Wave 2 alone breaks the live service
CORRECT — same wave:
Wave 2 (must land together):
Phase 1: remove config parameter, permission grant, env var (infrastructure)
Phase 2: remove SDK client & dead code paths (application code)
> Phases 1 and 2 must deploy atomically.When a wave deploys code that depends on a resource that does not yet exist in the environment (new required env var, NOT NULL schema column, new API endpoint), the service fails on startup or at the call site.
Fix: either create the resource in an earlier wave (safe default), or merge resource-creation and consumer into a single must-land-together wave.
Example (adding a required external API key):
WRONG — consumer first:
Wave 1: deploy service code that reads NEW_API_KEY env var
Wave 2: provision NEW_API_KEY in the environment
→ Wave 1 fails at startup: env var missing
CORRECT — resource first:
Wave 1: provision NEW_API_KEY in the environment
Wave 2: deploy service code that reads NEW_API_KEYWhen a wave changes an interface (REST endpoint shape, event schema, DB column type) in a way that is incompatible with current consumers, deploying the change alone breaks every caller that has not yet been updated.
Fix: use expand-contract sequencing across three waves. Never remove the old version until all consumers have migrated.
Example (renaming an API field):
WRONG — big-bang:
Wave 2: rename field user_id → userId in both API and all consumers
→ Any consumer not yet deployed breaks
CORRECT — expand-contract:
Wave 2: API emits both user_id and userId (backwards-compatible)
Wave 3: migrate all consumers to read userId
Wave 4: remove user_id from the API response