@bastani/atomic 0.8.26-alpha.1 → 0.8.26-alpha.10

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 (303) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +5 -5
  3. package/dist/builtin/intercom/CHANGELOG.md +54 -0
  4. package/dist/builtin/intercom/package.json +2 -2
  5. package/dist/builtin/mcp/CHANGELOG.md +54 -0
  6. package/dist/builtin/mcp/package.json +3 -3
  7. package/dist/builtin/subagents/CHANGELOG.md +55 -0
  8. package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
  9. package/dist/builtin/subagents/agents/debugger.md +6 -6
  10. package/dist/builtin/subagents/package.json +4 -4
  11. package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
  12. package/dist/builtin/subagents/skills/browser/EXAMPLES.md +151 -0
  13. package/dist/builtin/subagents/skills/browser/LICENSE.txt +21 -0
  14. package/dist/builtin/subagents/skills/browser/REFERENCE.md +451 -0
  15. package/dist/builtin/subagents/skills/browser/SKILL.md +170 -0
  16. package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
  17. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +55 -12
  18. package/dist/builtin/subagents/src/runs/foreground/execution.ts +71 -12
  19. package/dist/builtin/subagents/src/runs/shared/acceptance.ts +2 -1
  20. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +34 -0
  21. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +416 -7
  22. package/dist/builtin/subagents/src/runs/shared/worktree.ts +2 -2
  23. package/dist/builtin/web-access/CHANGELOG.md +54 -0
  24. package/dist/builtin/web-access/package.json +2 -2
  25. package/dist/builtin/workflows/CHANGELOG.md +66 -0
  26. package/dist/builtin/workflows/README.md +10 -8
  27. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +11 -8
  28. package/dist/builtin/workflows/builtin/goal.ts +137 -109
  29. package/dist/builtin/workflows/builtin/index.d.ts +2 -0
  30. package/dist/builtin/workflows/builtin/open-claude-design.ts +228 -151
  31. package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
  32. package/dist/builtin/workflows/builtin/ralph.ts +452 -279
  33. package/dist/builtin/workflows/package.json +2 -2
  34. package/dist/builtin/workflows/skills/create-spec/SKILL.md +14 -0
  35. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +29 -10
  36. package/dist/builtin/workflows/src/extension/index.ts +10 -2
  37. package/dist/builtin/workflows/src/extension/runtime.ts +35 -3
  38. package/dist/builtin/workflows/src/extension/wiring.ts +13 -1
  39. package/dist/builtin/workflows/src/runs/background/status.ts +52 -6
  40. package/dist/builtin/workflows/src/runs/foreground/executor.ts +453 -21
  41. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +77 -11
  42. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +402 -8
  43. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -2
  44. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +2 -2
  45. package/dist/builtin/workflows/src/shared/persistence-restore.ts +182 -6
  46. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +76 -6
  47. package/dist/builtin/workflows/src/shared/stage-prompt.ts +33 -2
  48. package/dist/builtin/workflows/src/shared/store-types.ts +31 -0
  49. package/dist/builtin/workflows/src/shared/store.ts +160 -18
  50. package/dist/builtin/workflows/src/shared/types.ts +3 -3
  51. package/dist/builtin/workflows/src/shared/workflow-failures.ts +758 -132
  52. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +39 -3
  53. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +74 -74
  54. package/dist/core/agent-session.d.ts +33 -6
  55. package/dist/core/agent-session.d.ts.map +1 -1
  56. package/dist/core/agent-session.js +157 -182
  57. package/dist/core/agent-session.js.map +1 -1
  58. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  59. package/dist/core/atomic-guide-command.js +11 -9
  60. package/dist/core/atomic-guide-command.js.map +1 -1
  61. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  62. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  63. package/dist/core/compaction/branch-summarization.js +6 -3
  64. package/dist/core/compaction/branch-summarization.js.map +1 -1
  65. package/dist/core/compaction/compaction.d.ts.map +1 -1
  66. package/dist/core/compaction/compaction.js +23 -10
  67. package/dist/core/compaction/compaction.js.map +1 -1
  68. package/dist/core/compaction/context-compaction.d.ts +175 -0
  69. package/dist/core/compaction/context-compaction.d.ts.map +1 -0
  70. package/dist/core/compaction/context-compaction.js +1636 -0
  71. package/dist/core/compaction/context-compaction.js.map +1 -0
  72. package/dist/core/compaction/index.d.ts +1 -0
  73. package/dist/core/compaction/index.d.ts.map +1 -1
  74. package/dist/core/compaction/index.js +1 -0
  75. package/dist/core/compaction/index.js.map +1 -1
  76. package/dist/core/extensions/types.d.ts +3 -2
  77. package/dist/core/extensions/types.d.ts.map +1 -1
  78. package/dist/core/extensions/types.js.map +1 -1
  79. package/dist/core/footer-data-provider.d.ts.map +1 -1
  80. package/dist/core/footer-data-provider.js +3 -0
  81. package/dist/core/footer-data-provider.js.map +1 -1
  82. package/dist/core/index.d.ts +1 -1
  83. package/dist/core/index.d.ts.map +1 -1
  84. package/dist/core/index.js.map +1 -1
  85. package/dist/core/package-manager.d.ts.map +1 -1
  86. package/dist/core/package-manager.js +14 -7
  87. package/dist/core/package-manager.js.map +1 -1
  88. package/dist/core/session-manager.d.ts +41 -1
  89. package/dist/core/session-manager.d.ts.map +1 -1
  90. package/dist/core/session-manager.js +146 -7
  91. package/dist/core/session-manager.js.map +1 -1
  92. package/dist/core/slash-commands.d.ts.map +1 -1
  93. package/dist/core/slash-commands.js +1 -1
  94. package/dist/core/slash-commands.js.map +1 -1
  95. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts +5 -5
  96. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  97. package/dist/core/tools/ask-user-question/tool/format-answer.js +5 -5
  98. package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
  99. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +16 -3
  100. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  101. package/dist/core/tools/ask-user-question/tool/response-envelope.js +21 -3
  102. package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
  103. package/dist/index.d.ts +4 -3
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +3 -2
  106. package/dist/index.js.map +1 -1
  107. package/dist/modes/index.d.ts +1 -1
  108. package/dist/modes/index.d.ts.map +1 -1
  109. package/dist/modes/index.js.map +1 -1
  110. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/chat-session-host.js +17 -0
  112. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  113. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +17 -0
  114. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +1 -0
  115. package/dist/modes/interactive/components/context-compaction-summary-message.js +83 -0
  116. package/dist/modes/interactive/components/context-compaction-summary-message.js.map +1 -0
  117. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/footer.js +4 -1
  119. package/dist/modes/interactive/components/footer.js.map +1 -1
  120. package/dist/modes/interactive/components/index.d.ts +1 -0
  121. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/index.js +1 -0
  123. package/dist/modes/interactive/components/index.js.map +1 -1
  124. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  125. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  126. package/dist/modes/interactive/interactive-mode.js +75 -10
  127. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  128. package/dist/modes/rpc/rpc-client.d.ts +13 -8
  129. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  130. package/dist/modes/rpc/rpc-client.js +8 -1
  131. package/dist/modes/rpc/rpc-client.js.map +1 -1
  132. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  133. package/dist/modes/rpc/rpc-mode.js +4 -0
  134. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  135. package/dist/modes/rpc/rpc-types.d.ts +14 -3
  136. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  137. package/dist/modes/rpc/rpc-types.js.map +1 -1
  138. package/dist/utils/git-env.d.ts +10 -0
  139. package/dist/utils/git-env.d.ts.map +1 -0
  140. package/dist/utils/git-env.js +33 -0
  141. package/dist/utils/git-env.js.map +1 -0
  142. package/docs/compaction.md +185 -50
  143. package/docs/custom-provider.md +11 -9
  144. package/docs/extensions.md +46 -42
  145. package/docs/index.md +13 -6
  146. package/docs/json.md +15 -12
  147. package/docs/packages.md +2 -0
  148. package/docs/providers.md +4 -1
  149. package/docs/quickstart.md +18 -11
  150. package/docs/rpc.md +38 -23
  151. package/docs/sdk.md +17 -8
  152. package/docs/session-format.md +26 -13
  153. package/docs/sessions.md +3 -3
  154. package/docs/settings.md +2 -2
  155. package/docs/skills.md +1 -15
  156. package/docs/termux.md +9 -10
  157. package/docs/themes.md +2 -2
  158. package/docs/tmux.md +3 -3
  159. package/docs/tui.md +19 -32
  160. package/docs/usage.md +2 -2
  161. package/docs/workflows.md +60 -16
  162. package/package.json +6 -12
  163. package/dist/builtin/subagents/skills/browser-use/SKILL.md +0 -234
  164. package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +0 -76
  165. package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +0 -92
  166. package/node_modules/@earendil-works/pi-tui/README.md +0 -779
  167. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts +0 -54
  168. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts.map +0 -1
  169. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +0 -632
  170. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js.map +0 -1
  171. package/node_modules/@earendil-works/pi-tui/dist/components/box.d.ts +0 -22
  172. package/node_modules/@earendil-works/pi-tui/dist/components/box.d.ts.map +0 -1
  173. package/node_modules/@earendil-works/pi-tui/dist/components/box.js +0 -104
  174. package/node_modules/@earendil-works/pi-tui/dist/components/box.js.map +0 -1
  175. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.d.ts +0 -22
  176. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.d.ts.map +0 -1
  177. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.js +0 -35
  178. package/node_modules/@earendil-works/pi-tui/dist/components/cancellable-loader.js.map +0 -1
  179. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +0 -249
  180. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +0 -1
  181. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +0 -1857
  182. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +0 -1
  183. package/node_modules/@earendil-works/pi-tui/dist/components/image.d.ts +0 -28
  184. package/node_modules/@earendil-works/pi-tui/dist/components/image.d.ts.map +0 -1
  185. package/node_modules/@earendil-works/pi-tui/dist/components/image.js +0 -89
  186. package/node_modules/@earendil-works/pi-tui/dist/components/image.js.map +0 -1
  187. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts +0 -37
  188. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +0 -1
  189. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +0 -378
  190. package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +0 -1
  191. package/node_modules/@earendil-works/pi-tui/dist/components/loader.d.ts +0 -31
  192. package/node_modules/@earendil-works/pi-tui/dist/components/loader.d.ts.map +0 -1
  193. package/node_modules/@earendil-works/pi-tui/dist/components/loader.js +0 -69
  194. package/node_modules/@earendil-works/pi-tui/dist/components/loader.js.map +0 -1
  195. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +0 -96
  196. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +0 -1
  197. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +0 -644
  198. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +0 -1
  199. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.d.ts +0 -50
  200. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.d.ts.map +0 -1
  201. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.js +0 -159
  202. package/node_modules/@earendil-works/pi-tui/dist/components/select-list.js.map +0 -1
  203. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.d.ts +0 -50
  204. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.d.ts.map +0 -1
  205. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.js +0 -185
  206. package/node_modules/@earendil-works/pi-tui/dist/components/settings-list.js.map +0 -1
  207. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.d.ts +0 -12
  208. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.d.ts.map +0 -1
  209. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.js +0 -23
  210. package/node_modules/@earendil-works/pi-tui/dist/components/spacer.js.map +0 -1
  211. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts +0 -19
  212. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts.map +0 -1
  213. package/node_modules/@earendil-works/pi-tui/dist/components/text.js +0 -89
  214. package/node_modules/@earendil-works/pi-tui/dist/components/text.js.map +0 -1
  215. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.d.ts +0 -13
  216. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.d.ts.map +0 -1
  217. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.js +0 -51
  218. package/node_modules/@earendil-works/pi-tui/dist/components/truncated-text.js.map +0 -1
  219. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +0 -39
  220. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +0 -1
  221. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js +0 -2
  222. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +0 -1
  223. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts +0 -16
  224. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts.map +0 -1
  225. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +0 -110
  226. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js.map +0 -1
  227. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +0 -23
  228. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +0 -1
  229. package/node_modules/@earendil-works/pi-tui/dist/index.js +0 -32
  230. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +0 -1
  231. package/node_modules/@earendil-works/pi-tui/dist/keybindings.d.ts +0 -193
  232. package/node_modules/@earendil-works/pi-tui/dist/keybindings.d.ts.map +0 -1
  233. package/node_modules/@earendil-works/pi-tui/dist/keybindings.js +0 -174
  234. package/node_modules/@earendil-works/pi-tui/dist/keybindings.js.map +0 -1
  235. package/node_modules/@earendil-works/pi-tui/dist/keys.d.ts +0 -184
  236. package/node_modules/@earendil-works/pi-tui/dist/keys.d.ts.map +0 -1
  237. package/node_modules/@earendil-works/pi-tui/dist/keys.js +0 -1173
  238. package/node_modules/@earendil-works/pi-tui/dist/keys.js.map +0 -1
  239. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.d.ts +0 -28
  240. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.d.ts.map +0 -1
  241. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.js +0 -44
  242. package/node_modules/@earendil-works/pi-tui/dist/kill-ring.js.map +0 -1
  243. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts +0 -3
  244. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.d.ts.map +0 -1
  245. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +0 -53
  246. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js.map +0 -1
  247. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.d.ts +0 -50
  248. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.d.ts.map +0 -1
  249. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.js +0 -361
  250. package/node_modules/@earendil-works/pi-tui/dist/stdin-buffer.js.map +0 -1
  251. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +0 -90
  252. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +0 -1
  253. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +0 -366
  254. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +0 -1
  255. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +0 -113
  256. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +0 -1
  257. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +0 -472
  258. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +0 -1
  259. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +0 -227
  260. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +0 -1
  261. package/node_modules/@earendil-works/pi-tui/dist/tui.js +0 -1106
  262. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +0 -1
  263. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.d.ts +0 -17
  264. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.d.ts.map +0 -1
  265. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.js +0 -25
  266. package/node_modules/@earendil-works/pi-tui/dist/undo-stack.js.map +0 -1
  267. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +0 -84
  268. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +0 -1
  269. package/node_modules/@earendil-works/pi-tui/dist/utils.js +0 -1029
  270. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +0 -1
  271. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +0 -25
  272. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +0 -1
  273. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +0 -96
  274. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +0 -1
  275. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  276. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  277. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  278. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  279. package/node_modules/@earendil-works/pi-tui/package.json +0 -47
  280. package/node_modules/get-east-asian-width/index.d.ts +0 -60
  281. package/node_modules/get-east-asian-width/index.js +0 -30
  282. package/node_modules/get-east-asian-width/license +0 -9
  283. package/node_modules/get-east-asian-width/lookup-data.js +0 -21
  284. package/node_modules/get-east-asian-width/lookup.js +0 -138
  285. package/node_modules/get-east-asian-width/package.json +0 -71
  286. package/node_modules/get-east-asian-width/readme.md +0 -65
  287. package/node_modules/get-east-asian-width/utilities.js +0 -24
  288. package/node_modules/marked/LICENSE.md +0 -44
  289. package/node_modules/marked/README.md +0 -106
  290. package/node_modules/marked/bin/main.js +0 -282
  291. package/node_modules/marked/bin/marked.js +0 -15
  292. package/node_modules/marked/lib/marked.cjs +0 -2211
  293. package/node_modules/marked/lib/marked.cjs.map +0 -7
  294. package/node_modules/marked/lib/marked.d.cts +0 -728
  295. package/node_modules/marked/lib/marked.d.ts +0 -728
  296. package/node_modules/marked/lib/marked.esm.js +0 -2189
  297. package/node_modules/marked/lib/marked.esm.js.map +0 -7
  298. package/node_modules/marked/lib/marked.umd.js +0 -2213
  299. package/node_modules/marked/lib/marked.umd.js.map +0 -7
  300. package/node_modules/marked/man/marked.1 +0 -111
  301. package/node_modules/marked/man/marked.1.md +0 -92
  302. package/node_modules/marked/marked.min.js +0 -69
  303. package/node_modules/marked/package.json +0 -111
@@ -158,78 +158,255 @@ const PLANNER_RFC_TEMPLATE = `
158
158
 
159
159
  | Document Metadata | Details |
160
160
  | ---------------------- | ------------------------------------------------------------------------------ |
161
- | Author(s) | !\`git config user.name\` |
161
+ | Author(s) | Run \`git config user.name\` and insert the result. |
162
162
  | Status | Draft (WIP) / In Review (RFC) / Approved / Implemented / Deprecated / Rejected |
163
163
  | Team / Owner | |
164
164
  | Created / Last Updated | |
165
165
 
166
166
  ## 1. Executive Summary
167
167
 
168
+ _Instruction: A "TL;DR" of the document. Assume the reader is a VP or an engineer from another team who has 2 minutes. Summarize the Context (Problem), the Solution (Proposal), and the Impact (Value). Name the one or two **doors** at the heart of the change. Keep it under 200 words._
169
+
170
+ > **Example:** This RFC proposes replacing our current nightly batch billing system with an event-driven architecture. Currently, billing delays cause a 5% increase in customer support tickets. The proposed solution introduces two money doors — \`authorize_charge\` (reversible hold) and \`settle_payment\` (irreversible capture) — as the single chokepoint for outbound money, reducing billing latency from 24 hours to <5 minutes while making double-charges structurally impossible.
171
+
168
172
  ## 2. Context and Motivation
169
173
 
174
+ _Instruction: Why are we doing this? Why now? Link to the Product Requirement Document (PRD) and cite the relevant \`research/\` documents._
175
+
170
176
  ### 2.1 Current State
171
177
 
178
+ _Instruction: Describe the existing architecture. Use a "Context Diagram" if possible. Be honest about the flaws — including which existing doors **leak** (named for tools, dishonest compression, scattered danger)._
179
+
180
+ - **Architecture:** Currently, Service A communicates with Service B via a shared SQL database.
181
+ - **Limitations:** This creates a tight coupling; when Service A locks the table, Service B times out.
182
+ - **Leaking doors (today):** e.g. \`chargeCard(token, cents)\` is reachable from checkout, the retry job, *and* the admin panel — no one owns "charge exactly once." \`processPayment(...) -> bool\` collapses a declined card, a network failure, and a duplicate submission into the same \`false\`.
183
+
172
184
  ### 2.2 The Problem
173
185
 
186
+ _Instruction: What is the specific pain point?_
187
+
188
+ - **User Impact:** Customers cannot download receipts during the nightly batch window.
189
+ - **Business Impact:** We are losing $X/month in churn due to billing errors.
190
+ - **Technical Debt:** Danger is scattered; the boundary is misplaced, with defensive code deep inside the core instead of at the door.
191
+
174
192
  ## 3. Goals and Non-Goals
175
193
 
194
+ _Instruction: This is the contract / Definition of Success. Be precise._
195
+
176
196
  ### 3.1 Functional Goals
177
197
 
198
+ - [ ] Users must be able to export data in CSV format.
199
+ - [ ] System must support multi-tenant data isolation.
200
+
178
201
  ### 3.2 Non-Goals (Out of Scope)
179
202
 
203
+ _Instruction: Explicitly state what you are NOT doing. Remember: **intent lives in what the door refuses** — the doors you deliberately do not build are as much a statement of purpose as the ones you do. This prevents scope creep._
204
+
205
+ - [ ] We will NOT support PDF export in this version (CSV only).
206
+ - [ ] We will NOT migrate data older than 3 years.
207
+ - [ ] We will NOT expose a second path to move money; \`settle_payment\` remains the only chokepoint.
208
+
180
209
  ## 4. Proposed Solution (High-Level Design)
181
210
 
211
+ _Instruction: The "Big Picture." Diagrams are mandatory here._
212
+
182
213
  ### 4.1 System Architecture Diagram
183
214
 
184
- Include a Mermaid system architecture diagram grounded in the actual components this work touches.
215
+ _Instruction: Insert a C4 System Context or Container diagram. Show the "Black Boxes" and mark where the **airlock** sits (the single edge where untrusted network becomes a trusted request)._
216
+
217
+ \`\`\`mermaid
218
+ %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#f8f9fa','primaryTextColor':'#2c3e50','primaryBorderColor':'#4a5568','lineColor':'#4a90e2','secondaryColor':'#ffffff','tertiaryColor':'#e9ecef','clusterBkg':'#ffffff','clusterBorder':'#cbd5e0'}}}%%
219
+ flowchart TB
220
+ classDef person fill:#5a67d8,stroke:#4c51bf,stroke-width:3px,color:#fff,font-weight:600
221
+ classDef core fill:#4a90e2,stroke:#357abd,stroke-width:2.5px,color:#fff,font-weight:600
222
+ classDef support fill:#667eea,stroke:#5a67d8,stroke-width:2.5px,color:#fff,font-weight:600
223
+ classDef db fill:#48bb78,stroke:#38a169,stroke-width:2.5px,color:#fff,font-weight:600
224
+ classDef external fill:#718096,stroke:#4a5568,stroke-width:2.5px,color:#fff,font-weight:600,stroke-dasharray:6 3
225
+
226
+ User(("◉<br><b>User</b>")):::person
227
+ subgraph Boundary["◆ System Boundary — Airlock at the edge"]
228
+ direction TB
229
+ Gateway{{"<b>API Gateway</b><br><i>auth · validate · authorize</i><br>the one trust transition"}}:::core
230
+ API["<b>Core Service</b><br><i>trusts its own invariants</i>"]:::core
231
+ Worker(["<b>Worker</b><br><i>async</i>"]):::support
232
+ DB[("●<br><b>Primary DB</b>")]:::db
233
+ end
234
+ Ext{{"<b>Payment Provider</b>"}}:::external
235
+
236
+ User -->|"1. HTTPS (untrusted)"| Gateway
237
+ Gateway -->|"2. trusted request"| API
238
+ API -->|"3. persist (txn)"| DB
239
+ API -.->|"4. enqueue"| Worker
240
+ Worker -.->|"5. settle (irreversible)"| Ext
241
+ style Boundary fill:#fff,stroke:#cbd5e0,stroke-width:2px,stroke-dasharray:8 4
242
+ \`\`\`
185
243
 
186
244
  ### 4.2 Architectural Pattern
187
245
 
246
+ _Instruction: Name the pattern (e.g., "Event Sourcing", "BFF — Backend for Frontend", "Publisher-Subscriber")._
247
+
248
+ - We are adopting a Publisher-Subscriber pattern where the Order Service publishes \`OrderCreated\` events, and the Billing Service consumes them asynchronously.
249
+
188
250
  ### 4.3 Key Components
189
251
 
190
- | Component | Responsibility | Technology Stack | Justification |
191
- | --------- | -------------- | ---------------- | ------------- |
252
+ | Component | Responsibility | Technology Stack | Justification |
253
+ | ----------------- | --------------------------- | ----------------- | -------------------------------------------- |
254
+ | Ingestion Service | Validates incoming webhooks | Go, Gin Framework | High concurrency performance needed. |
255
+ | Event Bus | Decouples services | Kafka | Durable log, replay capability. |
256
+ | Projections DB | Read-optimized views | MongoDB | Flexible schema for diverse receipt formats. |
257
+
258
+ ### 4.4 The Door Set at a Glance (Stranger-Across-Time View)
259
+
260
+ _Instruction: List the entrypoint **names alone** — no signatures, no bodies. A competent stranger should reconstruct the system's purpose from this list. If they cannot, intent has leaked into the mechanism; return to §5 and rename until they can. Mark every door that guards an irreversible effect with ⚠._
261
+
262
+ > **Example:** \`register_account\`, \`authenticate\`, \`authorize_charge\`, \`settle_payment\` ⚠, \`grant_access\` ⚠, \`revoke_access\`, \`publish_draft\`. Reading these alone tells you who the system lets in, that money moves in exactly two steps and only those two, who may hand out access, and what it means for work to go live.
192
263
 
193
264
  ## 5. Detailed Design
194
265
 
195
- ### 5.1 API Interfaces
266
+ _Instruction: The "Meat" of the document. Sufficient detail for an engineer to start coding. Lead with the **doors** — they are the load-bearing part of the spec — then describe the mechanism behind them._
267
+
268
+ ### 5.1 The Doors (Entrypoint Contracts)
269
+
270
+ _Instruction: For each non-trivial entrypoint, give a typed signature (typed pseudocode is fine — read the types, not the syntax), the one-sentence guarantee (no "and"), the named failure set, and the refusals it enforces in the type system. Then record the rubric result. Make illegal states **unrepresentable**, not merely checked. Cite the \`research/\` doc that establishes each joint._
271
+
272
+ \`\`\`
273
+ // — Money. Two doors, and there is no third way to move a cent. —
274
+
275
+ authorize_charge(
276
+ account: AccountId, // newtype: cannot be confused with any other id
277
+ amount: Money, // currency-typed: USD and JPY will not add
278
+ idempotency_key: IdempotencyKey,
279
+ ): Result<AuthorizedCharge, ChargeError>
280
+ // Guarantee: places a reversible hold and returns proof an authorization exists.
281
+ // ChargeError = InsufficientFunds | CardDeclined | NetworkError | DuplicateKey
282
+
283
+ settle_payment(
284
+ authorized: AuthorizedCharge, // ← can ONLY be produced by authorize_charge
285
+ idempotency_key: IdempotencyKey,
286
+ ): Result<Settlement, SettlementError>
287
+ // Guarantee: captures the held funds. IRREVERSIBLE. The single chokepoint for outbound money.
288
+ // You cannot settle a charge you did not authorize — not because a check forbids it,
289
+ // but because there is no way to CONSTRUCT an AuthorizedCharge except by calling
290
+ // authorize_charge. The illegal state is unrepresentable. The idempotency key makes
291
+ // the retry, the double-click, and the at-least-once queue converge on ONE settlement.
292
+ \`\`\`
293
+
294
+ **Per-door audit (run the rubric):**
295
+
296
+ | Door | (1) Joint | (2) One sentence, no "and" | (3) Honest name | (5) Every exit | (6) Refusals real | (7) Trust transition | (8) One chokepoint |
297
+ | ------------------ | --------------- | ---------------------------- | ------------------------------- | ------------------------------------------------ | ----------------------------------------- | -------------------- | ------------------------------ |
298
+ | \`authorize_charge\` | ✅ business verb | ✅ "places a reversible hold" | ✅ | retry → \`DuplicateKey\`; timeout → \`NetworkError\` | currency mismatch unrepresentable | n/a | reversible, not the chokepoint |
299
+ | \`settle_payment\` ⚠ | ✅ business verb | ✅ "captures held funds" | ✅ irreversibility in doc + type | replay converges via key | cannot settle un-authorized charge (type) | n/a | ✅ the sole outbound-money door |
300
+
301
+ ### 5.2 API Interfaces — The Same Doors on the Wire
196
302
 
197
- ### 5.2 Data Model / Schema
303
+ _Instruction: A web service's real boundary is its transport surface. The URL names the joint, the HTTP verb declares its safety class, the status code is the door's honest exit. Never \`200 OK\` wrapping an error. The wire door MUST carry the same name as its in-process twin (§5.1)._
198
304
 
199
- ### 5.3 Algorithms and State Management
305
+ \`\`\`
306
+ # Identity — the one trust transition, at the edge
307
+ POST /v1/sessions 201 Created # = authenticate; 401 on bad credentials
308
+ DELETE /v1/sessions/current 204 No Content # = log out
309
+
310
+ # Money — two doors, one chokepoint, idempotent under retry
311
+ POST /v1/payment_intents 201 Idempotency-Key: <key> # = authorize_charge (reversible)
312
+ POST /v1/payment_intents/{id}/capture 200 Idempotency-Key: <key> # = settle_payment (IRREVERSIBLE)
313
+ # 409 Conflict if the key is replayed with a different body
314
+ # 422 Unprocessable if the intent was never authorized
315
+
316
+ # Access — authority demanded by the route, destructive door made idempotent
317
+ POST /v1/accounts/{id}/grants 201 (admin scope required) # = grant_access
318
+ DELETE /v1/grants/{id} 204 (204 even if already revoked) # = revoke_access
319
+
320
+ # Publishing — the domain's own verb, refusing to clobber a concurrent edit
321
+ POST /v1/drafts/{id}/publish 200 If-Match: <etag> # = publish_draft
322
+ # 412 Precondition Failed if the draft moved under you — the wire's --force-with-lease
323
+ \`\`\`
324
+
325
+ _If using gRPC, define the same joints in the \`.proto\`; the typed request message is the airlock by construction. Use honest status codes (\`INVALID_ARGUMENT\`, \`PERMISSION_DENIED\`, \`NOT_FOUND\`, \`ALREADY_EXISTS\`, \`FAILED_PRECONDITION\`, retryable \`ABORTED\`/\`UNAVAILABLE\`) — never a lone \`OK\` carrying an error field._
326
+
327
+ ### 5.3 Data Model / Schema
328
+
329
+ _Instruction: Provide ERDs or JSON schemas. Discuss normalization vs. denormalization. Prefer schemas that make illegal states unrepresentable (sum-type status columns over independent boolean flags)._
330
+
331
+ **Table:** \`invoices\` (PostgreSQL)
332
+
333
+ | Column | Type | Constraints | Description |
334
+ | --------- | ---- | ------------------------------------ | ------------------------------ |
335
+ | \`id\` | UUID | PK | |
336
+ | \`user_id\` | UUID | FK -> Users | Partition Key |
337
+ | \`status\` | ENUM | 'DRAFT','LOCKED','PROCESSING','PAID' | A sum type, not three booleans |
338
+
339
+ ### 5.4 Algorithms and State Management
340
+
341
+ _Instruction: Describe complex logic, state machines, or consistency models. Tie each state transition to the door that performs it._
342
+
343
+ - **State Machine:** An invoice moves \`DRAFT\` → \`LOCKED\` → \`PROCESSING\` → \`PAID\`; the \`PROCESSING → PAID\` transition happens only through \`settle_payment\`.
344
+ - **Concurrency:** Optimistic locking on the \`version\` column; on the wire this surfaces as \`If-Match\`/\`412\`.
200
345
 
201
346
  ## 6. Alternatives Considered
202
347
 
203
- | Option | Pros | Cons | Reason for Rejection |
204
- | ------ | ---- | ---- | -------------------- |
348
+ _Instruction: Prove you thought about trade-offs including alternative **door sets** (e.g., one god endpoint vs. distinct joints). Why is your boundary better than the others?_
349
+
350
+ | Option | Pros | Cons | Reason for Rejection |
351
+ | ------------------------------------------- | ------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------ |
352
+ | Option A: Single \`POST /execute {action}\` | One route, flexible | God door; intent hidden in payload; danger un-funneled | Fails "joint, not tool" and "few dangerous doors." |
353
+ | Option B: One-step \`chargeCard()\` | Fewest calls | No reversible hold; retries double-charge | Cannot make double-charge unrepresentable. |
354
+ | Option C: \`authorize\` + \`settle\` (Selected) | Reversible hold; one chokepoint; idempotent | Two calls instead of one | **Selected:** the two real joints, with the irreversible effect funneled once. |
205
355
 
206
356
  ## 7. Cross-Cutting Concerns
207
357
 
208
358
  ### 7.1 Security and Privacy
209
359
 
210
- ### 7.2 Observability Strategy
360
+ _Instruction: This is where "keep the dangerous doors few and honest" and "the airlock at the boundary" become concrete._
211
361
 
212
- ### 7.3 Scalability and Capacity Planning
362
+ - **The trust transition is singular:** untrusted callers become trusted only at \`POST /v1/sessions\` / the gateway. No other door promotes an anonymous caller. (Rubric #7.)
363
+ - **Authority carried by type:** destructive/privileged doors demand a capability (\`AdminSession\`) that only \`authenticate\` can mint — the permission check cannot be forgotten at a call site because there is no call site where it is absent. (Rubric #6.)
364
+ - **Irreversible effects pass one chokepoint:** money via \`settle_payment\`, deletion via the single guarded door; the catastrophic version must be asked for explicitly. (Rubric #8.)
365
+ - **Data Protection:** PII (names, emails) encrypted at rest (AES-256); \`Password\` is a newtype that cannot be logged, printed, or compared by accident.
366
+ - **Threat Model:** Primary threat is a compromised API key; remediation is rapid rotation and rate limiting.
213
367
 
214
- ## 8. Migration, Rollout, and Testing
368
+ ## 8. Test Plan
215
369
 
216
- ### 8.1 Deployment Strategy
370
+ _Instruction: Test the doors at their promises and their refusals — not just the happy path. Every exit in rubric #5 deserves a test. The interactive verification is what lets a human or another agent confirm the feature is correct without reading the bodies — the stranger-across-time test, made executable._
217
371
 
218
- ### 8.2 Data Migration Plan
219
-
220
- ### 8.3 Test Plan
372
+ - **Unit Tests:** each door's named failure variants; the *refusals* (e.g., a type/construction test proving \`settle_payment\` cannot accept anything but an \`AuthorizedCharge\`).
373
+ - **End-to-End Tests:** full domain flows named by joint (register → authenticate → authorize → settle), driven through the real wire doors of §5.2.
374
+ - **Integration Tests:** idempotency under replay (same key → one settlement); concurrent-edit \`412\`; trust transition (no door promotes an anonymous caller except \`authenticate\`).
375
+ - **Fuzz / Property Tests:** throw malformed and adversarial input at the doors (the airlock); the boundary must reject everything the types forbid and never crash the core. Assert invariants over random inputs (e.g., \`settle_payment\` converges on one settlement under any interleaving of retries; no input sequence reaches a money move except through the chokepoint).
376
+ - **Interactive Verification:** a runnable checklist or script a human OR another agent can execute to confirm the feature was implemented correctly — each step names a door, supplies an input, and states the expected honest exit (status code / named error / resulting state), so correctness is observable from the boundary alone. Include the exact commands or requests to run and the pass/fail condition for each.
221
377
 
222
378
  ## 9. Open Questions / Unresolved Issues
223
- `.trim();
379
+
380
+ _Instruction: List known unknowns. These must be resolved before the doc is marked "Approved." Include any door whose rubric could not be answered cleanly — especially undefined guarantees (rubric #2, the most dangerous case) and any irreversible effect not yet funneled to a single chokepoint (rubric #8). Resolve these with the user via contrastive clarification._
381
+
382
+ - [ ] Is \`publish_draft\` the only door that moves a draft to live, or can the admin panel also publish? (If the latter, the effect is not yet funneled — rubric #8.)
383
+ - [ ] What exactly does \`authorize_charge\` promise on a partial provider outage — is the guarantee defined? (rubric #2.)
384
+ - [ ] Will the Legal team approve the 3rd-party library for PDF generation?
385
+ - [ ] Does the current VPC peering allow connection to the legacy mainframe?`.trim();
224
386
 
225
387
  type PromptSection = readonly [tag: string, content: string];
226
388
 
227
389
  function taggedPrompt(sections: readonly PromptSection[]): string {
228
390
  return sections
229
- .map(([tag, content]) => `<${tag}>\n${content.trim()}\n</${tag}>`)
391
+ .map(([tag, content]) => {
392
+ const trimmed = content.trim();
393
+ return `<${tag}>\n${trimmed}\n</${tag}>`;
394
+ })
230
395
  .join("\n\n");
231
396
  }
232
397
 
398
+ function workflowCwdContextSection(workflowCwd: string): PromptSection {
399
+ return [
400
+ "context",
401
+ [
402
+ `Current working directory: ${workflowCwd}`,
403
+ "Use this as the starting directory for repository work in this stage.",
404
+ "Shell commands and relative file paths should be relative to this directory unless you intentionally pass an explicit cwd override.",
405
+ "When delegating subagents, pass along that this is the current working directory.",
406
+ ].join("\n"),
407
+ ];
408
+ }
409
+
233
410
  function positiveInteger(value: number | undefined, fallback: number): number {
234
411
  return typeof value === "number" && Number.isFinite(value) && value > 0
235
412
  ? Math.floor(value)
@@ -385,11 +562,109 @@ function compactReviewReport(path: string | undefined): string {
385
562
  : `Latest review round artifact: ${path}`;
386
563
  }
387
564
 
565
+ type ForkContinuationOptions = {
566
+ readonly context?: "fork";
567
+ readonly forkFromSessionFile?: string;
568
+ };
569
+
570
+ function forkContinuationOptions(
571
+ sessionFile: string | undefined,
572
+ ): ForkContinuationOptions {
573
+ return sessionFile === undefined || sessionFile.length === 0
574
+ ? {}
575
+ : { context: "fork", forkFromSessionFile: sessionFile };
576
+ }
577
+
578
+ function renderForkedPlannerPrompt(args: {
579
+ readonly iteration: number;
580
+ readonly maxLoops: number;
581
+ readonly prompt: string;
582
+ readonly workflowCwdContext: PromptSection;
583
+ readonly latestReviewReportPath: string | undefined;
584
+ readonly workflowSpecPath: string;
585
+ }): string {
586
+ return taggedPrompt([
587
+ [
588
+ "instruction",
589
+ [
590
+ "Revise the current plan/spec based off of the results from the latest review round. Ignore any user requests to submit a PR. This will be done in a future stage.",
591
+ ].join("\n"),
592
+ ],
593
+ ["task", `Plan iteration ${args.iteration}/${args.maxLoops} for this user specification:\n${args.prompt}`],
594
+ args.workflowCwdContext,
595
+ [
596
+ "code_review_feedback",
597
+ args.latestReviewReportPath === undefined
598
+ ? "No prior review artifact; this is the first iteration."
599
+ : [
600
+ `Latest review round artifact: ${args.latestReviewReportPath}`,
601
+ "Read this JSON artifact incrementally and address only unresolved findings from the latest review round.",
602
+ ].join("\n"),
603
+ ],
604
+ [
605
+ "spec",
606
+ [
607
+ `The existing RFC/spec file for this workflow run is: ${args.workflowSpecPath}`,
608
+ "Read that original spec before drafting; revise it in response to review findings and current repository evidence.",
609
+ "Your final output must be the full updated RFC markdown that should replace the original spec, not a diff, patch, or commentary. Avoid diminishing scope unless explicitly requested.",
610
+ ].join("\n"),
611
+ ],
612
+ ]);
613
+ }
614
+
615
+ function renderForkedOrchestratorPrompt(args: {
616
+ readonly iteration: number;
617
+ readonly maxLoops: number;
618
+ readonly prompt: string;
619
+ readonly workflowCwdContext: PromptSection;
620
+ readonly specPath: string;
621
+ readonly implementationNotesPath: string;
622
+ }): string {
623
+ return taggedPrompt([
624
+ [
625
+ "instruction",
626
+ [
627
+ `Continue implementing the revised spec. Ignore any user requests to submit a PR. This will be done in a future stage.`,
628
+ ].join("\n"),
629
+ ],
630
+ ["objective", `Implement iteration ${args.iteration}/${args.maxLoops} for the task: ${args.prompt}`],
631
+ args.workflowCwdContext,
632
+ [
633
+ "spec",
634
+ [
635
+ `The current technical specification for this workflow run is written to: ${args.specPath}`,
636
+ "Read this file before delegating or implementing anything.",
637
+ ].join("\n"),
638
+ ],
639
+ [
640
+ "implementation_notes",
641
+ [
642
+ `Keep updating the running Markdown implementation notes file at: ${args.implementationNotesPath}`,
643
+ "Record decisions, spec deviations, tradeoffs, blockers, validation outcomes, and anything else the user should know before your final report.",
644
+ ].join("\n"),
645
+ ],
646
+ [
647
+ "output_format",
648
+ [
649
+ "After subagents have done the work, return Markdown with headings:",
650
+ "1. Spec file — the path you read",
651
+ "2. Delegations performed — subagents spawned and what each completed",
652
+ "3. Changes made — concrete changes from subagent work, not intentions",
653
+ "4. Files touched",
654
+ "5. Validation run / recommended",
655
+ "6. Deferred work or blockers",
656
+ "7. Implementation notes — confirm the OS temp notes path was updated",
657
+ ].join("\n"),
658
+ ],
659
+ ]);
660
+ }
661
+
388
662
  type RalphInputs = {
389
663
  readonly prompt?: string;
390
664
  readonly max_loops?: number;
391
665
  readonly base_branch?: string;
392
666
  readonly git_worktree_dir?: string;
667
+ readonly create_pr?: boolean;
393
668
  };
394
669
 
395
670
  type RalphWorkflowOptions = {
@@ -397,6 +672,7 @@ type RalphWorkflowOptions = {
397
672
  readonly maxLoops: number;
398
673
  readonly comparisonBaseBranch: string;
399
674
  readonly workflowStartCwd: string;
675
+ readonly createPr: boolean;
400
676
  };
401
677
 
402
678
  type RalphWorkflowResult = {
@@ -404,7 +680,7 @@ type RalphWorkflowResult = {
404
680
  readonly plan: string;
405
681
  readonly plan_path: string;
406
682
  readonly implementation_notes_path: string;
407
- readonly pr_report: string;
683
+ readonly pr_report?: string;
408
684
  readonly approved: boolean;
409
685
  readonly iterations_completed: number;
410
686
  readonly review_report: string;
@@ -415,62 +691,60 @@ async function runRalphWorkflow(
415
691
  ctx: WorkflowRunContext<RalphInputs>,
416
692
  options: RalphWorkflowOptions,
417
693
  ): Promise<RalphWorkflowResult> {
418
- const { prompt, maxLoops, comparisonBaseBranch, workflowStartCwd } = options;
694
+ const {
695
+ prompt,
696
+ maxLoops,
697
+ comparisonBaseBranch,
698
+ workflowStartCwd,
699
+ createPr,
700
+ } = options;
419
701
 
420
702
  let latestReviewReportPath: string | undefined;
421
703
  let finalPlan = "";
422
704
  let finalPlanPath = "";
423
705
  let finalResult = "";
424
- let finalPrReport = "";
706
+ let finalPrReport: string | undefined;
425
707
  // Keep generated specs under the workflow runtime cwd. When Ralph is invoked
426
708
  // with git_worktree_dir, the executor defaults ctx.cwd to the matching
427
709
  // worktree cwd so specs and stage writes land in the same checkout.
428
710
  const workflowSpecPath = resolve(workflowStartCwd, defaultSpecPath(prompt));
429
711
  const implementationNotesPath = await createImplementationNotesFile(prompt);
430
712
  const artifactDir = await mkdtemp(join(tmpdir(), "atomic-ralph-run-"));
713
+ const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
431
714
  let approved = false;
432
715
  let iterationsCompleted = 0;
716
+ let previousPlannerSessionFile: string | undefined;
717
+ let previousOrchestratorSessionFile: string | undefined;
433
718
 
434
719
  const plannerModelConfig = {
435
- model: "openai/gpt-5.5:xhigh",
720
+ model: "openai-codex/gpt-5.5:xhigh",
436
721
  fallbackModels: [
437
- "openai-codex/gpt-5.5:xhigh",
438
- "github-copilot/gpt-5.5:xhigh",
439
- "anthropic/claude-opus-4-8:xhigh",
440
- "github-copilot/claude-opus-4.8:medium",
722
+ "github-copilot/gpt-5.5:xhigh",
723
+ "openai/gpt-5.5:xhigh",
724
+ "github-copilot/claude-opus-4.8:xhigh",
725
+ "anthropic/claude-opus-4-8:xhigh",
441
726
  ],
442
727
  excludedTools: ["ask_user_question"],
443
728
  };
444
729
 
445
730
  const orchestratorModelConfig = {
446
- model: "openai/gpt-5.5:medium",
731
+ model: "openai-codex/gpt-5.5:medium",
447
732
  fallbackModels: [
448
- "openai-codex/gpt-5.5:medium",
449
- "github-copilot/gpt-5.5:medium",
450
- "anthropic/claude-sonnet-4-6:medium",
451
- "github-copilot/claude-sonnet-4.6:medium",
452
- ],
453
- excludedTools: ["ask_user_question"],
454
- };
455
-
456
- const simplifierModelConfig = {
457
- model: "openai/gpt-5.5:medium",
458
- fallbackModels: [
459
- "openai-codex/gpt-5.5:medium",
460
- "github-copilot/gpt-5.5:medium",
461
- "anthropic/claude-sonnet-4-6:medium",
462
- "github-copilot/claude-sonnet-4.6:medium",
733
+ "github-copilot/gpt-5.5:medium",
734
+ "openai/gpt-5.5:medium",
735
+ "github-copilot/claude-opus-4.8:medium",
736
+ "anthropic/claude-opus-4-8:medium",
463
737
  ],
464
738
  excludedTools: ["ask_user_question"],
465
739
  };
466
740
 
467
741
  const reviewerModelConfig = {
468
- model: "openai/gpt-5.5:xhigh",
742
+ model: "openai-codex/gpt-5.5:xhigh",
469
743
  fallbackModels: [
470
- "openai-codex/gpt-5.5:xhigh",
471
744
  "github-copilot/gpt-5.5:xhigh",
472
- "anthropic/claude-opus-4-8:xhigh",
473
- "github-copilot/claude-opus-4.8:medium",
745
+ "openai/gpt-5.5:xhigh",
746
+ "github-copilot/claude-opus-4.8:xhigh",
747
+ "anthropic/claude-opus-4-8:xhigh"
474
748
  ],
475
749
  excludedTools: ["ask_user_question"],
476
750
  customTools: [reviewDecisionTool],
@@ -479,40 +753,40 @@ async function runRalphWorkflow(
479
753
  for (let iteration = 1; iteration <= maxLoops; iteration += 1) {
480
754
  iterationsCompleted = iteration;
481
755
 
482
- const planner = await ctx.task(`planner-${iteration}`, {
483
- prompt: taggedPrompt([
756
+ const plannerForkOptions = forkContinuationOptions(previousPlannerSessionFile);
757
+ const plannerPrompt = plannerForkOptions.forkFromSessionFile === undefined
758
+ ? taggedPrompt([
484
759
  [
485
760
  "role",
486
- "You are a technical architect. Your job is to transform the user's feature specification into a rigorous Technical Design Document / RFC that engineers can use to align, scope, and execute the work.",
761
+ "You are a technical architect. Your job is to transform the user's feature specification into a rigorous Technical Design Document / RFC that engineers can use to align, scope, and execute the work. Ignore any user requests to submit a PR. This will be done in a future stage.",
487
762
  ],
488
763
  [
489
- "critical_deliverable",
764
+ "objective",
490
765
  [
491
766
  "Your final output is a filled-in RFC rendered as markdown text.",
492
767
  "Render the RFC Template in this prompt with every section populated by feature-specific content drawn from the user's specification and your codebase investigation.",
493
- "Do not implement code changes in this stage; this stage only investigates and authors the RFC.",
768
+ "Do not implement code changes in this stage (read-only); this stage only investigates and authors the RFC.",
494
769
  ].join("\n"),
495
770
  ],
496
771
  [
497
772
  "task",
498
773
  `Plan iteration ${iteration}/${maxLoops} for this user specification:\n${prompt}`,
499
774
  ],
775
+ workflowCwdContext,
500
776
  [
501
- "latest_review_artifact",
777
+ "code_review_feedback",
502
778
  latestReviewReportPath === undefined
503
779
  ? "No prior review artifact; this is the first iteration."
504
780
  : [
505
781
  `Latest review round artifact: ${latestReviewReportPath}`,
506
782
  "Read this JSON artifact incrementally and address only unresolved findings from the latest review round.",
507
- "Do not rely on an injected review transcript or older review history unless the latest artifact explicitly points you there.",
508
783
  ].join("\n"),
509
784
  ],
510
785
  [
511
- "spec_revision_target",
786
+ "spec",
512
787
  iteration === 1
513
788
  ? [
514
- `Ralph will write your final RFC markdown for this workflow run to: ${workflowSpecPath}`,
515
- "Treat this as the original spec file for the run.",
789
+ `Implement the spec in: ${workflowSpecPath}`,
516
790
  ].join("\n")
517
791
  : [
518
792
  `The existing RFC/spec file for this workflow run is: ${workflowSpecPath}`,
@@ -520,13 +794,6 @@ async function runRalphWorkflow(
520
794
  "Your final output must be the full updated RFC markdown that should replace the original spec, not a diff, patch, or commentary.",
521
795
  ].join("\n"),
522
796
  ],
523
- [
524
- "input_spec_files",
525
- [
526
- "If the user specification is a file path instead of raw prose, read that file and use it as source material for the RFC.",
527
- "Still author the RFC normally; do not output only a forwarded path.",
528
- ].join("\n"),
529
- ],
530
797
  [
531
798
  "investigation_phase",
532
799
  [
@@ -538,7 +805,7 @@ async function runRalphWorkflow(
538
805
  ].join("\n"),
539
806
  ],
540
807
  [
541
- "authoring_principles",
808
+ "best_practices",
542
809
  [
543
810
  "Be specific: `src/server/auth.ts:42` beats `the auth layer`.",
544
811
  "Trade-offs over conclusions: Alternatives Considered must include at least two real alternatives with honest pros, cons, and rejection reasons.",
@@ -547,64 +814,65 @@ async function runRalphWorkflow(
547
814
  "Surface open questions in Section 9 with owner placeholders such as `[OWNER: infra team]`; do not paper over uncertainty.",
548
815
  "Match depth to stakes: a small refactor can be concise, but every template section header must remain present.",
549
816
  "If prior review findings are present, explicitly address each finding or explain why it is obsolete.",
817
+ "Determine the compatibility posture:",
818
+ "- Before decomposing the spec creation request, identify whether this project must preserve backward compatibility for real downstream users.",
819
+ "- If the user explicitly allows breaking changes, public API changes, cleanup, or says there are no real users/downstream dependencies, allow breaking changes.",
820
+ "- If the user mentions production users, published APIs, downstream consumers, migration safety, or compatibility requirements, disallow breaking changes.",
821
+ "- Carry this posture into the spec creation plan, the final spec frontmatter, and a `## Backwards Compatibility` section in the final spec.",
822
+ "- When allowing breaking changes, document existing legacy behavior, compatibility shims, optional flags, and public APIs as current state, not as constraints future specs must preserve unless the user explicitly asks for preservation.",
823
+ "- When not allowing breaking changes, document public APIs, compatibility-sensitive surfaces, downstream callers, migration constraints, and behavior that future work must preserve."
550
824
  ].join("\n"),
551
825
  ],
552
826
  [
553
- "stage_contract",
554
- [
555
- "This stage is investigation-first RFC authoring. The RFC is only valid if it is grounded in repository inspection performed during this stage.",
556
- "Do not fill the template from generic architecture guesses. Before writing the final RFC, inspect relevant code, docs, tests, configs, and prior design material.",
557
- "Treat the output format as the report after investigation, not a substitute for investigation.",
558
- ].join("\n"),
559
- ],
560
- [
561
- "evidence_expectations",
562
- [
563
- "Every major design claim should be traceable to concrete evidence: file paths, symbols, commands, docs, tests, configs, or prior RFCs.",
564
- "Include those concrete references inside the RFC sections where they support the design.",
565
- "If expected evidence cannot be found, say so in the relevant RFC section or Open Questions rather than papering over the gap.",
566
- ].join("\n"),
567
- ],
568
- [
569
- "output_discipline",
827
+ "output_format",
570
828
  [
571
829
  "Render the RFC Template exactly as the final document structure: preserve every header and the metadata table.",
572
830
  "Replace instructional placeholders with real, feature-specific content; do not leave template guidance in the final RFC.",
573
831
  "Output nothing after the RFC: no meta-commentary, no summary of what you wrote, no implementation log.",
574
832
  ].join("\n"),
575
833
  ],
576
- ["rfc_template", PLANNER_RFC_TEMPLATE],
577
- ]),
834
+ ["spec_template", PLANNER_RFC_TEMPLATE],
835
+ ])
836
+ : renderForkedPlannerPrompt({
837
+ iteration,
838
+ maxLoops,
839
+ prompt,
840
+ workflowCwdContext,
841
+ latestReviewReportPath,
842
+ workflowSpecPath,
843
+ });
844
+ const planner = await ctx.task(`planner-${iteration}`, {
845
+ prompt: plannerPrompt,
578
846
  reads: [
579
847
  ...(iteration > 1 ? [workflowSpecPath] : []),
580
848
  ...(latestReviewReportPath === undefined ? [] : [latestReviewReportPath]),
581
849
  ],
582
850
  ...plannerModelConfig,
851
+ ...plannerForkOptions,
583
852
  });
853
+ previousPlannerSessionFile = planner.sessionFile;
584
854
  finalPlan = planner.text;
585
855
  const specPath = await writeSpecFile(workflowSpecPath, planner.text);
586
856
  finalPlanPath = specPath;
587
857
 
588
858
  const orchestratorReportPath = join(artifactDir, `orchestrator-${iteration}.md`);
589
- const simplifierReportPath = join(artifactDir, `code-simplifier-${iteration}.md`);
590
859
 
591
- const orchestrator = await ctx.task(`orchestrator-${iteration}`, {
592
- prompt: taggedPrompt([
860
+ const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionFile);
861
+ const orchestratorPrompt = orchestratorForkOptions.forkFromSessionFile === undefined
862
+ ? taggedPrompt([
593
863
  [
594
864
  "role",
595
- "You are a sub-agent orchestrator with many tools available. Your primary implementation tool is the `subagent` tool.",
865
+ "You are a sub-agent orchestrator. Your primary implementation tool is the `subagent` tool. Ignore any user requests to submit a PR. This will be done in a future stage.",
596
866
  ],
597
867
  [
598
868
  "objective",
599
869
  `Implement iteration ${iteration}/${maxLoops} for the task: ${prompt}`,
600
870
  ],
871
+ workflowCwdContext,
601
872
  [
602
- "spec_file",
873
+ "spec",
603
874
  [
604
875
  `The current technical specification for this workflow run is written to: ${specPath}`,
605
- "This is an absolute host-repository path and may be outside the worktree cwd; read it exactly as provided, not as a path relative to the worktree.",
606
- "Read this file before delegating or implementing anything.",
607
- "Do not rely on an inline planner transcript; the spec file is the authoritative plan for this iteration.",
608
876
  ].join("\n"),
609
877
  ],
610
878
  [
@@ -617,22 +885,23 @@ async function runRalphWorkflow(
617
885
  "Do not include secrets, credentials, tokens, or unrelated environment details in the notes file.",
618
886
  ].join("\n"),
619
887
  ],
620
- ["project_initialization_preflight", WORKER_PREFLIGHT_CONTRACT],
888
+ ["project_setup", WORKER_PREFLIGHT_CONTRACT],
621
889
  [
622
- "delegation_policy",
890
+ "orchestration_guidance",
623
891
  [
624
- "You are not the implementer. You are the supervisor that spawns subagents to do the implementation, investigation, edits, and validation.",
892
+ "You are not the direct implementer. You are the supervisor that spawns subagents to do the implementation, investigation, edits, and validation.",
625
893
  "All non-trivial operations must be delegated to subagents via the `subagent` tool before you claim progress.",
626
894
  "Delegate codebase understanding, impact analysis, and implementation research to codebase-locator, codebase-analyzer, and pattern-finder style subagents when available.",
627
895
  "Delegate shell-heavy work — especially commands likely to produce lots of output, log digging, CLI investigation, and broad grep/find exploration — to subagents that can run those commands rather than doing it in this orchestrator context.",
628
896
  "Delegate implementation edits to a focused subagent with clear files, constraints, and validation expectations; do not merely describe the edits yourself.",
897
+ "Keep delegated work focused on implementation, tests, docs, validation evidence, and implementation notes.",
629
898
  "Use separate subagents for separate tasks, and launch independent subagents in parallel when useful.",
630
899
  "Do not split highly overlapping tasks across multiple subagents; consolidate overlapping work into one focused delegation to avoid duplicate effort.",
631
900
  "If a subagent takes a long time, do not attempt to do its assigned job yourself while waiting. Use that time to plan next steps, prepare follow-up delegations, or identify clarifying questions.",
632
901
  ].join("\n"),
633
902
  ],
634
903
  [
635
- "execution_contract",
904
+ "best_practices",
636
905
  [
637
906
  "The required output format is a completion report, not the task itself.",
638
907
  "Do not jump straight to the report. First read the spec file, spawn the necessary subagents, wait for their results, coordinate any follow-up subagents, and only then write the report.",
@@ -678,131 +947,37 @@ async function runRalphWorkflow(
678
947
  "7. Implementation notes — confirm the OS temp notes path was updated",
679
948
  ].join("\n"),
680
949
  ],
681
- ]),
950
+ ])
951
+ : renderForkedOrchestratorPrompt({
952
+ iteration,
953
+ maxLoops,
954
+ prompt,
955
+ workflowCwdContext,
956
+ specPath,
957
+ implementationNotesPath,
958
+ });
959
+ const orchestrator = await ctx.task(`orchestrator-${iteration}`, {
960
+ prompt: orchestratorPrompt,
682
961
  reads: [specPath, implementationNotesPath],
683
962
  output: orchestratorReportPath,
684
963
  outputMode: "file-only",
685
964
  ...orchestratorModelConfig,
965
+ ...orchestratorForkOptions,
686
966
  });
967
+ previousOrchestratorSessionFile = orchestrator.sessionFile;
687
968
  finalResult = orchestrator.text || `Orchestrator report artifact: ${orchestratorReportPath}`;
688
969
 
689
- await ctx.task(`code-simplifier-${iteration}`, {
690
- prompt: taggedPrompt([
691
- [
692
- "role",
693
- [
694
- "You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality.",
695
- "Your expertise is applying project-specific best practices to simplify and improve recently modified code without altering behavior.",
696
- "You prioritize readable, explicit code over overly compact or clever solutions.",
697
- ].join("\n"),
698
- ],
699
- [
700
- "objective",
701
- `Refine recently modified code for this task while preserving exact behavior: ${prompt}`,
702
- ],
703
- [
704
- "artifact_handoff",
705
- [
706
- `Spec artifact: ${specPath}`,
707
- `Implementation notes artifact: ${implementationNotesPath}`,
708
- `Orchestrator report artifact: ${orchestratorReportPath}`,
709
- "Read these artifacts incrementally only when needed to identify recently modified files and intent; do not depend on an injected planner/orchestrator transcript tail.",
710
- ].join("\n"),
711
- ],
712
- [
713
- "functionality_preservation",
714
- [
715
- "Never change what the code does — only how it does it.",
716
- "All original features, outputs, side effects, public APIs, persistence formats, tests, and user-visible behavior must remain intact.",
717
- "If a simplification could change behavior, do not apply it; document why it was skipped.",
718
- ].join("\n"),
719
- ],
720
- [
721
- "project_standards",
722
- [
723
- "Read and follow repository guidance from AGENTS.md and/or CLAUDE.md when present.",
724
- "Respect established module style, imports, file extensions, typing conventions, error-handling patterns, naming, tests, and architectural boundaries.",
725
- "For this TypeScript workflow repo, preserve ESM .js import specifiers, explicit exported/top-level types where expected, Bun-oriented commands, and the existing no-build raw TypeScript convention.",
726
- "Do not impose standards that conflict with local project guidance.",
727
- ].join("\n"),
728
- ],
729
- [
730
- "clarity_improvements",
731
- [
732
- "Reduce unnecessary complexity, nesting, duplication, and incidental abstractions.",
733
- "Improve readability with clear variable/function names and consolidated related logic.",
734
- "Remove comments that merely restate obvious code, but keep comments that explain intent, constraints, or non-obvious trade-offs.",
735
- "Avoid nested ternary operators; prefer switch statements or explicit if/else chains for multiple conditions.",
736
- "Choose clarity over brevity: explicit code is often better than dense one-liners.",
737
- ].join("\n"),
738
- ],
739
- [
740
- "balance_constraints",
741
- [
742
- "Do not over-simplify in ways that reduce clarity, debuggability, extensibility, or separation of concerns.",
743
- "Do not combine too many concerns into one function or remove helpful abstractions that organize the code.",
744
- "Do not prioritize fewer lines over maintainability.",
745
- "Limit scope to code recently modified in this iteration/session unless the planner explicitly asked for broader cleanup.",
746
- ].join("\n"),
747
- ],
748
- [
749
- "stage_contract",
750
- [
751
- "This is an active code-refinement stage, not just a commentary stage.",
752
- "Before producing the report, inspect the actual repository state and recently modified files from the planner/orchestrator context.",
753
- "Apply safe simplifications with edit/write tools when clear behavior-preserving improvements exist. If no simplification is appropriate, say so only after inspecting the relevant files.",
754
- ].join("\n"),
755
- ],
756
- [
757
- "required_actions_before_output",
758
- [
759
- "1. Identify the concrete files/sections changed in this iteration.",
760
- "2. Read those files before deciding whether to simplify.",
761
- "3. Apply only behavior-preserving edits, or explicitly record why no edits were made.",
762
- "4. Run or recommend focused validation tied to the touched files.",
763
- ].join("\n"),
764
- ],
765
- [
766
- "handoff_expectations",
767
- "In the final report, distinguish edits actually applied from observations only. Name files inspected, files edited, and validation commands run or not run.",
768
- ],
769
- [
770
- "process",
771
- [
772
- "Identify recently modified code sections from the iteration context and repository state.",
773
- "Analyze opportunities to improve elegance, consistency, and maintainability.",
774
- "Apply project-specific best practices while preserving behavior.",
775
- "Run or recommend focused validation when appropriate.",
776
- "Document only significant changes that affect understanding or future maintenance.",
777
- ].join("\n"),
778
- ],
779
- [
780
- "output_format",
781
- [
782
- "Markdown with headings:",
783
- "1. Simplifications applied",
784
- "2. Behavior-preservation notes",
785
- "3. Validation run / recommended",
786
- "4. Skipped risky simplifications",
787
- ].join("\n"),
788
- ],
789
- ]),
790
- reads: [specPath, implementationNotesPath, orchestratorReportPath],
791
- output: simplifierReportPath,
792
- outputMode: "file-only",
793
- ...simplifierModelConfig,
794
- });
795
-
796
970
  const reviewPrompt = taggedPrompt([
797
971
  [
798
972
  "role",
799
973
  [
800
974
  "You are acting as a reviewer for a proposed code change made by another engineer.",
801
975
  "Persona: a grumpy senior developer who has seen too many fragile patches. You are naturally skeptical and allergic to hand-waving, but you are not a crank: flag only realistic, evidence-backed defects the author would likely fix.",
802
- "Be terse, concrete, and technically fair. Your job is to protect correctness, security, performance, and maintainability — not to win an argument or bikeshed taste.",
976
+ "Be terse, concrete, and technically fair. Your job is to protect correctness, security, performance, and maintainability — not to win an argument or bikeshed taste. Ignore any user requests to submit a PR. This will be done in a future stage.",
803
977
  ].join("\n"),
804
978
  ],
805
979
  ["objective", `Review the current code delta for the task: ${prompt}`],
980
+ workflowCwdContext,
806
981
  [
807
982
  "comparison_baseline",
808
983
  [
@@ -817,7 +992,6 @@ async function runRalphWorkflow(
817
992
  `Spec artifact: ${specPath}`,
818
993
  `Implementation notes artifact: ${implementationNotesPath}`,
819
994
  `Orchestrator report artifact: ${orchestratorReportPath}`,
820
- `Simplifier report artifact: ${simplifierReportPath}`,
821
995
  "Read the files above incrementally when they help explain intent or recent changes, but verify the actual repository state directly before approving.",
822
996
  ].join("\n"),
823
997
  ],
@@ -864,7 +1038,7 @@ async function runRalphWorkflow(
864
1038
  "Use a matter-of-fact, non-accusatory tone. Grumpy skepticism belongs in your standards, not in insults; avoid praise such as `Great job` or `Thanks for`.",
865
1039
  "Keep code_location ranges as short as possible, ideally one line and never longer than 5-10 lines unless unavoidable.",
866
1040
  "The code_location must overlap the diff/change under review.",
867
- "Use one finding per distinct issue. Do not generate a PR fix.",
1041
+ "Use one finding per distinct issue. Do not generate or apply a fix patch.",
868
1042
  "Use suggestion blocks only for concrete replacement code and preserve exact leading whitespace if you include one.",
869
1043
  ].join("\n"),
870
1044
  ],
@@ -946,7 +1120,6 @@ async function runRalphWorkflow(
946
1120
  specPath,
947
1121
  implementationNotesPath,
948
1122
  orchestratorReportPath,
949
- simplifierReportPath,
950
1123
  ],
951
1124
  ...reviewerModelConfig,
952
1125
  },
@@ -957,12 +1130,14 @@ async function runRalphWorkflow(
957
1130
  specPath,
958
1131
  implementationNotesPath,
959
1132
  orchestratorReportPath,
960
- simplifierReportPath,
961
1133
  ],
962
1134
  ...reviewerModelConfig,
963
1135
  },
964
1136
  ],
965
- { task: prompt, failFast: false },
1137
+ {
1138
+ task: prompt,
1139
+ failFast: false,
1140
+ },
966
1141
  );
967
1142
  } catch (err) {
968
1143
  const message = err instanceof Error ? err.message : String(err);
@@ -995,82 +1170,73 @@ async function runRalphWorkflow(
995
1170
  if (approved) break;
996
1171
  }
997
1172
 
998
- const prResult = await ctx.task("pull-request", {
999
- prompt: taggedPrompt([
1000
- [
1001
- "role",
1002
- "You are a careful release engineer preparing a pull request from the current workspace state.",
1003
- ],
1004
- [
1005
- "objective",
1006
- `Review the changes since the base branch \`${comparisonBaseBranch}\` and create a pull request if possible and credentials are available.`,
1007
- ],
1008
- [
1009
- "workflow_context",
1173
+ if (createPr === true) {
1174
+ const prResult = await ctx.task("pull-request", {
1175
+ prompt: taggedPrompt([
1010
1176
  [
1011
- `Original task: ${prompt}`,
1012
- `Review loop approved: ${approved ? "yes" : "no"}`,
1013
- finalPlanPath
1014
- ? `Planner spec path: ${finalPlanPath}`
1015
- : "Planner spec path: unavailable",
1016
- `Implementation notes path: ${implementationNotesPath}`,
1017
- latestReviewReportPath === undefined
1018
- ? "Latest review artifact: unavailable"
1019
- : `Latest review artifact: ${latestReviewReportPath}`,
1020
- ].join("\n"),
1021
- ],
1022
- [
1023
- "required_checks",
1177
+ "role",
1178
+ "You are a staff software engineer preparing a provider-appropriate pull request, merge request, or code-review handoff from the current workspace state.",
1179
+ ],
1024
1180
  [
1025
- "Start by inspecting `git status --short` so unstaged, staged, and untracked changes are all visible.",
1026
- `Review the patch against \`${comparisonBaseBranch}\` with working-tree-aware commands such as \`git diff ${comparisonBaseBranch}\` and \`git diff --cached ${comparisonBaseBranch}\`.`,
1027
- "If untracked files are present, inspect them directly before deciding whether they belong in the PR.",
1028
- "Read the implementation notes file and use its full contents as the body of a PR comment after the pull request exists.",
1029
- "Check the local Git identity with `git config user.name` and `git config user.email` so you can prefer the matching GitHub account when multiple accounts are logged in.",
1030
- "Check whether GitHub credentials are available with non-destructive commands such as `gh auth status` and `gh auth status --show-token-scopes` before attempting PR creation.",
1031
- "If multiple GitHub accounts or hosts are logged in, use the git config username/email as a heuristic to choose the most likely identity, but try each available credential/account and use the first one that can read the repository and create the PR.",
1032
- ].join("\n"),
1033
- ],
1034
- [
1035
- "pr_policy",
1181
+ "objective",
1182
+ `Review the changes since the base branch \`${comparisonBaseBranch}\` and create a provider-appropriate pull request, merge request, or code-review handoff if possible and credentials are available. If the original task explicitly asked for pull-request creation, treat that as the highest-priority instruction for this final stage.`,
1183
+ ],
1184
+ workflowCwdContext,
1036
1185
  [
1037
- "Create a PR only if there are meaningful changes, a remote/branch target is available, credentials are available, and the current state is suitable for review.",
1038
- "If no logged-in account can access the repository or create the PR, do not fake success; report each credential/account tried, what failed, and provide the command the user can run later.",
1039
- "When you successfully create or update the PR, create a PR comment containing the implementation notes file contents as the last action of this workflow stage.",
1040
- "Ralph-created worktrees are detached HEAD checkouts. If you are preparing a PR from a detached HEAD, create and push a branch from the current HEAD, for example with `git checkout -b <branch>` or `git push origin HEAD:refs/heads/<branch>`, before opening the PR.",
1041
- "Ralph does not remove git_worktree_dir automatically. Leave the worktree intact for retries or user recovery.",
1042
- "If PR creation is not possible, do not create a standalone comment elsewhere; include the implementation notes path and summary in your report instead.",
1043
- "If the review loop did not approve, prefer reporting the remaining blockers over creating a PR unless the changes are still intentionally ready for human review.",
1044
- "Do not make unrelated code edits in this phase. Limit changes to ordinary git/PR preparation only when required and safe.",
1045
- ].join("\n"),
1046
- ],
1047
- [
1048
- "output_format",
1186
+ "required_checks",
1187
+ [
1188
+ "Start by inspecting `git status --short` so unstaged, staged, and untracked changes are all visible.",
1189
+ `Review the patch against \`${comparisonBaseBranch}\` with working-tree-aware commands such as \`git diff ${comparisonBaseBranch}\` and \`git diff --cached ${comparisonBaseBranch}\`.`,
1190
+ "If untracked files are present, inspect them directly before deciding whether they belong in the PR.",
1191
+ "Read the implementation notes file and use its full contents as the body of a provider-appropriate PR/review comment after the pull request, merge request, or review exists.",
1192
+ "Detect the source-control and code-review provider from `git remote -v`, repository hosting URLs, configured CLI auth, and repository metadata before choosing a creation tool.",
1193
+ "Use the provider-appropriate tool for the detected remote: GitHub `gh pr create`, Azure DevOps/Azure Repos `az repos pr create`, GitLab `glab mr create` when available, Bitbucket's configured CLI/API workflow, or Sapling/Phabricator `sl`/Phabricator/Differential tooling used by the repository.",
1194
+ "Check the local Git identity with `git config user.name` and `git config user.email` so you can prefer the matching account when multiple provider accounts are logged in.",
1195
+ "Check provider credentials with non-destructive commands before attempting PR/review creation, such as `gh auth status`, `az account show`, `az repos pr list`, `glab auth status`, `sl` status/config commands, or the repository's documented Phabricator/Differential checks.",
1196
+ "If multiple accounts, hosts, or providers are available, use the remote URL and git config username/email as heuristics to choose the most likely identity, but try each available credential/account that can read the repository and create the provider-appropriate review request.",
1197
+ ].join("\n"),
1198
+ ],
1049
1199
  [
1050
- "Return Markdown with headings:",
1051
- "1. Change review — summary of files and diff scope inspected",
1052
- "2. PR status created PR URL, or why no PR was created",
1053
- "3. Implementation notes comment whether the PR comment was created as the last action, or why it could not be created",
1054
- "4. Commands run include exit status or clear outcome",
1055
- "5. Follow-up for the user exact next steps if credentials or repository state blocked PR creation",
1056
- ].join("\n"),
1200
+ "pr_policy",
1201
+ [
1202
+ "Create a provider-appropriate PR/MR/review request only if there are meaningful changes, a remote/branch target is available, credentials are available, and the current state is suitable for review.",
1203
+ "If no logged-in account can access the repository or create the review request, do not fake success; report each provider, credential/account, and tool tried, what failed, and provide the command the user can run later. Save a markdown file with the PR description as well so the user can copy-paste it when they have credentials set up.",
1204
+ "When you successfully create or update the review request, create a provider-appropriate comment containing the implementation notes file contents as the last action of this workflow stage.",
1205
+ "Worktrees are detached HEAD checkouts. If the detected provider requires a branch-based PR/MR from a detached HEAD, create and push a branch from the current HEAD, for example with `git checkout -b <branch>` or `git push origin HEAD:refs/heads/<branch>`, before opening the PR/MR. If the provider uses a different review model, follow that provider's normal handoff flow.",
1206
+ "Leave the worktree intact for retries or user recovery.",
1207
+ "If PR/MR/review creation is not possible, do not create a standalone comment elsewhere; include the implementation notes path and summary in your report instead.",
1208
+ "If the review loop did not approve, prefer reporting the remaining blockers over creating a PR/MR/review unless the changes are still intentionally ready for human review.",
1209
+ "Do not make unrelated code edits in this phase. Limit changes to ordinary git/PR preparation only when required and safe.",
1210
+ ].join("\n"),
1211
+ ],
1212
+ [
1213
+ "output_format",
1214
+ [
1215
+ "Return Markdown with headings:",
1216
+ "1. Change review — summary of files and diff scope inspected",
1217
+ "2. PR/review status — created PR/MR/review URL, or why no review request was created",
1218
+ "3. Implementation notes comment — whether the provider-appropriate comment was created as the last action, or why it could not be created",
1219
+ "4. Commands run — include exit status or clear outcome",
1220
+ "5. Follow-up for the user — exact next steps if credentials or repository state blocked PR creation",
1221
+ ].join("\n"),
1222
+ ],
1223
+ ]),
1224
+ reads: [
1225
+ ...(finalPlanPath ? [finalPlanPath] : []),
1226
+ implementationNotesPath,
1227
+ ...(latestReviewReportPath === undefined ? [] : [latestReviewReportPath]),
1057
1228
  ],
1058
- ]),
1059
- reads: [
1060
- ...(finalPlanPath ? [finalPlanPath] : []),
1061
- implementationNotesPath,
1062
- ...(latestReviewReportPath === undefined ? [] : [latestReviewReportPath]),
1063
- ],
1064
- ...orchestratorModelConfig,
1065
- });
1066
- finalPrReport = prResult.text;
1229
+ ...orchestratorModelConfig,
1230
+ });
1231
+ finalPrReport = prResult.text;
1232
+ }
1067
1233
 
1068
1234
  return {
1069
1235
  result: finalResult,
1070
1236
  plan: finalPlan,
1071
1237
  plan_path: finalPlanPath,
1072
1238
  implementation_notes_path: implementationNotesPath,
1073
- pr_report: finalPrReport,
1239
+ ...(finalPrReport === undefined ? {} : { pr_report: finalPrReport }),
1074
1240
  approved,
1075
1241
  iterations_completed: iterationsCompleted,
1076
1242
  review_report: compactReviewReport(latestReviewReportPath),
@@ -1080,7 +1246,7 @@ async function runRalphWorkflow(
1080
1246
 
1081
1247
  export default defineWorkflow("ralph")
1082
1248
  .description(
1083
- "Plan → orchestrate → simplify → parallel review loop with bounded iteration.",
1249
+ "Plan → orchestrate → parallel review loop with bounded iteration.",
1084
1250
  )
1085
1251
  .input("prompt", Type.String({ description: "The task or goal to plan, execute, and refine." }))
1086
1252
  .input("max_loops", Type.Number({
@@ -1094,7 +1260,12 @@ export default defineWorkflow("ralph")
1094
1260
  .input("git_worktree_dir", Type.String({
1095
1261
  default: "",
1096
1262
  description:
1097
- "Optional Git worktree path. Ralph must start inside a Git repo; absolute paths are used as-is, relative paths resolve from the repo root, existing Git worktrees from the invoking repository are reused/shared as-is, and missing paths are created from base_branch.",
1263
+ "Optional Git worktree path. Must start inside a Git repo; absolute paths are used as-is, relative paths resolve from the repo root, existing Git worktrees from the invoking repository are reused/shared as-is, and missing paths are created from base_branch.",
1264
+ }))
1265
+ .input("create_pr", Type.Boolean({
1266
+ default: false,
1267
+ description:
1268
+ "Whether to run the final pull-request creation stage. Defaults to false; prompt text alone does not opt in. Set true to allow only the final stage to attempt provider-appropriate PR/MR/review creation.",
1098
1269
  }))
1099
1270
  .worktreeFromInputs({
1100
1271
  gitWorktreeDir: "git_worktree_dir",
@@ -1104,11 +1275,11 @@ export default defineWorkflow("ralph")
1104
1275
  .output("plan", Type.Optional(Type.String({ description: "Latest RFC-style plan text." })))
1105
1276
  .output("plan_path", Type.Optional(Type.String({ description: "Path to the latest generated spec under specs/." })))
1106
1277
  .output("implementation_notes_path", Type.Optional(Type.String({ description: "OS-temp notes file containing decisions, deviations, blockers, and validation notes." })))
1107
- .output("pr_report", Type.Optional(Type.String({ description: "Pull-request preparation report with diff review, PR status, commands, and follow-up steps." })))
1108
- .output("approved", Type.Optional(Type.Boolean({ description: "Whether the reviewer loop approved before PR handoff." })))
1278
+ .output("pr_report", Type.Optional(Type.String({ description: "Pull-request report emitted only when create_pr=true and the final pull-request stage runs." })))
1279
+ .output("approved", Type.Optional(Type.Boolean({ description: "Whether the reviewer loop approved before completion or optional final handoff." })))
1109
1280
  .output("iterations_completed", Type.Optional(Type.Number({ description: "Number of plan/orchestrate/review loops completed." })))
1110
1281
  .output("review_report", Type.Optional(Type.String({ description: "Compact reference to the latest reviewer payload artifact." })))
1111
- .output("review_report_path", Type.Optional(Type.String({ description: "JSON artifact path for the latest Ralph review round." })))
1282
+ .output("review_report_path", Type.Optional(Type.String({ description: "JSON artifact path for the latest review round." })))
1112
1283
  .run(async (ctx) => {
1113
1284
  const workflowCtx = ctx;
1114
1285
  const workflowStartCwd = workflowCtx.cwd ?? process.cwd();
@@ -1119,11 +1290,13 @@ export default defineWorkflow("ralph")
1119
1290
  inputs.base_branch,
1120
1291
  "origin/main",
1121
1292
  );
1293
+ const createPr = inputs.create_pr === true;
1122
1294
  return await runRalphWorkflow(workflowCtx, {
1123
1295
  prompt,
1124
1296
  maxLoops,
1125
1297
  comparisonBaseBranch,
1126
1298
  workflowStartCwd,
1299
+ createPr,
1127
1300
  });
1128
1301
  })
1129
1302
  .compile();