Bursts & Waves
Concepts
Section titled “Concepts”| Term | Definition |
|---|---|
| Bead | A unit of work tracked by Beads.Keeper (SQLite). Has an ID, status, type, priority, labels, dependencies. |
| Pipeline | An ordered sequence of psychonaut stages that process a bead. Stages can be sequential or fan-out. |
| BeadRun | One bead + its pipeline execution. Tracks current stage, agent statuses, results, and assumptions. |
| Burst | A set of BeadRuns kicked off from ready beads. All execute concurrently. |
| Wave | Repeated bursts until no ready beads remain. Closing beads can unblock others. |
Burst.Manager State Machine
Section titled “Burst.Manager State Machine”The Burst.Manager is a deterministic GenServer (not an LLM psychonaut) with a 5-phase state machine:
:idle --> :collecting --> :running --> :draining --> :collecting (next burst) \-> :done --> :idle (no more beads)Phase Details
Section titled “Phase Details”:idle — Waiting for start_wave/1. Opens a session for JSONL logging.
:collecting — Queries Keeper.ready/1 for unblocked beads. For each bead:
- Fetches full bead data via
Keeper.show/2 - Matches against pipeline recipes via
Keeper.match_pipeline/2 - Falls back to default pipeline if no match
- Creates a
BeadRunstruct - Marks bead as
:in_progress
Safety: max 100 bursts per wave to prevent infinite loops.
:running — Spawns agents for the first stage of each BeadRun. Monitors all spawned processes. Handles:
:agent_donemessages with results:DOWNmessages for crashes- Stage advancement logic (sequential chaining or fan-out completion)
:draining — All BeadRuns have reached terminal status. For each:
:donebeads: callsKeeper.close_bead/3:errorbeads: adds failure comment viaKeeper.add_comment/4, resets status to:open
Computes wave stats, broadcasts {:burst_complete, info}, transitions to :collecting for the next burst.
:done — Keeper.ready/1 returned empty. Logs wave summary, broadcasts {:wave_complete, stats}, closes session, returns to :idle.
Wave Execution
Section titled “Wave Execution”Waves keep running until br ready returns empty:
Wave 1: Burst 1: [bead-42 (frontend), bead-43 (backend)] --> both complete Burst 2: [bead-44 (was blocked by 42)] --> completes Burst 3: [br ready returns empty] --> wave doneBeadRun
Section titled “BeadRun”A BeadRun is a passive data structure tracking a bead through its pipeline:
%Annihilation.Burst.BeadRun{ bead_id: 42, bead_data: %{title: "...", labels: ["frontend"]}, pipeline: %Pipeline{name: "default", stages: [...]}, current_stage: 0, stage_agents: %{"42_s0_coder" => :running}, # agent_id => status stage_results: %{"42_s0_coder" => "..."}, # agent_id => result text completed_stages: [%{stage_index: 0, results: %{...}}], status: :running, # :pending | :running | :done | :error assumptions: [], # Recorded drifts during this run started_at: ~U[...], completed_at: nil, error_reason: nil}Stage Advancement
Section titled “Stage Advancement”When an agent completes, StageExecutor.stage_status/1 determines what happens:
:in_progress— agents still running, wait:all_succeeded— advance to next stage or mark done:has_failures— mark BeadRun as error:sequential_blocked— a sequential agent failed, chain broken
For fan-out stages, all agents must complete before the stage is evaluated. For sequential stages, agents run one at a time — each receives the prior agent’s output threaded into its context.
StageExecutor
Section titled “StageExecutor”StageExecutor prepares spawn configs without actually spawning processes:
Fan-Out Preparation
Section titled “Fan-Out Preparation”StageExecutor.prepare_fan_out(bead_run, stage_config)# Returns: [%{agent_id: "42_s0_security", agent_template: ..., context: "...", ...}, ...]All agents receive identical accumulated context from previous stages and run concurrently.
Sequential Preparation
Section titled “Sequential Preparation”StageExecutor.prepare_sequential_first(bead_run, stage_config)# Returns: %{agent_id: "42_s0_coder", ...}
StageExecutor.prepare_sequential_next(bead_run, stage_config, prior_result)# Returns: %{agent_id: "42_s0_reviewer", context: "...prior output...", ...}Each sequential agent receives the prior agent’s result appended to the base context.
Context Threading
Section titled “Context Threading”Agents receive accumulated output from all previous stages:
## Stage 0 Results
### Agent: 42_s0_orchestrator[orchestrator's plan]
## Stage 1 Results
### Agent: 42_s1_coder[coder's implementation]Results are truncated at 10,000 characters per agent to prevent context overflow.
Who Controls Bead Status
Section titled “Who Controls Bead Status”Only Burst.Manager modifies bead status. Individual psychonauts never call Keeper.close or Keeper.update directly:
- Psychonauts do their work (code, test, review)
- Agent completes -> result sent to Burst.Manager via
:agent_donemessage - All pipeline stages pass -> Burst.Manager calls
Keeper.close_bead/3 - Stage fails -> bead stays open, failure logged as comment