@printpractical/cruze 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +167 -0
  3. package/bin/cruze.mjs +17 -0
  4. package/dist/adapters/inbound/cli/cli_context.js +75 -0
  5. package/dist/adapters/inbound/cli/commands/code.js +30 -0
  6. package/dist/adapters/inbound/cli/commands/documents.js +52 -0
  7. package/dist/adapters/inbound/cli/commands/init.js +23 -0
  8. package/dist/adapters/inbound/cli/commands/install.js +15 -0
  9. package/dist/adapters/inbound/cli/commands/journal.js +31 -0
  10. package/dist/adapters/inbound/cli/commands/progress.js +51 -0
  11. package/dist/adapters/inbound/cli/commands/review.js +18 -0
  12. package/dist/adapters/inbound/cli/commands/status.js +45 -0
  13. package/dist/adapters/inbound/cli/commands.js +36 -0
  14. package/dist/adapters/inbound/cli/parse_command.js +90 -0
  15. package/dist/adapters/inbound/cli/run_cli.js +50 -0
  16. package/dist/adapters/outbound/git_repository.js +57 -0
  17. package/dist/adapters/outbound/node_project_files.js +101 -0
  18. package/dist/adapters/outbound/package_bundle.js +56 -0
  19. package/dist/adapters/outbound/process_agent_runner.js +26 -0
  20. package/dist/adapters/outbound/system_clock.js +14 -0
  21. package/dist/adapters/outbound/terminal_prompter.js +22 -0
  22. package/dist/app/ports/agent_runner.js +11 -0
  23. package/dist/app/ports/bundle.js +22 -0
  24. package/dist/app/ports/clock.js +6 -0
  25. package/dist/app/ports/project_files.js +20 -0
  26. package/dist/app/ports/prompter.js +5 -0
  27. package/dist/app/ports/repository.js +13 -0
  28. package/dist/app/project_context.js +45 -0
  29. package/dist/app/use_cases/abandon_work.js +42 -0
  30. package/dist/app/use_cases/approve_artifact.js +146 -0
  31. package/dist/app/use_cases/check_code.js +90 -0
  32. package/dist/app/use_cases/init_project.js +59 -0
  33. package/dist/app/use_cases/install_skills.js +93 -0
  34. package/dist/app/use_cases/journal_events.js +48 -0
  35. package/dist/app/use_cases/land_change.js +113 -0
  36. package/dist/app/use_cases/new_project_doc.js +40 -0
  37. package/dist/app/use_cases/new_work_item.js +75 -0
  38. package/dist/app/use_cases/project_status.js +73 -0
  39. package/dist/app/use_cases/record_progress.js +101 -0
  40. package/dist/app/use_cases/run_review.js +71 -0
  41. package/dist/app/use_cases/validate_project.js +22 -0
  42. package/dist/domain/agent_skill_homes.js +25 -0
  43. package/dist/domain/approvals/evaluate.js +36 -0
  44. package/dist/domain/approvals/fingerprint.js +52 -0
  45. package/dist/domain/approvals/records.js +50 -0
  46. package/dist/domain/architecture_sections.js +23 -0
  47. package/dist/domain/check/check_source.js +64 -0
  48. package/dist/domain/check/imports.js +81 -0
  49. package/dist/domain/check/rust_imports.js +84 -0
  50. package/dist/domain/check/type_count.js +17 -0
  51. package/dist/domain/config.js +128 -0
  52. package/dist/domain/cruze_error.js +10 -0
  53. package/dist/domain/edits/agents_file.js +44 -0
  54. package/dist/domain/edits/managed_tables.js +60 -0
  55. package/dist/domain/edits/progress_block.js +33 -0
  56. package/dist/domain/edits/status_lines.js +52 -0
  57. package/dist/domain/elements.js +126 -0
  58. package/dist/domain/glob.js +46 -0
  59. package/dist/domain/hashing.js +52 -0
  60. package/dist/domain/ids.js +37 -0
  61. package/dist/domain/journal.js +62 -0
  62. package/dist/domain/land/bookkeeping.js +54 -0
  63. package/dist/domain/land/merge_plan.js +132 -0
  64. package/dist/domain/land/text_ops.js +66 -0
  65. package/dist/domain/markdown.js +79 -0
  66. package/dist/domain/markdown_tables.js +34 -0
  67. package/dist/domain/project/artifact_ref.js +42 -0
  68. package/dist/domain/project/deltas.js +49 -0
  69. package/dist/domain/project/layout.js +40 -0
  70. package/dist/domain/project/living_model.js +54 -0
  71. package/dist/domain/project/new_items.js +48 -0
  72. package/dist/domain/project/plan_parts.js +111 -0
  73. package/dist/domain/project/progress.js +43 -0
  74. package/dist/domain/project/project_view.js +72 -0
  75. package/dist/domain/project/roadmap.js +43 -0
  76. package/dist/domain/project/work_items.js +68 -0
  77. package/dist/domain/project_name.js +20 -0
  78. package/dist/domain/scaffold.js +29 -0
  79. package/dist/domain/skill.js +106 -0
  80. package/dist/domain/skill_links.js +103 -0
  81. package/dist/domain/status/next_step.js +119 -0
  82. package/dist/domain/status/verification.js +16 -0
  83. package/dist/domain/status/work_status.js +101 -0
  84. package/dist/domain/trace.js +44 -0
  85. package/dist/domain/validation/delta_rules.js +79 -0
  86. package/dist/domain/validation/element_rules.js +99 -0
  87. package/dist/domain/validation/living_rules.js +97 -0
  88. package/dist/domain/validation/plan_rules.js +105 -0
  89. package/dist/domain/validation/problem.js +21 -0
  90. package/dist/domain/validation/project_rules.js +99 -0
  91. package/dist/domain/validation/validate_project.js +31 -0
  92. package/dist/domain/validation/work_item_rules.js +144 -0
  93. package/dist/main.js +32 -0
  94. package/package.json +40 -0
  95. package/scripts/build.mjs +37 -0
  96. package/skills/about/SKILL.md +21 -0
  97. package/skills/architect/SKILL.md +43 -0
  98. package/skills/architect/feature.md +29 -0
  99. package/skills/architect/project.md +58 -0
  100. package/skills/architect/tweak.md +22 -0
  101. package/skills/architect/walkthrough.md +29 -0
  102. package/skills/behavioural-testing/SKILL.md +63 -0
  103. package/skills/behavioural-testing/examples.md +102 -0
  104. package/skills/behavioural-testing/fakes.md +30 -0
  105. package/skills/build/SKILL.md +62 -0
  106. package/skills/dependency-approval/SKILL.md +48 -0
  107. package/skills/domain-language/SKILL.md +37 -0
  108. package/skills/envision/SKILL.md +29 -0
  109. package/skills/envision/feature.md +22 -0
  110. package/skills/envision/project.md +20 -0
  111. package/skills/explore/SKILL.md +39 -0
  112. package/skills/formats/SKILL.md +84 -0
  113. package/skills/formats/reference/architecture.md +80 -0
  114. package/skills/formats/reference/config.md +57 -0
  115. package/skills/formats/reference/durable-docs.md +71 -0
  116. package/skills/formats/reference/specs.md +65 -0
  117. package/skills/formats/reference/work-items.md +100 -0
  118. package/skills/formats/templates/adr.md +7 -0
  119. package/skills/formats/templates/architecture.md +100 -0
  120. package/skills/formats/templates/change.md +29 -0
  121. package/skills/formats/templates/feature.md +49 -0
  122. package/skills/formats/templates/glossary.md +8 -0
  123. package/skills/formats/templates/roadmap.md +32 -0
  124. package/skills/formats/templates/spec.md +11 -0
  125. package/skills/formats/templates/standalone-change.md +46 -0
  126. package/skills/formats/templates/vision.md +37 -0
  127. package/skills/grilling/SKILL.md +66 -0
  128. package/skills/hexagonal-design/SKILL.md +119 -0
  129. package/skills/hexagonal-design/contracts.md +68 -0
  130. package/skills/hexagonal-design/fundamentals.md +50 -0
  131. package/skills/hexagonal-design/languages/cpp.md +37 -0
  132. package/skills/hexagonal-design/languages/rust.md +40 -0
  133. package/skills/hexagonal-design/runtime.md +48 -0
  134. package/skills/land/SKILL.md +43 -0
  135. package/skills/next/SKILL.md +30 -0
  136. package/skills/plan/SKILL.md +52 -0
  137. package/skills/plan/tasks.md +26 -0
  138. package/skills/plan/test-plan.md +14 -0
  139. package/skills/research/SKILL.md +41 -0
  140. package/skills/research/evaluation.md +27 -0
  141. package/skills/rethink/SKILL.md +53 -0
  142. package/skills/rethink/levels.md +45 -0
  143. package/skills/roadmap/SKILL.md +51 -0
  144. package/skills/roles/SKILL.md +57 -0
  145. package/skills/roles/code-reviewer.md +55 -0
  146. package/skills/roles/design-reviewer.md +63 -0
  147. package/skills/roles/researcher.md +33 -0
  148. package/skills/roles/verifier.md +38 -0
  149. package/skills/triage/SKILL.md +35 -0
  150. package/skills/verify/SKILL.md +39 -0
  151. package/skills/verify/manual-test.md +23 -0
  152. package/src/adapters/inbound/cli/cli_context.ts +75 -0
  153. package/src/adapters/inbound/cli/commands/code.ts +30 -0
  154. package/src/adapters/inbound/cli/commands/documents.ts +52 -0
  155. package/src/adapters/inbound/cli/commands/init.ts +23 -0
  156. package/src/adapters/inbound/cli/commands/install.ts +15 -0
  157. package/src/adapters/inbound/cli/commands/journal.ts +31 -0
  158. package/src/adapters/inbound/cli/commands/progress.ts +51 -0
  159. package/src/adapters/inbound/cli/commands/review.ts +18 -0
  160. package/src/adapters/inbound/cli/commands/status.ts +45 -0
  161. package/src/adapters/inbound/cli/commands.ts +36 -0
  162. package/src/adapters/inbound/cli/parse_command.ts +90 -0
  163. package/src/adapters/inbound/cli/run_cli.ts +50 -0
  164. package/src/adapters/outbound/git_repository.ts +57 -0
  165. package/src/adapters/outbound/node_project_files.ts +101 -0
  166. package/src/adapters/outbound/package_bundle.ts +56 -0
  167. package/src/adapters/outbound/process_agent_runner.ts +26 -0
  168. package/src/adapters/outbound/system_clock.ts +14 -0
  169. package/src/adapters/outbound/terminal_prompter.ts +22 -0
  170. package/src/app/ports/agent_runner.ts +11 -0
  171. package/src/app/ports/bundle.ts +22 -0
  172. package/src/app/ports/clock.ts +6 -0
  173. package/src/app/ports/project_files.ts +20 -0
  174. package/src/app/ports/prompter.ts +5 -0
  175. package/src/app/ports/repository.ts +13 -0
  176. package/src/app/project_context.ts +45 -0
  177. package/src/app/use_cases/abandon_work.ts +42 -0
  178. package/src/app/use_cases/approve_artifact.ts +146 -0
  179. package/src/app/use_cases/check_code.ts +90 -0
  180. package/src/app/use_cases/init_project.ts +59 -0
  181. package/src/app/use_cases/install_skills.ts +93 -0
  182. package/src/app/use_cases/journal_events.ts +48 -0
  183. package/src/app/use_cases/land_change.ts +113 -0
  184. package/src/app/use_cases/new_project_doc.ts +40 -0
  185. package/src/app/use_cases/new_work_item.ts +75 -0
  186. package/src/app/use_cases/project_status.ts +73 -0
  187. package/src/app/use_cases/record_progress.ts +101 -0
  188. package/src/app/use_cases/run_review.ts +71 -0
  189. package/src/app/use_cases/validate_project.ts +22 -0
  190. package/src/domain/agent_skill_homes.ts +25 -0
  191. package/src/domain/approvals/evaluate.ts +36 -0
  192. package/src/domain/approvals/fingerprint.ts +52 -0
  193. package/src/domain/approvals/records.ts +50 -0
  194. package/src/domain/architecture_sections.ts +23 -0
  195. package/src/domain/check/check_source.ts +64 -0
  196. package/src/domain/check/imports.ts +81 -0
  197. package/src/domain/check/rust_imports.ts +84 -0
  198. package/src/domain/check/type_count.ts +17 -0
  199. package/src/domain/config.ts +128 -0
  200. package/src/domain/cruze_error.ts +10 -0
  201. package/src/domain/edits/agents_file.ts +44 -0
  202. package/src/domain/edits/managed_tables.ts +60 -0
  203. package/src/domain/edits/progress_block.ts +33 -0
  204. package/src/domain/edits/status_lines.ts +52 -0
  205. package/src/domain/elements.ts +126 -0
  206. package/src/domain/glob.ts +46 -0
  207. package/src/domain/hashing.ts +52 -0
  208. package/src/domain/ids.ts +37 -0
  209. package/src/domain/journal.ts +62 -0
  210. package/src/domain/land/bookkeeping.ts +54 -0
  211. package/src/domain/land/merge_plan.ts +132 -0
  212. package/src/domain/land/text_ops.ts +66 -0
  213. package/src/domain/markdown.ts +79 -0
  214. package/src/domain/markdown_tables.ts +34 -0
  215. package/src/domain/project/artifact_ref.ts +42 -0
  216. package/src/domain/project/deltas.ts +49 -0
  217. package/src/domain/project/layout.ts +40 -0
  218. package/src/domain/project/living_model.ts +54 -0
  219. package/src/domain/project/new_items.ts +48 -0
  220. package/src/domain/project/plan_parts.ts +111 -0
  221. package/src/domain/project/progress.ts +43 -0
  222. package/src/domain/project/project_view.ts +72 -0
  223. package/src/domain/project/roadmap.ts +43 -0
  224. package/src/domain/project/work_items.ts +68 -0
  225. package/src/domain/project_name.ts +20 -0
  226. package/src/domain/scaffold.ts +29 -0
  227. package/src/domain/skill.ts +106 -0
  228. package/src/domain/skill_links.ts +103 -0
  229. package/src/domain/status/next_step.ts +119 -0
  230. package/src/domain/status/verification.ts +16 -0
  231. package/src/domain/status/work_status.ts +101 -0
  232. package/src/domain/trace.ts +44 -0
  233. package/src/domain/validation/delta_rules.ts +79 -0
  234. package/src/domain/validation/element_rules.ts +99 -0
  235. package/src/domain/validation/living_rules.ts +97 -0
  236. package/src/domain/validation/plan_rules.ts +105 -0
  237. package/src/domain/validation/problem.ts +21 -0
  238. package/src/domain/validation/project_rules.ts +99 -0
  239. package/src/domain/validation/validate_project.ts +31 -0
  240. package/src/domain/validation/work_item_rules.ts +144 -0
  241. package/src/main.ts +32 -0
  242. package/templates/init/AGENTS.md +28 -0
  243. package/templates/init/CHANGELOG.md +8 -0
  244. package/templates/init/CLAUDE.md +1 -0
  245. package/templates/init/README.md +1 -0
  246. package/templates/init/ci.yml +23 -0
  247. package/templates/init/config.yaml +33 -0
  248. package/templates/init/gitattributes +2 -0
@@ -0,0 +1,32 @@
1
+ # Roadmap
2
+
3
+ ## Release
4
+
5
+ <Release name>: <one sentence on what the release delivers.>
6
+
7
+ ## Phases
8
+
9
+ ### Phase 1: Walking skeleton
10
+
11
+ | Item | Kind | Goals | Blocked by |
12
+ | --- | --- | --- | --- |
13
+ | walking-skeleton | change | <GOAL IDs> | |
14
+
15
+ ### Phase 2: <name>
16
+
17
+ | Item | Kind | Goals | Blocked by |
18
+ | --- | --- | --- | --- |
19
+ | <slug> | feature | <GOAL IDs> | walking-skeleton |
20
+
21
+ ## Coverage
22
+
23
+ | Goal | Items |
24
+ | --- | --- |
25
+ | GOAL-<name> | <slugs> |
26
+
27
+ <!-- cruze:managed -->
28
+ ## Status
29
+
30
+ | Item | ID | State |
31
+ | --- | --- | --- |
32
+ <!-- /cruze:managed -->
@@ -0,0 +1,11 @@
1
+ # <Capability title>
2
+
3
+ <What this capability does, seen from outside, in one to three sentences.>
4
+
5
+ ## REQ-<capability>.<name>: <Requirement title>
6
+ <The requirement in one to three sentences using SHALL or MUST.>
7
+
8
+ ### SCN-<capability>.<name>: <Scenario title>
9
+ - GIVEN <starting state, with concrete values>
10
+ - WHEN <the one action>
11
+ - THEN <observable outcome, with concrete values>
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: {{id}}
3
+ title: {{title}}
4
+ roadmap: <roadmap item slug, when the change is on the roadmap>
5
+ ---
6
+
7
+ # Change: {{title}}
8
+
9
+ ## Intent
10
+
11
+ <Why this change, in the user's words, and what it deliberately leaves out.>
12
+
13
+ ## Adopt or build
14
+
15
+ | Component | Decision | Choice | Reason |
16
+ | --- | --- | --- | --- |
17
+
18
+ ## Spec delta
19
+
20
+ ### MODIFIED REQ-<capability>.<name>: <Requirement title>
21
+ <The full new requirement, with every scenario it keeps.>
22
+
23
+ ## Architecture delta
24
+
25
+ None.
26
+
27
+ ## Scope
28
+
29
+ - Delivers: <SCN and REQ IDs from the spec delta>
30
+ - Builds: <architecture IDs from the delta, and planned elements this change builds>
31
+
32
+ ## Test plan
33
+
34
+ | Subject | Seam | Test file | Kind |
35
+ | --- | --- | --- | --- |
36
+
37
+ ## Tasks
38
+
39
+
40
+ ## Settled decisions
41
+
42
+ - D1: <decision> (<reason>)
43
+
44
+ <!-- cruze:managed -->
45
+ ## Progress
46
+ <!-- /cruze:managed -->
@@ -0,0 +1,37 @@
1
+ # {{project_name}}
2
+
3
+ ## Problem
4
+
5
+ <The problem, in the user's words, in one short paragraph.>
6
+
7
+ ## Users
8
+
9
+ - <Who, and in what situation they use it.>
10
+
11
+ ## Goals
12
+
13
+ | ID | Goal | Measure |
14
+ | --- | --- | --- |
15
+ | GOAL-<name> | <What the product achieves for its users.> | <How you would know it's met.> |
16
+
17
+ ## Non-goals
18
+
19
+ - <What the product deliberately doesn't do, and why.>
20
+
21
+ ## Constraints
22
+
23
+ - <Platform, language, dependency, performance, security or legal limit.>
24
+
25
+ <!-- cruze:managed -->
26
+ ## Feature map
27
+
28
+ ### Implemented
29
+
30
+ | Feature | Release | Summary |
31
+ | --- | --- | --- |
32
+
33
+ ### Future
34
+
35
+ | Feature | Summary | Goals |
36
+ | --- | --- | --- |
37
+ <!-- /cruze:managed -->
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: cruze-grilling
3
+ description: How to interview the user until design decisions are settled. Questions go in rounds over a tree of decisions, facts are looked up rather than asked, each question carries a recommendation, and challenges the user overrides are recorded. Use when a design step needs decisions from the user, when shaping an idea, vision, feature, architecture or plan with them, when the user steers toward something that breaks a rule, or when the user asks to be grilled or to stress-test a plan.
4
+ ---
5
+
6
+ # Grilling
7
+
8
+ Interview the user until you both understand the design the same way. Decisions are the user's. Facts are yours to find.
9
+
10
+ ## Running the interview
11
+
12
+ 1. List the open decisions this step must settle, as a tree in which each decision hangs off the ones it depends on. Take them from the sections of the document the step writes and from what the user has already said. Done when every section the step writes has its decisions listed.
13
+ 2. Settle the facts yourself. Anything the repository, the living docs, a `cruze` command or a primary source can answer is a fact, so look it up rather than asking. Where the agent can run a helper in parallel, send it to look while you ask about everything that doesn't depend on the answer.
14
+ 3. Find the frontier: every open decision whose prerequisites are settled. A question that depends on another open question waits for a later round.
15
+ 4. Ask the frontier as one round, in the format below. Every question carries your recommended answer and the reason for it.
16
+ 5. Wait for the answers. Record each settled decision as described under Recording, then recompute the frontier.
17
+ 6. Repeat until the frontier is empty: every branch visited, and nothing silently assumed.
18
+ 7. Write the sections the step produces from the settled decisions, then summarize them and ask the user to confirm that they match their understanding. Done when the user confirms. Decisions and glossary terms are recorded as they settle, and nothing is approved before the confirmation.
19
+
20
+ ## A round
21
+
22
+ ```markdown
23
+ **Q4. Where the jump-host list lives**
24
+ Per device in the device config, or as named hosts that devices reference. Named hosts avoid repeating a host's address and credentials across devices, but add a second lookup.
25
+ Recommended: named hosts, because the lab config already shares two jump hosts across 30 devices.
26
+
27
+ **Q5. What a refused second hop reports**
28
+ ...
29
+ ```
30
+
31
+ - Number questions across the whole session, not per round, so an answer such as "Q7: yes" is never ambiguous.
32
+ - Keep a round to what the user can answer in one reply, about 3 to 7 questions. When the frontier is bigger, ask first the questions that others depend on.
33
+ - Ask about behaviour and trade-offs in the user's terms and the glossary's words, not about implementation mechanics.
34
+ - When the user answers "you decide" or "I don't know", take your recommendation and record it with "(recommended; the user deferred)".
35
+ - When an answer contradicts an earlier decision, point to that decision and ask which one stands.
36
+
37
+ ## What to ask and what to decide
38
+
39
+ Ask the user when a choice affects any of these:
40
+
41
+ - Scope: what is in and what is out.
42
+ - A public contract, including the errors a caller sees.
43
+ - The architecture: contexts, ports, dependency direction and the module map.
44
+ - A dependency, always, through `.agents/skills/cruze-dependency-approval/SKILL.md`.
45
+ - Security, privacy or compliance.
46
+ - Compatibility, stored data or migration.
47
+ - A commitment that is costly or hard to reverse.
48
+
49
+ Decide yourself anything local and reversible, such as private names, file-local structure, internal representation and equivalent idioms. Pick the conventional option without asking. Uncertainty alone doesn't make a choice the user's: investigate first, and ask only when the evidence leaves two materially different valid outcomes.
50
+
51
+ ## Challenge, then defer
52
+
53
+ When the user steers toward something that breaks a principle, an accepted ADR or a Cruze knowledge skill:
54
+
55
+ 1. Name the rule, the concrete risk in this project and a recommended alternative, once. For example: "I'd push back on reading the config inside the SSH adapter. cruze-hexagonal-design keeps adapters from calling other adapters, and here the SSH adapter would silently depend on the file format. I recommend passing the resolved hop into the adapter. Your call."
56
+ 2. The user decides, and their decision stands.
57
+ 3. Record the override. It becomes an ADR when it passes the ADR test in `.agents/skills/cruze-formats/reference/durable-docs.md`; otherwise it becomes a settled decision that names the rule and the reason: `D4: the SSH adapter reads jump-host config directly, overriding cruze-hexagonal-design's adapter rule (the user wants one file for the prototype)`.
58
+ 4. Never raise the same challenge again. Reviewers read the settled decisions and ADRs, so they won't either.
59
+
60
+ Be direct and precise, peer to peer. Challenge only with a specific reason, and never agree without thinking.
61
+
62
+ ## Recording
63
+
64
+ - Record each decision as soon as it settles, not at the end.
65
+ - The workflow step names the document. Features and changes keep decisions in `## Settled decisions` as `D<n>: <decision> (<reason>)`. At project scope, the vision keeps goals, non-goals and constraints in their own sections, and other project decisions go in the architecture's `## Decisions` as `D<n>` lines. A decision that passes the ADR test becomes an ADR.
66
+ - Put a term in the glossary the moment it settles, following `.agents/skills/cruze-domain-language/SKILL.md`.
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: cruze-hexagonal-design
3
+ description: The architecture standard for a Cruze project, covering hexagonal ports and adapters with domain-driven design, the owner of each rule, dependency direction, many small modules and composition. Use when designing or reviewing the architecture or an architecture delta, when placing a new element in the module map, when naming a port, adapter or module, when writing code that adds a type, file or import between modules, or when reviewing code for layering and structure.
4
+ ---
5
+
6
+ # Hexagonal design
7
+
8
+ The system is a hexagon. A domain and an application form the core, and adapters reach the outside world through ports. Every rule has one owner, dependencies point inward, and the module map in `docs/architecture.md` says where each owner lives. Designs, plans, code and reviews are all held to this standard.
9
+
10
+ ## Placing an owner
11
+
12
+ Follow these steps whenever a design or a task introduces behaviour, such as a rule, a workflow, a mapping or an integration.
13
+
14
+ 1. Describe one representative operation in the caller's terms before choosing any structure. Done when you can say who calls, with what, and what they get back or see fail.
15
+ 2. Search the living docs and the code for an existing owner of the same behaviour. Reuse or extend it when it is correct. Done when you can name the owner, or can say that none exists.
16
+ 3. Name the owner by what it means, in the glossary's terms. A rule or invariant goes to a domain concept (`ENT`), a workflow to a use case (`UC`), a capability the application needs to a port (`PORT`), and a technology to an adapter (`ADP`).
17
+ 4. Place it in the module map. Its `Module` names a `MOD` whose `Layer` matches its role, and its `File` names the real path. Done when every new element has both, and its module's layer may import everything the element uses.
18
+ 5. Check the direction of every new dependency against the `RULE` elements and the `layers:` in `.cruze/config.yaml`. Done when no dependency points outward.
19
+ 6. Name the tests that will prove it, following `.agents/skills/cruze-behavioural-testing/SKILL.md`. When a plausible wrong outcome exists, make sure a scenario step rules it out, such as `AND the first hop is closed`.
20
+
21
+ Stop when the behaviour and its boundaries are covered. A pure library needs no application layer or ports, so don't invent layers to complete the recipe.
22
+
23
+ ## Priorities
24
+
25
+ When two rules pull apart, the earlier one wins. Prefer the simplest design that keeps all of them, and never simplify by merging responsibilities that mean different things.
26
+
27
+ 1. Domain rules and invariants have the right owner.
28
+ 2. Use-case boundaries are explicit.
29
+ 3. Dependencies point inward.
30
+ 4. Concepts and modules are cohesive.
31
+ 5. Each behaviour has one authoritative implementation.
32
+ 6. Infrastructure and runtime resources have clear owners.
33
+ 7. The design is simple within those boundaries.
34
+ 8. Runtime cost is low where the workload makes it matter.
35
+
36
+ ## Layers
37
+
38
+ | Layer | Owns | May depend on |
39
+ | --- | --- | --- |
40
+ | `domain` | Concepts, state, rules, invariants and domain errors (`ENT`) | Domain code, the standard library, and approved libraries with no infrastructure in them, such as an error-derive crate |
41
+ | `application` | Use cases (`UC`) and the ports they define (`PORT`) | The domain |
42
+ | `adapter` | Inbound adapters that drive use cases, and outbound adapters that implement driven ports (`ADP`) | Application, domain and third-party libraries |
43
+ | `composition` | Constructing adapters, injecting them, starting the runtime | Everything |
44
+
45
+ `cruze check` enforces imports between the project's own layers. It allows every third-party import, so review checks that infrastructure libraries appear only in adapters.
46
+
47
+ Layers are dependency boundaries, not runtime hops. A port can be a plain function call. Add a task, thread, channel or process only for a concrete ownership, concurrency, isolation or backpressure need, and read [runtime.md](runtime.md) first.
48
+
49
+ ### Domain
50
+
51
+ - Identify domain logic by meaning, not complexity. A one-line rule about what the domain means still belongs in the domain.
52
+ - Model each concept with the smallest building block that fits: value object, entity, aggregate, domain service or policy, domain error, or a domain event when the event means something to the domain. Each is an `ENT` with the matching `Kind`; domain errors live with the concept that raises them.
53
+ - Prefer meaningful types over primitives when a value has identity, constraints or units, such as `DeviceName` rather than a string. Make invalid states unrepresentable where practical, and enforce each invariant in the type that owns it.
54
+ - Keep aggregates small. Data being related is not a reason to group it.
55
+ - The domain imports no transport, persistence, serialization format, framework, OS API, telemetry SDK, retry or connection handling. Pass information in rather than handing the domain an infrastructure handle.
56
+ - Domain behaviour is synchronous unless asynchrony is part of the domain itself.
57
+
58
+ ### Application
59
+
60
+ - Write one use case per independently meaningful operation, such as `OpenConsole` or `ListDevices`, not one large service.
61
+ - A use case loads state through ports, calls domain behaviour, sequences effects, decides what a partial failure means, and translates port failures into use-case failures. The workflow stays visible in that one operation instead of spreading across pass-through services.
62
+ - A domain rule stays in the domain even when only one use case uses it.
63
+ - Add command buses, query buses or CQRS machinery only for a concrete need.
64
+
65
+ ### Ports
66
+
67
+ - A driven port names a capability the application needs, not a technology: `DeviceCatalog`, `Clock` and `HopConnector`, not `TomlFile`, `TokioTimer` or `Ssh2Client`.
68
+ - The application owns each port's contract and shapes it around what the core needs, never mirroring an SDK. Read [contracts.md](contracts.md) before writing a port's `Operations`.
69
+ - A port that keeps a technology out of the core is justified with one adapter. An interface over an internal policy with one strategy is not.
70
+ - Declare a driving port only when several inbound adapters share it or the application promises a stable contract. Otherwise an inbound adapter calls the use case directly.
71
+ - Name each thing once. Never produce `Foo`, `FooPort`, `FooService` and `FooImpl` families.
72
+
73
+ ### Adapters
74
+
75
+ - Inbound adapters (CLI, HTTP, RPC, message consumers) decode input, validate it at the protocol level, map it to use-case input, call the use case and map the result back. They stay thin, with no domain rules and no workflow.
76
+ - Outbound adapters hold everything technology-specific: serialization, persistence layout, framing, retries and backoff, connections, SDK types and OS calls. They translate technology failures before those cross into the core.
77
+ - An adapter never calls an unrelated adapter to get around the application.
78
+
79
+ ### Composition
80
+
81
+ - One composition root constructs the concrete adapters and runtime resources, injects them through constructors or parameters, and starts the application.
82
+ - Domain and application code never construct an adapter. There are no service locators, hidden lookups, mutable globals or implicit runtime dependencies.
83
+
84
+ ## Many small modules
85
+
86
+ - Give each responsibility its own module, grouped by domain concept, with the hexagonal roles inside. A file may hold a few closely related types.
87
+ - When a file passes its budget (`check:` in `.cruze/config.yaml`, enforced by `cruze check`) or gains a second responsibility, split it into a submodule named for what it owns.
88
+ - Entry-point and namespace files, such as `main`, `lib.rs`, `mod.rs` and `index.ts`, hold only wiring and declarations.
89
+ - Don't create generic modules such as `utils`, `helpers`, `common`, `services`, `models`, `types` or `manager`. Shared behaviour belongs with the concept that owns it.
90
+ - Duplication is semantic. Two implementations of one rule are duplication even when the text differs, so consolidate them in the owner, not in a helper.
91
+ - Structure follows the module map, never a per-language template. Write idiomatic code for the language and use its standard tooling. [languages/rust.md](languages/rust.md) and [languages/cpp.md](languages/cpp.md) add rules for those languages.
92
+ - In an existing codebase, its established layout and naming win over these structure rules. Ownership and dependency direction still apply.
93
+
94
+ ## Representations and errors
95
+
96
+ - Keep transport, application, domain and persistence representations separate when their meaning differs. Map them explicitly at the boundary, with one owner per mapping. Don't copy a type only to have one per layer.
97
+ - Domain errors describe domain failures, application errors describe use-case failures, and adapter errors describe infrastructure failures. Translate at each boundary and never expose an SDK's error type through a port. Expected failures are values the caller handles, not crashes.
98
+
99
+ ## Warning signs
100
+
101
+ Reconsider ownership when a design or a diff shows any of these:
102
+
103
+ - An entry-point or namespace file gains behaviour.
104
+ - A module gains a second responsibility you could describe on its own.
105
+ - A handler holds a domain rule or orchestrates a workflow.
106
+ - Domain code imports infrastructure or framework types, or technology starts shaping the domain model.
107
+ - Application code constructs an adapter.
108
+ - Logic that already exists is implemented again, or a change keeps a private copy of shared behaviour.
109
+ - An interface mirrors its only implementation, or a chain of components only forwards calls.
110
+ - Commodity infrastructure is being hand-written although a mature library does it. Follow `.agents/skills/cruze-research/SKILL.md`.
111
+
112
+ These are review signals, not automatic failures. When one could be checked mechanically, propose a `cruze check` rule or a linter setting instead of repeating the finding.
113
+
114
+ ## Further reading
115
+
116
+ - [contracts.md](contracts.md): writing a port's `Operations`, a public API, an IPC protocol or a stored format.
117
+ - [runtime.md](runtime.md): concurrency, long-lived resources (connections, sessions, devices, subprocesses), state machines, cancellation or a hot path.
118
+ - [fundamentals.md](fundamentals.md): choosing a data structure, a state representation or an abstraction mechanism; defining equality or ordering; bounding loops, retries and fan-out.
119
+ - `.agents/skills/cruze-dependency-approval/SKILL.md`: before any design or code adds a dependency.
@@ -0,0 +1,68 @@
1
+ # Contracts and composition
2
+
3
+ A contract tells a caller how to use a capability correctly without reading its implementation. A signature alone is not a contract. Apply this to the seams the work touches: ports, use cases other code calls, public APIs, IPC and stored formats. Don't specify every private helper or an imagined future caller.
4
+
5
+ ## Design from the caller
6
+
7
+ 1. Name the real callers: another module, a library user, a CLI user, a plugin, a peer process, or a reader of stored data. A language's `public` keyword doesn't make something a supported API.
8
+ 2. Write a short usage example in the caller's terms: the outcome, the collaborators needed, valid inputs, and how the caller handles each result and failure.
9
+ 3. Decide what the caller must not need to know. Expose a capability, not a concrete SDK's operations or your internal data layout.
10
+ 4. State the obligations from the table below that apply, including what is deliberately left unspecified. Ask the user about any uncertain obligation that matters instead of inventing a guarantee.
11
+ 5. Show the composition: the entry point, the domain decisions, the collaborators, the effects and who owns each resource. Pick the language mechanism (trait, interface, function type) only after this.
12
+
13
+ A concrete function or type can be a fine seam. Use a port to keep a technology out of the core, even with one adapter. Don't put an interface on every internal operation, and don't turn a module into a plugin system for callers that don't exist.
14
+
15
+ ## Obligations
16
+
17
+ In a `PORT` element, each item under `Operations` gives the signature in the project's language, then the rows below that apply.
18
+
19
+ | Concern | What the caller can rely on |
20
+ | --- | --- |
21
+ | Provides and requires | Operations offered, capabilities consumed, preconditions |
22
+ | Inputs and state | Valid values, invariants, allowed call sequences, where input is trusted |
23
+ | Results and effects | What success means, when effects become visible or durable |
24
+ | Failure | Which failures the caller can tell apart, partial progress, the state left behind, whether a retry is safe |
25
+ | Ownership | What is borrowed, copied or retained, and who releases it |
26
+ | Execution | Ordering, concurrency, reentrancy, deadlines and resource limits |
27
+ | Lifecycle | Startup, cancellation, completion and shutdown duties |
28
+ | Compatibility | Source, binary, wire, stored-data or behavioural promises actually made |
29
+ | Freedom | Ordering, representation or diagnostics the caller must not assume |
30
+
31
+ Add compatibility machinery (versioning, extension points, binary stability) only for a concrete reason: existing callers, stored data, peers that upgrade independently, or an explicit requirement. Name the supported callers or versions when it matters.
32
+
33
+ A contract lives in one place: the `PORT` or `UC` element in `docs/architecture.md`, a schema, or a header. Deltas replace that element's body rather than writing a second competing definition.
34
+
35
+ ## Compose guarantees, not just types
36
+
37
+ Suppose an operation saves a document and then notifies subscribers. It must decide what a failed notification means after a successful save. Matching types don't make the pair atomic. The use case owns that outcome and any compensating step; adapters implement the capabilities and translate technical failures.
38
+
39
+ - Name the owner of each decision, effect, transaction and resource.
40
+ - Check that what one component guarantees meets what the next one requires.
41
+ - Keep business sequencing and recovery in the use case. The composition root wires components and decides no business policy.
42
+ - Avoid ambient transactions, service locators, implicit subscriptions, mutable globals, and background work that callers can discover only by reading code.
43
+ - Separate what a component owns from what it borrows. A reusable component never shuts down its caller's runtime or closes a borrowed connection.
44
+ - Treat retry permission, deadlines and partial success as behaviour the caller sees, not details an adapter picks.
45
+
46
+ A `FLOW` element shows the composition for a key scenario. Its `Failure paths` say what each failure leaves behind.
47
+
48
+ ## IPC and stored formats
49
+
50
+ When a seam crosses processes or persists data, decide the protocol behaviour that applies:
51
+
52
+ - Framing, encoding, field meanings, numeric ranges, and size limits.
53
+ - Handling of unknown, missing or duplicate fields, unknown variants, malformed data and trailing input. A serialization library's defaults are not a policy.
54
+ - Correlation, ordering, concurrent requests, reconnects and backpressure.
55
+ - Delivery, retries, duplicate handling, and how long an idempotency guarantee lasts.
56
+ - Whether cancellation stops the local wait, asks the peer to cancel, or confirms termination, and what effects may remain after a timeout or disconnect.
57
+ - Compatibility, only for the peer versions or stored formats you must support. In-memory layout is not a wire format.
58
+
59
+ A peer may commit a request and then lose the reply, so a timeout doesn't prove a rollback. Decide whether the outcome can be queried, a retry is safe, or the caller sees an unknown outcome. A request ID alone doesn't give exactly-once execution.
60
+
61
+ ## Evidence that a contract holds
62
+
63
+ - Take expected values from worked examples, independent of the implementation's algorithm.
64
+ - Cover a representative success, invalid input, and the important failures and state histories. Assert effects the caller can observe, not private call chains.
65
+ - Run one set of contract tests against the fake and every real adapter. Evidence from a fake alone says nothing about the real dependency.
66
+ - Where a format or API is promised to outside callers, compile or run a representative caller against it.
67
+
68
+ Ask two questions of every contract test. What plausible wrong implementation would fail it? Would a different correct implementation pass it without copying these internals?
@@ -0,0 +1,50 @@
1
+ # Engineering fundamentals
2
+
3
+ Use these to test material engineering choices in a design, a plan, code or a review. Keep the search bounded by the work at hand: the seams it touches, its scenarios, and the failure and workload risks that are credible. Stop when those have decisions backed by evidence.
4
+
5
+ ## Workload before structure
6
+
7
+ - Before choosing a data structure, describe the operations that dominate the real workload: input size and its upper bound, the mix of lookups, inserts, deletes and scans, ordering and duplicate rules, how it's mutated, concurrency, latency target and memory budget.
8
+ - State the expected, worst-case or amortized cost that matters, and the skewed or hostile inputs that change it.
9
+ - Enforce bounds at trust boundaries, before allocation, indexing, recursion, conversion and arithmetic. Account for overflow, truncation, empty input and limits across concurrent work.
10
+ - Choose by the operations you need: a contiguous sequence for ordered scans and indexing, a hash map or set for keyed lookup, an ordered map for sorted traversal and ranges, a heap for repeated minimum or maximum, a queue for FIFO work. A small bounded scan beats an index that costs more to maintain than it saves.
11
+
12
+ ## States and transitions
13
+
14
+ - Represent a closed set of states with the language's strongest practical type: an enum, sum type or tagged union. Keep each state's data on its variant, instead of coordinating booleans, nulls and loose fields.
15
+ - Define the legal transitions in one visible operation or table. Construction and deserialization validate the state, mutation rejects illegal transitions, and exhaustive matching forces a decision when a state is added.
16
+ - When states cross a stored, wire or public boundary, change their serialized names, values or unknown-state handling only on purpose, with the migration decided.
17
+
18
+ ## The cheapest abstraction that works
19
+
20
+ - Start concrete when there is one behaviour and one representation. Extract a function when only an operation varies. Use an enum for a closed set of variants, generics for compile-time variation, an interface or trait for open substitution, and dynamic dispatch only when runtime variety requires it.
21
+ - Name the alternatives and their costs: a direct collaborator or an interface, a closed enum or plugin dispatch, a generic algorithm or two concrete functions.
22
+ - Add an abstraction for a current variation point, boundary, invariant or test seam, not for an imagined second implementation. Equally, merge duplicated domain rules that must change together.
23
+
24
+ ## Standard machinery first
25
+
26
+ - Use the language's standard algorithms, collections, parsing and resource-management constructs when their contracts fit.
27
+ - Check the real contract: ordering and stability, comparator requirements, invalidation on mutation, allocation, errors, partial results and complexity.
28
+ - Write a direct loop when it makes stateful control flow clearer, or when the standard operation can't meet a demonstrated bound. Say why, and test the edge cases.
29
+
30
+ ## Equality, hashing and ordering
31
+
32
+ - Define domain identity before implementing equality. Equal values hash equally, and an ordering agrees with equality wherever an ordered collection relies on it.
33
+ - Keep keys stable while they sit in a hash or ordered collection. Never base identity on mutable, transient, locale-dependent or process-specific data unless that is the contract.
34
+ - Decide the edge cases the language won't decide for you: case and Unicode normalization, `NaN` and signed zero, absent values, identity versus value equality, and tie-breaks.
35
+
36
+ ## Termination, fan-out and resources
37
+
38
+ - Every loop, recursion, retry, poll, queue, stream and background task has a termination or cancellation condition. Where progress isn't guaranteed, give a maximum count, depth or duration.
39
+ - Bound fan-out and buffering by the workload and the capacity downstream: concurrency limits, queue sizes, backpressure, overload behaviour and who sees the failure.
40
+ - Pair every acquired resource with an owner and a release path across success, error, cancellation and partial initialization. That includes memory, file descriptors, sockets, locks, transactions, temporary files, subscriptions, timers, tasks and external quotas.
41
+
42
+ ## Duplicated literals
43
+
44
+ - Give a literal one home when it encodes a domain fact or must change in step with others: states, event kinds, protocol fields, units, limits, error codes, paths, header names and serialization keys. That home is a typed value, a named constant, a schema or a config entry, at the boundary that owns it.
45
+ - Leave incidental repetition alone: log messages, test descriptions, fixture text and one-off explanations are clearer in place.
46
+ - Before extracting a literal, name the future change the extraction keeps consistent.
47
+
48
+ ## Findings
49
+
50
+ Each material finding gives the evidence, the workload or invariant affected, and a concrete alternative. "Use a deque, because removing from the front of this array is linear at the stated queue bound" is a finding. "Improve performance" is not.
@@ -0,0 +1,37 @@
1
+ # C++
2
+
3
+ These add to the hexagonal design rules for C++ projects. The module map decides the layout; this file never does.
4
+
5
+ ## Files
6
+
7
+ - Organize headers and sources by the concept they own. Public headers sit under `include/<project>/` only when an outside caller needs them; a type private to one source file has no header.
8
+ - `main.cpp` is the composition root: it constructs adapters and use cases, injects dependencies and starts the application.
9
+ - Don't create `Domain.hpp`, `Services.cpp`, `Models.hpp` or `Utils.cpp` catch-alls.
10
+ - Domain headers expose no application, adapter, framework, OS or third-party infrastructure types.
11
+
12
+ ## Modelling
13
+
14
+ - Use modern C++ with value semantics, `enum class` for closed sets, small domain classes and value objects with validating constructors.
15
+ - Use free functions or concrete classes when behaviour needs no polymorphism. Don't create `IFoo`, `Foo` and `FooImpl` without a substitution purpose.
16
+ - Prefer composition over deep inheritance.
17
+
18
+ ## Ports and ownership
19
+
20
+ - Ports are narrow abstract interfaces owned by the application, used where runtime substitution is useful. They never mirror a third-party SDK.
21
+ - Use RAII for every resource. Pass lightweight owned objects by value, transferred exclusive ownership as `std::unique_ptr`, and shared ownership as `std::shared_ptr` only when ownership really is shared. Required dependencies owned elsewhere are references. No raw owning pointers or manual `new` and `delete`.
22
+ - Inject dependencies explicitly and wire them in `main.cpp`.
23
+
24
+ ## Errors
25
+
26
+ - Represent expected domain and application failures explicitly: `std::expected` from C++23, or a small result type the project owns on older standards. Exceptions are not a substitute for modelling failures.
27
+ - Catch third-party exceptions in the adapter and translate them. Never let them cross a port.
28
+
29
+ ## Concurrency
30
+
31
+ - Use threads, executors or queues only when they buy real runtime value, and make shutdown explicit.
32
+ - Keep shared mutable state and lock scope small. Avoid needless queues, context switches, allocations and copies on hot paths.
33
+
34
+ ## Dependencies and tooling
35
+
36
+ - Prefer the standard library, then mature libraries, subject to `.agents/skills/cruze-dependency-approval/SKILL.md`. Weigh portability and build-system impact.
37
+ - Use the project's build system and its own tooling. Format with `clang-format` and lint with `clang-tidy` when the project configures them.
@@ -0,0 +1,40 @@
1
+ # Rust
2
+
3
+ These add to the hexagonal design rules for Rust projects. The module map decides the layout; this file never does.
4
+
5
+ ## Modules
6
+
7
+ - `main.rs` is the composition root and stays thin. `lib.rs` and every `mod.rs` hold only module declarations, visibility and deliberate re-exports, and `lib.rs` exposes the use cases, ports and domain types that tests drive.
8
+ - Name modules for the concept they own. Don't put domain definitions in a `mod.rs`, and don't create `domain.rs`, `services.rs`, `models.rs` or `utils.rs` catch-alls.
9
+ - Where the layer rules need a hard boundary, a Cargo workspace with one crate per layer makes the compiler enforce it. The walking-skeleton change decides this.
10
+
11
+ ## Modelling
12
+
13
+ - Use structs for entities and aggregates, enums for closed alternatives and states, and newtypes for primitives with meaning (`struct DeviceName(String)`).
14
+ - Use concrete functions and types for single-strategy behaviour. Use traits for ports and for strategies that really vary. A struct doesn't need a trait of its own.
15
+ - Prefer APIs that keep invariants: validating constructors (`TryFrom`, `parse`), private fields, and no public setters that skip a rule.
16
+
17
+ ## Ports and injection
18
+
19
+ - Ports are traits owned by the application layer. Adapter types never appear in their signatures.
20
+ - Inject through constructors or parameters. Prefer generics (static dispatch). Use `Box<dyn Trait>` or `Arc<dyn Trait>` only when you need to choose at runtime or store mixed implementations.
21
+
22
+ ## Errors
23
+
24
+ - Define structured error enums with `thiserror` for the domain, each use case and each adapter, and convert between them at the boundaries.
25
+ - `anyhow` belongs only in the composition root and binaries, where no caller inspects the error. Never return it from a port or a domain function.
26
+ - No `unwrap`, `expect` or `panic!` for conditions that can happen in production. Tests may use them.
27
+
28
+ ## Async and concurrency
29
+
30
+ - Use Tokio when the project needs async. Keep the domain synchronous.
31
+ - Call async functions directly. Spawn a task only when it owns a resource, runs concurrently, handles events or isolates failure, and give every long-lived task an explicit shutdown.
32
+ - Prefer ownership and borrowing over shared synchronization. Use a channel when one task owning the state makes things simpler, and a `Mutex` when shared state is simpler. Don't build an actor only to avoid a lock.
33
+
34
+ ## Dependencies and tooling
35
+
36
+ - Common choices, still subject to `.agents/skills/cruze-dependency-approval/SKILL.md`: `serde` at serialization boundaries (never as a reason to couple domain types to a format), `tracing` for instrumentation, `clap` for CLI parsing, `thiserror` for errors.
37
+ - Add dependencies with `cargo add`, so the version comes from the registry.
38
+ - No `unsafe` unless the user approves it or an unavoidable low-level boundary needs it, with a `// SAFETY:` comment giving the reason.
39
+ - Format with `cargo fmt`, lint with `cargo clippy -- -D warnings`, and test with `cargo test`.
40
+ - Behaviour, contract and smoke tests live in `tests/` and reach the code through the library's public API. They share fakes through `tests/support/mod.rs`, which each test file declares with `mod support;`. Domain tests sit in a `#[cfg(test)] mod tests` beside the code and need no fakes.
@@ -0,0 +1,48 @@
1
+ # Runtime ownership
2
+
3
+ Runtime architecture decides how work executes and who owns resources. It is independent of the hexagonal layers: a port is not a thread, and a use case is not a task. Record runtime decisions in an `XC-concurrency` element under the architecture's cross-cutting concerns, and in the `Operations` contracts of the ports involved.
4
+
5
+ ## Choose the execution model
6
+
7
+ Pick the simplest model that meets the ownership, concurrency, lifecycle, isolation and performance needs: direct calls, async calls, tasks, an event loop, actors, a worker pool, dedicated threads, state machines or a pipeline. State the concrete need before adding a task, channel, queue or scheduler hop.
8
+
9
+ Stateless transformation and ordinary domain computation get no task or actor of their own.
10
+
11
+ ## Resource owners
12
+
13
+ Every long-lived, mutable, stateful or exclusive resource has one named owner. This covers sockets, connections, sessions, hardware devices, subprocesses, mutable runtime state and shared caches.
14
+
15
+ - Say how the resource is created, accessed, mutated, failed and shut down, and what final cleanup happens.
16
+ - For background work, say how it is cancelled and whether shutdown drains, rejects or abandons work in flight.
17
+ - A dedicated task or component can own a resource when that buys exclusive ownership, serialized mutation, event handling, lifecycle control or failure isolation. A lock is simpler for plain shared in-process state. Message passing is not always better.
18
+ - Bound every queue, and say what happens on overload.
19
+ - For repeated operations on a resource, use `registry -> resolved handle -> resource`, with the registry named for what it holds, such as `SessionRegistry`. The registry discovers, creates, registers and hands out handles. Routine work goes through the handle, not back through the registry.
20
+
21
+ ## State machines
22
+
23
+ - Use an explicit state machine when the valid operations depend on the current state. Explicit states and transitions replace combinations of boolean flags.
24
+ - State with domain meaning, such as a console session being `opening`, `open` or `closed`, belongs in the domain as an `ENT` with a `States` fact.
25
+ - State that exists because of a protocol, transport, OS, hardware interface or runtime lifecycle belongs to the adapter or runtime component that owns that concern.
26
+
27
+ ## Failures, retries and cancellation
28
+
29
+ - Technical retry and backoff live in an outbound adapter. Whether an operation is safe to repeat, and the use case's deadline, are part of the core contract.
30
+ - Never retry non-idempotent work blindly, and never stack retries at several layers.
31
+ - Stopping a wait, dropping a future, requesting cancellation, ending a task and cancelling remotely are different events. Say which one an operation promises, what effects may remain, and how completion is observed.
32
+ - When a caller needs a guaranteed or fallible finish, give it an explicit `close` or `shutdown` operation. Destruction alone can't report failure.
33
+
34
+ ## Cross-cutting infrastructure
35
+
36
+ Centralize repeated tracing and context propagation, authentication metadata, instrumentation, protocol error mapping and serialization conventions in middleware, wrappers or a dedicated adapter component. Record each as an `XC` element. Business policy, such as an authorization decision, stays in the core even when it recurs.
37
+
38
+ ## Performance
39
+
40
+ - On a hot path, look for avoidable allocations, copies, serialization, queue hops, scheduler transitions, repeated lookups and repeated policy evaluation.
41
+ - Resolve an expensive decision once, for as long as its result stays valid, and say what invalidates it.
42
+ - Measure the real workload before adding complex optimization. Clean layering doesn't justify runtime overhead, and speculative performance doesn't justify erasing an ownership boundary.
43
+
44
+ ## Tests these decisions need
45
+
46
+ - A device session owned by one task: test acquisition failure, overload, cancellation and cleanup.
47
+ - A state machine: test each rejected transition and the behaviour of each terminal state.
48
+ - A cached handle: test what happens after the resource is removed or replaced.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: cruze-land
3
+ description: Lands a verified change by merging its deltas into the living docs with cruze land, updating the changelog, README and AGENTS.md, and committing or opening a pull request; also lands bug fixes from triage.
4
+ ---
5
+
6
+ # Land
7
+
8
+ Land makes finished work part of the living model. `cruze land` merges the change's spec and architecture deltas into `docs/`, marks what it built, and archives the work when it is finished. This skill takes care of what people read around it: the changelog, the README and the pitfalls in `AGENTS.md`. Then it gets the work onto main.
9
+
10
+ ## Landing a change
11
+
12
+ 1. **Check it is ready.** Run `cruze next`. It must name `land` for this change. When it names `verify`, the change hasn't been accepted yet.
13
+ 2. **Bring in main.** Merge or rebase the branch onto an up-to-date main, and resolve conflicts.
14
+ - `journal.jsonl` files merge by keeping every line; `cruze init` sets that up in `.gitattributes`. When that file lacks the rule, keep both sides' lines.
15
+ - When an `approvals.json` conflicts, take main's version of it. Then run `cruze status`, and re-approve what it shows stale, as step 3 describes.
16
+ - Resolve code conflicts as usual, then run the tests.
17
+ 3. **Run `cruze status`.** When the change or its feature shows `upstream changed`, another branch landed changes to elements it cites. Then:
18
+ - Show the user the diff of each changed element, and check that the change's code and tests still hold against it.
19
+ - When they still hold, re-approve the stale documents: the feature first, then the change. The change's verification carries over when its own design didn't change.
20
+ - When they don't hold, stop and offer `rethink`.
21
+ 4. **Run `cruze land`** and quote its report: what it merged, what is now built, and whether the work finished and was archived.
22
+ - A `merge-conflict` means someone changed an element this feature merged earlier. Stop and run `rethink`, which reconciles it.
23
+ - A `merge-invalid` means the merged docs wouldn't validate. Nothing was written. Stop and run `rethink`.
24
+ 5. **Update the changelog.** Under `## [Unreleased]` in `CHANGELOG.md`, add one line per user-visible behaviour the change delivers, in the user's words, under `### Added`, `### Changed` or `### Removed`. Name the behaviour, not the code, including any rule a user can now run into that no scenario covers yet.
25
+ 6. **Update the README** when the change altered how someone installs, runs or uses the product. Run every command you add, to check it works.
26
+ 7. **Check the pitfalls.** Run `cruze journal list --event disposition`, `cruze journal list --event rethink` and `cruze journal list --event bug`. When findings under the same rubric item with the same root cause, or two defects with the same cause, have now happened twice, add one line under `## Known pitfalls` in `AGENTS.md` saying what to do instead. Keep `AGENTS.md` under one page. When the pitfalls outgrow it, propose to the user a `cruze check` rule or a knowledge-skill change for the oldest ones.
27
+ 8. **Commit** the land with a message such as `docs: land <change>`. `cruze land` keeps the Commands and Layout sections of `AGENTS.md` current, from `commands:` in `.cruze/config.yaml` and the built modules; when `commands:` is empty, the Commands section stays as it was.
28
+ 9. **Get it onto main.** Follow the project's convention in `AGENTS.md`. When it has none, ask the user whether they want pull requests or direct merges, and add their answer under `## Conventions`, such as "Changes land through pull requests." Open the pull request, or merge. CI must pass before the merge; when the project has no CI runner, run its steps locally with the project's commands.
29
+
30
+ Done when the change is on main, or in an open pull request, and `cruze status` no longer lists it as in progress.
31
+
32
+ ## Landing a bug fix
33
+
34
+ A fix from `triage` has no change folder, so `cruze land` doesn't run.
35
+
36
+ 1. Check that the fix commit has its failing-then-passing test, and that the full test suite, `cruze check` and `cruze trace --all` pass.
37
+ 2. Add a line under `### Fixed` in `CHANGELOG.md`: what the user saw, and that it is fixed.
38
+ 3. Check the pitfalls, as in step 7 above.
39
+ 4. Commit, then open the pull request or merge, as for a change.
40
+
41
+ ## Next step
42
+
43
+ Once the work is on main, switch to an up-to-date main, run `cruze next` there, and name what it says. Before the merge, `cruze next` on the change's branch can name work that main doesn't hold yet. When a feature just finished and every roadmap item has landed, the next step is `roadmap`, to close the release.