cclaw-cli 0.10.1 → 0.11.0

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.
@@ -0,0 +1,71 @@
1
+ import { RUNTIME_ROOT } from "../constants.js";
2
+ export const STAGE_COMMON_GUIDANCE_REL_PATH = `${RUNTIME_ROOT}/references/stages/common-guidance.md`;
3
+ export function stageCommonGuidanceMarkdown() {
4
+ return `# Common Stage Guidance
5
+
6
+ Shared guidance loaded by every stage skill. Keep this file concise and stable so
7
+ per-stage skills can stay focused on stage-specific work.
8
+
9
+ ## Shared completion protocol
10
+
11
+ - Stage-specific skills expose **Completion Parameters** only.
12
+ - Generic execution steps live in \`.cclaw/references/protocols/completion.md\`.
13
+ - Do not restate the protocol in each stage file.
14
+
15
+ ## Shared decision protocol
16
+
17
+ - Decision wording, ask-tool format, retry budget, and escalation rules live in
18
+ \`.cclaw/references/protocols/decision.md\`.
19
+ - Stage files should reference that path, not duplicate the full text.
20
+
21
+ ## Shared handoff menu
22
+
23
+ Use this same closeout menu for every stage:
24
+
25
+ - **A) Advance** — run \`/cc-next\` and continue.
26
+ - **B) Revise this stage** — stay on current stage and apply feedback.
27
+ - **C) Pause / park** — stop now and resume later.
28
+ - **D) Rewind** — move to a prior stage explicitly chosen by the user.
29
+ - **E) Abandon** — cancel this flow; artifacts remain on disk.
30
+
31
+ Recommendation defaults:
32
+
33
+ - Completion status \`DONE\` -> recommend **A**.
34
+ - Completion status \`DONE_WITH_CONCERNS\` -> recommend **B**.
35
+ - Completion status \`BLOCKED\` -> recommend **B** or **C**.
36
+
37
+ ## Completion status vocabulary
38
+
39
+ - \`DONE\` — all required gates and checks satisfied.
40
+ - \`DONE_WITH_CONCERNS\` — required gates pass, but recommended items remain.
41
+ - \`BLOCKED\` — one or more required/triggered conditions fail.
42
+
43
+ ## Decision record template
44
+
45
+ Use when a stage makes a non-trivial architecture/scope/testing decision.
46
+
47
+ \`\`\`
48
+ Decision: <one-line title>
49
+ Context: <what forced this decision>
50
+ Options considered:
51
+ - A: ...
52
+ - B: ...
53
+ Chosen option: <A/B/...>
54
+ Why: <short rationale>
55
+ Risk: <main downside>
56
+ Rollback / fallback: <if decision proves wrong>
57
+ \`\`\`
58
+
59
+ ## Self-improvement reminder
60
+
61
+ If a reusable lesson appears during the stage, append one strict-schema JSONL
62
+ entry via \`/cc-learn add\`. Do not keep operational lessons only in chat.
63
+
64
+ ## Progressive disclosure baseline
65
+
66
+ - Start with the current stage skill.
67
+ - Load deeper references only when required by a blocker or gate.
68
+ - Prefer \`.cclaw/references/stages/<stage>-examples.md\` and protocol files over
69
+ copying large instruction blocks into stage skills.
70
+ `;
71
+ }
@@ -2,6 +2,9 @@ import type { FlowStage, TransitionRule } from "../types.js";
2
2
  export interface StageGate {
3
3
  id: string;
4
4
  description: string;
5
+ tier?: "required" | "recommended" | "conditional";
6
+ /** Used when tier=conditional. Predicate syntax mirrors conditional delegation rules. */
7
+ condition?: string;
5
8
  }
6
9
  export interface StageRationalization {
7
10
  claim: string;
@@ -24,6 +27,9 @@ export interface CrossStageTrace {
24
27
  export interface ArtifactValidation {
25
28
  section: string;
26
29
  required: boolean;
30
+ tier?: "required" | "recommended" | "conditional";
31
+ /** Optional predicate for conditional validations. */
32
+ condition?: string;
27
33
  validationRule: string;
28
34
  }
29
35
  export interface StageAutoSubagentDispatch {
@@ -106,6 +112,8 @@ export declare function conditionalDispatchesForStage(stage: FlowStage): StageAu
106
112
  export declare function stageSchema(stage: FlowStage): StageSchema;
107
113
  export declare function orderedStageSchemas(): StageSchema[];
108
114
  export declare function stageGateIds(stage: FlowStage): string[];
115
+ export declare function stageRecommendedGateIds(stage: FlowStage): string[];
116
+ export declare function stageConditionalGateIds(stage: FlowStage): string[];
109
117
  export declare function nextCclawCommand(stage: FlowStage): string;
110
118
  export declare function buildTransitionRules(): TransitionRule[];
111
119
  export declare function stagePolicyNeedles(stage: FlowStage): string[];
@@ -1,4 +1,122 @@
1
1
  import { COMMAND_FILE_ORDER } from "../constants.js";
2
+ /**
3
+ * Gate tiers:
4
+ * - required: blocking for stage completion.
5
+ * - recommended: quality signal; unmet -> DONE_WITH_CONCERNS, not BLOCKED.
6
+ * - conditional: becomes blocking only when triggered.
7
+ */
8
+ const REQUIRED_GATE_IDS = {
9
+ brainstorm: [
10
+ "brainstorm_approaches_compared",
11
+ "brainstorm_direction_approved",
12
+ "brainstorm_artifact_reviewed"
13
+ ],
14
+ scope: [
15
+ "scope_mode_selected",
16
+ "scope_contract_written",
17
+ "scope_user_approved"
18
+ ],
19
+ design: [
20
+ "design_architecture_locked",
21
+ "design_data_flow_mapped",
22
+ "design_failure_modes_mapped",
23
+ "design_test_and_perf_defined"
24
+ ],
25
+ spec: [
26
+ "spec_acceptance_measurable",
27
+ "spec_testability_confirmed",
28
+ "spec_user_approved"
29
+ ],
30
+ plan: [
31
+ "plan_tasks_sliced_2_5_min",
32
+ "plan_dependency_waves_defined",
33
+ "plan_acceptance_mapped",
34
+ "plan_wait_for_confirm"
35
+ ],
36
+ tdd: [
37
+ "tdd_red_test_written",
38
+ "tdd_green_full_suite",
39
+ "tdd_refactor_completed",
40
+ "tdd_traceable_to_plan"
41
+ ],
42
+ review: [
43
+ "review_layer1_spec_compliance",
44
+ "review_layer2_security",
45
+ "review_criticals_resolved",
46
+ "review_army_json_valid"
47
+ ],
48
+ ship: [
49
+ "ship_review_verdict_valid",
50
+ "ship_preflight_passed",
51
+ "ship_rollback_plan_ready",
52
+ "ship_finalization_executed"
53
+ ]
54
+ };
55
+ const CONDITIONAL_GATE_RULES = {
56
+ review: {
57
+ review_security_audit_swept: "diff_lines_gt:100||files_touched_gt:10||trust_boundary_changed"
58
+ },
59
+ ship: {
60
+ ship_post_merge_tests: "files_touched_gt:10||release_blast_radius_high"
61
+ }
62
+ };
63
+ const REQUIRED_ARTIFACT_SECTIONS = {
64
+ brainstorm: ["Context", "Problem", "Approaches", "Selected Direction"],
65
+ scope: ["Scope Mode", "In Scope / Out of Scope", "Completion Dashboard", "Scope Summary"],
66
+ design: ["Architecture Boundaries", "Architecture Diagram", "Failure Mode Table", "Completion Dashboard"],
67
+ spec: ["Acceptance Criteria", "Edge Cases", "Testability Map", "Approval"],
68
+ plan: ["Task List", "Dependency Waves", "Acceptance Mapping", "WAIT_FOR_CONFIRM"],
69
+ tdd: ["RED Evidence", "GREEN Evidence", "REFACTOR Notes", "Traceability"],
70
+ review: ["Layer 1 Verdict", "Review Army Contract", "Severity Summary", "Final Verdict"],
71
+ ship: ["Preflight Results", "Release Notes", "Rollback Plan", "Finalization"]
72
+ };
73
+ const CONDITIONAL_ARTIFACT_RULES = {
74
+ review: {
75
+ "Review Readiness Dashboard": "diff_lines_gt:100||files_touched_gt:10||trust_boundary_changed"
76
+ },
77
+ ship: {
78
+ Monitoring: "release_blast_radius_high"
79
+ }
80
+ };
81
+ function tieredStageGates(stage, gates) {
82
+ const requiredSet = new Set(REQUIRED_GATE_IDS[stage]);
83
+ const conditional = CONDITIONAL_GATE_RULES[stage] ?? {};
84
+ return gates.map((gate) => {
85
+ const condition = conditional[gate.id];
86
+ if (condition) {
87
+ return {
88
+ ...gate,
89
+ tier: "conditional",
90
+ condition
91
+ };
92
+ }
93
+ return {
94
+ ...gate,
95
+ tier: requiredSet.has(gate.id) ? "required" : "recommended"
96
+ };
97
+ });
98
+ }
99
+ function tieredArtifactValidation(stage, rows) {
100
+ const requiredSections = new Set(REQUIRED_ARTIFACT_SECTIONS[stage]);
101
+ const conditional = CONDITIONAL_ARTIFACT_RULES[stage] ?? {};
102
+ return rows.map((row) => {
103
+ const condition = conditional[row.section];
104
+ if (condition) {
105
+ return {
106
+ ...row,
107
+ tier: "conditional",
108
+ condition,
109
+ required: false
110
+ };
111
+ }
112
+ const required = requiredSections.has(row.section);
113
+ return {
114
+ ...row,
115
+ tier: required ? "required" : "recommended",
116
+ required
117
+ };
118
+ });
119
+ }
2
120
  const BRAINSTORM = {
3
121
  stage: "brainstorm",
4
122
  skillFolder: "brainstorming",
@@ -1689,8 +1807,12 @@ export function conditionalDispatchesForStage(stage) {
1689
1807
  }
1690
1808
  export function stageSchema(stage) {
1691
1809
  const base = STAGE_SCHEMA_MAP[stage];
1810
+ const tieredGates = tieredStageGates(stage, base.requiredGates);
1811
+ const tieredValidation = tieredArtifactValidation(stage, base.artifactValidation);
1692
1812
  return {
1693
1813
  ...base,
1814
+ requiredGates: tieredGates,
1815
+ artifactValidation: tieredValidation,
1694
1816
  mandatoryDelegations: mandatoryDelegationsForStage(stage)
1695
1817
  };
1696
1818
  }
@@ -1698,7 +1820,19 @@ export function orderedStageSchemas() {
1698
1820
  return COMMAND_FILE_ORDER.map((stage) => stageSchema(stage));
1699
1821
  }
1700
1822
  export function stageGateIds(stage) {
1701
- return stageSchema(stage).requiredGates.map((gate) => gate.id);
1823
+ return stageSchema(stage).requiredGates
1824
+ .filter((gate) => gate.tier === "required")
1825
+ .map((gate) => gate.id);
1826
+ }
1827
+ export function stageRecommendedGateIds(stage) {
1828
+ return stageSchema(stage).requiredGates
1829
+ .filter((gate) => gate.tier === "recommended")
1830
+ .map((gate) => gate.id);
1831
+ }
1832
+ export function stageConditionalGateIds(stage) {
1833
+ return stageSchema(stage).requiredGates
1834
+ .filter((gate) => gate.tier === "conditional")
1835
+ .map((gate) => gate.id);
1702
1836
  }
1703
1837
  export function nextCclawCommand(stage) {
1704
1838
  const next = stageSchema(stage).next;
@@ -25,7 +25,7 @@ This is the **recommended way to start** working with cclaw. Use \`/cc-next\` fo
25
25
  ## HARD-GATE
26
26
 
27
27
  - **Do not** skip reading \`${flowPath}\` — always check current state before acting.
28
- - **Do not** start implementation stages directly from \`/cc <prompt>\` — always begin at the first stage of the resolved track (brainstorm for standard, spec for quick).
28
+ - **Do not** start implementation stages directly from \`/cc <prompt>\` — always begin at the first stage of the resolved track (brainstorm for medium/standard, spec for quick).
29
29
  - **Do not** start a stage pipeline for a task that is not a software change (pure question, non-software task, conversation).
30
30
 
31
31
  ## Algorithm
@@ -40,6 +40,7 @@ This is the **recommended way to start** working with cclaw. Use \`/cc-next\` fo
40
40
  | **pure-question** | "how does X work?", "explain Y", "what are the trade-offs of Z?" | Answer directly, do NOT open a stage. |
41
41
  | **trivial** | typo, one-liner, rename, config tweak, copy change, version bump with zero behavior change | Fast-path: skip \`brainstorm\` and \`scope\`, seed \`00-idea.md\`, move straight to \`design\` or \`spec\` depending on whether an interface change is involved. |
42
42
  | **software — bug fix with repro** | regression / hotfix / named symptom + repro steps | Fast-path: set track to \`quick\`, seed \`04-spec.md\` with the reproduction, enter \`tdd\` with a RED reproduction test first. |
43
+ | **software — medium** | additive feature following existing architecture | medium track (\`brainstorm → spec → plan → tdd → review → ship\`). |
43
44
  | **software — standard** | feature, refactor, migration, integration, architecture change | Full 8-stage flow starting at \`brainstorm\`. |
44
45
 
45
46
  Record the chosen class in \`.cclaw/artifacts/00-idea.md\` on the \`Class:\` line. Do NOT silently treat a non-software task as software.
@@ -63,20 +64,23 @@ This is the **recommended way to start** working with cclaw. Use \`/cc-next\` fo
63
64
  4. Read \`${flowPath}\`.
64
65
  5. If flow already has completed stages beyond brainstorm, warn the user that starting a new brainstorm will reset progress. Ask for confirmation before proceeding.
65
66
  6. **Track heuristic** — classify the idea text and **recommend** a track (the user can override before any state mutation):
67
+ - First, load \`${RUNTIME_ROOT}/config.yaml\`. If \`trackHeuristics\` is defined, apply those per-track rules (\`priority\`, \`fallback\`, \`tracks.<id>.{triggers,patterns,veto}\`) before built-in defaults.
66
68
  - **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known.
67
69
  Triggers (case-insensitive substring or close variant): \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`copy change\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`config tweak\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`.
68
- - **standard** (full 8 stages default) — anything that introduces a new capability, touches multiple modules, or has unclear scope.
69
- Triggers: \`new feature\`, \`add\`, \`build\`, \`design\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`endpoint\`, \`schema\`, \`api\`, \`integrate\`, \`workflow\`, \`onboarding\`, or any prompt that does not match quick triggers.
70
- - When triggers conflict (e.g. "small refactor that touches 5 modules") prefer **standard** quick is opt-in and only safe when scope is genuinely tiny.
70
+ - **medium** (\`brainstorm spec plan → tdd → review → ship\`) — additive work that fits existing architecture and still needs product framing.
71
+ Triggers: \`add endpoint\`, \`add field\`, \`extend existing\`, \`wire integration\`, \`small migration\`, \`new screen following existing patterns\`.
72
+ - **standard** (full 8 stages default fallback) anything that introduces a new capability with architecture uncertainty, touches many modules, or has unclear scope.
73
+ Triggers: \`new feature\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`schema\`, \`integrate\`, \`workflow\`, \`onboarding\`, or any prompt that does not match quick/medium confidently.
74
+ - When triggers conflict, prefer **standard** over **medium**, and **medium** over **quick**.
71
75
  7. Present the recommendation as a single decision with explicit options:
72
- > \`Recommended track: <quick|standard>\` because \`<one-line reason citing matched triggers>\`.
73
- > Override? (A) keep \`<recommended>\` (B) switch to \`<other>\` (C) cancel.
76
+ > \`Recommended track: <quick|medium|standard>\` because \`<one-line reason citing matched triggers>\`.
77
+ > Override? (A) keep \`<recommended>\` (B) switch track (C) cancel.
74
78
  If \`AskQuestion\`/\`AskUserQuestion\` is available, send exactly ONE question; on schema error, fall back to plain text.
75
- 8. Persist the chosen track to \`${flowPath}\` (\`track\` field). Compute \`skippedStages\` from the track and write that too. Use the **first stage of the chosen track** as \`currentStage\` (quick → \`spec\`, standard → \`brainstorm\`, trivial fast-path → \`design\` or \`spec\` per Phase 0).
79
+ 8. Persist the chosen track to \`${flowPath}\` (\`track\` field). Compute \`skippedStages\` from the track and write that too. Use the **first stage of the chosen track** as \`currentStage\` (quick → \`spec\`, medium/standard → \`brainstorm\`, trivial fast-path → \`design\` or \`spec\` per Phase 0).
76
80
  9. Write the prompt to \`.cclaw/artifacts/00-idea.md\` with the following header lines: \`Class:\` (from Phase 0), \`Track:\` (chosen track + matched heuristic), \`Stack:\` (from Phase 2 detection, or \`unknown\`), and a \`Discovered context\` section if Phase 1 found origin docs.
77
81
  10. Load the **first-stage skill for the chosen track** and its command file:
78
82
  - quick → \`.cclaw/skills/specification-authoring/SKILL.md\` + \`.cclaw/commands/spec.md\`
79
- - standard → \`.cclaw/skills/brainstorming/SKILL.md\` + \`.cclaw/commands/brainstorm.md\`
83
+ - medium/standard → \`.cclaw/skills/brainstorming/SKILL.md\` + \`.cclaw/commands/brainstorm.md\`
80
84
  - trivial fast-path → design or spec skill per Phase 0 decision.
81
85
  11. Execute that stage with the prompt + Phase 1/Phase 2 context as initial input.
82
86
 
@@ -136,19 +140,21 @@ Do **not** silently discard an existing flow when the user provides a prompt. If
136
140
  - Ask: "Continue with reset? (A) Yes, start fresh (B) No, resume current flow"
137
141
  - If (B) → switch to Path B behavior.
138
142
  6. **Classify the idea** using the heuristic below and present a single track recommendation. Wait for explicit confirmation or override before mutating any state.
143
+ - If \`${RUNTIME_ROOT}/config.yaml\` defines \`trackHeuristics\`, apply that override first (priority/fallback/rules), then use built-in defaults only as fallback.
139
144
 
140
145
  **Track heuristic** (lowercase substring match against the user prompt):
141
146
 
142
147
  | Track | Triggers | Use when |
143
148
  |---|---|---|
144
149
  | \`quick\` | \`bug\`, \`bugfix\`, \`fix\`, \`hotfix\`, \`patch\`, \`typo\`, \`regression\`, \`rename\`, \`bump\`, \`upgrade dep\`, \`docs only\`, \`comment\`, \`lint\`, \`format\`, \`small\`, \`tiny\`, \`one-liner\`, \`revert\`, \`copy change\` | Single-purpose, spec is essentially known, low blast radius |
145
- | \`standard\` | \`new feature\`, \`add\`, \`build\`, \`design\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`endpoint\`, \`schema\`, \`api\`, \`integrate\`, \`workflow\`, \`onboarding\` (or no quick trigger matched) | Anything new, multi-module, or unclear scope |
150
+ | \`medium\` | \`add endpoint\`, \`add field\`, \`extend existing\`, \`wire integration\`, \`small migration\`, \`new screen following existing pattern\` | Additive work with existing architecture |
151
+ | \`standard\` | \`new feature\`, \`build\`, \`design\`, \`refactor\`, \`migration\`, \`platform\`, \`architecture\`, \`schema\`, \`api\`, \`integrate\`, \`workflow\`, \`onboarding\` (or no confident quick/medium match) | New or uncertain multi-module work |
146
152
 
147
- - On conflict, prefer \`standard\` (quick is opt-in for genuinely tiny work).
148
- - Always state the recommendation as a one-line reason citing the matched trigger.
149
- 7. Persist the chosen track in \`${flowPath}\` (\`track\` + \`skippedStages\`). Set \`currentStage\` to the first stage of the chosen track (\`quick\` → \`spec\`, \`standard\` → \`brainstorm\`, trivial fast-path → \`design\` or \`spec\`). Reset gate catalog.
153
+ - On conflict, prefer \`standard\` over \`medium\`, and \`medium\` over \`quick\`.
154
+ - Always state the recommendation as a one-line reason citing matched triggers.
155
+ 7. Persist the chosen track in \`${flowPath}\` (\`track\` + \`skippedStages\`). Set \`currentStage\` to the first stage of the chosen track (\`quick\` → \`spec\`, \`medium\`/ \`standard\` → \`brainstorm\`, trivial fast-path → \`design\` or \`spec\`). Reset gate catalog.
150
156
  8. Write \`${RUNTIME_ROOT}/artifacts/00-idea.md\` with the user's prompt plus header lines: \`Class:\`, \`Track:\`, \`Stack:\`, and a \`Discovered context\` section from Phase 1.
151
- 9. Load and execute the **first stage skill of the chosen track** (\`brainstorming\` for standard, \`specification-authoring\` for quick) plus its matching command file.
157
+ 9. Load and execute the **first stage skill of the chosen track** (\`brainstorming\` for medium/standard, \`specification-authoring\` for quick) plus its matching command file.
152
158
 
153
159
  ### Reclassification on discovery
154
160
 
package/dist/doctor.js CHANGED
@@ -278,8 +278,8 @@ export async function doctorChecks(projectRoot, options = {}) {
278
278
  { id: "iron_law", pattern: /^\*\*IRON LAW — [A-Z]+:\*\* .+$/m, label: "Iron Law punchcard (<EXTREMELY-IMPORTANT> wrapper)" },
279
279
  { id: "hard_gate", pattern: /^## HARD-GATE$/m, label: "## HARD-GATE" },
280
280
  { id: "checklist", pattern: /^## Checklist$/m, label: "## Checklist" },
281
- { id: "completion_protocol", pattern: /^## Stage Completion Protocol$/m, label: "## Stage Completion Protocol" },
282
- { id: "handoff_menu", pattern: /^### Handoff Menu$/m, label: "### Handoff Menu" },
281
+ { id: "completion_parameters", pattern: /^## Completion Parameters$/m, label: "## Completion Parameters" },
282
+ { id: "shared_guidance", pattern: /^## Shared Stage Guidance$/m, label: "## Shared Stage Guidance" },
283
283
  { id: "good_vs_bad", pattern: /Good vs Bad/i, label: "Good vs Bad examples" },
284
284
  { id: "anti_patterns", pattern: /^## Anti-Patterns & Red Flags$/m, label: "## Anti-Patterns & Red Flags" }
285
285
  ];
@@ -303,14 +303,12 @@ export async function doctorChecks(projectRoot, options = {}) {
303
303
  const metaContent = await fs.readFile(metaSkillPath, "utf8");
304
304
  const requiredSignals = [
305
305
  { id: "instruction_priority", pattern: /Instruction Priority/i, label: "Instruction Priority" },
306
- { id: "spawned_detection", pattern: /Spawned Subagent Detection/i, label: "Spawned Subagent Detection" },
307
- { id: "shared_decision", pattern: /Shared Decision \+ Tool-Use Protocol/i, label: "Shared Decision + Tool-Use Protocol" },
308
- { id: "shared_completion", pattern: /Shared Stage Completion Protocol/i, label: "Shared Stage Completion Protocol" },
309
- { id: "escalation_rule", pattern: /Escalation Rule \(3 attempts\)/i, label: "Escalation Rule (3 attempts)" },
310
- { id: "invocation_preamble", pattern: /Invocation Preamble/i, label: "Invocation Preamble" },
311
- { id: "operational_self_improvement", pattern: /Operational Self-Improvement/i, label: "Operational Self-Improvement" },
312
- { id: "engineering_ethos", pattern: /Engineering Ethos/i, label: "Engineering Ethos" },
313
- { id: "task_classification", pattern: /Task Classification/i, label: "Task Classification" }
306
+ { id: "routing_flow", pattern: /Routing flow/i, label: "Routing flow" },
307
+ { id: "task_classification", pattern: /Task classification/i, label: "Task classification" },
308
+ { id: "stage_map", pattern: /Stage quick map/i, label: "Stage quick map" },
309
+ { id: "protocol_refs", pattern: /Protocol references/i, label: "Protocol references" },
310
+ { id: "knowledge_guidance", pattern: /Knowledge guidance/i, label: "Knowledge guidance" },
311
+ { id: "failure_guardrails", pattern: /Failure guardrails/i, label: "Failure guardrails" }
314
312
  ];
315
313
  const missingMeta = requiredSignals
316
314
  .filter((signal) => !signal.pattern.test(metaContent))
@@ -782,6 +780,11 @@ export async function doctorChecks(projectRoot, options = {}) {
782
780
  ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "knowledge.jsonl")),
783
781
  details: `${RUNTIME_ROOT}/knowledge.jsonl must exist`
784
782
  });
783
+ checks.push({
784
+ name: "knowledge:digest_exists",
785
+ ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "state", "knowledge-digest.md")),
786
+ details: `${RUNTIME_ROOT}/state/knowledge-digest.md must exist`
787
+ });
785
788
  // There must be NO legacy markdown knowledge store — JSONL is the only store.
786
789
  const legacyKnowledgeMdPath = path.join(projectRoot, RUNTIME_ROOT, "knowledge.md");
787
790
  const legacyExists = await exists(legacyKnowledgeMdPath);
@@ -968,9 +971,16 @@ export async function doctorChecks(projectRoot, options = {}) {
968
971
  name: "gates:evidence:current_stage",
969
972
  ok: gateEvidence.ok,
970
973
  details: gateEvidence.ok
971
- ? `stage "${gateEvidence.stage}" gate evidence is consistent (required=${gateEvidence.requiredCount}, passed=${gateEvidence.passedCount}, blocked=${gateEvidence.blockedCount})`
974
+ ? `stage "${gateEvidence.stage}" gate evidence is consistent (required=${gateEvidence.requiredCount}, recommended=${gateEvidence.recommendedCount}, conditional=${gateEvidence.conditionalCount}, triggered=${gateEvidence.triggeredConditionalCount}, passed=${gateEvidence.passedCount}, blocked=${gateEvidence.blockedCount})`
972
975
  : gateEvidence.issues.join(" ")
973
976
  });
977
+ checks.push({
978
+ name: "warning:gates:recommended:current_stage",
979
+ ok: true,
980
+ details: gateEvidence.missingRecommended.length > 0
981
+ ? `warning: stage "${gateEvidence.stage}" has unmet recommended gates: ${gateEvidence.missingRecommended.join(", ")}`
982
+ : `no unmet recommended gates for stage "${gateEvidence.stage}"`
983
+ });
974
984
  const completedClosure = verifyCompletedStagesGateClosure(flowState);
975
985
  checks.push({
976
986
  name: "gates:closure:completed_stages",
@@ -981,18 +991,6 @@ export async function doctorChecks(projectRoot, options = {}) {
981
991
  : `all ${flowState.completedStages.length} completed stages have every required gate passed`
982
992
  : completedClosure.issues.join(" ")
983
993
  });
984
- // Self-improvement block in stage skills
985
- for (const stage of COMMAND_FILE_ORDER) {
986
- const skillPath = path.join(projectRoot, RUNTIME_ROOT, "skills", stageSkillFolder(stage), "SKILL.md");
987
- if (await exists(skillPath)) {
988
- const content = await fs.readFile(skillPath, "utf8");
989
- checks.push({
990
- name: `skill:${stage}:self_improvement`,
991
- ok: content.includes("## Operational Self-Improvement"),
992
- details: `${skillPath} must contain self-improvement block`
993
- });
994
- }
995
- }
996
994
  const isRepo = await isGitRepo(projectRoot);
997
995
  checks.push({
998
996
  name: "git:cclaw_ignored_runtime",
@@ -2,6 +2,10 @@ import type { FlowStage, FlowTrack, TransitionRule } from "./types.js";
2
2
  export declare const TRANSITION_RULES: TransitionRule[];
3
3
  export interface StageGateState {
4
4
  required: string[];
5
+ recommended: string[];
6
+ conditional: string[];
7
+ /** Conditional gates currently considered active for blocking checks. */
8
+ triggered: string[];
5
9
  passed: string[];
6
10
  blocked: string[];
7
11
  }
@@ -1,5 +1,5 @@
1
1
  import { COMMAND_FILE_ORDER } from "./constants.js";
2
- import { buildTransitionRules, orderedStageSchemas, stageGateIds } from "./content/stage-schema.js";
2
+ import { buildTransitionRules, orderedStageSchemas, stageConditionalGateIds, stageGateIds, stageRecommendedGateIds } from "./content/stage-schema.js";
3
3
  import { FLOW_STAGES, FLOW_TRACKS, TRACK_STAGES } from "./types.js";
4
4
  export const TRANSITION_RULES = buildTransitionRules();
5
5
  export function isFlowTrack(value) {
@@ -27,6 +27,9 @@ export function createInitialFlowState(activeRunIdOrOptions = "active", maybeTra
27
27
  for (const schema of orderedStageSchemas()) {
28
28
  stageGateCatalog[schema.stage] = {
29
29
  required: stageGateIds(schema.stage),
30
+ recommended: stageRecommendedGateIds(schema.stage),
31
+ conditional: stageConditionalGateIds(schema.stage),
32
+ triggered: [],
30
33
  passed: [],
31
34
  blocked: []
32
35
  };
@@ -5,12 +5,19 @@ export interface GateEvidenceCheckResult {
5
5
  stage: FlowStage;
6
6
  issues: string[];
7
7
  requiredCount: number;
8
+ recommendedCount: number;
9
+ conditionalCount: number;
10
+ triggeredConditionalCount: number;
8
11
  passedCount: number;
9
12
  blockedCount: number;
10
- /** True only when every required gate for the stage is in `passed` and none are `blocked`. */
13
+ /** True only when required + triggered conditional gates are passed and unblocked. */
11
14
  complete: boolean;
12
15
  /** Required gate ids that are neither passed nor blocked. */
13
16
  missingRequired: string[];
17
+ /** Recommended gates not yet passed (does not block). */
18
+ missingRecommended: string[];
19
+ /** Triggered conditional gates that are not yet passed. */
20
+ missingTriggeredConditional: string[];
14
21
  }
15
22
  export interface CompletedStagesClosureResult {
16
23
  ok: boolean;
@@ -18,6 +25,7 @@ export interface CompletedStagesClosureResult {
18
25
  openStages: Array<{
19
26
  stage: FlowStage;
20
27
  missingRequired: string[];
28
+ missingTriggeredConditional: string[];
21
29
  blocked: string[];
22
30
  }>;
23
31
  }