| name | waves |
| description | Use when a plan already exists and is ready to run — dispatches each wave's tasks, reviews every return before trusting it, and gates advancement on evidence. Invoke via route or explicit command. |
waves
waves executes the task list a plan produced: wave by wave, dispatching each wave's
frontier, distrusting every report until it's checked, and gating the next wave on
evidence instead of a claim.
Runtimes and dispatch
waves runs on three runtimes. Each names one dispatch mechanism, one progress view, and
one usage reader; the detail table is in references/runtime-dispatch.md.
- Claude — Workflow or Agent tool for dispatch; TodoWrite for the progress tree; the
statusline rate-limit cache as the usage reader.
- Codex — subagents for dispatch (the AGENT-BRIEF is the dispatch prompt: spawn one
agent per brief, wait for all, return a summary;
/agent to inspect); task view for
the progress tree; usage reader N/A.
- Antigravity —
start_subagent for dispatch (dynamic subagents, isolated context,
parallel); agent view for the progress tree; usage reader N/A.
Antigravity returns are reviewable code diffs
On Antigravity, subagent returns surface as native reviewable code diffs. Two binding
rules: the EV/memory-progress.md ledger is still written (a diff is not evidence),
and the hard gate is not skipped by an "Always Proceed" policy — review the diff against
the brief's acceptance criteria before marking the task complete.
Dispatch procedure
For each task in the wave's frontier:
- Write the brief from
references/agent-brief-template.md, filled in for this task:
base SHA, write-scope, acceptance criteria, seams, and test list, taken from the plan.
Write the filled brief to <repo>/docs/briefs/<task-id>-brief.md. Briefs are
gitignored by default — the plan is the durable source and the brief is derived from
it; a repo's config may flip this to committed via a ## Briefs line in
docs/agents/galdr.md. Writing brief files happens before dispatch, so it precedes
the in-flight window; once any dispatch is out, the git-discipline rule below applies
as written.
- Before dispatching, append a WIP dispatch line to memory-progress.md (continue skill
format):
**WIP** dispatched <brief path> @<base sha> scope=<paths> — next: review on return.
- Dispatch with the declared write-scope as the only paths the subagent may touch.
- On return, run the two-verdict review below before acting on anything the report
claims.
Two-verdict review — distrust the report
A subagent's report is a claim, not evidence. Do not act on it as-is.
- Do not accept "tests pass," "all done," or an equivalent report without reading the
diff yourself.
- Do not run code-quality review before spec compliance — order matters, and skipping
the first step to get to the second hides missing scope.
- Do not skip running the gate commands yourself because the report says they were run.
Order, every time:
- Spec compliance first — check the diff against the brief's acceptance criteria,
checkbox by checkbox. Quote the criterion for every gap found.
- Code quality second — only once spec compliance passes.
Severity: Critical findings are fixed now (before complete); Important before the
next task — mirroring review's branch-level severity gate.
Status contract
Every dispatch returns exactly one of four statuses:
complete — acceptance criteria met, gates green, commits made.
blocked — cannot proceed on its own.
needs-decision — a choice only the controller or user can make.
failed — attempted and did not succeed.
blocked and needs-decision carry the ⚠️ escalation payload, all three parts, every
time:
- What was tried.
- What's needed to unblock or decide.
- One recommendation — a single option with brief reasoning, not a menu.
Model tiers
- Mechanical tasks (brief marked
mechanical: true) → haiku.
- Standard implementation and per-task review → sonnet.
- Planning, wave-gate review, and debug → the session model.
Failure escalation at a single task:
- First failure: retry on the same tier.
- Second failure at the same task: escalate one model tier, retry once.
- Third failure at the same task: stop the wave. This is one of the four STOP
conditions below — the escalation path ends here, at two tries.
Tier→model-id bindings (which literal model haiku/sonnet/session map to) are read from
the repo's docs/agents/galdr.md config, written by setup; defaults are named in setup
itself (task 3.4), not here — models change, skill text shouldn't.
Proportional review
Review depth follows the brief's own classification, not a fixed ceremony:
- Brief marked
mechanical: true: diff sanity check only — read the diff, confirm it
does the small thing it claims, run the gates.
- Everything else: the full two-verdict review above.
Wave gate
Before opening the next wave:
- Run the verify skill against the full gate manifest — not the in-task tiered
cadence, the full suite.
- Run one refactor pass across the wave's tests. Refactoring belongs here, at the wave
gate — the task's TDD loop stops at green.
- Write the EV line for every gate command run, plus a wave-level status line, to
memory-progress.md, and print the usage report (below) in your response to the
user — the ledger line and the printed report are both required; neither substitutes
for the other.
A wave gate that produced no EV lines has not happened, regardless of what the dispatch
reports said. Defer a task to a later cycle? Append it to the backlog per /galdr:backlog
(skills/backlog/SKILL.md).
Live progress table
The plan's ## Progress table (format in skills/plan/SKILL.md) is a derived view
waves maintains — never hand-edited; memory-progress.md stays the durable state:
- Wave open — mark the wave's frontier tasks
in-progress.
- Wave gate — regenerate the whole table from
memory-progress.md.
- First dispatch of the run — advance the spec's
Lifecycle status: line to
in-progress.
Both table writes happen only at points the controller may already write the repo (wave
open, wave gate) — never while a dispatch is in flight.
Native progress tree
Alongside the plan table, waves keeps a native progress list mirroring the plan's tasks
(per-runtime mechanism in references/runtime-dispatch.md). Seed one pending entry
per task at run start; flip a wave's frontier tasks to in_progress at wave open; set
each to its final status at the wave gate. The native tree is an ephemeral mirror —
memory-progress.md stays the only durable state.
Usage and token report
At each wave gate and at run end, waves prints this report in its response to the
user — a memory-progress.md EV line records the same numbers for the ledger but does
not, on its own, satisfy this; the user sees the block itself, every time, not a
summary folded into other text. Reports together:
- Tokens — spent this wave plus running cumulative, summed from each dispatch
return's usage in the wave.
- Usage limits (Claude only) — the real 5h and 7d
used_percentage, the 5h reset
time, and each line's pp delta since the run's last report (omitted on the first) —
from the rate-limit reader below. Label as usage-limit percentages, not cost. On
Codex and Antigravity the usage reader is N/A — report tokens only.
When the cache is unavailable, report tokens only plus "for your limit %, run
/usage". Exact report layout: references/progress-and-usage.md.
Continuous execution
Waves run back-to-back with no pause for permission between them. Stop only on one of
these four conditions (verbatim from spec §6):
- Blocked with a ⚠️ the controller cannot resolve.
- A plan contradiction is discovered.
- Third failure at the same task (after the two-failure escalation above has already
been used).
- User interrupt.
No other reason pauses a wave. "This feels like a good stopping point" is not one of
the four.
Rate-limit reader (Claude)
waves reads real usage from the file at the rate-limits-cache key (## Budget section
of docs/agents/galdr.md, written by setup — cite the config, never a literal path). It
parses five_hour.used_percentage, seven_day.used_percentage, resets_at, and
cached_at. The Claude statusline writes this file; galdr never queries an API. This
reader is Claude-only (N/A on Codex and Antigravity). Treat the data as unavailable
— never error, never block — when the file is missing or when cached_at is older than
the rate-limits-max-age key (seconds). Exact read, staleness, and fallback steps:
references/progress-and-usage.md.
Pre-dispatch budget guard
Before each not-yet-started dispatch, waves may park instead of dispatching. Three
triggers:
- Usage limit warning — a usage limit warning appears this session.
- User says "park it".
- Quota threshold (Claude only) — the rate-limit reader shows
five_hour.used_percentage at or above the five-hour-park-pct key, or
seven_day.used_percentage at or above the seven-day-park-pct key (## Budget
section — cite the config, never a literal). This trigger depends on the statusline
rate-limit cache, so it is Claude-only; on Codex and Antigravity it is inactive. The
other two triggers above apply on all runtimes.
Park is graceful: in-flight dispatches always finish — reviewed, gated, committed —
before the next dispatch parks; never interrupt one in flight.
On park, waves emits one inline line naming the wave and task it parked at plus "run
/galdr:continue after your limit resets". The durable resume header is written by
continue's limit-park (skills/continue/SKILL.md §6), not here.
Git discipline
- Subagents commit their own work as they reach each green pair — the controller does
not hold their changes and batch-commit at the end. A task returns
complete only
with its commits already made (status contract above); uncommitted work is not done.
- Subagents commit only inside their declared write-scope. Never outside it, even for a
one-line fix noticed in passing — report it instead of touching it.
- Subagents never push. Subagents never open a pull request. No exceptions.
- While any dispatched agent is in flight in a repo, the controller performs no git
operations in that repo — no commits, no checkouts, no merges — until every dispatch
in the wave has returned. This rule keeps the controller from colliding with the
subagents' own commits; it is not a reason to defer committing to the end.
Research-brief variant
When a task is a research task rather than an implementation task, its brief adds:
- Primary-source ownership — cite the primary source itself, not a summary of it,
wherever a primary source exists.
- Per-claim citation — every claim in the returned artifact carries its source
inline, not gathered into a bibliography at the end.
- Artifact committed to the repo — the research output is a file committed at a
path the write-scope names, not left only in the subagent's transcript.
Dispatch, the status contract, and the review gate all apply unchanged.
Reference
references/agent-brief-template.md — the brief template every dispatch fills in
before it goes out.
references/progress-and-usage.md — the exact rate-limit cache read, staleness and
fallback logic, and the gate/run-end usage report layout.
references/runtime-dispatch.md — the per-runtime dispatch, progress-tree, and
usage-reader detail table.