@smartmemory/compose 0.2.50-beta → 0.2.51

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.
Files changed (118) hide show
  1. package/.claude/skills/compose/SKILL.md +24 -1
  2. package/.claude/skills/compose/references/hermes-tools.md +80 -0
  3. package/README.md +1 -1
  4. package/bin/compose.js +310 -52
  5. package/dist/assets/App-CT0vXPgd.js +724 -0
  6. package/dist/assets/_baseUniq-CsOHc_iS.js +1 -0
  7. package/dist/assets/{arc-DeHak63Z.js → arc-BXht3LyE.js} +1 -1
  8. package/dist/assets/architectureDiagram-Q4EWVU46-BV1r86-w.js +36 -0
  9. package/dist/assets/blockDiagram-DXYQGD6D-BgcMJjAR.js +132 -0
  10. package/dist/assets/{browser-DW2JlJCC.js → browser-CnKiSnlr.js} +6 -6
  11. package/dist/assets/{c4Diagram-AAUBKEIU-BsFJmPuS.js → c4Diagram-AHTNJAMY-nBIRLJTv.js} +1 -1
  12. package/dist/assets/channel-Dd4XaiYv.js +1 -0
  13. package/dist/assets/{chunk-4BX2VUAB-XO4S2_89.js → chunk-4BX2VUAB-CNmGyhrp.js} +1 -1
  14. package/dist/assets/chunk-4TB4RGXK-MLT7I7w4.js +206 -0
  15. package/dist/assets/{chunk-55IACEB6-CtFSLInj.js → chunk-55IACEB6-D8KuKVLa.js} +1 -1
  16. package/dist/assets/{chunk-2J33WTMH-AEu6HIoY.js → chunk-EDXVE4YY-TPlt1bS2.js} +1 -1
  17. package/dist/assets/{chunk-FMBD7UC4-BMGd_Y9a.js → chunk-FMBD7UC4-tYY8xcjr.js} +1 -1
  18. package/dist/assets/chunk-OYMX7WX6-yBPwT1AT.js +231 -0
  19. package/dist/assets/{chunk-QZHKN3VN-DHhUJ8RK.js → chunk-QZHKN3VN-B4Wfybww.js} +1 -1
  20. package/dist/assets/{chunk-ND2GUHAM-BlrOECEr.js → chunk-YZCP3GAM-DE6_5aqh.js} +1 -1
  21. package/dist/assets/classDiagram-6PBFFD2Q-DshSQDF9.js +1 -0
  22. package/dist/assets/classDiagram-v2-HSJHXN6E-DshSQDF9.js +1 -0
  23. package/dist/assets/clone-CBsbNGAa.js +1 -0
  24. package/dist/assets/{cose-bilkent-S5V4N54A-C3M0mZqk.js → cose-bilkent-S5V4N54A-DzzRyJtB.js} +1 -1
  25. package/dist/assets/dagre-KV5264BT-CTcTVGdU.js +4 -0
  26. package/dist/assets/diagram-5BDNPKRD-qR6mc8kJ.js +10 -0
  27. package/dist/assets/diagram-G4DWMVQ6-CUcGXyNb.js +24 -0
  28. package/dist/assets/diagram-MMDJMWI5-B68cPonH.js +43 -0
  29. package/dist/assets/diagram-TYMM5635-q8Id8eFG.js +24 -0
  30. package/dist/assets/{erDiagram-TEJ5UH35-AMDitV0b.js → erDiagram-SMLLAGMA-CtxJi57K.js} +1 -1
  31. package/dist/assets/{flowDiagram-I6XJVG4X-C0t2ZGQv.js → flowDiagram-DWJPFMVM-BzzO4JYU.js} +1 -1
  32. package/dist/assets/ganttDiagram-T4ZO3ILL-Dn0wIyhR.js +292 -0
  33. package/dist/assets/gitGraphDiagram-UUTBAWPF-tnNFXfMM.js +106 -0
  34. package/dist/assets/graph-DZe55uk8.js +331 -0
  35. package/dist/assets/graph-Tq_bs_r0.js +1 -0
  36. package/dist/assets/index-8UhRLbGq.js +123 -0
  37. package/dist/assets/index-CRqB9els.css +1 -0
  38. package/dist/assets/infoDiagram-42DDH7IO-BXLvLeS0.js +2 -0
  39. package/dist/assets/{ishikawaDiagram-YF4QCWOH-CCBwgjFs.js → ishikawaDiagram-UXIWVN3A-DWx-7BBy.js} +5 -5
  40. package/dist/assets/{journeyDiagram-JHISSGLW-zUJN38EU.js → journeyDiagram-VCZTEJTY-C42hXNha.js} +1 -1
  41. package/dist/assets/{kanban-definition-UN3LZRKU-BNxWi-8J.js → kanban-definition-6JOO6SKY-CEq930ew.js} +1 -1
  42. package/dist/assets/katex-DkKDou_j.js +257 -0
  43. package/dist/assets/layout-qtUgN9BC.js +1 -0
  44. package/dist/assets/{linear-CRH9b4g7.js → linear-D158F7OT.js} +1 -1
  45. package/dist/assets/min-hESxN-c0.js +1 -0
  46. package/dist/assets/{mindmap-definition-RKZ34NQL-DolYwq7Y.js → mindmap-definition-QFDTVHPH-d9SSh2nG.js} +7 -7
  47. package/dist/assets/mobile-1gVCT0OK.css +1 -0
  48. package/dist/assets/mobile-Chw8RWyH.js +17 -0
  49. package/dist/assets/pieDiagram-DEJITSTG-gglmeMav.js +30 -0
  50. package/dist/assets/quadrantDiagram-34T5L4WZ-CqFC_htU.js +7 -0
  51. package/dist/assets/{requirementDiagram-4Y6WPE33-DsXZ05jo.js → requirementDiagram-MS252O5E-B1ZFIotK.js} +1 -1
  52. package/dist/assets/sankeyDiagram-XADWPNL6-BvItvZt5.js +10 -0
  53. package/dist/assets/sequenceDiagram-FGHM5R23-CAIn5Z3U.js +157 -0
  54. package/dist/assets/stateDiagram-FHFEXIEX-CyJrGzib.js +1 -0
  55. package/dist/assets/stateDiagram-v2-QKLJ7IA2-DprhF_Ho.js +1 -0
  56. package/dist/assets/{timeline-definition-PNZ67QCA-Bvnhw58e.js → timeline-definition-GMOUNBTQ-k_0vJQAK.js} +1 -1
  57. package/dist/assets/{vennDiagram-CIIHVFJN-5WnyjZqf.js → vennDiagram-DHZGUBPP-TZAW60b0.js} +4 -4
  58. package/dist/assets/wardley-RL74JXVD-DzQEoG6X.js +162 -0
  59. package/dist/assets/wardleyDiagram-NUSXRM2D-BAoVVIjZ.js +20 -0
  60. package/dist/assets/{xychartDiagram-2RQKCTM6-BCShes6B.js → xychartDiagram-5P7HB3ND-CynkZcUb.js} +1 -1
  61. package/dist/index.html +4 -4
  62. package/lib/build.js +272 -33
  63. package/lib/codex-preflight.js +151 -0
  64. package/lib/completion-writer.js +21 -1
  65. package/lib/feature-validator.js +5 -1
  66. package/lib/hooks-status.js +135 -0
  67. package/lib/install-agent-defs.js +22 -0
  68. package/lib/migrate-anon.js +277 -0
  69. package/lib/roadmap-parser.js +1 -1
  70. package/lib/test-bootstrap.js +165 -2
  71. package/lib/vocabulary-inject.js +103 -0
  72. package/package.json +2 -1
  73. package/pipelines/build-quick.stratum.yaml +433 -0
  74. package/pipelines/build.stratum.yaml +60 -3
  75. package/scripts/watch-server.sh +32 -0
  76. package/server/build-routes.js +89 -9
  77. package/server/build-stream-bridge.js +12 -0
  78. package/server/compose-mcp-tools.js +73 -1
  79. package/server/compose-mcp.js +27 -0
  80. package/server/feature-scaffold-routes.js +82 -0
  81. package/server/health-routes.js +261 -0
  82. package/server/qa-scope-routes.js +96 -0
  83. package/server/validate-routes.js +70 -0
  84. package/server/vision-routes.js +29 -0
  85. package/server/vision-server.js +21 -0
  86. package/dist/assets/App-Bxyif1yv.js +0 -706
  87. package/dist/assets/architectureDiagram-3BPJPVTR-C5Nkyl9y.js +0 -36
  88. package/dist/assets/blockDiagram-GPEHLZMM-BilnUBG2.js +0 -132
  89. package/dist/assets/channel-ZgbQ1k0u.js +0 -1
  90. package/dist/assets/chunk-727SXJPM-CZeBRpM9.js +0 -206
  91. package/dist/assets/chunk-AQP2D5EJ-_vmxcBc4.js +0 -231
  92. package/dist/assets/classDiagram-4FO5ZUOK-KXxOorUx.js +0 -1
  93. package/dist/assets/classDiagram-v2-Q7XG4LA2-KXxOorUx.js +0 -1
  94. package/dist/assets/dagre-BM42HDAG-DJlm4fEk.js +0 -4
  95. package/dist/assets/diagram-2AECGRRQ-BmcONQG5.js +0 -43
  96. package/dist/assets/diagram-5GNKFQAL-5JbWGIwd.js +0 -10
  97. package/dist/assets/diagram-KO2AKTUF-DAnIvyI0.js +0 -3
  98. package/dist/assets/diagram-LMA3HP47-Bmh7tvmI.js +0 -24
  99. package/dist/assets/diagram-OG6HWLK6-hnHVMNnk.js +0 -24
  100. package/dist/assets/ganttDiagram-6RSMTGT7-BPlM-BEN.js +0 -292
  101. package/dist/assets/gitGraphDiagram-PVQCEYII-Lv_YTxnb.js +0 -106
  102. package/dist/assets/graph-BBXaecIU.js +0 -331
  103. package/dist/assets/graph-CAnANduQ.js +0 -1
  104. package/dist/assets/index-BwLfbbOu.css +0 -1
  105. package/dist/assets/index-COq21Zym.js +0 -119
  106. package/dist/assets/infoDiagram-5YYISTIA-Dul1vdUm.js +0 -2
  107. package/dist/assets/katex-C5jXJg4s.js +0 -257
  108. package/dist/assets/layout-DGIYPm2g.js +0 -1
  109. package/dist/assets/mobile-Cag5dHlF.css +0 -1
  110. package/dist/assets/mobile-DwmxS_O4.js +0 -17
  111. package/dist/assets/pieDiagram-4H26LBE5-oxNfr2TX.js +0 -30
  112. package/dist/assets/quadrantDiagram-W4KKPZXB-BmZCvD-z.js +0 -7
  113. package/dist/assets/sankeyDiagram-5OEKKPKP-DsnYaawP.js +0 -40
  114. package/dist/assets/sequenceDiagram-3UESZ5HK-Dt5mu3g8.js +0 -162
  115. package/dist/assets/stateDiagram-AJRCARHV-BFR5ZINQ.js +0 -1
  116. package/dist/assets/stateDiagram-v2-BHNVJYJU-BDrQD8fR.js +0 -1
  117. package/dist/assets/wardley-L42UT6IY-CTxW4xow.js +0 -173
  118. package/dist/assets/wardleyDiagram-YWT4CUSO-K8Y1EOvb.js +0 -78
@@ -0,0 +1,433 @@
1
+ # metadata:
2
+ # id: build-quick
3
+ # label: "Quick Feature Build"
4
+ # description: "Trimmed build lifecycle for small additive work — design → implement → ship, single gate, Phase-7 enforcement preserved"
5
+ # category: development
6
+ # steps: 11
7
+ # estimated_minutes: 45
8
+ #
9
+ # COMP-BUILD-QUICK: a trimmed variant of build.stratum.yaml. Symmetric to fix
10
+ # mode's Quick path. Collapses the full lifecycle to design → implement → ship:
11
+ # prd, architecture, blueprint, verification, plan, plan_gate, and report are
12
+ # OMITTED (not self-skipping). Phase-7 enforcement (parallel + codex review,
13
+ # coverage sweep, test review) is preserved verbatim — only phase ceremony
14
+ # shrinks. NOT OpenSpec's no-gates model: the design gate and ship gate remain.
15
+ #
16
+ # workflow.name is kept as `build` so the runner (lib/build.js extractFlowName /
17
+ # step-id couplings for execute|docs|ship) sees the identical flow; only the
18
+ # step list differs. Selected via `compose build --quick` → template 'build-quick'.
19
+
20
+ version: "0.3"
21
+
22
+ workflow:
23
+ name: build
24
+ description: "Quick feature build — design → implement → ship (single design gate, Phase-7 enforcement preserved)"
25
+ input:
26
+ featureCode:
27
+ type: string
28
+ required: true
29
+ description:
30
+ type: string
31
+ required: true
32
+ pre_merge_gate:
33
+ type: array
34
+ required: false # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: default-OFF per-task gate (lint+build), omitted unless capabilities.preMergeGate
35
+
36
+ contracts:
37
+ PhaseResult:
38
+ phase: {type: string}
39
+ artifact: {type: string}
40
+ outcome: {type: string, values: [complete, skipped, failed]}
41
+ summary: {type: string}
42
+
43
+ # Canonical review output — produced by both review_check (Codex) and parallel_review (Claude).
44
+ # Schema source: compose/contracts/review-result.json (_roadmap: STRAT-CLAUDE-EFFORT-PARITY)
45
+ ReviewResult:
46
+ clean: {type: boolean}
47
+ summary: {type: string}
48
+ findings: {type: array}
49
+ meta: {type: object}
50
+ lenses_run: {type: array}
51
+ auto_fixes: {type: array}
52
+ asks: {type: array}
53
+
54
+ TestResult:
55
+ passing: {type: boolean}
56
+ summary: {type: string}
57
+ failures: {type: array}
58
+
59
+ TaskGraph:
60
+ tasks: {type: array}
61
+
62
+ LensTask:
63
+ id: {type: string}
64
+ lens_name: {type: string}
65
+ lens_focus: {type: string}
66
+ confidence_gate: {type: number}
67
+ exclusions: {type: string}
68
+
69
+ TriageResult:
70
+ tasks: {type: array}
71
+
72
+ functions:
73
+ design_gate:
74
+ mode: gate
75
+ timeout: 3600
76
+
77
+ ship_gate:
78
+ mode: gate
79
+ timeout: 1800
80
+
81
+ flows:
82
+ # --- Sub-flow: review ---
83
+ # Single-step: codex reviews, stratum retries via ensure_failed.
84
+ # Cross-agent fix (claude) is dispatched by build.js when ensure_failed
85
+ # fires with a recovery_agent configured on the parent flow step.
86
+ review_check:
87
+ input:
88
+ task: {type: string}
89
+ blueprint: {type: string}
90
+ output: ReviewResult
91
+ steps:
92
+ - id: review
93
+ agent: codex
94
+ intent: >
95
+ Review the implementation against the blueprint and task.
96
+ inputs:
97
+ task: "$.input.task"
98
+ blueprint: "$.input.blueprint"
99
+ review_mode: "true"
100
+ confidence_gate: "7"
101
+ output_contract: ReviewResult
102
+ ensure:
103
+ - "result.clean == True"
104
+ retries: 5
105
+
106
+ # --- Sub-flow: parallel_review ---
107
+ # Multi-lens review: triage selects lenses, parallel dispatch runs them,
108
+ # merge deduplicates and classifies findings. Falls back to review_check
109
+ # if parallel dispatch is unavailable.
110
+ parallel_review:
111
+ input:
112
+ task: {type: string}
113
+ blueprint: {type: string}
114
+ diff: {type: string}
115
+ prior_dirty_lenses: {type: array, optional: true}
116
+ output: ReviewResult
117
+ steps:
118
+ - id: triage
119
+ agent: "claude:orchestrator"
120
+ intent: >
121
+ Decide which review lenses to activate.
122
+
123
+ RETRY PATH — If the file .compose/prior_dirty_lenses.json exists, read it.
124
+ It contains a JSON array of lens IDs that had actionable findings in the prior
125
+ review run. In this case:
126
+ - Activate all lenses listed in that array.
127
+ - Always also include diff-quality and contract-compliance (baseline lenses —
128
+ they re-run on every retry to catch regressions introduced by the fix, even
129
+ if they passed clean last time).
130
+ - Skip all other lenses — they already passed clean.
131
+
132
+ FIRST RUN PATH — If .compose/prior_dirty_lenses.json does not exist:
133
+ - Always include diff-quality and contract-compliance.
134
+ - Add security if files touch auth, crypto, SQL, HTTP handlers.
135
+ - Add framework if detected framework files (React, Express, Next.js, etc).
136
+
137
+ Return JSON: { "tasks": LensTask[] } where each task has id, lens_name,
138
+ lens_focus, confidence_gate, exclusions.
139
+ inputs:
140
+ diff: "$.input.diff"
141
+ output_contract: TriageResult
142
+
143
+ - id: review_lenses
144
+ type: parallel_dispatch
145
+ agent: "claude:read-only-reviewer"
146
+ source: "$.steps.triage.output.tasks"
147
+ max_concurrent: 4
148
+ isolation: none
149
+ output_contract: ReviewResult
150
+ intent_template: >
151
+ Lens: {lens_name}. Focus: {lens_focus}.
152
+ require: all
153
+
154
+ - id: merge
155
+ agent: "claude:orchestrator"
156
+ intent: >
157
+ Merge ReviewResult arrays from all lens runs into a single canonical ReviewResult.
158
+ The input contains the parallel dispatch aggregate with tasks[].result for each lens.
159
+ 1. Concatenate all findings arrays from completed task results.
160
+ Deduplicate by file+line+lens: keep finding with highest confidence;
161
+ carry over its applied_gate.
162
+ 2. Recompute clean: zero must-fix AND zero should-fix findings (post-dedupe, post-gate).
163
+ 3. lenses_run = IDs of lenses that produced any must-fix or should-fix finding.
164
+ 4. auto_fixes = mechanical fixes (formatting, typos, simple tests).
165
+ 5. asks = findings requiring human judgment.
166
+ Return canonical ReviewResult with clean, summary, findings, lenses_run,
167
+ auto_fixes, asks, meta.
168
+ inputs:
169
+ results: "$.steps.review_lenses.output"
170
+ task: "$.input.task"
171
+ blueprint: "$.input.blueprint"
172
+ reduce_mode: "true"
173
+ output_contract: ReviewResult
174
+ depends_on: [review_lenses]
175
+
176
+ # --- Sub-flow: coverage ---
177
+ # Single-step: claude runs tests, stratum retries via ensure_failed.
178
+ # Cross-agent fix is dispatched by build.js on ensure_failed.
179
+ coverage_check:
180
+ input:
181
+ task: {type: string}
182
+ plan: {type: string}
183
+ output: TestResult
184
+ steps:
185
+ - id: run_tests
186
+ agent: "claude::fast"
187
+ intent: >
188
+ Run the project test suite. Return structured JSON:
189
+ { "passing": boolean, "summary": string, "failures": string[] }.
190
+ inputs:
191
+ task: "$.input.task"
192
+ output_contract: TestResult
193
+ ensure:
194
+ - "result.passing == True"
195
+ retries: 15
196
+
197
+ # --- Sub-flow: test_review (COMP-TEST-BOOTSTRAP-4-1) ---
198
+ # Reviews the test files the coverage step generated this build. The
199
+ # implementation review (review/codex_review) runs BEFORE coverage, so
200
+ # generated tests are never otherwise reviewed. build.js injects the exact
201
+ # generated-test file list into this step's intent, and skips the step
202
+ # entirely (synthetic clean stepDone) when coverage produced no test files.
203
+ # ADVISORY: no blocking ensure — findings surface to the human, never fail ship.
204
+ test_review:
205
+ input:
206
+ task: {type: string}
207
+ blueprint: {type: string}
208
+ output: ReviewResult
209
+ steps:
210
+ - id: review_generated_tests
211
+ agent: codex
212
+ intent: >
213
+ Review the auto-generated test files listed below (written by the coverage
214
+ step this build) and verify their assertions match intent. Read each file.
215
+ Flag tests that are placeholders (assert true / pass with no real assertion),
216
+ tautological, or assert only on mocks/stubs rather than exercising the
217
+ feature's behavior. For each weak test, cite file:line and state what real
218
+ assertion is missing. Do NOT flag hand-written tests or pure style. Output a
219
+ canonical ReviewResult.
220
+ inputs:
221
+ task: "$.input.task"
222
+ blueprint: "$.input.blueprint"
223
+ review_mode: "true"
224
+ confidence_gate: "7"
225
+ # ADVISORY (COMP-TEST-BOOTSTRAP-4-1): deliberately NO output_contract and NO
226
+ # ensure. A schema/postcondition failure here would trigger executeChildFlow's
227
+ # blocking fix-retry path and could block ship (report→docs→ship chain through
228
+ # test_review). Without either gate the step always completes; build.js captures
229
+ # whatever the reviewer returns and surfaces it via the test_review stream event.
230
+
231
+ # --- Main flow: quick feature lifecycle (design → implement → ship) ---
232
+ build:
233
+ input:
234
+ featureCode: {type: string}
235
+ description: {type: string}
236
+ pre_merge_gate: {type: array} # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: optional per-task pre-merge gate
237
+ output: PhaseResult
238
+ max_rounds: 10
239
+ steps:
240
+ # Phase: Explore & Design
241
+ - id: explore_design
242
+ agent: claude
243
+ intent: >
244
+ Explore the codebase and write a design doc for this feature.
245
+ Launch 2-3 explorer subagents in parallel to map architecture,
246
+ find similar features, and analyze related implementations.
247
+ Write the design to docs/features/{featureCode}/design.md.
248
+ Return the artifact path in the "artifact" field.
249
+
250
+ QUICK-PATH GUARDRAIL: this is `compose build --quick`, scoped to small
251
+ additive work (e.g. one flag + a test). If the work proves multi-file,
252
+ cross-cutting, or in need of architecture/PRD-level design, STOP and
253
+ recommend the user re-run with full `compose build` (no `--quick`)
254
+ rather than under-scoping. Note the recommendation in the design doc.
255
+ inputs:
256
+ featureCode: "$.input.featureCode"
257
+ description: "$.input.description"
258
+ output_contract: PhaseResult
259
+ ensure:
260
+ - "result.outcome == 'complete'"
261
+ - "file_exists(result.artifact)"
262
+ retries: 2
263
+
264
+ # Gate: Design review
265
+ - id: design_gate
266
+ function: design_gate
267
+ on_approve: decompose
268
+ on_revise: explore_design
269
+ on_kill: null
270
+ depends_on: [explore_design]
271
+
272
+ # Phase: Decompose — analyze the design and emit a task graph
273
+ # (Quick path: no separate plan step — decompose reads the design doc directly.)
274
+ - id: decompose
275
+ type: decompose
276
+ agent: claude
277
+ intent: >
278
+ Read the design doc at docs/features/{featureCode}/design.md and decompose
279
+ it into independent tasks. For each task, identify files_owned (exclusive
280
+ write), files_read (read-only), and depends_on (tasks that must complete first).
281
+ Return a TaskGraph with the task array.
282
+
283
+ QUICK-PATH GUARDRAIL: if decomposition reveals the work is actually multi-file,
284
+ cross-cutting, or architecture-dependent, STOP and recommend the user re-run
285
+ with full `compose build` (no `--quick`) rather than under-scoping.
286
+ output_contract: TaskGraph
287
+ ensure:
288
+ - "no_file_conflicts(result.tasks)"
289
+ - "len(result.tasks) >= 1"
290
+ retries: 2
291
+ depends_on: [design_gate]
292
+
293
+ # Phase: Execute — parallel dispatch of decomposed tasks
294
+ - id: execute
295
+ type: parallel_dispatch
296
+ source: "$.steps.decompose.output.tasks"
297
+ agent: claude
298
+ max_concurrent: 3
299
+ isolation: worktree
300
+ capture_diff: true
301
+ defer_advance: true
302
+ pre_merge_verify: "$.input.pre_merge_gate" # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: optional per-task fast gate (default-OFF)
303
+ require: all
304
+ merge: sequential_apply
305
+ intent_template: >
306
+ Implement this task using TDD. Write the test first, watch it fail,
307
+ implement, watch it pass.
308
+
309
+ Task: {task.description}
310
+ You own these files (may create/modify): {task.files_owned}
311
+ You may read (but NOT modify): {task.files_read}
312
+
313
+ Feature: {task.id}
314
+ depends_on: [decompose]
315
+
316
+ # Sub-flow: Review (parallel multi-lens review; falls back to review_check)
317
+ # Parent-step ensure drives the fix loop: ensure_failed -> build.js fix ->
318
+ # retry the whole parallel_review sub-flow, which re-runs fresh triage/lenses/merge.
319
+ # Quick path: review reference is the design doc (no blueprint step exists).
320
+ - id: review
321
+ flow: parallel_review
322
+ inputs:
323
+ task: "$.steps.execute.output.outcome"
324
+ blueprint: "$.steps.explore_design.output.artifact"
325
+ diff: "$.steps.execute.output.tasks"
326
+ ensure:
327
+ - "result.clean == True"
328
+ depends_on: [execute]
329
+
330
+ # Sub-flow: Codex review (independent cross-model pass after Claude lenses + fixes)
331
+ - id: codex_review
332
+ flow: review_check
333
+ inputs:
334
+ task: "$.steps.execute.output.outcome"
335
+ blueprint: "$.steps.explore_design.output.artifact"
336
+ ensure:
337
+ - "result.clean == True"
338
+ depends_on: [review]
339
+
340
+ # Sub-flow: Coverage (claude runs tests; build.js dispatches fix on ensure_failed)
341
+ - id: coverage
342
+ flow: coverage_check
343
+ inputs:
344
+ task: "$.steps.execute.output.outcome"
345
+ plan: "$.input.description"
346
+ ensure:
347
+ - "result.passing == True"
348
+ depends_on: [codex_review]
349
+
350
+ # Sub-flow: Test review (COMP-TEST-BOOTSTRAP-4-1) — review the tests the
351
+ # coverage step generated this build. build.js injects the generated-test
352
+ # file list into the intent, and reports a synthetic clean result (skip)
353
+ # when coverage produced no test files. Advisory — never blocks ship.
354
+ - id: test_review
355
+ flow: test_review
356
+ inputs:
357
+ task: "$.steps.execute.output.outcome"
358
+ blueprint: "$.steps.explore_design.output.artifact"
359
+ depends_on: [coverage]
360
+
361
+ # Phase: Update Docs
362
+ - id: docs
363
+ agent: claude
364
+ intent: >
365
+ Update project documentation for this feature. You MUST:
366
+
367
+ 1. CHANGELOG.md — Add an entry under today's date with the feature code
368
+ and a bullet list of what was built. Read the existing format first.
369
+ 2. ROADMAP.md — Find this feature's row and change its status to COMPLETE.
370
+ If this completes a parent feature, update the parent header too.
371
+ 3. README.md — Update ONLY if the feature changes user-facing setup,
372
+ commands, or capabilities. Skip if purely internal.
373
+ 4. CLAUDE.md — Update ONLY if new conventions, commands, or architecture
374
+ patterns were introduced. Skip if no changes.
375
+ 5. Public docs — If the feature introduces or changes any of these, update
376
+ the relevant file in docs/:
377
+ - New CLI commands or flags → docs/compose-one-pager.md
378
+ - New connector or agent type → docs/connectors.md
379
+ - New workflow or lifecycle change → docs/use-cases.md
380
+ - API or config changes → docs/PRODUCT-SPEC.md
381
+ Read each file before editing. Skip if the feature is purely internal
382
+ with no user-facing changes.
383
+
384
+ Read each file before editing. Do not skip CHANGELOG and ROADMAP —
385
+ they are always required. Commit nothing — the ship step handles commits.
386
+ inputs:
387
+ featureCode: "$.input.featureCode"
388
+ description: "$.input.description"
389
+ output_contract: PhaseResult
390
+ retries: 2
391
+ depends_on: [test_review]
392
+
393
+ # Phase: Ship
394
+ - id: ship
395
+ agent: "claude::critical"
396
+ intent: >
397
+ Final verification and commit. You MUST:
398
+
399
+ 1. Run the test suite (npm test or node --test test/*.test.js).
400
+ If tests fail, fix them before proceeding.
401
+ 2. Run the build (npx vite build). Must pass.
402
+ 3. Check git status — verify CHANGELOG.md and ROADMAP.md were updated
403
+ by the docs step. If they weren't, update them now.
404
+ 4. Stage all changed files for this feature (git add — be explicit,
405
+ never stage worktrees, pycache, or node_modules).
406
+ 5. Commit with message: "feat(<featureCode>): <one-line summary>"
407
+ 6. Push to remote.
408
+ 7. Read docs/features/{featureCode}/design.md and extract acceptance criteria
409
+ as plan_items: an array of objects { text, file, critical } where:
410
+ - text is the checkbox item text
411
+ - file is the backtick-quoted file path in the item (null if none)
412
+ - critical is true if the item mentions MUST, required, security, or tests
413
+ Use lib/plan-parser.js (parsePlanItems) to do this extraction.
414
+ 8. Collect the list of files you staged as files_changed.
415
+
416
+ Include plan_items and files_changed in your result JSON.
417
+ Report the commit hash and files changed.
418
+ inputs:
419
+ featureCode: "$.input.featureCode"
420
+ description: "$.input.description"
421
+ output_contract: PhaseResult
422
+ ensure:
423
+ - "plan_completion(result.plan_items, result.files_changed)"
424
+ retries: 2
425
+ depends_on: [docs]
426
+
427
+ # Gate: Ship review
428
+ - id: ship_gate
429
+ function: ship_gate
430
+ on_approve: null
431
+ on_revise: ship
432
+ on_kill: null
433
+ depends_on: [ship]
@@ -21,6 +21,12 @@ workflow:
21
21
  pre_merge_gate:
22
22
  type: array
23
23
  required: false # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: default-OFF per-task gate (lint+build), omitted unless capabilities.preMergeGate
24
+ implementer_agent:
25
+ type: string
26
+ required: false # COMP-CODEX-IMPL: who writes the code (default claude; codex under --codex). Compose always supplies it.
27
+ reviewer_agent:
28
+ type: string
29
+ required: false # COMP-CODEX-IMPL: cross-model reviewer, always != implementer (default codex; claude under --codex).
24
30
 
25
31
  contracts:
26
32
  PhaseResult:
@@ -80,10 +86,11 @@ flows:
80
86
  input:
81
87
  task: {type: string}
82
88
  blueprint: {type: string}
89
+ reviewer_agent: {type: string} # COMP-CODEX-IMPL: threaded from the parent build flow (sub-flows have their own $.input scope)
83
90
  output: ReviewResult
84
91
  steps:
85
92
  - id: review
86
- agent: codex
93
+ agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: codex by default; claude when codex is the implementer (no self-review)
87
94
  intent: >
88
95
  Review the implementation against the blueprint and task.
89
96
  inputs:
@@ -187,12 +194,49 @@ flows:
187
194
  - "result.passing == True"
188
195
  retries: 15
189
196
 
197
+ # --- Sub-flow: test_review (COMP-TEST-BOOTSTRAP-4-1) ---
198
+ # Reviews the test files the coverage step generated this build. The
199
+ # implementation review (review/codex_review) runs BEFORE coverage, so
200
+ # generated tests are never otherwise reviewed. build.js injects the exact
201
+ # generated-test file list into this step's intent, and skips the step
202
+ # entirely (synthetic clean stepDone) when coverage produced no test files.
203
+ # ADVISORY: no blocking ensure — findings surface to the human, never fail ship.
204
+ test_review:
205
+ input:
206
+ task: {type: string}
207
+ blueprint: {type: string}
208
+ reviewer_agent: {type: string} # COMP-CODEX-IMPL: threaded from the parent build flow
209
+ output: ReviewResult
210
+ steps:
211
+ - id: review_generated_tests
212
+ agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: codex by default; claude when codex implements
213
+ intent: >
214
+ Review the auto-generated test files listed below (written by the coverage
215
+ step this build) and verify their assertions match intent. Read each file.
216
+ Flag tests that are placeholders (assert true / pass with no real assertion),
217
+ tautological, or assert only on mocks/stubs rather than exercising the
218
+ feature's behavior. For each weak test, cite file:line and state what real
219
+ assertion is missing. Do NOT flag hand-written tests or pure style. Output a
220
+ canonical ReviewResult.
221
+ inputs:
222
+ task: "$.input.task"
223
+ blueprint: "$.input.blueprint"
224
+ review_mode: "true"
225
+ confidence_gate: "7"
226
+ # ADVISORY (COMP-TEST-BOOTSTRAP-4-1): deliberately NO output_contract and NO
227
+ # ensure. A schema/postcondition failure here would trigger executeChildFlow's
228
+ # blocking fix-retry path and could block ship (report→docs→ship chain through
229
+ # test_review). Without either gate the step always completes; build.js captures
230
+ # whatever the reviewer returns and surfaces it via the test_review stream event.
231
+
190
232
  # --- Main flow: compose feature lifecycle ---
191
233
  build:
192
234
  input:
193
235
  featureCode: {type: string}
194
236
  description: {type: string}
195
237
  pre_merge_gate: {type: array} # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: optional per-task pre-merge gate
238
+ implementer_agent: {type: string} # COMP-CODEX-IMPL: code-writing executor (default claude; codex under --codex)
239
+ reviewer_agent: {type: string} # COMP-CODEX-IMPL: cross-model reviewer, always != implementer
196
240
  output: PhaseResult
197
241
  max_rounds: 10
198
242
  steps:
@@ -344,7 +388,7 @@ flows:
344
388
  - id: execute
345
389
  type: parallel_dispatch
346
390
  source: "$.steps.decompose.output.tasks"
347
- agent: claude
391
+ agent: "$.input.implementer_agent" # COMP-CODEX-IMPL: claude by default, codex under --codex (resolved via STRAT-AGENT-INTERP)
348
392
  max_concurrent: 3
349
393
  isolation: worktree
350
394
  capture_diff: true
@@ -382,6 +426,7 @@ flows:
382
426
  inputs:
383
427
  task: "$.steps.execute.output.outcome"
384
428
  blueprint: "$.steps.blueprint.output.artifact"
429
+ reviewer_agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: thread the role into the sub-flow
385
430
  ensure:
386
431
  - "result.clean == True"
387
432
  depends_on: [review]
@@ -396,6 +441,18 @@ flows:
396
441
  - "result.passing == True"
397
442
  depends_on: [codex_review]
398
443
 
444
+ # Sub-flow: Test review (COMP-TEST-BOOTSTRAP-4-1) — review the tests the
445
+ # coverage step generated this build. build.js injects the generated-test
446
+ # file list into the intent, and reports a synthetic clean result (skip)
447
+ # when coverage produced no test files. Advisory — never blocks ship.
448
+ - id: test_review
449
+ flow: test_review
450
+ inputs:
451
+ task: "$.steps.execute.output.outcome"
452
+ blueprint: "$.steps.blueprint.output.artifact"
453
+ reviewer_agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: thread the role into the sub-flow
454
+ depends_on: [coverage]
455
+
399
456
  # Phase: Report (skippable)
400
457
  - id: report
401
458
  agent: claude
@@ -414,7 +471,7 @@ flows:
414
471
  retries: 2
415
472
  skip_if: "true"
416
473
  skip_reason: "Report skipped by default — set skip_if to false to enable"
417
- depends_on: [coverage]
474
+ depends_on: [test_review]
418
475
 
419
476
  # Phase: Update Docs
420
477
  - id: docs
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ # watch-server.sh — restart the Compose :4001 API server on source changes (dev).
3
+ #
4
+ # Frees the port first (killing any stale/orphaned `node server/index.js` left by a
5
+ # dead session — exactly the leftover that reds the pre-push test suite), then runs
6
+ # the server under Node's built-in --watch so any change in the loaded module graph
7
+ # (server/**, lib/**) triggers a clean restart. server/index.js handles SIGTERM with
8
+ # process.exit(0), so the port releases cleanly between restarts.
9
+ #
10
+ # Scope: the :4001 API server only. For the full stack (agent server :4002 + Vite),
11
+ # use `npm run dev:server` (the supervisor) — it crash-restarts but does NOT watch files.
12
+ #
13
+ # Usage: npm run dev:watch (or: bash scripts/watch-server.sh ; PORT=4099 to override)
14
+ set -euo pipefail
15
+
16
+ PORT="${PORT:-4001}"
17
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
18
+ cd "$ROOT"
19
+
20
+ # Free the port so --watch can bind: kill any current listener (stale orphan or a
21
+ # previous run). lsof exits non-zero when nothing is listening — the `|| true`
22
+ # keeps `set -e` from tripping on the empty case.
23
+ stale="$(lsof -ti ":$PORT" -sTCP:LISTEN 2>/dev/null || true)"
24
+ if [ -n "$stale" ]; then
25
+ echo "[watch-server] freeing :$PORT — killing listener(s): $(echo "$stale" | tr '\n' ' ')"
26
+ # shellcheck disable=SC2086 # word-splitting intended: $stale may hold several PIDs
27
+ kill $stale 2>/dev/null || true
28
+ sleep 1
29
+ fi
30
+
31
+ echo "[watch-server] node --watch server/index.js on :$PORT — edit server/** or lib/** to restart (Ctrl-C to stop)"
32
+ exec env PORT="$PORT" node --watch server/index.js