Waves
Waves are groups of streams that execute in parallel. orchex automatically computes waves from the dependency graph using topological sort — you define dependencies, orchex figures out the optimal execution order.
How Waves Work
orchex analyzes the dependency graph and assigns each stream to a wave:
- Wave 1 — All streams with no dependencies (they can run simultaneously)
- Wave 2 — Streams whose dependencies all completed in Wave 1
- Wave N — Streams whose dependencies all completed in previous waves
Each wave must complete (all streams pass verification) before the next wave starts.
Example
Streams and their dependencies:
A (no deps) ─┐
B (no deps) ─┤── Wave 1 (3 streams in parallel)
C (no deps) ─┘
D (deps: [A]) ─┐
E (deps: [B,C]) ─┘── Wave 2 (2 streams in parallel)
F (deps: [D,E]) ──── Wave 3 (1 stream)orchex executes A, B, and C simultaneously in Wave 1. When all three finish and pass verification, D and E run in parallel in Wave 2. Finally, F runs alone in Wave 3.
Without Waves (Serial)
[A] → [B] → [C] → [D] → [E] → [F] (6 sequential steps)With Waves (Parallel)
Wave 1: [A] [B] [C] (parallel)
Wave 2: [D] [E] (parallel)
Wave 3: [F]6 streams in 3 waves instead of 6 sequential steps — up to 2x faster in this example. With more independent streams, the speedup grows.
Wave Properties
- Wave number — Sequential index starting at 1
- Parallelism — All streams in a wave execute simultaneously
- No intra-wave deps — No stream depends on another stream in the same wave
- Blocking — A wave must complete before the next starts
- Verification — Each stream's
verifycommands run at the end of its execution, before the wave is considered complete
Execution Modes
orchex supports three execution modes:
| Mode | Behavior | Use Case |
|---|---|---|
wave |
Execute one wave and return | Step through waves manually, inspect results between waves |
auto |
Execute all waves sequentially until done | Hands-off execution |
dry_run |
Show wave plan without executing | Preview the execution plan |
// Step through one wave at a time
orchex.execute({ mode: "wave" });
// Run everything
orchex.execute({ mode: "auto" });
// Just see the plan
orchex.execute({ dry_run: true });Why Waves Matter
Speed
Parallel execution is orchex's primary value. A 10-stream feature with 3 waves completes in the time of 3 sequential tasks, not 10.
Safety Boundaries
Each wave boundary is a checkpoint. If a stream in Wave 2 fails, Wave 1's work is already committed. Self-healing only retries the failed stream, not the entire orchestration.
Context Propagation
Streams in later waves can reference the output of earlier waves. When Wave 1's auth-types stream creates src/types/auth.ts, Wave 2's auth-middleware stream sees the actual file contents in its context — not a plan, but the real code.
Rate Limit Distribution
If you configure multiple LLM providers, orchex distributes parallel streams across providers. One provider rate-limiting doesn't block streams running on other providers.
Dependency Optimization
Minimize Dependency Chains
Long dependency chains create sequential bottlenecks. Only add dependencies when a stream truly needs another stream's output.
# Bad: Artificial linear chain (4 waves)
streams:
task-1: { deps: [] }
task-2: { deps: ["task-1"] } # Does task-2 really need task-1?
task-3: { deps: ["task-2"] }
task-4: { deps: ["task-3"] }
# Good: Independent tasks (1 wave)
streams:
task-1: { deps: [] }
task-2: { deps: [] }
task-3: { deps: [] }
task-4: { deps: [] }Declare Only True Dependencies
A dependency exists only if Stream B requires Stream A's output or side effects.
# Bad: False dependency
update-readme: { deps: [] }
add-tests: { deps: ["update-readme"] } # Tests don't need the README
# Good: Independent tasks
update-readme: { deps: [] }
add-tests: { deps: [] }Avoid Redundant Dependencies
If A depends on B, and B depends on C, then A implicitly depends on C. Don't list C in A's deps.
# Bad: Redundant
base: { deps: [] }
middle: { deps: ["base"] }
top: { deps: ["base", "middle"] } # "base" is redundant
# Good: Minimal
base: { deps: [] }
middle: { deps: ["base"] }
top: { deps: ["middle"] } # Implies baseCommon Patterns
Fork-Join
Setup → parallel features → integration:
[setup]
↓ ↓ ↓
[A] [B] [C] ← Wave 2 (parallel)
↓ ↓ ↓
[integration] ← Wave 3Diamond
Multiple paths converge on one output:
[database]
↓ ↓
[users] [products] ← Wave 2 (parallel)
↓ ↓
[checkout] ← Wave 3Independent Pipelines
Two unrelated feature pipelines run in parallel:
[auth-types] [billing-types] ← Wave 1 (parallel)
↓ ↓
[auth-api] [billing-api] ← Wave 2 (parallel)
↓ ↓
[auth-tests] [billing-tests] ← Wave 3 (parallel)Anti-Patterns
The Monolith Stream
One giant stream that should be split into waves:
# Bad: One stream does everything
do-everything:
owns: ["src/types.ts", "src/api.ts", "src/routes.ts", "tests/api.test.ts"]
plan: "Create types, implement API, add routes, write tests"Split into streams with proper dependencies for parallelism and manageable scope.
Premature Convergence
Forcing parallel work to synchronize unnecessarily:
# Bad: Unnecessary checkpoint
feature-a-step-1: { deps: [] }
feature-b-step-1: { deps: [] }
checkpoint: { deps: ["feature-a-step-1", "feature-b-step-1"] } # Why?
feature-a-step-2: { deps: ["checkpoint"] }
feature-b-step-2: { deps: ["checkpoint"] }If A and B are independent pipelines, let them complete independently.
Tier Limits
Wave count is subject to tier limits:
| Tier | Max Waves |
|---|---|
| Local (Free) | 2 |
| Pro | 10 |
| Team | 25 |
| Enterprise | Unlimited |
orchex warns you when your wave count approaches the tier limit (at 80% or above).
Related
- Streams — The individual tasks within waves
- Ownership — Why file ownership matters across parallel streams
- Wave Planning (Advanced) — Optimization strategies and metrics
- orchex learn — Automatic wave inference from plan documents