cclaw-cli 7.7.1 → 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.
Files changed (282) hide show
  1. package/README.md +210 -134
  2. package/dist/artifact-frontmatter.d.ts +51 -0
  3. package/dist/artifact-frontmatter.js +131 -0
  4. package/dist/artifact-paths.d.ts +7 -27
  5. package/dist/artifact-paths.js +20 -249
  6. package/dist/cancel.d.ts +16 -0
  7. package/dist/cancel.js +66 -0
  8. package/dist/cli.d.ts +2 -27
  9. package/dist/cli.js +90 -508
  10. package/dist/compound.d.ts +26 -0
  11. package/dist/compound.js +96 -0
  12. package/dist/config.d.ts +14 -51
  13. package/dist/config.js +23 -359
  14. package/dist/constants.d.ts +11 -18
  15. package/dist/constants.js +19 -106
  16. package/dist/content/antipatterns.d.ts +1 -0
  17. package/dist/content/antipatterns.js +109 -0
  18. package/dist/content/artifact-templates.d.ts +10 -0
  19. package/dist/content/artifact-templates.js +550 -0
  20. package/dist/content/cancel-command.d.ts +2 -2
  21. package/dist/content/cancel-command.js +25 -17
  22. package/dist/content/core-agents.d.ts +9 -233
  23. package/dist/content/core-agents.js +39 -768
  24. package/dist/content/decision-protocol.d.ts +1 -12
  25. package/dist/content/decision-protocol.js +27 -20
  26. package/dist/content/examples.d.ts +8 -42
  27. package/dist/content/examples.js +293 -425
  28. package/dist/content/idea-command.d.ts +2 -0
  29. package/dist/content/idea-command.js +38 -0
  30. package/dist/content/iron-laws.d.ts +4 -138
  31. package/dist/content/iron-laws.js +18 -197
  32. package/dist/content/meta-skill.d.ts +1 -3
  33. package/dist/content/meta-skill.js +57 -134
  34. package/dist/content/node-hooks.d.ts +12 -8
  35. package/dist/content/node-hooks.js +188 -838
  36. package/dist/content/recovery.d.ts +8 -0
  37. package/dist/content/recovery.js +179 -0
  38. package/dist/content/reference-patterns.d.ts +4 -13
  39. package/dist/content/reference-patterns.js +260 -389
  40. package/dist/content/research-playbooks.d.ts +8 -8
  41. package/dist/content/research-playbooks.js +108 -121
  42. package/dist/content/review-loop.d.ts +6 -192
  43. package/dist/content/review-loop.js +29 -731
  44. package/dist/content/skills.d.ts +8 -38
  45. package/dist/content/skills.js +681 -732
  46. package/dist/content/specialist-prompts/architect.d.ts +1 -0
  47. package/dist/content/specialist-prompts/architect.js +225 -0
  48. package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
  49. package/dist/content/specialist-prompts/brainstormer.js +168 -0
  50. package/dist/content/specialist-prompts/index.d.ts +2 -0
  51. package/dist/content/specialist-prompts/index.js +14 -0
  52. package/dist/content/specialist-prompts/planner.d.ts +1 -0
  53. package/dist/content/specialist-prompts/planner.js +182 -0
  54. package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
  55. package/dist/content/specialist-prompts/reviewer.js +193 -0
  56. package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
  57. package/dist/content/specialist-prompts/security-reviewer.js +133 -0
  58. package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
  59. package/dist/content/specialist-prompts/slice-builder.js +232 -0
  60. package/dist/content/stage-playbooks.d.ts +8 -0
  61. package/dist/content/stage-playbooks.js +404 -0
  62. package/dist/content/start-command.d.ts +2 -12
  63. package/dist/content/start-command.js +221 -207
  64. package/dist/flow-state.d.ts +21 -178
  65. package/dist/flow-state.js +67 -170
  66. package/dist/fs-utils.d.ts +6 -26
  67. package/dist/fs-utils.js +29 -162
  68. package/dist/gitignore.d.ts +2 -1
  69. package/dist/gitignore.js +51 -34
  70. package/dist/harness-detect.d.ts +10 -0
  71. package/dist/harness-detect.js +29 -0
  72. package/dist/install.d.ts +27 -15
  73. package/dist/install.js +230 -1342
  74. package/dist/knowledge-store.d.ts +19 -163
  75. package/dist/knowledge-store.js +56 -590
  76. package/dist/logger.d.ts +8 -3
  77. package/dist/logger.js +13 -4
  78. package/dist/orchestrator-routing.d.ts +29 -0
  79. package/dist/orchestrator-routing.js +156 -0
  80. package/dist/run-persistence.d.ts +7 -118
  81. package/dist/run-persistence.js +29 -845
  82. package/dist/runtime/run-hook.entry.d.ts +1 -3
  83. package/dist/runtime/run-hook.entry.js +19 -4
  84. package/dist/runtime/run-hook.mjs +13 -1024
  85. package/dist/types.d.ts +25 -261
  86. package/dist/types.js +8 -36
  87. package/package.json +6 -3
  88. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  89. package/dist/artifact-linter/brainstorm.js +0 -353
  90. package/dist/artifact-linter/design.d.ts +0 -18
  91. package/dist/artifact-linter/design.js +0 -444
  92. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  93. package/dist/artifact-linter/findings-dedup.js +0 -232
  94. package/dist/artifact-linter/plan.d.ts +0 -2
  95. package/dist/artifact-linter/plan.js +0 -826
  96. package/dist/artifact-linter/review-army.d.ts +0 -49
  97. package/dist/artifact-linter/review-army.js +0 -520
  98. package/dist/artifact-linter/review.d.ts +0 -2
  99. package/dist/artifact-linter/review.js +0 -113
  100. package/dist/artifact-linter/scope.d.ts +0 -2
  101. package/dist/artifact-linter/scope.js +0 -158
  102. package/dist/artifact-linter/shared.d.ts +0 -637
  103. package/dist/artifact-linter/shared.js +0 -2163
  104. package/dist/artifact-linter/ship.d.ts +0 -2
  105. package/dist/artifact-linter/ship.js +0 -250
  106. package/dist/artifact-linter/spec.d.ts +0 -2
  107. package/dist/artifact-linter/spec.js +0 -176
  108. package/dist/artifact-linter/tdd.d.ts +0 -118
  109. package/dist/artifact-linter/tdd.js +0 -1404
  110. package/dist/artifact-linter.d.ts +0 -15
  111. package/dist/artifact-linter.js +0 -517
  112. package/dist/codex-feature-flag.d.ts +0 -58
  113. package/dist/codex-feature-flag.js +0 -193
  114. package/dist/content/closeout-guidance.d.ts +0 -14
  115. package/dist/content/closeout-guidance.js +0 -44
  116. package/dist/content/diff-command.d.ts +0 -1
  117. package/dist/content/diff-command.js +0 -43
  118. package/dist/content/harness-doc.d.ts +0 -1
  119. package/dist/content/harness-doc.js +0 -65
  120. package/dist/content/hook-events.d.ts +0 -9
  121. package/dist/content/hook-events.js +0 -23
  122. package/dist/content/hook-manifest.d.ts +0 -81
  123. package/dist/content/hook-manifest.js +0 -156
  124. package/dist/content/hooks.d.ts +0 -11
  125. package/dist/content/hooks.js +0 -1972
  126. package/dist/content/idea.d.ts +0 -60
  127. package/dist/content/idea.js +0 -416
  128. package/dist/content/language-policy.d.ts +0 -2
  129. package/dist/content/language-policy.js +0 -13
  130. package/dist/content/learnings.d.ts +0 -6
  131. package/dist/content/learnings.js +0 -141
  132. package/dist/content/observe.d.ts +0 -19
  133. package/dist/content/observe.js +0 -86
  134. package/dist/content/opencode-plugin.d.ts +0 -1
  135. package/dist/content/opencode-plugin.js +0 -635
  136. package/dist/content/review-prompts.d.ts +0 -1
  137. package/dist/content/review-prompts.js +0 -104
  138. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  139. package/dist/content/runtime-shared-snippets.js +0 -80
  140. package/dist/content/session-hooks.d.ts +0 -7
  141. package/dist/content/session-hooks.js +0 -107
  142. package/dist/content/skills-elicitation.d.ts +0 -1
  143. package/dist/content/skills-elicitation.js +0 -167
  144. package/dist/content/stage-command.d.ts +0 -2
  145. package/dist/content/stage-command.js +0 -17
  146. package/dist/content/stage-schema.d.ts +0 -117
  147. package/dist/content/stage-schema.js +0 -955
  148. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  149. package/dist/content/stages/_lint-metadata/index.js +0 -97
  150. package/dist/content/stages/brainstorm.d.ts +0 -2
  151. package/dist/content/stages/brainstorm.js +0 -184
  152. package/dist/content/stages/design.d.ts +0 -2
  153. package/dist/content/stages/design.js +0 -288
  154. package/dist/content/stages/index.d.ts +0 -8
  155. package/dist/content/stages/index.js +0 -11
  156. package/dist/content/stages/plan.d.ts +0 -2
  157. package/dist/content/stages/plan.js +0 -191
  158. package/dist/content/stages/review.d.ts +0 -2
  159. package/dist/content/stages/review.js +0 -240
  160. package/dist/content/stages/schema-types.d.ts +0 -203
  161. package/dist/content/stages/schema-types.js +0 -1
  162. package/dist/content/stages/scope.d.ts +0 -2
  163. package/dist/content/stages/scope.js +0 -254
  164. package/dist/content/stages/ship.d.ts +0 -2
  165. package/dist/content/stages/ship.js +0 -159
  166. package/dist/content/stages/spec.d.ts +0 -2
  167. package/dist/content/stages/spec.js +0 -170
  168. package/dist/content/stages/tdd.d.ts +0 -4
  169. package/dist/content/stages/tdd.js +0 -273
  170. package/dist/content/state-contracts.d.ts +0 -1
  171. package/dist/content/state-contracts.js +0 -63
  172. package/dist/content/status-command.d.ts +0 -4
  173. package/dist/content/status-command.js +0 -109
  174. package/dist/content/subagent-context-skills.d.ts +0 -4
  175. package/dist/content/subagent-context-skills.js +0 -279
  176. package/dist/content/subagents.d.ts +0 -3
  177. package/dist/content/subagents.js +0 -997
  178. package/dist/content/templates.d.ts +0 -26
  179. package/dist/content/templates.js +0 -1692
  180. package/dist/content/track-render-context.d.ts +0 -18
  181. package/dist/content/track-render-context.js +0 -53
  182. package/dist/content/tree-command.d.ts +0 -1
  183. package/dist/content/tree-command.js +0 -64
  184. package/dist/content/utility-skills.d.ts +0 -30
  185. package/dist/content/utility-skills.js +0 -160
  186. package/dist/content/view-command.d.ts +0 -2
  187. package/dist/content/view-command.js +0 -92
  188. package/dist/delegation.d.ts +0 -649
  189. package/dist/delegation.js +0 -1539
  190. package/dist/early-loop.d.ts +0 -70
  191. package/dist/early-loop.js +0 -302
  192. package/dist/execution-topology.d.ts +0 -44
  193. package/dist/execution-topology.js +0 -95
  194. package/dist/gate-evidence.d.ts +0 -85
  195. package/dist/gate-evidence.js +0 -631
  196. package/dist/harness-adapters.d.ts +0 -151
  197. package/dist/harness-adapters.js +0 -756
  198. package/dist/harness-selection.d.ts +0 -31
  199. package/dist/harness-selection.js +0 -214
  200. package/dist/hook-schema.d.ts +0 -6
  201. package/dist/hook-schema.js +0 -114
  202. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  203. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  204. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  205. package/dist/init-detect.d.ts +0 -2
  206. package/dist/init-detect.js +0 -50
  207. package/dist/internal/advance-stage/advance.d.ts +0 -89
  208. package/dist/internal/advance-stage/advance.js +0 -655
  209. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  210. package/dist/internal/advance-stage/cancel-run.js +0 -19
  211. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  212. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  213. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  214. package/dist/internal/advance-stage/helpers.js +0 -145
  215. package/dist/internal/advance-stage/hook.d.ts +0 -8
  216. package/dist/internal/advance-stage/hook.js +0 -40
  217. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  218. package/dist/internal/advance-stage/parsers.js +0 -357
  219. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  220. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  221. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  222. package/dist/internal/advance-stage/review-loop.js +0 -199
  223. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  224. package/dist/internal/advance-stage/rewind.js +0 -108
  225. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  226. package/dist/internal/advance-stage/start-flow.js +0 -241
  227. package/dist/internal/advance-stage/verify.d.ts +0 -21
  228. package/dist/internal/advance-stage/verify.js +0 -185
  229. package/dist/internal/advance-stage.d.ts +0 -7
  230. package/dist/internal/advance-stage.js +0 -138
  231. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  232. package/dist/internal/cohesion-contract-stub.js +0 -148
  233. package/dist/internal/compound-readiness.d.ts +0 -23
  234. package/dist/internal/compound-readiness.js +0 -102
  235. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  236. package/dist/internal/detect-public-api-changes.js +0 -45
  237. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  238. package/dist/internal/detect-supply-chain-changes.js +0 -138
  239. package/dist/internal/early-loop-status.d.ts +0 -7
  240. package/dist/internal/early-loop-status.js +0 -93
  241. package/dist/internal/envelope-validate.d.ts +0 -7
  242. package/dist/internal/envelope-validate.js +0 -66
  243. package/dist/internal/flow-state-repair.d.ts +0 -20
  244. package/dist/internal/flow-state-repair.js +0 -104
  245. package/dist/internal/plan-split-waves.d.ts +0 -190
  246. package/dist/internal/plan-split-waves.js +0 -764
  247. package/dist/internal/runtime-integrity.d.ts +0 -7
  248. package/dist/internal/runtime-integrity.js +0 -268
  249. package/dist/internal/slice-commit.d.ts +0 -7
  250. package/dist/internal/slice-commit.js +0 -619
  251. package/dist/internal/tdd-loop-status.d.ts +0 -14
  252. package/dist/internal/tdd-loop-status.js +0 -68
  253. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  254. package/dist/internal/tdd-red-evidence.js +0 -153
  255. package/dist/internal/waiver-grant.d.ts +0 -62
  256. package/dist/internal/waiver-grant.js +0 -294
  257. package/dist/internal/wave-status.d.ts +0 -74
  258. package/dist/internal/wave-status.js +0 -506
  259. package/dist/managed-resources.d.ts +0 -53
  260. package/dist/managed-resources.js +0 -313
  261. package/dist/policy.d.ts +0 -10
  262. package/dist/policy.js +0 -167
  263. package/dist/retro-gate.d.ts +0 -9
  264. package/dist/retro-gate.js +0 -47
  265. package/dist/run-archive.d.ts +0 -61
  266. package/dist/run-archive.js +0 -391
  267. package/dist/runs.d.ts +0 -2
  268. package/dist/runs.js +0 -2
  269. package/dist/stack-detection.d.ts +0 -116
  270. package/dist/stack-detection.js +0 -489
  271. package/dist/streaming/event-stream.d.ts +0 -31
  272. package/dist/streaming/event-stream.js +0 -114
  273. package/dist/tdd-cycle.d.ts +0 -107
  274. package/dist/tdd-cycle.js +0 -289
  275. package/dist/tdd-verification-evidence.d.ts +0 -17
  276. package/dist/tdd-verification-evidence.js +0 -122
  277. package/dist/track-heuristics.d.ts +0 -27
  278. package/dist/track-heuristics.js +0 -154
  279. package/dist/util/slice-id.d.ts +0 -58
  280. package/dist/util/slice-id.js +0 -89
  281. package/dist/worktree-manager.d.ts +0 -20
  282. package/dist/worktree-manager.js +0 -108
@@ -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
- }