cclaw-cli 7.7.1 → 8.1.1

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