@printpractical/cruze 0.0.13 → 0.0.15

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 (308) hide show
  1. package/README.md +61 -118
  2. package/dist/adapters/inbound/cli/cli_context.js +0 -27
  3. package/dist/adapters/inbound/cli/commands/code.js +5 -18
  4. package/dist/adapters/inbound/cli/commands/documents.js +11 -37
  5. package/dist/adapters/inbound/cli/commands/init.js +1 -1
  6. package/dist/adapters/inbound/cli/commands/install.js +1 -0
  7. package/dist/adapters/inbound/cli/commands/review.js +2 -9
  8. package/dist/adapters/inbound/cli/commands/status.js +16 -63
  9. package/dist/adapters/inbound/cli/commands.js +10 -37
  10. package/dist/adapters/inbound/cli/parse_command.js +0 -54
  11. package/dist/adapters/outbound/git_repository.js +2 -71
  12. package/dist/app/ports/repository.js +0 -12
  13. package/dist/app/project_context.js +15 -25
  14. package/dist/app/use_cases/approve_document.js +29 -0
  15. package/dist/app/use_cases/check_code.js +21 -56
  16. package/dist/app/use_cases/install_skills.js +7 -1
  17. package/dist/app/use_cases/new_document.js +25 -0
  18. package/dist/app/use_cases/project_status.js +43 -67
  19. package/dist/app/use_cases/run_review.js +11 -30
  20. package/dist/app/use_cases/validate_project.js +8 -5
  21. package/dist/domain/approvals.js +51 -0
  22. package/dist/domain/check/check_source.js +3 -32
  23. package/dist/domain/check/imports.js +3 -3
  24. package/dist/domain/check/rust_imports.js +25 -3
  25. package/dist/domain/config.js +8 -84
  26. package/dist/domain/hashing.js +16 -30
  27. package/dist/domain/ids.js +13 -27
  28. package/dist/domain/next_step.js +41 -0
  29. package/dist/domain/project/features.js +71 -0
  30. package/dist/domain/project/layout.js +11 -27
  31. package/dist/domain/project/project_docs.js +48 -0
  32. package/dist/domain/project/release.js +30 -0
  33. package/dist/domain/scaffold.js +0 -1
  34. package/dist/domain/skill_budget.js +4 -4
  35. package/dist/domain/trace.js +8 -25
  36. package/dist/domain/validation/document_rules.js +65 -0
  37. package/dist/domain/validation/release_rules.js +45 -0
  38. package/dist/domain/validation/review_rules.js +21 -0
  39. package/dist/domain/validation/validate_project.js +20 -27
  40. package/dist/domain/versions/cruze_version.js +3 -9
  41. package/dist/main.js +1 -1
  42. package/package.json +1 -1
  43. package/skills/asking/SKILL.md +51 -0
  44. package/skills/behavioural-testing/SKILL.md +14 -16
  45. package/skills/behavioural-testing/examples.md +1 -2
  46. package/skills/behavioural-testing/fakes.md +2 -2
  47. package/skills/build/SKILL.md +34 -38
  48. package/skills/dependency-approval/SKILL.md +34 -31
  49. package/skills/envision/SKILL.md +23 -18
  50. package/skills/envision/architecture.md +16 -0
  51. package/skills/envision/breakdown.md +14 -0
  52. package/skills/envision/possibilities.md +6 -7
  53. package/skills/fix/SKILL.md +34 -0
  54. package/skills/formats/SKILL.md +39 -87
  55. package/skills/formats/config.md +47 -0
  56. package/skills/formats/templates/architecture.md +18 -74
  57. package/skills/formats/templates/feature.md +18 -34
  58. package/skills/formats/templates/vision.md +15 -27
  59. package/skills/hexagonal-design/SKILL.md +11 -11
  60. package/skills/hexagonal-design/contracts.md +3 -3
  61. package/skills/hexagonal-design/fundamentals.md +1 -1
  62. package/skills/hexagonal-design/languages/cpp.md +1 -1
  63. package/skills/hexagonal-design/languages/rust.md +1 -1
  64. package/skills/hexagonal-design/languages/swift.md +2 -2
  65. package/skills/hexagonal-design/runtime.md +2 -2
  66. package/skills/research/SKILL.md +4 -4
  67. package/skills/research/evaluation.md +1 -1
  68. package/skills/review/SKILL.md +27 -0
  69. package/skills/roles/SKILL.md +8 -59
  70. package/skills/roles/code-reviewer.md +22 -32
  71. package/skills/roles/researcher.md +3 -3
  72. package/skills/shape/SKILL.md +37 -0
  73. package/skills/shape/self-check.md +12 -0
  74. package/src/adapters/inbound/cli/cli_context.ts +0 -27
  75. package/src/adapters/inbound/cli/commands/code.ts +5 -18
  76. package/src/adapters/inbound/cli/commands/documents.ts +11 -37
  77. package/src/adapters/inbound/cli/commands/init.ts +1 -1
  78. package/src/adapters/inbound/cli/commands/install.ts +1 -0
  79. package/src/adapters/inbound/cli/commands/review.ts +2 -9
  80. package/src/adapters/inbound/cli/commands/status.ts +16 -63
  81. package/src/adapters/inbound/cli/commands.ts +10 -37
  82. package/src/adapters/inbound/cli/parse_command.ts +0 -54
  83. package/src/adapters/outbound/git_repository.ts +2 -71
  84. package/src/app/ports/repository.ts +0 -12
  85. package/src/app/project_context.ts +15 -25
  86. package/src/app/use_cases/approve_document.ts +29 -0
  87. package/src/app/use_cases/check_code.ts +21 -56
  88. package/src/app/use_cases/install_skills.ts +7 -1
  89. package/src/app/use_cases/new_document.ts +25 -0
  90. package/src/app/use_cases/project_status.ts +49 -73
  91. package/src/app/use_cases/run_review.ts +11 -30
  92. package/src/app/use_cases/validate_project.ts +8 -5
  93. package/src/domain/approvals.ts +51 -0
  94. package/src/domain/check/check_source.ts +3 -32
  95. package/src/domain/check/imports.ts +3 -3
  96. package/src/domain/check/rust_imports.ts +25 -3
  97. package/src/domain/config.ts +9 -85
  98. package/src/domain/hashing.ts +16 -30
  99. package/src/domain/ids.ts +13 -27
  100. package/src/domain/next_step.ts +41 -0
  101. package/src/domain/project/features.ts +71 -0
  102. package/src/domain/project/layout.ts +11 -27
  103. package/src/domain/project/project_docs.ts +48 -0
  104. package/src/domain/project/release.ts +30 -0
  105. package/src/domain/scaffold.ts +0 -1
  106. package/src/domain/skill_budget.ts +4 -4
  107. package/src/domain/trace.ts +8 -25
  108. package/src/domain/validation/document_rules.ts +65 -0
  109. package/src/domain/validation/release_rules.ts +45 -0
  110. package/src/domain/validation/review_rules.ts +21 -0
  111. package/src/domain/validation/validate_project.ts +21 -28
  112. package/src/domain/versions/cruze_version.ts +3 -9
  113. package/src/main.ts +1 -1
  114. package/templates/init/AGENTS.md +4 -12
  115. package/templates/init/ci.yml +3 -3
  116. package/templates/init/config.yaml +8 -17
  117. package/templates/init/review/claude.yaml +2 -2
  118. package/dist/adapters/inbound/cli/argument_files.js +0 -29
  119. package/dist/adapters/inbound/cli/commands/diff.js +0 -23
  120. package/dist/adapters/inbound/cli/commands/journal.js +0 -32
  121. package/dist/adapters/inbound/cli/commands/progress.js +0 -55
  122. package/dist/adapters/inbound/cli/commands/realign.js +0 -28
  123. package/dist/adapters/inbound/cli/commands/show.js +0 -96
  124. package/dist/app/use_cases/abandon_work.js +0 -42
  125. package/dist/app/use_cases/approve_artifact.js +0 -197
  126. package/dist/app/use_cases/journal_events.js +0 -64
  127. package/dist/app/use_cases/land_change.js +0 -134
  128. package/dist/app/use_cases/new_project_doc.js +0 -48
  129. package/dist/app/use_cases/new_work_item.js +0 -75
  130. package/dist/app/use_cases/realign_done.js +0 -45
  131. package/dist/app/use_cases/realign_status.js +0 -106
  132. package/dist/app/use_cases/record_progress.js +0 -118
  133. package/dist/app/use_cases/show_elements.js +0 -18
  134. package/dist/app/use_cases/show_notes.js +0 -11
  135. package/dist/app/use_cases/show_scope.js +0 -51
  136. package/dist/app/use_cases/upstream_diff.js +0 -55
  137. package/dist/domain/approvals/agent_approval.js +0 -68
  138. package/dist/domain/approvals/evaluate.js +0 -36
  139. package/dist/domain/approvals/fingerprint.js +0 -52
  140. package/dist/domain/approvals/rebase.js +0 -39
  141. package/dist/domain/approvals/records.js +0 -50
  142. package/dist/domain/approvals/upstream_text.js +0 -36
  143. package/dist/domain/architecture_sections.js +0 -23
  144. package/dist/domain/check/decision_comments.js +0 -38
  145. package/dist/domain/decision_citations.js +0 -62
  146. package/dist/domain/edits/agents_file.js +0 -58
  147. package/dist/domain/edits/managed_tables.js +0 -60
  148. package/dist/domain/edits/progress_block.js +0 -33
  149. package/dist/domain/edits/status_lines.js +0 -52
  150. package/dist/domain/elements.js +0 -126
  151. package/dist/domain/journal.js +0 -109
  152. package/dist/domain/land/bookkeeping.js +0 -54
  153. package/dist/domain/land/merge_plan.js +0 -137
  154. package/dist/domain/land/text_ops.js +0 -66
  155. package/dist/domain/line_diff.js +0 -56
  156. package/dist/domain/project/artifact_ref.js +0 -42
  157. package/dist/domain/project/deltas.js +0 -49
  158. package/dist/domain/project/element_lookup.js +0 -124
  159. package/dist/domain/project/living_model.js +0 -55
  160. package/dist/domain/project/new_items.js +0 -48
  161. package/dist/domain/project/notes.js +0 -74
  162. package/dist/domain/project/plan_parts.js +0 -111
  163. package/dist/domain/project/progress.js +0 -43
  164. package/dist/domain/project/project_view.js +0 -72
  165. package/dist/domain/project/roadmap.js +0 -43
  166. package/dist/domain/project/scope_view.js +0 -134
  167. package/dist/domain/project/work_items.js +0 -68
  168. package/dist/domain/status/next_step.js +0 -181
  169. package/dist/domain/status/pending_rethink.js +0 -22
  170. package/dist/domain/status/verification.js +0 -29
  171. package/dist/domain/status/work_status.js +0 -125
  172. package/dist/domain/validation/decision_rules.js +0 -76
  173. package/dist/domain/validation/delta_rules.js +0 -81
  174. package/dist/domain/validation/element_rules.js +0 -104
  175. package/dist/domain/validation/future_rules.js +0 -40
  176. package/dist/domain/validation/living_rules.js +0 -99
  177. package/dist/domain/validation/plan_rules.js +0 -124
  178. package/dist/domain/validation/project_rules.js +0 -115
  179. package/dist/domain/validation/size_rules.js +0 -45
  180. package/dist/domain/validation/vision_rules.js +0 -41
  181. package/dist/domain/validation/work_item_rules.js +0 -175
  182. package/dist/domain/versions/realign_notes.js +0 -72
  183. package/dist/domain/versions/rule_versions.js +0 -29
  184. package/dist/domain/versions/scheduled_exceptions.js +0 -41
  185. package/skills/about/SKILL.md +0 -21
  186. package/skills/architect/SKILL.md +0 -49
  187. package/skills/architect/feature.md +0 -40
  188. package/skills/architect/project.md +0 -71
  189. package/skills/architect/tweak.md +0 -22
  190. package/skills/architect/walkthrough.md +0 -35
  191. package/skills/domain-language/SKILL.md +0 -37
  192. package/skills/envision/feature.md +0 -25
  193. package/skills/envision/intake.md +0 -28
  194. package/skills/envision/project.md +0 -24
  195. package/skills/explore/SKILL.md +0 -39
  196. package/skills/formats/reference/architecture.md +0 -84
  197. package/skills/formats/reference/config.md +0 -80
  198. package/skills/formats/reference/durable-docs.md +0 -74
  199. package/skills/formats/reference/specs.md +0 -65
  200. package/skills/formats/reference/work-items.md +0 -100
  201. package/skills/formats/templates/adr.md +0 -7
  202. package/skills/formats/templates/change.md +0 -29
  203. package/skills/formats/templates/glossary.md +0 -8
  204. package/skills/formats/templates/roadmap.md +0 -32
  205. package/skills/formats/templates/spec.md +0 -11
  206. package/skills/formats/templates/standalone-change.md +0 -46
  207. package/skills/grilling/SKILL.md +0 -90
  208. package/skills/grilling/illustrating.md +0 -38
  209. package/skills/improve/SKILL.md +0 -51
  210. package/skills/land/SKILL.md +0 -48
  211. package/skills/next/SKILL.md +0 -31
  212. package/skills/plan/SKILL.md +0 -62
  213. package/skills/plan/tasks.md +0 -35
  214. package/skills/plan/test-plan.md +0 -14
  215. package/skills/realign/SKILL.md +0 -37
  216. package/skills/realign/notes/0.0.10.md +0 -131
  217. package/skills/realign/notes/0.0.11.md +0 -15
  218. package/skills/realign/notes/0.0.12.md +0 -31
  219. package/skills/realign/notes/0.0.13.md +0 -11
  220. package/skills/realign/notes/0.0.2.md +0 -69
  221. package/skills/realign/notes/0.0.3.md +0 -11
  222. package/skills/realign/notes/0.0.4.md +0 -27
  223. package/skills/realign/notes/0.0.5.md +0 -38
  224. package/skills/realign/notes/0.0.6.md +0 -44
  225. package/skills/realign/notes/0.0.7.md +0 -11
  226. package/skills/realign/notes/0.0.8.md +0 -97
  227. package/skills/realign/notes/0.0.9.md +0 -59
  228. package/skills/realign/notes.md +0 -40
  229. package/skills/rethink/SKILL.md +0 -62
  230. package/skills/rethink/levels.md +0 -54
  231. package/skills/roadmap/SKILL.md +0 -54
  232. package/skills/roles/auditor.md +0 -35
  233. package/skills/roles/design-reviewer.md +0 -43
  234. package/skills/roles/design-rubric.md +0 -41
  235. package/skills/roles/plan-rubric.md +0 -11
  236. package/skills/roles/surveyor.md +0 -41
  237. package/skills/roles/verifier.md +0 -42
  238. package/skills/triage/SKILL.md +0 -37
  239. package/skills/verify/SKILL.md +0 -45
  240. package/skills/verify/manual-test.md +0 -23
  241. package/src/adapters/inbound/cli/argument_files.ts +0 -29
  242. package/src/adapters/inbound/cli/commands/diff.ts +0 -23
  243. package/src/adapters/inbound/cli/commands/journal.ts +0 -32
  244. package/src/adapters/inbound/cli/commands/progress.ts +0 -55
  245. package/src/adapters/inbound/cli/commands/realign.ts +0 -28
  246. package/src/adapters/inbound/cli/commands/show.ts +0 -96
  247. package/src/app/use_cases/abandon_work.ts +0 -42
  248. package/src/app/use_cases/approve_artifact.ts +0 -197
  249. package/src/app/use_cases/journal_events.ts +0 -64
  250. package/src/app/use_cases/land_change.ts +0 -134
  251. package/src/app/use_cases/new_project_doc.ts +0 -48
  252. package/src/app/use_cases/new_work_item.ts +0 -75
  253. package/src/app/use_cases/realign_done.ts +0 -45
  254. package/src/app/use_cases/realign_status.ts +0 -106
  255. package/src/app/use_cases/record_progress.ts +0 -118
  256. package/src/app/use_cases/show_elements.ts +0 -18
  257. package/src/app/use_cases/show_notes.ts +0 -11
  258. package/src/app/use_cases/show_scope.ts +0 -51
  259. package/src/app/use_cases/upstream_diff.ts +0 -55
  260. package/src/domain/approvals/agent_approval.ts +0 -68
  261. package/src/domain/approvals/evaluate.ts +0 -36
  262. package/src/domain/approvals/fingerprint.ts +0 -52
  263. package/src/domain/approvals/rebase.ts +0 -39
  264. package/src/domain/approvals/records.ts +0 -50
  265. package/src/domain/approvals/upstream_text.ts +0 -36
  266. package/src/domain/architecture_sections.ts +0 -23
  267. package/src/domain/check/decision_comments.ts +0 -38
  268. package/src/domain/decision_citations.ts +0 -62
  269. package/src/domain/edits/agents_file.ts +0 -58
  270. package/src/domain/edits/managed_tables.ts +0 -60
  271. package/src/domain/edits/progress_block.ts +0 -33
  272. package/src/domain/edits/status_lines.ts +0 -52
  273. package/src/domain/elements.ts +0 -126
  274. package/src/domain/journal.ts +0 -109
  275. package/src/domain/land/bookkeeping.ts +0 -54
  276. package/src/domain/land/merge_plan.ts +0 -137
  277. package/src/domain/land/text_ops.ts +0 -66
  278. package/src/domain/line_diff.ts +0 -56
  279. package/src/domain/project/artifact_ref.ts +0 -42
  280. package/src/domain/project/deltas.ts +0 -49
  281. package/src/domain/project/element_lookup.ts +0 -124
  282. package/src/domain/project/living_model.ts +0 -55
  283. package/src/domain/project/new_items.ts +0 -48
  284. package/src/domain/project/notes.ts +0 -74
  285. package/src/domain/project/plan_parts.ts +0 -111
  286. package/src/domain/project/progress.ts +0 -43
  287. package/src/domain/project/project_view.ts +0 -72
  288. package/src/domain/project/roadmap.ts +0 -43
  289. package/src/domain/project/scope_view.ts +0 -134
  290. package/src/domain/project/work_items.ts +0 -68
  291. package/src/domain/status/next_step.ts +0 -181
  292. package/src/domain/status/pending_rethink.ts +0 -22
  293. package/src/domain/status/verification.ts +0 -29
  294. package/src/domain/status/work_status.ts +0 -125
  295. package/src/domain/validation/decision_rules.ts +0 -76
  296. package/src/domain/validation/delta_rules.ts +0 -81
  297. package/src/domain/validation/element_rules.ts +0 -104
  298. package/src/domain/validation/future_rules.ts +0 -40
  299. package/src/domain/validation/living_rules.ts +0 -99
  300. package/src/domain/validation/plan_rules.ts +0 -124
  301. package/src/domain/validation/project_rules.ts +0 -115
  302. package/src/domain/validation/size_rules.ts +0 -45
  303. package/src/domain/validation/vision_rules.ts +0 -41
  304. package/src/domain/validation/work_item_rules.ts +0 -175
  305. package/src/domain/versions/realign_notes.ts +0 -72
  306. package/src/domain/versions/rule_versions.ts +0 -29
  307. package/src/domain/versions/scheduled_exceptions.ts +0 -41
  308. package/templates/init/gitattributes +0 -2
@@ -23,5 +23,5 @@ Gather this for each serious candidate, from the registry and the repository dur
23
23
  | Component | Decision | Choice | Reason |
24
24
  | --- | --- | --- | --- |
25
25
  | SSH transport | adopt | `russh` <version> | Pure Rust, so no OpenSSL on macOS; maintained, Apache-2.0. `ssh2` needs libssh2. See `.cruze/notes/2026-09-25-ssh-libraries.md` |
26
- | Serial line settings (`115200 8N1`) | build | | A product-specific notation of three fields that no library parses; about 30 lines to own (D3, the user's decision) |
26
+ | Serial line settings (`115200 8N1`) | build | | A product-specific notation of three fields that no library parses; about 30 lines to own (the user's decision) |
27
27
  ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: cruze-review
3
+ description: Reviews a built feature in a fresh context for real defects, a public API that drifted from what the user approved, and scenarios without tests, fixes what it finds, and hands the user only the findings that are theirs.
4
+ ---
5
+
6
+ # Review
7
+
8
+ A reviewer who never saw the build reads the code against the approved feature. It looks for what tests miss: hangs, leaks, races, data loss, failure paths, an API that drifted from what the user approved. One round, then the agent fixes and checks its own fixes. The user hears only about findings that change what they approved.
9
+
10
+ ## Steps
11
+
12
+ 1. **Run the code reviewer** in a fresh context, as `.agents/skills/cruze-roles/SKILL.md` says, on this feature, with the diff from where the feature's branch left `main`: `cruze review code-reviewer --feature <slug> --base <merge-base>`, where the merge base is `git merge-base main HEAD`. Done when you have its report.
13
+ 2. **Check each finding** against the code before acting on it. Drop one whose evidence doesn't hold, and say why in one line.
14
+ 3. **Sort them.** A finding is the user's when fixing it would change a scenario, the public API they approved, or a significant dependency. Every other finding is yours, blockers included.
15
+ 4. **Fix yours.** Fix every blocker, and the concerns worth fixing, each with a test when it is a behaviour. Correct the documents where they no longer match the code, and show the user each change to an approved one with your report, for them to approve. Run the full suite, `cruze check --ci` and `cruze trace <slug>` again. Check your own fixes; don't run the reviewer a second time.
16
+ 5. **Bring the user theirs,** illustrated as `.agents/skills/cruze-asking/SKILL.md` says: the problem in plain words, who meets it and how, and the change to the feature you recommend, as code or output, before and after. Their answer goes through `shape` as a change to the approved feature, then back to build.
17
+ 6. **Report and open the pull request.** Tell the user, in a few lines:
18
+ - what the feature now does;
19
+ - how to try it: the commands to run, with what they should see;
20
+ - what the review found and what you fixed, counted;
21
+ - any finding you left, and why, each filed as an issue as `fix` says, so it isn't lost.
22
+
23
+ Add a line in the user's words under `[Unreleased]` in `CHANGELOG.md`. Update the README's status, and its usage when the feature changes what a user runs or sees, with the same commands as "how to try it". Push the branch and open a pull request, or merge as the project does. Done when the pull request is open or the branch is merged.
24
+
25
+ ## Next step
26
+
27
+ `cruze next` names it: usually `shape` for the next feature.
@@ -1,71 +1,20 @@
1
1
  ---
2
2
  name: cruze-roles
3
- description: Prompts for Cruze's fresh-context roles (the design reviewer, code reviewer, verifier and researcher), how to run one, and how to take a review through its two rounds to a disposition for every finding, with the user deciding only the exceptions. Use when a Cruze workflow step says to run a role, a review or research in a fresh context.
3
+ description: Prompts for Cruze's fresh-context roles, the code reviewer and the researcher, and how to run one. Use when a Cruze step says to run a review or research in a fresh context.
4
4
  ---
5
5
 
6
6
  # Roles
7
7
 
8
- A role is a prompt with fixed inputs and a report as its only output. It runs in a fresh context, so it judges the documents rather than the conversation that produced them. It never edits files.
8
+ A role is a prompt with fixed inputs and a report as its only output. It runs in a fresh context, so it judges the work rather than the conversation that produced it. It never edits files.
9
9
 
10
10
  | Role | File | Used by |
11
11
  | --- | --- | --- |
12
- | Design reviewer | [design-reviewer.md](design-reviewer.md), with [design-rubric.md](design-rubric.md) for a design or [plan-rubric.md](plan-rubric.md) for a plan | architect, at project and feature scope; plan, for the plan review |
13
- | Code reviewer | [code-reviewer.md](code-reviewer.md) | verify, for the code review |
14
- | Verifier | [verifier.md](verifier.md) | verify, to run the system |
15
- | Researcher | [researcher.md](researcher.md) | architect, for adopt-or-build decisions |
16
- | Auditor | [auditor.md](auditor.md) | realign, to compare existing code with what a release now expects |
17
- | Surveyor | [surveyor.md](surveyor.md) | improve, to find structure that departs from the standards or keeps causing friction |
12
+ | Code reviewer | [code-reviewer.md](code-reviewer.md) | review and fix |
13
+ | Researcher | [researcher.md](researcher.md) | envision, for technology choices; any step with a question that needs evidence |
18
14
 
19
15
  ## Running a role
20
16
 
21
- 1. Read the role file and gather exactly the inputs it lists. Done when you have every input path, plus any command output the role asks for.
22
- 2. Start a fresh context: a helper agent with no conversation history, where the agent can start one. Give it the role file's full text and the inputs the role lists, including draft documents it names, and nothing else. Your own opinions, the conversation and your reasons for the design stay out.
23
- 3. If the agent can't start a helper, run `cruze review <role> --item <ref>`, where the role is `design-reviewer`, `code-reviewer`, `verifier`, `researcher`, `auditor` or `surveyor`. Add `--base <commit>` for the code under review. It starts the agent configured under `review:` in `.cruze/config.yaml` in a fresh context and prints the role's report. When no agent is configured, or it isn't installed, it reports `status: run-in-helper` with the role's full prompt instead: start a helper, such as a subagent, and give it exactly that prompt. The configured agent can run only the commands `review.command` allows: before running the verifier, or a design reviewer whose design spells out commands to check against their `--help`, add those commands with the user's agreement. If no fresh context can run, the reviewers, the verifier and the auditor must still run fresh: tell the user, and have them run the role in a new session. The researcher may run in your own context, since its evidence is checkable; say that you did.
24
- 4. Take the report as it comes back. Check its evidence against the files before you act on any finding.
25
-
26
- ## Running a review
27
-
28
- A review has at most two rounds. Only blockers can force the second one.
29
-
30
- ### Round 1
31
-
32
- 1. Commit the documents under review (`docs: <artifact> for design review`), so the fixes in round 2 have a diff. Then run the reviewer on the complete artifact.
33
- 2. Record the round: `cruze journal add review --set review=<design|plan|code> --set round=1 --set blockers=<n> --set concerns=<n> --set nits=<n>`, with the counts from the report's last line, adding `--item <ref>` for a feature or change.
34
- 3. **Sort the findings.** A finding is an **exception**, which the user decides, when any of these holds:
35
- - Its fix changes behaviour: it adds, removes or rewrites a requirement or scenario, or changes what a person sees or does beyond what the spec says. Making the code or the plan meet a scenario as written is not a change of behaviour.
36
- - Its fix changes a port, a port's `Operations` or a public contract that the approved design names.
37
- - Its fix changes another decision the grilling skill leaves to the user: a context, dependency direction or a dependency.
38
- - You recommend anything but `fixed`: waiving, deferring or rejecting it, or a rethink because it needs a design change. A fix through a detail amendment is an exception too.
39
- - You would fix it differently from the reviewer's proposed fix.
40
-
41
- Every other finding is yours, blockers included: you fix it as the reviewer proposes. When `review.decide` in `.cruze/config.yaml` is `all`, every finding is an exception. Nits are a count, not findings: when a report lists any, they get no disposition and you don't bring them to the user.
42
- 4. **Present them in one message,** written to be read cold and illustrated as `.agents/skills/cruze-grilling/illustrating.md` says. First each exception: what goes wrong, shown as the reviewer's failure scenario played out (the interaction, the code or the diagram), what the fix changes, shown before and after, and your recommended disposition and why:
43
- - `fixed`: you will change the work as the finding proposes.
44
- - `waived`: the finding is right, but the user accepts the risk.
45
- - `deferred`: it belongs to later work. When it is future scope, add it with `cruze features add <slug> --summary <text> --goals <ids>`.
46
- - `rejected`: the finding is wrong, with the reason.
47
-
48
- A finding whose fix would change an approved element, such as one marked `Needs design change`, is never `waived`. Recommend `fixed` through a detail amendment when it qualifies, as "Detail" in `.agents/skills/cruze-rethink/levels.md` says, otherwise `rethink` at that element's level now, or `deferred` for a concern later work can carry. Once the rethink is done and the code follows it, record the finding as `fixed`. When the user wants the rethink later, record it as `rethink` instead, with `--item` naming the feature or change it amends: `cruze next` and the build gate hold that work until a rethink is recorded for it.
49
-
50
- Then one line for each finding you are fixing yourself. When there are no exceptions, say what you are fixing and carry on without waiting. The user can object to any line until the work is approved, and that finding becomes an exception: revert its fix and let them decide it.
51
- 5. **Record every disposition:** `cruze journal add disposition --set finding="<rubric item>: <summary>" --set disposition=<fixed|waived|deferred|rejected|rethink> --set reason="<reason>" --set review=<design|plan|code> --set decided=<agent|user>`, with the same `--item`. Use `decided=user` for each exception, once the user decides it, and `decided=agent` for each finding you fixed yourself. The CLI refuses `decided=agent` for anything but `fixed`. A recorded disposition is never raised again.
52
- 6. Apply every `fixed` change, then run `cruze validate`. Done when it reports no errors.
53
- 7. When a finding could be caught by a tool, such as a layering, naming or size rule, tell the user which `cruze check` rule or linter setting would catch it next time.
54
-
55
- ### Round 2
56
-
57
- Run round 2 only when a round-1 blocker was fixed. It checks only whether those blockers are fixed, and raises nothing new. You check them: in 49 recorded rounds across two projects, no reviewer re-reading a fix found a blocker still open, and the user sees every fix at the walkthrough, in the plan, or in verify's report.
58
-
59
- 1. **Check each blocker** against the diff of its fix, and run `cruze validate`. A blocker is fixed when the diff does what the proposal says and validate reports no new errors. When a fix differs from the proposal or reaches past what the finding names, say so in the message that presents it, so the user can object.
60
- 2. Record the round with `round=2`, the blockers still open, `concerns=0` and `checked_by=agent`.
61
- 3. Take any blocker still open to the user, who fixes it now, waives it or starts a rethink. There is no round 3.
62
-
63
- Done when every finding has a journaled disposition, and every exception, and every blocker left open in round 2, has the user's decision.
64
-
65
- ## The settled ledger
66
-
67
- Reviewers read the settled ledger so they never re-raise a decision. It consists of:
68
-
69
- - The `## Settled decisions` of the feature or change under review.
70
- - The `D<n>` lines in the `## Decisions` section of `docs/architecture.md`, and the accepted ADRs in `docs/adr/`.
71
- - Earlier dispositions of the item under review, from `cruze journal list --event disposition --item <ref>`. `cruze show <ref>` includes them. Never list the whole project's: two projects' reviewers read every disposition ever recorded, about 36k tokens a time, a hundred times each.
17
+ 1. **Start a fresh context:** a helper agent with no conversation history, where the agent can start one. Give it the role file's full text, the feature slug and the base commit, and nothing else: your opinions and your reasons for the code stay out.
18
+ 2. **Or let the CLI start one:** `cruze review <role> --feature <slug> --base <commit>`, where the role is `code-reviewer` or `researcher`. It runs the agent configured under `review:` in `.cruze/config.yaml` and prints the role's report. When no agent is configured, or it isn't installed, it prints `status: run-in-helper` with the full prompt instead: give exactly that prompt to a helper.
19
+ 3. **When no fresh context can run,** the code reviewer must still run fresh: tell the user, and have them run the prompt in a new session. The researcher may run in your own context, since its evidence is checkable; say that you did.
20
+ 4. **Take the report** as it comes back, and check each finding's evidence against the files before you act on it.
@@ -1,38 +1,30 @@
1
1
  # Code reviewer
2
2
 
3
- You review the code a change adds, before it lands. You work in two lanes. The spec lane asks whether the code does what the change promised, and nothing else. The architecture lane asks whether it sits where the design put it and is built the way the project's standards require. You report findings, and you edit nothing.
3
+ You review the code of one feature before it lands, in a fresh context. You ask two things: does the code do what the user approved, and will it hold up when it runs. You report findings, and you edit nothing.
4
4
 
5
5
  ## Inputs
6
6
 
7
- - The change's `change.md`, and the output of `cruze show <ref>`: the elements it builds, the scenarios it delivers, the settled decisions and the ledger. Read an element it lists as cited only when the diff calls it, with `cruze show <ID>`.
8
- - The diff under review, from `git diff <base>` for the base commit you are given. When the base is where an earlier verify stopped, review older code only where the diff changes what it does.
9
- - The ADRs in `docs/adr/`, and the specs in `docs/specs/` for the capabilities the change touches.
10
- - The references `cruze show` lists, at the sections the change's elements cite.
11
- - The settled ledger, as `.agents/skills/cruze-roles/SKILL.md` defines it, with the output of `cruze journal list --event disposition --item <ref>`.
12
- - The deviations the change recorded, from `cruze journal list --event deviation --item <ref>`.
13
- - The output of `cruze check` and `cruze trace --change <ref>`.
7
+ - The feature file in `docs/features/`: its scenarios, public API, stack sketch and decisions. This is what the user approved.
8
+ - The diff under review, from `git diff <base>` for the base commit you are given.
9
+ - `docs/architecture.md`, at the ports, runtime and layers the diff touches.
10
+ - The output of `cruze check` and `cruze trace <slug>`.
14
11
  - The standards: `.agents/skills/cruze-hexagonal-design/SKILL.md`, its language file for the project's language when one exists, `.agents/skills/cruze-behavioural-testing/SKILL.md` and `.agents/skills/cruze-dependency-approval/SKILL.md`.
15
12
 
13
+ Run the project's tests and lints, one plain command at a time, with no pipes, `&&`, `;` or redirects: an agent's allowed commands match only a plain command. When a command is refused, say so in your report.
14
+
16
15
  ## Rubric
17
16
 
18
17
  Review against these items and nothing else. Each finding names one.
19
18
 
20
- ### Spec lane
21
-
22
- 1. **Scenarios.** Every scenario the change delivers is implemented, and has a test that carries its ID, drives the seam the test plan names, and takes its expected values from the scenario.
23
- 2. **Failures.** Each failure scenario produces the error it specifies and leaves the state it specifies. Wire formats, codes and behaviour that a reference governs follow the section the design cites.
24
- 3. **Scope.** The code adds no behaviour the change's scope doesn't deliver, and no public item, variant or operation that only a later change uses. Unrequested or early code is a finding, even when it looks useful or the next change needs it.
25
- 4. **Protected tests.** No behaviour, contract or smoke test for an approved scenario, port or flow was weakened, skipped or deleted without a delta that changes its subject.
26
-
27
- ### Architecture lane
28
-
29
- 5. **Placement.** Every file the diff adds or changes is where the architecture puts its owner, and matches the task's file targets or a recorded deviation.
30
- 6. **Direction.** Dependencies point inward. No technology type crosses a port. Inbound adapters hold no domain rules or workflow.
31
- 7. **Size.** No file holds two responsibilities, and none passes its budget without a recorded exception. No file was split by length alone, leaving one responsibility across files, and no code is bent to fit a budget, such as a type alias, a string where an error type belongs, types merged or a function placed away from its owner to stay under a limit.
32
- 8. **Idiom.** The code is idiomatic for the language, uses its standard tooling, and follows the language file's rules, including where tests live. Tests reuse the fixtures and harnesses in the test support module rather than redefining them. Each `expect`, `unwrap` or panic in the diff has a reason its case can't happen; one a caller, the clock or a concurrent call can reach is a finding.
33
- 9. **Libraries.** Nothing hand-writes what a mature library does without a recorded `build` decision, and every new dependency has a recorded approval. No code works around a dependency or a feature: hand-written code, a shell command or a less idiomatic construct chosen because the clean one needs a dependency is a finding.
34
- 10. **Contracts.** Each adapter honours its port's `Operations`, and each fake passes the same contract tests as the real adapter.
35
- 11. **Deviations.** Each deviation the change recorded is a choice build may make on its own: a private helper or a new file inside the owner's module, a `check.exceptions` entry, a fixture in the test support module, or two tasks swapped. A deviation that added an element, port operation or scenario, wrote a file outside the owner's module, changed an approved scenario's behaviour or its test, worked around a dependency or a feature, or settled a limit, timeout, message or error case the design doesn't give, needed a design amendment: a blocker, with `Needs design change` naming the element.
19
+ 1. **Scenarios.** Every scenario is implemented and has a test that carries its ID, drives a public seam, and takes its expected values from the scenario. Each failure scenario produces the message and leaves the state it specifies.
20
+ 2. **Public API.** What the code exposes matches the feature's public API section: names, types, errors, commands and output. Anything public it doesn't list is a finding.
21
+ 3. **Runtime.** Follow each request, message and event from its source to its consumer through every task, channel and queue. Look for what tests rarely reach: a hang, a spin, a leak of a task, handle or memory, a race, unbounded growth, a full queue holding up unrelated work, a lost result across a reconnect, shutdown that waits forever or drops work it promised to finish.
22
+ 4. **Failures.** Each external call's failure is handled as the feature and the architecture say: disks, networks, peers and user mistakes. Nothing is silently swallowed.
23
+ 5. **Ports and adapters.** Dependencies point inward and match the layers. No technology type crosses a port. Inbound adapters hold no domain rules. Each fake passes the same contract tests as its real adapter.
24
+ 6. **Tests.** No test was weakened, skipped or deleted. Tests drive behaviour through public interfaces rather than restating what a fake was told.
25
+ 7. **Idiom.** The code is idiomatic for the language and follows its language file. Each `expect`, `unwrap` or panic has a reason its case can't happen.
26
+ 8. **Libraries.** Nothing hand-writes what a mature library does, and every significant dependency is in the architecture or approved.
27
+ 9. **Documents.** The feature's public API and stack sketch, and `docs/architecture.md` where the diff touches it, match the code: a port, operation, type, flag or claim the documents state that the code doesn't bear out, or the reverse.
36
28
 
37
29
  ## Findings
38
30
 
@@ -42,17 +34,15 @@ Each finding has this shape:
42
34
  ### <n>. <rubric item>: <one-line summary>
43
35
  - Severity: blocker | concern
44
36
  - Evidence: <path:line, quoting the code>
45
- - Failure scenario: <what goes wrong, concretely, when this runs>
37
+ - Failure scenario: <who meets it, how, and what goes wrong>
46
38
  - Proposed fix: <the specific change>
47
- - Needs design change: <the approved element whose text the fix must change, such as a port's `Operations`, or `no`>
39
+ - Changes what the user approved: <the scenario or public API the fix changes, or no>
48
40
  ```
49
41
 
50
- - A **blocker** means a scenario fails or is untested, a protected test was weakened, a layering rule is broken, an unapproved dependency was added, or an adapter can't honour its port's `Operations`. A failure is also a blocker when a user or client the design serves reaches it in ordinary use, their mistakes and failing disks, networks and peers included, and it loses or corrupts data, crashes, hangs, spins, or holds up someone else's work.
51
- - Everything else is a **concern**, even when its fix needs a design change, such as a failure only hand-made input reaches that harms only its sender: in one change, such cases were the only blockers of two verifies in a row. Say who reaches the failure, and how.
52
- - List every blocker. List at most 5 concerns, or one per 5 tasks of the change when that is more, the most important first. Count the rest as nits: give only their number, never their text. Report only what would go wrong: no concerns is a valid report, and a small change usually has few.
53
- - Drop any finding that contradicts the settled ledger. The only exception is a blocker with new evidence, which you mark `New evidence:` and explain.
54
- - When a finding could be caught mechanically, add `Check: <the cruze check rule or linter setting that would catch it>`.
42
+ - A **blocker** is a scenario that fails or has no test, a public API that differs from the approved one, a broken layer rule, or a failure that someone using the product in an ordinary way reaches and that loses or corrupts data, crashes, hangs, spins, or holds up other work.
43
+ - Everything else is a **concern**. Say who reaches it and how. A failure that only deliberately malformed input reaches, and that harms only its sender, is a concern.
44
+ - List every blocker, and at most 5 concerns, the most important first. Count the rest as nits by number only. No findings is a valid report.
55
45
 
56
46
  ## Report
57
47
 
58
- Report the spec lane, then the architecture lane. End with one line: `Blockers: <n>. Concerns: <n>. Nits: <n>.` When a lane has no findings, give the evidence for its most important item.
48
+ List the findings, then end with one line: `Blockers: <n>. Concerns: <n>. Nits: <n>.`
@@ -1,10 +1,10 @@
1
1
  # Researcher
2
2
 
3
- You find out whether mature libraries already provide the components a design needs, and you answer technical questions from primary sources. You report what you found, and you edit nothing in the project.
3
+ You find out whether mature libraries already provide the components the architecture needs, and you answer technical questions from primary sources. You report what you found, and you edit nothing in the project.
4
4
 
5
5
  ## Inputs
6
6
 
7
- - The components to research. For each: the capability in one line, the requirements that matter, and the module that would own it.
7
+ - The components to research. For each: the capability in one line, and the requirements that matter.
8
8
  - Or a question, with the version it applies to.
9
9
  - The constraints section of `docs/vision.md`.
10
10
  - The project's dependency manifests and lockfiles, if they exist.
@@ -25,7 +25,7 @@ For components, report one block each:
25
25
  | <component> | adopt or build | <package and version, when adopting> | <the deciding reason> |
26
26
 
27
27
  Evidence: <the evaluation table for the serious candidates, with sources and the date checked>
28
- New dependency: yes or no
28
+ New dependency: no, yes, or significant with the reason
29
29
  Claims to verify: <each feature, flag or command the design would rely on, with where the source shows it>
30
30
  ```
31
31
 
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: cruze-shape
3
+ description: Shapes one feature with the user before it is built, writing its behaviour as scenarios, its public API as code and a sketch of how it crosses the stack, and ends with the user's approval.
4
+ ---
5
+
6
+ # Shape
7
+
8
+ Shape is where the user decides what a feature does and what it looks like from outside, before any code exists. It produces one document, `docs/features/<slug>.md`, and one approval. Everything the user would otherwise discover at the end, such as an internal type they wouldn't have chosen or a thread they didn't expect, is shown here instead.
9
+
10
+ Read `.agents/skills/cruze-asking/SKILL.md` and `.agents/skills/cruze-formats/SKILL.md`, and `.agents/skills/cruze-hexagonal-design/SKILL.md` with its language file.
11
+
12
+ ## Steps
13
+
14
+ 1. **Find the feature.** Run `cruze next`, or take the slug the user names. Read its row in the vision's Release table, `docs/architecture.md`, and the feature files of what it needs. Work on a branch named for the feature. Done when you know what the feature is for and what it builds on.
15
+ 2. **Start the document** with `cruze new feature <slug> --title "<title>"`, unless it exists.
16
+ 3. **Write the behaviour.** For the feature's intent, write the scenarios: the main case first, then each edge and each failure a user can meet, with concrete values. Each one is a Given, a When and a Then, in the user's words, with the exact message or output they see. Invent the edge cases a user would hit: empty input, a duplicate, the thing not there, the network gone, the limit reached.
17
+ 4. **Write the public API** as real code in the project's language: every public type, function, command, endpoint, message or file format this feature adds or changes, with its errors. For a command-line tool, the commands and their exact output. Write "No change." when the feature has none.
18
+ 5. **Sketch the stack.** A plain-text diagram of the main scenario crossing the stack: the inbound adapter, the use case, the domain, each port and the adapter behind it, marking what is new. Below it, one line per change to `docs/architecture.md`, such as a new port or a new runtime task, and make those changes there. Name any value the system's own components pass each other untyped or encoded, such as a JSON value, and any new thread, task or queue.
19
+ 6. **Check it yourself** against [self-check.md](self-check.md), and fix what it finds. Done when every item passes.
20
+ 7. **Ask what only the user can answer,** in at most one round, as the asking skill says. Write the answers in.
21
+ 8. **Show it.** In one message:
22
+ - what the feature does, in two sentences;
23
+ - each scenario in one line, as the user would see it;
24
+ - the public API as code;
25
+ - the stack sketch;
26
+ - the decisions you took, one line each.
27
+
28
+ End with: "Do you approve this feature, or what should change?" Apply changes, and say what moved. Done when the user approves.
29
+ 9. **Approve and commit.** Run `cruze approve <slug>`, then commit the feature file and any architecture change with a message such as `docs: shape <slug>`.
30
+
31
+ ## Changing an approved feature
32
+
33
+ Shape also runs when build finds that a scenario or the public API must change. Edit the document, show the user exactly what changed, with the before and after as code or output, and approve again. `cruze status` shows the feature as edited until then.
34
+
35
+ ## Next step
36
+
37
+ `build`, for the approved feature.
@@ -0,0 +1,12 @@
1
+ # Self-check before showing a feature
2
+
3
+ Read the feature as an implementer who never saw the conversation. Each "no" is a gap build would fill with a guess; fix it in the document.
4
+
5
+ 1. **Every failure has a scenario.** For each external call the feature makes, and each input a user gives, the scenarios say what the user sees when it fails: the message, the exit code or the screen, and what state is left behind.
6
+ 2. **Every number is written down.** Each timeout, limit, buffer size, retry count and poll interval the feature depends on has a value, in the scenario or the architecture's runtime.
7
+ 3. **Every queue says what happens when it is full.** For each channel, buffer or queue the feature adds: what a sender does when it is full, and which other work waits meanwhile. One slow peer holds up only its own work unless a decision says otherwise.
8
+ 4. **Shutdown and recovery are covered.** What happens to work in flight when the process stops, a connection drops, or a dependency comes back.
9
+ 5. **The public API is complete.** Every error a caller can meet is named in the code sketch. Nothing public exists only for a later feature.
10
+ 6. **The ports stay ports.** No technology type, such as a database row, an HTTP request or a JSON value, crosses into the domain or the use cases.
11
+ 7. **Nothing is built ahead of need.** Every type, field and operation in the sketch is used by one of this feature's scenarios. A future feature leaves room; it adds nothing now.
12
+ 8. **Each scenario can be tested** through a public interface, with the values it states.
@@ -34,36 +34,9 @@ export interface Options {
34
34
  text: boolean;
35
35
  title?: string;
36
36
  feature?: string;
37
- roadmap?: string;
38
- change?: string;
39
- commit?: string;
40
- summary?: string;
41
- goals?: string;
42
- reason?: string;
43
- set: string[];
44
- item?: string;
45
- event?: string;
46
- out?: string;
47
- redact: boolean;
48
- all: boolean;
49
- file: string[];
50
37
  ci: boolean;
51
- gate?: string;
52
- override?: string;
53
- overlap: boolean;
54
- full: boolean;
55
- replan: string[];
56
- rebase: string[];
57
- byAgent: boolean;
58
- restampUnchanged: boolean;
59
- index: boolean;
60
- notes: boolean;
61
- kind?: string;
62
- about?: string;
63
- round?: string;
64
38
  package?: string;
65
39
  base?: string;
66
- blockers?: string;
67
40
  }
68
41
 
69
42
  export type Handler = (context: CliContext, args: string[], options: Options) => Promise<CommandResult>;
@@ -1,32 +1,19 @@
1
1
  import { posix } from "node:path";
2
2
  import { checkCode, traceTests } from "../../../../app/use_cases/check_code.ts";
3
- import { landChange } from "../../../../app/use_cases/land_change.ts";
4
3
  import type { CliContext, CommandResult, Options } from "../cli_context.ts";
5
4
 
6
5
  export async function runCheck(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
7
- const files = [...options.file, ...args].map((file) => posix.normalize(posix.join(context.workingDirectory, file)));
6
+ const files = args.map((file) => posix.normalize(posix.join(context.workingDirectory, file)));
8
7
  const report = await checkCode(context, { ci: options.ci, ...(files.length === 0 ? {} : { files }) });
9
- const lines = report.findings.map((f) => `${f.severity} ${f.path}${f.line === undefined ? "" : `:${f.line}`} ${f.message} [${f.rule}]${f.pending === true ? " (pending realign)" : ""}`);
8
+ const lines = report.findings.map((f) => `${f.severity} ${f.path}${f.line === undefined ? "" : `:${f.line}`} ${f.message} [${f.rule}]`);
10
9
  lines.push(`Checked ${report.checked} file(s): ${report.passed ? "passed" : "failed"}.`);
11
10
  return { json: report, human: lines.join("\n"), failed: !report.passed };
12
11
  }
13
12
 
14
- export async function runTrace(context: CliContext, _args: string[], options: Options): Promise<CommandResult> {
15
- const report = await traceTests(context, { all: options.all, ...(options.change === undefined ? {} : { change: options.change }) });
13
+ export async function runTrace(context: CliContext, args: string[]): Promise<CommandResult> {
14
+ const report = await traceTests(context, args[0]);
16
15
  const lines = report.missing.map((id) => `missing test for ${id}`);
17
- lines.push(...report.unknown.map((u) => `${u.path}:${u.line} cites ${u.id}, which no spec or delta defines`));
16
+ lines.push(...report.unknown.map((u) => `${u.path}:${u.line} cites ${u.id}, which no feature defines`));
18
17
  lines.push(`Traced ${report.scenarios.length} scenario(s) for ${report.scope}: ${report.passed ? "passed" : "failed"}.`);
19
18
  return { json: report, human: lines.join("\n"), failed: !report.passed };
20
19
  }
21
-
22
- export async function runLand(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
23
- const report = await landChange(context, args[0], options.override === undefined ? {} : { override: options.override });
24
- const lines = [`Landed ${report.change}.`];
25
- if (report.merged.length > 0) lines.push(`Merged into the living docs: ${report.merged.join(", ")}`);
26
- if (report.built.length > 0) lines.push(`Now built: ${report.built.join(", ")}`);
27
- if (report.removed.length > 0) lines.push(`Removed: ${report.removed.join(", ")}`);
28
- if (report.restamped.length > 0) lines.push(`Re-stamped approvals: ${report.restamped.join(", ")}`);
29
- if (report.unexcepted.length > 0) lines.push(`CI checks these again, now that the change realign scheduled them in has landed: ${report.unexcepted.join(", ")}`);
30
- if (report.archivedTo !== undefined) lines.push(`Finished; archived to ${report.archivedTo}.`);
31
- return { json: report, human: lines.join("\n") };
32
- }
@@ -1,9 +1,8 @@
1
- import { approveArtifact } from "../../../../app/use_cases/approve_artifact.ts";
2
- import { PROJECT_DOC_KINDS, createNote, createProjectDoc, type ProjectDocKind } from "../../../../app/use_cases/new_project_doc.ts";
3
- import { createWorkItem, type NewKind } from "../../../../app/use_cases/new_work_item.ts";
1
+ import { approveDocument } from "../../../../app/use_cases/approve_document.ts";
2
+ import { DOCUMENT_KINDS, createDocument, type DocumentKind } from "../../../../app/use_cases/new_document.ts";
4
3
  import { validate } from "../../../../app/use_cases/validate_project.ts";
5
4
  import type { Problem } from "../../../../domain/validation/problem.ts";
6
- import { UsageError, requireArgs, requireOption, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
5
+ import { UsageError, requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
7
6
 
8
7
  export async function runValidate(context: CliContext): Promise<CommandResult> {
9
8
  const report = await validate(context);
@@ -11,44 +10,19 @@ export async function runValidate(context: CliContext): Promise<CommandResult> {
11
10
  return { json: report, human: [...report.problems.map(formatProblem), summary].join("\n"), failed: !report.valid };
12
11
  }
13
12
 
14
- export async function runApprove(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
13
+ export async function runApprove(context: CliContext, args: string[]): Promise<CommandResult> {
15
14
  requireArgs(args, ["document"]);
16
- if (options.byAgent && options.restampUnchanged) throw new UsageError("--by-agent and --restamp-unchanged are alternatives");
17
- const agent = options.byAgent ? "plan-review" : options.restampUnchanged ? "rethink" : undefined;
18
- const report = await approveArtifact(context, args[0] ?? "", { replan: options.replan, rebase: options.rebase, ...(agent === undefined ? {} : { agent }) });
19
- const lines = [`Approved ${report.artifact} (${report.hash.slice(0, 19)}), pinned to ${report.upstream.length} upstream element(s).`];
20
- if (report.basis === "plan-review") lines.push("Approved for the user: its plan review closed with no blocker open.");
21
- if (report.restamped !== undefined) lines.push(`Re-stamped for the user: its own design is unchanged, and only ${report.restamped.join(", ")} changed.`);
22
- if (report.stamped.length > 0) lines.push(`Marked ${report.stamped.length} element(s) planned.`);
23
- if (report.bound !== undefined) lines.push(`Bound the change to branch ${report.bound}.`);
24
- if (report.replanned.length > 0) lines.push(`Set back to planned: ${report.replanned.join(", ")}.`);
25
- if (report.rebased.length > 0) lines.push(`Accepted the current living text of: ${report.rebased.join(", ")}.`);
26
- return { json: report, human: lines.join("\n") };
15
+ const record = await approveDocument(context, args[0] ?? "");
16
+ return { json: record, human: `Approved ${record.path} (${record.hash.slice(0, 19)}).` };
27
17
  }
28
18
 
29
19
  export async function runNew(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
30
20
  requireArgs(args, ["kind"]);
31
- if (PROJECT_DOC_KINDS.includes(args[0] as ProjectDocKind)) {
32
- const report = await createProjectDoc(context, args[0] as ProjectDocKind);
33
- return { json: report, human: `Created ${report.path}` };
34
- }
35
- requireArgs(args, ["kind", "slug"]);
36
- if (args[0] === "note") {
37
- const report = await createNote(context, args[1] ?? "", requireOption(options.title, "--title"), requireOption(options.kind, "--kind"), requireOption(options.about, "--about"));
38
- return { json: report, human: `Created ${report.path}` };
39
- }
40
- const kind = args[0] as NewKind;
41
- if (!["feature", "change", "adr"].includes(kind)) {
42
- throw new UsageError(`cruze new takes ${PROJECT_DOC_KINDS.join(", ")}, feature, change, adr or note, not "${args[0]}"`);
43
- }
44
- const report = await createWorkItem(context, {
45
- kind,
46
- slug: args[1] ?? "",
47
- title: requireOption(options.title, "--title"),
48
- ...(options.feature === undefined ? {} : { feature: options.feature }),
49
- ...(options.roadmap === undefined ? {} : { roadmap: options.roadmap }),
50
- });
51
- return { json: report, human: `Created ${report.kind} ${report.ref} at ${report.path}` };
21
+ const kind = args[0] as DocumentKind;
22
+ if (!DOCUMENT_KINDS.includes(kind)) throw new UsageError(`cruze new takes ${DOCUMENT_KINDS.join(", ")}, not "${args[0]}"`);
23
+ if (kind === "feature") requireArgs(args, ["kind", "slug"]);
24
+ const report = await createDocument(context, kind, args[1], options.title);
25
+ return { json: report, human: `Created ${report.path}` };
52
26
  }
53
27
 
54
28
  export function formatProblem(problem: Problem): string {
@@ -18,6 +18,6 @@ export async function runInit(context: CliContext, _args: string[], options: Opt
18
18
  if (report.created.length > 0) lines.push(`Created: ${report.created.join(", ")}`);
19
19
  if (report.skipped.length > 0) lines.push(`Left untouched (already present): ${report.skipped.join(", ")}`);
20
20
  lines.push(...describeSkillInstall(report.skills));
21
- lines.push("Next: open your coding agent in this repository and ask it what Cruze can do.");
21
+ lines.push("Next: open your coding agent in this repository and ask it to envision the project, with whatever you have: a sentence, a design document, notes.");
22
22
  return { json: report, human: lines.join("\n") };
23
23
  }
@@ -15,5 +15,6 @@ export function describeSkillInstall(report: InstallSkillsReport): string[] {
15
15
  if (from !== to) lines.push(`Recorded Cruze ${to} in .cruze/config.yaml${from === undefined ? "" : `, up from ${from}`}`);
16
16
  if (ci.repinned.length > 0) lines.push(`CI runs ${ci.repinned.join(", ")}`);
17
17
  for (const spec of ci.unrecognised) lines.push(`CI runs ${spec}, which Cruze can't move to ${to}; update .github/workflows/ci.yml yourself`);
18
+ for (const note of report.notes) lines.push(`Note: ${note}`);
18
19
  return lines;
19
20
  }
@@ -1,18 +1,11 @@
1
1
  import { runReview } from "../../../../app/use_cases/run_review.ts";
2
- import { readArgumentFile } from "../argument_files.ts";
3
- import { UsageError, requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
2
+ import { requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
4
3
 
5
4
  export async function runReviewCommand(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
6
5
  requireArgs(args, ["role"]);
7
- const round = options.round === undefined ? undefined : Number(options.round);
8
- if (round !== undefined && round !== 1 && round !== 2) throw new UsageError("--round is 1 or 2");
9
- if (options.blockers !== undefined && round !== 2) throw new UsageError("--blockers goes with --round 2");
10
- const blockers = options.blockers === undefined ? undefined : await readArgumentFile(options.blockers);
11
6
  const report = await runReview(context, {
12
7
  role: args[0] ?? "",
13
- ...(options.item === undefined ? {} : { item: options.item }),
14
- ...(round === undefined ? {} : { round }),
15
- ...(blockers === undefined ? {} : { blockers }),
8
+ ...(options.feature === undefined ? {} : { item: options.feature }),
16
9
  ...(options.base === undefined ? {} : { base: options.base }),
17
10
  });
18
11
  return { json: report, human: report.status === "reported" ? report.report : `${report.instruction}\n\n${report.prompt}` };
@@ -1,71 +1,24 @@
1
- import { checkBuildGate, findOverlaps, showStatus, suggestNext } from "../../../../app/use_cases/project_status.ts";
2
- import type { ApprovalStatus } from "../../../../domain/approvals/evaluate.ts";
3
- import { UsageError, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
1
+ import { showStatus, suggestNext } from "../../../../app/use_cases/project_status.ts";
2
+ import type { NextStep } from "../../../../domain/next_step.ts";
3
+ import type { CliContext, CommandResult } from "../cli_context.ts";
4
4
 
5
- export async function runStatus(context: CliContext, _args: string[], options: Options): Promise<CommandResult> {
6
- if (options.override !== undefined && options.gate === undefined) throw new UsageError("--override goes with --gate build");
7
- if (options.change !== undefined && !options.overlap) throw new UsageError("--change goes with --overlap");
8
- if (options.gate !== undefined && options.overlap) throw new UsageError("--gate and --overlap are alternatives");
9
- if (options.gate !== undefined) {
10
- if (options.gate !== "build") throw new UsageError(`unknown gate "${options.gate}"; the only gate is build`);
11
- const report = await checkBuildGate(context, options.override);
12
- const human = report.passed
13
- ? report.overridden ? `Build gate overridden and journaled:\n ${report.reasons.join("\n ")}` : "Build gate passed."
14
- : `Build gate blocked:\n ${report.reasons.join("\n ")}`;
15
- return { json: report, human, failed: !report.passed };
16
- }
17
- if (options.overlap) {
18
- const report = await findOverlaps(context, options.change);
19
- const human = report.overlaps.length === 0
20
- ? `No other branch touches what ${report.change} touches.`
21
- : report.overlaps.map((o) => `${o.branch}: ${o.item} also touches ${o.shared.join(", ")}`).join("\n");
22
- return { json: report, human };
23
- }
5
+ export async function runStatus(context: CliContext): Promise<CommandResult> {
24
6
  const report = await showStatus(context);
25
- const lines = [`Branch: ${report.branch ?? "(none)"}${report.active === undefined ? "" : `, building ${report.active}`}`];
26
- for (const doc of report.documents) lines.push(describe(doc.artifact, doc));
27
- for (const feature of report.features) {
28
- lines.push(`${describe(`feature ${feature.ref}`, feature.approval)}${pendingNote(feature.rethinkPending)}`);
29
- for (const change of feature.changes) {
30
- const name = change.ref.split("/")[1] ?? change.ref;
31
- lines.push(change.landed !== undefined ? ` ${name}: landed ${change.landed}` : ` ${describe(name, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
32
- }
7
+ const lines = report.documents.map((d) => `${d.path}: ${d.state}`);
8
+ for (const f of report.features) {
9
+ const needs = f.needs.length === 0 ? "" : `, needs ${f.needs.join(", ")}`;
10
+ const approval = f.approval === "missing" ? "" : `, ${f.approval}`;
11
+ lines.push(`${f.slug}: ${f.status}${approval}${f.scenarios === 0 ? "" : `, ${f.scenarios} scenario(s)`}${needs}${f.inRelease ? "" : " (not in the release)"}`);
33
12
  }
34
- for (const change of report.standalone) lines.push(`${describe(`change ${change.ref}`, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
35
- const json = {
36
- ...report,
37
- documents: report.documents.map(compact),
38
- features: report.features.map((f) => ({ ...f, approval: compact(f.approval), changes: f.changes.map((c) => ({ ...c, approval: compact(c.approval) })) })),
39
- standalone: report.standalone.map((c) => ({ ...c, approval: compact(c.approval) })),
40
- };
41
- return { json, human: lines.join("\n") };
42
- }
43
-
44
- /** The state without the record's hashes: an agent reads status often, and the hashes were a third of each read. */
45
- function compact(status: ApprovalStatus): Omit<ApprovalStatus, "record"> & { approvedAt?: string; by?: string; basis?: string } {
46
- const { record, ...rest } = status;
47
- if (record === undefined) return rest;
48
- return { ...rest, approvedAt: record.approvedAt, by: record.by, ...(record.basis === undefined ? {} : { basis: record.basis }) };
49
- }
50
-
51
- function pendingNote(findings: string[] | undefined): string {
52
- return findings === undefined ? "" : `, ${findings.length} finding(s) waiting on a rethink`;
13
+ lines.push(`Next: ${describe(report.next)}`);
14
+ return { json: report, human: lines.join("\n") };
53
15
  }
54
16
 
55
- /** Every step starts a new session: one session that ran plan, build, verify and land reached 745k tokens of context. */
56
- const FRESH_SESSION = "Run it in a new session, so its context starts empty.";
57
-
58
- const BASIS: Record<string, string> = { "plan-review": " (by the agent, after its plan review)", rethink: " (re-stamped by the agent after a rethink)" };
59
-
60
- function describe(label: string, status: ApprovalStatus): string {
61
- const byAgent = status.state === "approved" ? BASIS[status.record?.basis ?? ""] ?? "" : "";
62
- const detail = status.changed.length > 0 ? ` (${status.changed.join(", ")})` : status.unjournaled === true ? " (no journal entry)" : byAgent;
63
- return `${label}: ${status.state}${detail}`;
17
+ export async function runNext(context: CliContext): Promise<CommandResult> {
18
+ const next = await suggestNext(context);
19
+ return { json: next, human: `Next: ${describe(next)}` };
64
20
  }
65
21
 
66
- export async function runNext(context: CliContext): Promise<CommandResult> {
67
- const report = await suggestNext(context);
68
- const describe = (s: { step: string; target?: string; reason: string }): string => `${s.step}${s.target === undefined ? "" : ` ${s.target}`}: ${s.reason}`;
69
- const lines = [`Next: ${describe(report.next)}`, ...report.also.map((s) => `Also: ${describe(s)}`), FRESH_SESSION];
70
- return { json: { ...report, session: FRESH_SESSION }, human: lines.join("\n") };
22
+ function describe(step: NextStep): string {
23
+ return `${step.step}${step.target === undefined ? "" : ` ${step.target}`}: ${step.reason}`;
71
24
  }