Skip to main content
Version: latest

waves

kasmos lifecycle: optional planner drafts feed the architect, then coder waves, review and fix loop, readiness, and done.

Waves are the parallel execution unit in kasmos. A multi-wave plan runs wave 1 to completion, then wave 2, and so on. All tasks within a single wave run concurrently as separate agent instances on isolated git worktrees.

wave execution flow

the following diagram shows the high-level wave execution lifecycle — from plan content through architect elaboration, parallel coder waves, and into the review/verify pipeline:

wave orchestration states

The orchestration.WaveOrchestrator in orchestration/engine.go tracks five states:

statevaluemeaning
WaveStateIdle0not started; waiting for the first StartNextWave() call
WaveStateElaborating1architect agent is enriching task bodies before execution begins
WaveStateRunning2current wave's tasks are running
WaveStateWaveComplete3all tasks in the current wave resolved; awaiting user confirmation to advance
WaveStateAllComplete4all waves finished
Idle
├─ SetElaborating() ──► Elaborating
│ └─ UpdatePlan() ──► Idle
└─ StartNextWave() ──► Running
├─ tasks complete ──► WaveComplete (if more waves remain)
│ └─ user confirms ──► Running (next wave)
└─ all tasks complete ──► AllComplete

elaboration phase

Before wave 1 begins, kasmos optionally runs an architect agent to decompose the plan into coder-ready task bodies. While elaboration is in progress, the orchestrator moves to WaveStateElaborating. StartNextWave() returns nil in this state — no tasks are launched until UpdatePlan() is called with the enriched plan.

When elaboration completes, UpdatePlan() replaces the plan and resets the orchestrator to WaveStateIdle so waves can begin.

Planning can either use the legacy single-planner path or a configured planner list:

  1. when [orchestration].planners is unset or empty, the planner writes the task store and emits planner_finished
  2. when [orchestration].planners = ["planner_opus", "planner_gpt"] is set, plan start clears stale .kasmos/cache/<planSlug>-planner-<profile>.md caches, spawns each listed profile in draft mode, and lets the first listed planner update the task store as a preview
  3. draft-mode planners emit gateway-only planner_draft_finished signals with {"planner_id":"<profile>"} payloads
  4. the processor aggregates those draft signals and internally advances planning once every expected profile has reported
  5. the final architect reads the task-store plan plus planner draft caches, derives its own baseline inline, writes the final task-store plan, and records consumed drafts in decision_audit.planner_drafts
  6. coder waves proceed normally

The final architect metadata is written to .kasmos/cache/<task>-architect.json. That file may include an optional, schema-versioned decision_audit object with the planner-draft comparison and final decision. hq shows an architect decisions tab on task detail pages when audit metadata is available.

wave confirmation

When a wave completes, kasmos shows a confirmation dialog before advancing to the next wave. This gives you a chance to review what was done and abort if something went wrong. NeedsConfirm() returns true once per completion — calling it marks the dialog as shown. If you cancel, ResetConfirm() re-arms the latch so the dialog reappears.

blueprint skip (single-agent mode)

For small tasks, wave orchestration adds unnecessary overhead. ShouldBlueprintSkip in orchestration/engine.go returns true when the total number of tasks across all waves is at or below the configured threshold:

func ShouldBlueprintSkip(plan *taskparser.Plan, threshold int) bool {
if plan == nil || threshold <= 0 {
return false
}
total := 0
for _, wave := range plan.Waves {
total += len(wave.Tasks)
}
return total <= threshold
}

Configure this in .kasmos/config.toml:

[orchestration]
blueprint_skip_threshold = 2

When blueprint skip is active, the task goes directly to a single coder agent — no elaboration, no wave confirmation dialogs.

task statuses within a wave

Each task in a wave tracks its own state:

statemeaning
taskPendingallocated but not yet started
taskRunningagent is executing
taskCompleteagent finished successfully
taskFailedagent exited with an error

Failed tasks do not block the wave from completing — other tasks continue. Once all tasks in a wave have resolved (either complete or failed), the wave transitions to WaveStateWaveComplete. You can retry failed tasks with RetryFailedTasks().

subtask persistence

Task states within a wave are persisted to the task store via store.UpdateSubtaskStatus, so the TUI can display accurate per-task status even after a restart. The orchestrator is restored via RestoreToWave(), which fast-forwards to the target wave and re-applies saved task states.

file conflict detection

The architect agent produces metadata that lists which files each task intends to modify. DetectFileConflicts() checks for files claimed by multiple tasks in the same wave and surfaces them as warnings in the TUI, helping you spot potential merge conflicts before they happen.