cclaw-cli 7.7.0 → 8.1.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.
- package/README.md +210 -134
- package/dist/artifact-frontmatter.d.ts +51 -0
- package/dist/artifact-frontmatter.js +131 -0
- package/dist/artifact-paths.d.ts +7 -27
- package/dist/artifact-paths.js +20 -249
- package/dist/cancel.d.ts +16 -0
- package/dist/cancel.js +66 -0
- package/dist/cli.d.ts +2 -27
- package/dist/cli.js +90 -508
- package/dist/compound.d.ts +26 -0
- package/dist/compound.js +96 -0
- package/dist/config.d.ts +14 -51
- package/dist/config.js +23 -359
- package/dist/constants.d.ts +11 -18
- package/dist/constants.js +19 -106
- package/dist/content/antipatterns.d.ts +1 -0
- package/dist/content/antipatterns.js +109 -0
- package/dist/content/artifact-templates.d.ts +10 -0
- package/dist/content/artifact-templates.js +550 -0
- package/dist/content/cancel-command.d.ts +2 -2
- package/dist/content/cancel-command.js +25 -17
- package/dist/content/core-agents.d.ts +9 -233
- package/dist/content/core-agents.js +39 -766
- package/dist/content/decision-protocol.d.ts +1 -12
- package/dist/content/decision-protocol.js +27 -20
- package/dist/content/examples.d.ts +8 -42
- package/dist/content/examples.js +293 -425
- package/dist/content/idea-command.d.ts +2 -0
- package/dist/content/idea-command.js +38 -0
- package/dist/content/iron-laws.d.ts +4 -138
- package/dist/content/iron-laws.js +18 -197
- package/dist/content/meta-skill.d.ts +1 -3
- package/dist/content/meta-skill.js +57 -132
- package/dist/content/node-hooks.d.ts +12 -8
- package/dist/content/node-hooks.js +188 -838
- package/dist/content/recovery.d.ts +8 -0
- package/dist/content/recovery.js +179 -0
- package/dist/content/reference-patterns.d.ts +4 -13
- package/dist/content/reference-patterns.js +260 -389
- package/dist/content/research-playbooks.d.ts +8 -8
- package/dist/content/research-playbooks.js +108 -121
- package/dist/content/review-loop.d.ts +6 -192
- package/dist/content/review-loop.js +29 -731
- package/dist/content/skills.d.ts +8 -38
- package/dist/content/skills.js +681 -732
- package/dist/content/specialist-prompts/architect.d.ts +1 -0
- package/dist/content/specialist-prompts/architect.js +225 -0
- package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
- package/dist/content/specialist-prompts/brainstormer.js +168 -0
- package/dist/content/specialist-prompts/index.d.ts +2 -0
- package/dist/content/specialist-prompts/index.js +14 -0
- package/dist/content/specialist-prompts/planner.d.ts +1 -0
- package/dist/content/specialist-prompts/planner.js +182 -0
- package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/reviewer.js +193 -0
- package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
- package/dist/content/specialist-prompts/security-reviewer.js +133 -0
- package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
- package/dist/content/specialist-prompts/slice-builder.js +232 -0
- package/dist/content/stage-playbooks.d.ts +8 -0
- package/dist/content/stage-playbooks.js +404 -0
- package/dist/content/start-command.d.ts +2 -12
- package/dist/content/start-command.js +221 -207
- package/dist/flow-state.d.ts +21 -178
- package/dist/flow-state.js +67 -170
- package/dist/fs-utils.d.ts +6 -26
- package/dist/fs-utils.js +29 -162
- package/dist/gitignore.d.ts +2 -1
- package/dist/gitignore.js +51 -34
- package/dist/harness-detect.d.ts +10 -0
- package/dist/harness-detect.js +29 -0
- package/dist/install.d.ts +27 -15
- package/dist/install.js +230 -1342
- package/dist/knowledge-store.d.ts +19 -163
- package/dist/knowledge-store.js +56 -590
- package/dist/logger.d.ts +8 -3
- package/dist/logger.js +13 -4
- package/dist/orchestrator-routing.d.ts +29 -0
- package/dist/orchestrator-routing.js +156 -0
- package/dist/run-persistence.d.ts +7 -118
- package/dist/run-persistence.js +29 -845
- package/dist/runtime/run-hook.entry.d.ts +1 -3
- package/dist/runtime/run-hook.entry.js +19 -4
- package/dist/runtime/run-hook.mjs +13 -1024
- package/dist/types.d.ts +25 -261
- package/dist/types.js +8 -36
- package/package.json +6 -3
- package/dist/artifact-linter/brainstorm.d.ts +0 -2
- package/dist/artifact-linter/brainstorm.js +0 -353
- package/dist/artifact-linter/design.d.ts +0 -18
- package/dist/artifact-linter/design.js +0 -444
- package/dist/artifact-linter/findings-dedup.d.ts +0 -56
- package/dist/artifact-linter/findings-dedup.js +0 -232
- package/dist/artifact-linter/plan.d.ts +0 -2
- package/dist/artifact-linter/plan.js +0 -826
- package/dist/artifact-linter/review-army.d.ts +0 -49
- package/dist/artifact-linter/review-army.js +0 -520
- package/dist/artifact-linter/review.d.ts +0 -2
- package/dist/artifact-linter/review.js +0 -113
- package/dist/artifact-linter/scope.d.ts +0 -2
- package/dist/artifact-linter/scope.js +0 -158
- package/dist/artifact-linter/shared.d.ts +0 -637
- package/dist/artifact-linter/shared.js +0 -2163
- package/dist/artifact-linter/ship.d.ts +0 -2
- package/dist/artifact-linter/ship.js +0 -250
- package/dist/artifact-linter/spec.d.ts +0 -2
- package/dist/artifact-linter/spec.js +0 -176
- package/dist/artifact-linter/tdd.d.ts +0 -118
- package/dist/artifact-linter/tdd.js +0 -1404
- package/dist/artifact-linter.d.ts +0 -15
- package/dist/artifact-linter.js +0 -517
- package/dist/codex-feature-flag.d.ts +0 -58
- package/dist/codex-feature-flag.js +0 -193
- package/dist/content/closeout-guidance.d.ts +0 -14
- package/dist/content/closeout-guidance.js +0 -44
- package/dist/content/diff-command.d.ts +0 -1
- package/dist/content/diff-command.js +0 -43
- package/dist/content/harness-doc.d.ts +0 -1
- package/dist/content/harness-doc.js +0 -65
- package/dist/content/hook-events.d.ts +0 -9
- package/dist/content/hook-events.js +0 -23
- package/dist/content/hook-manifest.d.ts +0 -81
- package/dist/content/hook-manifest.js +0 -156
- package/dist/content/hooks.d.ts +0 -11
- package/dist/content/hooks.js +0 -1972
- package/dist/content/idea.d.ts +0 -60
- package/dist/content/idea.js +0 -416
- package/dist/content/language-policy.d.ts +0 -2
- package/dist/content/language-policy.js +0 -13
- package/dist/content/learnings.d.ts +0 -6
- package/dist/content/learnings.js +0 -141
- package/dist/content/observe.d.ts +0 -19
- package/dist/content/observe.js +0 -86
- package/dist/content/opencode-plugin.d.ts +0 -1
- package/dist/content/opencode-plugin.js +0 -635
- package/dist/content/review-prompts.d.ts +0 -1
- package/dist/content/review-prompts.js +0 -104
- package/dist/content/runtime-shared-snippets.d.ts +0 -8
- package/dist/content/runtime-shared-snippets.js +0 -80
- package/dist/content/session-hooks.d.ts +0 -7
- package/dist/content/session-hooks.js +0 -107
- package/dist/content/skills-elicitation.d.ts +0 -1
- package/dist/content/skills-elicitation.js +0 -167
- package/dist/content/stage-command.d.ts +0 -2
- package/dist/content/stage-command.js +0 -17
- package/dist/content/stage-schema.d.ts +0 -117
- package/dist/content/stage-schema.js +0 -955
- package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
- package/dist/content/stages/_lint-metadata/index.js +0 -97
- package/dist/content/stages/brainstorm.d.ts +0 -2
- package/dist/content/stages/brainstorm.js +0 -184
- package/dist/content/stages/design.d.ts +0 -2
- package/dist/content/stages/design.js +0 -288
- package/dist/content/stages/index.d.ts +0 -8
- package/dist/content/stages/index.js +0 -11
- package/dist/content/stages/plan.d.ts +0 -2
- package/dist/content/stages/plan.js +0 -191
- package/dist/content/stages/review.d.ts +0 -2
- package/dist/content/stages/review.js +0 -240
- package/dist/content/stages/schema-types.d.ts +0 -203
- package/dist/content/stages/schema-types.js +0 -1
- package/dist/content/stages/scope.d.ts +0 -2
- package/dist/content/stages/scope.js +0 -254
- package/dist/content/stages/ship.d.ts +0 -2
- package/dist/content/stages/ship.js +0 -159
- package/dist/content/stages/spec.d.ts +0 -2
- package/dist/content/stages/spec.js +0 -170
- package/dist/content/stages/tdd.d.ts +0 -4
- package/dist/content/stages/tdd.js +0 -273
- package/dist/content/state-contracts.d.ts +0 -1
- package/dist/content/state-contracts.js +0 -63
- package/dist/content/status-command.d.ts +0 -4
- package/dist/content/status-command.js +0 -109
- package/dist/content/subagent-context-skills.d.ts +0 -4
- package/dist/content/subagent-context-skills.js +0 -279
- package/dist/content/subagents.d.ts +0 -3
- package/dist/content/subagents.js +0 -997
- package/dist/content/templates.d.ts +0 -26
- package/dist/content/templates.js +0 -1692
- package/dist/content/track-render-context.d.ts +0 -18
- package/dist/content/track-render-context.js +0 -53
- package/dist/content/tree-command.d.ts +0 -1
- package/dist/content/tree-command.js +0 -64
- package/dist/content/utility-skills.d.ts +0 -30
- package/dist/content/utility-skills.js +0 -160
- package/dist/content/view-command.d.ts +0 -2
- package/dist/content/view-command.js +0 -92
- package/dist/delegation.d.ts +0 -649
- package/dist/delegation.js +0 -1539
- package/dist/early-loop.d.ts +0 -70
- package/dist/early-loop.js +0 -302
- package/dist/execution-topology.d.ts +0 -36
- package/dist/execution-topology.js +0 -73
- package/dist/gate-evidence.d.ts +0 -85
- package/dist/gate-evidence.js +0 -631
- package/dist/harness-adapters.d.ts +0 -151
- package/dist/harness-adapters.js +0 -756
- package/dist/harness-selection.d.ts +0 -31
- package/dist/harness-selection.js +0 -214
- package/dist/hook-schema.d.ts +0 -6
- package/dist/hook-schema.js +0 -114
- package/dist/hook-schemas/claude-hooks.v1.json +0 -10
- package/dist/hook-schemas/codex-hooks.v1.json +0 -10
- package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
- package/dist/init-detect.d.ts +0 -2
- package/dist/init-detect.js +0 -50
- package/dist/internal/advance-stage/advance.d.ts +0 -89
- package/dist/internal/advance-stage/advance.js +0 -655
- package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
- package/dist/internal/advance-stage/cancel-run.js +0 -19
- package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
- package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
- package/dist/internal/advance-stage/helpers.d.ts +0 -14
- package/dist/internal/advance-stage/helpers.js +0 -145
- package/dist/internal/advance-stage/hook.d.ts +0 -8
- package/dist/internal/advance-stage/hook.js +0 -40
- package/dist/internal/advance-stage/parsers.d.ts +0 -72
- package/dist/internal/advance-stage/parsers.js +0 -357
- package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
- package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
- package/dist/internal/advance-stage/review-loop.d.ts +0 -16
- package/dist/internal/advance-stage/review-loop.js +0 -199
- package/dist/internal/advance-stage/rewind.d.ts +0 -14
- package/dist/internal/advance-stage/rewind.js +0 -108
- package/dist/internal/advance-stage/start-flow.d.ts +0 -13
- package/dist/internal/advance-stage/start-flow.js +0 -241
- package/dist/internal/advance-stage/verify.d.ts +0 -21
- package/dist/internal/advance-stage/verify.js +0 -185
- package/dist/internal/advance-stage.d.ts +0 -7
- package/dist/internal/advance-stage.js +0 -138
- package/dist/internal/cohesion-contract-stub.d.ts +0 -24
- package/dist/internal/cohesion-contract-stub.js +0 -148
- package/dist/internal/compound-readiness.d.ts +0 -23
- package/dist/internal/compound-readiness.js +0 -102
- package/dist/internal/detect-public-api-changes.d.ts +0 -5
- package/dist/internal/detect-public-api-changes.js +0 -45
- package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
- package/dist/internal/detect-supply-chain-changes.js +0 -138
- package/dist/internal/early-loop-status.d.ts +0 -7
- package/dist/internal/early-loop-status.js +0 -93
- package/dist/internal/envelope-validate.d.ts +0 -7
- package/dist/internal/envelope-validate.js +0 -66
- package/dist/internal/flow-state-repair.d.ts +0 -20
- package/dist/internal/flow-state-repair.js +0 -104
- package/dist/internal/plan-split-waves.d.ts +0 -190
- package/dist/internal/plan-split-waves.js +0 -764
- package/dist/internal/runtime-integrity.d.ts +0 -7
- package/dist/internal/runtime-integrity.js +0 -268
- package/dist/internal/slice-commit.d.ts +0 -7
- package/dist/internal/slice-commit.js +0 -619
- package/dist/internal/tdd-loop-status.d.ts +0 -14
- package/dist/internal/tdd-loop-status.js +0 -68
- package/dist/internal/tdd-red-evidence.d.ts +0 -7
- package/dist/internal/tdd-red-evidence.js +0 -153
- package/dist/internal/waiver-grant.d.ts +0 -62
- package/dist/internal/waiver-grant.js +0 -294
- package/dist/internal/wave-status.d.ts +0 -63
- package/dist/internal/wave-status.js +0 -450
- package/dist/managed-resources.d.ts +0 -53
- package/dist/managed-resources.js +0 -313
- package/dist/policy.d.ts +0 -10
- package/dist/policy.js +0 -167
- package/dist/retro-gate.d.ts +0 -9
- package/dist/retro-gate.js +0 -47
- package/dist/run-archive.d.ts +0 -61
- package/dist/run-archive.js +0 -391
- package/dist/runs.d.ts +0 -2
- package/dist/runs.js +0 -2
- package/dist/stack-detection.d.ts +0 -116
- package/dist/stack-detection.js +0 -489
- package/dist/streaming/event-stream.d.ts +0 -31
- package/dist/streaming/event-stream.js +0 -114
- package/dist/tdd-cycle.d.ts +0 -107
- package/dist/tdd-cycle.js +0 -289
- package/dist/tdd-verification-evidence.d.ts +0 -17
- package/dist/tdd-verification-evidence.js +0 -122
- package/dist/track-heuristics.d.ts +0 -27
- package/dist/track-heuristics.js +0 -154
- package/dist/util/slice-id.d.ts +0 -58
- package/dist/util/slice-id.js +0 -89
- package/dist/worktree-manager.d.ts +0 -20
- package/dist/worktree-manager.js +0 -108
package/dist/content/skills.js
CHANGED
|
@@ -1,827 +1,776 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { INVESTIGATION_DISCIPLINE_BLOCK } from "./templates.js";
|
|
6
|
-
import { reviewStackAwareRoutes, reviewStackAwareRoutingSummary, stageAutoSubagentDispatch, stageSchema, stageTrackRenderContext } from "./stage-schema.js";
|
|
7
|
-
import { renderTrackTerminology } from "./track-render-context.js";
|
|
8
|
-
import { referencePatternsForStage } from "./reference-patterns.js";
|
|
9
|
-
import { harnessDelegationRecipes } from "../harness-adapters.js";
|
|
10
|
-
const VERIFICATION_STAGES = ["tdd", "review", "ship"];
|
|
11
|
-
const STAGE_LANGUAGE_POLICY_POINTER = "> Language policy: see `using-cclaw` section `Conversation Language Policy`.";
|
|
12
|
-
// ---------- Cross-cutting universal mechanics (Layer 2 building blocks) ----------
|
|
13
|
-
//
|
|
14
|
-
// These are shared, structural blocks that get injected into every stage skill.
|
|
15
|
-
// They check structural shape, not domain content. Each has a matching linter
|
|
16
|
-
// rule in `src/artifact-linter.ts` so artifacts can fail when shape is missing.
|
|
17
|
-
export const FORBIDDEN_SYCOPHANCY_PHRASES = [
|
|
18
|
-
"you're absolutely right",
|
|
19
|
-
"great point",
|
|
20
|
-
"absolutely!",
|
|
21
|
-
"thanks for catching",
|
|
22
|
-
"thanks for the great",
|
|
23
|
-
"good catch",
|
|
24
|
-
"love this",
|
|
25
|
-
"nailed it"
|
|
26
|
-
];
|
|
27
|
-
export const FORBIDDEN_PLACEHOLDER_TOKENS = [
|
|
28
|
-
"TBD",
|
|
29
|
-
"TODO",
|
|
30
|
-
"FIXME",
|
|
31
|
-
"implement later",
|
|
32
|
-
"similar to Task",
|
|
33
|
-
"add appropriate error handling",
|
|
34
|
-
"add proper logging",
|
|
35
|
-
"fill this in",
|
|
36
|
-
"<placeholder>"
|
|
37
|
-
];
|
|
38
|
-
export const CONFIDENCE_FINDING_REGEX_SOURCE = "\\[P[123]\\]\\s*\\(confidence:\\s*\\d{1,2}/10\\)\\s+[^\\s]+(?::\\d+)?\\s+—";
|
|
39
|
-
export function stopPerIssueBlock() {
|
|
40
|
-
return `## STOP-per-issue Protocol
|
|
1
|
+
const PLAN_AUTHORING = `---
|
|
2
|
+
name: plan-authoring
|
|
3
|
+
trigger: when writing or updating .cclaw/flows/<slug>/plan.md
|
|
4
|
+
---
|
|
41
5
|
|
|
42
|
-
|
|
6
|
+
# Skill: plan-authoring
|
|
43
7
|
|
|
44
|
-
|
|
45
|
-
- \`decision:\` — \`accept\` / \`reject\` / \`defer\` / \`skip — no issues\`
|
|
46
|
-
- \`rationale:\` — one line, evidence-backed
|
|
8
|
+
Use this skill whenever you create or modify any \`.cclaw/flows/<slug>/plan.md\`.
|
|
47
9
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
1. **Frontmatter is mandatory.** Every plan starts with the YAML block from \`.cclaw/lib/templates/plan.md\`. Required keys: \`slug\`, \`stage\`, \`status\`, \`ac\`, \`last_specialist\`, \`refines\`, \`shipped_at\`, \`ship_commit\`, \`review_iterations\`, \`security_flag\`.
|
|
13
|
+
2. **AC ids are sequential** starting at \`AC-1\`. They must match the AC table inside the body.
|
|
14
|
+
3. **Each AC is observable.** Verification line is mandatory. If you cannot write the verification, the AC is not real.
|
|
15
|
+
4. **The traceability block at the end** is rebuilt by \`commit-helper.mjs\`. Do not edit it by hand once a commit was recorded.
|
|
16
|
+
5. **Out-of-scope items** stay in the body. Do not let them leak into AC.
|
|
17
|
+
|
|
18
|
+
## When refining a shipped slug
|
|
53
19
|
|
|
54
|
-
|
|
20
|
+
- Quote at most one paragraph from \`.cclaw/flows/shipped/<old-slug>/plan.md\`.
|
|
21
|
+
- Set \`refines: <old-slug>\` in the new plan's frontmatter.
|
|
22
|
+
- Do not copy the shipped AC verbatim — write fresh AC for the refinement.
|
|
55
23
|
|
|
56
|
-
|
|
24
|
+
## What to refuse
|
|
57
25
|
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
- Never assert "this is fine" without confidence; never assert confidence above \`8\` without a cited artifact, line, or test.
|
|
26
|
+
- Plans without AC.
|
|
27
|
+
- Plans whose AC count exceeds 12 (split first).
|
|
28
|
+
- Plans that change scope between brainstormer and planner without going back to brainstormer.
|
|
62
29
|
`;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
30
|
+
const AC_TRACEABILITY = `---
|
|
31
|
+
name: ac-traceability
|
|
32
|
+
trigger: when committing changes for an active cclaw run
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Skill: ac-traceability
|
|
36
|
+
|
|
37
|
+
cclaw has one mandatory gate: every commit produced inside \`/cc\` references exactly one AC, and the AC ↔ commit chain is recorded in \`flow-state.json\`.
|
|
66
38
|
|
|
67
|
-
|
|
39
|
+
## Rules
|
|
68
40
|
|
|
69
|
-
- \`
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- \`
|
|
41
|
+
1. Use \`node .cclaw/hooks/commit-helper.mjs --ac=AC-N --message="..."\` for every AC commit. Do not call \`git commit\` directly.
|
|
42
|
+
2. Stage only AC-related changes before invoking the hook.
|
|
43
|
+
3. The hook will refuse the commit if:
|
|
44
|
+
- \`AC-N\` is not declared in the active plan;
|
|
45
|
+
- \`flow-state.json\` schemaVersion is not \`2\`;
|
|
46
|
+
- nothing is staged.
|
|
47
|
+
4. After the commit succeeds, the hook records the SHA in \`flow-state.json\` under the matching AC and re-renders the traceability block in \`plans/<slug>.md\`.
|
|
48
|
+
5. \`runCompoundAndShip\` refuses to ship a slug with any pending AC. There is no override.
|
|
73
49
|
|
|
74
|
-
|
|
50
|
+
## When you accidentally committed without the hook
|
|
51
|
+
|
|
52
|
+
- \`flow-state.json\` is now out of sync with the working tree.
|
|
53
|
+
- Run the hook manually for the affected AC: \`node .cclaw/hooks/commit-helper.mjs --ac=AC-N --message="resync"\` while staging an empty change is not allowed; instead, edit \`.cclaw/state/flow-state.json\` to add the SHA to the AC entry by hand and verify with the orchestrator before continuing.
|
|
75
54
|
`;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
55
|
+
const REFINEMENT = `---
|
|
56
|
+
name: refinement
|
|
57
|
+
trigger: when /cc detects an existing plan (active or shipped) for the new task
|
|
58
|
+
---
|
|
80
59
|
|
|
81
|
-
|
|
60
|
+
# Skill: refinement
|
|
82
61
|
|
|
83
|
-
|
|
62
|
+
\`/cc\` performs existing-plan detection at the start of every invocation. When it finds a fuzzy match, the user is asked to choose one of:
|
|
84
63
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
64
|
+
- **amend** — keep the active plan, add new AC, leave already-committed AC intact;
|
|
65
|
+
- **rewrite** — replace the active plan body and AC entirely (commits remain in git, but AC ids restart);
|
|
66
|
+
- **refine shipped** — create a new plan with \`refines: <old-slug>\` linking to the shipped slug;
|
|
67
|
+
- **new** — start an unrelated plan.
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
69
|
+
## Rules for refinement
|
|
70
|
+
|
|
71
|
+
1. \`refines: <old-slug>\` is set in the new plan's frontmatter and must match a real shipped slug.
|
|
72
|
+
2. Do not move artifacts out of \`.cclaw/flows/shipped/\`. The shipped slug stays read-only.
|
|
73
|
+
3. The new plan can quote up to one paragraph from the shipped plan but must restate the full Context for the refinement.
|
|
74
|
+
4. AC ids restart at AC-1 in the new plan. Do not number "AC-13" because the shipped slug had 12 AC.
|
|
75
|
+
5. \`knowledge.jsonl\` will record the new entry with \`refines: <old-slug>\` so the index forms a chain.
|
|
76
|
+
|
|
77
|
+
## What the orchestrator surfaces
|
|
95
78
|
|
|
96
|
-
|
|
79
|
+
- last_specialist of the active plan, so the user can see "stopped at architect" or "review iteration 3 in progress".
|
|
80
|
+
- The AC table with their statuses (\`pending\` / \`committed\`).
|
|
81
|
+
- Whether \`security_flag\` was set.
|
|
82
|
+
- A direct link to \`.cclaw/flows/shipped/<slug>/manifest.md\` if the match is a shipped slug.
|
|
97
83
|
`;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
const PARALLEL_BUILD = `---
|
|
85
|
+
name: parallel-build
|
|
86
|
+
trigger: when planner topology = parallel-build
|
|
87
|
+
---
|
|
101
88
|
|
|
102
|
-
|
|
89
|
+
# Skill: parallel-build
|
|
103
90
|
|
|
104
|
-
\`
|
|
91
|
+
\`parallel-build\` is the only parallelism allowed during build. It is opt-in. The orchestrator never picks it without planner naming it explicitly in \`plans/<slug>.md\` Topology section.
|
|
105
92
|
|
|
106
|
-
|
|
107
|
-
`;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Stages that perform real investigation work. The shared
|
|
111
|
-
* `INVESTIGATION_DISCIPLINE_BLOCK` is rendered once per stage skill in this
|
|
112
|
-
* set so the search → graph → narrow-read → draft ladder appears verbatim
|
|
113
|
-
* across the elicitation/spec/plan/tdd/review pipeline. `ship` is excluded:
|
|
114
|
-
* it consumes the upstream trace rather than producing one.
|
|
115
|
-
*/
|
|
116
|
-
export const INVESTIGATION_DISCIPLINE_STAGES = new Set([
|
|
117
|
-
"brainstorm",
|
|
118
|
-
"scope",
|
|
119
|
-
"design",
|
|
120
|
-
"spec",
|
|
121
|
-
"plan",
|
|
122
|
-
"tdd",
|
|
123
|
-
"review"
|
|
124
|
-
]);
|
|
125
|
-
export function investigationDisciplineBlock() {
|
|
126
|
-
return INVESTIGATION_DISCIPLINE_BLOCK;
|
|
127
|
-
}
|
|
128
|
-
export function behaviorAnchorBlock(stage) {
|
|
129
|
-
const anchor = behaviorAnchorFor(stage);
|
|
130
|
-
if (!anchor)
|
|
131
|
-
return "";
|
|
132
|
-
const ruleHint = anchor.ruleHint && anchor.ruleHint.trim().length > 0
|
|
133
|
-
? `\n\nRule hint: ${anchor.ruleHint.trim()}`
|
|
134
|
-
: "";
|
|
135
|
-
return `## Behavior anchor
|
|
136
|
-
|
|
137
|
-
Anchored to artifact section: \`${anchor.section}\`.
|
|
138
|
-
|
|
139
|
-
- Bad: ${anchor.bad}
|
|
140
|
-
- Good: ${anchor.good}${ruleHint}
|
|
141
|
-
`;
|
|
142
|
-
}
|
|
143
|
-
function crossCuttingMechanicsBlock(stage) {
|
|
144
|
-
// All stages share the universal mechanics, but each stage's matching
|
|
145
|
-
// linter rules decide what is mandatory vs. structural-only.
|
|
146
|
-
const blocks = [
|
|
147
|
-
stopPerIssueBlock(),
|
|
148
|
-
confidenceCalibrationBlock(),
|
|
149
|
-
outsideVoiceSlotBlock(),
|
|
150
|
-
antiSycophancyBlock(),
|
|
151
|
-
noPlaceholdersBlock()
|
|
152
|
-
];
|
|
153
|
-
if (stage === "tdd" || stage === "review" || stage === "ship") {
|
|
154
|
-
blocks.push(watchedFailProofBlock());
|
|
155
|
-
}
|
|
156
|
-
if (INVESTIGATION_DISCIPLINE_STAGES.has(stage)) {
|
|
157
|
-
blocks.push(investigationDisciplineBlock());
|
|
158
|
-
}
|
|
159
|
-
const anchor = behaviorAnchorBlock(stage);
|
|
160
|
-
if (anchor.length > 0) {
|
|
161
|
-
blocks.push(anchor);
|
|
162
|
-
}
|
|
163
|
-
return blocks.join("\n");
|
|
164
|
-
}
|
|
165
|
-
function whenNotToUseBlock(items) {
|
|
166
|
-
if (items.length === 0) {
|
|
167
|
-
return "";
|
|
168
|
-
}
|
|
169
|
-
return `## When Not to Use
|
|
170
|
-
${items.map((item) => `- ${item}`).join("\n")}
|
|
93
|
+
## Pre-conditions (all must hold)
|
|
171
94
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
* `slice-builder` dispatch. Uses literal commands so pattern-matching on read
|
|
177
|
-
* matches operator scripts.
|
|
178
|
-
*
|
|
179
|
-
* Empty for non-TDD stages.
|
|
180
|
-
*/
|
|
181
|
-
export function tddTopOfSkillBlock(stage) {
|
|
182
|
-
if (stage !== "tdd")
|
|
183
|
-
return "";
|
|
184
|
-
return `## TDD orchestration primer
|
|
95
|
+
1. **≥4 AC** in the plan.
|
|
96
|
+
2. **≥2 distinct touchSurface clusters** — there is at least one pair of AC whose \`touchSurface\` arrays are completely disjoint.
|
|
97
|
+
3. Every AC in a parallel wave carries \`parallelSafe: true\`.
|
|
98
|
+
4. No AC depends on outputs of another AC in the same wave.
|
|
185
99
|
|
|
186
|
-
|
|
100
|
+
For ≤4 AC the orchestrator picks \`inline\` even when AC look "parallelSafe". The git-worktree + sub-agent dispatch overhead is not worth saving 1-2 AC of wall-clock.
|
|
187
101
|
|
|
188
|
-
|
|
189
|
-
\`node .cclaw/cli.mjs internal wave-status --json\`
|
|
102
|
+
## Slice = 1+ AC with shared touchSurface
|
|
190
103
|
|
|
191
|
-
|
|
104
|
+
A **slice** is one or more AC whose \`touchSurface\` arrays intersect. AC with disjoint touchSurfaces go into different slices; AC with overlapping touchSurfaces stay in the **same** slice (run sequentially inside it). Each slice is owned by exactly one slice-builder sub-agent.
|
|
192
105
|
|
|
193
|
-
|
|
106
|
+
## Hard cap: 5 parallel slices per wave
|
|
194
107
|
|
|
195
|
-
|
|
196
|
-
|---------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
|
197
|
-
| \`parallel-builders\` | \`[]\` | **Fan out independent substantial units in one tool batch.** Emit one \`Task\` per routed ready builder in a single controller message. Do NOT ask. |
|
|
198
|
-
| \`single-builder\` | any/none | Dispatch one \`slice-builder\` for the next feature-atomic unit; serialize remaining ready units. |
|
|
199
|
-
| \`inline\` | \`[]\` | Execute inline only for low-risk inline-safe units; record equivalent RED/GREEN/REFACTOR evidence before completion. |
|
|
200
|
-
| \`strict-micro\` | any/none | Preserve micro-slice sequencing: one tiny task/slice at a time unless the strict plan explicitly proves safe fan-out. |
|
|
201
|
-
| \`blocked\`/mode blocked | non-empty | Issue exactly one AskQuestion (resolve overlap, split/serialize, or adjust claimedPaths), then re-run \`wave-status\`. |
|
|
108
|
+
If the slug produces more than 5 slices, **merge the thinner slices into fatter ones** (group AC by adjacent files / shared module) until you have ≤5. **Do not generate "wave 2", "wave 3", etc.** If after merging you still have >5 slices, the slug is too large — split it into multiple slugs.
|
|
202
109
|
|
|
203
|
-
|
|
110
|
+
This 5-slice cap is the v7-era constraint we kept on purpose:
|
|
204
111
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
4. The slice-builder span ACKs locally (\`delegation-record --status=acknowledged\`) and runs the **complete** RED → GREEN → REFACTOR → DOC cycle inside the span — including writing \`tdd-slices/S-<id>.md\` and emitting \`--phase=red\`, \`--phase=green\`, \`--phase=refactor\` (or \`--phase=refactor-deferred\` with rationale), and \`--phase=doc\` rows on its own.
|
|
209
|
-
5. The controller waits for ALL parallel spans to terminate before reconciling. Do not page back into the controller chat between spans.
|
|
112
|
+
- orchestration cost grows non-linearly past 5 sub-agents (context shuffling, integration review, conflict surface);
|
|
113
|
+
- 5 fits comfortably under the harness sub-agent quota everywhere we tested (Claude Code, Cursor, OpenCode, Codex);
|
|
114
|
+
- larger fan-outs reliably produce more integration findings than wall-clock saved.
|
|
210
115
|
|
|
211
|
-
|
|
116
|
+
## Execution
|
|
212
117
|
|
|
213
|
-
|
|
118
|
+
1. Orchestrator reads \`plans/<slug>.md\` Topology section, extracts the slice list (max 5).
|
|
119
|
+
2. For each slice, dispatch one \`slice-builder\` sub-agent. Pass:
|
|
120
|
+
- the slice id,
|
|
121
|
+
- the AC ids it owns,
|
|
122
|
+
- the slice's \`touchSurface\` (the only paths the slice may modify),
|
|
123
|
+
- the worktree path (see below).
|
|
124
|
+
3. Each slice-builder runs the full TDD cycle (RED → GREEN → REFACTOR) for every AC it owns, sequentially inside the slice, in its own working tree.
|
|
125
|
+
4. After all slice-builders return, the orchestrator invokes \`reviewer\` in mode \`integration\` (separate sub-agent if the harness supports it; inline otherwise). Integration reviewer checks path conflicts, double-edits, the AC↔commit chain across all slices, and integration tests covering the slice boundary.
|
|
126
|
+
5. If integration finds problems, the orchestrator dispatches \`slice-builder\` in \`fix-only\` mode against the cited file:line refs.
|
|
214
127
|
|
|
215
|
-
|
|
216
|
-
2. If \`integrationCheckRequired\` is true, dispatch \`integration-overseer\` (proactive) and append the \`cclaw_integration_overseer_skipped\` audit kind only when the contract waives it.
|
|
217
|
-
3. If \`wave-status\` reports another \`wave-fanout\` next dispatch with disjoint paths, **immediately repeat Step 2 — do not pause for \"continue\"**.
|
|
218
|
-
4. When all waves are closed and no more slices remain ready, run \`stage-complete tdd\`.
|
|
128
|
+
## Git-worktree pattern (when harness supports sub-agent dispatch)
|
|
219
129
|
|
|
220
|
-
|
|
130
|
+
Each parallel slice runs in its own \`git worktree\` rooted at \`.cclaw/worktrees/<slug>-<slice-id>/\`:
|
|
221
131
|
|
|
222
|
-
|
|
132
|
+
\`\`\`bash
|
|
133
|
+
$ git worktree add .cclaw/worktrees/<slug>-slice-1 -b cclaw/<slug>/slice-1
|
|
134
|
+
$ git worktree add .cclaw/worktrees/<slug>-slice-2 -b cclaw/<slug>/slice-2
|
|
135
|
+
$ git worktree add .cclaw/worktrees/<slug>-slice-3 -b cclaw/<slug>/slice-3
|
|
136
|
+
\`\`\`
|
|
223
137
|
|
|
224
|
-
|
|
225
|
-
`;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Review-only prelude: mandates parallel reviewer / security-reviewer dispatch
|
|
229
|
-
* via harness Task and forbids inline authoring of findings.
|
|
230
|
-
*
|
|
231
|
-
* Empty for non-review stages.
|
|
232
|
-
*/
|
|
233
|
-
export function reviewTopOfSkillBlock(stage) {
|
|
234
|
-
if (stage !== "review")
|
|
235
|
-
return "";
|
|
236
|
-
return `## Review orchestration primer
|
|
237
|
-
|
|
238
|
-
**MANDATE — controller never authors findings inline.** In review the controller orchestrates; \`reviewer\` (functional/spec/correctness/architecture/perf/observability) and \`security-reviewer\` (security sweep + dependency/version audit) are the **mandatory delegated workers** that produce findings, lens coverage, and the verdict input. Typing \`## Layer 1 Findings\`, \`## Layer 2 Findings\`, \`## Lens Coverage\`, or \`## Final Verdict\` content directly into \`07-review.md\` in the controller chat is a protocol violation. The controller writes ONLY the reconciled multi-specialist verdict block AFTER all reviewer Tasks return.
|
|
239
|
-
|
|
240
|
-
**Step 1 — Diff scope (always first):**
|
|
241
|
-
\`git diff --stat <base>...HEAD\` and \`git diff --name-only <base>...HEAD\`.
|
|
242
|
-
If the diff is empty, exit early with APPROVED (no changes to review).
|
|
243
|
-
|
|
244
|
-
**Step 2 — Dispatch the review army in PARALLEL (single controller message):**
|
|
245
|
-
|
|
246
|
-
| Lens | Worker | Mandatory? |
|
|
247
|
-
|--------------------------|-----------------------|------------|
|
|
248
|
-
| Spec compliance / Layer 1 | \`reviewer\` | yes |
|
|
249
|
-
| Layer 2 cross-slice / correctness / observability | \`reviewer\` | yes |
|
|
250
|
-
| Security sweep + dep/version audit | \`security-reviewer\` | yes (or \`NO_SECURITY_IMPACT\` attestation) |
|
|
251
|
-
| Adversarial second opinion | \`reviewer\` (adversarial framing) | only if trust boundaries moved OR diff is large+high-risk |
|
|
252
|
-
|
|
253
|
-
Emit ONE \`Task\` per lens in a single controller message. For each lens:
|
|
254
|
-
|
|
255
|
-
1. Append \`delegation-record --status=scheduled\` for the lens span (one row per lens; reuse the same \`spanId\` for the lens lifecycle).
|
|
256
|
-
2. Append \`delegation-record --status=launched\` immediately after.
|
|
257
|
-
3. Issue the harness Task call: \`Task(subagent_type=<harness reviewer/security-reviewer mapping>, description="<lens> review", prompt="<diff range, files, AC ids, upstream artifacts (spec, design, tdd Per-Slice Reviews), expected output schema for 07-review-army.json>")\`.
|
|
258
|
-
4. The reviewer span ACKs locally and writes its findings/lens coverage to \`07-review-army.json\` (and the structured findings table in \`07-review.md\`) on its own — including \`NO_SECURITY_IMPACT\` rationale if a security pass yields zero findings.
|
|
259
|
-
5. The controller waits for ALL lens spans to return before reconciling.
|
|
260
|
-
|
|
261
|
-
**Step 3 — Reconcile and verdict:** after all lens spans complete:
|
|
262
|
-
|
|
263
|
-
1. Run \`validateReviewArmy\` (helper or linter) on \`07-review-army.json\`.
|
|
264
|
-
2. Dedup by fingerprint, mark multi-specialist confirmations.
|
|
265
|
-
3. Confirm acceptance criteria coverage and Pre-Critic / Lens Coverage / Anti-sycophancy fields are present (linter requires them).
|
|
266
|
-
4. Compute the final verdict: APPROVED, APPROVED_WITH_CONCERNS, or BLOCKED.
|
|
267
|
-
5. If BLOCKED, emit \`ROUTE_BACK_TO_TDD\` with the blocking finding ids and the managed \`npx cclaw-cli internal rewind tdd\` command. Do NOT silently stop.
|
|
268
|
-
|
|
269
|
-
**Step 4 — Auto-advance after stage-complete:** when \`stage-complete review\` returns \`ok\` with a new \`currentStage\` (typically \`ship\`), immediately load the next stage skill and continue. Announce \"Stage review complete → entering <next>. Continuing.\" and proceed without waiting for the user to retype \`/cc\`.
|
|
138
|
+
Each slice-builder sub-agent runs with its worktree path as cwd. After all slices finish:
|
|
270
139
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
Before execution:
|
|
293
|
-
1. Read \`.cclaw/state/flow-state.json\`.
|
|
294
|
-
- If the file is missing, do **not** invent an active run — this is normal for fresh init. Route to \`/cc <idea>\` first.
|
|
295
|
-
2. Load active artifacts from \`.cclaw/artifacts/\`.
|
|
296
|
-
3. Load upstream artifacts required by this stage:
|
|
297
|
-
${readLines}
|
|
298
|
-
4. Read the state contract from \`.cclaw/templates/state-contracts/<stage>.json\` for required fields, taxonomies, and derived markdown path.
|
|
299
|
-
5. Read the canonical artifact template at \`${artifactTemplatePath}\` to preserve heading/per-row tables contracts (stable section names and column order) plus calibrated review block scaffolding. Preserve existing substantive bullets/rows already in the artifact; never overwrite the artifact wholesale from the template — patch only sections you author this turn.
|
|
300
|
-
6. Extract upstream decisions, constraints, and open questions into the current artifact's \`Upstream Handoff\` section when present.
|
|
301
|
-
7. Confirm context readiness: upstream artifact freshness, required context, canonical template shape, relevant in-repo/reference patterns, and unresolved blockers are known. If any item is missing, load it or stop before drafting.
|
|
302
|
-
8. Before doing stage work, give a compact user-facing drift preamble: "Carrying forward: <1-3 bullets>. Drift since upstream: None / <specific drift>. Recommendation: continue / re-scope."
|
|
303
|
-
9. If you change an upstream decision, record an explicit drift reason in the current artifact before continuing.
|
|
304
|
-
10. Confirm stage inputs:
|
|
305
|
-
${inputs}
|
|
306
|
-
11. Confirm required context:
|
|
307
|
-
${requiredContext}
|
|
308
|
-
12. Use the injected knowledge digest; only fall back to full \`.cclaw/knowledge.jsonl\` when insufficient.
|
|
309
|
-
`;
|
|
310
|
-
}
|
|
311
|
-
function autoSubagentDispatchBlock(stage, track) {
|
|
312
|
-
const rules = stageAutoSubagentDispatch(stage);
|
|
313
|
-
if (rules.length === 0)
|
|
314
|
-
return "";
|
|
315
|
-
const schema = stageSchema(stage, track);
|
|
316
|
-
const rows = rules
|
|
317
|
-
.map((rule) => {
|
|
318
|
-
const userGate = rule.requiresUserGate ? "required" : "not required";
|
|
319
|
-
const dispatchClass = rule.dispatchClass ?? "stage-specialist";
|
|
320
|
-
const returnSchema = rule.returnSchema ?? "agent-default";
|
|
321
|
-
const runPhase = rule.runPhase ?? "any";
|
|
322
|
-
return `| ${rule.agent} | ${rule.mode} | ${runPhase} | ${dispatchClass} | ${returnSchema} | ${userGate} | ${rule.when} | ${rule.purpose} |`;
|
|
323
|
-
})
|
|
324
|
-
.join("\n");
|
|
325
|
-
const mandatory = schema.mandatoryDelegations;
|
|
326
|
-
const mandatoryList = mandatory.length > 0 ? mandatory.map((a) => `\`${a}\``).join(", ") : "none";
|
|
327
|
-
const delegationLogRel = `${RUNTIME_ROOT}/state/delegation-log.json`;
|
|
328
|
-
const delegationEventsRel = `${RUNTIME_ROOT}/state/delegation-events.jsonl`;
|
|
329
|
-
const hasPostElicitation = rules.some((rule) => rule.runPhase === "post-elicitation");
|
|
330
|
-
const runPhaseLegend = hasPostElicitation
|
|
331
|
-
? `\nRun Phase legend: \`post-elicitation\` = run only AFTER the adaptive elicitation Q&A loop converges (forcing questions answered/skipped/waived OR user stop-signal recorded). \`pre-elicitation\` = run before any user dialogue (rare). \`any\` = no ordering constraint.`
|
|
332
|
-
: "";
|
|
333
|
-
return `## Automatic Subagent Dispatch
|
|
334
|
-
| Agent | Mode | Run Phase | Class | Return Schema | User Gate | Trigger | Purpose |
|
|
335
|
-
|---|---|---|---|---|---|---|---|
|
|
336
|
-
${rows}
|
|
337
|
-
Mandatory: ${mandatoryList}. Record lifecycle rows in \`${delegationLogRel}\` and append-only \`${delegationEventsRel}\` before completion.${runPhaseLegend}
|
|
338
|
-
### Harness Dispatch Contract — use true harness dispatch: Claude Task, Cursor generic dispatch, OpenCode \`.opencode/agents/<agent>.md\` via Task/@agent, Codex \`.codex/agents/<agent>.toml\`. Do not collapse OpenCode or Codex to role-switch by default. Worker ACK Contract: ACK must include \`spanId\`, \`dispatchId\`, \`dispatchSurface\`, \`agentDefinitionPath\`, and \`ackTs\`; never claim \`fulfillmentMode: "isolated"\` without matching lifecycle proof. Canonical helper (same flags as \`delegation-record.mjs --help\`): \`node .cclaw/hooks/delegation-record.mjs --stage=<stage> --agent=<agent> --mode=<mandatory|proactive> --status=<scheduled|launched|acknowledged|completed|...> --span-id=<id> --dispatch-id=<id> --dispatch-surface=<surface> --agent-definition-path=<path> [--ack-ts=<iso>] [--evidence-ref=<ref>] --json\`. Lifecycle order: \`scheduled → launched → acknowledged → completed\` on one span (reuse the same span id); completed isolated/generic rows require a prior ACK event for that span or \`--ack-ts=<iso>\`. For a partial audit trail, \`--repair --span-id=<id> --repair-reason="<why>"\` appends missing phases (see \`--help\`) instead of inventing shortcuts.
|
|
339
|
-
|
|
340
|
-
If you must re-dispatch the same agent in the same stage before the previous span has a terminal row, pass \`--supersede=<prevSpanId>\` (closes the previous span as \`stale\` with \`supersededBy=<newSpanId>\`) or \`--allow-parallel\` (records both spans as concurrently active and tags the new row with \`allowParallel: true\`). Without one of those flags, a duplicate scheduled write on the same \`(stage, agent)\` pair fails with \`exit 2\` and \`{ ok: false, error: "dispatch_duplicate" }\`. Lifecycle timestamps are also validated: \`startTs ≤ launchedTs ≤ ackTs ≤ completedTs\` and per-span \`ts\` is non-decreasing — non-monotonic values fail with \`exit 2\` and \`{ ok: false, error: "delegation_timestamp_non_monotonic" }\`.
|
|
341
|
-
|
|
342
|
-
${perHarnessLifecycleRecipeBlock()}`;
|
|
343
|
-
}
|
|
344
|
-
function perHarnessLifecycleRecipeBlock() {
|
|
345
|
-
const recipes = harnessDelegationRecipes();
|
|
346
|
-
const rows = recipes
|
|
347
|
-
.map((recipe) => `| \`${recipe.harnessId}\` | \`${recipe.dispatchSurface}\` | \`${recipe.agentDefinitionExample}\` | \`${recipe.fulfillmentMode}\` |`)
|
|
348
|
-
.join("\n");
|
|
349
|
-
return `### Per-Harness Lifecycle Recipe — placeholders only
|
|
350
|
-
Reuse the same \`<span-id>\` and \`<dispatch-id>\` across scheduled -> launched -> acknowledged -> completed; substitute neutral tokens \`<agent-name>\`, \`<stage>\`, \`<iso-ts>\`, \`<artifact-anchor>\`. Full command sequences live in \`docs/harnesses.md\`.
|
|
351
|
-
| Harness | Dispatch surface | Agent definition path | fulfillmentMode |
|
|
352
|
-
|---|---|---|---|
|
|
353
|
-
${rows}
|
|
354
|
-
`;
|
|
355
|
-
}
|
|
356
|
-
function researchPlaybooksBlock(playbooks) {
|
|
357
|
-
if (playbooks.length === 0)
|
|
358
|
-
return "";
|
|
359
|
-
const rows = playbooks
|
|
360
|
-
.map((playbook) => `\`${RUNTIME_ROOT}/skills/${playbook}\``)
|
|
361
|
-
.join("; ");
|
|
362
|
-
return `## Research Playbooks
|
|
363
|
-
Execute in primary agent context before locking the stage; record outcomes in the artifact when relevant: ${rows}.
|
|
364
|
-
`;
|
|
365
|
-
}
|
|
366
|
-
function referencePatternsBlock(stage) {
|
|
367
|
-
const patterns = referencePatternsForStage(stage);
|
|
368
|
-
if (patterns.length === 0)
|
|
369
|
-
return "";
|
|
370
|
-
const summaries = patterns
|
|
371
|
-
.map((pattern) => {
|
|
372
|
-
const contract = pattern.contracts.find((item) => item.stage === stage);
|
|
373
|
-
const sections = contract ? contract.artifactSections.join(", ") : "n/a";
|
|
374
|
-
return `${pattern.title} (sections: ${sections})`;
|
|
375
|
-
})
|
|
376
|
-
.join("; ");
|
|
377
|
-
return `## Reference Patterns
|
|
378
|
-
Prompt-only; no runtime/delegation changes. These compact pattern titles come from the internal registry; use the behavior and artifact sections, not the source project history. Use: ${summaries}.
|
|
379
|
-
`;
|
|
380
|
-
}
|
|
381
|
-
function reviewSectionsBlock(sectionsInput) {
|
|
382
|
-
if (sectionsInput.length === 0)
|
|
383
|
-
return "";
|
|
384
|
-
const sections = sectionsInput
|
|
385
|
-
.map((sec) => {
|
|
386
|
-
const points = sec.evaluationPoints.map((p) => `- ${p}`).join("\n");
|
|
387
|
-
const title = sec.stopGate ? `${sec.title} (STOP gate)` : sec.title;
|
|
388
|
-
return `### ${title}\n${points}`;
|
|
389
|
-
})
|
|
390
|
-
.join("\n\n");
|
|
391
|
-
return `## Review Sections
|
|
392
|
-
|
|
393
|
-
${sections}
|
|
394
|
-
`;
|
|
395
|
-
}
|
|
396
|
-
function stackAwareReviewRoutingBlock(stage) {
|
|
397
|
-
if (stage !== "review")
|
|
398
|
-
return "";
|
|
399
|
-
const routes = reviewStackAwareRoutes()
|
|
400
|
-
.map((route) => `- ${route.stack}: ${route.signals.map((signal) => `\`${signal}\``).join(", ")} -> ${route.agent} lens for ${route.focus}.`)
|
|
401
|
-
.join("\n");
|
|
402
|
-
return `## Stack-Aware Review Routing
|
|
403
|
-
${reviewStackAwareRoutingSummary()}
|
|
404
|
-
|
|
405
|
-
Default general review still runs. Add only the matching stack lens when repo signals or changed files justify it.
|
|
406
|
-
|
|
407
|
-
${routes}
|
|
408
|
-
`;
|
|
409
|
-
}
|
|
410
|
-
function reviewLoopBlock(reviewLoop) {
|
|
411
|
-
if (!reviewLoop)
|
|
412
|
-
return "";
|
|
413
|
-
const checklist = reviewLoop.checklist.map((item) => `- \`${item}\``).join("\n");
|
|
414
|
-
return `## Outside Voice Review Loop
|
|
415
|
-
- Stage: \`${reviewLoop.stage}\`
|
|
416
|
-
- Target score: \`${reviewLoop.targetScore}\`
|
|
417
|
-
- Max iterations: \`${reviewLoop.maxIterations}\`
|
|
418
|
-
- Checklist dimensions:
|
|
419
|
-
${checklist}
|
|
420
|
-
`;
|
|
421
|
-
}
|
|
422
|
-
function verificationBlock(stage) {
|
|
423
|
-
if (!VERIFICATION_STAGES.includes(stage))
|
|
424
|
-
return "";
|
|
425
|
-
return `## Verification Before Completion
|
|
426
|
-
|
|
427
|
-
This is the gate function for completion claims. No "done", "all good", or
|
|
428
|
-
"tests pass" unless fresh evidence from this turn proves it.
|
|
429
|
-
|
|
430
|
-
- Run verification commands (tests/build/lint/type-check) for the changed scope.
|
|
431
|
-
- Before \`tdd -> review\` and \`review -> ship\`, discover the real test command
|
|
432
|
-
from repo config (package scripts, pytest/go/cargo/maven/gradle signals) and
|
|
433
|
-
cite that exact command in the gate evidence.
|
|
434
|
-
- Confirm output directly; do not infer success from prior runs or green memories.
|
|
435
|
-
- If this is a bug fix, capture RED -> GREEN evidence for the regression path.
|
|
436
|
-
- If a command fails, report the failure as diagnostic evidence and stop before completion.
|
|
437
|
-
- If you only inspected files or reasoned about the change, say so; that is not verification.
|
|
438
|
-
|
|
439
|
-
Keep this verification evidence in the artifact before completion.
|
|
440
|
-
`;
|
|
441
|
-
}
|
|
442
|
-
function batchExecutionModeBlock(stage, track) {
|
|
443
|
-
const schema = stageSchema(stage, track);
|
|
444
|
-
if (!schema.batchExecutionAllowed)
|
|
445
|
-
return "";
|
|
446
|
-
const orderingGuidance = track === "quick"
|
|
447
|
-
? "Use spec acceptance items / bug reproduction slices for ordering."
|
|
448
|
-
: "Use plan slices for ordering.";
|
|
449
|
-
return `## Batch Execution Mode
|
|
450
|
-
|
|
451
|
-
Execute the current dependency batch task-by-task (RED -> GREEN -> REFACTOR).
|
|
452
|
-
Stop on BLOCKED status or when user input is required.
|
|
453
|
-
Apply concise turn announces: one announce per batch boundary (or when risk/source
|
|
454
|
-
changes materially), then execute tasks without repetitive boilerplate.
|
|
455
|
-
|
|
456
|
-
Detailed walkthrough:
|
|
457
|
-
${orderingGuidance} Keep RED -> GREEN -> REFACTOR evidence in the TDD artifact.
|
|
458
|
-
`;
|
|
459
|
-
}
|
|
460
|
-
function crossStageTraceBlock(trace) {
|
|
461
|
-
const reads = trace.readsFrom.length > 0
|
|
462
|
-
? trace.readsFrom.map((r) => `- ${r}`).join("\n")
|
|
463
|
-
: "- (first stage — no upstream artifacts)";
|
|
464
|
-
const writes = trace.writesTo.length > 0
|
|
465
|
-
? trace.writesTo.map((w) => `- ${w}`).join("\n")
|
|
466
|
-
: "- (terminal stage)";
|
|
467
|
-
return `## Cross-Stage Traceability
|
|
468
|
-
|
|
469
|
-
Reads from:
|
|
470
|
-
${reads}
|
|
471
|
-
|
|
472
|
-
Writes to:
|
|
473
|
-
${writes}
|
|
474
|
-
|
|
475
|
-
Rule: ${trace.traceabilityRule}
|
|
140
|
+
1. Integration reviewer reads from each worktree's branch.
|
|
141
|
+
2. The orchestrator merges \`cclaw/<slug>/slice-N\` into the main branch one slice at a time (or fast-forward if the wave was clean).
|
|
142
|
+
3. \`git worktree remove .cclaw/worktrees/<slug>-slice-N\` per slice; the cclaw branches stay until ship.
|
|
143
|
+
|
|
144
|
+
## Fallback: inline-sequential when sub-agent dispatch is unavailable
|
|
145
|
+
|
|
146
|
+
If the harness does not support sub-agent dispatch (or worktree creation fails — non-git repo, permission denied, etc.), \`parallel-build\` **degrades silently to \`inline\`** and runs all slices sequentially in the main working tree. The orchestrator records the fallback in \`builds/<slug>.md\`:
|
|
147
|
+
|
|
148
|
+
\`\`\`markdown
|
|
149
|
+
> Topology was \`parallel-build\` but the harness does not support sub-agent dispatch (or worktree creation failed). Slices ran sequentially in the main working tree.
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
This degradation is not an error and does not reduce review depth.
|
|
153
|
+
|
|
154
|
+
## Hard rules
|
|
155
|
+
|
|
156
|
+
- \`integration\` mode reviewer is mandatory after every parallel wave. No shortcut.
|
|
157
|
+
- Slice-builders never read each other's worktrees mid-flight.
|
|
158
|
+
- A slice-builder that detects a conflict with another slice stops and raises an integration finding instead of hand-merging.
|
|
159
|
+
- More than 5 parallel slices is forbidden. Merge or split.
|
|
476
160
|
`;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
161
|
+
const SECURITY_REVIEW = `---
|
|
162
|
+
name: security-review
|
|
163
|
+
trigger: when the diff touches authn / authz / secrets / supply chain / data exposure
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
# Skill: security-review
|
|
167
|
+
|
|
168
|
+
The orchestrator dispatches \`security-reviewer\` automatically when the active task or diff touches sensitive surfaces. You can also invoke it explicitly with \`/cc <task> --security-review\`.
|
|
169
|
+
|
|
170
|
+
## Rules
|
|
171
|
+
|
|
172
|
+
1. \`security-reviewer\` is a separate specialist from \`reviewer\`. They can run in parallel against the same diff.
|
|
173
|
+
2. \`security-reviewer\` decisions of severity \`security\` are block-level: ship is blocked until they are resolved by slice-builder mode=fix-only and the security review reruns clear.
|
|
174
|
+
3. \`security_flag: true\` in plan frontmatter triggers the compound learning gate even if no other quality signal is present.
|
|
175
|
+
|
|
176
|
+
## Threat-model checklist (mandatory)
|
|
177
|
+
|
|
178
|
+
For every \`threat-model\` invocation, write \`ok\` / \`flag\` / \`n/a\` for each:
|
|
179
|
+
|
|
180
|
+
1. Authentication
|
|
181
|
+
2. Authorization
|
|
182
|
+
3. Secrets (committed credentials, env, signing keys)
|
|
183
|
+
4. Supply chain (new third-party deps, version pinning, provenance)
|
|
184
|
+
5. Data exposure (logging, transmission, storage of user data)
|
|
185
|
+
|
|
186
|
+
## Pure UI / docs diffs
|
|
187
|
+
|
|
188
|
+
State explicitly that all five items are \`n/a\` and write a one-line justification per item. Do not skip the checklist.
|
|
492
189
|
`;
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
- \`
|
|
528
|
-
- \`
|
|
529
|
-
- \`
|
|
530
|
-
-
|
|
531
|
-
|
|
532
|
-
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
190
|
+
const REVIEW_LOOP = `---
|
|
191
|
+
name: review-loop
|
|
192
|
+
trigger: when reviewer or security-reviewer is invoked
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
# Skill: review-loop
|
|
196
|
+
|
|
197
|
+
Review is a producer ↔ critic loop, not a single pass. Iteration N proposes findings; \`slice-builder\` (in \`fix-only\` mode) closes them; iteration N+1 re-checks. The loop ends only when one of three convergence signals fires (see "Convergence detector" below). This is the cclaw analogue of the Karpathy "Ralph loop": short cycles, an explicit ledger, and hard rules for when to stop.
|
|
198
|
+
|
|
199
|
+
Every iteration runs the **Five Failure Modes** checklist:
|
|
200
|
+
|
|
201
|
+
1. Hallucinated actions
|
|
202
|
+
2. Scope creep
|
|
203
|
+
3. Cascading errors
|
|
204
|
+
4. Context loss
|
|
205
|
+
5. Tool misuse
|
|
206
|
+
|
|
207
|
+
For each mode the reviewer answers yes/no with a citation when "yes". A "yes" without a citation is itself a finding (you cited nothing, that is the finding).
|
|
208
|
+
|
|
209
|
+
## Concern Ledger
|
|
210
|
+
|
|
211
|
+
Every \`reviews/<slug>.md\` carries an append-only ledger. Each row is a single finding; rows are never edited or deleted, only appended.
|
|
212
|
+
|
|
213
|
+
\`\`\`markdown
|
|
214
|
+
## Concern Ledger
|
|
215
|
+
|
|
216
|
+
| ID | Opened in | Mode | Severity | Status | Closed in | Citation |
|
|
217
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
218
|
+
| F-1 | 1 | code | block | closed | 2 | \`src/api/list.ts:14\` |
|
|
219
|
+
| F-2 | 2 | code | warn | open | – | \`tests/integration/list.test.ts:31\` |
|
|
220
|
+
\`\`\`
|
|
221
|
+
|
|
222
|
+
Rules:
|
|
223
|
+
|
|
224
|
+
- **F-N** ids are stable and global per slug — never renumber. If a finding is superseded, append \`F-K supersedes F-J\` instead.
|
|
225
|
+
- **Severity** is \`block\` | \`warn\`. \`block\` rows must close before ship; \`warn\` rows may ship with a recorded note in \`ships/<slug>.md\`.
|
|
226
|
+
- **Status** is \`open\` | \`closed\`. A closed row records the iteration that closed it.
|
|
227
|
+
- **Citation** is a real \`file:line\` (or test id, or commit SHA). No prose-only findings — if you cannot cite, you do not have a finding yet.
|
|
228
|
+
|
|
229
|
+
When iteration N+1 runs, the reviewer reads the ledger first, re-validates each open row (still open? closed by a fix? superseded?), then appends new findings as F-(max+1). Closing a row requires a citation to the fix evidence (commit SHA, test name, or new file:line).
|
|
230
|
+
|
|
231
|
+
## Convergence detector
|
|
232
|
+
|
|
233
|
+
The loop ends when ANY of these fires:
|
|
234
|
+
|
|
235
|
+
1. **All ledger rows closed.** Decision: \`clear\`. Ship may proceed.
|
|
236
|
+
2. **Two consecutive iterations append zero new \`block\` findings AND every open row is \`warn\`.** Decision: \`clear\` with warn carry-over recorded in \`ships/<slug>.md\` and \`learnings/<slug>.md\`.
|
|
237
|
+
3. **Hard cap reached** (5 iterations) with at least one open \`block\` row remaining. Decision: \`cap-reached\`. Stop; surface to user.
|
|
238
|
+
|
|
239
|
+
Tie-breaker: if iteration 5 closes the last \`block\` row, return \`clear\` (signal #1) even though the cap was hit. The cap exists to bound runaway loops, not to punish a slug that converges on the last attempt.
|
|
240
|
+
|
|
241
|
+
## Hard cap
|
|
242
|
+
|
|
243
|
+
- 5 review iterations per slug. After the 5th, the reviewer writes \`status: cap-reached\` and stops.
|
|
244
|
+
- The orchestrator surfaces every remaining open ledger row and recommends \`/cc-cancel\` (split into a fresh slug) or \`accept warns and ship\` (only valid if every remaining open row has severity=warn).
|
|
245
|
+
|
|
246
|
+
## Decision values
|
|
247
|
+
|
|
248
|
+
- \`block\` — at least one ledger row is severity=block + status=open. \`slice-builder\` (mode=fix-only) must run next; then re-review.
|
|
249
|
+
- \`warn\` — open rows exist, all severity=warn, convergence detector signal #2 has fired. Ship may proceed; warns carry over.
|
|
250
|
+
- \`clear\` — convergence detector signal #1 fired (all rows closed) OR signal #2 (warn-only convergence). Ready for ship.
|
|
251
|
+
- \`cap-reached\` — signal #3 fired with at least one open block row remaining. Stop; surface to user.
|
|
252
|
+
|
|
253
|
+
## Worked example — three-iteration convergence
|
|
254
|
+
|
|
255
|
+
\`\`\`markdown
|
|
256
|
+
## Iteration 1 — code — 2026-04-18T10:14Z
|
|
257
|
+
|
|
258
|
+
Findings:
|
|
259
|
+
- F-1 block — \`src/api/list.ts:14\` — missing pagination cursor.
|
|
260
|
+
- F-2 warn — \`tests/integration/list.test.ts:31\` — no negative test for empty page.
|
|
261
|
+
|
|
262
|
+
Decision: block. slice-builder (mode=fix-only) invoked next.
|
|
263
|
+
|
|
264
|
+
## Iteration 2 — code — 2026-04-18T10:39Z
|
|
265
|
+
|
|
266
|
+
Ledger reread:
|
|
267
|
+
- F-1: closed — fix at \`src/api/list.ts:18\` (commit 7a91ab2). Citation matches.
|
|
268
|
+
- F-2: open — no fix attempted (warn carry-over).
|
|
269
|
+
|
|
270
|
+
New findings: none.
|
|
271
|
+
|
|
272
|
+
Decision: warn. Convergence signal #2 needs another zero-block iteration.
|
|
273
|
+
|
|
274
|
+
## Iteration 3 — code — 2026-04-18T11:02Z
|
|
275
|
+
|
|
276
|
+
Ledger reread:
|
|
277
|
+
- F-1: closed (sticky).
|
|
278
|
+
- F-2: open (warn carry-over).
|
|
279
|
+
|
|
280
|
+
New findings: none. Two consecutive zero-block iterations recorded.
|
|
281
|
+
|
|
282
|
+
Decision: clear (signal #2). F-2 carries to ships/<slug>.md and learnings/<slug>.md.
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
## Common pitfalls
|
|
286
|
+
|
|
287
|
+
- Adding "implicit" findings without citations because "the reviewer can see it". The reviewer cannot. Cite \`file:line\` or do not record the finding.
|
|
288
|
+
- Renumbering F-N ids when an old finding is superseded. Append a new row \`F-K supersedes F-J\`; never rewrite history.
|
|
289
|
+
- Closing a row without a fix citation. Closing is itself a claim — record the SHA / test name / file:line that proves the fix.
|
|
290
|
+
- Treating "no new findings" as instant clear. The convergence detector requires *two* consecutive zero-block iterations; one is not enough.
|
|
291
|
+
- Skipping the convergence check and looping until cap. The detector exists so easy slugs ship fast; do not waste budget.
|
|
292
|
+
- Mixing \`code\` and \`text-review\` modes within one iteration. Each iteration declares one mode in its header.
|
|
540
293
|
`;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const normalizedDispatch = dispatchBlock.length > 0
|
|
546
|
-
? dispatchBlock.replace(/^## Automatic Subagent Dispatch/mu, "### Automatic Subagent Dispatch")
|
|
547
|
-
: "### Automatic Subagent Dispatch\nNo automatic subagent dispatch rules for this stage.";
|
|
548
|
-
return `## Delegation & Completion
|
|
294
|
+
const COMMIT_MESSAGE_QUALITY = `---
|
|
295
|
+
name: commit-message-quality
|
|
296
|
+
trigger: before every commit-helper.mjs invocation
|
|
297
|
+
---
|
|
549
298
|
|
|
550
|
-
|
|
299
|
+
# Skill: commit-message-quality
|
|
551
300
|
|
|
552
|
-
|
|
301
|
+
\`commit-helper.mjs\` accepts any non-empty message, but the AC traceability chain only stays useful if the messages stay readable.
|
|
553
302
|
|
|
554
|
-
|
|
303
|
+
## Rules
|
|
555
304
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
305
|
+
1. **Imperative voice** — "Add StatusPill component", not "Added" or "Adding".
|
|
306
|
+
2. **Subject ≤72 characters** — long subjects truncate in \`git log --oneline\` and CI signals.
|
|
307
|
+
3. **Subject does not repeat the AC id** — the hook already appends \`refs: AC-N\`.
|
|
308
|
+
4. **Body when needed** — second-line blank, then a short rationale paragraph and any non-obvious context. Use \`--message\` for the subject; if the message must be multi-line, write it to a file and pass \`--file\`.
|
|
309
|
+
5. **Cite finding ids in fix commits** — \`fix: F-2 separate rejected token\`.
|
|
310
|
+
|
|
311
|
+
## Anti-patterns
|
|
312
|
+
|
|
313
|
+
- "WIP", "fixes", "stuff", "more". The reviewer rejects these as F-1 \`block\`.
|
|
314
|
+
- Subject lines that paraphrase the diff. Diff is the diff; the message is the why.
|
|
315
|
+
- Co-author trailers in solo commits.
|
|
316
|
+
|
|
317
|
+
## When to amend
|
|
318
|
+
|
|
319
|
+
Never amend a commit produced by \`commit-helper.mjs\` after the SHA is recorded in \`flow-state.json\`. Amend changes the SHA and breaks the AC chain. If the message is wrong, write a short note in \`builds/<slug>.md\` and move on; it is recoverable in review.
|
|
561
320
|
`;
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
321
|
+
const AC_QUALITY = `---
|
|
322
|
+
name: ac-quality
|
|
323
|
+
trigger: when authoring or reviewing AC entries
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
# Skill: ac-quality
|
|
327
|
+
|
|
328
|
+
Three checks per AC:
|
|
329
|
+
|
|
330
|
+
1. **Observable** — a user, test, or operator can tell whether it is satisfied without reading the diff.
|
|
331
|
+
2. **Independently committable** — a single commit covering only this AC is meaningful.
|
|
332
|
+
3. **Verifiable** — there is an explicit verification line (test name, manual step, or command).
|
|
333
|
+
|
|
334
|
+
## Smell check
|
|
335
|
+
|
|
336
|
+
| smell | example | rewrite |
|
|
337
|
+
| --- | --- | --- |
|
|
338
|
+
| sub-task | "implement the helper" | "search returns BM25-ranked results for queries with multiple terms" |
|
|
339
|
+
| vague verification | "tests pass" | "verified by tests/unit/search.test.ts: 'returns BM25-ranked hits'" |
|
|
340
|
+
| internal detail | "refactor the cache" | "cache hit rate >90% on the dashboard repaint scenario" |
|
|
341
|
+
| compound AC | "build the page and add analytics" | split into two AC |
|
|
342
|
+
|
|
343
|
+
## Numbering
|
|
344
|
+
|
|
345
|
+
- AC ids start at \`AC-1\` and are sequential.
|
|
346
|
+
- Refinement slugs restart at \`AC-1\` even when they refine a slug that had AC-1..AC-12.
|
|
347
|
+
- Do not reuse an AC id within the same slug; if you delete an AC, the remaining ids stay sequential after compaction.
|
|
348
|
+
|
|
349
|
+
## When to add an AC mid-flight
|
|
350
|
+
|
|
351
|
+
You don't. Adding AC during build is scope creep. Either the new work fits an existing AC (no new id), or it should be a follow-up (\`/cc-idea\`) or a fresh slug.
|
|
572
352
|
`;
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
?.trim() ?? "";
|
|
594
|
-
const words = stripped.split(/\s+/u).filter((word) => word.length > 0);
|
|
595
|
-
const short = words.slice(0, 4).join(" ");
|
|
596
|
-
const label = short.length === 0
|
|
597
|
-
? `Step ${index + 1}`
|
|
598
|
-
: short.replace(/["`]/gu, "");
|
|
599
|
-
return label.length > 48 ? `${label.slice(0, 45)}...` : label;
|
|
600
|
-
}
|
|
601
|
-
const MERMAID_PROCESS_MAX_NODES = 10;
|
|
602
|
-
function renderProcessFlowMermaid(executionModel) {
|
|
603
|
-
if (executionModel.processFlow && executionModel.processFlow.trim().length > 0) {
|
|
604
|
-
return `\`\`\`mermaid\n${executionModel.processFlow.trim()}\n\`\`\``;
|
|
605
|
-
}
|
|
606
|
-
const source = executionModel.process.length > 0
|
|
607
|
-
? executionModel.process
|
|
608
|
-
: executionModel.checklist;
|
|
609
|
-
if (source.length === 0) {
|
|
610
|
-
return "";
|
|
611
|
-
}
|
|
612
|
-
const limited = source.slice(0, MERMAID_PROCESS_MAX_NODES);
|
|
613
|
-
const nodes = limited.map((item, index) => ({
|
|
614
|
-
id: `S${index + 1}`,
|
|
615
|
-
label: mermaidNodeLabel(item, index)
|
|
616
|
-
}));
|
|
617
|
-
const lines = ["flowchart TD"];
|
|
618
|
-
for (const node of nodes) {
|
|
619
|
-
lines.push(` ${node.id}["${node.label}"]`);
|
|
620
|
-
}
|
|
621
|
-
for (let i = 0; i < nodes.length - 1; i += 1) {
|
|
622
|
-
lines.push(` ${nodes[i].id} --> ${nodes[i + 1].id}`);
|
|
623
|
-
}
|
|
624
|
-
if (source.length > MERMAID_PROCESS_MAX_NODES) {
|
|
625
|
-
lines.push(` S${nodes.length} --> More["...see full Checklist"]`);
|
|
626
|
-
}
|
|
627
|
-
return `\`\`\`mermaid\n${lines.join("\n")}\n\`\`\``;
|
|
628
|
-
}
|
|
629
|
-
function renderPlatformNotesBlock(notes) {
|
|
630
|
-
if (!notes || notes.length === 0) {
|
|
631
|
-
return "";
|
|
632
|
-
}
|
|
633
|
-
const body = notes.map((item) => `- ${item}`).join("\n");
|
|
634
|
-
return `## Platform Notes
|
|
635
|
-
${body}
|
|
353
|
+
const REFACTOR_SAFETY = `---
|
|
354
|
+
name: refactor-safety
|
|
355
|
+
trigger: when the slug is identified as a pure refactor
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
# Skill: refactor-safety
|
|
359
|
+
|
|
360
|
+
Refactors must be **behaviour-preserving**. The harness enforces this with three structural rules.
|
|
361
|
+
|
|
362
|
+
## Pin behaviour first
|
|
363
|
+
|
|
364
|
+
Before any rewrite, identify the pin:
|
|
365
|
+
|
|
366
|
+
- existing tests that should pass with the same expected output;
|
|
367
|
+
- a snapshot or fixture set that should not change;
|
|
368
|
+
- a manual repro the user accepts as the contract.
|
|
369
|
+
|
|
370
|
+
If no pin exists, "add a pin" is AC-1 of the refactor.
|
|
371
|
+
|
|
372
|
+
## One refactor at a time
|
|
636
373
|
|
|
374
|
+
A refactor slug must contain refactor changes only. A bug fix that would have been "while we're here" is a separate slug. The pin from the refactor slug is then valid input for the fix slug.
|
|
375
|
+
|
|
376
|
+
## Public API discipline
|
|
377
|
+
|
|
378
|
+
If the refactor renames or restructures public exports:
|
|
379
|
+
|
|
380
|
+
- add a deprecation alias so external consumers still compile;
|
|
381
|
+
- mark the old name with a \`@deprecated\` JSDoc / equivalent;
|
|
382
|
+
- record the deprecation deadline in \`ships/<slug>.md\`.
|
|
383
|
+
|
|
384
|
+
If the project policy forbids deprecation aliases (some libraries), the refactor is breaking; \`security_flag\` does not apply but breaking-change handling does (see breaking-changes skill).
|
|
385
|
+
|
|
386
|
+
## Verification
|
|
387
|
+
|
|
388
|
+
Refactor AC verification is "no behavioural diff": tests pass, snapshots unchanged, fixtures unchanged. If anything changes, the refactor leaked behaviour and must be split.
|
|
637
389
|
`;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
.map((item) => normalizedGuidanceKey(item))
|
|
642
|
-
.filter((item) => item.length > 0));
|
|
643
|
-
const seen = new Set();
|
|
644
|
-
const result = [];
|
|
645
|
-
for (const item of items) {
|
|
646
|
-
const key = normalizedGuidanceKey(item);
|
|
647
|
-
if (key.length === 0)
|
|
648
|
-
continue;
|
|
649
|
-
if (blocked.has(key))
|
|
650
|
-
continue;
|
|
651
|
-
if (seen.has(key))
|
|
652
|
-
continue;
|
|
653
|
-
seen.add(key);
|
|
654
|
-
result.push(item);
|
|
655
|
-
}
|
|
656
|
-
return result;
|
|
657
|
-
}
|
|
658
|
-
export function stageSkillMarkdown(stage, track = "standard", _packageVersion) {
|
|
659
|
-
const schema = stageSchema(stage, track);
|
|
660
|
-
const trackContext = stageTrackRenderContext(track);
|
|
661
|
-
const philosophy = schema.philosophy;
|
|
662
|
-
const executionModel = schema.executionModel;
|
|
663
|
-
const artifactRules = schema.artifactRules;
|
|
664
|
-
const reviewLens = schema.reviewLens;
|
|
665
|
-
const mandatoryDelegations = reviewLens.mandatoryDelegations;
|
|
666
|
-
const gateList = executionModel.requiredGates
|
|
667
|
-
.map((g) => `- \`${g.id}\` — ${g.description}`)
|
|
668
|
-
.join("\n");
|
|
669
|
-
const evidenceList = executionModel.requiredEvidence
|
|
670
|
-
.map((e) => `- [ ] ${e}`)
|
|
671
|
-
.join("\n");
|
|
672
|
-
const checklistItems = executionModel.checklist
|
|
673
|
-
.map((item, i) => `${i + 1}. ${item}`)
|
|
674
|
-
.join("\n");
|
|
675
|
-
const interactionFocus = dedupeGuidance(executionModel.interactionProtocol, [...executionModel.checklist, ...executionModel.process]).slice(0, 5);
|
|
676
|
-
const processFlowMermaid = renderProcessFlowMermaid(executionModel);
|
|
677
|
-
const platformNotesBlock = renderPlatformNotesBlock(executionModel.platformNotes);
|
|
678
|
-
const reviewLoopSection = reviewLoopBlock(reviewLens.reviewLoop);
|
|
679
|
-
const mandatoryDelegationSummary = mandatoryDelegations.length > 0
|
|
680
|
-
? mandatoryDelegations.map((name) => `\`${name}\``).join(", ")
|
|
681
|
-
: "none";
|
|
682
|
-
return `---
|
|
683
|
-
name: ${schema.skillName}
|
|
684
|
-
description: "${schema.skillDescription}"
|
|
390
|
+
const TDD_CYCLE = `---
|
|
391
|
+
name: tdd-cycle
|
|
392
|
+
trigger: always-on whenever stage=build (mandatory; build IS the TDD stage)
|
|
685
393
|
---
|
|
686
394
|
|
|
687
|
-
#
|
|
395
|
+
# Skill: tdd-cycle (RED → GREEN → REFACTOR)
|
|
396
|
+
|
|
397
|
+
build is a TDD stage. Every AC goes through the cycle. There is no other build mode.
|
|
688
398
|
|
|
689
|
-
|
|
399
|
+
> **Iron Law:** NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST. The RED failure is the spec.
|
|
690
400
|
|
|
691
|
-
|
|
401
|
+
## The three phases
|
|
692
402
|
|
|
693
|
-
|
|
403
|
+
### RED — write a failing test
|
|
694
404
|
|
|
695
|
-
|
|
405
|
+
- Touch test files **only**. No production edits in the RED commit.
|
|
406
|
+
- The test must encode the AC verification line authored by planner.
|
|
407
|
+
- The test must fail for the **right reason** — the assertion that encodes the AC, not a syntax / import / fixture error.
|
|
408
|
+
- Capture the runner output that proves the failure (command + 1-3 line excerpt). This is the **watched-RED proof**.
|
|
409
|
+
- **Test files are named by the unit under test, NOT by the AC id.** Mirror the production module path: \`src/lib/permissions.ts\` → \`tests/unit/permissions.test.ts\` (or whatever the project's convention is — \`*.spec.ts\`, \`__tests__/*.ts\`, \`*_test.go\`, \`test_*.py\`). \`AC-1.test.ts\`, \`tests/AC-2.test.ts\`, \`spec/ac3.spec.ts\` are anti-patterns. The AC id lives **inside** the test name (\`it('AC-1: tooltip shows email …', …)\`), in the commit message (\`red(AC-1): …\`), and in the build log — never in the filename.
|
|
410
|
+
- Commit: \`commit-helper.mjs --ac=AC-N --phase=red --message="red(AC-N): …"\`.
|
|
696
411
|
|
|
697
|
-
|
|
412
|
+
### GREEN — minimal production change
|
|
698
413
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
414
|
+
- Smallest possible production diff that turns RED into PASS.
|
|
415
|
+
- Run the **full relevant suite**, not the single test. A passing single test with the suite broken elsewhere is a regression, not GREEN.
|
|
416
|
+
- Capture the suite command + PASS/FAIL summary. This is the **GREEN evidence**.
|
|
417
|
+
- Touch only files declared in the plan. If a file outside the plan is required, **stop** and surface the conflict.
|
|
418
|
+
- Commit: \`commit-helper.mjs --ac=AC-N --phase=green --message="green(AC-N): …"\`.
|
|
702
419
|
|
|
703
|
-
|
|
704
|
-
- Active tier: \`${schema.complexityTier}\`; mandatory delegations: ${mandatoryDelegationSummary}
|
|
705
|
-
- Scale-to-complexity: execute required gates/sections; keep optional/deep sections compact unless risk, novelty, or config triggers them.
|
|
706
|
-
- Track render context: \`${trackContext.track}\` (${trackContext.usesPlanTerminology ? "plan-first wording" : "acceptance-first wording"})
|
|
420
|
+
### REFACTOR — mandatory pass
|
|
707
421
|
|
|
708
|
-
|
|
709
|
-
${philosophy.whenToUse.map((item) => `- ${item}`).join("\n")}
|
|
422
|
+
REFACTOR is **not optional**. Even when the GREEN diff feels minimal, you must consider rename / extract / inline / type-narrow / dedup / dead-code-removal. Run the same suite again; it must pass with **identical** expected output.
|
|
710
423
|
|
|
711
|
-
|
|
712
|
-
## HARD-GATE
|
|
713
|
-
${philosophy.hardGate}
|
|
424
|
+
If a refactor is warranted, apply it and commit:
|
|
714
425
|
|
|
715
|
-
|
|
716
|
-
${mergedAntiPatterns(philosophy, executionModel)}
|
|
426
|
+
\`commit-helper.mjs --ac=AC-N --phase=refactor --message="refactor(AC-N): …"\`.
|
|
717
427
|
|
|
718
|
-
|
|
428
|
+
If no refactor is warranted, say so **explicitly**:
|
|
719
429
|
|
|
720
|
-
|
|
721
|
-
${processFlowMermaid.length > 0 ? processFlowMermaid : "```mermaid\nflowchart TD\n S1[\"Execute Checklist\"] --> S2[\"Satisfy required gates\"] --> S3[\"Verify before closeout\"]\n```"}
|
|
430
|
+
\`commit-helper.mjs --ac=AC-N --phase=refactor --skipped --message="refactor(AC-N) skipped: <reason>"\`.
|
|
722
431
|
|
|
723
|
-
|
|
724
|
-
${delegationAndCompletionBlock(schema, track)}
|
|
725
|
-
${stackAwareReviewRoutingBlock(stage)}
|
|
726
|
-
${researchPlaybooksBlock(executionModel.researchPlaybooks ?? [])}
|
|
727
|
-
${referencePatternsBlock(stage)}
|
|
432
|
+
Silence fails the gate.
|
|
728
433
|
|
|
729
|
-
##
|
|
434
|
+
## Mandatory gates per AC
|
|
730
435
|
|
|
731
|
-
|
|
436
|
+
\`commit-helper\` enforces (a) ↔ (e) mechanically. The reviewer checks (b), (d), (f), (g) on iteration 1.
|
|
732
437
|
|
|
733
|
-
|
|
438
|
+
(a) **discovery_complete** — relevant tests / fixtures / helpers / commands cited.\n(b) **impact_check_complete** — affected callbacks / state / interfaces / contracts named.\n(c) **red_test_recorded** — failing test exists, watched-RED proof attached.\n(d) **red_fails_for_right_reason** — RED captured a real assertion failure.\n(e) **green_full_suite** — full relevant suite green after GREEN.\n(f) **refactor_run_or_skipped_with_reason** — REFACTOR ran, or explicitly skipped with reason.\n(g) **traceable_to_plan** — commits reference plan AC ids and the plan's file set.\n(h) **commit_chain_intact** — RED + GREEN + REFACTOR SHAs (or skipped sentinel) recorded in flow-state.
|
|
734
439
|
|
|
735
|
-
|
|
440
|
+
## Anti-patterns
|
|
736
441
|
|
|
737
|
-
|
|
442
|
+
- "The implementation is obvious, skipping RED." A-13 — gate fails immediately.
|
|
443
|
+
- "Single test green, didn't run the suite." A-14 — that's not GREEN; it's a regression.
|
|
444
|
+
- "Nothing to refactor, skipping silently." A-15 — emit the explicit \`--skipped\` commit with reason.
|
|
445
|
+
- "Stage everything with \`git add -A\`." A-16 — staged unrelated edits leak into the AC commit.
|
|
446
|
+
- "Production code in the RED commit." A-17 — RED is test files only.
|
|
447
|
+
- **"Test file named after the AC id" — \`AC-1.test.ts\`, \`tests/AC-2.spec.ts\`, etc.** The reviewer flags this as \`block\`. Mirror the unit under test in the filename; carry the AC id inside the test name and commit message only.
|
|
738
448
|
|
|
739
|
-
|
|
449
|
+
## Fix-only flow
|
|
740
450
|
|
|
741
|
-
|
|
451
|
+
When reviewer returns \`block\`, the same TDD cycle applies to the fix:
|
|
742
452
|
|
|
743
|
-
|
|
453
|
+
- F-N changes observable behaviour → new RED test that encodes the corrected behaviour, then GREEN, then REFACTOR.
|
|
454
|
+
- F-N is purely a refactor → commit under \`--phase=refactor\`.
|
|
455
|
+
- F-N is a docs / log / config nit → commit under \`--phase=refactor\` or \`--phase=refactor --skipped\`.
|
|
744
456
|
|
|
745
|
-
|
|
746
|
-
${crossCuttingMechanicsBlock(stage)}
|
|
747
|
-
## Required Gates
|
|
748
|
-
${gateList}
|
|
457
|
+
The AC id stays the same; commit messages cite \`F-N\`.
|
|
749
458
|
|
|
750
|
-
##
|
|
751
|
-
|
|
459
|
+
## When TDD does not apply
|
|
460
|
+
|
|
461
|
+
The single exception is **bootstrap of the test framework itself** — a slug whose AC-1 is "test framework installed and one passing example test exists". In that case the orchestrator must mark the slug as \`build_profile: bootstrap\` in plan frontmatter, and \`commit-helper\` accepts the GREEN commit without a prior RED for AC-1 only. Every subsequent AC and every other slug uses the full cycle.
|
|
462
|
+
`;
|
|
463
|
+
const BREAKING_CHANGES = `---
|
|
464
|
+
name: breaking-changes
|
|
465
|
+
trigger: when the diff modifies public API surface or persisted contracts
|
|
466
|
+
---
|
|
752
467
|
|
|
753
|
-
|
|
468
|
+
# Skill: breaking-changes
|
|
754
469
|
|
|
755
|
-
|
|
756
|
-
${executionModel.exitCriteria.map((item) => `- [ ] ${item}`).join("\n")}
|
|
470
|
+
A change is breaking when:
|
|
757
471
|
|
|
758
|
-
|
|
759
|
-
-
|
|
472
|
+
- a public export is renamed, removed, or changes signature;
|
|
473
|
+
- a CLI flag is renamed or removed;
|
|
474
|
+
- a wire format (HTTP, RPC, queue payload) changes shape or required fields;
|
|
475
|
+
- a persisted contract (DB schema, file format, env var) changes in a way that requires migration.
|
|
760
476
|
|
|
761
|
-
|
|
762
|
-
${artifactValidationBlock(artifactRules.artifactValidation)}
|
|
477
|
+
## Rules
|
|
763
478
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
479
|
+
1. **Plan must declare it.** Set \`breaking_change: true\` (or note it explicitly in the plan body).
|
|
480
|
+
2. **Migration must exist.** \`ships/<slug>.md\` carries a migration section: who is affected, what they need to do, when the old path stops working.
|
|
481
|
+
3. **Deprecation window.** Public libraries — at least one minor version. Internal services — at least one deploy cycle and one alert.
|
|
482
|
+
4. **Release notes.** The CHANGELOG line must start with \`BREAKING:\` and link to the migration section.
|
|
767
483
|
|
|
768
|
-
|
|
484
|
+
## Coexistence
|
|
769
485
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
-
|
|
773
|
-
-
|
|
774
|
-
-
|
|
486
|
+
When possible, ship the new path alongside the old. Examples:
|
|
487
|
+
|
|
488
|
+
- new endpoint path next to the old one;
|
|
489
|
+
- new column added before the old one is dropped;
|
|
490
|
+
- new env var name accepted along with the old (with a deprecation log line);
|
|
491
|
+
- new function exported with the new name; old name aliased to it.
|
|
492
|
+
|
|
493
|
+
Coexistence is not always possible (e.g. wire-format changes for older clients you cannot upgrade). When it is not possible, surface this back to architect; the decision must be recorded in \`decisions/<slug>.md\`.
|
|
494
|
+
|
|
495
|
+
## Common pitfalls
|
|
496
|
+
|
|
497
|
+
- "Internal API, not breaking." If the change crosses a service boundary, treat it as breaking.
|
|
498
|
+
- Renaming a CLI flag without an alias. Aliases for CLI flags are nearly always free; add them.
|
|
499
|
+
- Skipping the CHANGELOG line because "everyone knows". They do not.
|
|
500
|
+
- Forgetting the alert window for internal services. The deploy cycle is not enough; users need a heads-up.
|
|
775
501
|
`;
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
name: executing-waves
|
|
780
|
-
description: "Execute multi-wave work using existing cclaw run resume + verify-current-state — no new CLI needed."
|
|
502
|
+
const CONVERSATION_LANGUAGE = `---
|
|
503
|
+
name: conversation-language
|
|
504
|
+
trigger: always-on
|
|
781
505
|
---
|
|
782
506
|
|
|
783
|
-
#
|
|
507
|
+
# Skill: conversation-language
|
|
508
|
+
|
|
509
|
+
cclaw is a harness tool. The harness has one user; the user has one language. Your conversational output must be in that language. Detect it from the user's most recent message and stay in it for the remainder of the turn.
|
|
510
|
+
|
|
511
|
+
## What MUST stay in the user's language
|
|
784
512
|
|
|
785
|
-
|
|
513
|
+
Everything that the user reads as prose:
|
|
786
514
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
515
|
+
- Status updates ("starting plan", "RED for AC-2 looks good").
|
|
516
|
+
- Questions you ask the user.
|
|
517
|
+
- Clarifications, recommendations, summaries, recaps.
|
|
518
|
+
- Error explanations and recovery suggestions.
|
|
519
|
+
- Diff explanations during review iterations.
|
|
790
520
|
|
|
791
|
-
|
|
521
|
+
If the user wrote to you in Russian, your status updates are in Russian. If the user wrote in Ukrainian, your status updates are in Ukrainian. If the user mixed languages, follow their dominant language; if there is no dominant language, mirror the language of their final paragraph.
|
|
792
522
|
|
|
793
|
-
|
|
794
|
-
- Each wave has its own stage cycle (brainstorm -> scope -> design -> spec -> plan -> tdd -> review -> ship).
|
|
795
|
-
- User wants explicit per-wave verification before the next wave starts.
|
|
796
|
-
- Risk of cross-wave drift exists.
|
|
523
|
+
Do NOT translate during the same conversation. The user has already chosen their language; restating the same point in English is noise.
|
|
797
524
|
|
|
798
|
-
##
|
|
525
|
+
## What MUST NOT be translated
|
|
799
526
|
|
|
800
|
-
|
|
801
|
-
- Treating a wave as only a commit boundary without re-verifying upstream decisions.
|
|
527
|
+
Mechanical tokens stay in their original form regardless of conversation language:
|
|
802
528
|
|
|
803
|
-
|
|
529
|
+
- File paths (\`.cclaw/flows/<slug>/plan.md\`).
|
|
530
|
+
- AC ids (\`AC-1\`, \`AC-2\`).
|
|
531
|
+
- Decision ids (\`D-1\`, \`D-2\`).
|
|
532
|
+
- Slugs (\`add-approval-page\`, never "добавить-страницу-одобрения").
|
|
533
|
+
- Commands and CLI flags (\`/cc\`, \`--phase=red\`, \`commit-helper.mjs\`).
|
|
534
|
+
- Hook output and machine-readable JSON.
|
|
535
|
+
- Specialist names (\`brainstormer\`, \`architect\`, \`planner\`, \`reviewer\`, \`security-reviewer\`, \`slice-builder\`).
|
|
536
|
+
- Mode names (\`code\`, \`text-review\`, \`integration\`, \`release\`, \`adversarial\`, \`fix-only\`).
|
|
537
|
+
- Frontmatter keys (\`slug\`, \`stage\`, \`status\`, \`ac\`, \`phases\`).
|
|
538
|
+
- Stage names (\`plan\`, \`build\`, \`review\`, \`ship\`).
|
|
539
|
+
- TDD phase names (\`red\`, \`green\`, \`refactor\`).
|
|
804
540
|
|
|
805
|
-
|
|
806
|
-
2. **Carry-forward Audit**: at brainstorm of the next wave, re-read previous wave ship artifact and explicitly record in the existing \`## Wave Carry-forward\` section:
|
|
807
|
-
- Carrying forward: <scope D-XX decision references still valid>
|
|
808
|
-
- Drift detected: <decisions no longer valid + reason>
|
|
809
|
-
- Re-scope needed: <yes/no>
|
|
810
|
-
- Never create a second \`## Locked Decisions\` heading in brainstorm; reference prior D-XX IDs inline.
|
|
811
|
-
3. **Resume Path**: if a wave was interrupted mid-stage, \`cclaw run resume\` restores state. Run \`internal verify-current-state\` before continuing.
|
|
812
|
-
4. **Wave End**: at ship, architect cross-stage verification runs from dispatch matrix. If \`DRIFT_DETECTED\`, fix before ship.
|
|
813
|
-
5. **Next Wave Trigger**: launch new \`/cc <topic>\` for next wave and reference previous wave ship artifact in upstream handoff.
|
|
541
|
+
These tokens are the wire protocol of cclaw. Translating them breaks tool calls, AC matching, frontmatter parsing, and the commit-helper hook. They are identifiers, not vocabulary.
|
|
814
542
|
|
|
815
|
-
##
|
|
543
|
+
## What MAY be in either language
|
|
816
544
|
|
|
817
|
-
|
|
818
|
-
- \`wave-status: blocked-by-prev\` — waiting on previous wave verification.
|
|
819
|
-
- \`wave-status: shipped\` — wave shipped, next wave can start.
|
|
820
|
-
- \`wave-status: rolled-back\` — previous wave invalidated, current wave needs rebase.
|
|
545
|
+
Artifact bodies (the prose inside \`plans/<slug>.md\`, \`builds/<slug>.md\`, \`reviews/<slug>.md\`, \`ships/<slug>.md\`, \`decisions/<slug>.md\`, \`learnings/<slug>.md\`).
|
|
821
546
|
|
|
822
|
-
|
|
547
|
+
Default rule: write the artifact body in the same language as the user's conversation, because the artifact is for them and for the next agent who reads their notes. The frontmatter stays English (it is the wire protocol).
|
|
823
548
|
|
|
824
|
-
|
|
825
|
-
|
|
549
|
+
If the user explicitly asks for English-only artifacts ("write the plan in English so the rest of the team can read it"), honour the request. Otherwise stay in their language.
|
|
550
|
+
|
|
551
|
+
Commit messages: the AC line stays English (\`AC-N: …\`); the rest of the message body may follow the artifact-body language.
|
|
552
|
+
|
|
553
|
+
## Worked example — Russian conversation
|
|
554
|
+
|
|
555
|
+
User: "сделай мне CLI клиент для нашего REST API"
|
|
556
|
+
|
|
557
|
+
You (status): "Стартую план \`api-cli\`. Подтягиваю pattern \`api-endpoint.md\`. Пять AC: list, get, create, update, delete. Подтверждаешь?"
|
|
558
|
+
|
|
559
|
+
You (artifact \`flows/api-cli/plan.md\`):
|
|
560
|
+
|
|
561
|
+
\`\`\`markdown
|
|
562
|
+
---
|
|
563
|
+
slug: api-cli
|
|
564
|
+
stage: plan
|
|
565
|
+
status: active
|
|
566
|
+
ac:
|
|
567
|
+
- id: AC-1
|
|
568
|
+
text: list команда вызывает GET /resources и печатает таблицу.
|
|
569
|
+
status: pending
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
# api-cli
|
|
573
|
+
|
|
574
|
+
…
|
|
575
|
+
\`\`\`
|
|
576
|
+
|
|
577
|
+
Note: slug stays \`api-cli\` (English, kebab-case); AC ids stay \`AC-1\` (English); frontmatter keys stay English; the AC body is in Russian.
|
|
578
|
+
|
|
579
|
+
You (commit message): \`AC-1: добавлен list-команд via fetch\`. The \`AC-1:\` prefix is English (commit-helper requires it); the message body is Russian.
|
|
580
|
+
|
|
581
|
+
## Common pitfalls
|
|
582
|
+
|
|
583
|
+
- Translating slugs ("добавить-cli" instead of "add-cli"). Slugs are filenames; keep them ASCII kebab-case.
|
|
584
|
+
- Translating frontmatter keys (\`статус: активен\`). Frontmatter is parsed by code; keys must be English.
|
|
585
|
+
- Restating the same status update twice ("Старт. — Starting."). Pick one. Match the user.
|
|
586
|
+
- Switching to English when the answer is "complicated". The user's complexity tolerance is not your language tolerance.
|
|
587
|
+
- Translating commit-helper output (\`[ошибка]\`). Hook output is read by the harness; leave it in English. Your own commentary on top of the hook output may be in the user's language.
|
|
588
|
+
|
|
589
|
+
## How to detect language
|
|
590
|
+
|
|
591
|
+
1. Read the user's last message. If it has at least one full sentence in language X, X is the language.
|
|
592
|
+
2. If the user mixed languages within one message, count tokens; pick the language with the most non-stopword tokens.
|
|
593
|
+
3. If still tied, default to the language of their previous-but-one message.
|
|
594
|
+
4. If there is no usable history (first turn, terse prompt), default to English. Do not guess from one ambiguous word.
|
|
826
595
|
`;
|
|
596
|
+
const ANTI_SLOP = `---
|
|
597
|
+
name: anti-slop
|
|
598
|
+
trigger: always-on for any code-modifying step (slice-builder, fix-only, recovery)
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
# Skill: anti-slop
|
|
602
|
+
|
|
603
|
+
cclaw takes its lean ethos seriously: **no busywork, no fake fixes, no fake progress.** This skill applies whenever you are writing code, modifying tests, debugging a build/lint/test failure, or running verification commands.
|
|
604
|
+
|
|
605
|
+
## Two iron rules
|
|
606
|
+
|
|
607
|
+
### 1. No redundant verification
|
|
608
|
+
|
|
609
|
+
Do not re-run the same build, test, or lint command twice in a row without a code or input change in between. The result will not change. If a check failed, change something — or stop and report the failure as a finding.
|
|
610
|
+
|
|
611
|
+
**What counts as a "change":**
|
|
612
|
+
|
|
613
|
+
- modified production source
|
|
614
|
+
- modified test file
|
|
615
|
+
- modified config / fixture / lockfile
|
|
616
|
+
- different argument set passed to the same tool (\`npm test\` → \`npm test -- --reporter=verbose --testNamePattern="AC-1"\` is OK; the same \`npm test\` twice is not)
|
|
617
|
+
|
|
618
|
+
**Red flags (do NOT do these):**
|
|
619
|
+
|
|
620
|
+
- "let me try the test again" without any edit
|
|
621
|
+
- "let me re-build" without any edit
|
|
622
|
+
- "let me re-lint" without any edit
|
|
623
|
+
- "let me check if the issue is still there" without any edit
|
|
624
|
+
|
|
625
|
+
If a tool succeeded once, do not run it a second time to "make sure". If it failed once, the second identical run will fail too.
|
|
626
|
+
|
|
627
|
+
### 2. No environment shims, no fake fixes
|
|
628
|
+
|
|
629
|
+
When a build / test / lint fails, **fix the root cause** or **surface the failure as a finding**. The following are anti-patterns; reviewer flags them as \`block\`:
|
|
630
|
+
|
|
631
|
+
- wrapping a real failure in \`try / catch\` and ignoring the error
|
|
632
|
+
- skipping a test (\`.skip\`, \`xit\`, \`@pytest.mark.skip\`, \`#[ignore]\`) "until later" without a follow-up issue or AC
|
|
633
|
+
- adding \`process.env.NODE_ENV === "test"\` (or equivalent) branches just to make tests pass
|
|
634
|
+
- adding \`// @ts-ignore\`, \`// eslint-disable\`, \`# noqa\`, \`# type: ignore\` to silence the failure rather than fix it
|
|
635
|
+
- short-circuiting a function with a hardcoded fixture value when "in test"
|
|
636
|
+
- mocking a function inline inside production code "just to get past this"
|
|
637
|
+
- writing a fallback that hides a real error path (\`return data ?? STUB_DATA\` where STUB_DATA exists only to dodge an upstream failure)
|
|
638
|
+
- copy-pasting a stack-trace into a try/catch as the "fix"
|
|
639
|
+
|
|
640
|
+
If the real fix is out of scope for the current AC, **stop**. Surface the failure and let the orchestrator hand the slug back to planner. Do not "make it work" with a shim and commit. Reviewer will catch the shim, the slug will fail review, and you will redo the work properly. Save the round-trip.
|
|
641
|
+
|
|
642
|
+
## When you are tempted to add a fallback
|
|
643
|
+
|
|
644
|
+
Ask yourself: *"what real failure is this fallback hiding?"* If the answer is "I don't know" or "the test was flaky", the fallback is slop. Find the real failure first.
|
|
645
|
+
|
|
646
|
+
## Worked example — slop vs root-cause
|
|
647
|
+
|
|
648
|
+
❌ slop:
|
|
649
|
+
|
|
650
|
+
\`\`\`ts
|
|
651
|
+
function getUser(id: string) {
|
|
652
|
+
try {
|
|
653
|
+
return db.users.find(id);
|
|
654
|
+
} catch (e) {
|
|
655
|
+
if (process.env.NODE_ENV === "test") return { id, name: "test-user" }; // makes the test pass
|
|
656
|
+
throw e;
|
|
657
|
+
}
|
|
827
658
|
}
|
|
659
|
+
\`\`\`
|
|
660
|
+
|
|
661
|
+
✅ root-cause:
|
|
662
|
+
|
|
663
|
+
\`\`\`ts
|
|
664
|
+
// (test fixture seeds a user before calling getUser; production code untouched)
|
|
665
|
+
beforeEach(async () => { await db.users.insert({ id: "u-1", name: "Anna" }); });
|
|
666
|
+
\`\`\`
|
|
667
|
+
|
|
668
|
+
## What to surface as a finding (and stop)
|
|
669
|
+
|
|
670
|
+
- **Root cause is in someone else's slug.** Surface as \`block\`: "AC-N depends on \`<file>\` which is owned by \`<other slug>\`. Cannot complete without the other slug shipping first."
|
|
671
|
+
- **Test framework is broken.** Surface as \`block\`: "test runner exits with \`<exact-error>\` independent of the test under change."
|
|
672
|
+
- **Plan is wrong.** Surface as \`info\`: "AC-N as written cannot be implemented without touching \`<file>\`, but the plan rules out that file."
|
|
673
|
+
- **Dependency upgrade required.** Surface as \`info\`: "AC-N requires \`<lib>@>=X\`, current is \`<Y>\`. Recommend separate dep-bump slug."
|
|
674
|
+
|
|
675
|
+
In all four cases: stop, return the summary JSON, do **not** push code that "works around it".
|
|
676
|
+
|
|
677
|
+
## What this skill does NOT prevent
|
|
678
|
+
|
|
679
|
+
- Re-running a build / test after you actually changed code. That is normal TDD GREEN-cycle behaviour.
|
|
680
|
+
- Adding a real test fixture or mock library at the test boundary (\`vi.mock("./db")\` in the *test file*, not in production). The boundary matters.
|
|
681
|
+
- Documented \`// eslint-disable\` lines with a one-line justification AND a follow-up issue id. The justification is what makes it not slop.
|
|
682
|
+
- Running \`tsc --noEmit\` after \`npm test\` — that is a different tool, not a re-run of the same one.
|
|
683
|
+
`;
|
|
684
|
+
export const AUTO_TRIGGER_SKILLS = [
|
|
685
|
+
{
|
|
686
|
+
id: "plan-authoring",
|
|
687
|
+
fileName: "plan-authoring.md",
|
|
688
|
+
description: "Auto-applies whenever the agent edits .cclaw/flows/<slug>/plan.md.",
|
|
689
|
+
triggers: ["edit:.cclaw/flows/*/plan.md", "create:.cclaw/flows/*/plan.md"],
|
|
690
|
+
body: PLAN_AUTHORING
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
id: "ac-traceability",
|
|
694
|
+
fileName: "ac-traceability.md",
|
|
695
|
+
description: "Enforces commit-helper invocation and AC↔commit chain.",
|
|
696
|
+
triggers: ["before:git-commit", "before:git-push"],
|
|
697
|
+
body: AC_TRACEABILITY
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
id: "refinement",
|
|
701
|
+
fileName: "refinement.md",
|
|
702
|
+
description: "Activates when /cc detects an existing plan match.",
|
|
703
|
+
triggers: ["existing-plan-detected"],
|
|
704
|
+
body: REFINEMENT
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
id: "parallel-build",
|
|
708
|
+
fileName: "parallel-build.md",
|
|
709
|
+
description: "Rules and execution playbook for the parallel-build topology.",
|
|
710
|
+
triggers: ["topology:parallel-build"],
|
|
711
|
+
body: PARALLEL_BUILD
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
id: "security-review",
|
|
715
|
+
fileName: "security-review.md",
|
|
716
|
+
description: "Activates when the diff touches sensitive surfaces.",
|
|
717
|
+
triggers: ["security-flag:true", "diff:auth|secrets|supply-chain|pii"],
|
|
718
|
+
body: SECURITY_REVIEW
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
id: "review-loop",
|
|
722
|
+
fileName: "review-loop.md",
|
|
723
|
+
description: "Wraps every reviewer / security-reviewer invocation.",
|
|
724
|
+
triggers: ["specialist:reviewer", "specialist:security-reviewer"],
|
|
725
|
+
body: REVIEW_LOOP
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
id: "tdd-cycle",
|
|
729
|
+
fileName: "tdd-cycle.md",
|
|
730
|
+
description: "Mandatory always-on skill while stage=build. Enforces RED → GREEN → REFACTOR per AC, with watched-RED proof and full-suite GREEN evidence.",
|
|
731
|
+
triggers: ["stage:build", "specialist:slice-builder"],
|
|
732
|
+
body: TDD_CYCLE
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
id: "commit-message-quality",
|
|
736
|
+
fileName: "commit-message-quality.md",
|
|
737
|
+
description: "Enforces commit-message conventions for commit-helper.mjs.",
|
|
738
|
+
triggers: ["before:commit-helper"],
|
|
739
|
+
body: COMMIT_MESSAGE_QUALITY
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
id: "ac-quality",
|
|
743
|
+
fileName: "ac-quality.md",
|
|
744
|
+
description: "Three-check rubric for every AC entry; smell tests + numbering rules.",
|
|
745
|
+
triggers: ["edit:.cclaw/flows/*/plan.md", "specialist:planner", "specialist:reviewer:text-review"],
|
|
746
|
+
body: AC_QUALITY
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: "refactor-safety",
|
|
750
|
+
fileName: "refactor-safety.md",
|
|
751
|
+
description: "Behaviour-preservation rules for pure-refactor slugs.",
|
|
752
|
+
triggers: ["task:refactor", "pattern:refactor"],
|
|
753
|
+
body: REFACTOR_SAFETY
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
id: "breaking-changes",
|
|
757
|
+
fileName: "breaking-changes.md",
|
|
758
|
+
description: "Detect and document breaking changes; coexistence rules and CHANGELOG template.",
|
|
759
|
+
triggers: ["diff:public-api", "frontmatter:breaking_change=true"],
|
|
760
|
+
body: BREAKING_CHANGES
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: "conversation-language",
|
|
764
|
+
fileName: "conversation-language.md",
|
|
765
|
+
description: "Always-on policy: reply in the user's language; never translate paths, AC ids, slugs, hook output, or frontmatter keys.",
|
|
766
|
+
triggers: ["always-on"],
|
|
767
|
+
body: CONVERSATION_LANGUAGE
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
id: "anti-slop",
|
|
771
|
+
fileName: "anti-slop.md",
|
|
772
|
+
description: "Always-on guard against redundant verification, env-specific shims, and silent skip-and-pass fixes.",
|
|
773
|
+
triggers: ["always-on", "task:build", "task:fix-only", "task:recovery"],
|
|
774
|
+
body: ANTI_SLOP
|
|
775
|
+
}
|
|
776
|
+
];
|