@chllming/wave-orchestration 0.9.2 → 0.9.4

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 CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.9.4 - 2026-04-05
6
+
7
+ - Laddered gate modes: bootstrap/standard/strict per wave number
8
+ - Bootstrap pass: exit 0 + deliverables exist = advance (no QA signals needed)
9
+ - Fix: requireDocumentationStewardFromWave threshold strictly respected
10
+ - New config: gateModeThresholds, bootstrapPassConditions, testCommand
11
+ - evaluateBootstrapGate() and resolveGateMode() functions
12
+
13
+ ## 0.9.3 - 2026-03-30
14
+
15
+ ### Fixed And Hardened
16
+
17
+ - WAVE_GATE_REGEX now accepts gap alongside pass|concerns|blocked for all five gate dimensions (architecture, integration, durability, live, docs). Previously, agents that reported a documented gap (e.g. live=gap for an infrastructure topology constraint) had their marker rejected entirely, causing missing-wave-gate failures that prevented wave closure.
18
+ - validateContQaSummary now treats gap dimension values as a conditional pass (ok: true, statusCode: conditional-pass) instead of a hard blocker, with detail text listing which dimensions have documented gaps.
19
+ - The cont-QA coordination prompt now documents gap as a valid dimension value alongside pass|concerns|blocked.
20
+
21
+ ### Added
22
+
23
+ - First-time wave launch now auto-triggers wave project setup when no project profile exists, matching existing wave draft behavior. (Contributed by @justanothernate in #54)
24
+ - wave project setup now shows descriptive help text before each prompt, explains all template and posture options inline, and adds whitespace between question groups for readability. (Contributed by @justanothernate in #54)
25
+ - PromptSession gains a describe(text) method for writing contextual help to stderr during interactive setup flows.
26
+ - parseArgs now passes the loaded config object through to runLauncherCli, avoiding a redundant loadWaveConfig() call.
27
+
28
+ ### Testing And Validation
29
+
30
+ - `pnpm exec vitest run --config vitest.config.ts`
31
+ - `node scripts/wave.mjs doctor --json`
32
+ - `node scripts/wave.mjs launch --lane main --dry-run --no-dashboard`
33
+ - `pnpm test -- test/wave-orchestrator/release-surface.test.ts`
34
+
5
35
  ## 0.9.2 - 2026-03-29
6
36
 
7
37
  ### Added
package/README.md CHANGED
@@ -107,19 +107,18 @@ Wave is built to mitigate those failures with a canonical authority set, generat
107
107
 
108
108
  Current release:
109
109
 
110
- - `@chllming/wave-orchestration@0.9.2`
111
- - Release tag: [`v0.9.2`](https://github.com/chllming/agent-wave-orchestrator/releases/tag/v0.9.2)
110
+ - `@chllming/wave-orchestration@0.9.4`
111
+ - Release tag: [`v0.9.4`](https://github.com/chllming/agent-wave-orchestrator/releases/tag/v0.9.4)
112
112
  - Public install path: npmjs
113
113
  - Authenticated fallback: GitHub Packages
114
114
 
115
- Highlights in `0.9.2`:
115
+ Highlights in `0.9.4`:
116
116
 
117
- - Live agent execution now uses detached process runners by default, which reduces tmux churn and memory pressure during wider orchestration bursts. Tmux is now optional and dashboard-only.
118
- - The sandbox-safe runtime path is now `wave submit`, `wave supervise`, `wave status`, `wave wait`, and `wave attach`, which behaves better under short-lived exec clients such as LEAPclaw, OpenClaw, and Nemoshell.
119
- - Supervisor recovery, launcher progress journaling, and exact-context reads are now hardier for multi-wave runs, reruns, and daemon/client loss in containerized or sandboxed environments.
120
- - Owned Wave Control deployments now support Stack-authenticated browser access, Wave-managed approval states and provider grants, personal access tokens, dedicated service tokens, encrypted per-user credential leasing, and the separate `services/wave-control-web` operator frontend.
121
- - Corridor is now documented as a first-class security input: it can run direct or through an owned Wave Control broker, materialize per-wave security context on implementation-owned paths, and block closure before integration when fetches fail or matched findings cross the configured threshold.
122
- - Release docs, migration guidance, runtime-config and closure references, Wave Control docs, the new Corridor reference, the manifest, and the tracked install-state fixtures now all point at the `0.9.2` surface.
117
+ - Wave-gate markers now accept `gap` alongside `pass`, `concerns`, and `blocked` for all five gate dimensions. Agents that report a documented gap (e.g. `live=gap` for an infrastructure topology constraint) no longer have their marker rejected entirely, and `cont-QA` treats gap values as a conditional pass instead of a hard blocker.
118
+ - First-time `wave launch` now auto-triggers `wave project setup` when no project profile exists, matching existing `wave draft` behavior. The interactive setup flow now shows descriptive help text, explains all template and posture options inline, and adds whitespace between question groups for readability.
119
+ - `PromptSession` gains a `describe(text)` method for writing contextual help to stderr during interactive setup flows.
120
+ - `parseArgs` now passes the loaded config object through to `runLauncherCli`, avoiding a redundant `loadWaveConfig()` call.
121
+ - Release docs, migration guidance, runtime-config and closure references, the manifest, and the tracked install-state fixtures now all point at the `0.9.4` surface.
123
122
 
124
123
  Requirements:
125
124
 
package/docs/README.md CHANGED
@@ -38,7 +38,7 @@ The useful path is journey-first:
38
38
  - Setting up multiple projects in one monorepo:
39
39
  Read [guides/monorepo-projects.md](./guides/monorepo-projects.md) for `defaultProject`, `projects.<projectId>`, project-scoped state paths, and telemetry defaults.
40
40
  - Adding an optional pre-implementation design steward:
41
- Read [guides/author-and-run-waves.md](./guides/author-and-run-waves.md), then the standing prompt in [agents/wave-design-role.md](./agents/wave-design-role.md). The shipped `0.9.2` surface includes `role-design` plus `tui-design`, with docs-first design stewards by default and explicit hybrid design stewards when a wave also gives that same agent code ownership.
41
+ Read [guides/author-and-run-waves.md](./guides/author-and-run-waves.md), then the standing prompt in [agents/wave-design-role.md](./agents/wave-design-role.md). The shipped `0.9.3` surface includes `role-design` plus `tui-design`, with docs-first design stewards by default and explicit hybrid design stewards when a wave also gives that same agent code ownership.
42
42
  - Running in LEAPclaw, OpenClaw, Nemoshell, Docker, or another short-lived sandbox:
43
43
  Read [guides/sandboxed-environments.md](./guides/sandboxed-environments.md) first for the submit or supervise pattern, persistent-state expectations, and dashboard guidance, then use [plans/sandbox-end-state-architecture.md](./plans/sandbox-end-state-architecture.md) for the deeper runtime design.
44
44
  - Want signal-driven automation or long-running watcher loops:
@@ -53,8 +53,8 @@ The useful path is journey-first:
53
53
  Read [plans/migration.md](./plans/migration.md), then review the release notes in [../CHANGELOG.md](../CHANGELOG.md) before running `pnpm exec wave upgrade`.
54
54
  - Publishing the package:
55
55
  Read [reference/package-publishing-flow.md](./reference/package-publishing-flow.md) for the end-to-end release path, the GitHub publish workflows, the lifecycle scripts, and the verification or repair flow.
56
- - Want the practical `0.9.2` operating stance:
57
- Read [guides/recommendations-0.9.2.md](./guides/recommendations-0.9.2.md) for the recommended default around relaxed blocker states, advisory turn budgets, and targeted recovery.
56
+ - Want the practical `0.9.3` operating stance:
57
+ Read [guides/recommendations-0.9.4.md](./guides/recommendations-0.9.4.md) for the recommended default around relaxed blocker states, advisory turn budgets, and targeted recovery.
58
58
  - Want the concrete runtime module map:
59
59
  Read [plans/end-state-architecture.md](./plans/end-state-architecture.md) for the engine-by-engine architecture and artifact ownership model.
60
60
  - Want the CLI surface map:
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: "0.9.3 Recommendations"
3
+ summary: "How to use 0.9.3's softer blocker states, advisory turn budgets, and targeted recovery without weakening proof and closure."
4
+ ---
5
+
6
+ # 0.9.3 Recommendations
7
+
8
+ Use this guide when you are adopting `0.9.3` and want one practical operating stance for the softer blocker states, advisory turn-budget behavior, and targeted recovery flow that the current package line ships.
9
+
10
+ ## Recommended Default
11
+
12
+ For most repos, the safest `0.9.3` default is:
13
+
14
+ - bound work with `budget.minutes`
15
+ - leave generic `budget.turns` as advisory metadata
16
+ - author non-proof follow-up as `soft`, `stale`, or `advisory` instead of silently treating every open record as a hard blocker
17
+ - use `resolve-policy` when the answer already exists in repo policy or shipped docs
18
+ - prefer targeted rerun or resume after timeout, max-turn, rate-limit, or missing-status outcomes instead of relaunching the whole wave
19
+ - in short-lived sandboxes, prefer `wave submit`, `wave supervise`, `wave status`, and `wave wait` instead of binding the full run to one client shell
20
+ - when a wave-gate dimension has a documented gap that is not an actionable blocker, use `gap` instead of `pass` or `blocked` — the runtime treats it as a conditional pass
21
+
22
+ That recommendation matches the runtime:
23
+
24
+ - executor launch metadata only emits hard turn-limit flags from `claude.maxTurns` or `opencode.steps`
25
+ - open `stale` and `advisory` coordination records stay visible without reopening the active blocking edge
26
+ - recoverable launcher failures queue targeted retry state instead of immediately escalating to broad terminal wave failure
27
+
28
+ ## 1. Budgets
29
+
30
+ Treat the two budget knobs differently:
31
+
32
+ - `budget.minutes` is the primary attempt budget
33
+ - generic `budget.turns` is only a planning hint
34
+ - `claude.maxTurns` or `opencode.steps` are the hard runtime ceilings when you actually want deterministic turn stopping
35
+
36
+ Recommended pattern for synthesis-heavy implementation or closure work:
37
+
38
+ ```json
39
+ {
40
+ "executors": {
41
+ "profiles": {
42
+ "implementation-default": {
43
+ "id": "claude",
44
+ "model": "claude-sonnet-4-6",
45
+ "budget": {
46
+ "minutes": 35,
47
+ "turns": 12
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ In that pattern, `35` minutes is real policy. `12` turns is only guidance for planning and preview metadata.
56
+
57
+ Only set a hard runtime ceiling when you deliberately want the runtime itself to stop:
58
+
59
+ ```json
60
+ {
61
+ "executors": {
62
+ "profiles": {
63
+ "bounded-closure": {
64
+ "id": "claude",
65
+ "model": "claude-sonnet-4-6",
66
+ "budget": {
67
+ "minutes": 20
68
+ },
69
+ "claude": {
70
+ "maxTurns": 6
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## 2. Softer Coordination States
79
+
80
+ `0.9.2` keeps “still visible” separate from “still blocking”.
81
+
82
+ Use these states intentionally:
83
+
84
+ | State | Use it for | What the runtime does |
85
+ | --- | --- | --- |
86
+ | `soft` | follow-up that still matters but should not be treated like proof failure | remains visible and may still drive repair or retry targeting |
87
+ | `stale` | outdated clarification or blocker context kept for history | visible in control state, but does not reopen blocking by itself |
88
+ | `advisory` | known issue, note, or human context that should stay visible without blocking closure | visible in control state, but does not own the active blocking edge |
89
+
90
+ Practical command paths:
91
+
92
+ ```bash
93
+ pnpm exec wave control task act defer --lane main --wave 10 --id blocker-doc-follow-up
94
+ pnpm exec wave control task act mark-stale --lane main --wave 10 --id clarify-a7-rollout
95
+ pnpm exec wave control task act mark-advisory --lane main --wave 10 --id request-clarify-a7-rollout
96
+ pnpm exec wave control task act resolve-policy --lane main --wave 10 --id clarify-a7-rollout --detail "Policy already covered in the rollout guide."
97
+ ```
98
+
99
+ Use them when the repo already knows the answer, the remaining item is informational, or the follow-up should stay visible for the next wave without holding the current wave hostage.
100
+
101
+ ## 3. What Should Stay Hard
102
+
103
+ Do not relax everything.
104
+
105
+ Keep these hard or closure-critical unless you are intentionally changing wave policy:
106
+
107
+ - missing proof or required deliverables
108
+ - failed integration, documentation, or cont-QA closure gates
109
+ - real human-feedback or escalation requirements that block safe continuation
110
+ - requests or clarifications that still represent unresolved ownership or policy ambiguity for the current wave
111
+
112
+ Use `gap` in wave-gate markers when a dimension has a documented gap that is not actionable in the current wave. For example, `live=gap` is appropriate when an infrastructure topology constraint prevents full live validation but the constraint is known, documented, and does not represent a regression. Do not use `gap` to hide actual failures or unreviewed work.
113
+
114
+ If the current wave cannot truthfully close without the answer, keep it blocking.
115
+
116
+ ## 4. Recovery Recommendation
117
+
118
+ My recommendation after reviewing the current `0.9.3` code path is:
119
+
120
+ - let timeout, max-turn, rate-limit, and missing-status failures go through the built-in targeted recovery path first
121
+ - inspect the queued rerun or resume request before manually relaunching the whole wave
122
+ - preserve reusable proof from successful sibling owners whenever the reducer already identified it as reusable
123
+
124
+ That is the shape the launcher now prefers. It only broadens failure when the remaining blockers are still proof-critical or otherwise non-recoverable.
125
+
126
+ ## 5. Suggested Operator Policy
127
+
128
+ For most repo-owned runbooks:
129
+
130
+ - teach authors to use `budget.minutes` first
131
+ - teach operators to downgrade only non-proof follow-up
132
+ - treat `resolve-policy` as the preferred path when the answer already exists in docs or repo policy
133
+ - escalate to a full-wave rerun only after targeted recovery proves insufficient
134
+
135
+ If you want a single sentence policy:
136
+
137
+ > Keep proof and closure strict, keep generic turns advisory, and keep non-proof context visible without letting it accidentally own wave closure.
@@ -0,0 +1,191 @@
1
+ ---
2
+ title: "0.9.4 Recommendations"
3
+ summary: "How to use 0.9.4's softer blocker states, advisory turn budgets, and targeted recovery without weakening proof and closure."
4
+ ---
5
+
6
+ # 0.9.4 Recommendations
7
+
8
+ Use this guide when you are adopting `0.9.4` and want one practical operating stance for the softer blocker states, advisory turn-budget behavior, and targeted recovery flow that the current package line ships.
9
+
10
+ ## Recommended Default
11
+
12
+ For most repos, the safest `0.9.4` default is:
13
+
14
+ - bound work with `budget.minutes`
15
+ - leave generic `budget.turns` as advisory metadata
16
+ - author non-proof follow-up as `soft`, `stale`, or `advisory` instead of silently treating every open record as a hard blocker
17
+ - use `resolve-policy` when the answer already exists in repo policy or shipped docs
18
+ - prefer targeted rerun or resume after timeout, max-turn, rate-limit, or missing-status outcomes instead of relaunching the whole wave
19
+ - in short-lived sandboxes, prefer `wave submit`, `wave supervise`, `wave status`, and `wave wait` instead of binding the full run to one client shell
20
+ - when a wave-gate dimension has a documented gap that is not an actionable blocker, use `gap` instead of `pass` or `blocked` — the runtime treats it as a conditional pass
21
+
22
+ That recommendation matches the runtime:
23
+
24
+ - executor launch metadata only emits hard turn-limit flags from `claude.maxTurns` or `opencode.steps`
25
+ - open `stale` and `advisory` coordination records stay visible without reopening the active blocking edge
26
+ - recoverable launcher failures queue targeted retry state instead of immediately escalating to broad terminal wave failure
27
+
28
+ ## 1. Budgets
29
+
30
+ Treat the two budget knobs differently:
31
+
32
+ - `budget.minutes` is the primary attempt budget
33
+ - generic `budget.turns` is only a planning hint
34
+ - `claude.maxTurns` or `opencode.steps` are the hard runtime ceilings when you actually want deterministic turn stopping
35
+
36
+ Recommended pattern for synthesis-heavy implementation or closure work:
37
+
38
+ ```json
39
+ {
40
+ "executors": {
41
+ "profiles": {
42
+ "implementation-default": {
43
+ "id": "claude",
44
+ "model": "claude-sonnet-4-6",
45
+ "budget": {
46
+ "minutes": 35,
47
+ "turns": 12
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ In that pattern, `35` minutes is real policy. `12` turns is only guidance for planning and preview metadata.
56
+
57
+ Only set a hard runtime ceiling when you deliberately want the runtime itself to stop:
58
+
59
+ ```json
60
+ {
61
+ "executors": {
62
+ "profiles": {
63
+ "bounded-closure": {
64
+ "id": "claude",
65
+ "model": "claude-sonnet-4-6",
66
+ "budget": {
67
+ "minutes": 20
68
+ },
69
+ "claude": {
70
+ "maxTurns": 6
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## 2. Softer Coordination States
79
+
80
+ `0.9.2` keeps “still visible” separate from “still blocking”.
81
+
82
+ Use these states intentionally:
83
+
84
+ | State | Use it for | What the runtime does |
85
+ | --- | --- | --- |
86
+ | `soft` | follow-up that still matters but should not be treated like proof failure | remains visible and may still drive repair or retry targeting |
87
+ | `stale` | outdated clarification or blocker context kept for history | visible in control state, but does not reopen blocking by itself |
88
+ | `advisory` | known issue, note, or human context that should stay visible without blocking closure | visible in control state, but does not own the active blocking edge |
89
+
90
+ Practical command paths:
91
+
92
+ ```bash
93
+ pnpm exec wave control task act defer --lane main --wave 10 --id blocker-doc-follow-up
94
+ pnpm exec wave control task act mark-stale --lane main --wave 10 --id clarify-a7-rollout
95
+ pnpm exec wave control task act mark-advisory --lane main --wave 10 --id request-clarify-a7-rollout
96
+ pnpm exec wave control task act resolve-policy --lane main --wave 10 --id clarify-a7-rollout --detail "Policy already covered in the rollout guide."
97
+ ```
98
+
99
+ Use them when the repo already knows the answer, the remaining item is informational, or the follow-up should stay visible for the next wave without holding the current wave hostage.
100
+
101
+ ## 3. What Should Stay Hard
102
+
103
+ Do not relax everything.
104
+
105
+ Keep these hard or closure-critical unless you are intentionally changing wave policy:
106
+
107
+ - missing proof or required deliverables
108
+ - failed integration, documentation, or cont-QA closure gates
109
+ - real human-feedback or escalation requirements that block safe continuation
110
+ - requests or clarifications that still represent unresolved ownership or policy ambiguity for the current wave
111
+
112
+ Use `gap` in wave-gate markers when a dimension has a documented gap that is not actionable in the current wave. For example, `live=gap` is appropriate when an infrastructure topology constraint prevents full live validation but the constraint is known, documented, and does not represent a regression. Do not use `gap` to hide actual failures or unreviewed work.
113
+
114
+ If the current wave cannot truthfully close without the answer, keep it blocking.
115
+
116
+ ## 4. Recovery Recommendation
117
+
118
+ My recommendation after reviewing the current `0.9.4` code path is:
119
+
120
+ - let timeout, max-turn, rate-limit, and missing-status failures go through the built-in targeted recovery path first
121
+ - inspect the queued rerun or resume request before manually relaunching the whole wave
122
+ - preserve reusable proof from successful sibling owners whenever the reducer already identified it as reusable
123
+
124
+ That is the shape the launcher now prefers. It only broadens failure when the remaining blockers are still proof-critical or otherwise non-recoverable.
125
+
126
+ ## 5. Suggested Operator Policy
127
+
128
+ For most repo-owned runbooks:
129
+
130
+ - teach authors to use `budget.minutes` first
131
+ - teach operators to downgrade only non-proof follow-up
132
+ - treat `resolve-policy` as the preferred path when the answer already exists in docs or repo policy
133
+ - escalate to a full-wave rerun only after targeted recovery proves insufficient
134
+
135
+ If you want a single sentence policy:
136
+
137
+ > Keep proof and closure strict, keep generic turns advisory, and keep non-proof context visible without letting it accidentally own wave closure.
138
+
139
+
140
+ ## Laddered Gate Modes (new in 0.9.4)
141
+
142
+ Waves now have three gate strictness tiers based on wave number:
143
+
144
+ | Mode | Default waves | What's required to advance |
145
+ |------|--------------|---------------------------|
146
+ | **bootstrap** | 0-3 | Implementation agents exit 0 + deliverables exist |
147
+ | **standard** | 4-9 | + A0 verdict required, doc closure recommended |
148
+ | **strict** | 10+ | Full ceremony: all signals, all stewards, all proof |
149
+
150
+ ### Configuration
151
+
152
+ ```json
153
+ {
154
+ "validation": {
155
+ "gateModeThresholds": {
156
+ "bootstrap": 0,
157
+ "standard": 4,
158
+ "strict": 10
159
+ },
160
+ "bootstrapPassConditions": {
161
+ "requireTestsPass": true,
162
+ "requireDeliverablesExist": true,
163
+ "requireExitCodeZero": true
164
+ },
165
+ "testCommand": "pnpm test:repo"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ### Steward threshold fix
171
+
172
+ `requireDocumentationStewardFromWave` and `requireIntegrationStewardFromWave`
173
+ are now strictly respected. Previously, the documentation steward was required
174
+ whenever component promotions were active, regardless of the threshold setting.
175
+
176
+ ### Migration from 0.9.3
177
+
178
+ No breaking changes. Existing repos get bootstrap mode for waves 0-3 by default.
179
+ To keep the old strict behavior for all waves, set:
180
+
181
+ ```json
182
+ {
183
+ "validation": {
184
+ "gateModeThresholds": {
185
+ "bootstrap": 0,
186
+ "standard": 0,
187
+ "strict": 0
188
+ }
189
+ }
190
+ }
191
+ ```
@@ -8,7 +8,7 @@ Typical examples:
8
8
  - Nemoshell or similar hosted terminal sandboxes
9
9
  - Docker or devcontainer setups where the client process is disposable but the workspace and state volume persist
10
10
 
11
- The core rule in `0.9.2` is simple:
11
+ The core rule in `0.9.3` is simple:
12
12
 
13
13
  - clients should be short-lived
14
14
  - supervision should be long-lived
@@ -94,7 +94,7 @@ If the sandbox only gives you short exec windows, `wave autonomous` should not b
94
94
 
95
95
  ## Docker And Containerized Setups
96
96
 
97
- Docker works well with the `0.9.2` process-backed runner model, but only if the state directories survive container restarts.
97
+ Docker works well with the `0.9.3` process-backed runner model, but only if the state directories survive container restarts.
98
98
 
99
99
  Recommended container posture:
100
100
 
@@ -1,10 +1,10 @@
1
1
  # Current State
2
2
 
3
- - The published package is `0.9.2`; that release keeps the shipped monorepo, design-role, and signal-hygiene surfaces, but now also moves live agent execution to detached process runners, reduces tmux and memory pressure during wide orchestration bursts, hardens the sandbox-safe supervisor path for LEAPclaw, OpenClaw, Nemoshell, Docker, and similar short-lived exec environments, and documents the current authenticated Wave Control plus Corridor-backed security surface that already ships in this repo.
3
+ - The published package is `0.9.4`; that release keeps the shipped monorepo, design-role, signal-hygiene, detached process-runner, and sandbox supervisor surfaces, and now also accepts `gap` as a valid wave-gate dimension value (alongside `pass`, `concerns`, and `blocked`) so that agents reporting a documented gap no longer trigger missing-wave-gate failures. First-time `wave launch` now auto-triggers `wave project setup` when no project profile exists, and the interactive setup flow shows descriptive help text and inline option explanations. The current authenticated Wave Control plus Corridor-backed security surface continues to ship in this repo.
4
4
  - The canonical shipped runtime architecture is documented in `docs/plans/end-state-architecture.md`; the sandbox-runtime companion is `docs/plans/sandbox-end-state-architecture.md`; historical cutover notes remain in `docs/plans/architecture-hardening-migration.md`.
5
5
  - The repository contains the published `@chllming/wave-orchestration` package plus the starter scaffold used by `wave init`.
6
6
  - The runtime is package-first and non-destructive for adopting repos: `wave init --adopt-existing` records existing repo-owned plans, waves, prompts, and config without overwriting them, and `wave upgrade` writes only `.wave/install-state.json` plus `.wave/upgrade-history/`.
7
- - The recommended `0.9.2` operating stance is documented in `docs/guides/recommendations-0.9.2.md`: keep proof and closure strict, keep generic `budget.turns` advisory, and use softer coordination states only for non-proof follow-up.
7
+ - The recommended `0.9.4` operating stance is documented in `docs/guides/recommendations-0.9.4.md`: keep proof and closure strict, keep generic `budget.turns` advisory, and use softer coordination states only for non-proof follow-up.
8
8
  - Sandbox-safe setup guidance now ships in `docs/guides/sandboxed-environments.md`: use `wave submit/supervise/status/wait/attach` for short-lived clients, keep `tmux` optional and dashboard-only, and preserve `.tmp/` plus `.wave/` when running inside Nemoshell or Docker.
9
9
  - Runtime launch entrypoints now perform a best-effort npmjs version check, cache the result under `.wave/package-update-check.json`, and point operators at `pnpm exec wave self-update` when a newer published package exists.
10
10
  - The companion control plane now ships in two packages:
@@ -1,6 +1,6 @@
1
1
  # Migration
2
2
 
3
- This page is the practical repo-upgrade guide for the current `0.9.2` surface.
3
+ This page is the practical repo-upgrade guide for the current `0.9.4` surface.
4
4
 
5
5
  Use it when you are:
6
6
 
@@ -12,6 +12,36 @@ For the completed internal architecture cutover record, see [architecture-harden
12
12
 
13
13
  For the sandbox-specific long-running execution target, including async `submit/status/wait` semantics and daemon ownership goals, see [sandbox-end-state-architecture.md](./sandbox-end-state-architecture.md).
14
14
 
15
+
16
+ ## What `0.9.4` Changes
17
+
18
+ The `0.9.4` surface adds laddered gate modes and fixes the steward threshold enforcement.
19
+
20
+ - **Laddered gate modes**: bootstrap (waves 0-3), standard (4-9), strict (10+). Bootstrap mode requires only implementation agent exit 0 and deliverables exist — no formal QA signals needed.
21
+ - **Steward threshold fix**: `requireDocumentationStewardFromWave` is now strictly respected. Previously it was OR'd with `componentPromotionRuleActive`.
22
+ - **New config fields**: `gateModeThresholds`, `bootstrapPassConditions`, `testCommand`, `testCommandTimeout`.
23
+ - **No breaking changes**: existing repos get bootstrap mode for waves 0-3 by default.
24
+
25
+ ## What `0.9.4` Changes
26
+
27
+ The current `0.9.4` surface keeps everything from `0.9.2` and adds two focused improvements with no breaking changes.
28
+
29
+ The practical changes are:
30
+
31
+ - `WAVE_GATE_REGEX` now accepts `gap` alongside `pass|concerns|blocked` for all five gate dimensions (architecture, integration, durability, live, docs), so agents that report a documented gap no longer have their marker rejected entirely
32
+ - `validateContQaSummary` treats `gap` dimension values as a conditional pass (`ok: true`, `statusCode: conditional-pass`) instead of a hard blocker
33
+ - the cont-QA coordination prompt now documents `gap` as a valid dimension value
34
+ - first-time `wave launch` now auto-triggers `wave project setup` when no project profile exists, matching existing `wave draft` behavior
35
+ - `wave project setup` now shows descriptive help text before each prompt, explains all template and posture options inline, and adds whitespace between question groups for readability
36
+ - `PromptSession` gains a `describe(text)` method for writing contextual help to stderr during interactive setup flows
37
+ - `parseArgs` now passes the loaded config object through to `runLauncherCli`, avoiding a redundant `loadWaveConfig()` call
38
+
39
+ There are no breaking changes. Just upgrade with `pnpm up @chllming/wave-orchestration` and run `pnpm exec wave upgrade`.
40
+
41
+ If your repo uses wave-gate markers, you can now use `gap` for dimensions where the gap is documented and not an actionable blocker.
42
+
43
+ For the practical `0.9.4` operating stance after the upgrade, read [../guides/recommendations-0.9.4.md](../guides/recommendations-0.9.4.md).
44
+
15
45
  ## What `0.9.2` Changes
16
46
 
17
47
  The current `0.9.2` surface keeps the packaged operator-guidance alignment, monorepo project support, and project-aware default telemetry from `0.9.0`, but adds a more sandbox-friendly execution model and lower-overhead live orchestration.
@@ -150,10 +180,11 @@ pnpm exec wave coord inbox --lane main --wave 0 --agent A1 --dry-run
150
180
 
151
181
  Use `pnpm exec wave dashboard --lane <lane> --attach current` or `--attach global` when you need to reattach to a tmux-backed dashboard after the upgrade.
152
182
 
153
- ## `0.9.2` Release Model
183
+ ## `0.9.4` Release Model
154
184
 
155
- The current `0.9.2` surface combines these strands:
185
+ The current `0.9.4` surface combines these strands:
156
186
 
187
+ - the gap-value wave-gate fix and first-time setup UX improvements released in `0.9.4`
157
188
  - the detached process-runner and sandbox supervisor hardening released in `0.9.2`
158
189
  - the shipped `0.9.0` monorepo project support and project-aware runtime isolation
159
190
  - the shipped `design` worker role and hybrid design-steward flow introduced in `0.8.5`
@@ -261,7 +292,7 @@ The interactive `wave draft` flow supports `design` as a worker role and scaffol
261
292
 
262
293
  ## Version-Specific Upgrade Guidance
263
294
 
264
- ## Upgrading From `0.8.5` To `0.8.6`
295
+ ## Upgrading From `0.8.5` To `0.9.4`
265
296
 
266
297
  This is the smallest upgrade, but it changes the live wait-loop contract for external automation and intentionally long-running agents.
267
298
 
@@ -298,7 +329,7 @@ If the repo copied starter surface, sync:
298
329
  - if the repo uses long-running watchers, confirm they can write the ack file where the prompt tells them to
299
330
  - reroute one targeted feedback or coordination request and confirm the resident signal version changes even when the signal kind stays the same
300
331
 
301
- ## Upgrading From `0.8.4` To `0.8.6`
332
+ ## Upgrading From `0.8.4` To `0.9.4`
302
333
 
303
334
  ### What changed
304
335
 
@@ -336,54 +367,7 @@ If your repo copied starter config defaults, also sync the `designRolePromptPath
336
367
  - hybrid design stewards rejoin implementation when they explicitly own code
337
368
  - long-running prompts receive signal-state and ack paths when the repo uses the new waiting model
338
369
 
339
- ## Upgrading From `0.8.3` To `0.8.6`
340
-
341
- This is the most common one-step package upgrade path.
342
-
343
- ### What changed across that range
344
-
345
- - `0.8.4` tightened contradiction replay, component-promotion threshold handling, and projection persistence boundaries
346
- - `0.8.5` ships the `design` worker role, the `role-design` and `tui-design` starter bundles, and the hybrid design-steward runtime model as part of the published package
347
- - `0.8.6` adds versioned signal snapshots, `signal-hygiene`, prompt-injected signal ack loops, and the seeded operator wrappers
348
- - current operator and planner docs now describe the shipped surface directly instead of splitting behavior between a published package and newer `main`-only additions
349
-
350
- ### Required repo changes
351
-
352
- Usually none if the repo does not copy starter prompts, skills, planning docs, or wrapper scripts.
353
-
354
- ### Strongly recommended sync
355
-
356
- If the repo copied starter surface, sync:
357
-
358
- - `docs/agents/wave-design-role.md`
359
- - `skills/role-design/`
360
- - `skills/tui-design/`
361
- - `skills/signal-hygiene/`
362
- - `scripts/wave-status.sh`
363
- - `scripts/wave-watch.sh`
364
- - `docs/guides/author-and-run-waves.md`
365
- - `docs/guides/signal-wrappers.md`
366
- - `docs/guides/planner.md`
367
- - `docs/reference/skills.md`
368
- - `docs/reference/sample-waves.md`
369
- - `docs/plans/current-state.md`
370
- - `docs/plans/wave-orchestrator.md`
371
- - `docs/plans/end-state-architecture.md`
372
-
373
- If the repo copied starter `wave.config.json` defaults, also sync:
374
-
375
- - `roles.designRolePromptPath`
376
- - `skills.byRole.design`
377
- - `executors.profiles.design-pass`
378
-
379
- ### Validation focus
380
-
381
- - confirm contradiction-blocked replay cases still compare cleanly if the repo keeps replay fixtures
382
- - if the repo uses design stewards, confirm packet-only design waves still block implementation until `ready-for-implementation`
383
- - if the repo uses hybrid design stewards, confirm the same agent rejoins implementation only when the authored wave explicitly gives it code ownership
384
- - if the repo uses long-running agents or shell automation, confirm the new wrapper exit contract and ack-loop semantics before relying on an older polling script
385
-
386
- ## Upgrading From `0.8.3` To `0.9.2`
370
+ ## Upgrading From `0.8.3` To `0.9.4`
387
371
 
388
372
  Treat this as one move to the current `0.9.2` surface.
389
373
 
@@ -418,7 +402,7 @@ If your repo copied starter docs or skills, sync:
418
402
  - dry-run one design-steward wave if the repo wants the new authored surface
419
403
  - if the repo uses long-running watcher agents or shell automation, validate `scripts/wave-status.sh` and `scripts/wave-watch.sh` against a live or staged lane
420
404
 
421
- ## Upgrading From `0.6.x` Or `0.7.x` To `0.9.2`
405
+ ## Upgrading From `0.6.x` Or `0.7.x` To `0.9.4`
422
406
 
423
407
  This is the main migration path for older adopted repos.
424
408
 
@@ -459,7 +443,7 @@ pnpm exec wave control proof get --lane main --wave 0 --json
459
443
 
460
444
  If the repo carries proof-first waves, verify that required proof artifacts still exist locally and not only in historical summaries.
461
445
 
462
- ## Upgrading From `0.5.x` Or Earlier To `0.9.2`
446
+ ## Upgrading From `0.5.x` Or Earlier To `0.9.4`
463
447
 
464
448
  Do not treat this as a tiny patch bump.
465
449
 
@@ -569,4 +553,4 @@ For repos that depend on replay parity, replay at least:
569
553
 
570
554
  ## Summary
571
555
 
572
- The current `0.9.2` surface keeps the same authority-set and phase-engine architecture, ships both the design-role starter surface and the signal-driven long-running-agent starter surface, keeps the `0.8.7` policy and routing hardening, and now also packages the practical operator recommendations guide inside the release line. For most repos already on `0.8.x`, the upgrade is package bump plus validation. For older adopted repos, the real work is syncing repo-owned prompts, skills, planner corpus, wrapper scripts, and runbooks so they describe the runtime the package now ships.
556
+ The current `0.9.4` surface keeps the same authority-set and phase-engine architecture, ships both the design-role starter surface and the signal-driven long-running-agent starter surface, keeps the `0.8.7` policy and routing hardening, and now also packages the practical operator recommendations guide inside the release line. For most repos already on `0.8.x`, the upgrade is package bump plus validation. For older adopted repos, the real work is syncing repo-owned prompts, skills, planner corpus, wrapper scripts, and runbooks so they describe the runtime the package now ships.
@@ -428,9 +428,9 @@ The important distinction is:
428
428
  `cont-QA` must emit:
429
429
 
430
430
  - a final verdict
431
- - a final `[wave-gate]` marker
431
+ - a final `[wave-gate]` marker with each of the five gate dimensions (architecture, integration, durability, live, docs) set to `pass`, `concerns`, `blocked`, or `gap`
432
432
 
433
- Final PASS requires all gate dimensions to pass in the final state.
433
+ Final PASS requires all gate dimensions to be `pass` or `gap` in the final state. A `gap` value means the dimension has a documented gap that is not an actionable blocker; it is treated as a conditional pass (`ok: true`, `statusCode: conditional-pass`) with detail text listing which dimensions have documented gaps.
434
434
 
435
435
  ## Why The Closure Model Works
436
436
 
@@ -191,7 +191,7 @@ Practical guidance:
191
191
  - prefer `budget.minutes` for normal synthesis, integration, and closure work
192
192
  - use generic `budget.turns` as a planning hint, not a hard failure trigger
193
193
  - only set `claude.maxTurns` or `opencode.steps` when you deliberately want a hard ceiling for that runtime
194
- - see [../../guides/recommendations-0.9.2.md](../../guides/recommendations-0.9.2.md) for the recommended `0.9.2` operating stance that combines advisory turn budgets with softer non-proof coordination states
194
+ - see [../../guides/recommendations-0.9.3.md](../../guides/recommendations-0.9.3.md) for the recommended `0.9.3` operating stance that combines advisory turn budgets with softer non-proof coordination states
195
195
 
196
196
  ## Runtime Pages
197
197
 
@@ -203,7 +203,7 @@ Practical guidance:
203
203
 
204
204
  `wave.config.json` may also declare a `waveControl` block for local-first telemetry delivery.
205
205
 
206
- Packaged defaults in `@chllming/wave-orchestration@0.9.2`:
206
+ Packaged defaults in `@chllming/wave-orchestration@0.9.3`:
207
207
 
208
208
  - `endpoint`: `https://wave-control.up.railway.app/api/v1`
209
209
  - `reportMode`: `metadata-only`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chllming/wave-orchestration",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "license": "MIT",
5
5
  "description": "Generic wave-based multi-agent orchestration for repository work.",
6
6
  "repository": {
@@ -2,6 +2,28 @@
2
2
  "schemaVersion": 1,
3
3
  "packageName": "@chllming/wave-orchestration",
4
4
  "releases": [
5
+ {
6
+ "version": "0.9.4",
7
+ "date": "2026-03-30",
8
+ "summary": "Gap-value wave-gate fix and first-time project setup UX improvements.",
9
+ "features": [
10
+ "WAVE_GATE_REGEX now accepts `gap` alongside `pass|concerns|blocked` for all five gate dimensions (architecture, integration, durability, live, docs), so agents reporting a documented gap no longer have their marker rejected entirely.",
11
+ "`validateContQaSummary` now treats `gap` dimension values as a conditional pass (`ok: true`, `statusCode: conditional-pass`) instead of a hard blocker, with detail text listing which dimensions have documented gaps.",
12
+ "The cont-QA coordination prompt now documents `gap` as a valid dimension value alongside `pass|concerns|blocked`.",
13
+ "First-time `wave launch` now auto-triggers `wave project setup` when no project profile exists, matching existing `wave draft` behavior. (Contributed by @justanothernate in #54)",
14
+ "`wave project setup` now shows descriptive help text before each prompt, explains all template and posture options inline, and adds whitespace between question groups for readability. (Contributed by @justanothernate in #54)",
15
+ "`PromptSession` gains a `describe(text)` method for writing contextual help to stderr during interactive setup flows.",
16
+ "`parseArgs` now passes the loaded config object through to `runLauncherCli`, avoiding a redundant `loadWaveConfig()` call.",
17
+ "Release docs, migration guidance, runtime-config and closure references, the manifest, and the tracked install-state fixtures now all point at the `0.9.4` surface.",
18
+ "Planner migration guidance and the `planner-agentic` bundle placeholder remain part of the shipped current-surface docs so adopted repos still have one aligned upgrade target."
19
+ ],
20
+ "manualSteps": [
21
+ "Run `pnpm exec wave doctor` and `pnpm exec wave launch --lane main --dry-run --no-dashboard` after upgrading so the repo validates against the `0.9.4` release surface.",
22
+ "Push the `v0.9.4` tag after the release commit so the GitHub publish workflow can publish the matching npm package version.",
23
+ "If your repo copied starter docs or runbooks, sync `README.md`, `docs/README.md`, `docs/plans/current-state.md`, `docs/plans/migration.md`, `docs/reference/coordination-and-closure.md`, `docs/reference/runtime-config/README.md`, and `docs/guides/recommendations-0.9.4.md` so local guidance matches the packaged release."
24
+ ],
25
+ "breaking": false
26
+ },
5
27
  {
6
28
  "version": "0.9.2",
7
29
  "date": "2026-03-29",
@@ -50,7 +50,7 @@ const WAVE_SECURITY_REGEX =
50
50
  const WAVE_DESIGN_REGEX =
51
51
  /^\[wave-design\]\s*state=(ready-for-implementation|needs-clarification|blocked)\s+decisions=(\d+)\s+assumptions=(\d+)\s+open_questions=(\d+)\s*(?:detail=(.*))?$/gim;
52
52
  const WAVE_GATE_REGEX =
53
- /^\[wave-gate\]\s*architecture=(pass|concerns|blocked)\s+integration=(pass|concerns|blocked)\s+durability=(pass|concerns|blocked)\s+live=(pass|concerns|blocked)\s+docs=(pass|concerns|blocked)\s*(?:detail=(.*))?$/gim;
53
+ /^\[wave-gate\]\s*architecture=(pass|concerns|blocked|gap)\s+integration=(pass|concerns|blocked|gap)\s+durability=(pass|concerns|blocked|gap)\s+live=(pass|concerns|blocked|gap)\s+docs=(pass|concerns|blocked|gap)\s*(?:detail=(.*))?$/gim;
54
54
  const WAVE_GAP_REGEX =
55
55
  /^\[wave-gap\]\s*kind=(architecture|integration|durability|ops|docs)\s*(?:detail=(.*))?$/gim;
56
56
  const WAVE_COMPONENT_REGEX =
@@ -1268,17 +1268,34 @@ export function validateContQaSummary(agent, summary, options = {}) {
1268
1268
  detail: summary.verdict.detail || "Verdict read from cont-QA report.",
1269
1269
  };
1270
1270
  }
1271
+ const hardBlockers = [];
1272
+ const documentedGaps = [];
1271
1273
  for (const key of ["architecture", "integration", "durability", "live", "docs"]) {
1272
- if (summary.gate[key] !== "pass") {
1273
- return {
1274
- ok: false,
1275
- statusCode: `gate-${key}-${summary.gate[key]}`,
1276
- detail:
1277
- summary.gate.detail ||
1278
- `Final cont-QA gate did not pass ${key}; got ${summary.gate[key]}.`,
1279
- };
1274
+ if (summary.gate[key] === "gap") {
1275
+ documentedGaps.push(key);
1276
+ } else if (summary.gate[key] !== "pass") {
1277
+ hardBlockers.push(key);
1280
1278
  }
1281
1279
  }
1280
+ if (hardBlockers.length > 0) {
1281
+ const key = hardBlockers[0];
1282
+ return {
1283
+ ok: false,
1284
+ statusCode: `gate-${key}-${summary.gate[key]}`,
1285
+ detail:
1286
+ summary.gate.detail ||
1287
+ `Final cont-QA gate did not pass ${key}; got ${summary.gate[key]}.`,
1288
+ };
1289
+ }
1290
+ if (documentedGaps.length > 0) {
1291
+ return {
1292
+ ok: true,
1293
+ statusCode: "conditional-pass",
1294
+ detail:
1295
+ summary.gate.detail ||
1296
+ `cont-QA gate passed with documented gaps in: ${documentedGaps.join(", ")}.`,
1297
+ };
1298
+ }
1282
1299
  return {
1283
1300
  ok: true,
1284
1301
  statusCode: "pass",
@@ -531,6 +531,20 @@ function normalizeValidation(rawValidation = {}) {
531
531
  rawValidation.requireAgentComponentsFromWave,
532
532
  0,
533
533
  ),
534
+ gateModeThresholds: {
535
+ bootstrap: rawValidation.gateModeThresholds?.bootstrap ?? 0,
536
+ standard: rawValidation.gateModeThresholds?.standard ?? 4,
537
+ strict: rawValidation.gateModeThresholds?.strict ?? 10,
538
+ },
539
+ bootstrapPassConditions: {
540
+ requireA0Verdict: rawValidation.bootstrapPassConditions?.requireA0Verdict ?? false,
541
+ requireProofSignals: rawValidation.bootstrapPassConditions?.requireProofSignals ?? false,
542
+ requireTestsPass: rawValidation.bootstrapPassConditions?.requireTestsPass ?? true,
543
+ requireDeliverablesExist: rawValidation.bootstrapPassConditions?.requireDeliverablesExist ?? true,
544
+ requireExitCodeZero: rawValidation.bootstrapPassConditions?.requireExitCodeZero ?? true,
545
+ },
546
+ testCommand: typeof rawValidation.testCommand === "string" ? rawValidation.testCommand : null,
547
+ testCommandTimeout: typeof rawValidation.testCommandTimeout === "number" ? rawValidation.testCommandTimeout : 120,
534
548
  };
535
549
  }
536
550
 
@@ -253,7 +253,7 @@ export function buildExecutionPrompt({
253
253
  ? [
254
254
  `- Because you are Agent ${contQaAgentId}, your cont-QA report must end with exactly one standalone line in the form \`Verdict: PASS\`, \`Verdict: CONCERNS\`, or \`Verdict: BLOCKED\`.`,
255
255
  "- Also emit one matching structured marker in your terminal output: `[wave-verdict] pass`, `[wave-verdict] concerns`, or `[wave-verdict] blocked`.",
256
- "- Emit one final structured gate marker: `[wave-gate] architecture=<pass|concerns|blocked> integration=<pass|concerns|blocked> durability=<pass|concerns|blocked> live=<pass|concerns|blocked> docs=<pass|concerns|blocked> detail=<short-note>`.",
256
+ "- Emit one final structured gate marker: `[wave-gate] architecture=<pass|concerns|blocked|gap> integration=<pass|concerns|blocked|gap> durability=<pass|concerns|blocked|gap> live=<pass|concerns|blocked|gap> docs=<pass|concerns|blocked|gap> detail=<short-note>`.",
257
257
  "- Only use `Verdict: PASS` when the wave is coherent enough to unblock the next wave.",
258
258
  `- Do not declare PASS until the documentation gate is closed: impacted implementation-owned docs must exist, ${sharedPlanDocList} must reflect plan-affecting outcomes, and no unresolved architecture-versus-plans drift remains.`,
259
259
  "- If shared-plan reconciliation is still active inside the wave, require the exact remaining doc delta and an explicit `closed` or `no-change` note from the documentation steward or named owner before finalizing. Do not treat ownership handoff alone as the blocker.",
@@ -138,6 +138,46 @@ function validateEnvelopeForRun(runInfo, envelope, options = {}) {
138
138
  };
139
139
  }
140
140
 
141
+
142
+ // --- Laddered gate modes (0.9.4) ---
143
+ export function resolveGateMode(waveNumber, thresholds) {
144
+ if (!thresholds) return "strict";
145
+ if (waveNumber < (thresholds.standard ?? 4)) return "bootstrap";
146
+ if (waveNumber < (thresholds.strict ?? 10)) return "standard";
147
+ return "strict";
148
+ }
149
+
150
+ export function evaluateBootstrapGate(wave, agentRuns, options = {}) {
151
+ const conditions = options.bootstrapPassConditions ?? {};
152
+ const summaries = options.summaries ?? new Map();
153
+
154
+ // Check implementation agents (non-A0, non-A8, non-A9)
155
+ const implAgents = agentRuns.filter(a =>
156
+ !["A0", "E0", "A8", "A9"].includes(a.agentId)
157
+ );
158
+
159
+ for (const agent of implAgents) {
160
+ const summary = summaries.get(agent.agentId);
161
+ if (!summary) continue;
162
+
163
+ // Must have exit code 0
164
+ if (conditions.requireExitCodeZero !== false && summary.exitCode !== 0) {
165
+ return { ok: false, statusCode: "blocked", detail: `${agent.agentId} exit code ${summary.exitCode}` };
166
+ }
167
+
168
+ // Check deliverables exist
169
+ if (conditions.requireDeliverablesExist !== false && summary.deliverables) {
170
+ const missing = summary.deliverables.filter(d => !d.exists);
171
+ if (missing.length > 0) {
172
+ return { ok: false, statusCode: "concerns", detail: `${agent.agentId} missing deliverables: ${missing.map(d=>d.path).join(", ")}` };
173
+ }
174
+ }
175
+ }
176
+
177
+ return { ok: true, statusCode: "pass", detail: "bootstrap-pass: impl agents completed with deliverables" };
178
+ }
179
+ // --- End laddered gate modes ---
180
+
141
181
  export function materializeAgentExecutionSummaryForRun(wave, runInfo, options = {}) {
142
182
  const statusRecord = readStatusRecordIfPresent(runInfo.statusPath);
143
183
  if (!statusRecord) {
@@ -69,7 +69,7 @@ export const STARTER_TEMPLATE_PATHS = [
69
69
  "docs/guides/author-and-run-waves.md",
70
70
  "docs/guides/monorepo-projects.md",
71
71
  "docs/guides/planner.md",
72
- "docs/guides/recommendations-0.9.2.md",
72
+ "docs/guides/recommendations-0.9.4.md",
73
73
  "docs/guides/sandboxed-environments.md",
74
74
  "docs/guides/signal-wrappers.md",
75
75
  "docs/guides/terminal-surfaces.md",
@@ -332,7 +332,7 @@ function parseArgs(argv) {
332
332
  continue;
333
333
  }
334
334
  if (arg === "--help" || arg === "-h") {
335
- return { help: true, lanePaths, options };
335
+ return { help: true, lanePaths, options, config };
336
336
  }
337
337
  if (arg === "--dry-run") {
338
338
  options.dryRun = true;
@@ -474,7 +474,7 @@ function parseArgs(argv) {
474
474
  if (!options.dryRun && options.terminalSurface === "none") {
475
475
  throw new Error("--terminal-surface none is only supported with --dry-run");
476
476
  }
477
- return { help: false, lanePaths, options };
477
+ return { help: false, lanePaths, options, config };
478
478
  }
479
479
 
480
480
  // --- Local wrappers that bind engine calls to launcher scope ---
@@ -755,7 +755,25 @@ export async function runLauncherCli(argv) {
755
755
  printUsage(parsed.lanePaths, parsed.options.terminalSurface);
756
756
  return;
757
757
  }
758
- const { lanePaths, options } = parsed;
758
+ const { lanePaths, options, config } = parsed;
759
+
760
+ // Auto-run project setup on first launch if no profile exists yet.
761
+ const projectId = options.project || config.defaultProject;
762
+ if (!readProjectProfile({ config, project: projectId })) {
763
+ const { stderr: stderrStream } = await import("node:process");
764
+ stderrStream.write(
765
+ "\n No project profile found — running first-time setup.\n" +
766
+ " You can re-run this later with: wave project setup\n\n",
767
+ );
768
+ const { runPlannerCli } = await import("./planner.mjs");
769
+ await runPlannerCli(["project", "setup", ...(projectId ? ["--project", projectId] : [])]);
770
+ // Re-read the terminal surface from the newly created profile.
771
+ const freshProfile = readProjectProfile({ config, project: projectId });
772
+ if (freshProfile) {
773
+ options.terminalSurface = resolveDefaultTerminalSurface(freshProfile);
774
+ }
775
+ }
776
+
759
777
  const supervisorRunId = String(process.env.WAVE_SUPERVISOR_RUN_ID || "").trim() || null;
760
778
  const launcherProgressPath = launcherProgressPathForRun(lanePaths, supervisorRunId);
761
779
  const writeLauncherRunProgress = (patch = {}) => {
@@ -486,6 +486,10 @@ class PromptSession {
486
486
  }
487
487
  }
488
488
 
489
+ describe(text) {
490
+ stderr.write(` ${text}\n`);
491
+ }
492
+
489
493
  async close() {
490
494
  this.interface?.close();
491
495
  }
@@ -2925,7 +2929,13 @@ async function runProjectSetupFlow(options = {}) {
2925
2929
  const laneChoices = Array.from(
2926
2930
  new Set([config.defaultLane, ...projectLanes, ...Object.keys(config.lanes || {})].filter(Boolean)),
2927
2931
  );
2932
+ stderr.write("\n Wave project setup — answer a few questions so Wave can tailor defaults for this repo.\n Press Enter to accept the default shown in [brackets].\n\n");
2933
+ prompt.describe("Is this a fresh start, or has Wave been used in this repo before?");
2928
2934
  const newProject = await prompt.askBoolean("Treat this repository as a new project?", base.newProject);
2935
+
2936
+ prompt.describe("\nShould you review agent progress yourself, or let them run autonomously?");
2937
+ prompt.describe(" oversight — you review progress and approve risky steps (recommended)");
2938
+ prompt.describe(" dark-factory — agents run end-to-end without human checkpoints");
2929
2939
  const defaultOversightMode = normalizeOversightMode(
2930
2940
  await prompt.askChoice(
2931
2941
  "Default execution posture",
@@ -2933,6 +2943,10 @@ async function runProjectSetupFlow(options = {}) {
2933
2943
  base.defaultOversightMode,
2934
2944
  ),
2935
2945
  );
2946
+
2947
+ prompt.describe("\nHow do you want to watch agent sessions?");
2948
+ prompt.describe(" vscode — agent sessions appear as VS Code terminal tabs");
2949
+ prompt.describe(" tmux — agent sessions run in tmux panes (terminal-native)");
2936
2950
  const defaultTerminalSurface = normalizeTerminalSurface(
2937
2951
  await prompt.askChoice(
2938
2952
  "Default terminal surface",
@@ -2940,6 +2954,12 @@ async function runProjectSetupFlow(options = {}) {
2940
2954
  base.defaultTerminalSurface,
2941
2955
  ),
2942
2956
  );
2957
+
2958
+ prompt.describe("\nWhat kind of work will waves usually do?");
2959
+ prompt.describe(" implementation — building features, fixing bugs, writing code (most common)");
2960
+ prompt.describe(" qa — test coverage, test infrastructure, validation work");
2961
+ prompt.describe(" infra — deployment, CI/CD, infrastructure changes");
2962
+ prompt.describe(" release — versioning, changelog, release coordination");
2943
2963
  const template = normalizeDraftTemplate(
2944
2964
  await prompt.askChoice(
2945
2965
  "Default draft template",
@@ -2947,11 +2967,20 @@ async function runProjectSetupFlow(options = {}) {
2947
2967
  base.plannerDefaults.template,
2948
2968
  ),
2949
2969
  );
2970
+
2971
+ prompt.describe("\nWhich lane should new waves go into? A lane is just an ordered sequence of waves.");
2972
+ prompt.describe("'main' is the default and usually fine to start with.");
2950
2973
  const lane = await prompt.askChoice(
2951
2974
  "Default draft lane",
2952
2975
  laneChoices,
2953
2976
  base.plannerDefaults.lane,
2954
2977
  );
2978
+
2979
+ prompt.describe("\nDo you have deploy environments (e.g. staging, production) you want Wave to know about?");
2980
+ prompt.describe("This helps Wave attach the right deployment skills when agents do infra or release work.");
2981
+ prompt.describe("Supported providers: railway, docker-compose, kubernetes, ssh-manual.");
2982
+ prompt.describe("Use 'custom' for anything else (GitHub Actions, Vercel, Cloudflare, etc.).");
2983
+ prompt.describe("You can skip this now (enter 0) and add them later with 'wave project setup'.");
2955
2984
  const deployEnvironmentCount = await prompt.askInteger(
2956
2985
  "How many deploy environments should the planner remember?",
2957
2986
  base.deployEnvironments.length,
@@ -1786,8 +1786,7 @@ export function validateWaveDefinition(wave, options = {}) {
1786
1786
  }
1787
1787
  }
1788
1788
  const documentationRuleActive =
1789
- (documentationThreshold !== null && wave.wave >= documentationThreshold) ||
1790
- componentPromotionRuleActive;
1789
+ documentationThreshold !== null && wave.wave >= documentationThreshold;
1791
1790
  if (documentationRuleActive) {
1792
1791
  const documentationStewards = wave.agents.filter((agent) =>
1793
1792
  agent.rolePromptPaths?.includes(laneProfile.roles.documentationRolePromptPath),
package/wave.config.json CHANGED
@@ -31,51 +31,69 @@
31
31
  "profiles": {
32
32
  "implement-fast": {
33
33
  "id": "codex",
34
- "tags": ["implementation"],
34
+ "tags": [
35
+ "implementation"
36
+ ],
35
37
  "budget": {
36
- "turns": 12,
37
38
  "minutes": 45
38
39
  }
39
40
  },
40
41
  "deep-review": {
41
42
  "id": "claude",
42
- "tags": ["integration", "review"],
43
+ "tags": [
44
+ "integration",
45
+ "review"
46
+ ],
43
47
  "budget": {
44
- "turns": 10,
45
48
  "minutes": 30
46
49
  }
47
50
  },
48
51
  "eval-tuning": {
49
52
  "id": "codex",
50
- "tags": ["eval", "tuning"],
53
+ "tags": [
54
+ "eval",
55
+ "tuning"
56
+ ],
51
57
  "budget": {
52
- "turns": 14,
53
58
  "minutes": 45
54
59
  }
55
60
  },
56
61
  "docs-pass": {
57
62
  "id": "claude",
58
- "tags": ["documentation"],
63
+ "tags": [
64
+ "documentation"
65
+ ],
59
66
  "budget": {
60
- "turns": 8,
61
67
  "minutes": 20
62
68
  }
63
69
  },
64
70
  "design-pass": {
65
71
  "id": "claude",
66
- "tags": ["design", "review"],
72
+ "tags": [
73
+ "design",
74
+ "review"
75
+ ],
67
76
  "budget": {
68
- "turns": 10,
69
77
  "minutes": 30
70
78
  },
71
79
  "claude": {
72
- "allowedTools": ["Read", "Edit", "Write", "Bash", "Grep", "Glob"]
80
+ "allowedTools": [
81
+ "Read",
82
+ "Edit",
83
+ "Write",
84
+ "Bash",
85
+ "Grep",
86
+ "Glob"
87
+ ]
73
88
  }
74
89
  },
75
90
  "planning-readonly": {
76
91
  "id": "codex",
77
92
  "model": "gpt-5-codex",
78
- "tags": ["planning", "review"],
93
+ "tags": [
94
+ "planning",
95
+ "review"
96
+ ],
79
97
  "budget": {
80
98
  "minutes": 30
81
99
  },
@@ -83,25 +101,38 @@
83
101
  "search": true,
84
102
  "json": true,
85
103
  "sandbox": "read-only",
86
- "config": ["model_reasoning_effort=high"]
104
+ "config": [
105
+ "model_reasoning_effort=high"
106
+ ]
87
107
  }
88
108
  },
89
109
  "security-review": {
90
110
  "id": "claude",
91
- "tags": ["security", "review"],
111
+ "tags": [
112
+ "security",
113
+ "review"
114
+ ],
92
115
  "budget": {
93
- "turns": 8,
94
116
  "minutes": 20
95
117
  },
96
118
  "claude": {
97
- "allowedTools": ["Read", "Edit", "Write", "Bash", "Grep", "Glob"]
119
+ "allowedTools": [
120
+ "Read",
121
+ "Edit",
122
+ "Write",
123
+ "Bash",
124
+ "Grep",
125
+ "Glob"
126
+ ]
98
127
  }
99
128
  },
100
129
  "ops-triage": {
101
130
  "id": "opencode",
102
- "tags": ["ops", "research"],
131
+ "tags": [
132
+ "ops",
133
+ "research"
134
+ ],
103
135
  "budget": {
104
- "turns": 8,
105
136
  "minutes": 20
106
137
  }
107
138
  }
@@ -122,34 +153,81 @@
122
153
  },
123
154
  "skills": {
124
155
  "dir": "skills",
125
- "base": ["wave-core", "repo-coding-rules"],
156
+ "base": [
157
+ "wave-core",
158
+ "repo-coding-rules"
159
+ ],
126
160
  "byRole": {
127
- "design": ["role-design"],
128
- "implementation": ["role-implementation"],
129
- "integration": ["role-integration"],
130
- "documentation": ["role-documentation"],
131
- "cont-qa": ["role-cont-qa"],
132
- "cont-eval": ["role-cont-eval"],
133
- "security": ["role-security"],
134
- "infra": ["role-infra"],
135
- "deploy": ["role-deploy"],
136
- "research": ["role-research"]
161
+ "design": [
162
+ "role-design"
163
+ ],
164
+ "implementation": [
165
+ "role-implementation"
166
+ ],
167
+ "integration": [
168
+ "role-integration"
169
+ ],
170
+ "documentation": [
171
+ "role-documentation"
172
+ ],
173
+ "cont-qa": [
174
+ "role-cont-qa"
175
+ ],
176
+ "cont-eval": [
177
+ "role-cont-eval"
178
+ ],
179
+ "security": [
180
+ "role-security"
181
+ ],
182
+ "infra": [
183
+ "role-infra"
184
+ ],
185
+ "deploy": [
186
+ "role-deploy"
187
+ ],
188
+ "research": [
189
+ "role-research"
190
+ ]
137
191
  },
138
192
  "byRuntime": {
139
- "codex": ["runtime-codex"],
140
- "claude": ["runtime-claude"],
141
- "opencode": ["runtime-opencode"],
142
- "local": ["runtime-local"]
193
+ "codex": [
194
+ "runtime-codex"
195
+ ],
196
+ "claude": [
197
+ "runtime-claude"
198
+ ],
199
+ "opencode": [
200
+ "runtime-opencode"
201
+ ],
202
+ "local": [
203
+ "runtime-local"
204
+ ]
143
205
  },
144
206
  "byDeployKind": {
145
- "railway-cli": ["provider-railway"],
146
- "railway-mcp": ["provider-railway"],
147
- "docker-compose": ["provider-docker-compose"],
148
- "kubernetes": ["provider-kubernetes"],
149
- "aws": ["provider-aws"],
150
- "github-release": ["provider-github-release"],
151
- "ssh-manual": ["provider-ssh-manual"],
152
- "custom": ["provider-custom-deploy"]
207
+ "railway-cli": [
208
+ "provider-railway"
209
+ ],
210
+ "railway-mcp": [
211
+ "provider-railway"
212
+ ],
213
+ "docker-compose": [
214
+ "provider-docker-compose"
215
+ ],
216
+ "kubernetes": [
217
+ "provider-kubernetes"
218
+ ],
219
+ "aws": [
220
+ "provider-aws"
221
+ ],
222
+ "github-release": [
223
+ "provider-github-release"
224
+ ],
225
+ "ssh-manual": [
226
+ "provider-ssh-manual"
227
+ ],
228
+ "custom": [
229
+ "provider-custom-deploy"
230
+ ]
153
231
  }
154
232
  },
155
233
  "planner": {
@@ -223,8 +301,12 @@
223
301
  "infra": "opencode",
224
302
  "deploy": "opencode"
225
303
  },
226
- "fallbackExecutorOrder": ["claude", "opencode", "codex"]
304
+ "fallbackExecutorOrder": [
305
+ "claude",
306
+ "opencode",
307
+ "codex"
308
+ ]
227
309
  }
228
310
  }
229
311
  }
230
- }
312
+ }