@printpractical/cruze 0.0.8 → 0.0.10

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 (152) hide show
  1. package/README.md +17 -13
  2. package/dist/adapters/inbound/cli/cli_context.js +6 -0
  3. package/dist/adapters/inbound/cli/commands/code.js +2 -1
  4. package/dist/adapters/inbound/cli/commands/diff.js +23 -0
  5. package/dist/adapters/inbound/cli/commands/documents.js +1 -1
  6. package/dist/adapters/inbound/cli/commands/show.js +72 -3
  7. package/dist/adapters/inbound/cli/commands/status.js +7 -3
  8. package/dist/adapters/inbound/cli/commands.js +9 -3
  9. package/dist/adapters/inbound/cli/parse_command.js +8 -0
  10. package/dist/adapters/outbound/git_repository.js +49 -7
  11. package/dist/adapters/outbound/project_root.js +13 -0
  12. package/dist/app/ports/repository.js +4 -0
  13. package/dist/app/use_cases/approve_artifact.js +18 -10
  14. package/dist/app/use_cases/check_code.js +5 -3
  15. package/dist/app/use_cases/journal_events.js +6 -2
  16. package/dist/app/use_cases/new_project_doc.js +10 -2
  17. package/dist/app/use_cases/project_status.js +4 -1
  18. package/dist/app/use_cases/run_review.js +10 -2
  19. package/dist/app/use_cases/show_elements.js +18 -0
  20. package/dist/app/use_cases/show_notes.js +11 -0
  21. package/dist/app/use_cases/show_scope.js +17 -1
  22. package/dist/app/use_cases/upstream_diff.js +55 -0
  23. package/dist/domain/approvals/rebase.js +39 -0
  24. package/dist/domain/approvals/upstream_text.js +36 -0
  25. package/dist/domain/check/budget_text.js +43 -6
  26. package/dist/domain/check/check_source.js +20 -3
  27. package/dist/domain/check/decision_comments.js +38 -0
  28. package/dist/domain/config.js +12 -0
  29. package/dist/domain/decision_citations.js +62 -0
  30. package/dist/domain/edits/agents_file.js +15 -1
  31. package/dist/domain/ids.js +3 -1
  32. package/dist/domain/journal.js +16 -3
  33. package/dist/domain/land/merge_plan.js +7 -2
  34. package/dist/domain/line_diff.js +56 -0
  35. package/dist/domain/project/element_lookup.js +124 -0
  36. package/dist/domain/project/living_model.js +2 -1
  37. package/dist/domain/project/notes.js +74 -0
  38. package/dist/domain/project/scope_view.js +20 -4
  39. package/dist/domain/skill_budget.js +36 -0
  40. package/dist/domain/status/next_step.js +52 -7
  41. package/dist/domain/status/pending_rethink.js +22 -0
  42. package/dist/domain/status/verification.js +12 -0
  43. package/dist/domain/status/work_status.js +17 -2
  44. package/dist/domain/validation/decision_rules.js +76 -0
  45. package/dist/domain/validation/delta_rules.js +2 -0
  46. package/dist/domain/validation/future_rules.js +40 -0
  47. package/dist/domain/validation/living_rules.js +2 -0
  48. package/dist/domain/validation/plan_rules.js +1 -1
  49. package/dist/domain/validation/validate_project.js +4 -0
  50. package/dist/domain/validation/vision_rules.js +41 -0
  51. package/dist/domain/versions/rule_versions.js +3 -0
  52. package/dist/main.js +8 -4
  53. package/package.json +1 -1
  54. package/skills/architect/SKILL.md +6 -2
  55. package/skills/architect/feature.md +6 -4
  56. package/skills/architect/project.md +2 -2
  57. package/skills/behavioural-testing/SKILL.md +3 -2
  58. package/skills/behavioural-testing/fakes.md +3 -3
  59. package/skills/build/SKILL.md +3 -2
  60. package/skills/envision/SKILL.md +3 -2
  61. package/skills/envision/feature.md +3 -1
  62. package/skills/envision/intake.md +28 -0
  63. package/skills/envision/possibilities.md +13 -0
  64. package/skills/envision/project.md +5 -3
  65. package/skills/explore/SKILL.md +2 -2
  66. package/skills/formats/SKILL.md +13 -2
  67. package/skills/formats/reference/architecture.md +8 -4
  68. package/skills/formats/reference/config.md +9 -4
  69. package/skills/formats/reference/durable-docs.md +4 -1
  70. package/skills/formats/reference/work-items.md +1 -1
  71. package/skills/formats/templates/vision.md +12 -0
  72. package/skills/grilling/SKILL.md +10 -0
  73. package/skills/hexagonal-design/SKILL.md +2 -2
  74. package/skills/hexagonal-design/languages/rust.md +2 -1
  75. package/skills/hexagonal-design/runtime.md +1 -0
  76. package/skills/land/SKILL.md +6 -2
  77. package/skills/plan/SKILL.md +15 -5
  78. package/skills/plan/tasks.md +4 -4
  79. package/skills/realign/SKILL.md +5 -3
  80. package/skills/realign/notes/0.0.10.md +131 -0
  81. package/skills/realign/notes/0.0.2.md +1 -1
  82. package/skills/realign/notes/0.0.6.md +1 -1
  83. package/skills/realign/notes/0.0.8.md +2 -2
  84. package/skills/realign/notes/0.0.9.md +59 -0
  85. package/skills/realign/notes.md +2 -0
  86. package/skills/research/SKILL.md +3 -2
  87. package/skills/rethink/SKILL.md +6 -4
  88. package/skills/rethink/levels.md +8 -8
  89. package/skills/roadmap/SKILL.md +2 -1
  90. package/skills/roles/SKILL.md +4 -4
  91. package/skills/roles/auditor.md +1 -1
  92. package/skills/roles/code-reviewer.md +5 -4
  93. package/skills/roles/design-reviewer.md +5 -29
  94. package/skills/roles/design-rubric.md +40 -0
  95. package/skills/roles/plan-rubric.md +11 -0
  96. package/skills/roles/surveyor.md +3 -2
  97. package/skills/roles/verifier.md +2 -0
  98. package/skills/triage/SKILL.md +1 -1
  99. package/skills/verify/SKILL.md +3 -3
  100. package/src/adapters/inbound/cli/cli_context.ts +6 -0
  101. package/src/adapters/inbound/cli/commands/code.ts +2 -1
  102. package/src/adapters/inbound/cli/commands/diff.ts +23 -0
  103. package/src/adapters/inbound/cli/commands/documents.ts +1 -1
  104. package/src/adapters/inbound/cli/commands/show.ts +72 -3
  105. package/src/adapters/inbound/cli/commands/status.ts +7 -3
  106. package/src/adapters/inbound/cli/commands.ts +9 -3
  107. package/src/adapters/inbound/cli/parse_command.ts +8 -0
  108. package/src/adapters/outbound/git_repository.ts +49 -7
  109. package/src/adapters/outbound/project_root.ts +13 -0
  110. package/src/app/ports/repository.ts +4 -0
  111. package/src/app/use_cases/approve_artifact.ts +18 -10
  112. package/src/app/use_cases/check_code.ts +5 -3
  113. package/src/app/use_cases/journal_events.ts +6 -2
  114. package/src/app/use_cases/new_project_doc.ts +10 -2
  115. package/src/app/use_cases/project_status.ts +4 -1
  116. package/src/app/use_cases/run_review.ts +10 -2
  117. package/src/app/use_cases/show_elements.ts +18 -0
  118. package/src/app/use_cases/show_notes.ts +11 -0
  119. package/src/app/use_cases/show_scope.ts +17 -1
  120. package/src/app/use_cases/upstream_diff.ts +55 -0
  121. package/src/domain/approvals/rebase.ts +39 -0
  122. package/src/domain/approvals/upstream_text.ts +36 -0
  123. package/src/domain/check/budget_text.ts +43 -6
  124. package/src/domain/check/check_source.ts +20 -3
  125. package/src/domain/check/decision_comments.ts +38 -0
  126. package/src/domain/config.ts +12 -0
  127. package/src/domain/decision_citations.ts +62 -0
  128. package/src/domain/edits/agents_file.ts +15 -1
  129. package/src/domain/ids.ts +3 -1
  130. package/src/domain/journal.ts +16 -3
  131. package/src/domain/land/merge_plan.ts +7 -2
  132. package/src/domain/line_diff.ts +56 -0
  133. package/src/domain/project/element_lookup.ts +124 -0
  134. package/src/domain/project/living_model.ts +2 -1
  135. package/src/domain/project/notes.ts +74 -0
  136. package/src/domain/project/scope_view.ts +20 -4
  137. package/src/domain/skill_budget.ts +36 -0
  138. package/src/domain/status/next_step.ts +52 -7
  139. package/src/domain/status/pending_rethink.ts +22 -0
  140. package/src/domain/status/verification.ts +12 -0
  141. package/src/domain/status/work_status.ts +17 -2
  142. package/src/domain/validation/decision_rules.ts +76 -0
  143. package/src/domain/validation/delta_rules.ts +2 -0
  144. package/src/domain/validation/future_rules.ts +40 -0
  145. package/src/domain/validation/living_rules.ts +2 -0
  146. package/src/domain/validation/plan_rules.ts +1 -1
  147. package/src/domain/validation/validate_project.ts +4 -0
  148. package/src/domain/validation/vision_rules.ts +41 -0
  149. package/src/domain/versions/rule_versions.ts +3 -0
  150. package/src/main.ts +8 -4
  151. package/templates/init/AGENTS.md +1 -1
  152. package/templates/init/config.yaml +5 -4
@@ -0,0 +1,76 @@
1
+ import { definedDecisions, findDecisionCitations, workItemSlugs, } from "../decision_citations.js";
2
+
3
+ import { findSection, } from "../markdown.js";
4
+ import { readDelta } from "../project/deltas.js";
5
+ import { PATHS } from "../project/layout.js";
6
+
7
+
8
+ import { warning, } from "./problem.js";
9
+
10
+ const INSTEAD = "write what it decided into this text, or cite the ADR that records it";
11
+
12
+ /**
13
+ * The architecture cites only the decisions its own `## Decisions` defines. The other living docs
14
+ * cite none by number, and no living doc cites a feature's or change's, which is archived when it finishes.
15
+ */
16
+ export function livingDecisionProblems(view ) {
17
+ const slugs = slugsOf(view);
18
+ const project = projectDecisions(view);
19
+ const problems = [];
20
+ for (const [path, doc] of view.living.docs) {
21
+ for (const citation of citationsIn(doc, slugs)) {
22
+ if (citation.qualifier !== undefined) {
23
+ problems.push(warning(path, citation.line, "decision-citation", `cites ${citation.text}, a decision of ${citation.qualifier}, which the living docs don't hold; ${INSTEAD}`));
24
+ } else if (path !== PATHS.architecture) {
25
+ problems.push(warning(path, citation.line, "decision-citation", `cites ${citation.text}, but only the architecture cites decisions by number, its own; ${INSTEAD}`));
26
+ } else {
27
+ const unknown = citation.numbers.filter((n) => !project.has(n));
28
+ if (unknown.length > 0) {
29
+ problems.push(warning(path, citation.line, "decision-citation", `cites ${unknown.map((n) => `D${n}`).join(", ")}, which "## Decisions" doesn't define; ${INSTEAD}`));
30
+ }
31
+ }
32
+ }
33
+ }
34
+ return problems;
35
+ }
36
+
37
+ /**
38
+ * A delta's elements merge into the living docs, where the work's own decisions don't follow them.
39
+ * They may cite a project decision the work doesn't renumber, or one the living element already cites.
40
+ */
41
+ export function deltaDecisionProblems(view , item ) {
42
+ const slugs = slugsOf(view);
43
+ const project = projectDecisions(view);
44
+ const local = definedDecisions(sectionLines(item.doc, "Settled decisions"));
45
+ const problems = [];
46
+ for (const { element } of readDelta(item.doc).entries) {
47
+ const living = view.living.elements.get(element.id);
48
+ const carried = new Set(living === undefined ? [] : citationsIn(living.doc, slugs, living.element).flatMap((c) => (c.qualifier === undefined ? c.numbers : [])));
49
+ const allowed = (n ) => project.has(n) && (!local.has(n) || carried.has(n));
50
+ for (const citation of citationsIn(item.doc, slugs, element)) {
51
+ if (citation.qualifier === undefined && citation.numbers.every(allowed)) continue;
52
+ problems.push(warning(item.path, citation.line, "decision-citation", `${element.id} cites ${citation.text}, which won't mean the same in the living docs once this delta merges; ${INSTEAD}`));
53
+ }
54
+ }
55
+ return problems;
56
+ }
57
+
58
+ function citationsIn(doc , slugs , element ) {
59
+ const from = element === undefined ? doc.bodyStart : element.start + 1;
60
+ const to = element === undefined ? doc.lines.length : element.end;
61
+ return findDecisionCitations(doc.lines, slugs, (line) => line < from || line >= to || doc.inFence[line] === true || doc.inManaged[line] === true);
62
+ }
63
+
64
+ function projectDecisions(view ) {
65
+ const architecture = view.living.docs.get(PATHS.architecture);
66
+ return architecture === undefined ? new Set() : definedDecisions(sectionLines(architecture, "Decisions"));
67
+ }
68
+
69
+ function sectionLines(doc , title ) {
70
+ const range = findSection(doc, title);
71
+ return range === null ? [] : doc.lines.slice(range.start, range.end);
72
+ }
73
+
74
+ function slugsOf(view ) {
75
+ return workItemSlugs(view.items.map((item) => item.folderName));
76
+ }
@@ -4,6 +4,7 @@ import { specPath } from "../project/layout.js";
4
4
  import { orphanDeltaElements, readDelta, } from "../project/deltas.js";
5
5
 
6
6
 
7
+ import { deltaDecisionProblems } from "./decision_rules.js";
7
8
  import { elementProblems } from "./element_rules.js";
8
9
  import { error, } from "./problem.js";
9
10
 
@@ -44,6 +45,7 @@ export function deltaProblems(view , item ) {
44
45
  problems.push(error(path, op.start, "capability-exists", `capability ${op.capability} already has ${specPath(op.capability)}`));
45
46
  }
46
47
  }
48
+ problems.push(...deltaDecisionProblems(view, item));
47
49
  return problems;
48
50
  }
49
51
 
@@ -0,0 +1,40 @@
1
+ import { factsOf, headingElements } from "../elements.js";
2
+ import { readRows } from "../edits/managed_tables.js";
3
+ import { findIds, kindOf } from "../ids.js";
4
+
5
+ import { PATHS } from "../project/layout.js";
6
+ import { readDelta } from "../project/deltas.js";
7
+
8
+ import { readRoadmapItems } from "../project/roadmap.js";
9
+ import { warning, } from "./problem.js";
10
+
11
+ /**
12
+ * A `Future` fact keeps room for a need someone stated: a `LATER` capability of the vision, or a
13
+ * feature on the feature map or the roadmap. One that names neither reserves room for a need nobody
14
+ * stated, which the design reviewer treats as a finding; this makes it visible without a review.
15
+ */
16
+ export function futureProblems(view ) {
17
+ const slugs = anchorSlugs(view);
18
+ const unanchored = (text ) =>
19
+ !findIds(text).some((id) => kindOf(id) === "LATER") && ![...slugs].some((slug) => new RegExp(`(^|[^a-z0-9-])${slug}([^a-z0-9-]|$)`).test(text));
20
+ const check = (path , doc , from = 0, to = doc.lines.length) =>
21
+ headingElements(doc, from, to).flatMap((element) =>
22
+ (factsOf(doc, element).get("Future") ?? [])
23
+ .filter(unanchored)
24
+ .map(() => warning(path, element.start, "future-unanchored", `${element.id} keeps room for a need its Future fact doesn't name; cite the LATER capability, or the feature on the map or roadmap, that it serves`)),
25
+ );
26
+ const living = view.living.docs.get(PATHS.architecture);
27
+ const deltas = view.items
28
+ .filter((item) => !item.archived && item.kind !== "change")
29
+ .flatMap((item) => readDelta(item.doc).entries.flatMap((entry) => check(item.path, item.doc, entry.element.start, entry.element.end)));
30
+ return [...(living === undefined ? [] : check(PATHS.architecture, living)), ...deltas];
31
+ }
32
+
33
+ /** Feature slugs a Future fact may name: the feature map's, implemented or future, and the roadmap's items. */
34
+ function anchorSlugs(view ) {
35
+ const vision = view.snapshot.get(PATHS.vision) ?? "";
36
+ const roadmap = view.snapshot.get(PATHS.roadmap);
37
+ const mapped = ["Implemented", "Future"].flatMap((heading) => readRows(vision, heading).map((row) => row[0] ?? ""));
38
+ const planned = roadmap === undefined ? [] : readRoadmapItems(roadmap).map((item) => item.slug);
39
+ return new Set([...mapped, ...planned].map((slug) => slug.trim()).filter((slug) => /^[a-z0-9-]+$/.test(slug)));
40
+ }
@@ -4,6 +4,7 @@ import { findIds, scopeOf, STATUS_KINDS } from "../ids.js";
4
4
 
5
5
  import { PATHS } from "../project/layout.js";
6
6
 
7
+ import { livingDecisionProblems } from "./decision_rules.js";
7
8
  import { elementProblems } from "./element_rules.js";
8
9
  import { error, warning, } from "./problem.js";
9
10
 
@@ -26,6 +27,7 @@ export function livingProblems(view ) {
26
27
  if (!view.living.elements.has(id)) problems.push(error(path, lineOf(text, id), "unknown-id", `${id} is cited but not defined in the living docs`));
27
28
  }
28
29
  }
30
+ problems.push(...livingDecisionProblems(view));
29
31
  return problems;
30
32
  }
31
33
 
@@ -46,7 +46,7 @@ export function changePlanProblems(
46
46
  if (kindOf(id) === "MOD") {
47
47
  const modulePaths = modulePathsOf(view, delta.doc, delta.delta, id);
48
48
  if (!taskPaths.some((p) => modulePaths.some((m) => p.startsWith(m)))) {
49
- problems.push(error(path, scope.line, "unproved-scope", `${id} is in scope but no task writes inside ${modulePaths.join(" or ") || "its path"}`));
49
+ problems.push(error(path, scope.line, "unproved-scope", `${id} is in scope but no task writes inside ${modulePaths.join(" or ") || "its path"}; a module that owns other files, such as a build script, lists each under its Path`));
50
50
  }
51
51
  } else if (kindOf(id) === "REQ") {
52
52
  const scenarios = delta.delta.entries.find((e) => e.element.id === id)?.scenarios.map((s) => s.id) ?? [];
@@ -1,7 +1,9 @@
1
1
 
2
+ import { futureProblems } from "./future_rules.js";
2
3
  import { livingProblems } from "./living_rules.js";
3
4
  import { error, sortProblems, } from "./problem.js";
4
5
  import { configProblems, readmeProblems, roadmapProblems, templateLeftovers } from "./project_rules.js";
6
+ import { visionProblems } from "./vision_rules.js";
5
7
  import { workItemProblems } from "./work_item_rules.js";
6
8
 
7
9
  /** Every rule in the cruze-formats skill, applied to the whole project. */
@@ -13,6 +15,8 @@ export function validateProject(view ) {
13
15
  return sortProblems([
14
16
  ...configProblems(view),
15
17
  ...livingProblems(view),
18
+ ...visionProblems(view),
19
+ ...futureProblems(view),
16
20
  ...roadmapProblems(view),
17
21
  ...workItemProblems(view),
18
22
  ...templateLeftovers(view),
@@ -0,0 +1,41 @@
1
+ import { rowElements } from "../elements.js";
2
+ import { findSection } from "../markdown.js";
3
+ import { splitRow } from "../markdown_tables.js";
4
+ import { PATHS } from "../project/layout.js";
5
+
6
+ import { error, } from "./problem.js";
7
+
8
+ /** The section and the cells after the ID that each long-term row of the vision holds. */
9
+ const INTENT_ROWS = {
10
+ PRINCIPLE: { section: "Principles", cells: ["Principle", "Why"] },
11
+ LATER: { section: "Must stay possible", cells: ["Capability", "Likelihood", "Why", "Leave room for"] },
12
+ };
13
+
14
+ export const LIKELIHOODS = ["likely", "possible"];
15
+
16
+ /**
17
+ * The vision's principles and the capabilities that must stay possible are rows, so designs cite
18
+ * them and approvals pin them. One project kept its principles in a seed note and its long-term
19
+ * plans in the user's head: a feature reversed a principle unnoticed, and a later review proposed
20
+ * removing what those plans needed.
21
+ */
22
+ export function visionProblems(view ) {
23
+ const doc = view.living.docs.get(PATHS.vision);
24
+ if (doc === undefined) return [];
25
+ return rowElements(doc).flatMap((row) => {
26
+ const shape = INTENT_ROWS[row.kind];
27
+ if (shape === undefined) return [];
28
+ const section = findSection(doc, shape.section);
29
+ if (section === null || row.start < section.start || row.start >= section.end) {
30
+ return [error(PATHS.vision, row.start, "vision-row", `${row.id} belongs in the table under ## ${shape.section}`)];
31
+ }
32
+ const cells = splitRow(doc.lines[row.start] ?? "").slice(1);
33
+ if (cells.length !== shape.cells.length || cells.some((cell) => cell === "")) {
34
+ return [error(PATHS.vision, row.start, "vision-row", `${row.id} needs ${shape.cells.join(", ")}, each filled`)];
35
+ }
36
+ if (row.kind === "LATER" && !LIKELIHOODS.includes(cells[1] ?? "")) {
37
+ return [error(PATHS.vision, row.start, "vision-row", `${row.id}'s likelihood must be ${LIKELIHOODS.join(" or ")}`)];
38
+ }
39
+ return [];
40
+ });
41
+ }
@@ -17,6 +17,9 @@ export const RULE_SINCE = {
17
17
  "validate:change-too-large": "0.0.5",
18
18
  "validate:plan-too-large": "0.0.5",
19
19
  "validate:module-path-glob": "0.0.8",
20
+ "validate:decision-citation": "0.0.10",
21
+ "check:decision-citation": "0.0.10",
22
+ "validate:future-unanchored": "0.0.10",
20
23
  };
21
24
 
22
25
  /** Whether a rule arrived after the version the project's code meets, so it waits for `realign`. */
package/dist/main.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  // Composition root: the only place that constructs adapters.
3
- import { basename } from "node:path";
3
+ import { basename, relative } from "node:path";
4
4
  import { runCli } from "./adapters/inbound/cli/run_cli.js";
5
5
  import { GitRepository } from "./adapters/outbound/git_repository.js";
6
6
  import { NodeProjectFiles } from "./adapters/outbound/node_project_files.js";
7
7
  import { PackageBundle } from "./adapters/outbound/package_bundle.js";
8
+ import { findProjectRoot } from "./adapters/outbound/project_root.js";
8
9
  import { ProcessAgentRunner } from "./adapters/outbound/process_agent_runner.js";
9
10
  import { SystemClock } from "./adapters/outbound/system_clock.js";
10
11
  import { DefaultAnswerPrompter, TerminalPrompter } from "./adapters/outbound/terminal_prompter.js";
@@ -16,18 +17,21 @@ process.stdout.on("error", (error ) => {
16
17
  });
17
18
 
18
19
  const cwd = process.cwd();
20
+ // Every command but init works on the project that holds the working directory, so it runs from any subdirectory.
21
+ const root = process.argv[2] === "init" ? cwd : (findProjectRoot(cwd) ?? cwd);
19
22
  const exitCode = await runCli(
20
23
  process.argv.slice(2),
21
24
  {
22
- files: new NodeProjectFiles(cwd),
25
+ files: new NodeProjectFiles(root),
23
26
  bundle: await PackageBundle.locate(),
24
27
  clock: new SystemClock(),
25
- repository: new GitRepository(cwd),
28
+ repository: new GitRepository(root),
26
29
  interactivePrompter: new TerminalPrompter(),
27
30
  unattendedPrompter: new DefaultAnswerPrompter(),
28
- runner: new ProcessAgentRunner(cwd),
31
+ runner: new ProcessAgentRunner(root),
29
32
  interactive: process.stdin.isTTY === true,
30
33
  directoryName: basename(cwd),
34
+ workingDirectory: relative(root, cwd).split("\\").join("/"),
31
35
  },
32
36
  {
33
37
  stdout: (text) => process.stdout.write(`${text}\n`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@printpractical/cruze",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Spec-driven development for coding agents: one living model of the system, small deltas, convergent review.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Chris Buchter",
@@ -15,7 +15,7 @@ Architect decides the how and the how big. It designs the domain, the ports and
15
15
  - **Tweak scope:** the user asks for a small change to existing behaviour. When the design shows it needs any architecture change, it becomes a feature: say so and continue at feature scope.
16
16
  - Done when you can say which, and why.
17
17
  2. **Check what it builds on.** Run `cruze status`. `docs/vision.md` must be approved and current. At feature and tweak scope, `docs/architecture.md` must be approved and current as well. When a document isn't, stop and name the step that fixes it: `envision` for the vision, and `rethink` for an architecture that changed since its approval.
18
- 3. **Read the living model.** Read `docs/vision.md`, `docs/glossary.md`, `docs/architecture.md`, the ADRs in `docs/adr/`, `docs/roadmap.md`, `.cruze/config.yaml`, and the specs and code the work touches. Read any note in `.cruze/notes/` the user points to.
18
+ 3. **Read the living model.** Read `docs/vision.md`, `docs/glossary.md`, `docs/architecture.md` as "Reading it" in `.agents/skills/cruze-formats/reference/architecture.md` says, the ADRs in `docs/adr/`, `docs/roadmap.md`, `.cruze/config.yaml`, and the specs and code the work touches. Take up the notes and the parts of the user's input handed to this work, as "Taking up a hand-off later" in `.agents/skills/cruze-envision/intake.md` describes: at project scope, `cruze show --notes architect`, `cruze show --notes roadmap` and `cruze show --notes project`; at feature or tweak scope, the Notes section of `cruze show <feature>`. Read any other note the user points to.
19
19
  4. **Load the standards.** Read these, and follow them for the rest of this step:
20
20
  - `.agents/skills/cruze-hexagonal-design/SKILL.md`
21
21
  - `.agents/skills/cruze-grilling/SKILL.md`
@@ -31,8 +31,10 @@ Architect decides the how and the how big. It designs the domain, the ports and
31
31
  ## Rules
32
32
 
33
33
  - **Design for the roadmap, build for the phase.** Read the whole feature map and roadmap. When a later feature will need a seam, name it now in a `Future` fact, such as "transport will gain MQTT in phase 3, so inbound adapters stay behind `CommandSource`". Build only what the current work needs.
34
+ - **Answer to the vision's long-term intent.** Read `## Principles` and `## Must stay possible` in `docs/vision.md`. Every design follows each principle. Check the design against every `LATER` row, not only those in its area: nothing in it may rule one out. Where the design touches a capability's area, leave the room its row names, in a `Future` fact that cites its ID, and build nothing for it. A design that would depart from a principle or close off a capability goes to the user first, as "Long-term intent" in `.agents/skills/cruze-grilling/SKILL.md` describes.
34
35
  - **Adopt before you build.** Before designing any component that isn't domain logic, run the researcher role from `.agents/skills/cruze-roles/SKILL.md` on it. Record every decision in `## Adopt or build`, or at project scope in the adapter's `Adopts` fact. Every new dependency goes to the user through the dependency-approval skill.
35
- - **Every element with code has a home.** Each `ENT`, `UC`, `PORT`, `ADP` and `FLOW` names its `Module` and `File`. Each file has one responsibility and fits the budget in `.cruze/config.yaml`.
36
+ - **Every element with code has a home.** Each `ENT`, `UC`, `PORT`, `ADP` and `FLOW` names its `Module` and `File`. Each file has one responsibility. Never split an owner across files to keep them short.
37
+ - **Comply with the references.** When the project must follow an external document, such as a protocol specification, it is listed under `references:` in `.cruze/config.yaml`; at project scope, ask the user whether there is one, and list it with what it governs. Read the parts each element relies on, and cite the section in the element's body, such as `RFC 4254 §5.2`, so plan, build and the reviewers can check it.
36
38
  - **Ask, challenge and defer** as the grilling skill describes. Contexts, ports, public contracts, dependency direction and dependencies are always the user's decisions.
37
39
  - **Stepping back is normal.** When the design shows that the vision or an earlier decision is wrong, stop and say so. The vision changes through `envision`, and an approved architecture through `rethink`.
38
40
 
@@ -42,4 +44,6 @@ Architect decides the how and the how big. It designs the domain, the ports and
42
44
  - Feature scope: `plan` for the feature's first change.
43
45
  - Tweak scope: `plan` for the standalone change.
44
46
 
47
+ Plan branches from main, so get the approved design onto main first, as a pull request or a merge, together with the vision or feature map it builds on. A plan branched from an unmerged design branch carries the design into the change's pull request.
48
+
45
49
  Start it in a new session, so its context starts empty.
@@ -9,15 +9,17 @@ The result is a `feature.md` with a complete architecture delta and an ordered l
9
9
 
10
10
  ## Design the delta
11
11
 
12
- 3. **Trace each scenario through the model.** For every scenario in the spec delta, name the inbound adapter it enters through, the use case that runs it, the domain elements that decide it, and the ports it crosses. Done when every scenario has a path, and each missing piece is a named gap.
12
+ 3. **Trace each scenario through the model.** Find the elements with `cruze show --index`, and read each one the path crosses with `cruze show <ID>`. For every scenario in the spec delta, name the inbound adapter it enters through, the use case that runs it, the domain elements that decide it, and the ports it crosses. Done when every scenario has a path, and each missing piece is a named gap.
13
13
  4. **Place each gap,** following "Placing an owner" in the hexagonal-design skill. Prefer extending an existing element when it is the right owner. Each change to the living model becomes an operation under `## Architecture delta`:
14
14
  - `ADDED` for a new element, with its full body.
15
- - `MODIFIED` for an existing element, with its full new body. Copy the current body from `docs/architecture.md` and edit it, so nothing is lost by accident.
15
+ - `MODIFIED` for an existing element, with its full new body. Copy the current body from `cruze show <ID>` and edit it, so nothing is lost by accident.
16
16
  - `REMOVED` with a `Reason`, for an element the feature retires.
17
+ - When the delta changes or retires a rule, find every element, ADR, decision and sentence in the living docs and this feature that states the old rule, and modify or reword each.
18
+ - A new use of an existing port operation, such as the clock stamping a new kind of time, is a `MODIFIED` port whose `Operations` name the use, and each use case lists every port it calls under `Uses`.
17
19
  5. **Link behaviour to design.** Each use case that runs a requirement lists it under `Serves`. Add or modify a `FLOW` for each key scenario, with `Serves` naming its scenarios and the failure paths they need.
18
20
  6. **Research and decide.** For each new component that isn't domain logic, run the researcher role and record a row in `## Adopt or build`. Take every new dependency to the user. Then verify every claim the design relies on, following step 7 of adopt or build in `.agents/skills/cruze-research/SKILL.md`. Done when no claim in the design is unverified.
19
- 7. **Keep later seams open.** When the feature map shows a later feature that will extend this area, record the seam in a `Future` fact, and don't build it.
20
- 8. Done when `cruze validate` reports no errors in the delta itself, and every cited ID exists in the living docs or this delta.
21
+ 7. **Keep later seams open.** Check the design against every row of the vision's `## Must stay possible`: nothing in it may rule one out. When the feature map shows a later feature that will extend this area, or a capability needs room in it, record the seam in a `Future` fact on the element that keeps it, citing the `LATER` ID or the feature's slug, and don't build it.
22
+ 8. Done when `cruze validate` reports no errors and no `decision-citation` warning in the delta itself, and every cited ID exists in the living docs or this delta.
21
23
 
22
24
  ## Split it into changes
23
25
 
@@ -19,7 +19,7 @@ The result has four parts, reviewed together and shown at one walkthrough:
19
19
  8. **Modules (`MOD`).** Name the kind of system in the Overview, and choose the layout that is normal for that kind and the language, following `.agents/skills/cruze-hexagonal-design/shapes.md` and the language file. Give each context the fewest modules that keep its layer rules, usually one `core` module and its adapters, 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
20
  9. **Dependency rules (`RULE`).** State what may import what, in one or two sentences each.
21
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`.
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`, including each design choice handed to `architect` that the user keeps.
23
23
  12. **Overview (`VIEW-context`).** Draw the context diagram last, once the adapters and external systems are known.
24
24
 
25
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.
@@ -34,7 +34,7 @@ Add the language's build output and tool caches to `.gitignore` now, such as `/t
34
34
 
35
35
  ## Plan the release
36
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.
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. Take up the delivery order handed to `roadmap`, as for any hand-off.
38
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
39
  3. **Design the walking skeleton.** Run `cruze new change walking-skeleton --title "Walking skeleton"`. Then:
40
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.
@@ -11,7 +11,7 @@ Behaviour is the contract. Every scenario in the specs becomes a test that drive
11
11
 
12
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
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.
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. A test that guards a race or an ordering must be seen failing against code that has the flaw: run the racing work concurrently, on a multi-threaded runtime where there is one, and wait for a signal the system gives, such as a watch having opened, never for a fixed sleep.
15
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
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
17
 
@@ -39,13 +39,14 @@ A behaviour test drives a use case, not a single domain type, so it keeps passin
39
39
  ## Test support
40
40
 
41
41
  - Share fixtures and harnesses the way you share fakes. Keep one builder or constant for each domain value tests keep needing, such as a valid configuration or an ID from a string, and one harness per seam, such as an in-process service or the real binary started on a temporary directory. They live in the test support module the language file names.
42
- - Before writing a helper in a test file, look in the test support module. Use or extend what is there, and never redefine it.
42
+ - Before writing a helper in a test file, look in the test support module and in the test binary's other files. Use or extend what is there, and never redefine it. When a second test file needs a helper, move it into the test support module then, and use it from both.
43
43
  - Split a test file by the behaviour it covers, one use case, port or flow per file. File budgets apply to source, not to tests, so never split a test file to meet one.
44
44
 
45
45
  ## Expected values
46
46
 
47
47
  - 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.
48
48
  - For a failure scenario, check both the error and the state left behind. After a refused second hop, the first hop is closed.
49
+ - Compare through the constructors and values the code already has. A test is not a caller: never add an accessor, variant or equality to production code only so a test can observe something.
49
50
  - Where a plausible wrong outcome exists, assert that it didn't happen.
50
51
 
51
52
  ## Protecting the check
@@ -4,9 +4,9 @@ A fake is a real, working implementation of a driven port that keeps its state i
4
4
 
5
5
  ## Writing a fake
6
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.
7
+ 1. Read the port's `Operations`, with `cruze show <PORT ID>`. The fake implements every operation with the guarantees and failures listed there, and nothing more. That includes every way the real adapter ends on its own, such as a session closed when its stream ends or its server shuts down.
8
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)`.
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)`. When a use case writes through the port, also let a test stall an operation, and fail one that writes several things partway through, so each partial failure and cancellation can be tested from every state it can leave.
10
10
  4. Record effects the contract makes observable, such as the order hops were closed in, so tests can assert them.
11
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
12
 
@@ -17,7 +17,7 @@ Done when the fake passes the port's contract tests.
17
17
  A contract test states the port's contract once and runs it against every implementation.
18
18
 
19
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.
20
+ 2. Cover each operation's success, each failure the contract names, each way the implementation ends on its own, and the state after a failure.
21
21
  3. Run the suite against the fake in the ordinary test run.
22
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
23
 
@@ -16,7 +16,7 @@ Build turns an approved plan into code, one task at a time. Each task starts wit
16
16
  - `.agents/skills/cruze-behavioural-testing/SKILL.md`
17
17
  - `.agents/skills/cruze-hexagonal-design/SKILL.md`, and its language file when one exists for the project's language
18
18
  - `.agents/skills/cruze-dependency-approval/SKILL.md`
19
- 3. **Read the plan and the design.** Read the change's `change.md`. Run `cruze show <ref>` and read its output: the full body of every element the change builds, every scenario it delivers, and the settled decisions. Read an element it lists as cited only when the task calls it, from the place it names, never `feature.md` or `docs/architecture.md` whole. Read `commands:` in `.cruze/config.yaml`.
19
+ 3. **Read the plan and the design.** Read the change's `change.md`. Run `cruze show <ref>` and read its output: the full body of every element the change builds, every scenario it delivers, and the settled decisions. Read an element it lists as cited only when the task calls it, with `cruze show <ID>`, never `feature.md` or `docs/architecture.md` whole. Read a reference it lists at the sections the change's elements cite. Read `commands:` in `.cruze/config.yaml`.
20
20
  4. **Build each open task in order,** following the task loop below. Skip the tasks already ticked in `## Progress`.
21
21
  5. **Finish.** When every task is ticked:
22
22
  - Run the format, lint and build commands and the full suite, as `.agents/skills/cruze-formats/reference/config.md` defines it under `commands`.
@@ -36,7 +36,7 @@ For task `T<n>`:
36
36
  5. **Commit** with a Conventional Commit message naming the task, such as `feat(access): console session state machine (T2)`.
37
37
  6. **Tick it.** Run `cruze task done T<n>`, which records the commit. Its progress edit rides along in the next commit.
38
38
 
39
- 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
+ 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. Neither has a prefactor's task: run the tests its plan names under `## Risks` before the first task, and after each task, and they pass unchanged.
40
40
 
41
41
  Done for a task when its tests pass, `cruze check --ci` passes for its files, the commit exists and the task is ticked.
42
42
 
@@ -53,6 +53,7 @@ The plan is design. Within a task you decide only what is local and reversible.
53
53
  - a limit, timeout, buffer size, message or error case the design doesn't give. Picking one in code hides a gap in the design: the user decides it, at feature level. Two projects settled 35 of them as deviations.
54
54
 
55
55
  Explain what you found, with the evidence, and don't work around it. Completed tasks keep their commits.
56
+ - **Read a deviation back before you record it.** One that says the design gives no value, text, error or outcome and names the one you chose, or that the code can't keep a promise a port or use case makes, is a rethink, not a deviation. In one change, two deviations worded that way came back as code-review blockers and sent it back at verify.
56
57
  - Never edit `feature.md`, `docs/architecture.md` or `docs/specs/` during build. Design changes go through `rethink`.
57
58
 
58
59
  ## Protecting the check
@@ -10,7 +10,7 @@ Envision decides the what: the problem, who has it, and the behaviour that solve
10
10
  ## Steps
11
11
 
12
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`.
13
+ 2. **Gather the input.** Read what the user gave you: pasted drafts, files they point to, and the notes `cruze show --notes` lists. Read whichever of `docs/vision.md`, `docs/glossary.md`, `docs/roadmap.md` and `docs/architecture.md` exist, and run `cruze status`.
14
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
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
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.
@@ -20,7 +20,8 @@ Envision decides the what: the problem, who has it, and the behaviour that solve
20
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
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
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.
23
+ - Problem through Constraints stay within one page. A principle or a capability that must stay possible takes as much as its intent needs: never shorten one to fit.
24
+ - The product's long-term intent lives in the vision, in its Principles and Must stay possible tables, at either scope. Designs answer to it for the product's whole life, long after the conversation that settled it.
24
25
  - Only the CLI writes the feature map. Use `cruze features add`, `cruze features update` and `cruze features drop`.
25
26
 
26
27
  ## Next step
@@ -7,13 +7,15 @@ The result is a feature folder whose `feature.md` holds the intent, the settled
7
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
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
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.
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. Run `cruze show --notes <slug>`, and take up the notes about this feature and the parts of the user's input handed to it, open questions included, as "Taking up a hand-off later" in [intake.md](intake.md) describes.
11
11
  5. **List the open decisions:**
12
12
  - **Intent:** the problem and outcome in the user's words, who it is for, the constraints, and what is out of scope.
13
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
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
+ - **Later:** the vision's `PRINCIPLE` and `LATER` rows this feature touches, and the capabilities it may grow into, asked about as [possibilities.md](possibilities.md) describes. A feature that adds sign-in asks about single sign-on and multi-factor authentication, for example.
15
16
  6. **Grill in rounds** until every open decision is settled. Record decisions under `## Settled decisions` and terms in the glossary as they settle.
16
17
  - When a decision changes something the feature's summary on the feature map promises, such as a policy it names, correct the summary with `cruze features update <slug> --summary <text>`.
18
+ - When an answer names something the product may need later, or a decision departs from a principle, the vision changes, as "Long-term intent" in the grilling skill describes. A settled decision of this feature is archived when it lands, so it can't hold either.
17
19
  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.
18
20
  - Name every ID with glossary terms. An ID is never reused.
19
21
  - Done when every requirement has a scenario for its main case and one for each failure a user can meet.
@@ -0,0 +1,28 @@
1
+ # Taking in the user's input
2
+
3
+ The user may bring anything: a seed, a PRD, a TRD, a design write-up, an old project's notes, a pasted paragraph or a link. Everything in it is open for discussion, and every part of it reaches the step that takes it up. One project's 9,500-word seed held design that no step was told to read, and intent the vision had no room for.
4
+
5
+ 1. **Gather it.** Read every source the user names or pastes, and each note `cruze show --notes` lists with kind `input`. Run `cruze new note intake --title "Intake: <what the input is>" --kind intake --about project`. Under `## Sources`, cite each file in the repository by path, and copy in, verbatim, what would otherwise be lost: pasted text, and a document outside the repository, such as a link or a PDF.
6
+ 2. **Sort every part** by the step that takes it up. Name each part by its heading, or by a short quote where the input has none:
7
+ - `vision`: the problem, users, goals, non-goals, constraints, principles, and what must stay possible.
8
+ - `architect`: design choices, such as structure, protocols, technologies and data formats.
9
+ - `roadmap`: delivery order and phases.
10
+ - a feature's slug: one feature's behaviour, rules, limits and examples. Use the slug the feature map gives it.
11
+ - `user`: preferences about the process itself, which the user may add to `AGENTS.md`.
12
+
13
+ An open question goes to the step that settles it. Done when every part of every source has a place.
14
+ 3. **Read its stance.** Note how settled the input says each part is, from its own legend when it has one, or from its wording: "we decided" and "must" are firmer than "maybe", "TBD" or a question. Nothing is settled by being written down. The stance sets only your recommendation: keep what the input settled, with its reason; ask about what it proposed; research what it guesses; settle what it leaves open.
15
+ 4. **Write the hand-off** in the intake note, under `## Hand-off`, one row per part:
16
+
17
+ ```markdown
18
+ | Part | Source | Goes to | Status |
19
+ | --- | --- | --- | --- |
20
+ | Transport | `.cruze/notes/2026-10-12-seed.md`, "The protocol" | architect | open |
21
+ ```
22
+
23
+ A one-paragraph idea is all `vision`, so its hand-off is a row or two.
24
+ 5. **Take up the vision's parts now,** one section at a time. Each section is one question, keep or change, with the input's position as your recommendation. Set each row's status to `settled` or `dropped` as the user decides.
25
+
26
+ ## Taking up a hand-off later
27
+
28
+ Architect, the roadmap and feature-scope envision take up their own rows. `cruze show --notes <step or feature slug>` lists them, and `cruze show <ref>` lists them for a feature or change. Read each part at its source, ask the user about it as in step 5, record what they keep where the step records decisions, and set the row's status. A row still `open` when the step ends goes to the user: keep it open for a later step, or drop it.
@@ -0,0 +1,13 @@
1
+ # Exploring what may come later
2
+
3
+ The user knows where the product is heading better than any document does, but rarely says it unprompted. Ask, so designs leave room for it and never close it off.
4
+
5
+ 1. **Find the neighbours.** For each goal, user and capability in scope, name the capabilities that products in this domain commonly grow into, from what you know of the domain and its standards. Name them as the user would recognise them: single sign-on or multi-factor authentication next to sign-in, sync across devices next to local-only storage, teams and shared workspaces next to a single-user app, third-party plugins next to a fixed set of kinds, a second transport next to a local socket. Skip those the vision already records under `## Must stay possible` or `## Non-goals`.
6
+ 2. **Ask them as a round,** following `.agents/skills/cruze-grilling/SKILL.md`: whether the product may need each one, how likely, and why. Recommend an answer from what the user has said so far. Keep a round to 3 to 5, the likeliest first. "No" is a good answer too.
7
+ 3. **Record each answer:**
8
+ - **Likely or possible:** a `LATER-<name>` row under `## Must stay possible` in `docs/vision.md`, with the likelihood, why in the user's words, and what no design may close off. Say what must stay possible, never how to build it: the mechanism is decided when a feature builds it.
9
+ - **No, for a tempting neighbour of a goal:** a non-goal with the reason, so nobody proposes it again.
10
+ - **No, otherwise:** nothing.
11
+ 4. **Check the principles.** For each new `LATER` row, check every `PRINCIPLE` row against it. When one would stand in its way, such as "every record has exactly one owner" against shared workspaces, settle with the user which one gives, and amend the principle or the row.
12
+
13
+ Done when every capability in scope has had its neighbours asked about once, and each answer is recorded. The vision changed, so the user approves it again with `cruze approve vision`.
@@ -3,18 +3,20 @@
3
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
4
 
5
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.
6
+ 2. **Take in the input** as [intake.md](intake.md) describes, then draft every section you can from the parts handed to `vision`, marking each as a question for step 3. Done when every part of the input has a hand-off row.
7
7
  3. **List the open decisions,** section by section:
8
8
  - **Problem:** the problem in the user's words, and who feels it.
9
9
  - **Users:** each kind of user and the situation they are in.
10
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
11
  - **Non-goals:** what the product deliberately doesn't do, and why. Ask about the tempting neighbours of each goal.
12
12
  - **Constraints:** platforms, the implementation language, dependency policy, performance, security, privacy, licensing and legal limits.
13
+ - **Principles:** each rule every design must follow, as a `PRINCIPLE-<name>` row with why it holds. Ask about the rules behind the user's choices, such as what state and events are each for.
14
+ - **Must stay possible:** each capability the product may need after this release, as a `LATER-<name>` row, explored as [possibilities.md](possibilities.md) describes.
13
15
  - **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.
16
+ 4. **Grill in rounds** until every open decision is settled, following the grilling skill. As each domain term settles, add it to the glossary. Once the goals and feature map have settled, ask about what may come later, as [possibilities.md](possibilities.md) describes.
15
17
  5. **Write the vision.** Fill each section, and remove every template guide.
16
18
  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.
19
+ 7. **Confirm.** Walk the user through the vision in one short summary: the problem, the goals with their measures, the non-goals, the constraints, the principles, what must stay possible, and the feature map. Name what the hand-off gives each later step, and anything dropped, and why. Ask whether it matches their understanding, and apply any corrections.
18
20
  8. **Approve.** When the user approves, run `cruze approve vision` and quote its result.
19
21
  9. **Introduce the project in the README.** Under the title of `README.md`, write one paragraph drawn from the vision's Problem, Users and Goals: what the product is, who it is for, and why it exists, ending with a link to `docs/vision.md`. Keep anything already there that is still true. Done when `cruze validate` reports no `readme-overview` warning.
20
22
  10. **Commit,** with a message such as `docs: envision the project`.
@@ -10,7 +10,7 @@ Explore is the optional thinking partner that can come before any other Cruze st
10
10
  ## Steps
11
11
 
12
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`.
13
+ 2. **Read what exists.** Read whichever of these exist: `docs/vision.md`, `docs/glossary.md`, `docs/architecture.md` as "Reading it" in `.agents/skills/cruze-formats/reference/architecture.md` says, `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
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
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. Show what each approach looks like, following `.agents/skills/cruze-grilling/illustrating.md`.
16
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.
@@ -20,7 +20,7 @@ Explore is the optional thinking partner that can come before any other Cruze st
20
20
 
21
21
  Only when the user says to capture:
22
22
 
23
- 1. Run `cruze new note <slug> --title "<title>"` and write the note at the path it returns.
23
+ 1. Run `cruze new note <slug> --title "<title>" --kind explore --about <subjects>`, naming the feature slugs or contexts the idea concerns, or `project`, and write the note at the path it returns.
24
24
  2. Give the note these sections: `## Problem`, `## Options`, `## Recommendation` and `## Open questions`. Mark each statement as fact, hypothesis, preference or recommendation.
25
25
  3. Done when the note stands on its own for a reader who wasn't in the conversation.
26
26