cclaw-cli 0.31.0 → 0.32.0

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/README.md CHANGED
@@ -200,8 +200,9 @@ cclaw has eight stages, but a single prompt rarely needs all of them.
200
200
  | **standard** _(default)_ | all 8 stages | `new feature`, `refactor`, `migration`, `platform`, `schema`, `architecture` |
201
201
 
202
202
  Each stage produces a dated artifact under `.cclaw/artifacts/`:
203
- `00-idea.md` (seed) and `01-brainstorm.md` through `08-ship.md`
204
- (plus `09-retro.md` at automatic closeout see below).
203
+ `00-idea.md` (seed), `01-brainstorm.md` through `08-ship.md`, and
204
+ `09-retro.md` at automatic closeout (see
205
+ [Ship and closeout](#ship-and-closeout--automatic-resumable)).
205
206
 
206
207
  ### Track heuristics are configurable
207
208
 
@@ -254,8 +255,12 @@ it into ceremony:
254
255
  in a single place (`.cclaw/contexts/`), so every skill speaks the same
255
256
  dialect.
256
257
  - **Knowledge capture throughout the flow.** Every stage completion
257
- protocol can emit entries to `knowledge.jsonl` not only retro. Strict
258
- JSONL schema keeps it machine-queryable.
258
+ protocol emits typed entries (`rule` / `pattern` / `lesson`) to
259
+ `.cclaw/knowledge.jsonl` as the flow progresses — not only at retro.
260
+ Retro itself adds a `compound` entry, and the automatic compound pass
261
+ after ship promotes recurring entries (≥ 3) into first-class
262
+ rules/protocols/skills so the **next** run is easier. Strict JSONL
263
+ schema keeps the whole thing machine-queryable.
259
264
  - **Automatic integrity checks.** Runtime health is verified on every
260
265
  stage transition — no command you need to remember to run.
261
266
 
@@ -278,24 +283,38 @@ native subagent dispatch, such as Codex — see
278
283
 
279
284
  ---
280
285
 
281
- ## Ship and closeout
282
-
283
- Shipping writes `08-ship.md` and then closes out the feature through a
284
- guided three-step sequence:
285
-
286
- 1. **Retro** drafts `09-retro.md` from flow artifacts and the delegation
287
- log; you review and accept.
288
- 2. **Compound pass** promotes repeated knowledge entries (frequency ≥ 2,
289
- maturity = stable) into first-class rules or skills.
290
- 3. **Archive** moves artifacts to `.cclaw/runs/YYYY-MM-DD-<slug>/` and
291
- resets `flow-state.json`.
292
-
293
- Retro is not optional archive is gated on retro completion so you can't
294
- silently lose the learning pass.
295
-
296
- > **Coming next:** cclaw will chain these three steps automatically from
297
- > `ship` (one structured `edit`/`accept`/`skip` ask, resumable if the
298
- > session ends). Tracked as the v0.32 closeout-automation wave.
286
+ ## Ship and closeout — automatic, resumable
287
+
288
+ Shipping writes `08-ship.md`. `/cc-next` then automatically walks the
289
+ feature through a deterministic three-step closeout without extra
290
+ commands from you:
291
+
292
+ 1. **Retro (`09-retro.md`).** cclaw drafts a retrospective from your
293
+ stage artifacts, the delegation log, and the knowledge entries
294
+ recorded during the run. It then asks exactly **one** structured
295
+ question:
296
+ - **accept** *(default)* — keep the draft, record one `compound`
297
+ knowledge entry, advance.
298
+ - **edit**you edit `09-retro.md` in place, then `/cc-next` again.
299
+ - **skip** record a one-line reason, continue (archive will
300
+ surface the skip in the run manifest).
301
+ 2. **Compound pass.** If the knowledge store has clusters recurring 3+
302
+ times, cclaw proposes concrete lifts into rules/protocols/skills and
303
+ asks once: apply-all / apply-selected / skip. An empty pass advances
304
+ silently.
305
+ 3. **Archive.** Moves artifacts into `.cclaw/runs/YYYY-MM-DD-<slug>/`,
306
+ snapshots `state/`, writes a manifest, and resets `flow-state.json`
307
+ to the track's initial stage.
308
+
309
+ The chain is driven by `closeout.shipSubstate` inside `flow-state.json`
310
+ (`retro_review` → `compound_review` → `ready_to_archive` → `archived`).
311
+ If your session dies mid-closeout, a new `/cc-next` resumes at the
312
+ exact step — retro drafts are not regenerated and no structured ask is
313
+ repeated silently.
314
+
315
+ You can still invoke each step manually (`/cc-ops retro`, `/cc-ops
316
+ compound`, `/cc-ops archive`), but for the default path you do not need
317
+ to: `/cc-next` is the only command.
299
318
 
300
319
  ---
301
320
 
@@ -15,35 +15,46 @@ export function archiveCommandContract() {
15
15
 
16
16
  ## Purpose
17
17
 
18
- Archive the active cclaw run from inside the harness flow (agent-first finish).
18
+ Finalize the active cclaw run: move artifacts to \`${runsPath()}/<archive-id>\`,
19
+ snapshot state, write a manifest, and reset runtime for the next run.
19
20
 
20
- This command removes the user-facing CLI gap: users can stay in \`/cc-*\` flow and
21
- finish with \`/cc-ops archive\` after ship + retro are complete.
21
+ Auto-triggered by \`/cc-next\` when \`closeout.shipSubstate === "ready_to_archive"\`.
22
+ Direct invocation from a harness command is supported but rarely needed.
22
23
 
23
24
  ## HARD-GATE
24
25
 
25
- - Do not archive a shipped run when retro is still incomplete.
26
- - Do not manually move files between \`${activeArtifactsPath()}\` and \`${runsPath()}\`.
27
- - Use the archive runtime so state snapshots + manifest stay consistent.
26
+ - Do not archive with \`closeout.shipSubstate !== "ready_to_archive"\`.
27
+ - Do not archive a shipped run when \`retro.completedAt\` is missing and
28
+ \`closeout.retroSkipped !== true\`.
29
+ - Never hand-move files between \`${activeArtifactsPath()}\` and \`${runsPath()}\`.
30
+ Always run the archive runtime command so the snapshot+manifest stay
31
+ atomic.
28
32
 
29
33
  ## Inputs
30
34
 
31
- \`/cc-ops archive [--name=<slug>] [--skip-retro --retro-reason=<text>]\`
35
+ \`/cc-ops archive [--name=<slug>]\`
36
+
37
+ (Legacy flags \`--skip-retro --retro-reason=<text>\` still exist for CLI
38
+ invocations; in-harness the skip path is driven by \`closeout.retroSkipped\`
39
+ set during retro.)
32
40
 
33
41
  ## Algorithm
34
42
 
35
43
  1. Read \`${flowStatePath()}\`.
36
- 2. If ship is complete and \`retro.completedAt\` is absent:
37
- - block with explicit instruction: run \`/cc-ops retro\` first.
44
+ 2. Verify \`closeout.shipSubstate === "ready_to_archive"\`. If not, report
45
+ \`closeout not ready (state=<substate>) | run: /cc-next\` and stop.
38
46
  3. Build archive command:
39
- - base: \`npx cclaw archive\`
40
- - optional: \`--name=<slug>\`
41
- - optional override: \`--skip-retro --retro-reason=<text>\`
42
- 4. Execute archive command in project root.
43
- 5. Surface result:
47
+ - base: \`npx cclaw archive\`,
48
+ - optional: \`--name=<slug>\`,
49
+ - legacy override: \`--skip-retro --retro-reason=<text>\` (only when user
50
+ explicitly wants the CLI skip path).
51
+ 4. Execute the archive command in project root.
52
+ 5. On success, flow-state is reset to the initial stage for the default
53
+ track; \`closeout.shipSubstate\` returns to \`"idle"\` on reset.
54
+ 6. Surface:
44
55
  - archive id/path,
45
- - reset stage (brainstorm/spec depending on track default),
46
- - knowledge curation hint when threshold exceeded.
56
+ - reset stage,
57
+ - knowledge curation hint when \`activeEntryCount >= softThreshold\`.
47
58
 
48
59
  ## Output format
49
60
 
@@ -63,36 +74,51 @@ cclaw archive
63
74
  export function archiveCommandSkillMarkdown() {
64
75
  return `---
65
76
  name: ${ARCHIVE_SKILL_NAME}
66
- description: "Archive the active cclaw run from harness flow and reset runtime safely."
77
+ description: "Finalize the active cclaw run. Auto-triggered by /cc-next when shipSubstate=ready_to_archive."
67
78
  ---
68
79
 
69
80
  # /cc-ops archive
70
81
 
71
82
  ## HARD-GATE
72
83
 
73
- Never simulate archive by hand-editing runtime files. Always execute the archive
74
- runtime command so state snapshots and manifest generation stay atomic.
84
+ Never simulate archive by hand-editing runtime files. Always execute the
85
+ archive runtime command so state snapshots and manifest generation stay
86
+ atomic. Never bypass the substate check — if retro/compound haven't
87
+ advanced the substate to \`ready_to_archive\`, stop and surface the
88
+ mismatch.
75
89
 
76
90
  ## Protocol
77
91
 
78
92
  1. Read \`${flowStatePath()}\`:
79
- - confirm whether ship is completed,
80
- - check \`retro.completedAt\` for post-ship runs.
81
- 2. If ship complete and retro incomplete -> stop and direct user to \`/cc-ops retro\`.
82
- 3. Build shell command:
83
- - \`npx cclaw archive\`
84
- - append \`--name=<slug>\` when provided
85
- - append \`--skip-retro --retro-reason=<text>\` only when user explicitly requests skip
86
- 4. Run command from repo root.
87
- 5. Relay key lines from output:
88
- - archive destination under \`${runsPath()}\`
89
- - flow reset confirmation
90
- - knowledge curation recommendation
93
+ - if \`closeout.shipSubstate !== "ready_to_archive"\`, stop and route
94
+ the user back to \`/cc-next\` (it will resume at the correct step),
95
+ - sanity-check: \`completedStages\` must include \`"ship"\`,
96
+ - sanity-check: \`retro.completedAt\` is set **or**
97
+ \`closeout.retroSkipped === true\` with a reason.
98
+ 2. Build shell command:
99
+ - \`npx cclaw archive\`,
100
+ - append \`--name=<slug>\` when provided,
101
+ - append legacy \`--skip-retro --retro-reason=<text>\` only when the user
102
+ explicitly requests the CLI skip path (normally not needed — skip is
103
+ captured in \`closeout\` during retro).
104
+ 3. Run command from repo root.
105
+ 4. Relay key lines from output:
106
+ - archive destination under \`${runsPath()}\`,
107
+ - flow reset confirmation,
108
+ - knowledge curation recommendation if \`activeEntryCount >= 50\`.
109
+
110
+ ## Resume semantics
111
+
112
+ Archive is idempotent on a per-run basis. If a previous session ran
113
+ archive successfully, the active artifacts directory is empty and
114
+ \`closeout.shipSubstate\` is \`"idle"\`; \`/cc-next\` will simply report
115
+ "Flow complete" or prompt for a new \`/cc\` input.
91
116
 
92
117
  ## Validation
93
118
 
94
- - \`${runsPath()}\` contains a new archive folder.
119
+ - \`${runsPath()}\` contains a new archive folder for this run.
95
120
  - \`${activeArtifactsPath()}\` is reset for the next run.
96
121
  - \`${flowStatePath()}\` is valid JSON and points to the initial stage.
122
+ - \`closeout.shipSubstate === "idle"\` after reset.
97
123
  `;
98
124
  }
@@ -6,29 +6,49 @@ export function compoundCommandContract() {
6
6
 
7
7
  ## Purpose
8
8
 
9
- Lift repeated lessons into durable project assets (rules, protocols, skills)
10
- so the next run is easier and safer.
9
+ Lift repeated lessons from \`${RUNTIME_ROOT}/knowledge.jsonl\` into durable
10
+ project assets (rules, protocols, skills) so the next run is easier and safer.
11
+
12
+ Auto-triggered by \`/cc-next\` when \`closeout.shipSubstate === "compound_review"\`.
13
+ Direct invocation is supported but rarely needed.
11
14
 
12
15
  ## HARD-GATE
13
16
 
14
- - Do not mutate rules/skills without explicit user approval.
15
- - Every proposal must cite concrete knowledge evidence (line references or IDs).
17
+ - Do not mutate rules/skills/protocols without explicit user approval.
18
+ - Every proposal must cite concrete knowledge evidence (line refs or IDs).
16
19
  - Keep scope focused: one compound change set per run.
20
+ - Do not block the archive step if no clusters qualify — record an empty
21
+ compound pass and advance.
22
+
23
+ ## Inputs
24
+
25
+ \`/cc-ops compound\` (no flags). The structured ask presents candidates;
26
+ the user can approve individual lifts, accept-all, or skip.
17
27
 
18
28
  ## Algorithm
19
29
 
20
- 1. Read \`${RUNTIME_ROOT}/knowledge.jsonl\`.
21
- 2. Cluster repeated trigger/action pairs.
22
- 3. For clusters with frequency >= 3, propose one lift action:
23
- - rule update
24
- - protocol update
25
- - utility skill update
26
- 4. For each proposal include:
27
- - why now
28
- - target file(s)
29
- - expected risk reduction
30
- 5. Ask user approval for each proposal before writing.
31
- 6. Apply approved lifts and record completion in retro artifact.
30
+ 1. Read \`${RUNTIME_ROOT}/knowledge.jsonl\` (strict JSONL, one entry per line).
31
+ 2. Cluster entries by \`trigger\` + \`action\` similarity.
32
+ 3. Filter candidates whose recurrence count >= 3.
33
+ 4. If **no candidates** exist:
34
+ - set \`closeout.compoundCompletedAt = <ISO>\`,
35
+ - set \`closeout.compoundPromoted = 0\`,
36
+ - set \`closeout.shipSubstate = "ready_to_archive"\`,
37
+ - emit \`compound: no candidates | next: /cc-next\` and stop.
38
+ 5. Otherwise, present **one** structured ask (AskUserQuestion / AskQuestion /
39
+ plain text) summarising all candidates at once:
40
+ - \`apply-all\` (default) apply every listed lift,
41
+ - \`apply-selected\` prompt per-candidate,
42
+ - \`skip\` — record a skip reason and advance without changes.
43
+ 6. Apply approved lifts to the target file(s). Each lift also appends a
44
+ \`type: "compound"\` entry back to \`${RUNTIME_ROOT}/knowledge.jsonl\`
45
+ summarising what was lifted.
46
+ 7. Update flow-state:
47
+ - \`closeout.compoundCompletedAt = <ISO>\`,
48
+ - \`closeout.compoundPromoted = <count>\`,
49
+ - \`closeout.compoundSkipped = true\` if user picked skip,
50
+ - \`closeout.shipSubstate = "ready_to_archive"\`.
51
+ 8. Emit one-line summary: \`compound: promoted=<N> skipped=<bool> | next: /cc-next\`.
32
52
 
33
53
  ## Primary skill
34
54
 
@@ -38,7 +58,7 @@ so the next run is easier and safer.
38
58
  export function compoundCommandSkillMarkdown() {
39
59
  return `---
40
60
  name: ${COMPOUND_SKILL_NAME}
41
- description: "Compound mode: convert repeated learnings into durable rules/protocols/skills."
61
+ description: "Lift repeated learnings into durable rules/protocols/skills. Auto-triggered after retro accept."
42
62
  ---
43
63
 
44
64
  # /cc-ops compound
@@ -49,13 +69,21 @@ description: "Compound mode: convert repeated learnings into durable rules/proto
49
69
 
50
70
  ## HARD-GATE
51
71
 
52
- No silent codification. Every lift requires explicit user approval.
72
+ No silent codification. Every lift requires explicit user approval. An
73
+ empty pass is allowed and must advance \`closeout.shipSubstate\` to
74
+ \`"ready_to_archive"\`.
53
75
 
54
76
  ## Protocol
55
77
 
56
- 1. Parse \`.cclaw/knowledge.jsonl\` and group repeated lessons.
57
- 2. Keep only candidates with clear recurrence and actionable lift path.
58
- 3. Propose each candidate using this template:
78
+ 1. Parse \`.cclaw/knowledge.jsonl\` and group repeated lessons by
79
+ trigger+action similarity.
80
+ 2. Keep only candidates with recurrence >= 3 and an actionable lift path.
81
+ 3. If none qualify, record an empty pass:
82
+ - \`closeout.compoundCompletedAt = <ISO>\`,
83
+ - \`closeout.compoundPromoted = 0\`,
84
+ - \`closeout.shipSubstate = "ready_to_archive"\`,
85
+ - announce \`compound: no candidates\` and stop.
86
+ 4. Otherwise, render each candidate as:
59
87
 
60
88
  \`\`\`
61
89
  Candidate: <short title>
@@ -65,8 +93,35 @@ Change type: <add/update/remove>
65
93
  Expected benefit: <what regressions this prevents>
66
94
  \`\`\`
67
95
 
68
- 4. Ask user to approve/reject per candidate.
69
- 5. Apply only approved candidates.
70
- 6. Append a \`compound\` learning entry summarizing what was lifted.
96
+ 5. Present **one** structured question with three options:
97
+ - \`apply-all\` (default) apply every candidate,
98
+ - \`apply-selected\` prompt per-candidate approval next,
99
+ - \`skip\` — record a skip reason and advance.
100
+
101
+ 6. For approved candidates:
102
+ - edit the target file(s) with the lift,
103
+ - append a \`type: "compound"\` entry to \`.cclaw/knowledge.jsonl\`
104
+ describing what was promoted.
105
+
106
+ 7. Update flow-state \`closeout\`:
107
+ - \`compoundCompletedAt\`,
108
+ - \`compoundPromoted\` (count),
109
+ - \`compoundSkipped\` (boolean) + \`compoundSkipReason\` when applicable,
110
+ - \`shipSubstate = "ready_to_archive"\`.
111
+
112
+ ## Resume semantics
113
+
114
+ A new session with \`shipSubstate === "compound_review"\` re-runs the scan
115
+ and re-asks the structured question. If the user already applied lifts in
116
+ a previous session but the state file was not updated, they should pick
117
+ \`skip\` with reason \`already-applied\` — compound is idempotent from the
118
+ closeout chain's perspective.
119
+
120
+ ## Validation
121
+
122
+ - \`closeout.compoundCompletedAt\` is set.
123
+ - \`closeout.shipSubstate === "ready_to_archive"\`.
124
+ - If lifts were applied, the target files show the edit and at least one
125
+ new \`compound\` line exists in \`.cclaw/knowledge.jsonl\`.
71
126
  `;
72
127
  }
@@ -33,7 +33,7 @@ This is the only progression command the user needs to drive the entire flow. St
33
33
 
34
34
  - **Do not** invent gate completion: use only \`${flowPath}\` plus observable evidence in repo artifacts.
35
35
  - **Do not** skip stages: advance only from \`currentStage\` to its configured successor.
36
- - If the flow reaches terminal ship completion, route closeout in order: **/cc-ops retro -> /cc-ops compound (optional) -> /cc-ops archive**.
36
+ - After ship completes, the closeout chain **retro -> compound -> archive** runs automatically, driven by \`closeout.shipSubstate\`. Do not ask the user to type those commands manually — follow the substate switch in Path B below.
37
37
 
38
38
  ## Algorithm (mandatory)
39
39
 
@@ -55,9 +55,24 @@ This is the only progression command the user needs to drive the entire flow. St
55
55
  ### Path B: Current stage IS complete (all gates passed, all delegations satisfied)
56
56
 
57
57
  → If current stage's \`next\` is **\`done\`**:
58
- - if \`currentStage === "ship"\` and \`retro.completedAt\` is missing -> route to \`/cc-ops retro\`,
59
- - if \`currentStage === "ship"\` and \`retro.completedAt\` is present -> suggest \`/cc-ops compound\` then route to \`/cc-ops archive\`,
60
- - otherwise report **"Flow complete. All stages finished."** and stop.
58
+
59
+ When \`currentStage === "ship"\`, route by **\`closeout.shipSubstate\`**:
60
+ - \`"idle"\` or missing -> set \`closeout.shipSubstate = "retro_review"\`, then
61
+ load \`${RUNTIME_ROOT}/commands/retro.md\` + \`${RUNTIME_ROOT}/skills/flow-retro/SKILL.md\`
62
+ and execute the retro protocol (draft + one structured accept/edit/skip ask).
63
+ - \`"retro_review"\` -> continue the retro protocol (re-ask the structured
64
+ question; the draft already exists — do not regenerate it).
65
+ - \`"compound_review"\` -> load \`${RUNTIME_ROOT}/commands/compound.md\` +
66
+ \`${RUNTIME_ROOT}/skills/flow-compound/SKILL.md\`, execute the compound
67
+ scan, ask user **one** structured question (apply / skip) per candidate
68
+ cluster or a single accept-all / skip choice, and advance substate on
69
+ completion or skip.
70
+ - \`"ready_to_archive"\` -> load \`${RUNTIME_ROOT}/commands/archive.md\` +
71
+ \`${RUNTIME_ROOT}/skills/flow-archive/SKILL.md\`, run archive, reset state.
72
+ - \`"archived"\` (transient) -> report "run archived" and stop.
73
+
74
+ Otherwise report **"Flow complete. All stages finished."** and stop.
75
+
61
76
  → Otherwise: load **\`${RUNTIME_ROOT}/skills/<skillFolder>/SKILL.md\`** and **\`${RUNTIME_ROOT}/commands/<nextStage>.md\`** for the successor stage. Execute that stage's protocol.
62
77
 
63
78
  ### Track-aware successor resolution
@@ -74,6 +89,9 @@ This is the only progression command the user needs to drive the entire flow. St
74
89
  \`/cc-next\` in a **new session** = resume from where you left off:
75
90
  - Flow-state records \`currentStage\` and which gates have passed.
76
91
  - The stage skill reads upstream artifacts and picks up context.
92
+ - \`closeout.shipSubstate\` carries the post-ship substate, so a crashed
93
+ session during retro/compound/archive resumes at the exact step without
94
+ regenerating the retro draft.
77
95
  - No special resume command needed — \`/cc-next\` IS the resume command.
78
96
 
79
97
  ## Primary skill
@@ -149,11 +167,25 @@ Execute the stage protocol. The stage skill handles interaction, STOP points, ga
149
167
 
150
168
  If \`next\` is \`done\`:
151
169
 
152
- - If \`currentStage\` is \`ship\` and \`retro.completedAt\` is missing -> route to \`/cc-ops retro\`.
153
- - If \`currentStage\` is \`ship\` and \`retro.completedAt\` exists -> suggest \`/cc-ops compound\`, then route to \`/cc-ops archive\`.
154
- - Otherwise report **"Flow complete. All stages finished."** and stop.
170
+ When \`currentStage\` is \`ship\`, automatically drive the **closeout chain**
171
+ by inspecting \`closeout.shipSubstate\`:
172
+
173
+ | shipSubstate | Action |
174
+ |-----------------------|-----------------------------------------------------|
175
+ | \`idle\` / missing | Flip to \`retro_review\` and start retro protocol |
176
+ | \`retro_review\` | Continue retro protocol (re-ask accept/edit/skip) |
177
+ | \`compound_review\` | Run compound scan with a single approve/skip ask |
178
+ | \`ready_to_archive\` | Run archive skill; reset flow-state on success |
179
+ | \`archived\` | Report "run archived"; stop |
180
+
181
+ Each step owns its own state transition. \`/cc-next\` never shells out to
182
+ \`cclaw doctor\` or \`cclaw archive\` automatically — it loads the matching
183
+ skill and command contract and executes the protocol in-session.
184
+
185
+ Otherwise report **"Flow complete. All stages finished."** and stop.
155
186
 
156
- Otherwise load the next stage's skill and command contract, begin execution.
187
+ Otherwise (non-terminal \`next\`): load the next stage's skill and command
188
+ contract, begin execution.
157
189
 
158
190
  ## Stage order
159
191
 
@@ -46,20 +46,47 @@ Shared closeout sequence applied by every stage skill.
46
46
  - update \`guardEvidence\`.
47
47
  3. Persist stage artifact under \`.cclaw/artifacts/\`.
48
48
  4. Run \`npx cclaw doctor\` and resolve failures.
49
- 5. Capture reusable learnings from this stage artifact:
50
- - append 1-3 strict-schema JSONL entries when the stage produced non-obvious
51
- decisions, patterns, or lessons,
52
- - use \`type=rule|pattern|lesson\` (\`compound\` stays retro-focused).
49
+ 5. **Capture through-flow learnings** see the policy below. Knowledge
50
+ accrues continuously across stages, not just at retro.
53
51
  6. Notify user with stage completion and next action (\`/cc-next\`).
54
52
  7. Stop; do not auto-run the next stage unless user asks.
55
53
 
54
+ ## Through-flow knowledge capture
55
+
56
+ Knowledge is recorded **throughout the run**, not saved up for retro.
57
+ Each stage contributes a different kind of insight:
58
+
59
+ | Stage | Typical \`type\` | What to capture |
60
+ |-------------|-----------------|-------------------------------------------------------|
61
+ | brainstorm | \`lesson\` | rejected framings and why (only when non-obvious) |
62
+ | scope | \`rule\` | explicit out-of-scope boundaries worth remembering |
63
+ | design | \`pattern\` | architectural trade-offs and their rationale |
64
+ | spec | \`rule\` | non-negotiable acceptance criteria shape |
65
+ | plan | \`pattern\` | effective decomposition / risk-ordering heuristics |
66
+ | tdd | \`pattern\` | red→green→refactor cycle lessons, test-design notes |
67
+ | review | \`lesson\` | recurring defects / blockers caught in this codebase |
68
+ | ship | \`lesson\` | rollback triggers, preflight gotchas |
69
+ | retro | \`compound\` | process accelerators for the **next** run |
70
+
71
+ Rules:
72
+
73
+ - Append 1–3 strict-schema JSONL lines to \`.cclaw/knowledge.jsonl\` per
74
+ stage when that stage produced non-obvious decisions, patterns, or
75
+ lessons. Obvious restatements of the checklist do not count.
76
+ - Use \`type=rule|pattern|lesson\` during stages; reserve \`type=compound\`
77
+ for the retro step so the retro vs. through-flow signal stays
78
+ distinguishable.
79
+ - Set \`origin_stage\` to the stage that emitted the entry and
80
+ \`origin_feature\` to the active feature slug.
81
+
56
82
  ## Automatic learning capture policy
57
83
 
58
84
  - \`standard\` / \`medium\` tracks: required for \`design\`, \`tdd\`, and \`review\`;
59
85
  recommended for other stages.
60
86
  - \`quick\` track: recommended only (avoid overhead for tiny fixes).
61
87
  - "No learning captured" is acceptable only when explicitly justified (e.g. pure
62
- mechanical change, no new trade-offs).
88
+ mechanical change, no new trade-offs). Record the justification in the
89
+ stage artifact, not in knowledge.jsonl.
63
90
 
64
91
  ## Resume protocol
65
92
 
@@ -108,9 +135,13 @@ No release shortcuts:
108
135
 
109
136
  ## 6) Compound, Don't Repeat
110
137
 
111
- When a reusable lesson appears, add one strict-schema JSONL entry via
112
- \`/cc-learn add\`. Repeated lessons should be lifted into stable rules/skills so
113
- the same class of mistake gets harder to repeat.
138
+ Knowledge is recorded **throughout** the run, not saved for the retro.
139
+ When a reusable lesson appears in design, plan, tdd, or review, append one
140
+ strict-schema JSONL entry to \`.cclaw/knowledge.jsonl\` using
141
+ \`type=rule|pattern|lesson\`. Reserve \`type=compound\` for post-ship retro.
142
+ Repeated lessons (frequency ≥ 3) are lifted into stable
143
+ rules/protocols/skills during the automatic compound pass so the same
144
+ class of mistake gets harder to repeat.
114
145
 
115
146
  ## Turn Announce Discipline
116
147
 
@@ -15,28 +15,62 @@ export function retroCommandContract() {
15
15
 
16
16
  ## Purpose
17
17
 
18
- Mandatory retrospective gate before archive once ship is complete.
18
+ Auto-triggered retrospective after ship. \`/cc-next\` drafts \`${retroArtifactPath()}\`
19
+ from run artifacts and knowledge, then asks the user exactly ONE structured
20
+ question: **edit / accept / skip**. Default = accept.
21
+
22
+ This command is normally invoked indirectly by \`/cc-next\` when
23
+ \`closeout.shipSubstate === "retro_review"\`. Invoking it directly is still
24
+ supported for manual re-runs.
19
25
 
20
26
  ## HARD-GATE
21
27
 
22
- - Do not mark retro complete without writing \`${retroArtifactPath()}\`.
23
- - Do not finish retro without appending at least one \`type=compound\` entry into \`${knowledgePath()}\`.
28
+ - Do not finalize retro without \`${retroArtifactPath()}\` on disk (or an explicit
29
+ \`retroSkipped: true\` in closeout with a one-line reason).
30
+ - Do not finalize without appending **at least one** \`type=compound\` entry to
31
+ \`${knowledgePath()}\` (skipped runs set \`compoundEntries: 0\` instead).
32
+ - Never advance to compound/archive with \`shipSubstate\` still at
33
+ \`"retro_review"\`.
34
+
35
+ ## Inputs
36
+
37
+ \`/cc-ops retro\` (no flags). If the user wants to skip, they answer **skip**
38
+ in the structured ask; there is no \`--skip\` flag.
24
39
 
25
40
  ## Algorithm
26
41
 
27
- 1. Read \`${flowStatePath()}\`; confirm ship stage is complete for current run.
28
- 2. Synthesize retrospective artifact \`${retroArtifactPath()}\` with:
29
- - what slowed this run
30
- - what accelerated this run
31
- - concrete repeatable rule for next run
32
- 3. Append >=1 strict-schema JSONL entry to \`${knowledgePath()}\` with:
33
- - \`type: "compound"\`
34
- - \`stage: "ship"\` or \`"retro"\`
35
- 4. Update flow-state \`retro\` block:
36
- - \`required: true\`
37
- - \`completedAt: <ISO>\`
38
- - \`compoundEntries: <count>\`
39
- 5. Report completion summary and remind user that \`/cc-ops compound\` (optional) can lift repeated learnings before \`/cc-ops archive\`.
42
+ 1. Read \`${flowStatePath()}\`; confirm \`completedStages\` contains \`"ship"\`.
43
+ 2. If \`closeout.shipSubstate !== "retro_review"\`, and \`retro.completedAt\`
44
+ is already set, report "retro already complete" and stop.
45
+ 3. Draft \`${retroArtifactPath()}\` from available evidence:
46
+ - scan \`.cclaw/artifacts/01..08-*.md\` for decisions, blockers, rewinds,
47
+ - scan \`.cclaw/state/delegation-log.json\` for subagent outcomes,
48
+ - scan \`${knowledgePath()}\` for entries recorded during this run,
49
+ - structure the draft as: Outcomes / Slowed / Accelerated / Repeatable rule.
50
+ 4. Update \`closeout.retroDraftedAt = <ISO>\` in flow-state.
51
+ 5. Present **one** structured ask (AskUserQuestion on Claude, AskQuestion on
52
+ Cursor, plain-text options elsewhere):
53
+ - \`accept\` (default) — keep the draft as-is,
54
+ - \`edit\` user edits \`${retroArtifactPath()}\` in-place, then re-runs \`/cc-next\`,
55
+ - \`skip\` — record \`retroSkipped: true\` + one-line reason, no compound entry required.
56
+ 6. On **accept**:
57
+ - append >=1 strict-schema JSONL line to \`${knowledgePath()}\` with
58
+ \`type: "compound"\` and \`stage: "retro"\`,
59
+ - set \`retro.required = true\`, \`retro.completedAt = <ISO>\`,
60
+ \`retro.compoundEntries = <count>\`,
61
+ - set \`closeout.retroAcceptedAt = <ISO>\`,
62
+ - set \`closeout.shipSubstate = "compound_review"\`.
63
+ 7. On **edit**:
64
+ - leave \`shipSubstate = "retro_review"\`,
65
+ - tell user to edit \`${retroArtifactPath()}\` and run \`/cc-next\` again.
66
+ 8. On **skip**:
67
+ - require a one-line reason; if empty, re-ask once then escalate,
68
+ - set \`closeout.retroSkipped = true\`, \`closeout.retroSkipReason = <text>\`,
69
+ \`closeout.retroAcceptedAt = <ISO>\`,
70
+ - set \`retro.completedAt = <ISO>\` (marks gate satisfied for archive), and
71
+ \`retro.compoundEntries = 0\`,
72
+ - set \`closeout.shipSubstate = "compound_review"\`.
73
+ 9. Emit a one-line summary: \`retro: accepted|edited|skipped | next: /cc-next\`.
40
74
 
41
75
  ## Primary skill
42
76
 
@@ -46,33 +80,71 @@ Mandatory retrospective gate before archive once ship is complete.
46
80
  export function retroCommandSkillMarkdown() {
47
81
  return `---
48
82
  name: ${RETRO_SKILL_NAME}
49
- description: "Run mandatory retrospective and record compound knowledge before archive."
83
+ description: "Auto-drafted retrospective with a single structured accept/edit/skip ask. Triggered from /cc-next when shipSubstate=retro_review."
50
84
  ---
51
85
 
52
86
  # /cc-ops retro
53
87
 
54
88
  ## HARD-GATE
55
89
 
56
- Archive must remain blocked until retro artifact exists and compound knowledge was appended.
90
+ Archive stays blocked until one of:
91
+ - retro artifact exists **and** one compound knowledge entry was appended, OR
92
+ - retro was explicitly skipped with a one-line reason recorded in closeout.
93
+
94
+ Do not silently skip. Do not finalize without updating \`flow-state.json\`.
57
95
 
58
96
  ## Protocol
59
97
 
60
- 1. Confirm ship completion from \`${flowStatePath()}\`.
61
- 2. Create/update \`${retroArtifactPath()}\` with concise retrospective sections:
62
- - outcomes
63
- - bottlenecks
64
- - reusable acceleration patterns
65
- 3. Append at least one \`compound\` knowledge entry into \`${knowledgePath()}\`.
66
- 4. Update \`flow-state.json.retro\` with completion timestamp + compound count.
67
- 5. Print explicit completion line:
68
- - \`retro gate: complete\`
69
- - \`compound entries added: <N>\`
70
- - \`next: /cc-ops compound (optional) -> /cc-ops archive\`
98
+ 1. Confirm ship completion by reading \`${flowStatePath()}\`.
99
+ 2. If retro draft does not yet exist, synthesise \`${retroArtifactPath()}\` using:
100
+ - all \`.cclaw/artifacts/*-*.md\` from the active run (stages 01–08),
101
+ - \`.cclaw/state/delegation-log.json\` entries,
102
+ - \`${knowledgePath()}\` entries written during this run.
103
+ Draft sections:
104
+ - **Outcomes** what was actually shipped.
105
+ - **Slowed** concrete friction points (cite artifact line or delegation id).
106
+ - **Accelerated** patterns/decisions that worked and are worth keeping.
107
+ - **Repeatable rule** one candidate rule/pattern for next run.
108
+ Record \`closeout.retroDraftedAt\`.
109
+ 3. Ask the user **one** structured question via the harness question tool
110
+ (AskUserQuestion / AskQuestion / plain text fallback):
111
+
112
+ > Retro draft ready at \`${retroArtifactPath()}\`. How do you want to
113
+ > proceed? (default: accept)
114
+ >
115
+ > - **accept** — keep the draft and continue.
116
+ > - **edit** — I'll edit it, then re-run \`/cc-next\`.
117
+ > - **skip** — no retro this run (requires one-line reason).
118
+
119
+ 4. Apply the state transition for the chosen option:
120
+ - \`accept\` → append \`{ "type": "compound", "stage": "retro", ... }\` line
121
+ to \`${knowledgePath()}\`; set \`retro.completedAt\`, \`retro.compoundEntries\`,
122
+ \`closeout.retroAcceptedAt\`; set \`closeout.shipSubstate = "compound_review"\`.
123
+ - \`edit\` → leave \`shipSubstate = "retro_review"\`; announce resume path.
124
+ - \`skip\` → set \`closeout.retroSkipped\`, \`closeout.retroSkipReason\`,
125
+ \`closeout.retroAcceptedAt\`, \`retro.completedAt\`,
126
+ \`retro.compoundEntries = 0\`; set \`closeout.shipSubstate = "compound_review"\`.
127
+
128
+ 5. Print one-line completion summary:
129
+ - \`retro gate: accepted (<N> compound entries)\`
130
+ - \`retro gate: skipped (reason: <text>)\`
131
+ - \`retro gate: editing (re-run /cc-next when ready)\`
132
+
133
+ ## Resume semantics
134
+
135
+ A new session with \`closeout.shipSubstate === "retro_review"\` resumes
136
+ exactly here. If \`closeout.retroDraftedAt\` is present but
137
+ \`retroAcceptedAt\` is missing, re-ask the same structured question without
138
+ regenerating the draft.
71
139
 
72
140
  ## Validation
73
141
 
74
- - \`${retroArtifactPath()}\` exists and is non-empty.
75
- - \`${knowledgePath()}\` contains >=1 valid \`compound\` line.
76
- - \`retro.completedAt\` is set in flow-state.
142
+ - \`${retroArtifactPath()}\` exists and is non-empty, **or**
143
+ \`closeout.retroSkipped === true\` with a non-empty reason.
144
+ - When accepted: \`${knowledgePath()}\` gained a valid \`compound\` line
145
+ and \`retro.compoundEntries > 0\`.
146
+ - \`retro.completedAt\` is set.
147
+ - \`closeout.shipSubstate\` is \`"compound_review"\` (or still
148
+ \`"retro_review"\` when user picked \`edit\`).
77
149
  `;
78
150
  }
@@ -28,6 +28,35 @@ export interface RetroState {
28
28
  completedAt?: string;
29
29
  compoundEntries: number;
30
30
  }
31
+ /**
32
+ * Ship closeout substate machine.
33
+ *
34
+ * After ship completes, cclaw auto-chains retro → compound → archive.
35
+ * Each step is interruptible: `/cc-next` reads `shipSubstate` and resumes
36
+ * from the correct step even across sessions.
37
+ *
38
+ * - `idle` — ship not complete, or closeout not yet started.
39
+ * - `retro_review` — 09-retro.md draft exists; awaiting user edit/accept/skip.
40
+ * - `compound_review` — retro accepted; compound pass awaiting execution
41
+ * (or user skip).
42
+ * - `ready_to_archive` — retro + compound done; archive is the next
43
+ * automatic step.
44
+ * - `archived` — archive completed in this session (transient — archive
45
+ * resets flow-state so this value does not persist between runs).
46
+ */
47
+ export declare const SHIP_SUBSTATES: readonly ["idle", "retro_review", "compound_review", "ready_to_archive", "archived"];
48
+ export type ShipSubstate = (typeof SHIP_SUBSTATES)[number];
49
+ export interface CloseoutState {
50
+ shipSubstate: ShipSubstate;
51
+ retroDraftedAt?: string;
52
+ retroAcceptedAt?: string;
53
+ retroSkipped?: boolean;
54
+ retroSkipReason?: string;
55
+ compoundCompletedAt?: string;
56
+ compoundSkipped?: boolean;
57
+ compoundPromoted: number;
58
+ }
59
+ export declare function createInitialCloseoutState(): CloseoutState;
31
60
  export interface FlowState {
32
61
  activeRunId: string;
33
62
  currentStage: FlowStage;
@@ -44,6 +73,8 @@ export interface FlowState {
44
73
  rewinds: RewindRecord[];
45
74
  /** Mandatory retrospective gate status before archive. */
46
75
  retro: RetroState;
76
+ /** Ship → retro → compound → archive substate for resumable closeout. */
77
+ closeout: CloseoutState;
47
78
  }
48
79
  export interface InitialFlowStateOptions {
49
80
  activeRunId?: string;
@@ -2,6 +2,41 @@ import { COMMAND_FILE_ORDER } from "./constants.js";
2
2
  import { buildTransitionRules, orderedStageSchemas, stageConditionalGateIds, stageGateIds, stageRecommendedGateIds } from "./content/stage-schema.js";
3
3
  import { FLOW_STAGES, FLOW_TRACKS, TRACK_STAGES } from "./types.js";
4
4
  export const TRANSITION_RULES = buildTransitionRules();
5
+ /**
6
+ * Ship closeout substate machine.
7
+ *
8
+ * After ship completes, cclaw auto-chains retro → compound → archive.
9
+ * Each step is interruptible: `/cc-next` reads `shipSubstate` and resumes
10
+ * from the correct step even across sessions.
11
+ *
12
+ * - `idle` — ship not complete, or closeout not yet started.
13
+ * - `retro_review` — 09-retro.md draft exists; awaiting user edit/accept/skip.
14
+ * - `compound_review` — retro accepted; compound pass awaiting execution
15
+ * (or user skip).
16
+ * - `ready_to_archive` — retro + compound done; archive is the next
17
+ * automatic step.
18
+ * - `archived` — archive completed in this session (transient — archive
19
+ * resets flow-state so this value does not persist between runs).
20
+ */
21
+ export const SHIP_SUBSTATES = [
22
+ "idle",
23
+ "retro_review",
24
+ "compound_review",
25
+ "ready_to_archive",
26
+ "archived"
27
+ ];
28
+ export function createInitialCloseoutState() {
29
+ return {
30
+ shipSubstate: "idle",
31
+ retroDraftedAt: undefined,
32
+ retroAcceptedAt: undefined,
33
+ retroSkipped: undefined,
34
+ retroSkipReason: undefined,
35
+ compoundCompletedAt: undefined,
36
+ compoundSkipped: undefined,
37
+ compoundPromoted: 0
38
+ };
39
+ }
5
40
  export function isFlowTrack(value) {
6
41
  return typeof value === "string" && FLOW_TRACKS.includes(value);
7
42
  }
@@ -48,7 +83,8 @@ export function createInitialFlowState(activeRunIdOrOptions = "active", maybeTra
48
83
  required: false,
49
84
  completedAt: undefined,
50
85
  compoundEntries: 0
51
- }
86
+ },
87
+ closeout: createInitialCloseoutState()
52
88
  };
53
89
  }
54
90
  export function canTransition(from, to) {
package/dist/runs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { COMMAND_FILE_ORDER, RUNTIME_ROOT } from "./constants.js";
4
- import { canTransition, createInitialFlowState, isFlowTrack, skippedStagesForTrack } from "./flow-state.js";
4
+ import { canTransition, createInitialCloseoutState, createInitialFlowState, isFlowTrack, skippedStagesForTrack, SHIP_SUBSTATES } from "./flow-state.js";
5
5
  import { ensureFeatureSystem, readActiveFeature, syncActiveFeatureSnapshot } from "./feature-system.js";
6
6
  import { ensureDir, exists, withDirectoryLock, writeFileSafe } from "./fs-utils.js";
7
7
  export class InvalidStageTransitionError extends Error {
@@ -272,6 +272,37 @@ function sanitizeRetroState(value) {
272
272
  compoundEntries
273
273
  };
274
274
  }
275
+ function isShipSubstate(value) {
276
+ return typeof value === "string" && SHIP_SUBSTATES.includes(value);
277
+ }
278
+ function sanitizeCloseoutState(value) {
279
+ const fallback = createInitialCloseoutState();
280
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
281
+ return fallback;
282
+ }
283
+ const typed = value;
284
+ const shipSubstate = isShipSubstate(typed.shipSubstate) ? typed.shipSubstate : fallback.shipSubstate;
285
+ const retroDraftedAt = typeof typed.retroDraftedAt === "string" ? typed.retroDraftedAt : undefined;
286
+ const retroAcceptedAt = typeof typed.retroAcceptedAt === "string" ? typed.retroAcceptedAt : undefined;
287
+ const retroSkipped = typeof typed.retroSkipped === "boolean" ? typed.retroSkipped : undefined;
288
+ const retroSkipReason = typeof typed.retroSkipReason === "string" ? typed.retroSkipReason : undefined;
289
+ const compoundCompletedAt = typeof typed.compoundCompletedAt === "string" ? typed.compoundCompletedAt : undefined;
290
+ const compoundSkipped = typeof typed.compoundSkipped === "boolean" ? typed.compoundSkipped : undefined;
291
+ const promotedRaw = typed.compoundPromoted;
292
+ const compoundPromoted = typeof promotedRaw === "number" && Number.isFinite(promotedRaw) && promotedRaw >= 0
293
+ ? Math.floor(promotedRaw)
294
+ : 0;
295
+ return {
296
+ shipSubstate,
297
+ retroDraftedAt,
298
+ retroAcceptedAt,
299
+ retroSkipped,
300
+ retroSkipReason,
301
+ compoundCompletedAt,
302
+ compoundSkipped,
303
+ compoundPromoted
304
+ };
305
+ }
275
306
  function coerceFlowState(parsed) {
276
307
  const track = coerceTrack(parsed.track);
277
308
  const next = createInitialFlowState("active", track);
@@ -289,7 +320,8 @@ function coerceFlowState(parsed) {
289
320
  skippedStages: sanitizeSkippedStages(parsed.skippedStages, track),
290
321
  staleStages: sanitizeStaleStages(parsed.staleStages),
291
322
  rewinds: sanitizeRewinds(parsed.rewinds),
292
- retro: sanitizeRetroState(parsed.retro)
323
+ retro: sanitizeRetroState(parsed.retro),
324
+ closeout: sanitizeCloseoutState(parsed.closeout)
293
325
  };
294
326
  }
295
327
  function toArchiveDate(date = new Date()) {
@@ -536,9 +568,12 @@ export async function archiveRun(projectRoot, featureName, options = {}) {
536
568
  if (skipRetro && (!skipRetroReason || skipRetroReason.length === 0)) {
537
569
  throw new Error("archive --skip-retro requires --retro-reason=<text>.");
538
570
  }
539
- if (retroGate.required && !retroGate.completed && !skipRetro) {
571
+ const retroSkippedInCloseout = sourceState.closeout.retroSkipped === true &&
572
+ typeof sourceState.closeout.retroSkipReason === "string" &&
573
+ sourceState.closeout.retroSkipReason.trim().length > 0;
574
+ if (retroGate.required && !retroGate.completed && !skipRetro && !retroSkippedInCloseout) {
540
575
  throw new Error("Archive blocked: retro gate is required after ship completion. " +
541
- "Run /cc-ops retro and append at least one compound knowledge entry, or re-run /cc-ops archive with --skip-retro and --retro-reason.");
576
+ "Run /cc-next (auto-runs retro) or, for CLI-only flows, re-run `cclaw archive --skip-retro --retro-reason=<text>`.");
542
577
  }
543
578
  if (retroGate.completed) {
544
579
  const completedAt = sourceState.retro.completedAt ?? new Date().toISOString();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cclaw-cli",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Installer-first flow toolkit for coding agents",
5
5
  "type": "module",
6
6
  "bin": {