# How gsd-build Handles Dependencies Between Plans in Wave-Based Parallel Execution

> Learn how gsd-build handles plan dependencies during wave-based parallel execution. Discover its efficient wave assignment and parallel plan processing.

- Repository: [GSD/get-shit-done](https://github.com/gsd-build/get-shit-done)
- Tags: internals
- Published: 2026-02-16

---

**gsd-build resolves plan dependencies by assigning each plan to a wave based on the maximum wave of its dependencies plus one, then executes waves sequentially while running plans within each wave in parallel.**

The `gsd-build` orchestrator (from the `gsd-build/get-shit-done` repository) implements a deterministic **wave-based parallel execution** model that guarantees dependency order while maximizing throughput. By pre-computing wave assignments during the planning phase, the system ensures that plans only execute after all prerequisites have successfully completed.

## Understanding the Dependency Graph and Wave Assignment

During the `/gsd:plan-phase`, the orchestrator constructs a directed dependency graph from each plan's front-matter metadata. This phase determines the execution order by calculating wave numbers that reflect dependency depth.

### Parsing depends_on in the Planning Phase

The planner, defined in [`agents/gsd-planner.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-planner.md), reads the `depends_on` array from each plan's YAML front-matter. For example, a plan that requires both core utilities and CI infrastructure would declare:

```yaml
id: "02-02"
wave: 2
depends_on: ["01-01", "01-02"]
objective: "Add integration tests for feature X"

```

The planner validates that all referenced plan IDs exist in the inventory before proceeding to wave calculation.

### The Wave Calculation Algorithm

The core wave assignment algorithm appears in [`agents/gsd-planner.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-planner.md) (lines 59-67). It ensures that a plan's wave is always exactly one greater than the highest wave of its dependencies:

```typescript
waves = {}
for each plan in plan_order:
    if plan.depends_on is empty:
        plan.wave = 1
    else:
        plan.wave = max(waves[dep] for dep in plan.depends_on) + 1
    waves[plan.id] = plan.wave

```

This algorithm guarantees that **plans with no dependencies start at wave 1**, while dependent plans wait for all prerequisites to complete in earlier waves.

## Executing Plans by Wave in gsd-build

The execution phase, implemented in [`workflows/execute-phase.md`](https://github.com/gsd-build/get-shit-done/blob/main/workflows/execute-phase.md), loads the pre-computed wave assignments and orchestrates the actual plan execution.

### Loading the Plan Index

The executor loads the complete plan inventory including wave assignments in a single call:

```bash
PLAN_INDEX=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs phase-plan-index "${PHASE_NUMBER}")

```

The tool parses the JSON payload containing the `wave` field for each plan and a `waves` map that groups plan IDs by wave number (see [`workflows/execute-phase.md`](https://github.com/gsd-build/get-shit-done/blob/main/workflows/execute-phase.md), lines 50-58).

### Sequential Wave Processing

The orchestrator processes waves in strict numerical order. As documented in [`workflows/execute-phase.md`](https://github.com/gsd-build/get-shit-done/blob/main/workflows/execute-phase.md) (lines 74-78), the system iterates through waves sequentially:

```bash

# Execute each wave in sequence

for wave in $(seq 1 $MAX_WAVE); do
    execute_wave $wave
done

```

After each wave completes, the orchestrator performs spot-checks including summary existence verification, git commit validation, and self-checks before advancing. This ensures that downstream waves see a consistent, fully materialized state from upstream dependencies.

### Parallel Execution Within Waves

Within each wave, plans execute concurrently when the `PARALLELIZATION` flag is enabled. The executor spawns independent sub-agents for each plan in the current wave:

```bash
if [ "$PARALLELIZATION" = "true" ]; then
    # Run all plans in this wave in parallel

    for plan_id in "${WAVE_PLANS[@]}"; do
        spawn_executor_agent "$plan_id" &
    done
    wait
else
    # Sequential execution within wave

    for plan_id in "${WAVE_PLANS[@]}"; do
        execute_plan "$plan_id"
    done
fi

```

This approach maximizes throughput while maintaining safety. Because the wave calculation ensures that plans within the same wave have no dependencies on each other, parallel execution cannot violate dependency order.

## Validating Dependencies and Wave Consistency

Before execution begins, `gsd-build` validates the integrity of the dependency graph and wave assignments. The validation logic in [`agents/gsd-plan-checker.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-plan-checker.md) (lines 128-140) performs three critical checks:

1. **Reference existence**: Every plan ID listed in `depends_on` must exist in the plan inventory
2. **Wave consistency**: The pre-computed `wave` number must equal `max(dependency waves) + 1`
3. **Acyclic dependencies**: The dependency graph must not contain cycles that would prevent wave assignment

If validation fails, the planner raises errors immediately, preventing the execution phase from starting with invalid or inconsistent dependencies.

## Summary

- **gsd-build** assigns wave numbers based on dependency depth, ensuring plans execute only after all prerequisites complete.
- The **planning phase** ([`agents/gsd-planner.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-planner.md)) builds a directed graph from `depends_on` arrays and computes waves using `max(dependency waves) + 1`.
- The **execution phase** ([`workflows/execute-phase.md`](https://github.com/gsd-build/get-shit-done/blob/main/workflows/execute-phase.md)) processes waves sequentially while running plans within each wave in parallel when `PARALLELIZATION` is enabled.
- **Validation** ([`agents/gsd-plan-checker.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-plan-checker.md)) ensures dependency references exist and wave calculations are consistent before execution begins.

## Frequently Asked Questions

### How does gsd-build determine which wave a plan belongs to?

During the planning phase, gsd-build calculates a plan's wave by taking the maximum wave number of all its dependencies and adding one. Plans with empty `depends_on` arrays automatically receive wave 1. This algorithm, implemented in [`agents/gsd-planner.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-planner.md) (lines 59-67), ensures that a plan never executes before its prerequisites.

### Can plans in the same wave have dependencies on each other?

No. By definition, plans within the same wave have no dependencies on each other. The wave calculation algorithm guarantees that if Plan A depends on Plan B, Plan A's wave number will be strictly greater than Plan B's. This property makes it safe to execute all plans within a wave in parallel without risking race conditions or missing prerequisites.

### What happens if a plan fails during wave execution?

If a plan fails during execution, the current wave stops processing, and subsequent waves do not begin. The orchestrator performs validation checks after each wave—including summary existence verification and git commit validation—before advancing to the next wave. A failure in wave N prevents waves N+1 and higher from executing, protecting downstream plans from running with incomplete or failed prerequisites.

### Where does gsd-build validate that dependency references exist?

The [`agents/gsd-plan-checker.md`](https://github.com/gsd-build/get-shit-done/blob/main/agents/gsd-plan-checker.md) agent validates dependency references during the planning phase (lines 128-140). It verifies that every plan ID listed in a `depends_on` array exists in the plan inventory and that the pre-computed wave numbers match the calculated dependency depth. This validation occurs before the execution phase begins, preventing runtime errors from missing prerequisites.