@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.
- package/LICENSE +201 -0
- package/README.md +167 -0
- package/bin/cruze.mjs +17 -0
- package/dist/adapters/inbound/cli/cli_context.js +75 -0
- package/dist/adapters/inbound/cli/commands/code.js +30 -0
- package/dist/adapters/inbound/cli/commands/documents.js +52 -0
- package/dist/adapters/inbound/cli/commands/init.js +23 -0
- package/dist/adapters/inbound/cli/commands/install.js +15 -0
- package/dist/adapters/inbound/cli/commands/journal.js +31 -0
- package/dist/adapters/inbound/cli/commands/progress.js +51 -0
- package/dist/adapters/inbound/cli/commands/review.js +18 -0
- package/dist/adapters/inbound/cli/commands/status.js +45 -0
- package/dist/adapters/inbound/cli/commands.js +36 -0
- package/dist/adapters/inbound/cli/parse_command.js +90 -0
- package/dist/adapters/inbound/cli/run_cli.js +50 -0
- package/dist/adapters/outbound/git_repository.js +57 -0
- package/dist/adapters/outbound/node_project_files.js +101 -0
- package/dist/adapters/outbound/package_bundle.js +56 -0
- package/dist/adapters/outbound/process_agent_runner.js +26 -0
- package/dist/adapters/outbound/system_clock.js +14 -0
- package/dist/adapters/outbound/terminal_prompter.js +22 -0
- package/dist/app/ports/agent_runner.js +11 -0
- package/dist/app/ports/bundle.js +22 -0
- package/dist/app/ports/clock.js +6 -0
- package/dist/app/ports/project_files.js +20 -0
- package/dist/app/ports/prompter.js +5 -0
- package/dist/app/ports/repository.js +13 -0
- package/dist/app/project_context.js +45 -0
- package/dist/app/use_cases/abandon_work.js +42 -0
- package/dist/app/use_cases/approve_artifact.js +146 -0
- package/dist/app/use_cases/check_code.js +90 -0
- package/dist/app/use_cases/init_project.js +59 -0
- package/dist/app/use_cases/install_skills.js +93 -0
- package/dist/app/use_cases/journal_events.js +48 -0
- package/dist/app/use_cases/land_change.js +113 -0
- package/dist/app/use_cases/new_project_doc.js +40 -0
- package/dist/app/use_cases/new_work_item.js +75 -0
- package/dist/app/use_cases/project_status.js +73 -0
- package/dist/app/use_cases/record_progress.js +101 -0
- package/dist/app/use_cases/run_review.js +71 -0
- package/dist/app/use_cases/validate_project.js +22 -0
- package/dist/domain/agent_skill_homes.js +25 -0
- package/dist/domain/approvals/evaluate.js +36 -0
- package/dist/domain/approvals/fingerprint.js +52 -0
- package/dist/domain/approvals/records.js +50 -0
- package/dist/domain/architecture_sections.js +23 -0
- package/dist/domain/check/check_source.js +64 -0
- package/dist/domain/check/imports.js +81 -0
- package/dist/domain/check/rust_imports.js +84 -0
- package/dist/domain/check/type_count.js +17 -0
- package/dist/domain/config.js +128 -0
- package/dist/domain/cruze_error.js +10 -0
- package/dist/domain/edits/agents_file.js +44 -0
- package/dist/domain/edits/managed_tables.js +60 -0
- package/dist/domain/edits/progress_block.js +33 -0
- package/dist/domain/edits/status_lines.js +52 -0
- package/dist/domain/elements.js +126 -0
- package/dist/domain/glob.js +46 -0
- package/dist/domain/hashing.js +52 -0
- package/dist/domain/ids.js +37 -0
- package/dist/domain/journal.js +62 -0
- package/dist/domain/land/bookkeeping.js +54 -0
- package/dist/domain/land/merge_plan.js +132 -0
- package/dist/domain/land/text_ops.js +66 -0
- package/dist/domain/markdown.js +79 -0
- package/dist/domain/markdown_tables.js +34 -0
- package/dist/domain/project/artifact_ref.js +42 -0
- package/dist/domain/project/deltas.js +49 -0
- package/dist/domain/project/layout.js +40 -0
- package/dist/domain/project/living_model.js +54 -0
- package/dist/domain/project/new_items.js +48 -0
- package/dist/domain/project/plan_parts.js +111 -0
- package/dist/domain/project/progress.js +43 -0
- package/dist/domain/project/project_view.js +72 -0
- package/dist/domain/project/roadmap.js +43 -0
- package/dist/domain/project/work_items.js +68 -0
- package/dist/domain/project_name.js +20 -0
- package/dist/domain/scaffold.js +29 -0
- package/dist/domain/skill.js +106 -0
- package/dist/domain/skill_links.js +103 -0
- package/dist/domain/status/next_step.js +119 -0
- package/dist/domain/status/verification.js +16 -0
- package/dist/domain/status/work_status.js +101 -0
- package/dist/domain/trace.js +44 -0
- package/dist/domain/validation/delta_rules.js +79 -0
- package/dist/domain/validation/element_rules.js +99 -0
- package/dist/domain/validation/living_rules.js +97 -0
- package/dist/domain/validation/plan_rules.js +105 -0
- package/dist/domain/validation/problem.js +21 -0
- package/dist/domain/validation/project_rules.js +99 -0
- package/dist/domain/validation/validate_project.js +31 -0
- package/dist/domain/validation/work_item_rules.js +144 -0
- package/dist/main.js +32 -0
- package/package.json +40 -0
- package/scripts/build.mjs +37 -0
- package/skills/about/SKILL.md +21 -0
- package/skills/architect/SKILL.md +43 -0
- package/skills/architect/feature.md +29 -0
- package/skills/architect/project.md +58 -0
- package/skills/architect/tweak.md +22 -0
- package/skills/architect/walkthrough.md +29 -0
- package/skills/behavioural-testing/SKILL.md +63 -0
- package/skills/behavioural-testing/examples.md +102 -0
- package/skills/behavioural-testing/fakes.md +30 -0
- package/skills/build/SKILL.md +62 -0
- package/skills/dependency-approval/SKILL.md +48 -0
- package/skills/domain-language/SKILL.md +37 -0
- package/skills/envision/SKILL.md +29 -0
- package/skills/envision/feature.md +22 -0
- package/skills/envision/project.md +20 -0
- package/skills/explore/SKILL.md +39 -0
- package/skills/formats/SKILL.md +84 -0
- package/skills/formats/reference/architecture.md +80 -0
- package/skills/formats/reference/config.md +57 -0
- package/skills/formats/reference/durable-docs.md +71 -0
- package/skills/formats/reference/specs.md +65 -0
- package/skills/formats/reference/work-items.md +100 -0
- package/skills/formats/templates/adr.md +7 -0
- package/skills/formats/templates/architecture.md +100 -0
- package/skills/formats/templates/change.md +29 -0
- package/skills/formats/templates/feature.md +49 -0
- package/skills/formats/templates/glossary.md +8 -0
- package/skills/formats/templates/roadmap.md +32 -0
- package/skills/formats/templates/spec.md +11 -0
- package/skills/formats/templates/standalone-change.md +46 -0
- package/skills/formats/templates/vision.md +37 -0
- package/skills/grilling/SKILL.md +66 -0
- package/skills/hexagonal-design/SKILL.md +119 -0
- package/skills/hexagonal-design/contracts.md +68 -0
- package/skills/hexagonal-design/fundamentals.md +50 -0
- package/skills/hexagonal-design/languages/cpp.md +37 -0
- package/skills/hexagonal-design/languages/rust.md +40 -0
- package/skills/hexagonal-design/runtime.md +48 -0
- package/skills/land/SKILL.md +43 -0
- package/skills/next/SKILL.md +30 -0
- package/skills/plan/SKILL.md +52 -0
- package/skills/plan/tasks.md +26 -0
- package/skills/plan/test-plan.md +14 -0
- package/skills/research/SKILL.md +41 -0
- package/skills/research/evaluation.md +27 -0
- package/skills/rethink/SKILL.md +53 -0
- package/skills/rethink/levels.md +45 -0
- package/skills/roadmap/SKILL.md +51 -0
- package/skills/roles/SKILL.md +57 -0
- package/skills/roles/code-reviewer.md +55 -0
- package/skills/roles/design-reviewer.md +63 -0
- package/skills/roles/researcher.md +33 -0
- package/skills/roles/verifier.md +38 -0
- package/skills/triage/SKILL.md +35 -0
- package/skills/verify/SKILL.md +39 -0
- package/skills/verify/manual-test.md +23 -0
- package/src/adapters/inbound/cli/cli_context.ts +75 -0
- package/src/adapters/inbound/cli/commands/code.ts +30 -0
- package/src/adapters/inbound/cli/commands/documents.ts +52 -0
- package/src/adapters/inbound/cli/commands/init.ts +23 -0
- package/src/adapters/inbound/cli/commands/install.ts +15 -0
- package/src/adapters/inbound/cli/commands/journal.ts +31 -0
- package/src/adapters/inbound/cli/commands/progress.ts +51 -0
- package/src/adapters/inbound/cli/commands/review.ts +18 -0
- package/src/adapters/inbound/cli/commands/status.ts +45 -0
- package/src/adapters/inbound/cli/commands.ts +36 -0
- package/src/adapters/inbound/cli/parse_command.ts +90 -0
- package/src/adapters/inbound/cli/run_cli.ts +50 -0
- package/src/adapters/outbound/git_repository.ts +57 -0
- package/src/adapters/outbound/node_project_files.ts +101 -0
- package/src/adapters/outbound/package_bundle.ts +56 -0
- package/src/adapters/outbound/process_agent_runner.ts +26 -0
- package/src/adapters/outbound/system_clock.ts +14 -0
- package/src/adapters/outbound/terminal_prompter.ts +22 -0
- package/src/app/ports/agent_runner.ts +11 -0
- package/src/app/ports/bundle.ts +22 -0
- package/src/app/ports/clock.ts +6 -0
- package/src/app/ports/project_files.ts +20 -0
- package/src/app/ports/prompter.ts +5 -0
- package/src/app/ports/repository.ts +13 -0
- package/src/app/project_context.ts +45 -0
- package/src/app/use_cases/abandon_work.ts +42 -0
- package/src/app/use_cases/approve_artifact.ts +146 -0
- package/src/app/use_cases/check_code.ts +90 -0
- package/src/app/use_cases/init_project.ts +59 -0
- package/src/app/use_cases/install_skills.ts +93 -0
- package/src/app/use_cases/journal_events.ts +48 -0
- package/src/app/use_cases/land_change.ts +113 -0
- package/src/app/use_cases/new_project_doc.ts +40 -0
- package/src/app/use_cases/new_work_item.ts +75 -0
- package/src/app/use_cases/project_status.ts +73 -0
- package/src/app/use_cases/record_progress.ts +101 -0
- package/src/app/use_cases/run_review.ts +71 -0
- package/src/app/use_cases/validate_project.ts +22 -0
- package/src/domain/agent_skill_homes.ts +25 -0
- package/src/domain/approvals/evaluate.ts +36 -0
- package/src/domain/approvals/fingerprint.ts +52 -0
- package/src/domain/approvals/records.ts +50 -0
- package/src/domain/architecture_sections.ts +23 -0
- package/src/domain/check/check_source.ts +64 -0
- package/src/domain/check/imports.ts +81 -0
- package/src/domain/check/rust_imports.ts +84 -0
- package/src/domain/check/type_count.ts +17 -0
- package/src/domain/config.ts +128 -0
- package/src/domain/cruze_error.ts +10 -0
- package/src/domain/edits/agents_file.ts +44 -0
- package/src/domain/edits/managed_tables.ts +60 -0
- package/src/domain/edits/progress_block.ts +33 -0
- package/src/domain/edits/status_lines.ts +52 -0
- package/src/domain/elements.ts +126 -0
- package/src/domain/glob.ts +46 -0
- package/src/domain/hashing.ts +52 -0
- package/src/domain/ids.ts +37 -0
- package/src/domain/journal.ts +62 -0
- package/src/domain/land/bookkeeping.ts +54 -0
- package/src/domain/land/merge_plan.ts +132 -0
- package/src/domain/land/text_ops.ts +66 -0
- package/src/domain/markdown.ts +79 -0
- package/src/domain/markdown_tables.ts +34 -0
- package/src/domain/project/artifact_ref.ts +42 -0
- package/src/domain/project/deltas.ts +49 -0
- package/src/domain/project/layout.ts +40 -0
- package/src/domain/project/living_model.ts +54 -0
- package/src/domain/project/new_items.ts +48 -0
- package/src/domain/project/plan_parts.ts +111 -0
- package/src/domain/project/progress.ts +43 -0
- package/src/domain/project/project_view.ts +72 -0
- package/src/domain/project/roadmap.ts +43 -0
- package/src/domain/project/work_items.ts +68 -0
- package/src/domain/project_name.ts +20 -0
- package/src/domain/scaffold.ts +29 -0
- package/src/domain/skill.ts +106 -0
- package/src/domain/skill_links.ts +103 -0
- package/src/domain/status/next_step.ts +119 -0
- package/src/domain/status/verification.ts +16 -0
- package/src/domain/status/work_status.ts +101 -0
- package/src/domain/trace.ts +44 -0
- package/src/domain/validation/delta_rules.ts +79 -0
- package/src/domain/validation/element_rules.ts +99 -0
- package/src/domain/validation/living_rules.ts +97 -0
- package/src/domain/validation/plan_rules.ts +105 -0
- package/src/domain/validation/problem.ts +21 -0
- package/src/domain/validation/project_rules.ts +99 -0
- package/src/domain/validation/validate_project.ts +31 -0
- package/src/domain/validation/work_item_rules.ts +144 -0
- package/src/main.ts +32 -0
- package/templates/init/AGENTS.md +28 -0
- package/templates/init/CHANGELOG.md +8 -0
- package/templates/init/CLAUDE.md +1 -0
- package/templates/init/README.md +1 -0
- package/templates/init/ci.yml +23 -0
- package/templates/init/config.yaml +33 -0
- package/templates/init/gitattributes +2 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Architect at project scope
|
|
2
|
+
|
|
3
|
+
The result has four parts, reviewed together and shown at one walkthrough:
|
|
4
|
+
|
|
5
|
+
- `docs/architecture.md`, the living model of the whole system, which the user approves.
|
|
6
|
+
- The `layers:` rules in `.cruze/config.yaml`.
|
|
7
|
+
- `docs/roadmap.md` for the first release, which the user approves as its own step.
|
|
8
|
+
- The walking-skeleton change, designed and ready for `plan`. It is approved later, once `plan` has filled its test plan and tasks.
|
|
9
|
+
|
|
10
|
+
## Design the architecture
|
|
11
|
+
|
|
12
|
+
1. **Create it.** Run `cruze new architecture`. Follow its sections in order, one at a time, and grill the user on each section's material decisions before writing it.
|
|
13
|
+
2. **Bounded contexts (`CTX`).** Group the vision's capabilities into contexts by which language and rules belong together. Most small systems have one to three. Each context has a `Purpose`, and a `Depends on` naming what it uses from other contexts. Regroup the glossary's terms under one `##` heading per context.
|
|
14
|
+
3. **Domain model (`ENT`).** For each context, model the concepts the vision and glossary name, including invariants, relationships with cardinality, and `States` for anything whose valid operations depend on its state. Add the `VIEW-domain-model` class diagram.
|
|
15
|
+
4. **Use cases (`UC`).** Write one per operation a caller can ask for in this release, each with its input, output, errors and the ports it uses.
|
|
16
|
+
5. **Ports (`PORT`).** Define every capability the use cases need from outside, named by capability. Write each operation's contract, following `.agents/skills/cruze-hexagonal-design/contracts.md`. Add driving ports only where the hexagonal-design skill calls for them.
|
|
17
|
+
6. **Adapters (`ADP`).** Name the technology behind each driven port and each inbound adapter that drives use cases. Run the researcher role on every adapter's technology first, and record the result in the adapter's `Adopts` fact. Take every new dependency to the user.
|
|
18
|
+
7. **Flows (`FLOW`).** Write a `sequenceDiagram` for each of the 2 to 5 most important interactions, including their failure paths. Leave out `Serves` until scenarios exist.
|
|
19
|
+
8. **Modules (`MOD`).** Give each context its hexagonal modules, and give the shared CLI shell and the composition root the `system` scope. Add a `system` module in the `composition` layer for the build and CI files, such as the package manifest and `.github/workflows/`, so the tasks that write them have an owner. Every source file must fall inside some module's `Path`, including namespace files that join a context's modules, such as `src/inventory/mod.rs` or `index.ts`; list them in a `composition` module's `Path` when no other module fits. Every module gets a `Path` and a `Layer`, and every element above gets its `Module` and `File`.
|
|
20
|
+
9. **Dependency rules (`RULE`).** State what may import what, in one or two sentences each.
|
|
21
|
+
10. **Cross-cutting concerns (`XC`).** Cover errors, configuration, logging, concurrency and security, plus build and delivery (CI, formatting, linting). Read `.agents/skills/cruze-hexagonal-design/runtime.md` for concurrency.
|
|
22
|
+
11. **Decisions.** Write an ADR, with `cruze new adr <slug> --title "<title>"`, for each decision that passes the ADR test. Record the other project decisions as `D<n>` lines under `## Decisions`.
|
|
23
|
+
12. **Overview (`VIEW-context`).** Draw the context diagram last, once the adapters and external systems are known.
|
|
24
|
+
|
|
25
|
+
Done when `cruze validate` reports no errors in `docs/architecture.md`. At this stage it warns that elements have no status yet; approval adds the statuses.
|
|
26
|
+
|
|
27
|
+
## Write the layer rules
|
|
28
|
+
|
|
29
|
+
Fill `source`, `tests` and `layers:` in `.cruze/config.yaml` from the module map, following `.agents/skills/cruze-formats/reference/config.md`. Give each module's `Path` exactly one layer, and make each layer's `may_import` match the `RULE` elements. Done when `cruze validate` reports no config errors and no `module-layer` warnings.
|
|
30
|
+
|
|
31
|
+
## Ignore build output
|
|
32
|
+
|
|
33
|
+
Add the language's build output and tool caches to `.gitignore` now, such as `/target` for Rust or `node_modules/` for Node, so no later commit sweeps them in.
|
|
34
|
+
|
|
35
|
+
## Plan the release
|
|
36
|
+
|
|
37
|
+
1. **Create the roadmap.** Run `cruze new roadmap`. Agree the first release with the user: its name, and which features from the vision's feature map it delivers.
|
|
38
|
+
2. **Order the work.** Phase 1 holds only the `walking-skeleton` change. Later phases hold the release's features. Done when the roadmap passes the rules in step 5 of `.agents/skills/cruze-roadmap/SKILL.md`.
|
|
39
|
+
3. **Design the walking skeleton.** Run `cruze new change walking-skeleton --title "Walking skeleton"`. Then:
|
|
40
|
+
- Size the elements it builds for the skeleton. Anything the walking skeleton lists under `Builds` is marked built when it lands, so write those elements, such as the CLI adapter or the first entity, at the size the skeleton needs. Record their planned growth in `Future` facts; later features grow them through `MODIFIED` operations.
|
|
41
|
+
- Choose the thinnest end-to-end slice that crosses every layer: one real inbound adapter, one use case, the domain it needs, one driven adapter and the composition root. It also makes CI real: `cruze init` already runs `cruze validate`, `cruze check --ci` and `cruze trace --all` there, and the skeleton adds the language's format, lint, build and test steps. `plan` fills `commands:` in `.cruze/config.yaml` for it.
|
|
42
|
+
- Write its `## Intent`.
|
|
43
|
+
- In `## Adopt or build`, add a row for each tool it adds that no adapter owns, such as the test framework, linter or CI runner.
|
|
44
|
+
- Write the `## Spec delta` for the one capability it delivers, with scenarios.
|
|
45
|
+
- In `## Architecture delta`, link the new behaviour to the design: a `MODIFIED` operation for each use case that serves its requirements, adding them to `Serves`, and for each flow that runs its scenarios, adding them to its `Serves`. Each body is the element's full text from `docs/architecture.md` with that fact added.
|
|
46
|
+
- Fill `## Scope`. `Delivers` lists its scenarios. `Builds` lists the elements it modifies, the other architecture elements it builds, and every module whose first files it writes.
|
|
47
|
+
- Leave the test plan and tasks to `plan`.
|
|
48
|
+
- Done when `cruze validate` reports only the change's `not-planned` warning.
|
|
49
|
+
|
|
50
|
+
## Review, walk through and approve
|
|
51
|
+
|
|
52
|
+
1. Run the design review and the walkthrough from the skill's steps 6 and 7, over the architecture, the config, the roadmap and the walking skeleton together.
|
|
53
|
+
2. When the user approves the design, run `cruze approve architecture`. It marks every element `planned`.
|
|
54
|
+
3. Confirm the release ordering with the user, then run `cruze approve roadmap`.
|
|
55
|
+
4. Add an `## Architecture` section to `README.md`: one sentence on the system's shape, the `VIEW-context` diagram, and a link to `docs/architecture.md`.
|
|
56
|
+
5. Commit, with a message such as `docs: approve the architecture and roadmap`.
|
|
57
|
+
|
|
58
|
+
Done when `cruze status` shows the vision, the architecture and the roadmap approved.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Architect at tweak scope
|
|
2
|
+
|
|
3
|
+
A tweak changes existing behaviour without changing the architecture. The result is a standalone change with its intent, spec delta and scope, ready for `plan`. It has no design review and no walkthrough, because nothing structural changes; the plan review in `plan` covers it.
|
|
4
|
+
|
|
5
|
+
1. **Name the behaviour.** Find the requirements and scenarios in `docs/specs/` that the tweak changes, and the use cases that `Serve` them. Done when you can name every one.
|
|
6
|
+
2. **Check that it is a tweak.** Trace the new behaviour through `docs/architecture.md`. It is not a tweak when it needs a new requirement, which a use case would have to serve, or any new or changed element (an entity invariant, a use case's input or errors, a port operation, an adapter or a module). Tell the user, and continue at feature scope with [feature.md](feature.md), which puts the feature on the roadmap and creates its folder.
|
|
7
|
+
3. **Create the change.** Run `cruze new change <slug> --title "<title>"`, adding `--roadmap <slug>` when the tweak is a roadmap item.
|
|
8
|
+
4. **Settle the behaviour.** Grill the user on anything open: the exact new behaviour, its edge cases, and what a user now observes. Record decisions under the change's `## Settled decisions` as they settle.
|
|
9
|
+
5. **Write the design sections,** and remove every template guide, including any unused `D1` line.
|
|
10
|
+
- `## Intent`: why, in the user's words, and what is out of scope.
|
|
11
|
+
- `## Adopt or build`: the table header only, since a tweak adds no components.
|
|
12
|
+
- `## Spec delta`: `MODIFIED` requirements with their full new bodies, including every scenario each one keeps.
|
|
13
|
+
- `## Architecture delta`: `None.`
|
|
14
|
+
- `## Scope`: `Delivers` lists every new or changed scenario. `Builds` stays empty unless the tweak builds `planned` elements.
|
|
15
|
+
- Leave the test plan and tasks to `plan`.
|
|
16
|
+
6. **Confirm.** Summarize the new behaviour and ask the user to confirm it.
|
|
17
|
+
|
|
18
|
+
## A prefactor
|
|
19
|
+
|
|
20
|
+
A prefactor comes from an architecture-level rethink: the architecture already says what the code must become, and one or more built elements went back to `planned`. It changes structure, not behaviour. Create it as in step 3, then write its intent, set `## Spec delta` and `## Architecture delta` to `None.`, and list the replanned elements under `Builds`. The existing behaviour tests are its safety net: they must pass unchanged.
|
|
21
|
+
|
|
22
|
+
Done when the user has confirmed, `cruze validate` reports only the change's `not-planned` warning, and the change is committed.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# The design walkthrough
|
|
2
|
+
|
|
3
|
+
The walkthrough is where the user comes to understand the design well enough to explain it without you. It is the one heavy gate before code. Show the design as it stands in the files, one part at a time, in the order below. Pause after each part for questions.
|
|
4
|
+
|
|
5
|
+
At feature scope, show only what the feature adds, changes or removes, next to the current elements it touches. At project scope, show the whole architecture.
|
|
6
|
+
|
|
7
|
+
## Order
|
|
8
|
+
|
|
9
|
+
1. **What it does.** The intent in two sentences, then each requirement with its scenarios' titles.
|
|
10
|
+
2. **Where it sits.** The `VIEW-context` diagram, or at feature scope, the contexts the feature touches.
|
|
11
|
+
3. **The domain.** The domain-model class diagram, then each new or changed entity: its invariants, its states and who owns it.
|
|
12
|
+
4. **How it runs.** For each key flow, show its `sequenceDiagram` and walk one scenario through it step by step, including one failure path. This is the part the user must be able to retell.
|
|
13
|
+
5. **The seams.** Each new or changed port with its operations and their contracts, then the adapter behind each one and the library it adopts.
|
|
14
|
+
6. **Dependencies.** Every new dependency, named out loud with its purpose and the approval behind it. Also the components you chose to build yourself, with the reason.
|
|
15
|
+
7. **Where the code goes.** Each new element next to its module, file path and layer, and the layer rules those files must obey. At project scope, also the `layers:` in `.cruze/config.yaml`.
|
|
16
|
+
8. **The slices.** The changes in order, with what each delivers and builds, and why the first is first. At project scope, the roadmap's phases and the walking skeleton instead.
|
|
17
|
+
9. **Decisions and review.** The settled decisions and ADRs, each review finding with its disposition, and the points where a fresh implementer could still build something different.
|
|
18
|
+
|
|
19
|
+
## Showing diagrams
|
|
20
|
+
|
|
21
|
+
Mermaid diagrams live in the documents, so point to the file and line of each one, and paste its source into the conversation. When the user can render Mermaid (an editor preview, or GitHub), say where to open it. Keep each diagram under 15 nodes; split a bigger picture instead of shrinking it.
|
|
22
|
+
|
|
23
|
+
## Ending
|
|
24
|
+
|
|
25
|
+
1. Ask the user to explain one flow back in their own words, or to name what they would still find surprising in the code. Treat their answer as the check that the walkthrough worked, and go back over any part they can't retell.
|
|
26
|
+
2. Ask for approval in these words: "Do you approve this design?"
|
|
27
|
+
3. A request for changes is not an approval. Apply the changes and run `cruze validate`. When they touch placement, dependency direction, adopt-or-build decisions, port contracts or flows, run a new design review on the diff alone. Then walk through only the parts that changed, and ask again.
|
|
28
|
+
4. When the user rejects the design outright, don't approve anything. Ask what is wrong. When the problem is what to build, go back to `envision`; when it is the whole approach, restart this step's design; when the user wants to stop, leave the work unapproved and say how to resume.
|
|
29
|
+
5. Done when the user says they approve.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-behavioural-testing
|
|
3
|
+
description: The testing standard for a Cruze project, covering which tests to write, the seam each one drives, the ID it carries, and fakes instead of mocks. Use when writing a change's test plan, when writing, changing or fixing a test, when building a fake for a port, when deciding whether a unit test is warranted, or when reviewing tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Behavioural testing
|
|
7
|
+
|
|
8
|
+
Behaviour is the contract. Every scenario in the specs becomes a test that drives the system through a use case and checks what a caller would see. Tests pin behaviour, not structure, so the code behind them can be rewritten freely.
|
|
9
|
+
|
|
10
|
+
## Writing tests for a task
|
|
11
|
+
|
|
12
|
+
1. Find the test plan rows whose Subject the task proves. Done when you know the seam, test file and kind of every test the task needs.
|
|
13
|
+
2. Write one test at its seam, carrying its subject ID. Take the inputs and expected values from the scenario's GIVEN, WHEN and THEN.
|
|
14
|
+
3. Run it and watch it fail for the reason you expect (red). A test that passes before the code exists proves nothing, so fix the test.
|
|
15
|
+
4. Write the least code that makes it pass (green). Then write the next test. Work in tracer bullets, one test and one slice of code at a time, never all the tests first.
|
|
16
|
+
5. Done when every test plan row whose Subject the task proves has a passing test carrying that ID, and each test fails when the behaviour it checks is removed. Tasks that prove only a `UC`, `ADP` or `MOD` are proved by the rows of the scenarios and ports they serve.
|
|
17
|
+
|
|
18
|
+
## The four kinds
|
|
19
|
+
|
|
20
|
+
These match the test plan in `.agents/skills/cruze-formats/reference/work-items.md`.
|
|
21
|
+
|
|
22
|
+
| Kind | Subject | Seam | When |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| `behaviour` | `SCN` | The use case's API with a fake for each driven port, or the inbound adapter when the outcome is what that adapter shows, such as CLI output, an exit code or an HTTP status | One or more per scenario, always |
|
|
25
|
+
| `contract` | `PORT` | The same cases run against the fake and every real adapter | Every driven port that has a real adapter |
|
|
26
|
+
| `domain` | `ENT` | The entity's own API | Only for real logic: state machines, calculations, invariants with edge cases |
|
|
27
|
+
| `smoke` | `FLOW` | The real inbound adapter, wired by the real composition root | The top 1 to 3 flows |
|
|
28
|
+
|
|
29
|
+
A behaviour test drives a use case, not a single domain type, so it keeps passing when rules move between entities. In a library with no use cases, the seam is the library's public API. Write a domain test only when a rule's edge cases are too many to reach through use cases one by one.
|
|
30
|
+
|
|
31
|
+
## Seams and fakes
|
|
32
|
+
|
|
33
|
+
- A test reaches the system only through its seam. It never calls a private function, never replaces an internal collaborator, and never inspects storage behind a port instead of reading back through the use case.
|
|
34
|
+
- Replace each driven port with a fake: a small in-memory implementation that honours the port's contract, such as `InMemoryDeviceCatalog`. Fake only ports, never your own domain types or use cases.
|
|
35
|
+
- Assert outcomes: return values, errors, and state read back through the interface. Assert calls, their count or their order only when that is itself the contract, such as hops closed in reverse order, and observe it through effects the fake records.
|
|
36
|
+
- Time, randomness and the environment are ports too. Inject a clock instead of reading the system time.
|
|
37
|
+
- A fake earns trust from the contract tests it shares with the real adapter. Read [fakes.md](fakes.md) before writing one.
|
|
38
|
+
|
|
39
|
+
## Expected values
|
|
40
|
+
|
|
41
|
+
- Take expected values from an independent source: the scenario's worked example, a spec, or a known-good literal. Never compute the expected value the way the code does.
|
|
42
|
+
- For a failure scenario, check both the error and the state left behind. After a refused second hop, the first hop is closed.
|
|
43
|
+
- Where a plausible wrong outcome exists, assert that it didn't happen.
|
|
44
|
+
|
|
45
|
+
## Protecting the check
|
|
46
|
+
|
|
47
|
+
- Behaviour, contract and smoke tests for approved scenarios, ports and flows are the safety net. Never edit one to get green. When one fails, either the code is wrong, or the spec is. A wrong spec or design goes through the rethink step, and the test changes only with the delta that changes its subject: a spec delta for a `SCN`, an architecture delta for a `PORT` or `FLOW`.
|
|
48
|
+
- Domain tests are disposable. Rewrite or delete them along with the code they test.
|
|
49
|
+
- Never skip a test, delete one, or weaken an assertion to finish a task. Verify flags any diff to a safety-net test that has no matching delta.
|
|
50
|
+
|
|
51
|
+
## What not to write
|
|
52
|
+
|
|
53
|
+
- Tests of private functions, getters or plain data.
|
|
54
|
+
- Tests that restate the implementation, including snapshots whose expected output was derived the same way the code derives it.
|
|
55
|
+
- Mocks of internal collaborators, and assertions on calls that aren't part of a contract.
|
|
56
|
+
|
|
57
|
+
Side-by-side examples are in [examples.md](examples.md).
|
|
58
|
+
|
|
59
|
+
## Naming and tracing
|
|
60
|
+
|
|
61
|
+
- Every test carries its subject ID where `.agents/skills/cruze-formats/reference/work-items.md` says, such as `// SCN-access.direct-serial` on the line above it.
|
|
62
|
+
- A scenario may need several tests, and each of them carries its ID. One test covers one scenario.
|
|
63
|
+
- `cruze trace` checks scenarios only: it fails when a scenario the change delivers has no test carrying its ID, or when a test cites a scenario nobody defined. Run it before calling a change's tests complete, and quote its result. For the `contract`, `domain` and `smoke` rows, list each subject ID next to the test that carries it.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Good and bad tests
|
|
2
|
+
|
|
3
|
+
The examples are in Rust, from a console-access tool. The shape is the same in any language.
|
|
4
|
+
|
|
5
|
+
## Through the use case, with fakes
|
|
6
|
+
|
|
7
|
+
Good. It drives the use case, fakes the ports, and checks what the caller sees:
|
|
8
|
+
|
|
9
|
+
```rust
|
|
10
|
+
// SCN-access.second-hop-refused
|
|
11
|
+
#[test]
|
|
12
|
+
fn second_hop_refused_closes_the_first_hop() {
|
|
13
|
+
let catalog = InMemoryDeviceCatalog::with(device("lab-router", ssh_via("jump-1")));
|
|
14
|
+
let connector = FakeHopConnector::new();
|
|
15
|
+
connector.refuse("lab-router");
|
|
16
|
+
let open = OpenConsole::new(&catalog, &connector);
|
|
17
|
+
|
|
18
|
+
let result = open.run("lab-router");
|
|
19
|
+
|
|
20
|
+
assert_eq!(result.unwrap_err(), OpenConsoleError::HopRefused { hop: 2 });
|
|
21
|
+
assert_eq!(connector.open_hops(), Vec::<String>::new());
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Bad. It mocks an internal collaborator and asserts on calls, so it breaks on refactors that keep the behaviour:
|
|
26
|
+
|
|
27
|
+
```rust
|
|
28
|
+
#[test]
|
|
29
|
+
fn open_console_calls_resolver_then_connector() {
|
|
30
|
+
let mut resolver = MockPathResolver::new();
|
|
31
|
+
resolver.expect_resolve().times(1).returning(|_| Ok(path()));
|
|
32
|
+
// ...asserts that resolve() ran before connect()
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Expected values from the spec
|
|
37
|
+
|
|
38
|
+
Good. The expected value is the literal from the scenario:
|
|
39
|
+
|
|
40
|
+
```rust
|
|
41
|
+
// SCN-inventory.list-configured
|
|
42
|
+
#[test]
|
|
43
|
+
fn lists_devices_in_name_order() {
|
|
44
|
+
let catalog = InMemoryDeviceCatalog::with_names(&["lab-router", "core-switch"]);
|
|
45
|
+
assert_eq!(ListDevices::new(&catalog).run(), vec!["core-switch", "lab-router"]);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Bad. It recomputes the expectation the way the code does, so it can never disagree with the code:
|
|
50
|
+
|
|
51
|
+
```rust
|
|
52
|
+
#[test]
|
|
53
|
+
fn lists_devices_sorted() {
|
|
54
|
+
let names = vec!["lab-router", "core-switch"];
|
|
55
|
+
let mut expected = names.clone();
|
|
56
|
+
expected.sort();
|
|
57
|
+
assert_eq!(ListDevices::new(&catalog_of(&names)).run(), expected);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Reading back through the interface
|
|
62
|
+
|
|
63
|
+
Good. It checks the effect through the port's own operation:
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
// SCN-inventory.add-device
|
|
67
|
+
#[test]
|
|
68
|
+
fn added_device_is_listed() {
|
|
69
|
+
let catalog = InMemoryDeviceCatalog::empty();
|
|
70
|
+
AddDevice::new(&catalog).run(new_device("lab-router")).unwrap();
|
|
71
|
+
assert_eq!(ListDevices::new(&catalog).run(), vec!["lab-router"]);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Bad. It bypasses the interface to inspect storage:
|
|
76
|
+
|
|
77
|
+
```rust
|
|
78
|
+
#[test]
|
|
79
|
+
fn add_device_writes_the_toml_file() {
|
|
80
|
+
AddDevice::new(&TomlCatalog::at(&path)).run(new_device("lab-router")).unwrap();
|
|
81
|
+
assert!(std::fs::read_to_string(&path).unwrap().contains("[lab-router]"));
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The file format is the TOML adapter's business. Its contract tests cover it, and they read back through `DeviceCatalog`.
|
|
86
|
+
|
|
87
|
+
## A domain test that earns its place
|
|
88
|
+
|
|
89
|
+
Good. A state machine with real rules, tested through the entity's own API:
|
|
90
|
+
|
|
91
|
+
```rust
|
|
92
|
+
// ENT-access.console-session
|
|
93
|
+
#[test]
|
|
94
|
+
fn a_closed_session_cannot_reopen() {
|
|
95
|
+
let mut session = ConsoleSession::opening();
|
|
96
|
+
session.opened().unwrap();
|
|
97
|
+
session.close();
|
|
98
|
+
assert_eq!(session.opened(), Err(SessionError::AlreadyClosed));
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Not worth writing: a test that `Device::name()` returns the name it was built with.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Fakes and contract tests
|
|
2
|
+
|
|
3
|
+
A fake is a real, working implementation of a driven port that keeps its state in memory. Behaviour tests use it in place of the real adapter. Contract tests keep it honest.
|
|
4
|
+
|
|
5
|
+
## Writing a fake
|
|
6
|
+
|
|
7
|
+
1. Read the port's `Operations` in `docs/architecture.md`. The fake implements every operation with the guarantees and failures listed there, and nothing more.
|
|
8
|
+
2. Keep state in plain in-memory structures: a map for a catalog, a list for recorded effects, a settable value for a clock.
|
|
9
|
+
3. Give tests a way to arrange state and to inject each failure the contract lists. Use a constructor that takes the initial state, and a method such as `fail_next_with(HopError::Refused)`.
|
|
10
|
+
4. Record effects the contract makes observable, such as the order hops were closed in, so tests can assert them.
|
|
11
|
+
5. Put the fake where every test can reach it, such as `tests/support/` or the language's test-only module, never in production code paths. One fake per port, shared by all tests.
|
|
12
|
+
|
|
13
|
+
Done when the fake passes the port's contract tests.
|
|
14
|
+
|
|
15
|
+
## Contract tests
|
|
16
|
+
|
|
17
|
+
A contract test states the port's contract once and runs it against every implementation.
|
|
18
|
+
|
|
19
|
+
1. Write the cases as a function or suite that takes a constructor for the implementation under test.
|
|
20
|
+
2. Cover each operation's success, each failure the contract names, and the state after a failure.
|
|
21
|
+
3. Run the suite against the fake in the ordinary test run.
|
|
22
|
+
4. Run it against each real adapter too. When the real adapter needs something external, such as an SSH server, a serial device or a database, use a local stand-in (a test server, a pseudo-terminal, a container), and mark the run so CI can provide it.
|
|
23
|
+
|
|
24
|
+
When the contract changes, the port's `Operations` change first through a delta, then the contract suite, then the fake and the adapters.
|
|
25
|
+
|
|
26
|
+
## What a fake is not
|
|
27
|
+
|
|
28
|
+
- Not a mock that returns canned answers to expected calls. It behaves like the real thing, so a test can call it in any order.
|
|
29
|
+
- Not a partial stub that fails on operations "the test doesn't use". Implement the whole port.
|
|
30
|
+
- Not a place for logic the real adapter doesn't have. If a fake needs a rule, that rule probably belongs in the domain.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-build
|
|
3
|
+
description: Builds the change bound to this branch task by task, each one test-first, checked with cruze check and committed, stopping to rethink when reality diverges from the design.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build
|
|
7
|
+
|
|
8
|
+
Build turns an approved plan into code, one task at a time. Each task starts with a failing test at the seam the plan names and ends as a green, checked commit. The design is settled, so build follows it. When the code shows the design is wrong, build stops and says so.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. **Pass the gate.** Run `cruze status --gate build` and quote its result.
|
|
13
|
+
- When it is blocked, stop, and show the reasons with the step that fixes them (`cruze next` names it).
|
|
14
|
+
- Override it only when the user explicitly asks, with `cruze status --gate build --override "<their reason>"`. The override is journaled.
|
|
15
|
+
2. **Load the standards.** Read these, and follow them for every task:
|
|
16
|
+
- `.agents/skills/cruze-behavioural-testing/SKILL.md`
|
|
17
|
+
- `.agents/skills/cruze-hexagonal-design/SKILL.md`, and its language file when one exists for the project's language
|
|
18
|
+
- `.agents/skills/cruze-dependency-approval/SKILL.md`
|
|
19
|
+
3. **Read the plan and the design.** Read the change's `change.md` and its feature's `feature.md`. Read the full body of every element the change builds, and every scenario it delivers. Read `commands:` in `.cruze/config.yaml`.
|
|
20
|
+
4. **Build each open task in order,** following the task loop below. Skip the tasks already ticked in `## Progress`.
|
|
21
|
+
5. **Finish.** When every task is ticked:
|
|
22
|
+
- Run the full test suite, the formatter and the linter, using the project's commands.
|
|
23
|
+
- Run `cruze check` and `cruze trace`, and quote their results.
|
|
24
|
+
- Commit the progress record with a message such as `chore: record progress on <change>`.
|
|
25
|
+
- Done when all of them pass.
|
|
26
|
+
|
|
27
|
+
## The task loop
|
|
28
|
+
|
|
29
|
+
For task `T<n>`:
|
|
30
|
+
|
|
31
|
+
1. **Read it.** Note its owner, its files, the IDs it proves, and the test plan rows for those IDs.
|
|
32
|
+
2. **Red.** Write the tests for the IDs it proves, at the seams the test plan names, carrying the IDs. Run them, and see them fail for the reason you expect.
|
|
33
|
+
3. **Green.** Write the least code that makes them pass, in the task's files. Code that belongs to another task waits for that task.
|
|
34
|
+
4. **Check.** Run `cruze check <the task's files>`, the formatter and the linter, and fix what they report. Run the tests the task touched, and the rest of the suite when they are quick.
|
|
35
|
+
5. **Commit** with a Conventional Commit message naming the task, such as `feat(access): console session state machine (T2)`.
|
|
36
|
+
6. **Tick it.** Run `cruze task done T<n>`, which records the commit. Its progress edit rides along in the next commit.
|
|
37
|
+
|
|
38
|
+
A task with no behaviour of its own, such as a package manifest or a plain data type, has no red step. Build it, check it, commit it and tick it, and the first task whose test uses it covers it.
|
|
39
|
+
|
|
40
|
+
Done for a task when its tests pass, `cruze check` passes for its files, the commit exists and the task is ticked.
|
|
41
|
+
|
|
42
|
+
## Deviations
|
|
43
|
+
|
|
44
|
+
The plan is design. Within a task you decide only what is local and reversible.
|
|
45
|
+
|
|
46
|
+
- **Record it and carry on** for a task-level choice: a private helper in another file of the same module, a private type, or two tasks' commits swapped for a reason. Run `cruze task deviation T<n> "<what you did and why>"`.
|
|
47
|
+
- **Stop and offer `rethink`** when the code needs any of these:
|
|
48
|
+
- a new element, port operation or scenario;
|
|
49
|
+
- a file outside the owner's module;
|
|
50
|
+
- a change to an approved scenario's behaviour, or to its test;
|
|
51
|
+
- a dependency the design doesn't name.
|
|
52
|
+
|
|
53
|
+
Explain what you found, with the evidence, and don't work around it. Completed tasks keep their commits.
|
|
54
|
+
- Never edit `feature.md`, `docs/architecture.md` or `docs/specs/` during build. Design changes go through `rethink`.
|
|
55
|
+
|
|
56
|
+
## Protecting the check
|
|
57
|
+
|
|
58
|
+
Never weaken, skip or delete a behaviour, contract or smoke test for an approved scenario, port or flow to get green. A failing one means the code is wrong, or the spec is. A wrong spec goes through `rethink`.
|
|
59
|
+
|
|
60
|
+
## Next step
|
|
61
|
+
|
|
62
|
+
`verify`, once every task is ticked and the finishing checks pass.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-dependency-approval
|
|
3
|
+
description: The rule that no dependency enters a Cruze project without the user's explicit approval, with how to ask for one and where to record it. Use when a design or plan would add a library, package, crate, framework, build or test tool, or vendored code; before editing a dependency manifest; when a build finds it needs something the design didn't name; and when reviewing a diff that changes dependency declarations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dependency approval
|
|
7
|
+
|
|
8
|
+
Every new dependency needs the user's explicit approval before it is declared or relied on. That includes runtime libraries, development and test tools, build plugins, and vendored or copied third-party code. Changing how it is acquired, such as vendoring, a git submodule or copying files, doesn't get around the rule.
|
|
9
|
+
|
|
10
|
+
## Asking
|
|
11
|
+
|
|
12
|
+
1. Establish the need: the capability, and why the standard library and the project's already-approved dependencies don't provide it.
|
|
13
|
+
2. Choose a recommendation, following `.agents/skills/cruze-research/SKILL.md`, which also says where versions come from.
|
|
14
|
+
3. Say where it will sit: the module that owns it, and the port that keeps it out of the core when it is infrastructure.
|
|
15
|
+
4. Name the realistic alternatives, including writing it yourself and what owning that code would cost. Never offer a hand-written alternative for cryptography, TLS or a security protocol.
|
|
16
|
+
5. Ask, then wait. Nothing is declared, installed or written against it until the user answers.
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
**Dependency: `russh` for SSH hops**
|
|
20
|
+
- Why not std or existing: the standard library has no SSH client, and no approved dependency provides one.
|
|
21
|
+
- Checked: <version from the registry> (released <date>), Apache-2.0, <release cadence>, pure Rust, <n> transitive crates.
|
|
22
|
+
- Sits in: ADP-access.ssh-connector, behind PORT-access.hop-connector.
|
|
23
|
+
- Alternatives: `ssh2` binds libssh2 (C, needs OpenSSL on macOS); shelling out to `ssh` loses error detail.
|
|
24
|
+
Recommended: adopt `russh`. Approve?
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## What counts as approval
|
|
28
|
+
|
|
29
|
+
- The user names the dependency ("use serde"), or approves a design whose `## Adopt or build` table or `Adopts` fact names it. Approving a feature doesn't cover a dependency its design doesn't name, so the design walkthrough lists every new dependency out loud.
|
|
30
|
+
- An approval covers the package's ordinary transitive dependencies, and later use for the same purpose in the same package or workspace member.
|
|
31
|
+
- It doesn't cover another workspace member, a different purpose, or turning on native code, a network service or new platform requirements. Ask again for those.
|
|
32
|
+
- Routine version upgrades follow the project's upgrade policy, not this rule. Point out upgrades that change licensing, platforms or behaviour.
|
|
33
|
+
- Researching, reading docs or source, and comparing options need no approval.
|
|
34
|
+
|
|
35
|
+
## Recording
|
|
36
|
+
|
|
37
|
+
- A feature or standalone change records it as a row in `## Adopt or build`: the component, `adopt`, the package, and the reason. The adapter that uses it carries an `Adopts` fact in the architecture delta.
|
|
38
|
+
- At project scope, the adapter's `Adopts` fact in `docs/architecture.md` records it, and a dependency no adapter owns, such as a test framework or a build tool, goes in the walking-skeleton change's `## Adopt or build`. A choice that is hard to reverse, such as an async runtime, a framework or a database, also gets an ADR.
|
|
39
|
+
- Choosing to build commodity functionality is also the user's call: a parser, serializer, protocol codec, CLI parser, URL or version handling, retries, compression, or date and time handling. Record it as a `build` row with the concrete reason for owning the code.
|
|
40
|
+
- When a build finds it needs a dependency the design didn't name, stop the task and ask as above. An approval changes the design, so record it through the rethink step at feature level, or at change level for a standalone change. A refusal keeps the decision open: don't add the package provisionally, and don't hand-write a replacement unless the user chooses that.
|
|
41
|
+
|
|
42
|
+
## Checking
|
|
43
|
+
|
|
44
|
+
Before a change is verified, compare the diff of every place dependencies are declared with the approvals recorded in the feature, the change and the architecture. That includes manifests such as `package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, `vcpkg.json` and `conanfile.*`, CMake `FetchContent` and `find_package` calls, `.gitmodules`, and third-party code copied into the tree.
|
|
45
|
+
|
|
46
|
+
- Every new direct dependency has a record. An unrecorded one is a blocker, even when the build passes.
|
|
47
|
+
- Lockfile churn alone isn't a new dependency.
|
|
48
|
+
- Done when you can list each new direct dependency next to the row or fact that approved it.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-domain-language
|
|
3
|
+
description: How to build the project's shared language in docs/glossary.md and use it the same way in conversation, documents, IDs and code. Use when a new domain term comes up, when the user or a document uses a vague, overloaded or conflicting word, when naming an element, ID, type, module, function or test, or when writing or reviewing the glossary.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Domain language
|
|
7
|
+
|
|
8
|
+
Use one word per concept, everywhere: in conversation, specs, the architecture, IDs and code. `docs/glossary.md` holds those words, in the format given in `.agents/skills/cruze-formats/reference/durable-docs.md`.
|
|
9
|
+
|
|
10
|
+
## While designing
|
|
11
|
+
|
|
12
|
+
1. Read the glossary before the conversation starts, and use its words in your own questions and documents.
|
|
13
|
+
2. When the user uses a term differently from the glossary, say so immediately: "The glossary defines a hop as one link in a console path, but you seem to mean the jump host itself. Which is it?"
|
|
14
|
+
3. When a word is vague or overloaded, such as account, item, session, handle or data, propose one precise term and say what it excludes.
|
|
15
|
+
4. Test a boundary between two concepts with a concrete edge case: "A device reachable over two console paths: is that one device or two?"
|
|
16
|
+
5. When the user says how something works, check the living docs and the code. Point out any contradiction instead of choosing a side.
|
|
17
|
+
6. Write a term into the glossary the moment it settles. The glossary isn't approval-gated, so adding a term never makes a design stale.
|
|
18
|
+
|
|
19
|
+
Done when every domain noun in the documents this step writes is in the glossary or is a general programming term.
|
|
20
|
+
|
|
21
|
+
## What belongs
|
|
22
|
+
|
|
23
|
+
- Terms specific to this domain. General programming concepts, such as timeout, retry or cache, stay out unless the domain gives them a special meaning.
|
|
24
|
+
- A definition says what the thing is, in one or two sentences a domain expert would accept. It never mentions types, files, tables or other implementation.
|
|
25
|
+
- Pick one word per concept and list its synonyms under `_Avoid_`.
|
|
26
|
+
- Group terms under their bounded context. A word that means different things in two contexts gets an entry in each, and the translation happens where the contexts meet.
|
|
27
|
+
|
|
28
|
+
## Using the language
|
|
29
|
+
|
|
30
|
+
- Element titles and ID names use glossary terms: `ENT-inventory.console-path`, not `ENT-inventory.route`.
|
|
31
|
+
- Types, modules, functions and tests in code use the same words, in the language's naming style: `ConsolePath` in `console_path.rs`.
|
|
32
|
+
- A word listed under `_Avoid_` in a new title, ID, type or test name is a review finding. Rename it, or settle the term with the user.
|
|
33
|
+
- When a term is renamed, update the glossary and rename element titles freely. IDs keep their old wording, because an ID never changes. Code follows through a change like any other.
|
|
34
|
+
|
|
35
|
+
## Terms and decisions
|
|
36
|
+
|
|
37
|
+
The glossary holds language, not decisions. Record decisions as `.agents/skills/cruze-grilling/SKILL.md` describes.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-envision
|
|
3
|
+
description: Decides what to build with the user, either for the whole project (problem, users, goals, non-goals, constraints, feature map and glossary) or for one feature (intent and requirements with scenarios), by grilling in rounds on the gaps.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Envision
|
|
7
|
+
|
|
8
|
+
Envision decides the what: the problem, who has it, and the behaviour that solves it. It takes whatever drafts the user brings as input, finds the gaps, and grills in rounds until the user confirms a shared understanding. Architecture, modules and code belong to `architect`.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. **Pick the scope.** It is project scope when `docs/vision.md` doesn't exist yet, or when the user asks to rework the project's goals. It is feature scope when the user names a feature. When unsure, ask. Done when you can say which.
|
|
13
|
+
2. **Gather the input.** Read what the user gave you: pasted drafts, files they point to, and notes in `.cruze/notes/`. Read whichever of `docs/vision.md`, `docs/glossary.md`, `docs/roadmap.md` and `docs/architecture.md` exist, and run `cruze status`.
|
|
14
|
+
3. **Load the standards.** Read `.agents/skills/cruze-grilling/SKILL.md` and `.agents/skills/cruze-domain-language/SKILL.md`, and follow them for the rest of this step.
|
|
15
|
+
4. **Follow the scope's procedure.** For project scope, follow [project.md](project.md). For feature scope, follow [feature.md](feature.md). Each one ends with the user's confirmation.
|
|
16
|
+
5. **Check the documents.** Run `cruze validate`. Done when it reports no errors in the documents this step wrote. At feature scope, expect one `not-designed` warning for the feature, which `architect` clears.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
|
|
20
|
+
- Write in the user's terms and the glossary's words. Behaviour is described from outside the system: what a user does and what they observe.
|
|
21
|
+
- Requirements and scenarios follow `.agents/skills/cruze-formats/reference/specs.md`. Every scenario uses concrete values: real names, real inputs, exact output. The scenarios become the tests, so their values are the expected results.
|
|
22
|
+
- Keep implementation out: no modules, types, libraries or file formats unless the user names one as a constraint. When the user raises one, record it as a constraint or a settled decision and move on.
|
|
23
|
+
- The vision stays within one page, excluding the feature map.
|
|
24
|
+
- Only the CLI writes the feature map. Use `cruze features add` and `cruze features drop`.
|
|
25
|
+
|
|
26
|
+
## Next step
|
|
27
|
+
|
|
28
|
+
- After project scope: run `architect` at project scope.
|
|
29
|
+
- After feature scope: run `architect "<feature>"`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Envision at feature scope
|
|
2
|
+
|
|
3
|
+
The result is a feature folder whose `feature.md` holds the intent, the settled decisions and the spec delta, ready for `architect`. Formats: `.agents/skills/cruze-formats/reference/work-items.md` and `.agents/skills/cruze-formats/reference/specs.md`.
|
|
4
|
+
|
|
5
|
+
1. **Check the project.** `cruze status` must show `docs/vision.md` approved. If it isn't, stop and run envision at project scope first.
|
|
6
|
+
2. **Find the feature.** Look for it in the roadmap's phases and on the feature map's future list.
|
|
7
|
+
- When it isn't in the roadmap's phases, ask the user whether it belongs in this release. If it does, add it by following "Adding an item" in `.agents/skills/cruze-roadmap/SKILL.md`, and re-approve the roadmap. If it doesn't, put it on the future list with `cruze features add` and stop here.
|
|
8
|
+
- When its `Blocked by` items haven't landed (see the roadmap's `## Status`), tell the user. Continue only if they want to design ahead, and record that as a settled decision.
|
|
9
|
+
3. **Create the folder.** When the feature has no folder yet, run `cruze new feature <slug> --title "<title>" --roadmap <slug>`, using its roadmap slug. When a folder exists, edit its `feature.md`.
|
|
10
|
+
4. **Read the behaviour it touches.** Read the specs in `docs/specs/` for every capability the feature changes, so you know each requirement and scenario it builds on.
|
|
11
|
+
5. **List the open decisions:**
|
|
12
|
+
- **Intent:** the problem and outcome in the user's words, who it is for, the constraints, and what is out of scope.
|
|
13
|
+
- **Requirements:** each behaviour the feature adds, changes or removes, and the capability it belongs to. It goes in an existing capability when the behaviour fits one; otherwise it starts a new capability.
|
|
14
|
+
- **Scenarios:** for each requirement, the main case, each edge and failure case a user will meet, and what they observe in each. Invent concrete edge cases to test the boundaries.
|
|
15
|
+
6. **Grill in rounds** until every open decision is settled. Record decisions under `## Settled decisions` and terms in the glossary as they settle.
|
|
16
|
+
7. **Write the spec delta.** Use `ADDED` for new requirements, `MODIFIED` for a requirement whose text or scenarios change (writing its full new body with every scenario it keeps), `REMOVED` with a `Reason` and `Migration` for retired behaviour, and `ADDED CAPABILITY` for a new capability.
|
|
17
|
+
- Name every ID with glossary terms. An ID is never reused.
|
|
18
|
+
- Done when every requirement has a scenario for its main case and one for each failure a user can meet.
|
|
19
|
+
8. **Leave the design to architect.** Set `## Architecture delta` to `None.` and leave the Changes table with its header row only. Remove the remaining template guides.
|
|
20
|
+
9. **Confirm.** Summarize the intent and each requirement with its scenarios, in plain words, and ask the user to confirm them. Apply any corrections.
|
|
21
|
+
|
|
22
|
+
Done when the user has confirmed, `cruze validate` reports no errors for the feature, only its `not-designed` warning, and the feature is committed.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Envision at project scope
|
|
2
|
+
|
|
3
|
+
The result is an approved `docs/vision.md` and a `docs/glossary.md` holding the terms that settled. Formats: `.agents/skills/cruze-formats/reference/durable-docs.md`.
|
|
4
|
+
|
|
5
|
+
1. **Create the documents.** Run `cruze new vision` and `cruze new glossary` for whichever doesn't exist yet. When the vision exists and you are reworking it, edit it in place. Bounded contexts don't exist yet, so group the glossary's terms under one `##` heading naming the product's domain, such as `## Console access`. `architect` regroups them by context.
|
|
6
|
+
2. **Draft from the input.** Fill every section you can from what the user already gave you, and mark every guess as a question for step 3.
|
|
7
|
+
3. **List the open decisions,** section by section:
|
|
8
|
+
- **Problem:** the problem in the user's words, and who feels it.
|
|
9
|
+
- **Users:** each kind of user and the situation they are in.
|
|
10
|
+
- **Goals:** each goal as a `GOAL-<name>` row, with a measure that says how you would know it's met. A goal without a measure is still open.
|
|
11
|
+
- **Non-goals:** what the product deliberately doesn't do, and why. Ask about the tempting neighbours of each goal.
|
|
12
|
+
- **Constraints:** platforms, the implementation language, dependency policy, performance, security, privacy, licensing and legal limits.
|
|
13
|
+
- **Feature map:** the capabilities that deliver the goals, each a slug with a one-line summary and the goals it serves. They are what later `envision "<feature>"` runs pick up.
|
|
14
|
+
4. **Grill in rounds** until every open decision is settled, following the grilling skill. As each domain term settles, add it to the glossary.
|
|
15
|
+
5. **Write the vision.** Fill each section, and remove every template guide.
|
|
16
|
+
6. **Fill the feature map.** For each capability, run `cruze features add <slug> --summary "<summary>" --goals <GOAL IDs>`. Put command syntax in backticks, such as `` `consolectl console <device>` ``, so it isn't read as a template guide. Running `add` again for the same slug replaces its entry in place. Done when every goal is served by at least one feature on the map.
|
|
17
|
+
7. **Confirm.** Walk the user through the vision in one short summary: the problem, the goals with their measures, the non-goals, the constraints, and the feature map. Ask whether it matches their understanding, and apply any corrections.
|
|
18
|
+
8. **Approve.** When the user approves, run `cruze approve vision` and quote its result. Commit, with a message such as `docs: envision the project`.
|
|
19
|
+
|
|
20
|
+
Done when `cruze status` shows `docs/vision.md` approved and the glossary holds every domain term the vision uses.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-explore
|
|
3
|
+
description: Thinks an idea through with the user before any design, comparing options and sketching flows, and writes nothing until the user asks to capture it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Explore
|
|
7
|
+
|
|
8
|
+
Explore is the optional thinking partner that can come before any other Cruze step. It turns a loose idea into clear options and, when the user wants, a captured note that the next step takes as input. It never writes a design, creates work or records an approval.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. **Frame the problem.** Ask what prompted the idea, who it affects, and what outcome would make it worthwhile. If the user starts from a solution, restate the problem underneath it and confirm it. Done when you can state the problem in one sentence the user agrees with.
|
|
13
|
+
2. **Read what exists.** Read whichever of these exist: `docs/vision.md`, `docs/glossary.md`, `docs/architecture.md`, `docs/roadmap.md`, and the code the idea touches. Run `cruze status` to see work in flight. Use the glossary's words from here on, following `.agents/skills/cruze-domain-language/SKILL.md`.
|
|
14
|
+
3. **Separate facts from guesses.** List what is known evidence, what is a hypothesis, and what is a preference. Look up any fact you can rather than asking the user for it.
|
|
15
|
+
4. **Diverge.** Lay out two to four genuinely different approaches, including leaving things as they are when that is credible. For each, give what it changes, what it leaves alone, its benefits, its costs and failure modes, the assumptions it rests on, and what evidence would tell it apart from the others. Sketch an interaction as a Mermaid `sequenceDiagram` or `flowchart` when that makes a difference clearer.
|
|
16
|
+
5. **Converge.** Compare the strongest options against the user's outcome, the vision's goals and constraints, and the architecture. Challenge assumptions and accidental scope growth, following the challenge rules in `.agents/skills/cruze-grilling/SKILL.md`. Recommend one option only when its trade-offs are understood. Otherwise recommend the smallest step that would settle the question, such as a spike, a measurement or a research question.
|
|
17
|
+
6. **Offer to capture.** Summarize the problem, the options, the trade-offs, your recommendation and the open questions, then ask whether to capture them. When the user declines, stop here: the discussion itself was the result.
|
|
18
|
+
|
|
19
|
+
## Capturing
|
|
20
|
+
|
|
21
|
+
Only when the user says to capture:
|
|
22
|
+
|
|
23
|
+
1. Run `cruze new note <slug> --title "<title>"` and write the note at the path it returns.
|
|
24
|
+
2. Give the note these sections: `## Problem`, `## Options`, `## Recommendation` and `## Open questions`. Mark each statement as fact, hypothesis, preference or recommendation.
|
|
25
|
+
3. Done when the note stands on its own for a reader who wasn't in the conversation.
|
|
26
|
+
|
|
27
|
+
## Handing off
|
|
28
|
+
|
|
29
|
+
Name the next step, and pass the note's path to it when there is one:
|
|
30
|
+
|
|
31
|
+
| The idea is | Next step |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| A new project, or the project's first vision | `envision`, at project scope |
|
|
34
|
+
| A new capability whose requirements aren't settled | `envision "<feature>"` |
|
|
35
|
+
| A capability whose requirements are settled | `architect "<feature>"` |
|
|
36
|
+
| A small change to existing behaviour | `architect "<tweak>"` |
|
|
37
|
+
| A defect in built behaviour | `triage "<symptom>"` |
|
|
38
|
+
| A decision already made that now looks wrong | `rethink` |
|
|
39
|
+
| Not worth doing now | `cruze features add <slug> --summary <text> --goals <ids>`, with the user's agreement, to keep it on the future list |
|