Parent Epic
Part of #52 — Parallel stacked workstreams
Summary
Implement a wave-based task scheduler that runs independent tasks in parallel and waits for dependencies to complete before starting dependent tasks. Respects a configurable concurrency limit.
Context
When an epic has N sub-issues, some can run in parallel (independent) while others must wait (dependent on a previous task's completion). The scheduler determines which tasks to start and when.
Example with 4 sub-issues where #2 depends on #1, and #3/#4 are independent:
Wave 1: #1, #3, #4 (3 worktrees, 3 parallel agents)
Wave 2: #2 (starts after #1 reaches COMPLETE)
Changes
New: scheduler.py (or in orchestrator.py)
EpicScheduler class that takes an epic_id and manages task lifecycle
get_ready_tasks() — returns tasks whose dependencies are all COMPLETE
get_running_tasks() — returns tasks currently in non-terminal, non-INIT states
run() — main loop:
- Get ready tasks (dependencies satisfied)
- Filter to
max_parallel_tasks concurrency limit
- Launch ready tasks (create worktree, start tmux session)
- Poll task states periodically
- When a task completes, check if new tasks become ready
- When all tasks complete or any task fails (configurable), stop
config.py
- Add
max_parallel_tasks (int, default 3) to DEFAULTS
- Add validation: must be >= 1
persistence.py
- Use
get_epic_tasks() and get_dependent_tasks() from the schema sub-issue
Depends On
Design Decisions
- Fail-fast vs. continue: When one task fails, should sibling tasks continue? Default: continue (independent tasks aren't affected by a sibling's failure). Dependent tasks pause.
- Concurrency:
max_parallel_tasks caps how many agents run simultaneously. Respects system resources.
- Polling interval: Scheduler checks task states every 5 seconds (fast enough to detect completions, low overhead).
Testing
- 3 independent tasks → all start in wave 1
- Task with dependency → waits until parent is COMPLETE
- Concurrency limit respected (max 2 → only 2 tasks run at once)
- Parent task fails → dependent task stays in INIT, independent tasks continue
- All tasks complete → scheduler exits cleanly
Parent Epic
Part of #52 — Parallel stacked workstreams
Summary
Implement a wave-based task scheduler that runs independent tasks in parallel and waits for dependencies to complete before starting dependent tasks. Respects a configurable concurrency limit.
Context
When an epic has N sub-issues, some can run in parallel (independent) while others must wait (dependent on a previous task's completion). The scheduler determines which tasks to start and when.
Example with 4 sub-issues where #2 depends on #1, and #3/#4 are independent:
Changes
New:
scheduler.py(or inorchestrator.py)EpicSchedulerclass that takes an epic_id and manages task lifecycleget_ready_tasks()— returns tasks whose dependencies are all COMPLETEget_running_tasks()— returns tasks currently in non-terminal, non-INIT statesrun()— main loop:max_parallel_tasksconcurrency limitconfig.pymax_parallel_tasks(int, default 3) to DEFAULTSpersistence.pyget_epic_tasks()andget_dependent_tasks()from the schema sub-issueDepends On
parent_task_id,epic_idcolumns (sub-issue)Design Decisions
max_parallel_taskscaps how many agents run simultaneously. Respects system resources.Testing