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/harness-adapters.js
DELETED
|
@@ -1,756 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { RUNTIME_ROOT } from "./constants.js";
|
|
4
|
-
import { conversationLanguagePolicyMarkdown } from "./content/language-policy.js";
|
|
5
|
-
import { CCLAW_AGENTS, agentMarkdown } from "./content/core-agents.js";
|
|
6
|
-
import { IRON_LAWS } from "./content/iron-laws.js";
|
|
7
|
-
import { ensureDir, exists, writeFileSafe } from "./fs-utils.js";
|
|
8
|
-
export const CCLAW_MARKER_START = "<!-- cclaw-start -->";
|
|
9
|
-
export const CCLAW_MARKER_END = "<!-- cclaw-end -->";
|
|
10
|
-
function escapeRegExp(value) {
|
|
11
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
-
}
|
|
13
|
-
const RUNTIME_AGENTS_BLOCK_SOURCE = `${escapeRegExp(CCLAW_MARKER_START)}[\\s\\S]*?${escapeRegExp(CCLAW_MARKER_END)}`;
|
|
14
|
-
const RUNTIME_AGENTS_BLOCK_PATTERN = new RegExp(RUNTIME_AGENTS_BLOCK_SOURCE, "u");
|
|
15
|
-
const RUNTIME_AGENTS_BLOCK_GLOBAL_PATTERN = new RegExp(RUNTIME_AGENTS_BLOCK_SOURCE, "gu");
|
|
16
|
-
const UTILITY_SHIMS = [
|
|
17
|
-
{
|
|
18
|
-
fileName: "cc-idea.md",
|
|
19
|
-
skillName: "cc-idea",
|
|
20
|
-
command: "idea",
|
|
21
|
-
skillFolder: "flow-idea",
|
|
22
|
-
commandFile: "idea.md"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
fileName: "cc-cancel.md",
|
|
26
|
-
skillName: "cc-cancel",
|
|
27
|
-
command: "cancel",
|
|
28
|
-
skillFolder: "flow-cancel",
|
|
29
|
-
commandFile: "cancel.md"
|
|
30
|
-
}
|
|
31
|
-
];
|
|
32
|
-
/** Skill-kind shim name for the root `/cc` entry point. */
|
|
33
|
-
const ENTRY_SHIM_SKILL_NAME = "cc";
|
|
34
|
-
const LEGACY_CODEX_SKILL_PREFIX = "cclaw-cc";
|
|
35
|
-
/**
|
|
36
|
-
* Shims that older cclaw versions installed as top-level slash commands but
|
|
37
|
-
* which we now treat as internal (skill-only, invoked by the agent, never
|
|
38
|
-
* typed by users). On sync/upgrade we proactively delete any stale file from
|
|
39
|
-
* harness command directories so `/cc-learn` etc. do not linger.
|
|
40
|
-
*/
|
|
41
|
-
const LEGACY_HARNESS_SHIMS = ["cc-learn.md"];
|
|
42
|
-
export function harnessShimFileNames() {
|
|
43
|
-
return [
|
|
44
|
-
"cc.md",
|
|
45
|
-
...UTILITY_SHIMS.map((shim) => shim.fileName)
|
|
46
|
-
];
|
|
47
|
-
}
|
|
48
|
-
/** Skill folder names cclaw writes under `<commandDir>` for skill-kind harnesses. */
|
|
49
|
-
export function harnessShimSkillNames() {
|
|
50
|
-
return [
|
|
51
|
-
ENTRY_SHIM_SKILL_NAME,
|
|
52
|
-
...UTILITY_SHIMS.map((shim) => shim.skillName)
|
|
53
|
-
];
|
|
54
|
-
}
|
|
55
|
-
export const HARNESS_ADAPTERS = {
|
|
56
|
-
claude: {
|
|
57
|
-
id: "claude",
|
|
58
|
-
reality: {
|
|
59
|
-
declaredSupport: "full",
|
|
60
|
-
runtimeLaunch: "native Task launch",
|
|
61
|
-
proofRequired: "spanId+dispatchId or workerRunId+ACK for isolated completion",
|
|
62
|
-
proofSource: ".cclaw/state/delegation-events.jsonl plus delegation-log.json"
|
|
63
|
-
},
|
|
64
|
-
commandDir: ".claude/commands",
|
|
65
|
-
shimKind: "command",
|
|
66
|
-
capabilities: {
|
|
67
|
-
nativeSubagentDispatch: "full",
|
|
68
|
-
hookSurface: "full",
|
|
69
|
-
structuredAsk: "AskUserQuestion",
|
|
70
|
-
subagentFallback: "native"
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
cursor: {
|
|
74
|
-
id: "cursor",
|
|
75
|
-
reality: {
|
|
76
|
-
declaredSupport: "generic",
|
|
77
|
-
runtimeLaunch: "generic Task/Subagent launch with cclaw role prompt",
|
|
78
|
-
proofRequired: "spanId+dispatchId/evidenceRefs for generic-dispatch completion",
|
|
79
|
-
proofSource: ".cclaw/state/delegation-events.jsonl plus artifact evidenceRefs"
|
|
80
|
-
},
|
|
81
|
-
commandDir: ".cursor/commands",
|
|
82
|
-
shimKind: "command",
|
|
83
|
-
capabilities: {
|
|
84
|
-
// Cursor has a real Task tool with subagent_type (generalPurpose,
|
|
85
|
-
// explore, shell, browser-use, …) but no user-defined named
|
|
86
|
-
// subagents. cclaw maps each named agent (planner/reviewer/…) onto
|
|
87
|
-
// generic dispatch with a role prompt.
|
|
88
|
-
nativeSubagentDispatch: "generic",
|
|
89
|
-
hookSurface: "full",
|
|
90
|
-
structuredAsk: "AskQuestion",
|
|
91
|
-
subagentFallback: "generic-dispatch"
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
opencode: {
|
|
95
|
-
id: "opencode",
|
|
96
|
-
reality: {
|
|
97
|
-
declaredSupport: "full",
|
|
98
|
-
runtimeLaunch: "prompt-level launch via Task or @agent against generated .opencode/agents",
|
|
99
|
-
proofRequired: "spanId+dispatchId+ackTs+completedTs before isolated completion",
|
|
100
|
-
proofSource: ".opencode/agents/<agent>.md and .cclaw/state/delegation-events.jsonl"
|
|
101
|
-
},
|
|
102
|
-
commandDir: ".opencode/commands",
|
|
103
|
-
shimKind: "command",
|
|
104
|
-
capabilities: {
|
|
105
|
-
// OpenCode supports project-local markdown subagents under
|
|
106
|
-
// `.opencode/agents/`; primary agents can invoke them via the Task
|
|
107
|
-
// tool or explicit `@agent` mention. cclaw materializes its core
|
|
108
|
-
// roster there, so mandatory delegations are real isolated subagents.
|
|
109
|
-
nativeSubagentDispatch: "full",
|
|
110
|
-
hookSurface: "plugin",
|
|
111
|
-
// OpenCode exposes a native `question` tool (header + options +
|
|
112
|
-
// custom-answer fallback, multi-question navigation). It is
|
|
113
|
-
// permission-gated — `opencode.json` must set
|
|
114
|
-
// `permission.question: "allow"` and ACP clients must export
|
|
115
|
-
// `OPENCODE_ENABLE_QUESTION_TOOL=1`. cclaw surfaces the tool name
|
|
116
|
-
// in generated harness guidance; skills fall back to the shared
|
|
117
|
-
// plain-text lettered list when the tool is denied or unavailable.
|
|
118
|
-
structuredAsk: "question",
|
|
119
|
-
subagentFallback: "native"
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
codex: {
|
|
123
|
-
id: "codex",
|
|
124
|
-
reality: {
|
|
125
|
-
declaredSupport: "full",
|
|
126
|
-
runtimeLaunch: "prompt-level launch by asking Codex to spawn generated custom agents",
|
|
127
|
-
proofRequired: "spanId+dispatchId+ackTs+completedTs before isolated completion",
|
|
128
|
-
proofSource: ".codex/agents/<agent>.toml and .cclaw/state/delegation-events.jsonl"
|
|
129
|
-
},
|
|
130
|
-
// Codex CLI reads skills from the universal `.agents/skills/` path
|
|
131
|
-
// (OpenAI Codex 0.89, Jan 2026). It does NOT have a native
|
|
132
|
-
// `.codex/commands/*` slash-command discovery — cclaw installs
|
|
133
|
-
// its entry points as skills here. Current Codex releases also support
|
|
134
|
-
// native parallel subagents and project-local `.codex/agents/*.toml`
|
|
135
|
-
// custom agents; cclaw materializes its core roster there. Since v0.114
|
|
136
|
-
// (Mar 2026) Codex also exposes lifecycle hooks via `.codex/hooks.json`, behind
|
|
137
|
-
// the `[features] codex_hooks = true` feature flag in
|
|
138
|
-
// `~/.codex/config.toml`. cclaw writes that file on sync and
|
|
139
|
-
// `hookSurface: "limited"` records the reality: SessionStart /
|
|
140
|
-
// UserPromptSubmit / Stop fire for every turn, but PreToolUse /
|
|
141
|
-
// PostToolUse only intercept the `Bash` tool.
|
|
142
|
-
commandDir: ".agents/skills",
|
|
143
|
-
shimKind: "skill",
|
|
144
|
-
capabilities: {
|
|
145
|
-
nativeSubagentDispatch: "full",
|
|
146
|
-
hookSurface: "limited",
|
|
147
|
-
// Codex CLI exposes `request_user_input` — an experimental tool
|
|
148
|
-
// that asks 1-3 short questions and returns the user's answers.
|
|
149
|
-
// It is the primitive the built-in Plan / Collaboration mode
|
|
150
|
-
// templates use (see `codex-rs/collaboration-mode-templates`).
|
|
151
|
-
// Agents running inside Codex can call it directly; cclaw wires
|
|
152
|
-
// it into generated harness guidance. The shared plain-text
|
|
153
|
-
// lettered list is the documented fallback when the tool is unavailable.
|
|
154
|
-
structuredAsk: "request_user_input",
|
|
155
|
-
subagentFallback: "native"
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
export function harnessDispatchSurface(harnessId) {
|
|
160
|
-
switch (harnessId) {
|
|
161
|
-
case "claude":
|
|
162
|
-
return "Use Claude Code Task with the cclaw agent name as subagent_type; record fulfillmentMode: \"isolated\".";
|
|
163
|
-
case "cursor":
|
|
164
|
-
return "Use Cursor Subagent/Task with a generic subagent_type (explore for read-only mapping, generalPurpose for broader work, shell/browser-use when specifically needed) and paste the cclaw role prompt; record fulfillmentMode: \"generic-dispatch\" with evidenceRefs.";
|
|
165
|
-
case "opencode":
|
|
166
|
-
return "Use OpenCode subagents: invoke the generated .opencode/agents/<agent>.md agent via Task or @<agent>; if agents or plugin registration are missing, run `cclaw sync` and check opencode.json(.c) plugin registration with `npx cclaw-cli sync`; record scheduled/launched/acknowledged/completed events with spanId+dispatchId before claiming fulfillmentMode: \"isolated\".";
|
|
167
|
-
case "codex":
|
|
168
|
-
return "Use Codex native subagents: ask Codex to spawn the generated .codex/agents/<agent>.toml agent(s) by name; if hooks are inert, set `[features] codex_hooks = true` in ~/.codex/config.toml or rerun init/sync repair, then `npx cclaw-cli sync`; record scheduled/launched/acknowledged/completed events with spanId+dispatchId before claiming fulfillmentMode: \"isolated\".";
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Per-harness lifecycle recipe used by skills and harness docs to render the
|
|
173
|
-
* canonical scheduled -> launched -> acknowledged -> completed sequence in
|
|
174
|
-
* structural form. The recipe never embeds task-specific or domain-specific
|
|
175
|
-
* placeholders — only neutral angle-bracket tokens (`<agent-name>`, `<stage>`,
|
|
176
|
-
* `<span-id>`, `<dispatch-id>`, `<agent-def-path>`, `<iso-ts>`).
|
|
177
|
-
*
|
|
178
|
-
* This function returns the **canonical primary recipe** for each shipped
|
|
179
|
-
* harness — the dispatch surface that maps 1:1 onto the harness's vendor-
|
|
180
|
-
* native subagent surface:
|
|
181
|
-
*
|
|
182
|
-
* - `claude` -> `claude-task` (isolated)
|
|
183
|
-
* - `cursor` -> `cursor-task` (generic-dispatch)
|
|
184
|
-
* - `opencode` -> `opencode-agent` (isolated)
|
|
185
|
-
* - `codex` -> `codex-agent` (isolated)
|
|
186
|
-
*
|
|
187
|
-
* The remaining `--dispatch-surface` enum values (`generic-task`,
|
|
188
|
-
* `role-switch`, `manual`) are universal fallback paths available to any
|
|
189
|
-
* harness when the canonical surface is unavailable; they are documented in
|
|
190
|
-
* the dispatch-surface table in `docs/harnesses.md` rather than per-harness
|
|
191
|
-
* here, because their lifecycle commands are structurally identical except
|
|
192
|
-
* for the surface token. No shipped harness has a non-canonical *primary*
|
|
193
|
-
* surface, so this function only needs to enumerate the four canonical
|
|
194
|
-
* recipes above.
|
|
195
|
-
*/
|
|
196
|
-
export function harnessDelegationRecipe(harnessId) {
|
|
197
|
-
const helper = "node .cclaw/hooks/delegation-record.mjs";
|
|
198
|
-
const common = "--stage=<stage> --agent=<agent-name> --mode=mandatory --span-id=<span-id> --dispatch-id=<dispatch-id>";
|
|
199
|
-
switch (harnessId) {
|
|
200
|
-
case "claude":
|
|
201
|
-
return {
|
|
202
|
-
harnessId,
|
|
203
|
-
dispatchSurface: "claude-task",
|
|
204
|
-
agentDefinitionDirectory: ".claude/agents/",
|
|
205
|
-
agentDefinitionExample: ".claude/agents/<agent-name>.md",
|
|
206
|
-
invocationLine: "Call Task with subagent_type=<agent-name> and prompt body that paraphrases the stage skill role.",
|
|
207
|
-
fulfillmentMode: "isolated",
|
|
208
|
-
lifecycleCommands: [
|
|
209
|
-
`${helper} ${common} --status=scheduled --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --json`,
|
|
210
|
-
`${helper} ${common} --status=launched --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
211
|
-
`${helper} ${common} --status=acknowledged --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
212
|
-
`${helper} ${common} --status=completed --dispatch-surface=claude-task --agent-definition-path=.claude/agents/<agent-name>.md --completed-ts=<iso-ts> --json`
|
|
213
|
-
]
|
|
214
|
-
};
|
|
215
|
-
case "cursor":
|
|
216
|
-
return {
|
|
217
|
-
harnessId,
|
|
218
|
-
dispatchSurface: "cursor-task",
|
|
219
|
-
agentDefinitionDirectory: ".cclaw/agents/",
|
|
220
|
-
agentDefinitionExample: ".cclaw/agents/<agent-name>.md",
|
|
221
|
-
invocationLine: "Call Task with a generic subagent_type and paste the cclaw role prompt; capture worker output as evidenceRefs in the artifact.",
|
|
222
|
-
fulfillmentMode: "generic-dispatch",
|
|
223
|
-
lifecycleCommands: [
|
|
224
|
-
`${helper} ${common} --status=scheduled --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --json`,
|
|
225
|
-
`${helper} ${common} --status=launched --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
226
|
-
`${helper} ${common} --status=acknowledged --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
227
|
-
`${helper} ${common} --status=completed --dispatch-surface=cursor-task --agent-definition-path=.cclaw/agents/<agent-name>.md --completed-ts=<iso-ts> --evidence-ref=<artifact-anchor> --json`
|
|
228
|
-
]
|
|
229
|
-
};
|
|
230
|
-
case "opencode":
|
|
231
|
-
return {
|
|
232
|
-
harnessId,
|
|
233
|
-
dispatchSurface: "opencode-agent",
|
|
234
|
-
agentDefinitionDirectory: ".opencode/agents/",
|
|
235
|
-
agentDefinitionExample: ".opencode/agents/<agent-name>.md",
|
|
236
|
-
invocationLine: "Invoke the generated agent via Task or `@<agent-name>`; the agent body lives in `.opencode/agents/<agent-name>.md`.",
|
|
237
|
-
fulfillmentMode: "isolated",
|
|
238
|
-
lifecycleCommands: [
|
|
239
|
-
`${helper} ${common} --status=scheduled --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --json`,
|
|
240
|
-
`${helper} ${common} --status=launched --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --launched-ts=<iso-ts> --json`,
|
|
241
|
-
`${helper} ${common} --status=acknowledged --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --ack-ts=<iso-ts> --json`,
|
|
242
|
-
`${helper} ${common} --status=completed --dispatch-surface=opencode-agent --agent-definition-path=.opencode/agents/<agent-name>.md --completed-ts=<iso-ts> --json`
|
|
243
|
-
]
|
|
244
|
-
};
|
|
245
|
-
case "codex":
|
|
246
|
-
return {
|
|
247
|
-
harnessId,
|
|
248
|
-
dispatchSurface: "codex-agent",
|
|
249
|
-
agentDefinitionDirectory: ".codex/agents/",
|
|
250
|
-
agentDefinitionExample: ".codex/agents/<agent-name>.toml",
|
|
251
|
-
invocationLine: "Ask Codex to spawn the named custom agent; the agent definition lives in `.codex/agents/<agent-name>.toml`.",
|
|
252
|
-
fulfillmentMode: "isolated",
|
|
253
|
-
lifecycleCommands: [
|
|
254
|
-
`${helper} ${common} --status=scheduled --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --json`,
|
|
255
|
-
`${helper} ${common} --status=launched --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --launched-ts=<iso-ts> --json`,
|
|
256
|
-
`${helper} ${common} --status=acknowledged --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --ack-ts=<iso-ts> --json`,
|
|
257
|
-
`${helper} ${common} --status=completed --dispatch-surface=codex-agent --agent-definition-path=.codex/agents/<agent-name>.toml --completed-ts=<iso-ts> --json`
|
|
258
|
-
]
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/** All four harness recipes in tier-stable order. */
|
|
263
|
-
export function harnessDelegationRecipes() {
|
|
264
|
-
return harnessesByTier().map((id) => harnessDelegationRecipe(id));
|
|
265
|
-
}
|
|
266
|
-
export function harnessDispatchFallback(harnessId) {
|
|
267
|
-
const adapter = HARNESS_ADAPTERS[harnessId];
|
|
268
|
-
if (adapter.capabilities.subagentFallback !== "role-switch") {
|
|
269
|
-
return "Role-switch is only a degradation path if the active runtime cannot expose the declared dispatch surface; include non-empty evidenceRefs when used.";
|
|
270
|
-
}
|
|
271
|
-
return "Use a visible role-switch pass with non-empty evidenceRefs because this harness has no true dispatch surface.";
|
|
272
|
-
}
|
|
273
|
-
export function harnessTier(harnessId) {
|
|
274
|
-
const capabilities = HARNESS_ADAPTERS[harnessId].capabilities;
|
|
275
|
-
if (capabilities.nativeSubagentDispatch === "full" &&
|
|
276
|
-
capabilities.structuredAsk !== "plain-text" &&
|
|
277
|
-
capabilities.hookSurface === "full") {
|
|
278
|
-
return "tier1";
|
|
279
|
-
}
|
|
280
|
-
if (capabilities.hookSurface !== "none" || capabilities.nativeSubagentDispatch !== "none") {
|
|
281
|
-
return "tier2";
|
|
282
|
-
}
|
|
283
|
-
return "tier3";
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Harness IDs ordered from best (tier1) to least-capable. Stable sort — same
|
|
287
|
-
* tier preserves declaration order.
|
|
288
|
-
*/
|
|
289
|
-
export function harnessesByTier() {
|
|
290
|
-
return Object.keys(HARNESS_ADAPTERS).sort((a, b) => {
|
|
291
|
-
const tierOrder = { tier1: 0, tier2: 1, tier3: 2 };
|
|
292
|
-
return tierOrder[harnessTier(a)] - tierOrder[harnessTier(b)];
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
function ironLawsAgentsMdBlock() {
|
|
296
|
-
// keep this set in sync with `ironLawsSkillMarkdown()` —
|
|
297
|
-
// post-Phase A, only `stop-clean-or-handoff` is still hook-enforced
|
|
298
|
-
// (Stop hook). All other iron laws live in stage HARD-GATE blocks.
|
|
299
|
-
const enforcedLawIds = new Set([
|
|
300
|
-
"stop-clean-or-handoff"
|
|
301
|
-
]);
|
|
302
|
-
const enforcedRows = IRON_LAWS
|
|
303
|
-
.filter((law) => enforcedLawIds.has(law.id))
|
|
304
|
-
.map((law) => `| \`${law.id}\` | ${law.rule} | ${law.enforcement} |`)
|
|
305
|
-
.join("\n");
|
|
306
|
-
const advisoryRows = IRON_LAWS
|
|
307
|
-
.filter((law) => !enforcedLawIds.has(law.id))
|
|
308
|
-
.map((law) => {
|
|
309
|
-
const appliesTo = law.appliesTo === "all" ? "all stages" : law.appliesTo.join(", ");
|
|
310
|
-
return `- \`${law.id}\` (applies to: ${appliesTo})`;
|
|
311
|
-
})
|
|
312
|
-
.join("\n");
|
|
313
|
-
return `### Iron Laws
|
|
314
|
-
|
|
315
|
-
These rules are always-on. The hook-enforced runtime laws are:
|
|
316
|
-
|
|
317
|
-
| ID | Rule | Enforced by |
|
|
318
|
-
|---|---|---|
|
|
319
|
-
${enforcedRows}
|
|
320
|
-
|
|
321
|
-
Advisory laws are stage-owned through each stage's HARD-GATE block:
|
|
322
|
-
|
|
323
|
-
${advisoryRows}
|
|
324
|
-
`;
|
|
325
|
-
}
|
|
326
|
-
function agentsMdBlock() {
|
|
327
|
-
return `${CCLAW_MARKER_START}
|
|
328
|
-
## Cclaw — Workflow Adapter
|
|
329
|
-
|
|
330
|
-
> Auto-generated by \`cclaw sync\`. Do not edit this managed block manually.
|
|
331
|
-
> Existing project rules in this repository take precedence over cclaw defaults.
|
|
332
|
-
|
|
333
|
-
${conversationLanguagePolicyMarkdown()}
|
|
334
|
-
## Anti-Slop Guard
|
|
335
|
-
|
|
336
|
-
Treat quality as a hard requirement, not style preference:
|
|
337
|
-
|
|
338
|
-
1. Confirm there is a real problem statement before proposing broad changes.
|
|
339
|
-
2. Prefer one focused change over bundled unrelated edits.
|
|
340
|
-
3. Verify claims with fresh evidence in this turn.
|
|
341
|
-
4. If uncertain, escalate with options instead of fabricating certainty.
|
|
342
|
-
|
|
343
|
-
### Activation Rule
|
|
344
|
-
|
|
345
|
-
Before responding to a coding request:
|
|
346
|
-
1. Read \`.cclaw/state/flow-state.json\` for the current stage.
|
|
347
|
-
2. Use \`/cc\` to start, resume, or continue the flow.
|
|
348
|
-
3. If no stage applies, respond normally.
|
|
349
|
-
|
|
350
|
-
### Cclaw Baseline (always-on)
|
|
351
|
-
|
|
352
|
-
Three rules apply to every cclaw stage in this project, regardless of which skills loaded:
|
|
353
|
-
|
|
354
|
-
1. **Q&A convergence before drafting** — for brainstorm / scope / design, walk the stage forcing questions one at a time via the harness-native question tool (Claude \`AskUserQuestion\`, Cursor \`AskQuestion\`, Codex \`request_user_input\`, Gemini \`ask_user\`). The \`qa_log_unconverged\` linter rule will block \`stage-complete\` when convergence has not been reached. Convergence is satisfied when ANY of: (a) every forcing-question topic id is tagged \`[topic:<id>]\` in at least one \`## Q&A Log\` row, (b) the last 2 substantive rows produce no decision-changing impact (Ralph-Loop), or (c) an explicit user stop-signal row is recorded. \`[topic:<id>]\` tagging is mandatory (no English keyword fallback) so the gate works in any natural language.
|
|
355
|
-
2. **Subagents run after Q&A approval** — mandatory subagents in brainstorm / scope / design (\`product-discovery\`, \`critic\`, \`planner\`, \`architect\`) run only AFTER the user approves the elicitation outcome. See each stage's "Run Phase: post-elicitation" rows in the materialized Automatic Subagent Dispatch table.
|
|
356
|
-
3. **No command-line echo to chat** — the user does not run cclaw helpers manually. Never paste \`node .cclaw/hooks/...\` invocations, \`--evidence-json '{...}'\` payloads, or shell hash commands (\`shasum\`, \`sha256sum\`, \`Get-FileHash\`, \`certutil\`, etc.) into chat. Run helpers via the tool layer; report only the resulting summary.
|
|
357
|
-
|
|
358
|
-
${ironLawsAgentsMdBlock()}
|
|
359
|
-
|
|
360
|
-
### Task Classification (before \`/cc\`)
|
|
361
|
-
|
|
362
|
-
| Class | Examples | Route |
|
|
363
|
-
|---|---|---|
|
|
364
|
-
| Software — non-trivial | feature, refactor, migration, integration | \`/cc <idea>\` → stage flow (standard track) |
|
|
365
|
-
| Software — trivial | typo, one-liner, rename, config tweak | \`/cc <idea>\` → quick track |
|
|
366
|
-
| Software — bug fix | regression with repro | \`/cc <idea>\` → quick track, RED reproduces bug first |
|
|
367
|
-
| Pure question | "how does X work?" | Answer directly; no stage |
|
|
368
|
-
| Non-software | legal text, meeting notes | Answer directly; no stage |
|
|
369
|
-
|
|
370
|
-
When in doubt, prefer **non-trivial** — the quick track is opt-in and only safe when scope is clearly small.
|
|
371
|
-
|
|
372
|
-
### Instruction Priority (top wins)
|
|
373
|
-
|
|
374
|
-
1. User message in the current turn.
|
|
375
|
-
2. Active stage skill and command contract.
|
|
376
|
-
3. The \`using-cclaw\` meta-skill.
|
|
377
|
-
4. Contextual utility skills.
|
|
378
|
-
5. Training priors.
|
|
379
|
-
|
|
380
|
-
### Commands
|
|
381
|
-
|
|
382
|
-
| Command | Purpose |
|
|
383
|
-
|---|---|
|
|
384
|
-
| \`/cc\` | **Entry point.** No args = resume or progress current flow. With prompt = classify task and start the right flow. |
|
|
385
|
-
| \`/cc-idea\` | **Idea mode.** Generates a ranked repo-improvement backlog before implementation. |
|
|
386
|
-
| \`/cc-cancel\` | **Non-completion closeout.** Archives a cancelled/abandoned run with a required reason. |
|
|
387
|
-
|
|
388
|
-
Knowledge capture and curation run automatically as part of stage completion
|
|
389
|
-
protocols via the internal \`learnings\` skill — no user-facing command.
|
|
390
|
-
Reusable entries land in \`.cclaw/knowledge.jsonl\` as strict JSONL with
|
|
391
|
-
\`type\`, \`trigger\`, \`action\`, \`confidence\`, \`stage\`, and \`origin_stage\` metadata.
|
|
392
|
-
|
|
393
|
-
**Stage order:** brainstorm > scope > design > spec > plan > tdd > review > ship, then closeout: retro > compound > archive. Use \`/cc\` to keep moving through normal work and post-ship closeout; use \`/cc-cancel\` for cancelled/abandoned runs. Gates must pass before handoff.
|
|
394
|
-
|
|
395
|
-
### Verification Discipline
|
|
396
|
-
|
|
397
|
-
No completion claims without fresh evidence. No "Done" / "All good" / "Tests pass" without running the command in this message. Failed tool calls are diagnostic data, not instructions.
|
|
398
|
-
|
|
399
|
-
### Escalation
|
|
400
|
-
|
|
401
|
-
If the same approach fails three times in a row (same command, same finding, same tool), STOP. Summarize what you tried, what evidence you have, and ask the user how to proceed — do not invent a fourth angle silently.
|
|
402
|
-
|
|
403
|
-
### Detail Level
|
|
404
|
-
|
|
405
|
-
- This managed AGENTS block is intentionally minimal for cross-project use.
|
|
406
|
-
- Subagent dispatch coverage: Claude/OpenCode/Codex support native isolated workers; Cursor uses generic Task dispatch. Codex still has Bash-only tool hooks.
|
|
407
|
-
- Detailed operating procedures live in \`.cclaw/skills/using-cclaw/SKILL.md\`.
|
|
408
|
-
- Keep preambles brief; re-announce role/stage only when either changes.
|
|
409
|
-
- Subagent orchestration patterns: \`.cclaw/skills/subagent-dev/SKILL.md\` and \`.cclaw/skills/parallel-dispatch/SKILL.md\`.
|
|
410
|
-
|
|
411
|
-
### Codex users
|
|
412
|
-
|
|
413
|
-
OpenAI Codex CLI has **no native \`/cc\` slash command** (custom prompts
|
|
414
|
-
were deprecated in v0.89, Jan 2026). The \`/cc\`, \`/cc-idea\`, and
|
|
415
|
-
\`/cc-cancel\` tokens above describe intent — in Codex they map onto skills cclaw installs at
|
|
416
|
-
\`.agents/skills/cc*/SKILL.md\`. Activate one of two ways:
|
|
417
|
-
|
|
418
|
-
- Type \`/use cc\` (or \`cc-idea\` / \`cc-cancel\`) at Codex's prompt.
|
|
419
|
-
- Type \`/cc …\` as plain text — Codex matches the skill \`description\`
|
|
420
|
-
frontmatter (which spells out the token verbatim) and loads the right
|
|
421
|
-
skill body automatically.
|
|
422
|
-
|
|
423
|
-
Codex CLI v0.114+ (Mar 2026) **does** expose lifecycle hooks via
|
|
424
|
-
\`.codex/hooks.json\`, gated by the \`[features] codex_hooks = true\` flag
|
|
425
|
-
in \`~/.codex/config.toml\`. cclaw generates \`.codex/hooks.json\` on
|
|
426
|
-
sync; if the feature flag is off, hooks are inert and cclaw's
|
|
427
|
-
session-start rehydration simply does not fire. Run \`npx cclaw-cli sync\` to
|
|
428
|
-
see if the flag is missing. \`.codex/commands/*\` is still unused by
|
|
429
|
-
Codex CLI and is removed on every sync. Run \`npx cclaw-cli sync\` for
|
|
430
|
-
hook coverage details (Bash-only \`PreToolUse\`/\`PostToolUse\`; other events are full).
|
|
431
|
-
${CCLAW_MARKER_END}`;
|
|
432
|
-
}
|
|
433
|
-
/** Removes the cclaw AGENTS.md block. */
|
|
434
|
-
export function stripCclawBlock(content) {
|
|
435
|
-
let updated = content.replace(RUNTIME_AGENTS_BLOCK_GLOBAL_PATTERN, "");
|
|
436
|
-
return updated.replace(/\n{3,}/g, "\n\n").trim();
|
|
437
|
-
}
|
|
438
|
-
async function syncRoutingFile(filePath, title) {
|
|
439
|
-
const block = agentsMdBlock();
|
|
440
|
-
if (!(await exists(filePath))) {
|
|
441
|
-
await writeFileSafe(filePath, `# ${title}\n\n${block}\n`);
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
445
|
-
if (RUNTIME_AGENTS_BLOCK_PATTERN.test(content)) {
|
|
446
|
-
const stripped = stripCclawBlock(content);
|
|
447
|
-
const updated = stripped.length > 0 ? `${stripped}\n\n${block}\n` : `${block}\n`;
|
|
448
|
-
await writeFileSafe(filePath, updated);
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
await writeFileSafe(filePath, `${content.trimEnd()}\n\n${block}\n`);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
async function syncAgentsMd(projectRoot, harnesses = []) {
|
|
455
|
-
// AGENTS.md is universal — always injected or created. Claude Code, Cursor,
|
|
456
|
-
// Codex, and OpenCode all read it when present.
|
|
457
|
-
await syncRoutingFile(path.join(projectRoot, "AGENTS.md"), "AGENTS");
|
|
458
|
-
// CLAUDE.md is Claude Code's preferred routing file. If the claude harness
|
|
459
|
-
// is active, we materialise the routing block there too (create if missing,
|
|
460
|
-
// otherwise keep append-and-refresh semantics). For non-claude installs, we
|
|
461
|
-
// still refresh CLAUDE.md when it already exists — never silently drop it.
|
|
462
|
-
const claudePath = path.join(projectRoot, "CLAUDE.md");
|
|
463
|
-
const claudeExists = await exists(claudePath);
|
|
464
|
-
const claudeHarnessActive = harnesses.includes("claude");
|
|
465
|
-
if (claudeExists || claudeHarnessActive) {
|
|
466
|
-
await syncRoutingFile(claudePath, "CLAUDE");
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
async function removeCclawFromRoutingFile(filePath) {
|
|
470
|
-
if (!(await exists(filePath)))
|
|
471
|
-
return;
|
|
472
|
-
const content = await fs.readFile(filePath, "utf8");
|
|
473
|
-
if (!RUNTIME_AGENTS_BLOCK_PATTERN.test(content))
|
|
474
|
-
return;
|
|
475
|
-
const stripped = stripCclawBlock(content);
|
|
476
|
-
if (stripped.replace(/\s/g, "").length === 0) {
|
|
477
|
-
await fs.rm(filePath, { force: true });
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
await writeFileSafe(filePath, `${stripped}\n`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
export async function removeCclawFromAgentsMd(projectRoot) {
|
|
484
|
-
await removeCclawFromRoutingFile(path.join(projectRoot, "AGENTS.md"));
|
|
485
|
-
await removeCclawFromRoutingFile(path.join(projectRoot, "CLAUDE.md"));
|
|
486
|
-
}
|
|
487
|
-
function utilityShimBehavior(command) {
|
|
488
|
-
switch (command) {
|
|
489
|
-
case "cc":
|
|
490
|
-
return "This is the entry command, not a flow stage. It may initialize or resume flow state after confirmation.";
|
|
491
|
-
case "idea":
|
|
492
|
-
return "This is an ideation command, not a flow stage. It may write ideation artifacts/seeds but does not advance flow state.";
|
|
493
|
-
case "cancel":
|
|
494
|
-
return "This is a non-completion closeout utility, not a flow stage. It requires a reason and archives cancelled or abandoned work without presenting it as completed.";
|
|
495
|
-
default:
|
|
496
|
-
return "This is a utility command, not a flow stage.";
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
function utilityShimContent(harness, command, skillFolder, commandFile) {
|
|
500
|
-
const shimName = command === "cc" ? "cc" : `cc-${command}`;
|
|
501
|
-
return `---
|
|
502
|
-
name: ${shimName}
|
|
503
|
-
description: Generated shim for ${harness}. Utility command — not a flow stage.
|
|
504
|
-
source: generated-by-cclaw
|
|
505
|
-
---
|
|
506
|
-
|
|
507
|
-
# cclaw ${command}
|
|
508
|
-
|
|
509
|
-
Load and execute:
|
|
510
|
-
1. \`.cclaw/skills/${skillFolder}/SKILL.md\`
|
|
511
|
-
2. \`.cclaw/commands/${commandFile}\`
|
|
512
|
-
|
|
513
|
-
${utilityShimBehavior(command)}
|
|
514
|
-
`;
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Frontmatter `description` that triggers the skill when the user types any
|
|
518
|
-
* of the classic cclaw slash-tokens. Codex's skill matcher runs on the skill
|
|
519
|
-
* description verbatim, so we spell out every vocabulary Codex users type
|
|
520
|
-
* instead of relying on semantics.
|
|
521
|
-
*/
|
|
522
|
-
function codexSkillDescription(command) {
|
|
523
|
-
switch (command) {
|
|
524
|
-
case "cc":
|
|
525
|
-
return `Entry point for the cclaw track-aware workflow ending in ship plus auto-closeout (retro → compound → archive). Use whenever the user types \`/cc\`, \`/cclaw\`, or asks to "start the flow", "begin cclaw", "kick off the workflow", "classify this task", or wants to start/resume a non-trivial software change. No args = resume the active stage from \`.cclaw/state/flow-state.json\`. With a prompt = classify and pick a track (quick/medium/standard).`;
|
|
526
|
-
case "idea":
|
|
527
|
-
return `Read-only repo-improvement idea mode for cclaw. Use when the user types \`/cc-idea\` or asks to "scan the repo for TODOs/tech debt", "generate a backlog", "brainstorm improvement ideas", or wants a ranked list of candidate ideas before committing to a single flow. Does not mutate \`.cclaw/state/flow-state.json\`.`;
|
|
528
|
-
case "cancel":
|
|
529
|
-
return `Cancel or abandon the active cclaw run. Use when the user types \`/cc-cancel\` or asks to cancel, abandon, stop, discard, or reset an unfinished run. Requires a reason and archives with cancelled/abandoned disposition.`;
|
|
530
|
-
default:
|
|
531
|
-
return `Generated cclaw skill for ${command}.`;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Skill body for codex-kind shims. Deliberately terse — the meat lives in
|
|
536
|
-
* `.cclaw/skills/` and `.cclaw/commands/`, and Codex's progressive-disclosure
|
|
537
|
-
* model loads skill bodies lazily, so we want a pointer plus the honest
|
|
538
|
-
* harness caveat, not a duplicated contract.
|
|
539
|
-
*/
|
|
540
|
-
function codexSkillBody(command, skillFolder, commandFile) {
|
|
541
|
-
const slashToken = command === "cc" ? "/cc" : `/cc-${command}`;
|
|
542
|
-
const title = command === "cc" ? "cclaw /cc (Codex adapter)" : `cclaw ${slashToken} (Codex adapter)`;
|
|
543
|
-
const extraContractHeading = command === "cc"
|
|
544
|
-
? "If you have not already loaded the cclaw meta-skill this session, also load `.cclaw/skills/using-cclaw/SKILL.md` — it is the routing brain for stage/utility selection."
|
|
545
|
-
: "This skill is a utility entry point, not a flow stage. Do not mutate `.cclaw/state/flow-state.json` directly.";
|
|
546
|
-
const skillSlug = command === "cc" ? "cc" : `cc-${command}`;
|
|
547
|
-
return `# ${title}
|
|
548
|
-
|
|
549
|
-
You are running inside the OpenAI Codex harness. Codex has **no native
|
|
550
|
-
\`${slashToken}\` slash command** — custom prompts were deprecated in
|
|
551
|
-
Codex CLI v0.89 (Jan 2026). cclaw ships its entry points as skills
|
|
552
|
-
under \`.agents/skills/${skillSlug}/\` so the user can either:
|
|
553
|
-
|
|
554
|
-
- Type \`/use ${skillSlug}\` at the Codex prompt, or
|
|
555
|
-
- Type \`${slashToken} …\` (or describe the intent in natural language) — Codex's
|
|
556
|
-
skill matcher picks this skill up via the description frontmatter.
|
|
557
|
-
|
|
558
|
-
Lifecycle hooks **are** available in Codex CLI v0.114+ (behind the
|
|
559
|
-
\`[features] codex_hooks = true\` flag in \`~/.codex/config.toml\`) and
|
|
560
|
-
cclaw installs a matching \`.codex/hooks.json\`; run \`npx cclaw-cli sync\`
|
|
561
|
-
for the current hook surface and limitations.
|
|
562
|
-
|
|
563
|
-
## Protocol
|
|
564
|
-
|
|
565
|
-
1. Read \`.cclaw/state/flow-state.json\` first to know the active stage,
|
|
566
|
-
track, and run metadata.
|
|
567
|
-
2. Load and follow \`.cclaw/skills/${skillFolder}/SKILL.md\` as the
|
|
568
|
-
authoritative skill — its gates, artifacts, and delegations are
|
|
569
|
-
canonical.
|
|
570
|
-
3. Load \`.cclaw/commands/${commandFile}\` for the full command contract
|
|
571
|
-
(protocol, validation, post-state expectations).
|
|
572
|
-
4. ${extraContractHeading}
|
|
573
|
-
|
|
574
|
-
## Honest caveats
|
|
575
|
-
|
|
576
|
-
- Codex has native parallel subagents. cclaw writes project custom agents
|
|
577
|
-
under \`.codex/agents/*.toml\`; ask Codex to spawn the relevant cclaw
|
|
578
|
-
agent(s) by name, wait for their results, write evidence into the active
|
|
579
|
-
artifact, then append completed delegation rows with \`fulfillmentMode:
|
|
580
|
-
"isolated"\`. Use role-switch only if this Codex build has subagents
|
|
581
|
-
unavailable or disabled, and then include non-empty \`evidenceRefs\`.
|
|
582
|
-
- Codex's \`PreToolUse\` / \`PostToolUse\` hooks currently only intercept
|
|
583
|
-
the \`Bash\` tool. \`Write\`, \`Edit\`, \`WebSearch\`, and MCP tool calls
|
|
584
|
-
are **not** gated by hooks — use \`npx cclaw-cli sync\` for what cclaw
|
|
585
|
-
substitutes with in-turn agent steps for those call classes.
|
|
586
|
-
- Codex's \`SessionStart\` matcher only supports \`startup|resume\`. Claude
|
|
587
|
-
and Cursor also fire on \`clear\` and \`compact\`, so mid-session
|
|
588
|
-
context resets there re-inject cclaw's bootstrap automatically. In
|
|
589
|
-
Codex you must re-announce the active stage yourself after any
|
|
590
|
-
\`/clear\` or compaction — the skill does not reload implicitly.
|
|
591
|
-
`;
|
|
592
|
-
}
|
|
593
|
-
function codexSkillMarkdown(command, skillName, skillFolder, commandFile) {
|
|
594
|
-
const description = codexSkillDescription(command);
|
|
595
|
-
const frontmatter = [
|
|
596
|
-
"---",
|
|
597
|
-
`name: ${skillName}`,
|
|
598
|
-
`description: ${description}`,
|
|
599
|
-
"source: generated-by-cclaw",
|
|
600
|
-
"---",
|
|
601
|
-
""
|
|
602
|
-
].join("\n");
|
|
603
|
-
return `${frontmatter}${codexSkillBody(command, skillFolder, commandFile)}`;
|
|
604
|
-
}
|
|
605
|
-
async function writeCommandKindShims(commandDir, harness) {
|
|
606
|
-
await ensureDir(commandDir);
|
|
607
|
-
await writeFileSafe(path.join(commandDir, "cc.md"), utilityShimContent(harness, "cc", "flow-start", "start.md"));
|
|
608
|
-
for (const shim of UTILITY_SHIMS) {
|
|
609
|
-
await writeFileSafe(path.join(commandDir, shim.fileName), utilityShimContent(harness, shim.command, shim.skillFolder, shim.commandFile));
|
|
610
|
-
}
|
|
611
|
-
for (const legacy of LEGACY_HARNESS_SHIMS) {
|
|
612
|
-
const legacyPath = path.join(commandDir, legacy);
|
|
613
|
-
try {
|
|
614
|
-
await fs.unlink(legacyPath);
|
|
615
|
-
}
|
|
616
|
-
catch {
|
|
617
|
-
// fine — file may not exist (fresh install) or may be on read-only FS
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
async function writeSkillKindShims(commandDir) {
|
|
622
|
-
await ensureDir(commandDir);
|
|
623
|
-
await writeFileSafe(path.join(commandDir, ENTRY_SHIM_SKILL_NAME, "SKILL.md"), codexSkillMarkdown("cc", ENTRY_SHIM_SKILL_NAME, "flow-start", "start.md"));
|
|
624
|
-
for (const shim of UTILITY_SHIMS) {
|
|
625
|
-
await writeFileSafe(path.join(commandDir, shim.skillName, "SKILL.md"), codexSkillMarkdown(shim.command, shim.skillName, shim.skillFolder, shim.commandFile));
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Legacy codex surfaces cclaw wrote before that Codex CLI never
|
|
630
|
-
* consumed (`.codex/commands/*.md` had no discovery primitive). We keep
|
|
631
|
-
* removing `.codex/commands/` on every sync so upgrades from those
|
|
632
|
-
* installs leave a clean slate, but as of we DO write
|
|
633
|
-
* `.codex/hooks.json` again — Codex CLI grew a real hooks API in
|
|
634
|
-
(Mar 2026), and that file is the current, supported target.
|
|
635
|
-
*
|
|
636
|
-
* This function also removes skill folders named after the old
|
|
637
|
-
* `cclaw-cc*` scheme now that cclaw installs them
|
|
638
|
-
* as plain `cc*`. Leaving them around would make Codex list two skills
|
|
639
|
-
* for the same entry point.
|
|
640
|
-
*/
|
|
641
|
-
async function cleanupLegacyCodexSurfaces(projectRoot) {
|
|
642
|
-
const legacyCommandsDir = path.join(projectRoot, ".codex/commands");
|
|
643
|
-
try {
|
|
644
|
-
await fs.rm(legacyCommandsDir, { recursive: true, force: true });
|
|
645
|
-
}
|
|
646
|
-
catch {
|
|
647
|
-
// best-effort cleanup
|
|
648
|
-
}
|
|
649
|
-
// Remove old `cclaw-cc*` skill folders if they exist from a previous
|
|
650
|
-
// cclaw install. Idempotent; best-effort.
|
|
651
|
-
const legacySkillsRoot = path.join(projectRoot, ".agents/skills");
|
|
652
|
-
let legacySkillNames = [];
|
|
653
|
-
try {
|
|
654
|
-
legacySkillNames = (await fs.readdir(legacySkillsRoot, { withFileTypes: true }))
|
|
655
|
-
.filter((entry) => entry.isDirectory() && entry.name.startsWith(LEGACY_CODEX_SKILL_PREFIX))
|
|
656
|
-
.map((entry) => entry.name);
|
|
657
|
-
}
|
|
658
|
-
catch {
|
|
659
|
-
legacySkillNames = [];
|
|
660
|
-
}
|
|
661
|
-
for (const name of legacySkillNames) {
|
|
662
|
-
const folder = path.join(legacySkillsRoot, name);
|
|
663
|
-
try {
|
|
664
|
-
await fs.rm(folder, { recursive: true, force: true });
|
|
665
|
-
}
|
|
666
|
-
catch {
|
|
667
|
-
// best-effort
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
// If `.codex/` is now empty we drop it — happens when neither hooks
|
|
671
|
-
// are enabled nor the user has their own state there. Otherwise we
|
|
672
|
-
// leave the directory alone.
|
|
673
|
-
try {
|
|
674
|
-
const codexDir = path.join(projectRoot, ".codex");
|
|
675
|
-
const entries = await fs.readdir(codexDir);
|
|
676
|
-
if (entries.length === 0) {
|
|
677
|
-
await fs.rmdir(codexDir);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
catch {
|
|
681
|
-
// directory absent or non-empty
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
function codexAgentToml(agent) {
|
|
685
|
-
const instructions = `${agentMarkdown(agent)}\n\n${enhancedAgentInstruction(agent.name)}`.trim();
|
|
686
|
-
const sandboxMode = agent.tools.some((tool) => ["Write", "Edit", "Bash"].includes(tool))
|
|
687
|
-
? "workspace-write"
|
|
688
|
-
: "read-only";
|
|
689
|
-
return [
|
|
690
|
-
`name = ${JSON.stringify(agent.name)}`,
|
|
691
|
-
`description = ${JSON.stringify(agent.description)}`,
|
|
692
|
-
`sandbox_mode = ${JSON.stringify(sandboxMode)}`,
|
|
693
|
-
'developer_instructions = """',
|
|
694
|
-
instructions.replace(/"""/gu, '\"\"\"'),
|
|
695
|
-
'"""',
|
|
696
|
-
""
|
|
697
|
-
].join("\n");
|
|
698
|
-
}
|
|
699
|
-
function opencodeAgentMarkdown(agent) {
|
|
700
|
-
const editPermission = agent.tools.some((tool) => ["Write", "Edit"].includes(tool)) ? "ask" : "deny";
|
|
701
|
-
const bashPermission = agent.tools.includes("Bash") ? "ask" : "deny";
|
|
702
|
-
return `---
|
|
703
|
-
description: ${JSON.stringify(agent.description)}
|
|
704
|
-
mode: subagent
|
|
705
|
-
permission:
|
|
706
|
-
edit: ${editPermission}
|
|
707
|
-
bash: ${bashPermission}
|
|
708
|
-
---
|
|
709
|
-
|
|
710
|
-
${agentMarkdown(agent)}`;
|
|
711
|
-
}
|
|
712
|
-
function enhancedAgentInstruction(agentName) {
|
|
713
|
-
return `## Worker ACK Contract\n\nYou are the cclaw ${agentName} subagent. Follow the parent prompt as the task boundary. ACK first with JSON containing spanId, dispatchId or workerRunId, dispatchSurface, agentDefinitionPath, ackTs, and status: "ACK". Finish with the strict return schema plus the same spanId+dispatchId proof so the parent can append .cclaw/state/delegation-events.jsonl and .cclaw/state/delegation-log.json. Do not let the parent claim isolated completion without matching ACK/result proof. Do not recursively orchestrate other agents unless the parent explicitly asks.`;
|
|
714
|
-
}
|
|
715
|
-
async function syncAgentFiles(projectRoot, harnesses) {
|
|
716
|
-
const agents = CCLAW_AGENTS;
|
|
717
|
-
const agentsDir = path.join(projectRoot, RUNTIME_ROOT, "agents");
|
|
718
|
-
await ensureDir(agentsDir);
|
|
719
|
-
for (const agent of agents) {
|
|
720
|
-
await writeFileSafe(path.join(agentsDir, `${agent.name}.md`), agentMarkdown(agent));
|
|
721
|
-
}
|
|
722
|
-
if (harnesses.includes("opencode")) {
|
|
723
|
-
const opencodeAgentsDir = path.join(projectRoot, ".opencode/agents");
|
|
724
|
-
await ensureDir(opencodeAgentsDir);
|
|
725
|
-
for (const agent of agents) {
|
|
726
|
-
await writeFileSafe(path.join(opencodeAgentsDir, `${agent.name}.md`), opencodeAgentMarkdown(agent));
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
if (harnesses.includes("codex")) {
|
|
730
|
-
const codexAgentsDir = path.join(projectRoot, ".codex/agents");
|
|
731
|
-
await ensureDir(codexAgentsDir);
|
|
732
|
-
for (const agent of agents) {
|
|
733
|
-
await writeFileSafe(path.join(codexAgentsDir, `${agent.name}.toml`), codexAgentToml(agent));
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
export async function syncHarnessShims(projectRoot, harnesses) {
|
|
738
|
-
// Legacy codex cleanup is unconditional — even installs that never enabled
|
|
739
|
-
// codex but previously did will see stale `.codex/commands/*.md` and
|
|
740
|
-
// `.codex/hooks.json` get removed on upgrade.
|
|
741
|
-
await cleanupLegacyCodexSurfaces(projectRoot);
|
|
742
|
-
for (const harness of harnesses) {
|
|
743
|
-
const adapter = HARNESS_ADAPTERS[harness];
|
|
744
|
-
if (!adapter)
|
|
745
|
-
continue;
|
|
746
|
-
const commandDir = path.join(projectRoot, adapter.commandDir);
|
|
747
|
-
if (adapter.shimKind === "skill") {
|
|
748
|
-
await writeSkillKindShims(commandDir);
|
|
749
|
-
}
|
|
750
|
-
else {
|
|
751
|
-
await writeCommandKindShims(commandDir, harness);
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
await syncAgentFiles(projectRoot, harnesses);
|
|
755
|
-
await syncAgentsMd(projectRoot, harnesses);
|
|
756
|
-
}
|