feat: pre-compute wave numbers at plan time
Wave numbers now computed during plan-phase and stored in PLAN.md frontmatter. Execute-phase reads wave directly instead of deriving from depends_on at runtime. - Add assign_waves step to plan-phase workflow - Add wave field to frontmatter (plan-format, phase-prompt template) - Simplify execute-phase: remove analyze_dependencies and group_into_waves - Replace with group_by_wave that just reads frontmatter integers Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -45,30 +45,25 @@ Phase: $ARGUMENTS
|
||||
- Check which have *-SUMMARY.md (already complete)
|
||||
- Build list of incomplete plans
|
||||
|
||||
3. **Analyze dependencies**
|
||||
- Read each plan's `<context>` section
|
||||
- Detect cross-references to other plans' outputs
|
||||
- Build dependency graph
|
||||
|
||||
4. **Group into waves**
|
||||
- Wave 1: Plans with no dependencies
|
||||
- Wave N: Plans depending only on earlier waves
|
||||
3. **Group by wave**
|
||||
- Read `wave` from each plan's frontmatter
|
||||
- Group plans by wave number
|
||||
- Report wave structure to user
|
||||
|
||||
5. **Execute waves**
|
||||
For each wave:
|
||||
4. **Execute waves**
|
||||
For each wave in order:
|
||||
- Fill subagent-task-prompt template for each plan
|
||||
- Spawn all agents in wave simultaneously (parallel Task calls)
|
||||
- Wait for completion (Task blocks)
|
||||
- Verify SUMMARYs created
|
||||
- Proceed to next wave
|
||||
|
||||
6. **Aggregate results**
|
||||
5. **Aggregate results**
|
||||
- Collect summaries from all plans
|
||||
- Report phase completion status
|
||||
- Update ROADMAP.md
|
||||
|
||||
7. **Offer next steps**
|
||||
6. **Offer next steps**
|
||||
- More phases → `/gsd:plan-phase {next}`
|
||||
- Milestone complete → `/gsd:complete-milestone`
|
||||
</process>
|
||||
@@ -89,22 +84,13 @@ All three run in parallel. Task tool blocks until all complete.
|
||||
**No polling.** No background agents. No TaskOutput loops.
|
||||
</wave_execution>
|
||||
|
||||
<checkpoint_detection>
|
||||
Before adding a plan to a parallel wave, scan for checkpoints:
|
||||
|
||||
```bash
|
||||
grep -c 'type="checkpoint' {plan_path}
|
||||
```
|
||||
|
||||
**If checkpoints > 0:**
|
||||
- Plan requires user interaction
|
||||
- Execute in main context OR as solo subagent (not parallel)
|
||||
- User interaction flows through normally
|
||||
|
||||
**If checkpoints = 0:**
|
||||
- Fully autonomous
|
||||
- Safe for parallel wave execution
|
||||
</checkpoint_detection>
|
||||
<checkpoint_handling>
|
||||
Plans with `autonomous: false` in frontmatter have checkpoints:
|
||||
- Run in their assigned wave (can be parallel with other plans)
|
||||
- Pause at checkpoint, return to orchestrator
|
||||
- Orchestrator presents checkpoint to user
|
||||
- User responds, orchestrator resumes agent
|
||||
</checkpoint_handling>
|
||||
|
||||
<deviation_rules>
|
||||
During execution, handle discoveries automatically:
|
||||
|
||||
@@ -18,6 +18,7 @@ Every PLAN.md starts with YAML frontmatter:
|
||||
phase: XX-name
|
||||
plan: NN
|
||||
type: execute
|
||||
wave: N # Execution wave (1, 2, 3...). Pre-computed at plan time.
|
||||
depends_on: [] # Plan IDs this plan requires (e.g., ["01-01"])
|
||||
files_modified: [] # Files this plan modifies
|
||||
autonomous: true # false if plan has checkpoints
|
||||
@@ -30,17 +31,15 @@ domain: [optional] # Domain skill if loaded
|
||||
| `phase` | Yes | Phase identifier (e.g., `01-foundation`) |
|
||||
| `plan` | Yes | Plan number within phase (e.g., `01`, `02`) |
|
||||
| `type` | Yes | `execute` for standard plans, `tdd` for TDD plans |
|
||||
| `depends_on` | Yes | Array of plan IDs this plan requires. **Empty = Wave 1 candidate** |
|
||||
| `files_modified` | Yes | Files this plan touches. Used for conflict detection |
|
||||
| `wave` | Yes | Execution wave number (1, 2, 3...). Pre-computed during planning. |
|
||||
| `depends_on` | Yes | Array of plan IDs this plan requires. |
|
||||
| `files_modified` | Yes | Files this plan touches. |
|
||||
| `autonomous` | Yes | `true` if no checkpoints, `false` if has checkpoints |
|
||||
| `domain` | No | Domain skill if loaded (e.g., `next-js`) |
|
||||
|
||||
**Wave assignment:** `/gsd:execute-phase` reads `depends_on` and `files_modified` to build execution waves:
|
||||
- `depends_on: []` + no file conflicts → Wave 1 (parallel)
|
||||
- `depends_on: ["XX-YY"]` → runs after plan XX-YY completes
|
||||
- Shared `files_modified` → sequential by plan number
|
||||
**Wave is pre-computed:** `/gsd:plan-phase` assigns wave numbers based on `depends_on`. `/gsd:execute-phase` reads `wave` directly from frontmatter and groups plans by wave number. No runtime dependency analysis needed.
|
||||
|
||||
**Checkpoint detection:** Plans with `autonomous: false` require user interaction. Execute after parallel wave or in main context.
|
||||
**Checkpoint handling:** Plans with `autonomous: false` require user interaction. They run in their assigned wave but pause at checkpoints.
|
||||
</frontmatter>
|
||||
|
||||
<prompt_structure>
|
||||
@@ -51,6 +50,7 @@ Every PLAN.md follows this XML structure:
|
||||
phase: XX-name
|
||||
plan: NN
|
||||
type: execute
|
||||
wave: N
|
||||
depends_on: []
|
||||
files_modified: [path/to/file.ts]
|
||||
autonomous: true
|
||||
|
||||
@@ -13,8 +13,9 @@ Template for `.planning/phases/XX-name/{phase}-{plan}-PLAN.md` - executable phas
|
||||
phase: XX-name
|
||||
plan: NN
|
||||
type: execute
|
||||
depends_on: [] # Plan IDs this plan requires (e.g., ["01-01"]). Empty = parallel candidate.
|
||||
files_modified: [] # Files this plan modifies. Used for conflict detection.
|
||||
wave: N # Execution wave (1, 2, 3...). Pre-computed at plan time.
|
||||
depends_on: [] # Plan IDs this plan requires (e.g., ["01-01"]).
|
||||
files_modified: [] # Files this plan modifies.
|
||||
autonomous: true # false if plan has checkpoints requiring user interaction
|
||||
domain: [optional - if domain skill loaded]
|
||||
---
|
||||
@@ -125,12 +126,13 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md`
|
||||
| `phase` | Yes | Phase identifier (e.g., `01-foundation`) |
|
||||
| `plan` | Yes | Plan number within phase (e.g., `01`, `02`) |
|
||||
| `type` | Yes | Always `execute` for standard plans, `tdd` for TDD plans |
|
||||
| `depends_on` | Yes | Array of plan IDs this plan requires. **Empty = Wave 1 candidate** |
|
||||
| `files_modified` | Yes | Files this plan touches. Used for conflict detection |
|
||||
| `wave` | Yes | Execution wave number (1, 2, 3...). Pre-computed at plan time. |
|
||||
| `depends_on` | Yes | Array of plan IDs this plan requires. |
|
||||
| `files_modified` | Yes | Files this plan touches. |
|
||||
| `autonomous` | Yes | `true` if no checkpoints, `false` if has checkpoints |
|
||||
| `domain` | No | Domain skill if loaded (e.g., `next-js`) |
|
||||
|
||||
**Wave assignment:** `/gsd:execute-phase` reads `depends_on` to build execution waves. Plans with `depends_on: []` and no file conflicts with sibling plans run in Wave 1 (parallel).
|
||||
**Wave is pre-computed:** Wave numbers are assigned during `/gsd:plan-phase`. Execute-phase reads `wave` directly from frontmatter and groups plans by wave number. No runtime dependency analysis needed.
|
||||
|
||||
---
|
||||
|
||||
@@ -142,16 +144,19 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md`
|
||||
|
||||
```yaml
|
||||
# Plan 01 - User feature
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [src/models/user.ts, src/api/users.ts]
|
||||
autonomous: true
|
||||
|
||||
# Plan 02 - Product feature (no overlap with Plan 01)
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [src/models/product.ts, src/api/products.ts]
|
||||
autonomous: true
|
||||
|
||||
# Plan 03 - Order feature (no overlap)
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [src/models/order.ts, src/api/orders.ts]
|
||||
autonomous: true
|
||||
@@ -163,28 +168,31 @@ All three run in parallel (Wave 1) - no dependencies, no file conflicts.
|
||||
|
||||
```yaml
|
||||
# Plan 01 - Auth foundation
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [src/lib/auth.ts, src/middleware/auth.ts]
|
||||
autonomous: true
|
||||
|
||||
# Plan 02 - Protected features (needs auth)
|
||||
wave: 2
|
||||
depends_on: ["01"]
|
||||
files_modified: [src/features/dashboard.ts]
|
||||
autonomous: true
|
||||
```
|
||||
|
||||
Plan 02 waits for Plan 01 - genuine dependency on auth types/middleware.
|
||||
Plan 02 in Wave 2 waits for Plan 01 in Wave 1 - genuine dependency on auth types/middleware.
|
||||
|
||||
**Checkpoint plan:**
|
||||
|
||||
```yaml
|
||||
# Plan 03 - UI with verification
|
||||
wave: 3
|
||||
depends_on: ["01", "02"]
|
||||
files_modified: [src/components/Dashboard.tsx]
|
||||
autonomous: false # Has checkpoint:human-verify
|
||||
```
|
||||
|
||||
Runs after Wave 1, pauses at checkpoint, orchestrator presents to user, resumes on approval.
|
||||
Wave 3 runs after Waves 1 and 2. Pauses at checkpoint, orchestrator presents to user, resumes on approval.
|
||||
|
||||
</parallel_examples>
|
||||
|
||||
@@ -289,6 +297,7 @@ See `~/.claude/get-shit-done/references/tdd.md` for TDD plan structure.
|
||||
phase: 03-features
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified: [src/features/user/model.ts, src/features/user/api.ts, src/features/user/UserList.tsx]
|
||||
autonomous: true
|
||||
@@ -347,6 +356,7 @@ After completion, create `.planning/phases/03-features/03-01-SUMMARY.md`
|
||||
phase: 03-features
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["03-01", "03-02"]
|
||||
files_modified: [src/components/Dashboard.tsx]
|
||||
autonomous: false
|
||||
@@ -446,7 +456,7 @@ files_modified: [...]
|
||||
## Guidelines
|
||||
|
||||
- Always use XML structure for Claude parsing
|
||||
- Include `depends_on`, `files_modified`, `autonomous` in every plan
|
||||
- Include `wave`, `depends_on`, `files_modified`, `autonomous` in every plan
|
||||
- Prefer vertical slices over horizontal layers
|
||||
- Only reference prior SUMMARYs when genuinely needed
|
||||
- Group checkpoints with related auto tasks in same plan
|
||||
|
||||
@@ -68,68 +68,50 @@ ls -1 "$PHASE_DIR"/*-SUMMARY.md 2>/dev/null | sort
|
||||
```
|
||||
|
||||
For each plan, read frontmatter to extract:
|
||||
- `depends_on: []` - Plan IDs this plan requires
|
||||
- `files_modified: []` - Files this plan touches
|
||||
- `wave: N` - Execution wave (pre-computed)
|
||||
- `autonomous: true/false` - Whether plan has checkpoints
|
||||
|
||||
Build plan inventory:
|
||||
- Plan path
|
||||
- Plan ID (e.g., "03-01")
|
||||
- Dependencies
|
||||
- Files modified
|
||||
- Wave number
|
||||
- Autonomous flag
|
||||
- Completion status (SUMMARY exists = complete)
|
||||
|
||||
Skip completed plans. If all complete, report "Phase already executed" and exit.
|
||||
</step>
|
||||
|
||||
<step name="analyze_dependencies">
|
||||
Build dependency graph from frontmatter:
|
||||
<step name="group_by_wave">
|
||||
Read `wave` from each plan's frontmatter and group by wave number:
|
||||
|
||||
**Direct dependencies:**
|
||||
- `depends_on: ["03-01"]` → this plan depends on 03-01
|
||||
|
||||
**File conflict dependencies:**
|
||||
- If two plans modify same file, later plan (by number) depends on earlier
|
||||
|
||||
**Build graph:**
|
||||
```bash
|
||||
# For each plan, extract wave from frontmatter
|
||||
for plan in $PHASE_DIR/*-PLAN.md; do
|
||||
wave=$(grep "^wave:" "$plan" | cut -d: -f2 | tr -d ' ')
|
||||
autonomous=$(grep "^autonomous:" "$plan" | cut -d: -f2 | tr -d ' ')
|
||||
echo "$plan:$wave:$autonomous"
|
||||
done
|
||||
```
|
||||
plan-01: {deps: [], files: [src/user.ts], autonomous: true}
|
||||
plan-02: {deps: [], files: [src/product.ts], autonomous: true}
|
||||
plan-03: {deps: ["plan-01"], files: [src/dashboard.tsx], autonomous: false}
|
||||
plan-04: {deps: ["plan-02"], files: [src/cart.ts], autonomous: true}
|
||||
plan-05: {deps: ["plan-03", "plan-04"], files: [src/checkout.ts], autonomous: true}
|
||||
|
||||
**Group plans:**
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="group_into_waves">
|
||||
Group plans into execution waves based on dependencies:
|
||||
|
||||
**Wave assignment algorithm:**
|
||||
1. Wave 1: All plans with no dependencies AND autonomous=true
|
||||
2. Non-autonomous plans with no dependencies: execute after Wave 1, before Wave 2
|
||||
3. Wave N: Plans whose dependencies are all in earlier waves
|
||||
|
||||
**Separate checkpoint plans:**
|
||||
Plans with `autonomous: false` execute in main context (not parallel subagent) to handle user interaction.
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Wave 1 (parallel): [plan-01, plan-02]
|
||||
Checkpoint: [plan-03] - has human-verify, runs in main context
|
||||
Wave 2 (parallel): [plan-04]
|
||||
Wave 3: [plan-05]
|
||||
waves = {
|
||||
1: [plan-01, plan-02],
|
||||
2: [plan-03, plan-04],
|
||||
3: [plan-05]
|
||||
}
|
||||
```
|
||||
|
||||
**No dependency analysis needed.** Wave numbers are pre-computed during `/gsd:plan-phase`.
|
||||
|
||||
Report wave structure to user:
|
||||
```
|
||||
Execution Plan:
|
||||
Wave 1 (parallel): 03-01, 03-02
|
||||
Checkpoint: 03-03 (requires user verification)
|
||||
Wave 2 (parallel): 03-04
|
||||
Wave 2 (parallel): 03-03 [checkpoint], 03-04
|
||||
Wave 3: 03-05
|
||||
|
||||
Total: 5 plans in 3 waves + 1 checkpoint
|
||||
Total: 5 plans in 3 waves
|
||||
```
|
||||
</step>
|
||||
|
||||
|
||||
@@ -367,6 +367,37 @@ For each plan, determine:
|
||||
- `autonomous: true|false` - has checkpoints requiring user interaction?
|
||||
</step>
|
||||
|
||||
<step name="assign_waves">
|
||||
**Compute wave numbers before writing plans.**
|
||||
|
||||
Wave assignment algorithm (run in memory before writing any files):
|
||||
|
||||
```
|
||||
waves = {} # plan_id -> wave_number
|
||||
|
||||
for each plan in plan_order:
|
||||
if plan.depends_on is empty:
|
||||
plan.wave = 1
|
||||
else:
|
||||
# Wave = max wave of dependencies + 1
|
||||
plan.wave = max(waves[dep] for dep in plan.depends_on) + 1
|
||||
|
||||
waves[plan.id] = plan.wave
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
Plan 01: depends_on: [] → wave: 1
|
||||
Plan 02: depends_on: [] → wave: 1
|
||||
Plan 03: depends_on: ["01"] → wave: 2
|
||||
Plan 04: depends_on: ["02"] → wave: 2
|
||||
Plan 05: depends_on: ["03", "04"] → wave: 3
|
||||
```
|
||||
|
||||
Store wave number with each plan in memory. Write to frontmatter in next step.
|
||||
</step>
|
||||
|
||||
<step name="group_into_plans">
|
||||
**Group tasks into plans based on dependency waves and autonomy.**
|
||||
|
||||
@@ -521,14 +552,15 @@ Each plan follows template structure with:
|
||||
phase: XX-name
|
||||
plan: NN
|
||||
type: execute
|
||||
depends_on: [] # Plan IDs this plan requires. Empty = Wave 1 candidate.
|
||||
files_modified: [] # Files this plan touches. Used for conflict detection.
|
||||
wave: N # Execution wave (1, 2, 3...). Computed at plan time.
|
||||
depends_on: [] # Plan IDs this plan requires.
|
||||
files_modified: [] # Files this plan touches.
|
||||
autonomous: true # false if plan has checkpoints requiring user interaction
|
||||
domain: [optional]
|
||||
---
|
||||
```
|
||||
|
||||
**Wave assignment is automatic:** `/gsd:execute-phase` reads `depends_on` to build waves. Plans with empty `depends_on` and no file conflicts run in Wave 1 (parallel).
|
||||
**Wave is pre-computed:** Wave numbers are assigned during planning (see `assign_waves` step). `/gsd:execute-phase` reads `wave` directly from frontmatter and groups plans by wave number. No runtime dependency analysis needed.
|
||||
|
||||
**Context section - parallel-aware:**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user