@chllming/wave-orchestration 0.8.9 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/README.md +135 -18
- package/docs/README.md +9 -3
- package/docs/architecture/README.md +1498 -0
- package/docs/concepts/context7-vs-skills.md +1 -1
- package/docs/concepts/operating-modes.md +3 -3
- package/docs/concepts/what-is-a-wave.md +1 -1
- package/docs/guides/author-and-run-waves.md +27 -4
- package/docs/guides/monorepo-projects.md +226 -0
- package/docs/guides/planner.md +10 -3
- package/docs/guides/{recommendations-0.8.9.md → recommendations-0.9.1.md} +8 -7
- package/docs/guides/sandboxed-environments.md +158 -0
- package/docs/guides/terminal-surfaces.md +14 -12
- package/docs/plans/current-state.md +11 -7
- package/docs/plans/end-state-architecture.md +3 -1
- package/docs/plans/examples/wave-example-design-handoff.md +3 -1
- package/docs/plans/examples/wave-example-live-proof.md +6 -1
- package/docs/plans/examples/wave-example-rollout-fidelity.md +2 -0
- package/docs/plans/migration.md +48 -18
- package/docs/plans/sandbox-end-state-architecture.md +153 -0
- package/docs/plans/wave-orchestrator.md +4 -4
- package/docs/reference/cli-reference.md +125 -57
- package/docs/reference/coordination-and-closure.md +1 -1
- package/docs/reference/github-packages-setup.md +1 -1
- package/docs/reference/migration-0.2-to-0.5.md +9 -7
- package/docs/reference/npmjs-token-publishing.md +53 -0
- package/docs/reference/npmjs-trusted-publishing.md +4 -50
- package/docs/reference/package-publishing-flow.md +272 -0
- package/docs/reference/runtime-config/README.md +140 -12
- package/docs/reference/sample-waves.md +100 -5
- package/docs/reference/skills.md +1 -1
- package/docs/reference/wave-control.md +23 -5
- package/docs/roadmap.md +43 -201
- package/package.json +1 -1
- package/releases/manifest.json +38 -0
- package/scripts/wave-orchestrator/adhoc.mjs +49 -17
- package/scripts/wave-orchestrator/agent-process-runner.mjs +344 -0
- package/scripts/wave-orchestrator/agent-state.mjs +0 -1
- package/scripts/wave-orchestrator/artifact-schemas.mjs +7 -0
- package/scripts/wave-orchestrator/autonomous.mjs +96 -29
- package/scripts/wave-orchestrator/benchmark-external.mjs +23 -7
- package/scripts/wave-orchestrator/benchmark.mjs +33 -10
- package/scripts/wave-orchestrator/closure-engine.mjs +138 -17
- package/scripts/wave-orchestrator/config.mjs +239 -24
- package/scripts/wave-orchestrator/control-cli.mjs +71 -28
- package/scripts/wave-orchestrator/coord-cli.mjs +22 -14
- package/scripts/wave-orchestrator/coordination-store.mjs +8 -0
- package/scripts/wave-orchestrator/dashboard-renderer.mjs +123 -44
- package/scripts/wave-orchestrator/dep-cli.mjs +47 -21
- package/scripts/wave-orchestrator/derived-state-engine.mjs +6 -3
- package/scripts/wave-orchestrator/feedback.mjs +28 -11
- package/scripts/wave-orchestrator/gate-engine.mjs +106 -38
- package/scripts/wave-orchestrator/human-input-resolution.mjs +5 -1
- package/scripts/wave-orchestrator/install.mjs +13 -0
- package/scripts/wave-orchestrator/launcher-progress.mjs +91 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +179 -68
- package/scripts/wave-orchestrator/launcher.mjs +222 -53
- package/scripts/wave-orchestrator/ledger.mjs +7 -2
- package/scripts/wave-orchestrator/planner.mjs +48 -27
- package/scripts/wave-orchestrator/project-profile.mjs +31 -8
- package/scripts/wave-orchestrator/projection-writer.mjs +13 -1
- package/scripts/wave-orchestrator/proof-cli.mjs +18 -12
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +6 -0
- package/scripts/wave-orchestrator/retry-cli.mjs +19 -13
- package/scripts/wave-orchestrator/retry-control.mjs +3 -3
- package/scripts/wave-orchestrator/retry-engine.mjs +93 -6
- package/scripts/wave-orchestrator/role-helpers.mjs +30 -0
- package/scripts/wave-orchestrator/session-supervisor.mjs +94 -85
- package/scripts/wave-orchestrator/shared.mjs +77 -14
- package/scripts/wave-orchestrator/supervisor-cli.mjs +1306 -0
- package/scripts/wave-orchestrator/terminals.mjs +12 -32
- package/scripts/wave-orchestrator/tmux-adapter.mjs +300 -0
- package/scripts/wave-orchestrator/wave-control-client.mjs +84 -16
- package/scripts/wave-orchestrator/wave-files.mjs +43 -6
- package/scripts/wave.mjs +13 -0
|
@@ -0,0 +1,1498 @@
|
|
|
1
|
+
# Wave Orchestration Architecture
|
|
2
|
+
|
|
3
|
+
This document is a detailed, ground-truth architecture reference for Wave Orchestration.
|
|
4
|
+
It is derived from reading every source module, test file, configuration surface, and design document in the repository.
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
|
|
8
|
+
1. [Project Purpose and Design Philosophy](#1-project-purpose-and-design-philosophy)
|
|
9
|
+
2. [System Overview](#2-system-overview)
|
|
10
|
+
3. [Canonical Authority Model](#3-canonical-authority-model)
|
|
11
|
+
4. [Module Architecture](#4-module-architecture)
|
|
12
|
+
5. [Wave Execution Lifecycle](#5-wave-execution-lifecycle)
|
|
13
|
+
6. [Coordination and Blackboard Model](#6-coordination-and-blackboard-model)
|
|
14
|
+
7. [Gate Evaluation and Proof Model](#7-gate-evaluation-and-proof-model)
|
|
15
|
+
8. [Closure Sweep: How Waves Actually Close](#8-closure-sweep-how-waves-actually-close)
|
|
16
|
+
9. [Retry and Recovery](#9-retry-and-recovery)
|
|
17
|
+
10. [Run-State Reconciler](#10-run-state-reconciler)
|
|
18
|
+
11. [Sandbox Supervisor Model](#11-sandbox-supervisor-model)
|
|
19
|
+
12. [Runtime Abstraction and Executor Adapters](#12-runtime-abstraction-and-executor-adapters)
|
|
20
|
+
13. [Skills, Context7, and Compiled Context](#13-skills-context7-and-compiled-context)
|
|
21
|
+
14. [Entity Model](#14-entity-model)
|
|
22
|
+
15. [Artifact Hierarchy](#15-artifact-hierarchy)
|
|
23
|
+
16. [Telemetry and Wave Control](#16-telemetry-and-wave-control)
|
|
24
|
+
17. [CLI Surface Map](#17-cli-surface-map)
|
|
25
|
+
18. [Research Grounding](#18-research-grounding)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Project Purpose and Design Philosophy
|
|
30
|
+
|
|
31
|
+
### What Wave Is
|
|
32
|
+
|
|
33
|
+
Wave Orchestration is a framework for structured, multi-agent repository work. It replaces ad-hoc "vibe coding" sessions with a system where planning, coordination, evidence, proof, and closure are all explicit and machine-inspectable. The core thesis is that agentic coding is fast but fragile: agents hallucinate completion, coordination collapses at scale, and there is no trustworthy record of what actually happened. Wave makes all of those failure modes visible and addressable.
|
|
34
|
+
|
|
35
|
+
Wave is the orchestration substrate for **LEAP-claw**, the proprietary agent framework built on top of Wave's coordination, proof, and closure model. LEAP-claw agents operate through Wave's runtime abstraction, using Wave's canonical authority set, blackboard coordination, and proof-bounded closure while adding proprietary planning, reasoning, and execution strategies. Wave provides the runtime and coordination guarantees; LEAP-claw provides the agent intelligence.
|
|
36
|
+
|
|
37
|
+
The framework is **not** a chat wrapper or a prompt library. It is a runtime orchestrator that:
|
|
38
|
+
|
|
39
|
+
- Parses structured wave definitions from markdown
|
|
40
|
+
- Launches multiple coding agents in parallel across different LLM runtimes (Codex, Claude, OpenCode, LEAP-claw)
|
|
41
|
+
- Coordinates them through shared canonical state (not chat messages)
|
|
42
|
+
- Evaluates structured proof of completion through a multi-stage gate stack
|
|
43
|
+
- Closes waves only when all declared goals, proof artifacts, and closure stewards agree
|
|
44
|
+
|
|
45
|
+
### Design Principles
|
|
46
|
+
|
|
47
|
+
1. **Canonical authority set, not a single event log.** Three append-only sources of truth (wave definitions, coordination log, control-plane log) replace a single monolithic state store. Each is authoritative over a different domain.
|
|
48
|
+
|
|
49
|
+
2. **Phase engines replace a monolithic launcher.** Each concern (implementation selection, state derivation, gate evaluation, retry planning, closure sequencing) is a separate module with explicit inputs and outputs. The launcher is a thin orchestrator that wires them together.
|
|
50
|
+
|
|
51
|
+
3. **Planning engines emit intent; the supervisor emits facts.** The implementation engine says "launch agent A1"; the session supervisor records that A1 actually started at time T. This separation is critical for replay.
|
|
52
|
+
|
|
53
|
+
4. **Proof and closure are separate states.** An agent's owned slice can be proven (`owned_slice_proven`) without the wave being closure-ready (`wave_closure_ready`). Closure requires all cross-cutting conditions to also pass.
|
|
54
|
+
|
|
55
|
+
5. **Tasks are first-class entities.** Work units have ownership, leases, artifact contracts, dependency edges, and explicit closure state machines, not just "agent finished" flags.
|
|
56
|
+
|
|
57
|
+
6. **Retry is a dedicated deterministic subsystem.** Retry decisions are computed from stored state by pure functions, testable without launching any processes.
|
|
58
|
+
|
|
59
|
+
7. **Structured result envelopes replace log parsing.** Agents write typed JSON envelopes with a common header and role-specific payloads. Gates read envelopes, not log text.
|
|
60
|
+
|
|
61
|
+
8. **One strict artifact hierarchy.** Every artifact is classified as canonical event, structured snapshot, derived cache, or human-facing projection. Decision logic never reads projections.
|
|
62
|
+
|
|
63
|
+
9. **Replay is first-class.** A single reducer path (`wave-state-reducer.mjs`) rebuilds full wave state from the canonical authority set. Traces bundle everything needed for offline replay.
|
|
64
|
+
|
|
65
|
+
10. **The system stays opinionated about repo work.** Wave is a bounded-wave coding orchestrator with closure discipline, not a general-purpose agent framework.
|
|
66
|
+
|
|
67
|
+
### What Problem It Solves
|
|
68
|
+
|
|
69
|
+
Multi-agent coding systems fail in predictable ways documented in recent research (see [Section 18](#18-research-grounding)). Wave targets each failure mode with a specific architectural mechanism:
|
|
70
|
+
|
|
71
|
+
| Failure Mode | Wave Mechanism |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Cosmetic board, no canonical state | Append-only JSONL authority set; board is a projection |
|
|
74
|
+
| Hidden evidence never pooled | Shared summaries, per-agent inboxes, integration gate |
|
|
75
|
+
| No global-state reconstruction | Reducer rebuilds full state from canonical sources |
|
|
76
|
+
| Simultaneous coordination collapse | Helper assignments, dependency barriers, explicit blocking |
|
|
77
|
+
| Expert signal averaged away | Named stewards, capability routing, proof gates |
|
|
78
|
+
| Contradictions smoothed over | Contradiction entities, clarification triage, repair tracking |
|
|
79
|
+
| Premature closure | Multi-stage gate stack, structured proof markers, closure stewards |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. System Overview
|
|
84
|
+
|
|
85
|
+
### High-Level Architecture
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
+--------------------------+
|
|
89
|
+
| wave.mjs (CLI) |
|
|
90
|
+
| Subcommand router |
|
|
91
|
+
+----------+---------------+
|
|
92
|
+
|
|
|
93
|
+
+---------------------------+---------------------------+
|
|
94
|
+
| | |
|
|
95
|
+
+-----------+ +----------------+ +--------------+
|
|
96
|
+
| install | | launcher.mjs | | autonomous |
|
|
97
|
+
| planner | | (Thin orch.) | | (Multi-wave |
|
|
98
|
+
| doctor | | | | barrier) |
|
|
99
|
+
| draft | +-------+--------+ +--------------+
|
|
100
|
+
| adhoc | |
|
|
101
|
+
+-----------+ |
|
|
102
|
+
+---------------+---------------+
|
|
103
|
+
| | |
|
|
104
|
+
+------+------+ +-----+------+ +------+------+
|
|
105
|
+
| Impl Engine | | Derived | | Gate Engine |
|
|
106
|
+
| (run select)| | State Eng. | | (evaluate) |
|
|
107
|
+
+-------------+ +------------+ +--------------+
|
|
108
|
+
| | |
|
|
109
|
+
+------+------+ +-----+------+ +------+------+
|
|
110
|
+
| Retry Engine| | Closure | | Wave State |
|
|
111
|
+
| (plan retry)| | Engine | | Reducer |
|
|
112
|
+
+-------------+ +------------+ +--------------+
|
|
113
|
+
|
|
|
114
|
+
+---------------+---------------+
|
|
115
|
+
| |
|
|
116
|
+
+------+------+ +-------+-------+
|
|
117
|
+
| Session | | Projection |
|
|
118
|
+
| Supervisor | | Writer |
|
|
119
|
+
| (launch, | | (dashboards, |
|
|
120
|
+
| wait, tmux)| | traces, etc) |
|
|
121
|
+
+-------------+ +---------------+
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Four-Layer Model
|
|
125
|
+
|
|
126
|
+
**Layer 1 -- Canonical State** (append-only, never rewritten)
|
|
127
|
+
- `control-plane.mjs`: Lifecycle events (wave runs, agent runs, attempts, proof bundles, gates, contradictions, facts, human inputs)
|
|
128
|
+
- `coordination-store.mjs`: Workflow events (requests, acks, claims, evidence, decisions, blockers, handoffs, clarifications, escalations)
|
|
129
|
+
- `wave-files.mjs`: Parsed wave definitions from `docs/plans/waves/wave-<N>.md` (read-only)
|
|
130
|
+
|
|
131
|
+
**Layer 2 -- Phase Engines** (pure functions reading canonical state, emitting decisions)
|
|
132
|
+
- `implementation-engine.mjs`: Selects which agents to launch (initial, retry, override, persisted relaunch)
|
|
133
|
+
- `derived-state-engine.mjs`: Computes shared summaries, inboxes, assignments, ledger, docs queue, security and integration summaries
|
|
134
|
+
- `gate-engine.mjs`: Evaluates all closure gates and returns verdicts
|
|
135
|
+
- `closure-engine.mjs`: Sequences the staged closure sweep
|
|
136
|
+
- `retry-engine.mjs`: Plans retry targets, reusable work, executor fallbacks
|
|
137
|
+
- `wave-state-reducer.mjs`: Rebuilds full deterministic wave state from canonical sources
|
|
138
|
+
|
|
139
|
+
**Layer 3 -- Supervisor and Projection Writer** (side effects)
|
|
140
|
+
- `session-supervisor.mjs`: Launches processes, manages tmux sessions, writes observed lifecycle events (`agent_run.started`, `agent_run.completed`)
|
|
141
|
+
- `projection-writer.mjs`: Persists all human-facing projections (dashboards, traces, boards, summaries, inboxes, ledgers)
|
|
142
|
+
- `signals.mjs`: Writes versioned signal-state projections for long-running agents
|
|
143
|
+
|
|
144
|
+
**Layer 4 -- Launcher Orchestrator** (thin wiring)
|
|
145
|
+
- `launcher.mjs`: Parses args, acquires lock, iterates waves, calls engines in correct order, delegates all decisions
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 3. Canonical Authority Model
|
|
150
|
+
|
|
151
|
+
The system's source of truth is split across three canonical sources. Everything else is a derived projection.
|
|
152
|
+
|
|
153
|
+
### Authority Set
|
|
154
|
+
|
|
155
|
+
| Source | Storage | Authority Over |
|
|
156
|
+
|--------|---------|----------------|
|
|
157
|
+
| Wave definitions | Markdown files parsed at startup | Goals, agent roles, deliverables, exit contracts, proof artifacts, eval targets, component promotions, skills |
|
|
158
|
+
| Control-plane event log | Append-only JSONL per wave | Entity lifecycle: `wave_run`, `agent_run`, `attempt`, `proof_bundle`, `rerun_request`, `human_input`, `gate`, `contradiction`, `fact`, `artifact`, `benchmark_run`, `verification`, `review` |
|
|
159
|
+
| Coordination log | Append-only JSONL per wave | Workflow state: `request`, `ack`, `claim`, `evidence`, `decision`, `blocker`, `handoff`, `clarification-request`, `orchestrator-guidance`, `human-escalation`, `human-feedback`, `integration-summary` |
|
|
160
|
+
|
|
161
|
+
### Key Invariants
|
|
162
|
+
|
|
163
|
+
- Canonical logs are append-only. Events are never rewritten or deleted.
|
|
164
|
+
- The wave-state reducer can rebuild full wave state from these three sources alone.
|
|
165
|
+
- Result envelopes are immutable per attempt. A new attempt creates new envelopes; old ones are preserved.
|
|
166
|
+
- Projections (dashboards, boards, summaries, inboxes) are derived from canonical state and are safe to regenerate.
|
|
167
|
+
- **Decision logic never reads projections.** Gates, retry planning, and closure read canonical state and structured envelopes.
|
|
168
|
+
|
|
169
|
+
### Derived Projections
|
|
170
|
+
|
|
171
|
+
| Projection | Source | Purpose |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| Rolling message board | Coordination log + assignments + dependencies | Human-facing coordination view |
|
|
174
|
+
| Shared summary | Coordination log + execution summaries | Cross-agent awareness |
|
|
175
|
+
| Per-agent inboxes | Coordination log filtered by agent | Targeted awareness |
|
|
176
|
+
| Assignment snapshots | Coordination log + capability routing | Helper assignment tracking |
|
|
177
|
+
| Dependency snapshots | Cross-lane dependency tickets | Blocking dependency view |
|
|
178
|
+
| Wave ledger | Coordination log + feedback + assignments | Audit trail per wave |
|
|
179
|
+
| Docs queue | Execution summaries + doc-delta claims | Documentation closure input |
|
|
180
|
+
| Integration summary | Execution summaries + integration markers | Integration gate input |
|
|
181
|
+
| Security summary | Security review reports | Security gate input |
|
|
182
|
+
| Dashboard JSON | All of the above + agent status | Operator monitoring |
|
|
183
|
+
| Trace bundles | All canonical + derived state per attempt | Replay and audit |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 4. Module Architecture
|
|
188
|
+
|
|
189
|
+
### Core Modules (71 `.mjs` files in `scripts/wave-orchestrator/`)
|
|
190
|
+
|
|
191
|
+
#### Entry Point and Configuration
|
|
192
|
+
|
|
193
|
+
| Module | Size | Role |
|
|
194
|
+
|--------|------|------|
|
|
195
|
+
| `wave.mjs` | CLI router | Dispatches subcommands to dedicated modules |
|
|
196
|
+
| `config.mjs` | 47KB | Loads and normalizes `wave.config.json`, executor profiles, lane policies, skill routing |
|
|
197
|
+
| `shared.mjs` | 19KB | Constants (paths, defaults, regexes), utility functions (timestamps, file I/O, argument parsing) |
|
|
198
|
+
| `roots.mjs` | 375B | Resolves `PACKAGE_ROOT` and `WORKSPACE_ROOT` |
|
|
199
|
+
|
|
200
|
+
#### Canonical State Modules
|
|
201
|
+
|
|
202
|
+
| Module | Size | Role |
|
|
203
|
+
|--------|------|------|
|
|
204
|
+
| `wave-files.mjs` | 117KB | Parses wave markdown into structured definitions; validates waves; builds manifests; reconciles run state |
|
|
205
|
+
| `coordination-store.mjs` | 49KB | Reads/writes coordination JSONL; materializes coordination state; compiles shared summaries and inboxes |
|
|
206
|
+
| `control-plane.mjs` | 25KB | Reads/writes control-plane JSONL; builds task snapshots; manages proof bundles, rerun requests, human-input workflow |
|
|
207
|
+
| `coordination.mjs` | 43KB | Builds execution prompts; manages orchestrator boards; human feedback request reading |
|
|
208
|
+
|
|
209
|
+
#### Phase Engine Modules
|
|
210
|
+
|
|
211
|
+
| Module | Size | Role |
|
|
212
|
+
|--------|------|------|
|
|
213
|
+
| `implementation-engine.mjs` | 3KB | `planInitialWaveAttempt()` and `planRetryWaveAttempt()` -- selects which agent runs to launch |
|
|
214
|
+
| `derived-state-engine.mjs` | 27KB | `buildWaveDerivedState()` -- computes all blackboard projections from canonical sources |
|
|
215
|
+
| `gate-engine.mjs` | 56KB | Evaluates implementation, component, assignment, dependency, clarification, cont-eval, security, integration, documentation, and cont-QA gates |
|
|
216
|
+
| `closure-engine.mjs` | 17KB | `runClosureSweepPhase()` and `planClosureStages()` -- orchestrates the staged closure sequence |
|
|
217
|
+
| `retry-engine.mjs` | 40KB | Plans retry targets, identifies reusable work, computes executor fallback chains, generates persisted relaunch plans |
|
|
218
|
+
| `wave-state-reducer.mjs` | 26KB | `rebuildWaveState()` -- deterministic state reconstruction from canonical authority set for live queries and replay |
|
|
219
|
+
|
|
220
|
+
#### Session and Output Modules
|
|
221
|
+
|
|
222
|
+
| Module | Size | Role |
|
|
223
|
+
|--------|------|------|
|
|
224
|
+
| `session-supervisor.mjs` | 28KB | Process lifecycle: launches detached agent runners, waits for completion, manages locks, records `agent_run.started` / `agent_run.completed` events |
|
|
225
|
+
| `launcher-runtime.mjs` | 14KB | Builds agent launch specs: resolves skills, builds execution prompts, handles Context7 prefetch, manages rate-limit retries |
|
|
226
|
+
| `projection-writer.mjs` | 10KB | Single persistence layer for all projections: dashboards, traces, summaries, inboxes, boards, ledgers, docs queues |
|
|
227
|
+
| `traces.mjs` | 45KB | Builds hermetic trace bundles per attempt with quality metrics |
|
|
228
|
+
|
|
229
|
+
#### Agent and Task Modules
|
|
230
|
+
|
|
231
|
+
| Module | Size | Role |
|
|
232
|
+
|--------|------|------|
|
|
233
|
+
| `agent-state.mjs` | 43KB | Builds and validates agent execution summaries for all roles (implementation, cont-QA, cont-eval, integration, documentation, security, design) |
|
|
234
|
+
| `task-entity.mjs` | 31KB | Task entity model with ownership, leases, artifact contracts, dependency edges, closure state machines |
|
|
235
|
+
| `result-envelope.mjs` | 19KB | Builds immutable attempt-scoped result envelopes with common header and role-specific payloads |
|
|
236
|
+
| `contradiction-entity.mjs` | 13KB | Materializes contradictions from control-plane events; tracks repair work |
|
|
237
|
+
|
|
238
|
+
#### Executor and Skills
|
|
239
|
+
|
|
240
|
+
| Module | Size | Role |
|
|
241
|
+
|--------|------|------|
|
|
242
|
+
| `executors.mjs` | 15KB | Builds executor-specific launch commands for Codex, Claude, OpenCode, and Local |
|
|
243
|
+
| `skills.mjs` | 33KB | Skill loading, resolution by role/runtime/deploy-kind, artifact generation |
|
|
244
|
+
| `context7.mjs` | 14KB | Context7 bundle integration, prefetch, library resolution, prompt fingerprinting |
|
|
245
|
+
|
|
246
|
+
#### Coordination and Human Input
|
|
247
|
+
|
|
248
|
+
| Module | Size | Role |
|
|
249
|
+
|--------|------|------|
|
|
250
|
+
| `clarification-triage.mjs` | 21KB | Orchestrator-first triage of clarification requests from repo policy, ownership, prior decisions |
|
|
251
|
+
| `human-input-workflow.mjs` | 13KB | Human feedback request lifecycle management |
|
|
252
|
+
| `human-input-resolution.mjs` | 11KB | Resolution of human input requests back into coordination state |
|
|
253
|
+
| `routing-state.mjs` | builds | Deterministic helper assignment from capability routing, explicit targets, least-busy fallback |
|
|
254
|
+
|
|
255
|
+
#### Specialized Features
|
|
256
|
+
|
|
257
|
+
| Module | Size | Role |
|
|
258
|
+
|--------|------|------|
|
|
259
|
+
| `autonomous.mjs` | 16KB | Multi-wave autonomous execution with inter-wave barriers, dependency checks, external attempt limits |
|
|
260
|
+
| `planner.mjs` | 131KB | Agentic wave planning, draft generation, component maturity tracking, exit contract authoring |
|
|
261
|
+
| `adhoc.mjs` | 46KB | Ad-hoc transient runs on the same runtime surface |
|
|
262
|
+
| `benchmark.mjs` | 34KB | Benchmark running and result tracking |
|
|
263
|
+
| `swe-bench-pro-task.mjs` | 31KB | SWE-Bench Pro task orchestration |
|
|
264
|
+
| `install.mjs` | 31KB | Workspace initialization, upgrades, adoption, `wave doctor` validation |
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 5. Wave Execution Lifecycle
|
|
269
|
+
|
|
270
|
+
### Phase 1: Startup
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
CLI invocation
|
|
274
|
+
-> parseArgs() -- resolve lane, project, wave range, executor, options
|
|
275
|
+
-> acquireLauncherLock() -- prevent concurrent launchers on same lane
|
|
276
|
+
-> parseWaveFiles() -- parse all wave-<N>.md into structured definitions
|
|
277
|
+
-> applyExecutorSelectionsToWave() -- resolve per-agent executor from lane policy
|
|
278
|
+
-> applyContext7SelectionsToWave() -- resolve Context7 library selections
|
|
279
|
+
-> validateWaveDefinition() -- validate agents, deliverables, exit contracts
|
|
280
|
+
-> buildManifest() -- build manifest of all docs and waves
|
|
281
|
+
-> writeManifest() -- persist manifest JSON
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Phase 2: Per-Wave Loop
|
|
285
|
+
|
|
286
|
+
For each wave in the selected range:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
1. buildWaveDerivedState()
|
|
290
|
+
Computes shared summary, inboxes, message board, assignments, dependencies,
|
|
291
|
+
ledger, docs queue, security summary, integration summary from canonical state.
|
|
292
|
+
|
|
293
|
+
2. writeWaveDerivedProjections()
|
|
294
|
+
Persists all derived state to disk.
|
|
295
|
+
|
|
296
|
+
3. resetPersistedWaveLaunchState()
|
|
297
|
+
Clears stale relaunch plans unless --resume-control-state is set.
|
|
298
|
+
|
|
299
|
+
4. planInitialWaveAttempt()
|
|
300
|
+
Selects which agents to launch:
|
|
301
|
+
a. Check for reusable pre-completed agents (proven work from prior attempts)
|
|
302
|
+
b. Check for operator retry overrides
|
|
303
|
+
c. Check for persisted relaunch plans (from prior launcher crash)
|
|
304
|
+
d. Fall back to selectInitialWaveRuns() -- all non-pre-completed agents
|
|
305
|
+
|
|
306
|
+
5. For design-first waves: launch design agents first, wait for design gate,
|
|
307
|
+
then transition to implementation agents.
|
|
308
|
+
|
|
309
|
+
6. For each selected agent run:
|
|
310
|
+
a. launchAgentSession() -- build prompt, resolve skills, create tmux session
|
|
311
|
+
b. recordAgentRunStarted() -- supervisor writes control-plane event
|
|
312
|
+
|
|
313
|
+
7. waitForWaveCompletion()
|
|
314
|
+
Polling loop watching status files, with periodic:
|
|
315
|
+
- refreshDerivedState() -- recompute blackboard projections
|
|
316
|
+
- monitorWaveHumanFeedback() -- reconcile answered feedback
|
|
317
|
+
- syncLiveWaveSignals() -- update signal projections
|
|
318
|
+
- emitCoordinationAlertEvents() -- flag overdue acks and stale clarifications
|
|
319
|
+
- recordAgentRunFinished() -- supervisor writes completion events
|
|
320
|
+
|
|
321
|
+
8. materializeAgentExecutionSummaries()
|
|
322
|
+
Build structured summaries from agent output for gate evaluation.
|
|
323
|
+
|
|
324
|
+
9. buildGateSnapshot()
|
|
325
|
+
Evaluate all gates: implementation, component, assignment, dependency,
|
|
326
|
+
clarification, design, cont-eval, security, integration, docs, cont-QA.
|
|
327
|
+
|
|
328
|
+
10. If implementation gate passes and closure agents declared:
|
|
329
|
+
runClosureSweepPhase() -- staged closure (see Section 8)
|
|
330
|
+
|
|
331
|
+
11. If any gate fails and retries remain:
|
|
332
|
+
planRetryWaveAttempt() -- select agents to relaunch (see Section 9)
|
|
333
|
+
Go to step 6.
|
|
334
|
+
|
|
335
|
+
12. On wave completion:
|
|
336
|
+
markWaveCompleted() -- update run-state
|
|
337
|
+
writeWaveAttemptTraceProjection() -- persist trace bundle
|
|
338
|
+
computeReducerSnapshot() -- persist reducer state for replay
|
|
339
|
+
flushWaveControlTelemetry() -- deliver telemetry events
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Phase 3: Cleanup
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
-> cleanupLaneTmuxSessions() -- kill tmux sessions (unless --keep-sessions)
|
|
346
|
+
-> removeLaneTemporaryTerminalEntries() -- clean terminal registry
|
|
347
|
+
-> releaseLauncherLock() -- release lock for other launchers
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Autonomous Mode
|
|
351
|
+
|
|
352
|
+
`wave autonomous` adds an outer loop around the per-wave launcher:
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
for each wave in lane order:
|
|
356
|
+
1. Check cross-lane dependency barriers
|
|
357
|
+
2. Check run-state for already-completed waves
|
|
358
|
+
3. Spawn `wave launch --start-wave N --end-wave N` as subprocess
|
|
359
|
+
4. If wave fails after max external attempts, stop
|
|
360
|
+
5. Continue to next wave
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Autonomous mode disables `--terminal-surface none` and requires a real executor (not `local`).
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## 6. Coordination and Blackboard Model
|
|
368
|
+
|
|
369
|
+
### Why a Blackboard
|
|
370
|
+
|
|
371
|
+
Traditional multi-agent systems fail when agents treat chat output as system of record. Evidence gets lost, contradictions are smoothed over, and there is no way to reconstruct what the system actually knew at any point. Wave uses a blackboard-style architecture where agents work against shared canonical state.
|
|
372
|
+
|
|
373
|
+
### How It Works
|
|
374
|
+
|
|
375
|
+
1. **Agents write to canonical logs, not to each other.** An implementation agent posts a `claim`, `evidence`, `blocker`, or `clarification-request` to the coordination log.
|
|
376
|
+
|
|
377
|
+
2. **The derived-state engine compiles shared awareness.** After any state change, `buildWaveDerivedState()` recomputes:
|
|
378
|
+
- Shared summary: aggregated coordination state visible to all agents
|
|
379
|
+
- Per-agent inboxes: filtered view of state relevant to a specific agent
|
|
380
|
+
- Message board: human-readable markdown projection
|
|
381
|
+
- Assignment snapshot: who owns what capability-targeted requests
|
|
382
|
+
- Dependency snapshot: cross-lane blocking state
|
|
383
|
+
|
|
384
|
+
3. **Agents receive compiled context, not raw logs.** When an agent is launched or re-contextualized, it receives the shared summary and its inbox, not a dump of raw log lines.
|
|
385
|
+
|
|
386
|
+
4. **The orchestrator triages clarifications.** When an agent posts a `clarification-request`, the `clarification-triage.mjs` module resolves it from repo policy, ownership, and prior decisions before escalating to human feedback.
|
|
387
|
+
|
|
388
|
+
5. **Human input flows through the control plane.** Human feedback requests are tracked as `human_input` entities with explicit lifecycle states (`pending -> assigned -> answered|escalated|resolved|timed_out|rerouted`).
|
|
389
|
+
|
|
390
|
+
### Coordination Record Types
|
|
391
|
+
|
|
392
|
+
| Kind | Purpose |
|
|
393
|
+
|------|---------|
|
|
394
|
+
| `request` | Agent asks for something from another agent or the orchestrator |
|
|
395
|
+
| `ack` | Agent acknowledges a request |
|
|
396
|
+
| `claim` | Agent claims a deliverable is complete |
|
|
397
|
+
| `evidence` | Agent provides supporting evidence for a claim |
|
|
398
|
+
| `decision` | Orchestrator or agent records a decision |
|
|
399
|
+
| `blocker` | Something is blocking progress |
|
|
400
|
+
| `handoff` | Work is transferred between agents |
|
|
401
|
+
| `clarification-request` | Agent needs clarification before proceeding |
|
|
402
|
+
| `orchestrator-guidance` | Orchestrator provides direction |
|
|
403
|
+
| `human-escalation` | Issue escalated to human operator |
|
|
404
|
+
| `human-feedback` | Human provides feedback |
|
|
405
|
+
| `integration-summary` | Cross-agent integration state |
|
|
406
|
+
|
|
407
|
+
### Blocking Semantics
|
|
408
|
+
|
|
409
|
+
Coordination records have explicit blocking behavior:
|
|
410
|
+
|
|
411
|
+
- **Hard blockers** (`hard`, `proof-critical`, `closure-critical`): Block wave progression
|
|
412
|
+
- **Soft blockers** (`soft`): Visible but non-blocking
|
|
413
|
+
- **Stale/Advisory** (`stale`, `advisory`): Informational only
|
|
414
|
+
|
|
415
|
+
Operators can downgrade blockers via `wave control task` commands: `defer`, `mark-advisory`, `mark-stale`, `resolve-policy`.
|
|
416
|
+
|
|
417
|
+
### Helper Assignments
|
|
418
|
+
|
|
419
|
+
When an agent posts a capability-targeted request, the routing engine assigns it:
|
|
420
|
+
|
|
421
|
+
1. Check explicit targets in the request
|
|
422
|
+
2. Check `capabilityRouting.preferredAgents` in config
|
|
423
|
+
3. Match capability owners with demonstrated same-wave completions
|
|
424
|
+
4. Fall back to least-busy agent
|
|
425
|
+
|
|
426
|
+
Assignments remain blocking until the linked follow-up resolves or is explicitly downgraded.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 7. Gate Evaluation and Proof Model
|
|
431
|
+
|
|
432
|
+
### Two-Phase Proof
|
|
433
|
+
|
|
434
|
+
Wave separates individual agent proof from wave-level closure:
|
|
435
|
+
|
|
436
|
+
**Phase 1: `owned_slice_proven`** (per-agent)
|
|
437
|
+
|
|
438
|
+
An agent's owned slice is proven when:
|
|
439
|
+
- All declared deliverables exist on disk
|
|
440
|
+
- Proof markers meet or exceed the exit contract
|
|
441
|
+
- Proof artifacts (if declared) are present with valid SHA256
|
|
442
|
+
- Doc-delta is declared if required
|
|
443
|
+
- Component promotions meet target maturity
|
|
444
|
+
- No open self-owned blockers
|
|
445
|
+
|
|
446
|
+
**Phase 2: `wave_closure_ready`** (cross-cutting)
|
|
447
|
+
|
|
448
|
+
All owned slices are proven AND:
|
|
449
|
+
- No unresolved contradictions
|
|
450
|
+
- No open clarification barriers
|
|
451
|
+
- No open helper assignment barriers
|
|
452
|
+
- No open cross-lane dependency barriers
|
|
453
|
+
- Integration gate passed
|
|
454
|
+
- Documentation gate passed
|
|
455
|
+
- cont-EVAL gate passed (if applicable)
|
|
456
|
+
- Security review gate passed (if applicable)
|
|
457
|
+
- cont-QA final verdict is PASS
|
|
458
|
+
- Component matrix promotions validated
|
|
459
|
+
|
|
460
|
+
Only when `wave_closure_ready = true` does the system emit a `wave_run.completed` event.
|
|
461
|
+
|
|
462
|
+
### Gate Stack
|
|
463
|
+
|
|
464
|
+
The `gate-engine.mjs` evaluates gates in this order:
|
|
465
|
+
|
|
466
|
+
| Gate | Evaluates | Required |
|
|
467
|
+
|------|-----------|----------|
|
|
468
|
+
| Implementation | All agent exit codes and execution summaries | Always |
|
|
469
|
+
| Component | Per-component maturity promotions | When declared |
|
|
470
|
+
| Design | Design packets are `ready-for-implementation` | When design agents present |
|
|
471
|
+
| Assignment | All helper assignments resolved | When assignments exist |
|
|
472
|
+
| Dependency | Cross-lane dependency tickets resolved | When dependencies exist |
|
|
473
|
+
| Clarification | All clarification barriers cleared | When clarifications exist |
|
|
474
|
+
| cont-EVAL | Eval report artifact + `[wave-eval]` marker + exact target_ids | When E0 declared |
|
|
475
|
+
| Security | Security report + `[wave-security]` marker | When security agent declared |
|
|
476
|
+
| Integration | Integration evidence aggregation | Always |
|
|
477
|
+
| Documentation | Doc closure state | Always |
|
|
478
|
+
| Component Matrix | Cross-agent component validation | When components declared |
|
|
479
|
+
| cont-QA | Final verdict + `[wave-gate]` marker | Always |
|
|
480
|
+
|
|
481
|
+
### Result Envelopes
|
|
482
|
+
|
|
483
|
+
Agents produce structured JSON envelopes (not free-form text). Each envelope has:
|
|
484
|
+
|
|
485
|
+
**Common header (all roles):**
|
|
486
|
+
```
|
|
487
|
+
schemaVersion, agentId, waveNumber, attempt, completedAt, exitCode,
|
|
488
|
+
role, proof{}, deliverables[], proofArtifacts[], gaps[],
|
|
489
|
+
unresolvedBlockers[], riskNotes[], facts[]
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Role-specific payloads:**
|
|
493
|
+
- `implementation`: docDelta, components[]
|
|
494
|
+
- `integration`: state (clean|claims_pending|conflicts_detected|blocked), counts
|
|
495
|
+
- `documentation`: docClosure state, paths
|
|
496
|
+
- `cont-qa`: verdict, gateClaims (architecture/integration/durability/live/docs)
|
|
497
|
+
- `cont-eval`: state, targets, benchmarks, regressions
|
|
498
|
+
- `security`: state (clean|findings|blocked), findings/approvals counts
|
|
499
|
+
- `deploy`: state, environment, healthCheck
|
|
500
|
+
|
|
501
|
+
Envelope path: `.tmp/<lane>-wave-launcher/results/wave-<N>/attempt-<A>/<agentId>.json`
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## 8. Closure Sweep: How Waves Actually Close
|
|
506
|
+
|
|
507
|
+
### The Core Problem
|
|
508
|
+
|
|
509
|
+
Agents say "done" before the work is actually done. This is the single most common failure mode in multi-agent coding systems. An agent can produce plausible-looking output, claim PASS, and move on -- but the deliverables don't exist, the tests don't run, the integration breaks, or the proof is narrative rather than structural. Wave's closure model exists to make premature closure impossible.
|
|
510
|
+
|
|
511
|
+
### Closure Is Not "Agent Finished"
|
|
512
|
+
|
|
513
|
+
A wave does not close when agents finish running. A wave closes when:
|
|
514
|
+
|
|
515
|
+
1. Every agent's **owned slice is structurally proven** (deliverables exist, proof markers valid, SHA256 checks pass)
|
|
516
|
+
2. Every **cross-cutting concern** is clear (no open blockers, clarifications, dependencies, contradictions)
|
|
517
|
+
3. A **staged sweep of closure stewards** has validated the integrated result
|
|
518
|
+
4. The **final cont-QA verdict** is PASS based on structural evidence, not agent self-report
|
|
519
|
+
|
|
520
|
+
This is enforced by the `closure-engine.mjs` module. The launcher cannot bypass closure; the gate stack is fail-closed.
|
|
521
|
+
|
|
522
|
+
### How the Closure Sweep Executes
|
|
523
|
+
|
|
524
|
+
The sweep is sequential and staged. Each stage launches a closure agent, waits for it to complete, evaluates the gate, and only proceeds to the next stage if the gate passes. This is implemented in `runClosureSweepPhase()`.
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
528
|
+
│ IMPLEMENTATION PHASE (parallel) │
|
|
529
|
+
│ A1, A2, A3... run concurrently │
|
|
530
|
+
│ Each writes: status file, execution summary, result envelope │
|
|
531
|
+
│ Gate: readWaveImplementationGate() checks all exit codes + summaries│
|
|
532
|
+
│ If any fail → retry (Section 9), do not enter closure │
|
|
533
|
+
└──────────────────────────┬──────────────────────────────────────────┘
|
|
534
|
+
│ all agents exit 0 + valid summaries
|
|
535
|
+
▼
|
|
536
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
537
|
+
│ STAGE 1: cont-EVAL (optional — only if E0 declared in wave) │
|
|
538
|
+
│ Launch: E0 agent │
|
|
539
|
+
│ Reads: implementation result envelopes, eval target declarations │
|
|
540
|
+
│ Writes: eval report artifact + [wave-eval] structured marker │
|
|
541
|
+
│ Gate: readWaveContEvalGate() │
|
|
542
|
+
│ ✓ Report artifact exists │
|
|
543
|
+
│ ✓ [wave-eval] marker present with exact target_ids match │
|
|
544
|
+
│ ✓ benchmark_ids valid │
|
|
545
|
+
│ On fail: only E0 reruns; all implementation proof preserved │
|
|
546
|
+
└──────────────────────────┬──────────────────────────────────────────┘
|
|
547
|
+
│ gate passes (or stage skipped)
|
|
548
|
+
▼
|
|
549
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
550
|
+
│ STAGE 2: Security Review (optional — only if security agent exists) │
|
|
551
|
+
│ Launch: security review agent (A7) │
|
|
552
|
+
│ Reads: implementation envelopes, source diff, dependency state │
|
|
553
|
+
│ Writes: security report + [wave-security] structured marker │
|
|
554
|
+
│ Gate: readWaveSecurityGate() │
|
|
555
|
+
│ ✓ Report exists │
|
|
556
|
+
│ ✓ [wave-security] marker with state=clear|concerns|blocked │
|
|
557
|
+
│ ✓ state != blocked (concerns are logged but non-blocking) │
|
|
558
|
+
│ On fail: only A7 reruns; implementation proof preserved │
|
|
559
|
+
└──────────────────────────┬──────────────────────────────────────────┘
|
|
560
|
+
│ gate passes (or stage skipped)
|
|
561
|
+
▼
|
|
562
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
563
|
+
│ STAGE 3: Integration │
|
|
564
|
+
│ Launch: integration steward (A8) │
|
|
565
|
+
│ Reads: all implementation envelopes, coordination state, │
|
|
566
|
+
│ contradiction entities, shared summary │
|
|
567
|
+
│ Writes: integration evidence, contradiction resolutions │
|
|
568
|
+
│ Gate: readWaveIntegrationBarrier() │
|
|
569
|
+
│ ✓ Integration state is clean or claims_pending (not blocked) │
|
|
570
|
+
│ ✓ No unresolved hard contradictions │
|
|
571
|
+
│ ✓ Evidence aggregation shows cross-agent consistency │
|
|
572
|
+
│ On fail: only A8 reruns │
|
|
573
|
+
└──────────────────────────┬──────────────────────────────────────────┘
|
|
574
|
+
│ gate passes
|
|
575
|
+
▼
|
|
576
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
577
|
+
│ STAGE 4: Documentation │
|
|
578
|
+
│ Launch: documentation steward (A9) │
|
|
579
|
+
│ Reads: doc-delta claims from implementation envelopes, │
|
|
580
|
+
│ component matrix, shared plan docs │
|
|
581
|
+
│ Writes: documentation closure report │
|
|
582
|
+
│ Gate: readWaveDocumentationGate() + readWaveComponentMatrixGate() │
|
|
583
|
+
│ ✓ Doc closure state is valid │
|
|
584
|
+
│ ✓ Component matrix promotions are consistent across agents │
|
|
585
|
+
│ ✓ Current levels match expected post-promotion state │
|
|
586
|
+
│ On fail: only A9 reruns │
|
|
587
|
+
└──────────────────────────┬──────────────────────────────────────────┘
|
|
588
|
+
│ gate passes
|
|
589
|
+
▼
|
|
590
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
591
|
+
│ STAGE 5: cont-QA (final verdict) │
|
|
592
|
+
│ Launch: cont-QA steward (A0) │
|
|
593
|
+
│ Reads: ALL preceding closure evidence, all envelopes, │
|
|
594
|
+
│ full coordination state, forwarded closure gaps │
|
|
595
|
+
│ Writes: final verdict + [wave-gate] structured marker │
|
|
596
|
+
│ Gate: readWaveContQaGate() │
|
|
597
|
+
│ ✓ Verdict artifact exists │
|
|
598
|
+
│ ✓ [wave-gate] marker present │
|
|
599
|
+
│ ✓ Verdict is PASS (not FAIL, not PARTIAL) │
|
|
600
|
+
│ This is the terminal gate. PASS here = wave_closure_ready │
|
|
601
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### What Each Closure Agent Actually Validates
|
|
605
|
+
|
|
606
|
+
**cont-EVAL (E0):** Runs declared eval targets from the wave's `### Eval targets` section against the benchmark catalog. Verifies that eval results meet declared thresholds. Writes a typed eval report with `target_ids` linking back to wave declarations. The gate enforces exact match between declared and reported target IDs.
|
|
607
|
+
|
|
608
|
+
**Security Reviewer (A7):** Reviews source changes for OWASP top-10, dependency vulnerabilities, credential exposure, and wave-declared security concerns. Writes a structured report with `state` field. `clear` = no findings. `concerns` = findings logged but non-blocking. `blocked` = critical findings that must be resolved.
|
|
609
|
+
|
|
610
|
+
**Integration Steward (A8):** The cross-agent consistency checker. Reads all implementation envelopes to detect contradictions (agent A1 changed an interface that agent A2 depends on), verify that claims from different agents are compatible, and confirm that the integrated codebase is coherent. Works against the materialized contradiction entities from the control plane.
|
|
611
|
+
|
|
612
|
+
**Documentation Steward (A9):** Validates that all doc-delta claims from implementation agents were actually fulfilled, that the component maturity matrix is consistent (no agent promoted a component that another agent left at a lower level), and that shared plan docs reflect the current state.
|
|
613
|
+
|
|
614
|
+
**cont-QA (A0):** The final authority. Has access to everything: all envelopes, all coordination state, all forwarded closure gaps, all prior closure-stage reports. Makes the terminal PASS/FAIL decision based on structural evidence. The gate rejects narrative-only verdicts -- the `[wave-gate]` marker must be present with the exact structured format.
|
|
615
|
+
|
|
616
|
+
### Closure Gap Forwarding
|
|
617
|
+
|
|
618
|
+
A special case exists for `wave-proof-gap` status codes. When a closure-stage agent (e.g., A7 security review) identifies a gap but the gap is not a hard failure, the system does not stop the closure sweep:
|
|
619
|
+
|
|
620
|
+
1. Records the gap as a `closure-critical` blocker in the coordination log via `forwardedClosureGapRecord()`
|
|
621
|
+
2. Continues launching subsequent closure stages (A8, A9, A0) with the gap as structured input
|
|
622
|
+
3. Later closure agents evaluate the available artifacts. They don't refuse to run just because an earlier stage had a gap
|
|
623
|
+
4. The final disposition remains blocked until all forwarded gaps are resolved
|
|
624
|
+
|
|
625
|
+
**Why this matters:** Without gap forwarding, a minor security concern in Stage 2 would prevent the system from collecting integration evidence (Stage 3), documentation validation (Stage 4), and the QA assessment (Stage 5). That evidence is valuable regardless of whether the security gap needs resolution. Gap forwarding collects maximum evidence before blocking.
|
|
626
|
+
|
|
627
|
+
### Closure Role Bindings
|
|
628
|
+
|
|
629
|
+
Closure roles are resolved through `resolveWaveRoleBindings()`:
|
|
630
|
+
|
|
631
|
+
| Role | Default Agent ID | Config Override |
|
|
632
|
+
|------|-----------------|----------------|
|
|
633
|
+
| cont-QA | A0 | `roles.contQaAgentId` or wave-level `contQaAgentId` |
|
|
634
|
+
| cont-EVAL | E0 | `roles.contEvalAgentId` or wave-level `contEvalAgentId` |
|
|
635
|
+
| Integration | A8 | `roles.integrationAgentId` or wave-level `integrationAgentId` |
|
|
636
|
+
| Documentation | A9 | `roles.documentationAgentId` or wave-level `documentationAgentId` |
|
|
637
|
+
| Security | A7 | Detected by `isSecurityReviewAgent()` from role prompt path |
|
|
638
|
+
|
|
639
|
+
Waves can override these defaults. Starter defaults (`E0`, `A7`, `A8`, `A9`, `A0`) fill gaps only when a wave does not declare its own bindings.
|
|
640
|
+
|
|
641
|
+
### Design-First Gating (Pre-Closure)
|
|
642
|
+
|
|
643
|
+
Before the closure sweep, waves can optionally run a **design-first pass**:
|
|
644
|
+
|
|
645
|
+
1. Design agents (detected by `isDesignAgent()`) run before implementation agents
|
|
646
|
+
2. Design agents produce **design packets** under `docs/plans/waves/design/`
|
|
647
|
+
3. The design gate blocks implementation until every design packet is `ready-for-implementation`
|
|
648
|
+
4. Once the design gate clears, implementation agents fan out normally
|
|
649
|
+
5. Hybrid design stewards (flagged by `isImplementationOwningDesignAgent()`) rejoin the implementation fan-out after their design pass
|
|
650
|
+
|
|
651
|
+
This is orchestrated by `resolvePostDesignPassTransition()` in `launcher.mjs`.
|
|
652
|
+
|
|
653
|
+
### Infra Gate (Post-Implementation, Pre-Closure)
|
|
654
|
+
|
|
655
|
+
An additional gate checks infrastructure signal state. `readWaveInfraGate()` in `closure-engine.mjs` scans agent logs for structured infra signals and blocks if any signal ended in a non-conformant state. Conformant states (`conformant`, `setup-required`, `setup-in-progress`, `action-required`, `action-approved`, `action-complete`) are non-blocking.
|
|
656
|
+
|
|
657
|
+
### Strict Validation Rules
|
|
658
|
+
|
|
659
|
+
Live closure enforces strict marker validation. This is intentionally unforgiving:
|
|
660
|
+
|
|
661
|
+
- **cont-EVAL:** Report artifact must exist. `[wave-eval]` marker must be present with `target_ids` exactly matching the wave's declared eval targets. `benchmark_ids` must reference valid catalog entries.
|
|
662
|
+
- **Security:** Report must exist. `[wave-security]` marker must be present with `state` in `{clear, concerns, blocked}`.
|
|
663
|
+
- **cont-QA:** Final verdict artifact must exist. `[wave-gate]` marker must be present with structured verdict.
|
|
664
|
+
- **Legacy tolerance:** Underspecified or evaluator-era artifacts fail in live closure. They are only tolerated in replay mode for historical compatibility.
|
|
665
|
+
|
|
666
|
+
### Smart Rerun After Closure Failure
|
|
667
|
+
|
|
668
|
+
When a closure gate fails, the system does not rerun the entire wave:
|
|
669
|
+
|
|
670
|
+
| Failure Point | What Reruns | What Is Preserved |
|
|
671
|
+
|---|---|---|
|
|
672
|
+
| cont-EVAL fails | Only E0 | All implementation proof |
|
|
673
|
+
| Security fails | Only A7 | All implementation proof + E0 results |
|
|
674
|
+
| Integration fails | Only A8 | All implementation proof + E0 + A7 |
|
|
675
|
+
| Documentation fails | Only A9 | All proof + E0 + A7 + A8 |
|
|
676
|
+
| cont-QA fails | Only A0 | All proof + all closure stages |
|
|
677
|
+
|
|
678
|
+
This targeted rerun is computed by `planRetryWaveAttempt()` in the implementation engine, which reads the gate snapshot to identify exactly which closure role failed.
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
## 9. Retry and Recovery
|
|
683
|
+
|
|
684
|
+
### Retry Planning
|
|
685
|
+
|
|
686
|
+
The `retry-engine.mjs` is a pure-function module that computes retry decisions from stored state:
|
|
687
|
+
|
|
688
|
+
1. **Identify reusable work.** Agents with valid proof from prior attempts are marked `pre-completed` and skip relaunch. The `selectReusablePreCompletedAgentIds()` function checks:
|
|
689
|
+
- Exit code 0
|
|
690
|
+
- Valid execution summary
|
|
691
|
+
- Proof registry confirms proof is still valid
|
|
692
|
+
- No retry override targeting this agent
|
|
693
|
+
|
|
694
|
+
2. **Compute relaunch targets.** Failed agents are selected for relaunch. The system considers:
|
|
695
|
+
- Direct failures (non-zero exit, timeout, missing status)
|
|
696
|
+
- Shared component sibling failures (one component failure blocks siblings)
|
|
697
|
+
- Closure gap invalidation (proof revoked by contradiction)
|
|
698
|
+
|
|
699
|
+
3. **Apply operator overrides.** Operators can set retry overrides via `wave control rerun` to force specific agents to rerun or skip.
|
|
700
|
+
|
|
701
|
+
4. **Persist relaunch plans.** If the launcher crashes, the relaunch plan survives on disk so the next launch can resume from the same point.
|
|
702
|
+
|
|
703
|
+
### Executor Fallback
|
|
704
|
+
|
|
705
|
+
When a runtime fails repeatedly, the retry engine can reassign an agent to a fallback executor from the lane policy's fallback chain. The `executorFallbackChain()` function reads:
|
|
706
|
+
1. Agent's explicit executor profile
|
|
707
|
+
2. Lane role defaults
|
|
708
|
+
3. Global fallback chain in config
|
|
709
|
+
|
|
710
|
+
### Barriers
|
|
711
|
+
|
|
712
|
+
Retry can be blocked by barriers that require human intervention:
|
|
713
|
+
- Unresolved clarifications requiring human feedback
|
|
714
|
+
- Cross-lane dependency barriers
|
|
715
|
+
- Helper assignment barriers with no available owner
|
|
716
|
+
- Repeated failures exhausting the retry budget
|
|
717
|
+
|
|
718
|
+
The barrier is surfaced through the coordination log and dashboard so operators can act.
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
## 10. Run-State Reconciler
|
|
723
|
+
|
|
724
|
+
### What the Reconciler Does
|
|
725
|
+
|
|
726
|
+
The reconciler answers one question: **which waves are actually complete?** It inspects on-disk artifacts (status files, execution summaries, coordination state, dependency tickets, assignment records) and determines whether each wave's completion evidence is structurally valid. This runs at launcher startup before any new execution begins.
|
|
727
|
+
|
|
728
|
+
The core function is `reconcileRunStateFromStatusFiles()` in `wave-files.mjs`. It is called from `launcher.mjs` during startup and can also be invoked standalone via `wave launch --reconcile-status`.
|
|
729
|
+
|
|
730
|
+
### Why It Exists
|
|
731
|
+
|
|
732
|
+
Several scenarios can leave run state and disk artifacts out of sync:
|
|
733
|
+
|
|
734
|
+
- The launcher crashes mid-wave, leaving status files on disk but no recorded completion
|
|
735
|
+
- A wave completed in a prior launcher run, but the wave definition has changed since (prompt drift)
|
|
736
|
+
- Coordination state has changed (new blockers, clarifications, escalations) that invalidate a previous completion
|
|
737
|
+
- An operator manually edited artifacts or resolved dependencies outside the launcher
|
|
738
|
+
|
|
739
|
+
The reconciler detects all of these and produces a correct run state.
|
|
740
|
+
|
|
741
|
+
### How It Works
|
|
742
|
+
|
|
743
|
+
```
|
|
744
|
+
reconcileRunStateFromStatusFiles(allWaves, runStatePath, statusDir, options)
|
|
745
|
+
│
|
|
746
|
+
├─ Read existing run-state.json (previous completions, history)
|
|
747
|
+
│
|
|
748
|
+
├─ For each wave definition:
|
|
749
|
+
│ │
|
|
750
|
+
│ └─ analyzeWaveCompletionFromStatusFiles()
|
|
751
|
+
│ │
|
|
752
|
+
│ ├─ Status File Validation
|
|
753
|
+
│ │ ├─ Read agent status files (wave-<N>-<agentId>.status)
|
|
754
|
+
│ │ ├─ Check exit code == 0
|
|
755
|
+
│ │ └─ Verify metadata (promptHash present)
|
|
756
|
+
│ │
|
|
757
|
+
│ ├─ Prompt Drift Detection
|
|
758
|
+
│ │ ├─ Compare current prompt hash to status file's recorded hash
|
|
759
|
+
│ │ └─ Flag: prompt-hash-missing or prompt-hash-mismatch
|
|
760
|
+
│ │
|
|
761
|
+
│ ├─ Agent Summary Validation (per role)
|
|
762
|
+
│ │ ├─ cont-QA → validateContQaSummary()
|
|
763
|
+
│ │ ├─ cont-EVAL → validateContEvalSummary()
|
|
764
|
+
│ │ ├─ Security → validateSecuritySummary()
|
|
765
|
+
│ │ ├─ Integration → validateIntegrationSummary()
|
|
766
|
+
│ │ ├─ Documentation → validateDocumentationClosureSummary()
|
|
767
|
+
│ │ └─ Implementation → validateImplementationSummary()
|
|
768
|
+
│ │
|
|
769
|
+
│ ├─ Coordination State Checks
|
|
770
|
+
│ │ ├─ Open clarifications → open-clarification
|
|
771
|
+
│ │ ├─ Open clarification-linked requests → open-clarification-request
|
|
772
|
+
│ │ ├─ Unresolved human escalations → open-human-escalation
|
|
773
|
+
│ │ ├─ Pending human feedback → open-human-feedback
|
|
774
|
+
│ │ ├─ Blocking helper assignments → helper-assignment-unresolved / open
|
|
775
|
+
│ │ └─ Open dependency tickets → dependency-open / unresolved
|
|
776
|
+
│ │
|
|
777
|
+
│ ├─ Component Matrix Validation
|
|
778
|
+
│ │ ├─ Promotion consistency across agents
|
|
779
|
+
│ │ └─ Current levels match expected state
|
|
780
|
+
│ │
|
|
781
|
+
│ └─ Returns: { ok: boolean, reasons: [{code, detail}], evidence: {...} }
|
|
782
|
+
│
|
|
783
|
+
├─ For each analyzed wave, decide outcome:
|
|
784
|
+
│ ├─ ok == true → mark "completed"
|
|
785
|
+
│ ├─ Previously completed + only prompt drift → preserve as "completed_with_drift"
|
|
786
|
+
│ └─ Otherwise → mark "blocked" with reasons
|
|
787
|
+
│
|
|
788
|
+
├─ Write state transitions to run-state.json history (append-only)
|
|
789
|
+
│
|
|
790
|
+
└─ Return reconciliation report:
|
|
791
|
+
{ completedFromStatus, addedFromBefore, blockedFromStatus, preservedWithDrift, state }
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### Blocking Reason Codes
|
|
795
|
+
|
|
796
|
+
When a wave fails reconciliation, the reasons are tagged with specific codes:
|
|
797
|
+
|
|
798
|
+
| Code | Meaning |
|
|
799
|
+
|------|---------|
|
|
800
|
+
| `nonzero-status` | Agent exited with non-zero code |
|
|
801
|
+
| `missing-status` | Agent status file does not exist |
|
|
802
|
+
| `prompt-hash-missing` | Status file lacks promptHash metadata |
|
|
803
|
+
| `prompt-hash-mismatch` | Prompt has changed since agent ran |
|
|
804
|
+
| `invalid-cont-qa-summary` | cont-QA summary validation failed |
|
|
805
|
+
| `invalid-cont-eval-summary` | cont-EVAL summary validation failed |
|
|
806
|
+
| `invalid-security-summary` | Security summary validation failed |
|
|
807
|
+
| `invalid-integration-summary` | Integration summary validation failed |
|
|
808
|
+
| `invalid-documentation-summary` | Documentation summary validation failed |
|
|
809
|
+
| `invalid-implementation-summary` | Implementation proof validation failed |
|
|
810
|
+
| `component-promotions-invalid` | Component matrix promotion inconsistencies |
|
|
811
|
+
| `component-matrix-invalid` | Current level mismatches |
|
|
812
|
+
| `open-clarification` | Unresolved clarification records in coordination log |
|
|
813
|
+
| `open-clarification-request` | Clarification-linked requests still open |
|
|
814
|
+
| `open-human-escalation` | Human escalations unresolved |
|
|
815
|
+
| `open-human-feedback` | Human feedback still pending |
|
|
816
|
+
| `helper-assignment-unresolved` | Blocking assignments not assigned |
|
|
817
|
+
| `helper-assignment-open` | Blocking assignments assigned but not completed |
|
|
818
|
+
| `dependency-assignment-unresolved` | Inbound dependencies not assigned |
|
|
819
|
+
| `dependency-open` | Required cross-lane dependencies remain open |
|
|
820
|
+
|
|
821
|
+
### Prompt Drift Preservation
|
|
822
|
+
|
|
823
|
+
When a wave was previously completed by an actual launcher run, but the wave definition has since changed (causing prompt hash mismatch), the reconciler does **not** invalidate the completion. Instead it preserves the wave as `completed_with_drift`.
|
|
824
|
+
|
|
825
|
+
The logic in `shouldPreserveCompletedWave()` requires both conditions:
|
|
826
|
+
|
|
827
|
+
1. **Previous completion is authoritative**: the wave's `lastSource` is not empty and not `"legacy-run-state"` (i.e., it was completed by a real execution, not imported from old data)
|
|
828
|
+
2. **Only prompt drift reasons exist**: every blocking reason is in `{prompt-hash-missing, prompt-hash-mismatch}` and no other validation failures are present
|
|
829
|
+
|
|
830
|
+
This is a pragmatic choice: prompt changes alone (e.g., editing a wave description after completion) should not force a full re-execution. But if the agent summary is also invalid, or coordination state has open blockers, the completion is revoked.
|
|
831
|
+
|
|
832
|
+
### Run State Structure
|
|
833
|
+
|
|
834
|
+
The persistent run state at `.tmp/<lane>-wave-launcher/run-state.json`:
|
|
835
|
+
|
|
836
|
+
```javascript
|
|
837
|
+
{
|
|
838
|
+
completedWaves: [0, 1, 2], // derived sorted list
|
|
839
|
+
waves: {
|
|
840
|
+
"0": {
|
|
841
|
+
wave: 0,
|
|
842
|
+
currentState: "completed", // or "completed_with_drift" or "blocked"
|
|
843
|
+
lastTransitionAt: "2024-03-22T...",
|
|
844
|
+
lastSource: "live-launcher", // who determined this state
|
|
845
|
+
lastReasonCode: "wave-complete", // why
|
|
846
|
+
lastDetail: "Wave 0 completed.", // human-readable
|
|
847
|
+
lastEvidence: { // supporting metadata
|
|
848
|
+
waveFileHash: "sha256:...",
|
|
849
|
+
statusFiles: [{ agentId, path, promptHash, code, completedAt, sha256 }],
|
|
850
|
+
summaryFiles: [{ agentId, path, sha256 }],
|
|
851
|
+
coordinationLogSha256: "sha256:...",
|
|
852
|
+
assignmentsSha256: "sha256:...",
|
|
853
|
+
gateSnapshotSha256: "sha256:..."
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
history: [ // append-only audit trail
|
|
858
|
+
{ seq: 1, at: "...", wave: 0, fromState: null, toState: "completed", source: "live-launcher", ... }
|
|
859
|
+
]
|
|
860
|
+
}
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### Evidence Collection
|
|
864
|
+
|
|
865
|
+
Every state transition records comprehensive evidence via `buildRunStateEvidence()`:
|
|
866
|
+
|
|
867
|
+
- `waveFileHash`: SHA256 of the wave definition file
|
|
868
|
+
- `statusFiles[]`: Per-agent status file metadata (path, promptHash, exit code, SHA256)
|
|
869
|
+
- `summaryFiles[]`: Per-agent execution summary metadata (path, SHA256)
|
|
870
|
+
- `coordinationLogSha256`: Hash of the coordination log at transition time
|
|
871
|
+
- `assignmentsSha256`: Hash of the assignment snapshot
|
|
872
|
+
- `dependencySnapshotSha256`: Hash of the dependency snapshot
|
|
873
|
+
- `gateSnapshotSha256`: Hash of the gate snapshot
|
|
874
|
+
- `blockedReasons[]`: List of blocking reasons (if transition is to "blocked")
|
|
875
|
+
|
|
876
|
+
This makes every run-state transition auditable: you can verify exactly what evidence supported the decision.
|
|
877
|
+
|
|
878
|
+
### Reconcile-Only Mode
|
|
879
|
+
|
|
880
|
+
`wave launch --reconcile-status` runs reconciliation without executing any waves. It also cleans up stale artifacts:
|
|
881
|
+
|
|
882
|
+
- Removes stale launcher locks (from crashed launchers)
|
|
883
|
+
- Kills orphaned tmux sessions
|
|
884
|
+
- Prunes stale terminal registry entries
|
|
885
|
+
- Clears stale dashboard artifacts
|
|
886
|
+
|
|
887
|
+
Output format (`reconcile-format.mjs`):
|
|
888
|
+
```
|
|
889
|
+
[reconcile] added from status files: wave-0, wave-1
|
|
890
|
+
[reconcile] wave 2 not reconstructable: nonzero-status=A1 exited 1; open-clarification=CR-001
|
|
891
|
+
[reconcile] wave 3 preserved as completed: prompt-hash-mismatch=A2 hash changed
|
|
892
|
+
[reconcile] completed waves now: 0, 1, 3
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
## 11. Sandbox Supervisor Model
|
|
898
|
+
|
|
899
|
+
### The Problem
|
|
900
|
+
|
|
901
|
+
Sandboxed environments (like Codex's sandbox) have constraints that break the standard launcher model:
|
|
902
|
+
|
|
903
|
+
- **Short-lived sessions**: Sandbox `exec` commands have wall-clock timeouts shorter than real wave execution
|
|
904
|
+
- **Process pressure**: Bursty agent spawning can hit `EAGAIN`, `EMFILE`, `ENFILE` limits
|
|
905
|
+
- **Launcher death**: The launcher process can die before agents finish, orphaning tmux sessions
|
|
906
|
+
- **Ambiguous terminal state**: A missing tmux session does not mean the agent failed
|
|
907
|
+
|
|
908
|
+
The standard `wave launch` model assumes the launcher process stays alive for the entire wave. In sandboxed environments, this assumption breaks.
|
|
909
|
+
|
|
910
|
+
### Solution: Async Submit/Observe
|
|
911
|
+
|
|
912
|
+
The sandbox model separates the client (short-lived) from the daemon (long-running) through five commands:
|
|
913
|
+
|
|
914
|
+
```
|
|
915
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
916
|
+
│ wave submit [launcher options] [--json] │
|
|
917
|
+
│ │
|
|
918
|
+
│ Purpose: Quick queue, return runId, exit immediately │
|
|
919
|
+
│ 1. Parse and validate launcher flags │
|
|
920
|
+
│ 2. Generate runId: run-<timestamp>-<random> │
|
|
921
|
+
│ 3. Create supervisor/runs/<runId>/ │
|
|
922
|
+
│ 4. Write request.json (immutable) + state.json (status=pending) │
|
|
923
|
+
│ 5. Append event to events.jsonl: { type: "submitted" } │
|
|
924
|
+
│ 6. Call ensureSupervisorRunning() — spawn daemon if needed │
|
|
925
|
+
│ 7. Return { runId, statePath, supervisorPid } │
|
|
926
|
+
│ 8. Exit 0 │
|
|
927
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
928
|
+
|
|
929
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
930
|
+
│ wave supervise [--project <id>] [--lane <name>] [--once] │
|
|
931
|
+
│ │
|
|
932
|
+
│ Purpose: Long-running daemon that claims and supervises runs │
|
|
933
|
+
│ Loop: │
|
|
934
|
+
│ 1. Update heartbeat + lease in daemon.lock (15s renewal) │
|
|
935
|
+
│ 2. Scan supervisor/runs/*/state.json for all states │
|
|
936
|
+
│ 3. Reconcile "running" states: │
|
|
937
|
+
│ - If launcher-status.json exists → read exit code → terminal │
|
|
938
|
+
│ - If PID alive (signal 0) → still running │
|
|
939
|
+
│ - If PID dead + no status → mark failed │
|
|
940
|
+
│ 4. If no active runs: claim next "pending" run │
|
|
941
|
+
│ - Spawn detached launcher process │
|
|
942
|
+
│ - Launcher writes to launcher.log │
|
|
943
|
+
│ - Launcher writes launcher-status.json atomically on exit │
|
|
944
|
+
│ 5. Sleep 2s, repeat (or break if --once) │
|
|
945
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
946
|
+
|
|
947
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
948
|
+
│ wave status --run-id <id> [--project <id>] [--lane <name>] [--json] │
|
|
949
|
+
│ │
|
|
950
|
+
│ Purpose: Read-only state snapshot (no side effects) │
|
|
951
|
+
│ Reads supervisor/runs/<runId>/state.json and returns current state │
|
|
952
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
953
|
+
|
|
954
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
955
|
+
│ wave wait --run-id <id> [--timeout-seconds <n>] [--json] │
|
|
956
|
+
│ │
|
|
957
|
+
│ Purpose: Observational poll until terminal or timeout │
|
|
958
|
+
│ Polls state.json every 2s │
|
|
959
|
+
│ Returns when status ∈ {completed, failed} or deadline reached │
|
|
960
|
+
│ Non-cancelling: timeout does NOT kill the run │
|
|
961
|
+
│ Sets process.exitCode from launcher exit code │
|
|
962
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
963
|
+
|
|
964
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
965
|
+
│ wave attach --run-id <id> --project <id> --lane <name> ... │
|
|
966
|
+
│ │
|
|
967
|
+
│ Purpose: Projection-only attach surface │
|
|
968
|
+
│ --agent <id> attaches to a live session when one exists, otherwise │
|
|
969
|
+
│ follows the recorded agent log │
|
|
970
|
+
│ --dashboard reuses the stable lane dashboard attach flow │
|
|
971
|
+
│ Missing projection is an operator error, not a run-health verdict │
|
|
972
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
### Run State Machine
|
|
976
|
+
|
|
977
|
+
```
|
|
978
|
+
┌─────────────────────────────────────────────┐
|
|
979
|
+
│ "pending" │
|
|
980
|
+
│ • submittedAt set │
|
|
981
|
+
│ • launcherPid: null, exitCode: null │
|
|
982
|
+
└──────────┬──────────────────────────────────┘
|
|
983
|
+
│ daemon claims run, spawns launcher
|
|
984
|
+
┌──────────▼──────────────────────────────────┐
|
|
985
|
+
│ "running" │
|
|
986
|
+
│ • startedAt set │
|
|
987
|
+
│ • launcherPid: <pid> (detached process) │
|
|
988
|
+
└──────────┬──────────────────────────────────┘
|
|
989
|
+
│ launcher writes launcher-status.json
|
|
990
|
+
│ OR launcher process dies unexpectedly
|
|
991
|
+
┌──────────▼──────────────────────────────────┐
|
|
992
|
+
│ "completed" | "failed" │
|
|
993
|
+
│ • completedAt set │
|
|
994
|
+
│ • exitCode: <0|1|...> │
|
|
995
|
+
└─────────────────────────────────────────────┘
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
### Daemon Lock and Lease Mechanism
|
|
999
|
+
|
|
1000
|
+
Only one supervisor daemon runs per lane. The lock at `.tmp/<lane>-wave-launcher/supervisor/daemon.lock` contains:
|
|
1001
|
+
|
|
1002
|
+
```javascript
|
|
1003
|
+
{
|
|
1004
|
+
supervisorId: "supervisor-<pid>-<random>",
|
|
1005
|
+
pid: 45821,
|
|
1006
|
+
project: "default",
|
|
1007
|
+
lane: "main",
|
|
1008
|
+
acquiredAt: "2024-03-22T10:30:00.000Z",
|
|
1009
|
+
heartbeatAt: "2024-03-22T10:30:15.000Z", // renewed every poll cycle
|
|
1010
|
+
leaseExpiresAt: "2024-03-22T10:30:17.000Z" // 15s from heartbeat
|
|
1011
|
+
}
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
**Acquisition:** Try exclusive file create (`O_EXCL`). If the file exists:
|
|
1015
|
+
- Read the existing lock
|
|
1016
|
+
- Check if the PID is alive (`process.kill(pid, 0)`) AND the lease is fresh (`leaseExpiresAt > now`)
|
|
1017
|
+
- If stale or dead: delete the lock, retry
|
|
1018
|
+
- If alive and fresh: return `null` (daemon already running)
|
|
1019
|
+
|
|
1020
|
+
**Renewal:** Each poll cycle updates `heartbeatAt` and extends `leaseExpiresAt` by 15 seconds.
|
|
1021
|
+
|
|
1022
|
+
**Stale detection:** If `leaseExpiresAt < Date.now()` and PID is not responding to signal 0, the lock is considered stale and can be claimed by a new daemon.
|
|
1023
|
+
|
|
1024
|
+
### Launcher Spawning
|
|
1025
|
+
|
|
1026
|
+
When the daemon claims a pending run, it spawns the launcher as a **detached child process**:
|
|
1027
|
+
|
|
1028
|
+
```javascript
|
|
1029
|
+
spawn('bash', ['-lc', wrapperCommand], {
|
|
1030
|
+
cwd: REPO_ROOT,
|
|
1031
|
+
detached: true, // survives daemon exit
|
|
1032
|
+
stdio: "ignore", // no parent I/O dependency
|
|
1033
|
+
env: { ...process.env, WAVE_SUPERVISOR_RUN_ID: runId }
|
|
1034
|
+
});
|
|
1035
|
+
child.unref(); // parent won't wait for exit
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
The wrapper shell command:
|
|
1039
|
+
1. Runs `node wave-launcher.mjs <args>`
|
|
1040
|
+
2. Redirects all output to `launcher.log`
|
|
1041
|
+
3. Captures the exit code
|
|
1042
|
+
4. Writes `launcher-status.json` atomically (the terminal state marker)
|
|
1043
|
+
|
|
1044
|
+
**Critical design choice:** `detached: true` + `unref()` means the launcher process survives even if the supervisor daemon dies. The daemon does not need to stay alive for the launcher to complete.
|
|
1045
|
+
|
|
1046
|
+
### Orphan Adoption
|
|
1047
|
+
|
|
1048
|
+
If the supervisor daemon dies and restarts (or a new daemon starts):
|
|
1049
|
+
|
|
1050
|
+
1. New daemon acquires the lock (old one is stale)
|
|
1051
|
+
2. Scans `supervisor/runs/*/state.json` for runs in "running" state
|
|
1052
|
+
3. For each running run:
|
|
1053
|
+
- Check `launcher-status.json`
|
|
1054
|
+
- If present: reconcile to `completed` or `failed` based on exit code
|
|
1055
|
+
- Else check if the launcher PID is alive (`process.kill(pid, 0)`)
|
|
1056
|
+
- If alive: the run is healthy, just supervise it
|
|
1057
|
+
- Else inspect any `agents/*.runtime.json`
|
|
1058
|
+
- If a runtime PID is alive or heartbeat is fresh: keep the run running with degraded terminal disposition
|
|
1059
|
+
- If all runtime records are terminal and no launcher status exists: mark as `failed` with detail "launcher exited before writing status"
|
|
1060
|
+
|
|
1061
|
+
This is conservative: the daemon only cleans up after confirming both that the PID is dead and the lease has expired.
|
|
1062
|
+
|
|
1063
|
+
### Supervisor State Files
|
|
1064
|
+
|
|
1065
|
+
All supervisor state lives under `.tmp/<lane>-wave-launcher/supervisor/`:
|
|
1066
|
+
|
|
1067
|
+
```
|
|
1068
|
+
supervisor/
|
|
1069
|
+
├── daemon.lock Daemon lease file
|
|
1070
|
+
└── runs/
|
|
1071
|
+
└── <runId>/
|
|
1072
|
+
├── request.json Immutable: submitted request (never changes)
|
|
1073
|
+
├── state.json Mutable: current daemon snapshot
|
|
1074
|
+
├── events.jsonl Append-only: supervisor observation history
|
|
1075
|
+
├── launcher-status.json Atomic: launcher exit record (written once)
|
|
1076
|
+
└── launcher.log Text: launcher stdout/stderr stream
|
|
1077
|
+
└── agents/
|
|
1078
|
+
└── <agentId>.runtime.json Runtime pid/heartbeat/disposition snapshot (`agents/<agentId>.runtime.json`)
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
### Canonical Authority in Sandboxed Runs
|
|
1082
|
+
|
|
1083
|
+
The sandbox model adds a fourth observation layer but does not change the canonical authority set:
|
|
1084
|
+
|
|
1085
|
+
| Authority | What It Covers |
|
|
1086
|
+
|-----------|---------------|
|
|
1087
|
+
| Wave definitions | Declared work, closure roles, proof contracts |
|
|
1088
|
+
| Coordination log | Workflow state, claims, evidence, blockers |
|
|
1089
|
+
| Control-plane log | Entity lifecycle, proof bundles, gates |
|
|
1090
|
+
| **Supervisor run state** | **Daemon-observed runtime facts (PIDs, exits, leases)** |
|
|
1091
|
+
|
|
1092
|
+
The supervisor state is authoritative for *what the daemon observed about process execution*. It does not override wave definitions or coordination state.
|
|
1093
|
+
|
|
1094
|
+
### Typical Sandbox Workflow
|
|
1095
|
+
|
|
1096
|
+
For operator setup in LEAPclaw, OpenClaw, Nemoshell, Docker, and similar short-lived exec environments, read [../guides/sandboxed-environments.md](../guides/sandboxed-environments.md) first. The example below shows the runtime shape, not the full operator checklist.
|
|
1097
|
+
|
|
1098
|
+
```bash
|
|
1099
|
+
# Client: quick exit, daemon takes over
|
|
1100
|
+
runId=$(wave submit --project backend --lane main \
|
|
1101
|
+
--executor codex --no-dashboard --json | jq -r .runId)
|
|
1102
|
+
|
|
1103
|
+
# Client: wait with timeout (non-cancelling)
|
|
1104
|
+
wave wait --run-id "$runId" --project backend --lane main --timeout-seconds 600
|
|
1105
|
+
|
|
1106
|
+
# Or poll from external automation
|
|
1107
|
+
wave status --run-id "$runId" --project backend --lane main --json
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
### Current Limitations
|
|
1111
|
+
|
|
1112
|
+
The sandbox supervisor model is functional but some design-doc features are still partial:
|
|
1113
|
+
|
|
1114
|
+
- **Per-agent runtime records** now exist and carry PID, PGID, heartbeat, runner metadata, and terminal disposition, and the supervisor can now recover completed runs from finalized progress journals or canonical run-state when the launcher exits late
|
|
1115
|
+
- **Full orphan adoption** across daemon restarts remains partial; the daemon can continue supervising degraded runs, resume the active wave, and recover finalized status from canonical state, but it still refuses to synthesize success from agent runtime files alone
|
|
1116
|
+
- **Tmux is now dashboard-only**. Agent execution uses detached process runners, `wave attach --agent` falls back to log following when no live interactive session exists, and dashboard attach falls back to the last written dashboard file when no live dashboard session is present
|
|
1117
|
+
- **Setup guidance is split by intent**. Use [../guides/sandboxed-environments.md](../guides/sandboxed-environments.md) for operator setup, deployment, and container advice, and keep [../plans/sandbox-end-state-architecture.md](../plans/sandbox-end-state-architecture.md) for the deeper design rationale and remaining gap analysis
|
|
1118
|
+
|
|
1119
|
+
---
|
|
1120
|
+
|
|
1121
|
+
## 12. Runtime Abstraction and Executor Adapters
|
|
1122
|
+
|
|
1123
|
+
### What Stays the Same Across Runtimes
|
|
1124
|
+
|
|
1125
|
+
- Wave parsing and validation
|
|
1126
|
+
- State reduction and phase decisions
|
|
1127
|
+
- Eval targets, deliverables, proof artifacts
|
|
1128
|
+
- Component and closure gates
|
|
1129
|
+
- Skill resolution (resolved before executor projection)
|
|
1130
|
+
- Shared summaries and inboxes
|
|
1131
|
+
- Authority-set state and projections
|
|
1132
|
+
- Trace bundles and replay
|
|
1133
|
+
|
|
1134
|
+
### Where Runtime-Specific Logic Lives
|
|
1135
|
+
|
|
1136
|
+
The `executors.mjs` module builds launch specs for each runtime:
|
|
1137
|
+
|
|
1138
|
+
**Codex** (`codex exec`):
|
|
1139
|
+
- `--sandbox` flags (none, unsafe-full-access, danger-full-access)
|
|
1140
|
+
- `--add-dir` for skill directory projection
|
|
1141
|
+
- JSON mode, search, images support
|
|
1142
|
+
- Full-access sandbox modes for repo-modifying work
|
|
1143
|
+
|
|
1144
|
+
**Claude** (`claude -p`):
|
|
1145
|
+
- System prompt overlay via `--system-prompt`
|
|
1146
|
+
- Settings merge from `.claude/settings.json`
|
|
1147
|
+
- Hooks and permission model
|
|
1148
|
+
- Skill text merged into system prompt
|
|
1149
|
+
|
|
1150
|
+
**OpenCode** (`opencode run`):
|
|
1151
|
+
- Generated `opencode.json` configuration
|
|
1152
|
+
- Attached files and instruction overlays
|
|
1153
|
+
- Skill content projected through config
|
|
1154
|
+
|
|
1155
|
+
**LEAP-claw** (proprietary agent framework):
|
|
1156
|
+
- Wave's orchestration substrate serves as the runtime for LEAP-claw agents
|
|
1157
|
+
- LEAP-claw agents participate in the same blackboard coordination, proof, and closure model as any other executor
|
|
1158
|
+
- Proprietary planning and reasoning strategies are layered on top of Wave's canonical authority set
|
|
1159
|
+
- Skill projection, context compilation, and result envelope contracts apply identically
|
|
1160
|
+
- LEAP-claw agents can be mixed with Codex, Claude, and OpenCode agents within the same wave via the runtime mix policy
|
|
1161
|
+
|
|
1162
|
+
**Local** (smoke executor):
|
|
1163
|
+
- Prompt/closure verification without a real hosted runtime
|
|
1164
|
+
- Used for testing and dry-run validation
|
|
1165
|
+
|
|
1166
|
+
### Runtime Resolution Order
|
|
1167
|
+
|
|
1168
|
+
When determining which executor an agent uses:
|
|
1169
|
+
|
|
1170
|
+
1. Explicit `### Executor` block in the agent's wave definition
|
|
1171
|
+
2. Executor profile id from config
|
|
1172
|
+
3. Lane role default from `wave.config.json`
|
|
1173
|
+
4. CLI `--executor` flag
|
|
1174
|
+
5. Global default executor
|
|
1175
|
+
|
|
1176
|
+
### Runtime Mix Policy
|
|
1177
|
+
|
|
1178
|
+
Waves can use multiple executors simultaneously. The config supports:
|
|
1179
|
+
- Mix targets capping agents per executor
|
|
1180
|
+
- Profiles declaring fallback chains
|
|
1181
|
+
- Lane policy supplying role-based defaults
|
|
1182
|
+
- Retry-time reassignment to policy-safe fallbacks
|
|
1183
|
+
|
|
1184
|
+
---
|
|
1185
|
+
|
|
1186
|
+
## 13. Skills, Context7, and Compiled Context
|
|
1187
|
+
|
|
1188
|
+
### Skills System
|
|
1189
|
+
|
|
1190
|
+
Skills are reusable operating knowledge bundles stored in `skills/<skill-id>/`:
|
|
1191
|
+
|
|
1192
|
+
```
|
|
1193
|
+
skills/<skill-id>/
|
|
1194
|
+
skill.json -- metadata: id, name, description, tags, roles, runtimes
|
|
1195
|
+
SKILL.md -- reusable instructions (runtime-agnostic)
|
|
1196
|
+
adapters/
|
|
1197
|
+
codex.md -- Codex-specific overlay
|
|
1198
|
+
claude.md -- Claude-specific overlay
|
|
1199
|
+
opencode.md -- OpenCode-specific overlay
|
|
1200
|
+
local.md -- Local executor overlay
|
|
1201
|
+
references/ -- optional reference material
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
**Resolution order:**
|
|
1205
|
+
1. Base skills (global)
|
|
1206
|
+
2. Role-specific skills (e.g., `role-design/`, `role-implementation/`)
|
|
1207
|
+
3. Runtime-specific skills (e.g., `runtime-claude/`, `runtime-codex/`)
|
|
1208
|
+
4. Deploy-kind skills (e.g., `provider-railway/`)
|
|
1209
|
+
5. Explicit per-agent `### Skills` in wave definition
|
|
1210
|
+
|
|
1211
|
+
The orchestrator resolves skill IDs without knowing the runtime. The executor adapter then projects skills into the runtime's surface:
|
|
1212
|
+
- Codex: skill directories via `--add-dir`
|
|
1213
|
+
- Claude: merged skill text in system prompt overlay
|
|
1214
|
+
- OpenCode: instructions and attached files via generated config
|
|
1215
|
+
- Local: prompt-only projections
|
|
1216
|
+
|
|
1217
|
+
### Context7
|
|
1218
|
+
|
|
1219
|
+
Context7 provides external documentation fetched at launch time. The integration works as:
|
|
1220
|
+
|
|
1221
|
+
1. `wave.config.json` declares a Context7 bundle index at `docs/context7/bundle-index.json`
|
|
1222
|
+
2. Wave definitions can declare `### Context7` selections per agent
|
|
1223
|
+
3. At launch, `prefetchContext7ForSelection()` fetches library documentation
|
|
1224
|
+
4. Fetched content is cached in `.tmp/<lane>-wave-launcher/context7/`
|
|
1225
|
+
5. Context7 content is injected into the agent's execution prompt
|
|
1226
|
+
|
|
1227
|
+
### Compiled Context
|
|
1228
|
+
|
|
1229
|
+
Rather than hand-maintaining separate context files for each runtime, Wave compiles context dynamically:
|
|
1230
|
+
|
|
1231
|
+
1. **Project profile** (`.wave/project-profile.json`): Repo-level defaults
|
|
1232
|
+
2. **Shared summary**: Aggregated coordination state
|
|
1233
|
+
3. **Per-agent inbox**: Filtered coordination state
|
|
1234
|
+
4. **Skills**: Resolved and projected for the target runtime
|
|
1235
|
+
5. **Context7**: External documentation fetched at launch
|
|
1236
|
+
6. **Signal state**: Versioned signal projections for long-running agents
|
|
1237
|
+
7. **Design packets**: Output from design-pass agents
|
|
1238
|
+
8. **Message board**: Human-readable coordination projection
|
|
1239
|
+
|
|
1240
|
+
All of this is assembled into a single execution prompt per agent at launch time by `buildExecutionPrompt()` in `coordination.mjs`.
|
|
1241
|
+
|
|
1242
|
+
---
|
|
1243
|
+
|
|
1244
|
+
## 14. Entity Model
|
|
1245
|
+
|
|
1246
|
+
### Core Entities
|
|
1247
|
+
|
|
1248
|
+
| Entity | Lifecycle States | Purpose |
|
|
1249
|
+
|--------|-----------------|---------|
|
|
1250
|
+
| `wave_run` | planned -> running -> completed\|failed\|blocked | Top-level wave execution |
|
|
1251
|
+
| `agent_run` | planned -> started -> completed\|failed\|timed_out\|cancelled | Per-agent execution |
|
|
1252
|
+
| `attempt` | planned -> running -> completed\|failed\|cancelled | One execution pass (wave can have multiple) |
|
|
1253
|
+
| `proof_bundle` | active -> superseded\|revoked | Proof evidence with SHA256 validation |
|
|
1254
|
+
| `rerun_request` | active -> applied\|cleared | Operator-requested targeted reruns |
|
|
1255
|
+
| `human_input` | pending -> assigned -> answered\|escalated\|resolved\|timed_out\|rerouted | Human feedback lifecycle |
|
|
1256
|
+
| `gate` | pending -> passed\|blocked\|waived | Gate evaluation result |
|
|
1257
|
+
| `task` | pending -> in_progress -> proven\|blocked -> completed | Durable work unit |
|
|
1258
|
+
| `contradiction` | detected -> repair_needed -> resolved\|dismissed | Conflict between agents |
|
|
1259
|
+
| `fact` | active -> superseded | Stable semantic facts with content hashing |
|
|
1260
|
+
| `coordination_record` | open -> acknowledged -> in_progress -> resolved\|closed\|superseded\|cancelled | Workflow event |
|
|
1261
|
+
|
|
1262
|
+
### Task Entity
|
|
1263
|
+
|
|
1264
|
+
Tasks are first-class entities defined in `task-entity.mjs`:
|
|
1265
|
+
|
|
1266
|
+
- **Task types:** design, implementation, integration, documentation, cont-qa, cont-eval, security, component, helper, dependency, clarification, human-input, escalation
|
|
1267
|
+
- **Closure states:** open -> owned_slice_proven -> wave_closure_ready -> closed (also: cancelled, superseded)
|
|
1268
|
+
- **Lease states:** unleased -> leased -> released\|expired
|
|
1269
|
+
- **Dependency edges:** Tasks can declare `blocks` and `blockedBy` relationships
|
|
1270
|
+
|
|
1271
|
+
The `evaluateOwnedSliceProven()` function checks all per-task closure conditions.
|
|
1272
|
+
|
|
1273
|
+
### Fact Lineage
|
|
1274
|
+
|
|
1275
|
+
Facts have stable semantic IDs with separate content hashing:
|
|
1276
|
+
- `factId`: Stable identifier across versions
|
|
1277
|
+
- `contentHash`: Changes when the fact's content changes
|
|
1278
|
+
- `citedBy`, `contradictedBy`: Cross-referencing for lineage
|
|
1279
|
+
- `supersedes`, `supersededBy`: Version chain
|
|
1280
|
+
|
|
1281
|
+
---
|
|
1282
|
+
|
|
1283
|
+
## 15. Artifact Hierarchy
|
|
1284
|
+
|
|
1285
|
+
Every artifact in the system belongs to exactly one of four classes:
|
|
1286
|
+
|
|
1287
|
+
### Class 1: Canonical Event Streams (append-only, never rewritten)
|
|
1288
|
+
|
|
1289
|
+
| Artifact | Path |
|
|
1290
|
+
|----------|------|
|
|
1291
|
+
| Control-plane log | `.tmp/<lane>-wave-launcher/control-plane/wave-<N>.jsonl` |
|
|
1292
|
+
| Coordination log | `.tmp/<lane>-wave-launcher/coordination/wave-<N>.jsonl` |
|
|
1293
|
+
| Cross-lane dependency tickets | `.tmp/wave-orchestrator/dependencies/<ticket-id>.json` |
|
|
1294
|
+
|
|
1295
|
+
### Class 2: Canonical Structured Snapshots (immutable, attempt-scoped)
|
|
1296
|
+
|
|
1297
|
+
| Artifact | Path |
|
|
1298
|
+
|----------|------|
|
|
1299
|
+
| Agent result envelopes | `.tmp/<lane>-wave-launcher/results/wave-<N>/attempt-<A>/<agentId>.json` |
|
|
1300
|
+
| Design packets | `docs/plans/waves/design/` (repo-owned) |
|
|
1301
|
+
|
|
1302
|
+
### Class 3: Derived Caches (computed from canonical, safe to delete)
|
|
1303
|
+
|
|
1304
|
+
| Artifact | Path |
|
|
1305
|
+
|----------|------|
|
|
1306
|
+
| Shared summaries | `.tmp/<lane>-wave-launcher/coordination/wave-<N>-shared-summary.md` |
|
|
1307
|
+
| Per-agent inboxes | `.tmp/<lane>-wave-launcher/inboxes/wave-<N>/<agentId>.md` |
|
|
1308
|
+
| Assignment snapshots | `.tmp/<lane>-wave-launcher/assignments/wave-<N>.json` |
|
|
1309
|
+
| Dependency snapshots | `.tmp/<lane>-wave-launcher/dependency-snapshots/wave-<N>.json` |
|
|
1310
|
+
| Ledgers | `.tmp/<lane>-wave-launcher/ledger/wave-<N>.json` |
|
|
1311
|
+
| Docs queues | `.tmp/<lane>-wave-launcher/docs-queue/wave-<N>.json` |
|
|
1312
|
+
| Security summaries | `.tmp/<lane>-wave-launcher/security/wave-<N>.json` |
|
|
1313
|
+
| Integration summaries | `.tmp/<lane>-wave-launcher/integration/wave-<N>.json` |
|
|
1314
|
+
|
|
1315
|
+
### Class 4: Human-Facing Projections (generated from canonical + derived)
|
|
1316
|
+
|
|
1317
|
+
| Artifact | Path |
|
|
1318
|
+
|----------|------|
|
|
1319
|
+
| Global dashboard | `.tmp/<lane>-wave-launcher/dashboards/global.json` |
|
|
1320
|
+
| Per-wave dashboard | `.tmp/<lane>-wave-launcher/dashboards/wave-<N>.json` |
|
|
1321
|
+
| Markdown boards | `.tmp/<lane>-wave-launcher/coordination/wave-<N>-board.md` |
|
|
1322
|
+
| Status files | `.tmp/<lane>-wave-launcher/status/` |
|
|
1323
|
+
| Trace bundles | `.tmp/<lane>-wave-launcher/traces/wave-<N>/attempt-<A>/` |
|
|
1324
|
+
| Signal projections | `.tmp/<lane>-wave-launcher/signals/` |
|
|
1325
|
+
| Proof registries | `.tmp/<lane>-wave-launcher/proof/wave-<N>.json` |
|
|
1326
|
+
| Retry overrides | `.tmp/<lane>-wave-launcher/control/retry-override-wave-<N>.json` |
|
|
1327
|
+
|
|
1328
|
+
**Critical rule:** Decision-making modules (gates, retry, closure, reducer) read only Class 1 and Class 2 artifacts. Classes 3 and 4 exist for human operators and agent context injection.
|
|
1329
|
+
|
|
1330
|
+
---
|
|
1331
|
+
|
|
1332
|
+
## 16. Telemetry and Wave Control
|
|
1333
|
+
|
|
1334
|
+
### Local-First Model
|
|
1335
|
+
|
|
1336
|
+
Wave Control is a local-first telemetry system with optional remote delivery:
|
|
1337
|
+
|
|
1338
|
+
1. **Local event spool.** All events are first written to the local control-plane JSONL log.
|
|
1339
|
+
2. **Queue for remote delivery.** Events are batched into a queue for the Wave Control service.
|
|
1340
|
+
3. **Best-effort delivery.** Remote delivery is non-blocking. If it fails, the local spool is the authoritative record.
|
|
1341
|
+
4. **Metadata-only by default.** The packaged default mode is `metadata-only`, sending only structured metadata (not full logs or source code).
|
|
1342
|
+
|
|
1343
|
+
### Event Types
|
|
1344
|
+
|
|
1345
|
+
The `wave-control-schema.mjs` module normalizes these entity types:
|
|
1346
|
+
- `wave_run`, `agent_run`, `wave_signal`, `agent_signal`
|
|
1347
|
+
- `coordination_record`, `task`, `attempt`, `gate`, `proof_bundle`
|
|
1348
|
+
- `rerun_request`, `human_input`, `artifact`, `contradiction`, `fact`
|
|
1349
|
+
- `benchmark_run`, `benchmark_item`, `verification`, `review`
|
|
1350
|
+
|
|
1351
|
+
### Configuration
|
|
1352
|
+
|
|
1353
|
+
```json
|
|
1354
|
+
// wave.config.json
|
|
1355
|
+
{
|
|
1356
|
+
"waveControl": {
|
|
1357
|
+
"enabled": true,
|
|
1358
|
+
"endpoint": "https://wave-control.up.railway.app/api/v1",
|
|
1359
|
+
"reportMode": "metadata-only",
|
|
1360
|
+
"authTokenEnv": "WAVE_CONTROL_AUTH_TOKEN"
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
```
|
|
1364
|
+
|
|
1365
|
+
Opt-out options:
|
|
1366
|
+
- `waveControl.enabled: false` in config
|
|
1367
|
+
- `waveControl.reportMode: "disabled"` in config
|
|
1368
|
+
- `--no-telemetry` CLI flag
|
|
1369
|
+
|
|
1370
|
+
---
|
|
1371
|
+
|
|
1372
|
+
## 17. CLI Surface Map
|
|
1373
|
+
|
|
1374
|
+
### Command Groups
|
|
1375
|
+
|
|
1376
|
+
| Command | Module | Purpose |
|
|
1377
|
+
|---------|--------|---------|
|
|
1378
|
+
| `wave init` | `install.mjs` | Initialize workspace with Wave |
|
|
1379
|
+
| `wave upgrade` | `install.mjs` | Upgrade existing Wave config |
|
|
1380
|
+
| `wave self-update` | `install.mjs` | Update the Wave package |
|
|
1381
|
+
| `wave doctor` | `install.mjs` | Validate workspace setup |
|
|
1382
|
+
| `wave project setup` | `planner.mjs` | Save project defaults |
|
|
1383
|
+
| `wave draft` | `planner.mjs` | Generate wave definitions |
|
|
1384
|
+
| `wave launch` | `launcher.mjs` | Execute waves (core orchestrator) |
|
|
1385
|
+
| `wave autonomous` | `autonomous.mjs` | Multi-wave autonomous execution |
|
|
1386
|
+
| `wave submit` | `supervisor-cli.mjs` | Submit async run request |
|
|
1387
|
+
| `wave supervise` | `supervisor-cli.mjs` | Long-running supervisor daemon |
|
|
1388
|
+
| `wave status` | `supervisor-cli.mjs` | Read supervisor run state |
|
|
1389
|
+
| `wave wait` | `supervisor-cli.mjs` | Wait for run completion |
|
|
1390
|
+
| `wave control` | `control-cli.mjs` | Read-only status, task, rerun, proof, telemetry surfaces |
|
|
1391
|
+
| `wave coord` | `coord-cli.mjs` | Direct coordination log inspection |
|
|
1392
|
+
| `wave feedback` | `feedback.mjs` | Human feedback collection and delivery |
|
|
1393
|
+
| `wave dashboard` | `dashboard-renderer.mjs` | Dashboard rendering and display |
|
|
1394
|
+
| `wave retry` | `retry-cli.mjs` | Retry control (legacy, prefer `wave control rerun`) |
|
|
1395
|
+
| `wave proof` | `proof-cli.mjs` | Proof registry (legacy, prefer `wave control proof`) |
|
|
1396
|
+
| `wave dep` | `dep-cli.mjs` | Cross-lane dependency management |
|
|
1397
|
+
| `wave adhoc` | `adhoc.mjs` | Ad-hoc transient runs |
|
|
1398
|
+
| `wave benchmark` | `benchmark.mjs` | Benchmark execution and tracking |
|
|
1399
|
+
| `wave local` | `local-executor.mjs` | Local smoke executor |
|
|
1400
|
+
|
|
1401
|
+
### Preferred Operator Surfaces
|
|
1402
|
+
|
|
1403
|
+
`wave control` is the preferred operator surface for runtime interaction:
|
|
1404
|
+
- `wave control status` -- live state projection
|
|
1405
|
+
- `wave control task` -- create, get, list, act on blocking items
|
|
1406
|
+
- `wave control rerun` -- targeted rerun management
|
|
1407
|
+
- `wave control proof` -- proof bundle management
|
|
1408
|
+
- `wave control telemetry` -- event queue inspection
|
|
1409
|
+
|
|
1410
|
+
Legacy surfaces (`wave coord`, `wave retry`, `wave proof`) remain for direct log inspection but `wave control` is the recommended path.
|
|
1411
|
+
|
|
1412
|
+
---
|
|
1413
|
+
|
|
1414
|
+
## 18. Research Grounding
|
|
1415
|
+
|
|
1416
|
+
Wave's architecture is directly informed by published research on multi-agent systems, harness engineering, and coordination failure. The key sources and how they map to the architecture:
|
|
1417
|
+
|
|
1418
|
+
### Harness and Runtime
|
|
1419
|
+
|
|
1420
|
+
| Source | Architectural Influence |
|
|
1421
|
+
|--------|------------------------|
|
|
1422
|
+
| [Effective harnesses for long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) (Anthropic) | Session supervisor design, structured status files, timeout handling |
|
|
1423
|
+
| [Harness engineering: leveraging Codex](https://openai.com/index/harness-engineering/) (OpenAI) | Executor adapter model, sandbox modes, launch spec pattern |
|
|
1424
|
+
| [Building Effective AI Coding Agents for the Terminal](https://arxiv.org/abs/2603.05344) | Terminal surface management, tmux session model, runtime overlays |
|
|
1425
|
+
| [Verified Multi-Agent Orchestration](https://arxiv.org/abs/2603.11445) | Plan-execute-verify-replan maps to Wave's implementation-gate-retry-closure cycle |
|
|
1426
|
+
|
|
1427
|
+
### Coordination and Closure
|
|
1428
|
+
|
|
1429
|
+
| Source | Architectural Influence |
|
|
1430
|
+
|--------|------------------------|
|
|
1431
|
+
| [LLM-Based Multi-Agent Blackboard System](https://arxiv.org/abs/2510.01285) | Blackboard architecture pattern, shared state over direct messaging |
|
|
1432
|
+
| [Exploring Advanced LLM Multi-Agent Systems Based on Blackboard Architecture](https://arxiv.org/abs/2507.01701) | Projection model (canonical state -> derived views -> human projections) |
|
|
1433
|
+
| [Why Do Multi-Agent LLM Systems Fail?](https://arxiv.org/abs/2503.13657) | Failure taxonomy that Wave's gate stack addresses point by point |
|
|
1434
|
+
| [Silo-Bench](https://arxiv.org/abs/2603.01045) | Integration barriers, dependency barriers, evidence pooling mechanisms |
|
|
1435
|
+
|
|
1436
|
+
### Skills and Context
|
|
1437
|
+
|
|
1438
|
+
| Source | Architectural Influence |
|
|
1439
|
+
|--------|------------------------|
|
|
1440
|
+
| [SoK: Agentic Skills](https://arxiv.org/abs/2602.20867) | Skill bundle format, resolution order, runtime projection |
|
|
1441
|
+
| [Agent Workflow Memory](https://arxiv.org/abs/2409.07429) | Compiled context model, dynamic assembly over static files |
|
|
1442
|
+
| [Agent READMEs](https://arxiv.org/abs/2511.12884) | Project profile, shared plan docs, per-agent context compilation |
|
|
1443
|
+
|
|
1444
|
+
### Evaluation and Benchmarking
|
|
1445
|
+
|
|
1446
|
+
| Source | Architectural Influence |
|
|
1447
|
+
|--------|------------------------|
|
|
1448
|
+
| [EvoClaw: Evaluating AI Agents on Continuous Software Evolution](https://arxiv.org/abs/2603.13428) | Adapted as `evoclaw-style-sequence` benchmark family for measuring long-horizon wave sequencing, dependent wave maintenance, and error accumulation across wave chains |
|
|
1449
|
+
| [VeRO: An Evaluation Harness for Agents to Optimize Agents](https://arxiv.org/abs/2602.22480) | Proof-oriented evaluation model, benchmark validity buckets, review entity types |
|
|
1450
|
+
| [MetaClaw: Just Talk](https://arxiv.org/abs/2603.17187) | Failure-driven skill synthesis, zero-downtime evolution of agent capabilities (referenced via OpenClaw platform) |
|
|
1451
|
+
|
|
1452
|
+
**Note on naming:** LEAP-claw is the proprietary agent framework built on Wave's orchestration substrate. OpenClaw, EvoClaw, and MetaClaw are unrelated external projects: OpenClaw is an open-source multi-agent platform, EvoClaw and MetaClaw are research papers. Wave adapts their evaluation methodologies into its benchmark catalog (`docs/evals/external-benchmarks.json`) but does not embed or depend on their codebases. The `leap-claw` identifier also appears in test fixtures as a lane name for integration testing.
|
|
1453
|
+
|
|
1454
|
+
### Known Gaps
|
|
1455
|
+
|
|
1456
|
+
The architecture addresses the documented failure modes structurally but empirical validation is still in progress:
|
|
1457
|
+
- Limited published results on coordination-oriented benchmarks exercised systematically
|
|
1458
|
+
- Stress data on simultaneous coordination under contention is limited
|
|
1459
|
+
- Expertise routing is explicit but shallow (declared capability, not demonstrated quality)
|
|
1460
|
+
- DPBench-style simultaneous coordination is only indirectly addressed
|
|
1461
|
+
|
|
1462
|
+
---
|
|
1463
|
+
|
|
1464
|
+
## Appendix: Key File Paths
|
|
1465
|
+
|
|
1466
|
+
```
|
|
1467
|
+
Entry point: scripts/wave.mjs
|
|
1468
|
+
Core orchestrator: scripts/wave-orchestrator/launcher.mjs
|
|
1469
|
+
Phase engines: scripts/wave-orchestrator/{implementation,derived-state,gate,closure,retry}-engine.mjs
|
|
1470
|
+
State reducer: scripts/wave-orchestrator/wave-state-reducer.mjs
|
|
1471
|
+
Session supervisor: scripts/wave-orchestrator/session-supervisor.mjs
|
|
1472
|
+
Supervisor CLI: scripts/wave-orchestrator/supervisor-cli.mjs
|
|
1473
|
+
Projection writer: scripts/wave-orchestrator/projection-writer.mjs
|
|
1474
|
+
Wave parser: scripts/wave-orchestrator/wave-files.mjs
|
|
1475
|
+
Reconcile formatting: scripts/wave-orchestrator/reconcile-format.mjs
|
|
1476
|
+
Agent state: scripts/wave-orchestrator/agent-state.mjs
|
|
1477
|
+
Task entities: scripts/wave-orchestrator/task-entity.mjs
|
|
1478
|
+
Coordination store: scripts/wave-orchestrator/coordination-store.mjs
|
|
1479
|
+
Control plane: scripts/wave-orchestrator/control-plane.mjs
|
|
1480
|
+
Executor adapters: scripts/wave-orchestrator/executors.mjs
|
|
1481
|
+
Skills: scripts/wave-orchestrator/skills.mjs
|
|
1482
|
+
Context7: scripts/wave-orchestrator/context7.mjs
|
|
1483
|
+
Config: scripts/wave-orchestrator/config.mjs
|
|
1484
|
+
Result envelopes: scripts/wave-orchestrator/result-envelope.mjs
|
|
1485
|
+
Contradictions: scripts/wave-orchestrator/contradiction-entity.mjs
|
|
1486
|
+
Signals: scripts/wave-orchestrator/signals.mjs
|
|
1487
|
+
Traces: scripts/wave-orchestrator/traces.mjs
|
|
1488
|
+
Tests: test/wave-orchestrator/*.test.ts (61 files)
|
|
1489
|
+
Wave config: wave.config.json
|
|
1490
|
+
Wave definitions: docs/plans/waves/wave-<N>.md
|
|
1491
|
+
Skills bundles: skills/<skill-id>/
|
|
1492
|
+
Run state: .tmp/<lane>-wave-launcher/run-state.json
|
|
1493
|
+
Supervisor state: .tmp/<lane>-wave-launcher/supervisor/
|
|
1494
|
+
Supervisor daemon lock: .tmp/<lane>-wave-launcher/supervisor/daemon.lock
|
|
1495
|
+
Supervisor runs: .tmp/<lane>-wave-launcher/supervisor/runs/<runId>/
|
|
1496
|
+
Sandbox setup guide: docs/guides/sandboxed-environments.md
|
|
1497
|
+
Sandbox architecture: docs/plans/sandbox-end-state-architecture.md
|
|
1498
|
+
```
|