specrails-desktop 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/.claude/commands/specrails/batch-implement.md +287 -0
  2. package/.claude/commands/specrails/compat-check.md +271 -0
  3. package/.claude/commands/specrails/doctor.md +62 -0
  4. package/.claude/commands/specrails/enrich.md +1635 -0
  5. package/.claude/commands/specrails/explore-spec.md +173 -0
  6. package/.claude/commands/specrails/health-check.md +527 -0
  7. package/.claude/commands/specrails/implement.md +1457 -0
  8. package/.claude/commands/specrails/memory-inspect.md +259 -0
  9. package/.claude/commands/specrails/opsx-diff.md +419 -0
  10. package/.claude/commands/specrails/propose-spec.md +102 -0
  11. package/.claude/commands/specrails/reconfig.md +89 -0
  12. package/.claude/commands/specrails/refactor-recommender.md +212 -0
  13. package/.claude/commands/specrails/retry.md +363 -0
  14. package/.claude/commands/specrails/telemetry.md +552 -0
  15. package/.claude/commands/specrails/why.md +96 -0
  16. package/LICENSE +21 -0
  17. package/README.md +290 -0
  18. package/cli/dist/specrails-desktop.js +1098 -0
  19. package/client/dist/assets/ActivityFeedPage-Gy4x8dBt.js +1 -0
  20. package/client/dist/assets/AgentsPage-CPgu--Fb.js +86 -0
  21. package/client/dist/assets/AnalyticsPage-B5sJEee2.js +1 -0
  22. package/client/dist/assets/BarChart-7IMQ8HY1.js +33 -0
  23. package/client/dist/assets/CodePage-CBdFvbwe.js +2 -0
  24. package/client/dist/assets/DesktopAnalyticsPage-w0rdTq4w.js +1 -0
  25. package/client/dist/assets/DocsDialog-BZUYM7wm.js +11 -0
  26. package/client/dist/assets/DocsPage-9QglWl46.js +11 -0
  27. package/client/dist/assets/ExportDropdown-BLZFXtNi.js +1 -0
  28. package/client/dist/assets/IntegrationsPage-BxBE4y99.js +3 -0
  29. package/client/dist/assets/JobDetailPage-DydWx_5S.js +16 -0
  30. package/client/dist/assets/JobsPage-20ibw0IO.js +1 -0
  31. package/client/dist/assets/abap-Bw6f2wDG.js +1 -0
  32. package/client/dist/assets/activity-BEIp_Y1A.js +1 -0
  33. package/client/dist/assets/activity-BdrPln96.js +1 -0
  34. package/client/dist/assets/activity-CpkRS8Sx.js +1 -0
  35. package/client/dist/assets/activity-DKCpESPt.js +1 -0
  36. package/client/dist/assets/activity-DOUVEjJi.js +1 -0
  37. package/client/dist/assets/activity-DRwkql_y.js +1 -0
  38. package/client/dist/assets/activity-DcDQ7tjw.js +1 -0
  39. package/client/dist/assets/activity-Dv6H7wEr.js +1 -0
  40. package/client/dist/assets/addon-image-3WCl5Vhd.js +1 -0
  41. package/client/dist/assets/addon-ligatures-C5OdliKs.js +2 -0
  42. package/client/dist/assets/addon-webgl-BbX6pSjl.js +44 -0
  43. package/client/dist/assets/addspec-B5yl4Loj.js +1 -0
  44. package/client/dist/assets/addspec-BEeF5-zc.js +1 -0
  45. package/client/dist/assets/addspec-D33ocMxf.js +1 -0
  46. package/client/dist/assets/addspec-DFswZ0jK.js +1 -0
  47. package/client/dist/assets/addspec-DRE-jZv7.js +1 -0
  48. package/client/dist/assets/addspec-DVZ15Jp8.js +1 -0
  49. package/client/dist/assets/addspec-Fkv91Opc.js +1 -0
  50. package/client/dist/assets/addspec-GWm4ffKl.js +1 -0
  51. package/client/dist/assets/agents-1nCDWRmP.js +1 -0
  52. package/client/dist/assets/agents-Bm9rPqnt.js +1 -0
  53. package/client/dist/assets/agents-CMxtJMLD.js +1 -0
  54. package/client/dist/assets/agents-DK-Dlc0i.js +1 -0
  55. package/client/dist/assets/agents-Q6Ldfpxx.js +1 -0
  56. package/client/dist/assets/agents-TeOSy-ax.js +1 -0
  57. package/client/dist/assets/agents-iTqjRajS.js +1 -0
  58. package/client/dist/assets/agents-s87sMGzL.js +1 -0
  59. package/client/dist/assets/agentstudio-B6Wb59E7.js +1 -0
  60. package/client/dist/assets/agentstudio-BADhZ41e.js +1 -0
  61. package/client/dist/assets/agentstudio-BSnWLR63.js +1 -0
  62. package/client/dist/assets/agentstudio-BdidyBzZ.js +1 -0
  63. package/client/dist/assets/agentstudio-CxlUllqI.js +1 -0
  64. package/client/dist/assets/agentstudio-D3I62TLJ.js +1 -0
  65. package/client/dist/assets/agentstudio-DuH9TogZ.js +1 -0
  66. package/client/dist/assets/agentstudio-Kw88_dUF.js +1 -0
  67. package/client/dist/assets/aiedit-BWxHGsYA.js +1 -0
  68. package/client/dist/assets/aiedit-D2ji6Qy0.js +1 -0
  69. package/client/dist/assets/aiedit-DAhZTvtk.js +1 -0
  70. package/client/dist/assets/aiedit-DJMny-D5.js +1 -0
  71. package/client/dist/assets/aiedit-DOcxERkU.js +1 -0
  72. package/client/dist/assets/aiedit-DvrcbwGv.js +1 -0
  73. package/client/dist/assets/aiedit-TTwzL1TS.js +1 -0
  74. package/client/dist/assets/aiedit-WBSjT_C1.js +1 -0
  75. package/client/dist/assets/analytics-BIdr0YfL.js +1 -0
  76. package/client/dist/assets/analytics-C6EzgtdE.js +1 -0
  77. package/client/dist/assets/analytics-C9Zc-rkM.js +1 -0
  78. package/client/dist/assets/analytics-CVx3YOc0.js +1 -0
  79. package/client/dist/assets/analytics-CYj0tfj7.js +1 -0
  80. package/client/dist/assets/analytics-CnY4kNG3.js +1 -0
  81. package/client/dist/assets/analytics-CrPCZRJ-.js +1 -0
  82. package/client/dist/assets/analytics-DMCto-TF.js +1 -0
  83. package/client/dist/assets/apex-Cw8_REBo.js +1 -0
  84. package/client/dist/assets/atom-one-dark-B-oHczHB.css +1 -0
  85. package/client/dist/assets/attachments-BIsSSnHJ.js +1 -0
  86. package/client/dist/assets/attachments-BW4L3l2L.js +1 -0
  87. package/client/dist/assets/attachments-Bcf6BG6V.js +1 -0
  88. package/client/dist/assets/attachments-Bke8sCU4.js +1 -0
  89. package/client/dist/assets/attachments-COcrGRFz.js +1 -0
  90. package/client/dist/assets/attachments-DYHGA2Dj.js +1 -0
  91. package/client/dist/assets/attachments-Dd92KpUH.js +1 -0
  92. package/client/dist/assets/attachments-DzdU6DV6.js +1 -0
  93. package/client/dist/assets/azcli-Cz6HAoOw.js +1 -0
  94. package/client/dist/assets/bat-CcJ-xyqL.js +1 -0
  95. package/client/dist/assets/bicep-z1WDCKYz.js +2 -0
  96. package/client/dist/assets/browser-5ErDlJoR.js +1 -0
  97. package/client/dist/assets/browser-Bc-YdlVg.js +1 -0
  98. package/client/dist/assets/browser-BlYF4OOq.js +1 -0
  99. package/client/dist/assets/browser-CT-ReZGt.js +1 -0
  100. package/client/dist/assets/browser-DGITz3fC.js +1 -0
  101. package/client/dist/assets/browser-JsAIGCEW.js +1 -0
  102. package/client/dist/assets/browser-M5-rbPlw.js +1 -0
  103. package/client/dist/assets/browser-Qya9cARy.js +1 -0
  104. package/client/dist/assets/cameligo-BRewOpfa.js +1 -0
  105. package/client/dist/assets/chat-BEGuC03z.js +1 -0
  106. package/client/dist/assets/chat-BEW60P_u.js +1 -0
  107. package/client/dist/assets/chat-BQNMD0PL.js +1 -0
  108. package/client/dist/assets/chat-BsbNGPW9.js +1 -0
  109. package/client/dist/assets/chat-CboQguCi.js +1 -0
  110. package/client/dist/assets/chat-DRCa9pOt.js +1 -0
  111. package/client/dist/assets/chat-DwUm6W9z.js +1 -0
  112. package/client/dist/assets/chat-yoXwguQu.js +1 -0
  113. package/client/dist/assets/chunk-CilyBKbf.js +1 -0
  114. package/client/dist/assets/clojure-DBjRWN6g.js +1 -0
  115. package/client/dist/assets/clsx-DnqN-uhr.js +1 -0
  116. package/client/dist/assets/code-AL1rVIMb.js +1 -0
  117. package/client/dist/assets/code-C0BKpkht.js +1 -0
  118. package/client/dist/assets/code-C0FTS3ew.js +1 -0
  119. package/client/dist/assets/code-CPcHxzxw.js +1 -0
  120. package/client/dist/assets/code-D3ryDniw.js +1 -0
  121. package/client/dist/assets/code-D3zVVQTj.js +1 -0
  122. package/client/dist/assets/code-PCmfS3dn.js +1 -0
  123. package/client/dist/assets/code-exI0G5Wd.js +1 -0
  124. package/client/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  125. package/client/dist/assets/coffee-Cfk_XHGR.js +1 -0
  126. package/client/dist/assets/commands-B772IyDa.js +1 -0
  127. package/client/dist/assets/commands-BDDp6xFG.js +1 -0
  128. package/client/dist/assets/commands-CJxCry-o.js +1 -0
  129. package/client/dist/assets/commands-CfgY-_of.js +1 -0
  130. package/client/dist/assets/commands-DLrvnPNg.js +1 -0
  131. package/client/dist/assets/commands-IXMOKBYt.js +1 -0
  132. package/client/dist/assets/commands-UD1NzmwX.js +1 -0
  133. package/client/dist/assets/commands-sqrqsxyE.js +1 -0
  134. package/client/dist/assets/common-DCr6VzJ7.js +1 -0
  135. package/client/dist/assets/common-Dard9UNH.js +1 -0
  136. package/client/dist/assets/common-DeDELLZJ.js +1 -0
  137. package/client/dist/assets/common-DltqHaAe.js +1 -0
  138. package/client/dist/assets/common-Dmm1GhdD.js +1 -0
  139. package/client/dist/assets/common-DnjcgkPH.js +1 -0
  140. package/client/dist/assets/common-GbpxfPG8.js +1 -0
  141. package/client/dist/assets/common-wA36jmj1.js +1 -0
  142. package/client/dist/assets/cpp-BVob6BaP.js +1 -0
  143. package/client/dist/assets/csharp-C4fbRuOu.js +1 -0
  144. package/client/dist/assets/csp-DthFP_vT.js +1 -0
  145. package/client/dist/assets/css-CGMH0hcW.js +3 -0
  146. package/client/dist/assets/css.worker-Wv5dxAWO.js +89 -0
  147. package/client/dist/assets/cssMode-Cc6ozl-J.js +1 -0
  148. package/client/dist/assets/cypher-Pnf68BRV.js +1 -0
  149. package/client/dist/assets/dart-PMMOtxZX.js +1 -0
  150. package/client/dist/assets/dashboard-B4ixDVk8.js +1 -0
  151. package/client/dist/assets/dashboard-BZBADHSj.js +1 -0
  152. package/client/dist/assets/dashboard-C1MfeUHs.js +1 -0
  153. package/client/dist/assets/dashboard-C7SK6xu5.js +1 -0
  154. package/client/dist/assets/dashboard-CB6Le1yN.js +1 -0
  155. package/client/dist/assets/dashboard-CoTpMOBM.js +1 -0
  156. package/client/dist/assets/dashboard-Duo4DDCW.js +1 -0
  157. package/client/dist/assets/dashboard-I19DXBxw.js +1 -0
  158. package/client/dist/assets/dist-js-BY-Fv_fg.js +1 -0
  159. package/client/dist/assets/dist-js-Bakc4uxT.js +1 -0
  160. package/client/dist/assets/dockerfile-di1nsJCc.js +1 -0
  161. package/client/dist/assets/ecl-D_WVcB5M.js +1 -0
  162. package/client/dist/assets/editor-Br_kD0ds.css +1 -0
  163. package/client/dist/assets/editor.api2-XLGzZfbc.js +872 -0
  164. package/client/dist/assets/editor.main-CfXxHimg.js +6 -0
  165. package/client/dist/assets/editor.worker-Bd9IXS8d.js +26 -0
  166. package/client/dist/assets/elixir-OAdJEMOn.js +1 -0
  167. package/client/dist/assets/explore-4mFpnrKU.js +1 -0
  168. package/client/dist/assets/explore-A8Ltoblq.js +1 -0
  169. package/client/dist/assets/explore-B9A3iN2W.js +1 -0
  170. package/client/dist/assets/explore-BV5Xxlsn.js +1 -0
  171. package/client/dist/assets/explore-BrBJvfjP.js +1 -0
  172. package/client/dist/assets/explore-C3FSE42C.js +1 -0
  173. package/client/dist/assets/explore-D2EFgt8J.js +1 -0
  174. package/client/dist/assets/explore-hFc3HFcp.js +1 -0
  175. package/client/dist/assets/flow9-D3QEZjgn.js +1 -0
  176. package/client/dist/assets/format-command-CwGuwzGA.js +1 -0
  177. package/client/dist/assets/freemarker2-DP7J1gG3.js +3 -0
  178. package/client/dist/assets/fsharp-BF0k_8N8.js +1 -0
  179. package/client/dist/assets/go-BAQO5Jsz.js +1 -0
  180. package/client/dist/assets/graphql-hdFVFkiV.js +1 -0
  181. package/client/dist/assets/handlebars-BjRlucw6.js +1 -0
  182. package/client/dist/assets/hcl-DWnl1o-X.js +1 -0
  183. package/client/dist/assets/html-OumBQJ-U.js +1 -0
  184. package/client/dist/assets/html.worker-CQP8QQsS.js +502 -0
  185. package/client/dist/assets/htmlMode-CStc3zXM.js +1 -0
  186. package/client/dist/assets/index-CimDRRi7.css +2 -0
  187. package/client/dist/assets/index-XGZaKl_u.js +142 -0
  188. package/client/dist/assets/ini-CB-6OVu3.js +1 -0
  189. package/client/dist/assets/integrations-C3p12Ms6.js +1 -0
  190. package/client/dist/assets/integrations-Cr6hH7XR.js +1 -0
  191. package/client/dist/assets/integrations-Cublz3m6.js +1 -0
  192. package/client/dist/assets/integrations-D28q1kF6.js +1 -0
  193. package/client/dist/assets/integrations-DRdbki5W.js +1 -0
  194. package/client/dist/assets/integrations-DaC4SzzL.js +1 -0
  195. package/client/dist/assets/integrations-DmQYCUvN.js +1 -0
  196. package/client/dist/assets/integrations-HIlUxXVs.js +1 -0
  197. package/client/dist/assets/java-d1CmfiHX.js +1 -0
  198. package/client/dist/assets/javascript-CMk--e7g.js +1 -0
  199. package/client/dist/assets/jobs-BE1siB0M.js +1 -0
  200. package/client/dist/assets/jobs-BHcQ_Faf.js +1 -0
  201. package/client/dist/assets/jobs-CFfc2dNX.js +1 -0
  202. package/client/dist/assets/jobs-CSi5n8X_.js +1 -0
  203. package/client/dist/assets/jobs-Dc3X86PY.js +1 -0
  204. package/client/dist/assets/jobs-De5tASex.js +1 -0
  205. package/client/dist/assets/jobs-DsoXEdo7.js +1 -0
  206. package/client/dist/assets/jobs-Wl-ApPMb.js +1 -0
  207. package/client/dist/assets/json.worker-DzV-CpCQ.js +58 -0
  208. package/client/dist/assets/jsonMode-C2h3ZcjZ.js +7 -0
  209. package/client/dist/assets/julia-Bgv08lKa.js +1 -0
  210. package/client/dist/assets/kotlin-u98kaVTf.js +1 -0
  211. package/client/dist/assets/less-CjYwpgg5.js +2 -0
  212. package/client/dist/assets/lexon-YTjaAFBB.js +1 -0
  213. package/client/dist/assets/lib-CPxTMOAq.js +7 -0
  214. package/client/dist/assets/liquid-mI3KJrBE.js +1 -0
  215. package/client/dist/assets/lspLanguageFeatures-DU09ggWi.js +4 -0
  216. package/client/dist/assets/lua-BzmkWv27.js +1 -0
  217. package/client/dist/assets/m3-CFwk9fw0.js +1 -0
  218. package/client/dist/assets/markdown-CR5iMpSZ.js +1 -0
  219. package/client/dist/assets/mdx-C41VDTR_.js +1 -0
  220. package/client/dist/assets/mips-CcEalc17.js +1 -0
  221. package/client/dist/assets/monaco.contribution-CPObAXMC.js +2 -0
  222. package/client/dist/assets/msdax-BQbkawnr.js +1 -0
  223. package/client/dist/assets/mysql-GTlaaW_P.js +1 -0
  224. package/client/dist/assets/nav-0fwkrgHt.js +1 -0
  225. package/client/dist/assets/nav-BEL3MTwK.js +1 -0
  226. package/client/dist/assets/nav-B_G-TJDW.js +1 -0
  227. package/client/dist/assets/nav-C2YXcbZS.js +1 -0
  228. package/client/dist/assets/nav-ClzOE4mA.js +1 -0
  229. package/client/dist/assets/nav-CtYwmMgu.js +1 -0
  230. package/client/dist/assets/nav-D2bOGSEg.js +1 -0
  231. package/client/dist/assets/nav-iH1V5j6o.js +1 -0
  232. package/client/dist/assets/objective-c-Byu1T5if.js +1 -0
  233. package/client/dist/assets/pascal-BrfzBfRm.js +1 -0
  234. package/client/dist/assets/pascaligo-BXXKFUeo.js +1 -0
  235. package/client/dist/assets/perl-B3OikKq-.js +1 -0
  236. package/client/dist/assets/pgsql-CTsa0Acc.js +1 -0
  237. package/client/dist/assets/php-DiQh3FUW.js +1 -0
  238. package/client/dist/assets/pla-92uH8Fzm.js +1 -0
  239. package/client/dist/assets/postiats-BbeWkKUr.js +1 -0
  240. package/client/dist/assets/powerquery-DgDMzpsm.js +1 -0
  241. package/client/dist/assets/powershell-BfdUUzaG.js +1 -0
  242. package/client/dist/assets/preload-helper-DSXbuxSR.js +1 -0
  243. package/client/dist/assets/protobuf-BojW2ftW.js +2 -0
  244. package/client/dist/assets/pug-BxqTg3IU.js +1 -0
  245. package/client/dist/assets/python-Y27rKQtk.js +1 -0
  246. package/client/dist/assets/qsharp-BX_A-MW9.js +1 -0
  247. package/client/dist/assets/r-D9BMnxvJ.js +1 -0
  248. package/client/dist/assets/razor-Cd5-q9Bp.js +1 -0
  249. package/client/dist/assets/redis-5cJqEQJJ.js +1 -0
  250. package/client/dist/assets/redshift-d8BBqiwb.js +1 -0
  251. package/client/dist/assets/restructuredtext-C8a6yIcZ.js +1 -0
  252. package/client/dist/assets/ruby-egeh-6KX.js +1 -0
  253. package/client/dist/assets/rust-a3r9IInB.js +1 -0
  254. package/client/dist/assets/sb-y8iRIDei.js +1 -0
  255. package/client/dist/assets/scala-BPDK2AmK.js +1 -0
  256. package/client/dist/assets/scheme-BIWUEoOs.js +1 -0
  257. package/client/dist/assets/scss-CA-PSzwg.js +3 -0
  258. package/client/dist/assets/settings-55oDcbSh.js +1 -0
  259. package/client/dist/assets/settings-Bd4Tq1RB.js +1 -0
  260. package/client/dist/assets/settings-CCSM-Fhn.js +1 -0
  261. package/client/dist/assets/settings-D3e_bDoW.js +1 -0
  262. package/client/dist/assets/settings-DKbTkbn7.js +1 -0
  263. package/client/dist/assets/settings-Dxpo6_w7.js +1 -0
  264. package/client/dist/assets/settings-bt84e3Aa.js +1 -0
  265. package/client/dist/assets/settings-nu68QukM.js +1 -0
  266. package/client/dist/assets/setup-BMqwfbW9.js +1 -0
  267. package/client/dist/assets/setup-Bb5LcG28.js +1 -0
  268. package/client/dist/assets/setup-BeEx2_da.js +1 -0
  269. package/client/dist/assets/setup-CCCrB53Q.js +1 -0
  270. package/client/dist/assets/setup-CJA0ATmd.js +1 -0
  271. package/client/dist/assets/setup-CeiDbZcb.js +1 -0
  272. package/client/dist/assets/setup-Cus7TApA.js +1 -0
  273. package/client/dist/assets/setup-D9qOs2Xo.js +1 -0
  274. package/client/dist/assets/shell--LiT1Bja.js +1 -0
  275. package/client/dist/assets/solidity-DdqZccZg.js +1 -0
  276. package/client/dist/assets/sophia-S6-YxNG_.js +1 -0
  277. package/client/dist/assets/sparql-BSf5kMp2.js +1 -0
  278. package/client/dist/assets/specs-BFfu3u-a.js +1 -0
  279. package/client/dist/assets/specs-B__C8-8a.js +1 -0
  280. package/client/dist/assets/specs-CZ1PsXsC.js +1 -0
  281. package/client/dist/assets/specs-D2FzlLn9.js +1 -0
  282. package/client/dist/assets/specs-DaUTrNF9.js +1 -0
  283. package/client/dist/assets/specs-Dyc5hYeE.js +1 -0
  284. package/client/dist/assets/specs-cKEh2LXt.js +1 -0
  285. package/client/dist/assets/specs-k0PyLDVt.js +1 -0
  286. package/client/dist/assets/sql-D7KgjR8G.js +1 -0
  287. package/client/dist/assets/st-BnoDa-Ml.js +1 -0
  288. package/client/dist/assets/swift-DEUHTkUX.js +1 -0
  289. package/client/dist/assets/systemverilog-Tqb_KPnW.js +1 -0
  290. package/client/dist/assets/tcl-BmBFS2qq.js +1 -0
  291. package/client/dist/assets/terminal-80yDMgMF.js +1 -0
  292. package/client/dist/assets/terminal-Bje4ziIa.js +1 -0
  293. package/client/dist/assets/terminal-C2WYcFHF.js +1 -0
  294. package/client/dist/assets/terminal-CSONJOex.js +1 -0
  295. package/client/dist/assets/terminal-DEqzGtcr.js +1 -0
  296. package/client/dist/assets/terminal-DeWzh6ys.js +1 -0
  297. package/client/dist/assets/terminal-YOlsJCQj.js +1 -0
  298. package/client/dist/assets/terminal-lkZYR4wJ.js +1 -0
  299. package/client/dist/assets/tickets-CB7N30gm.js +1 -0
  300. package/client/dist/assets/tickets-CF2PYelu.js +1 -0
  301. package/client/dist/assets/tickets-DNOANUXr.js +1 -0
  302. package/client/dist/assets/tickets-DU1aqsbr.js +1 -0
  303. package/client/dist/assets/tickets-DYvafSaY.js +1 -0
  304. package/client/dist/assets/tickets-DlpC_iTg.js +1 -0
  305. package/client/dist/assets/tickets-DucYgtdl.js +1 -0
  306. package/client/dist/assets/tickets-clefmXLv.js +1 -0
  307. package/client/dist/assets/ts.worker-METxwbDZ.js +67719 -0
  308. package/client/dist/assets/tsMode-B0y_xEci.js +11 -0
  309. package/client/dist/assets/twig-BQV8igWC.js +1 -0
  310. package/client/dist/assets/typescript-BzK0OgwW.js +1 -0
  311. package/client/dist/assets/typespec-DlFroUGY.js +1 -0
  312. package/client/dist/assets/useProjectCache-DSaiGFjV.js +1 -0
  313. package/client/dist/assets/vb-BlrJpIMX.js +1 -0
  314. package/client/dist/assets/wgsl-BWgIc6FZ.js +298 -0
  315. package/client/dist/assets/workers-rt--R2Qy.js +1 -0
  316. package/client/dist/assets/xml-eX9QXAmI.js +1 -0
  317. package/client/dist/assets/yaml-fcsNkpOt.js +1 -0
  318. package/client/dist/index.html +246 -0
  319. package/docs/README.md +54 -0
  320. package/docs/cli.md +198 -0
  321. package/docs/codex.md +210 -0
  322. package/docs/creating-specs.md +197 -0
  323. package/docs/customizing.md +197 -0
  324. package/docs/getting-started.md +140 -0
  325. package/docs/internals/README.md +25 -0
  326. package/docs/internals/adding-a-provider.md +238 -0
  327. package/docs/internals/api-reference.md +634 -0
  328. package/docs/internals/architecture.md +332 -0
  329. package/docs/internals/configuration.md +172 -0
  330. package/docs/internals/openspec-workflow.md +282 -0
  331. package/docs/internals/operations-runbook.md +198 -0
  332. package/docs/internals/profiles.md +152 -0
  333. package/docs/platforms/macos.md +130 -0
  334. package/docs/platforms/windows.md +81 -0
  335. package/docs/running-pipelines.md +240 -0
  336. package/docs/terminal.md +138 -0
  337. package/docs/tracking-cost.md +155 -0
  338. package/package.json +82 -0
  339. package/server/dist/agent-generator.js +232 -0
  340. package/server/dist/agent-refine-db.js +124 -0
  341. package/server/dist/agent-refine-manager.js +526 -0
  342. package/server/dist/ai-invocations.js +111 -0
  343. package/server/dist/attachment-manager.js +299 -0
  344. package/server/dist/auth.js +207 -0
  345. package/server/dist/binary-probe.js +35 -0
  346. package/server/dist/browser-capture-manager.js +576 -0
  347. package/server/dist/browser-capture-types.js +28 -0
  348. package/server/dist/browser-network.js +149 -0
  349. package/server/dist/browser-playwright.js +888 -0
  350. package/server/dist/build-dirs.js +44 -0
  351. package/server/dist/changes-reader.js +120 -0
  352. package/server/dist/chat-manager.js +1060 -0
  353. package/server/dist/chromium-resolver.js +311 -0
  354. package/server/dist/code-explorer-router.js +788 -0
  355. package/server/dist/codex-otel-bridge.js +235 -0
  356. package/server/dist/command-resolver.js +102 -0
  357. package/server/dist/config.js +306 -0
  358. package/server/dist/context-budget.js +113 -0
  359. package/server/dist/context-scope.js +279 -0
  360. package/server/dist/contract-refine-runner.js +521 -0
  361. package/server/dist/core-compat.js +207 -0
  362. package/server/dist/core-package.js +14 -0
  363. package/server/dist/db.js +1034 -0
  364. package/server/dist/desktop-analytics.js +156 -0
  365. package/server/dist/desktop-db.js +456 -0
  366. package/server/dist/desktop-router.js +735 -0
  367. package/server/dist/docs-router.js +207 -0
  368. package/server/dist/explore-contract-refine.js +421 -0
  369. package/server/dist/explore-cwd-manager.js +242 -0
  370. package/server/dist/explore-draft-title.js +47 -0
  371. package/server/dist/explore-smash.js +450 -0
  372. package/server/dist/feature-flags.js +17 -0
  373. package/server/dist/file-provenance.js +382 -0
  374. package/server/dist/file-summary-generator.js +221 -0
  375. package/server/dist/file-summary-manager.js +689 -0
  376. package/server/dist/hooks.js +102 -0
  377. package/server/dist/ids.js +7 -0
  378. package/server/dist/index.js +586 -0
  379. package/server/dist/metrics.js +136 -0
  380. package/server/dist/mobile/index.js +16 -0
  381. package/server/dist/mobile/mobile-admin-router.js +84 -0
  382. package/server/dist/mobile/mobile-auth.js +67 -0
  383. package/server/dist/mobile/mobile-devices.js +80 -0
  384. package/server/dist/mobile/mobile-event-bus.js +39 -0
  385. package/server/dist/mobile/mobile-gateway.js +285 -0
  386. package/server/dist/mobile/mobile-mdns.js +81 -0
  387. package/server/dist/mobile/mobile-pairing.js +179 -0
  388. package/server/dist/mobile/mobile-redact.js +53 -0
  389. package/server/dist/mobile/mobile-router.js +411 -0
  390. package/server/dist/mobile/mobile-tls.js +86 -0
  391. package/server/dist/mobile/mobile-types.js +9 -0
  392. package/server/dist/mobile/mobile-ws.js +275 -0
  393. package/server/dist/path-resolver.js +298 -0
  394. package/server/dist/plugin-manager.js +617 -0
  395. package/server/dist/plugins/claude-approval.js +179 -0
  396. package/server/dist/plugins/claude-md-mutation.js +146 -0
  397. package/server/dist/plugins/codex-mcp.js +108 -0
  398. package/server/dist/plugins/contributors.js +72 -0
  399. package/server/dist/plugins/drift.js +58 -0
  400. package/server/dist/plugins/index.js +14 -0
  401. package/server/dist/plugins/json-mutation.js +120 -0
  402. package/server/dist/plugins/manager.js +32 -0
  403. package/server/dist/plugins/ownership.js +86 -0
  404. package/server/dist/plugins/paths.js +37 -0
  405. package/server/dist/plugins/prereq-installer.js +104 -0
  406. package/server/dist/plugins/rail-integration.js +79 -0
  407. package/server/dist/plugins/serena/index.js +13 -0
  408. package/server/dist/plugins/serena/install.js +91 -0
  409. package/server/dist/plugins/serena/instructions-content.js +21 -0
  410. package/server/dist/plugins/serena/manifest.js +111 -0
  411. package/server/dist/plugins/serena/verify.js +78 -0
  412. package/server/dist/plugins-router.js +215 -0
  413. package/server/dist/pricing.js +89 -0
  414. package/server/dist/profile-manager.js +310 -0
  415. package/server/dist/profiles-router.js +759 -0
  416. package/server/dist/project-registry.js +443 -0
  417. package/server/dist/project-router.js +4016 -0
  418. package/server/dist/proposal-manager.js +291 -0
  419. package/server/dist/provider-selection.js +69 -0
  420. package/server/dist/providers/claude-adapter.js +281 -0
  421. package/server/dist/providers/codex-adapter.js +264 -0
  422. package/server/dist/providers/index.js +23 -0
  423. package/server/dist/providers/registry.js +37 -0
  424. package/server/dist/providers/types.js +22 -0
  425. package/server/dist/queue-manager.js +1511 -0
  426. package/server/dist/rails-router.js +362 -0
  427. package/server/dist/rails-store.js +116 -0
  428. package/server/dist/result-event.js +106 -0
  429. package/server/dist/schemas/profile.v1.json +151 -0
  430. package/server/dist/setup-manager.js +1165 -0
  431. package/server/dist/setup-prerequisites.js +372 -0
  432. package/server/dist/smash-runner.js +663 -0
  433. package/server/dist/spec-draft-parser.js +133 -0
  434. package/server/dist/spec-launcher-manager.js +174 -0
  435. package/server/dist/spec-models.js +32 -0
  436. package/server/dist/specrails-tech-client.js +82 -0
  437. package/server/dist/spending.js +448 -0
  438. package/server/dist/telemetry-compactor.js +180 -0
  439. package/server/dist/telemetry-export.js +317 -0
  440. package/server/dist/telemetry-receiver.js +224 -0
  441. package/server/dist/terminal-manager.js +633 -0
  442. package/server/dist/terminal-marks-store.js +117 -0
  443. package/server/dist/terminal-osc-parser.js +159 -0
  444. package/server/dist/terminal-settings.js +282 -0
  445. package/server/dist/terminal-shell-integration.js +196 -0
  446. package/server/dist/ticket-broadcast.js +47 -0
  447. package/server/dist/ticket-store.js +397 -0
  448. package/server/dist/ticket-watcher.js +117 -0
  449. package/server/dist/types.js +10 -0
  450. package/server/dist/user-mcp-config.js +117 -0
  451. package/server/dist/util/cli-prompt.js +181 -0
  452. package/server/dist/util/secure-fs.js +50 -0
  453. package/server/dist/util/win-spawn.js +43 -0
  454. package/server/dist/webhook-manager.js +89 -0
  455. package/server/dist/ws-routing.js +47 -0
@@ -0,0 +1,1457 @@
1
+ # Implementation Pipeline
2
+
3
+ Full OpenSpec lifecycle with specialized agents: architect designs, developer implements, reviewer validates and archives. Handles 1 to N features — adapts automatically (sequential for 1, parallel with worktrees for N).
4
+
5
+ **MANDATORY: Always follow this pipeline exactly as written. NEVER skip, shortcut, or "optimize away" any phase — even if the task seems simple enough to do directly. The orchestrator MUST launch the architect, developer, and reviewer agents as specified. Do NOT implement changes yourself in the main conversation; delegate to the agents defined in each phase. No exceptions.**
6
+
7
+ **Input:** $ARGUMENTS — accepts three modes:
8
+
9
+ 1. **Issue numbers** (recommended): `#85, #71, #63` — implement these specific GitHub Issues directly. Skips exploration and selection.
10
+ 2. **Text description** (single feature): `"add price history chart"` — implement a single feature from a description. Skips exploration and selection.
11
+ 3. **Area names** (fallback): `Analytics, UI, Testing` — explores areas and picks the best items. Only use if no backlog issues exist.
12
+
13
+ **IMPORTANT:** Before running, ensure Read/Write/Bash/Glob/Grep permissions are set to "allow" — background agents cannot request permissions interactively.
14
+
15
+ ---
16
+
17
+ ## Phase -1: Environment Setup (cloud pre-flight)
18
+
19
+ **This phase runs BEFORE anything else.** Detect if we're in a cloud/remote environment and ensure all required tools are available.
20
+
21
+ ### Detection
22
+
23
+ Check the environment variable `CLAUDE_CODE_ENTRYPOINT`. If it contains `remote_mobile` or `remote_web`, OR if `CLAUDE_CODE_REMOTE` is `true`, we're in a **cloud environment**.
24
+
25
+ ### Checks to run (sequential, fail-fast)
26
+
27
+ #### 1. Backlog provider availability
28
+
29
+ Read `.specrails/backlog-config.json` and extract `BACKLOG_PROVIDER`.
30
+
31
+ **If `BACKLOG_PROVIDER=local`:**
32
+ ```bash
33
+ [[ -f ".specrails/local-tickets.json" ]] && echo "Local tickets storage: OK" || echo "WARNING: local-tickets.json not found"
34
+ ```
35
+ - Set `LOCAL_TICKETS_AVAILABLE=true/false` based on file existence.
36
+ - Set `GH_AVAILABLE=false` (GitHub CLI not needed for local provider).
37
+ - Set `BACKLOG_AVAILABLE=true` if local-tickets.json exists.
38
+
39
+ **Otherwise:**
40
+ ```bash
41
+ gh auth status 2>&1
42
+ ```
43
+ - Set `GH_AVAILABLE=true/false` for later phases.
44
+
45
+ #### 2. OpenSpec CLI
46
+
47
+ ```bash
48
+ which openspec && openspec --version
49
+ ```
50
+
51
+ - If missing: try `npm install -g @fission-ai/openspec`
52
+ - If install fails: **STOP** — openspec is required.
53
+
54
+ #### 3. Project dependencies
55
+
56
+
57
+
58
+ #### 4. Test runner
59
+
60
+
61
+
62
+ #### 5. Agent discovery
63
+
64
+ Agent discovery runs in one of two modes: **profile mode** (a profile JSON is active) or **legacy mode** (no profile — identical to pre-4.1.0 behavior).
65
+
66
+ ##### Profile detection
67
+
68
+ A profile is active when either condition holds:
69
+
70
+ 1. The environment variable `SPECRAILS_PROFILE_PATH` is set AND points to a readable file. Tools like `specrails-desktop` set this to a job-scoped snapshot.
71
+ 2. The file `.specrails/profiles/project-default.json` exists and is readable.
72
+
73
+ If condition 1 holds, use `$SPECRAILS_PROFILE_PATH` as the profile path. Otherwise, if condition 2 holds, use `.specrails/profiles/project-default.json`. Otherwise, fall through to **legacy mode**.
74
+
75
+ ##### Preflight: `jq` availability (profile mode only)
76
+
77
+ When running in profile mode, `jq` is required to read the profile JSON. Run:
78
+
79
+ ```bash
80
+ command -v jq >/dev/null 2>&1 || { echo "[error] 'jq' is required for profile-aware mode. Install with: brew install jq / apt install jq / https://stedolan.github.io/jq/"; exit 1; }
81
+ ```
82
+
83
+ ##### Profile mode — load, validate, populate
84
+
85
+ Read the profile:
86
+
87
+ ```bash
88
+ PROFILE="$(cat "$PROFILE_PATH")"
89
+ ```
90
+
91
+ Validate the schema version. Only `schemaVersion: 1` is supported:
92
+
93
+ ```bash
94
+ SCHEMA_VERSION="$(jq -r '.schemaVersion // empty' <<<"$PROFILE")"
95
+ case "$SCHEMA_VERSION" in
96
+ 1) ;;
97
+ "") echo "[error] profile validation failed: missing required field 'schemaVersion'"; exit 1 ;;
98
+ *) echo "[error] profile validation failed: unsupported schemaVersion '$SCHEMA_VERSION'. Supported: 1"; exit 1 ;;
99
+ esac
100
+ ```
101
+
102
+ Validate required top-level fields. Every valid v1 profile MUST contain `name`, `orchestrator.model`, `agents` (non-empty array), and `routing` (non-empty array):
103
+
104
+ ```bash
105
+ for field in name orchestrator agents routing; do
106
+ jq -e ".$field" <<<"$PROFILE" >/dev/null 2>&1 || { echo "[error] profile validation failed: missing required field '$field'"; exit 1; }
107
+ done
108
+ jq -e '.orchestrator.model' <<<"$PROFILE" >/dev/null 2>&1 || { echo "[error] profile validation failed: missing required field 'orchestrator.model'"; exit 1; }
109
+ jq -e '.agents | length > 0' <<<"$PROFILE" >/dev/null 2>&1 || { echo "[error] profile validation failed: 'agents' must be a non-empty array"; exit 1; }
110
+ jq -e '.routing | length > 0' <<<"$PROFILE" >/dev/null 2>&1 || { echo "[error] profile validation failed: 'routing' must be a non-empty array"; exit 1; }
111
+ ```
112
+
113
+ Validate baseline agents — `sr-architect`, `sr-developer`, and `sr-reviewer` MUST appear in `agents[]`:
114
+
115
+ ```bash
116
+ for required in sr-architect sr-developer sr-reviewer; do
117
+ jq -e --arg id "$required" '[.agents[].id] | index($id)' <<<"$PROFILE" >/dev/null 2>&1 \
118
+ || { echo "[error] profile validation failed: required baseline agent '$required' missing from 'agents[]'"; exit 1; }
119
+ done
120
+ ```
121
+
122
+ Validate routing terminal rule — exactly one entry SHALL have `default: true` and it MUST be the last element:
123
+
124
+ ```bash
125
+ DEFAULT_COUNT="$(jq '[.routing[] | select(.default == true)] | length' <<<"$PROFILE")"
126
+ if [[ "$DEFAULT_COUNT" -ne 1 ]]; then
127
+ echo "[error] profile validation failed: routing must contain exactly one entry with 'default: true' (found $DEFAULT_COUNT)"; exit 1
128
+ fi
129
+ IS_LAST="$(jq '(.routing | last | .default) == true' <<<"$PROFILE")"
130
+ if [[ "$IS_LAST" != "true" ]]; then
131
+ echo "[error] profile validation failed: the 'default: true' routing rule must be the last element of 'routing'"; exit 1
132
+ fi
133
+ ```
134
+
135
+ Populate `AVAILABLE_AGENTS` from the profile and verify each referenced agent file exists on disk:
136
+
137
+ ```bash
138
+ AVAILABLE_AGENTS="$(jq -r '.agents[].id' <<<"$PROFILE" | sort)"
139
+ for id in $AVAILABLE_AGENTS; do
140
+ [[ -f ".claude/agents/$id.md" ]] \
141
+ || { echo "[error] profile references agent '$id' but .claude/agents/$id.md does not exist"; exit 1; }
142
+ done
143
+ ```
144
+
145
+ Also store per-agent model overrides and the orchestrator model for use in later phases:
146
+
147
+ ```bash
148
+ # ORCHESTRATOR_MODEL is informational; the caller is responsible for spawning
149
+ # the orchestrator with this model (e.g. specrails-desktop reads this field directly).
150
+ ORCHESTRATOR_MODEL="$(jq -r '.orchestrator.model' <<<"$PROFILE")"
151
+
152
+ # Per-agent model overrides keyed by agent id.
153
+ # Consumed by subagent invocation sites in later phases.
154
+ declare -A AGENT_MODEL
155
+ while IFS=$'\t' read -r id model; do
156
+ [[ -n "$model" && "$model" != "null" ]] && AGENT_MODEL[$id]="$model"
157
+ done < <(jq -r '.agents[] | [.id, (.model // "null")] | @tsv' <<<"$PROFILE")
158
+
159
+ # Routing rules (array), consumed by Phase 3b.
160
+ ROUTING="$(jq '.routing' <<<"$PROFILE")"
161
+
162
+ PROFILE_MODE="profile"
163
+ PROFILE_NAME="$(jq -r '.name' <<<"$PROFILE")"
164
+ ```
165
+
166
+ ##### Apply per-agent model overrides (profile mode only)
167
+
168
+ Claude Code's Agent tool determines a subagent's model from the `model:` line in the agent's `.md` frontmatter at invocation time — there is no per-call model parameter. When a profile is active, rewrite each agent's frontmatter `model:` value in-place to match `AGENT_MODEL[$id]`.
169
+
170
+ This rewrite is safe because:
171
+ - Multi-feature runs execute in **isolated git worktrees** (`isolation: worktree`), so each rail mutates its own copy of `.claude/agents/` without cross-rail contention.
172
+ - Single-feature runs are sequential within a single checkout.
173
+ - The app writes a job-scoped snapshot of the profile and spawns `claude` with `$SPECRAILS_PROFILE_PATH` pointing at it; the frontmatter rewrite follows the snapshot, never the catalog.
174
+
175
+ ```bash
176
+ for id in "${!AGENT_MODEL[@]}"; do
177
+ model="${AGENT_MODEL[$id]}"
178
+ file=".claude/agents/$id.md"
179
+ [[ -f "$file" ]] || continue
180
+ # Rewrite the first `model:` line within the frontmatter block (lines between the
181
+ # first two `---` separators). Use sed with portable syntax (macOS + Linux).
182
+ awk -v new="$model" '
183
+ BEGIN { in_fm=0; done=0 }
184
+ /^---$/ { in_fm = !in_fm; print; next }
185
+ in_fm && !done && /^model:[[:space:]]/ { print "model: " new; done=1; next }
186
+ { print }
187
+ ' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
188
+ done
189
+ ```
190
+
191
+ If a profile does not declare `model` for a given agent (the field is optional), that agent's frontmatter is left untouched.
192
+
193
+ ##### Legacy mode — preserve current behavior
194
+
195
+ If no profile is active, scan the agents directory exactly as before:
196
+
197
+ ```bash
198
+ AVAILABLE_AGENTS="$(ls .claude/agents/sr-*.md 2>/dev/null | sed 's|.*/||;s|\.md$||' | sort)"
199
+ PROFILE_MODE="legacy"
200
+ PROFILE_NAME=""
201
+ ```
202
+
203
+ Per-agent model overrides are empty in legacy mode — subagent invocations inherit the `model:` value from each agent's `.md` frontmatter. Routing in Phase 3b uses the hardcoded legacy rules.
204
+
205
+ ##### Agent roles (both modes)
206
+
207
+ The pipeline adapts dynamically to the installed agents:
208
+
209
+ | Agent | Role | Required? | Phase(s) affected |
210
+ |-------|------|-----------|-------------------|
211
+ | sr-architect | Architecture & design | **Core** (always present) | 3a |
212
+ | sr-developer | Full-stack implementation | **Core** (always present) | 3b |
213
+ | sr-reviewer | Generalist quality gate | **Core** (always present) | 4b |
214
+ | sr-merge-resolver | Merge conflict resolution | Optional — required for multi-feature merge conflict resolution | 4a |
215
+ | sr-product-manager | Product exploration | Optional | 1 |
216
+ | sr-test-writer | Test generation | Optional | 3c |
217
+ | sr-doc-sync | Documentation sync | Optional | 3d |
218
+ | sr-frontend-developer | Frontend implementation | Optional | 3b (routing) |
219
+ | sr-backend-developer | Backend implementation | Optional | 3b (routing) |
220
+ | sr-frontend-reviewer | Frontend review | Optional | 4b |
221
+ | sr-backend-reviewer | Backend review | Optional | 4b |
222
+ | sr-security-reviewer | Security analysis | Optional | 4b |
223
+ | sr-performance-reviewer | Performance analysis | Optional | 4b |
224
+
225
+ **Gate rules** (applied throughout the pipeline):
226
+ - If an optional agent is NOT in `AVAILABLE_AGENTS`, **skip** that phase/sub-step silently and note `"<agent> not installed — skipping"`.
227
+ - Core agents are guaranteed to exist. If a core agent is missing, **STOP** and print: `[error] Core agent <name> not found. Run /specrails:enrich or reinstall.`
228
+ - In **profile mode**, the profile's `agents[]` IS the source of truth for `AVAILABLE_AGENTS`. Agents not listed are considered unavailable regardless of what is on disk.
229
+
230
+ ### Summary
231
+
232
+ Print a setup report:
233
+
234
+ ```
235
+ ## Environment Setup
236
+ | Tool | Status | Notes |
237
+ |------|--------|-------|
238
+ | Backlog provider | ok/missing | |
239
+ | OpenSpec | ok | ... |
240
+ | Dependencies | ok | ... |
241
+ | Test runner | ok | ... |
242
+ | Agents | N installed | core: 3/3, optional: M |
243
+ ```
244
+
245
+ **Pass `TEST_CMD`, `BACKLOG_AVAILABLE`, and `AVAILABLE_AGENTS` forward** — all later phases must use these.
246
+
247
+ ---
248
+
249
+ ## Phase 0: Parse input and determine mode
250
+
251
+ ### Flag Detection
252
+
253
+ Before parsing input, scan `$ARGUMENTS` for control flags:
254
+
255
+ - If `--dry-run` or `--preview` is present in `$ARGUMENTS`:
256
+ - Set `DRY_RUN=true`
257
+ - Strip the flag from the arguments before further parsing
258
+ - Print: `[dry-run] Preview mode active — no git, PR, or backlog operations will run.`
259
+ - Set `CACHE_DIR=.claude/.dry-run/<kebab-case-feature-name>` (derive after parsing the remaining input)
260
+ - Note: if a cache already exists at `CACHE_DIR`, print `[dry-run] Overwriting existing cache at CACHE_DIR` before overwriting.
261
+
262
+ - If `--apply <feature-name>` is present in `$ARGUMENTS`:
263
+ - Set `APPLY_MODE=true`
264
+ - Set `APPLY_TARGET=<feature-name>` (the argument immediately following `--apply`)
265
+ - Set `CACHE_DIR=.claude/.dry-run/<feature-name>`
266
+ - Verify `CACHE_DIR` exists. If it does not: print `[apply] Error: no cached dry-run found at CACHE_DIR` and stop.
267
+ - Skip Phases 1–4b. Go directly to Phase 4c (the apply path handles the rest).
268
+ - Strip `--apply` and the feature name before further parsing.
269
+
270
+ - If `--confidence-override "<reason>"` is present in `$ARGUMENTS`:
271
+ - Set `CONFIDENCE_OVERRIDE_REASON=<reason>` (the quoted string immediately following `--confidence-override`)
272
+ - Strip `--confidence-override` and the reason before further parsing.
273
+
274
+ If none of these flags is present: `DRY_RUN=false`, `APPLY_MODE=false`, `CONFIDENCE_OVERRIDE_REASON=""`. Pipeline runs as normal.
275
+
276
+ Note: `CACHE_DIR` for `--dry-run` is finalized after the feature name is derived from the remaining input. All subsequent phases that reference `CACHE_DIR` have access to it.
277
+
278
+ Initialize conflict-tracking variables:
279
+ - `SNAPSHOTS_CAPTURED=false` — set to true in Phase 0 if issue snapshots are successfully written.
280
+ - `CONFLICT_OVERRIDES=[]` — list of conflict records where the user chose to continue; appended by Phase 3a.0 and Phase 4c.0.
281
+
282
+ ---
283
+
284
+ **If the user passed a text description** (e.g. `"add feature X"`):
285
+ - **Single-feature mode**. Derive a kebab-case change name.
286
+ - Set `SINGLE_MODE = true`. No worktrees, no parallelism.
287
+ - **Skip Phase 1 and Phase 2** — go directly to Phase 3a.
288
+
289
+ **If the user passed issue/ticket references** (e.g. `#85, #71` for GitHub, `#1, #2` for local tickets, or `PROJ-85, PROJ-71` for JIRA):
290
+ - Fetch each issue/ticket:
291
+ ```bash
292
+
293
+ ```
294
+ - Extract area, value, effort, and feature details from each issue body.
295
+ - If only 1 issue: set `SINGLE_MODE = true`.
296
+ - **Skip Phase 1 and Phase 2** — go directly to confirmation table.
297
+
298
+ #### Phase 0 snapshot capture
299
+
300
+ After fetching issue refs, capture a baseline snapshot for conflict detection.
301
+
302
+ ##### If `BACKLOG_PROVIDER=local` and input mode was issue numbers:
303
+
304
+ For each resolved ticket ID, read `.specrails/local-tickets.json` and extract the ticket object at `tickets["{id}"]`.
305
+
306
+ Build a snapshot object for each ticket:
307
+ - `number`: ticket `id` (integer)
308
+ - `title`: ticket `title` string
309
+ - `state`: map ticket `status` — `"done"` or `"cancelled"` → `"closed"`, otherwise → `"open"`
310
+ - `assignees`: `[ticket.assignee]` if non-null, else `[]`
311
+ - `labels`: ticket `labels` array, sorted alphabetically
312
+ - `body_sha`: SHA-256 of the ticket `description` string — compute with:
313
+ ```bash
314
+ echo -n "{description}" | sha256sum | cut -d' ' -f1
315
+ ```
316
+ If `sha256sum` is not available, fall back to `openssl dgst -sha256 -r` or `shasum -a 256`.
317
+ - `updated_at`: ticket `updated_at` value
318
+ - `captured_at`: current local time in ISO 8601 format
319
+
320
+ Write the following JSON to `.claude/backlog-cache.json` (overwrite fully — this establishes a fresh baseline for this run):
321
+
322
+ ```json
323
+ {
324
+ "schema_version": "1",
325
+ "provider": "local",
326
+ "last_updated": "<ISO 8601 timestamp>",
327
+ "written_by": "implement",
328
+ "issues": {
329
+ "<id>": { <snapshot object> },
330
+ ...
331
+ }
332
+ }
333
+ ```
334
+
335
+ If the write succeeds: set `SNAPSHOTS_CAPTURED=true`.
336
+
337
+ If the write fails: print `[backlog-cache] Warning: could not write cache. Conflict detection disabled for this run.` and set `SNAPSHOTS_CAPTURED=false`. Do NOT abort the pipeline.
338
+
339
+ ##### If `GH_AVAILABLE=true` and input mode was issue numbers (GitHub/JIRA):
340
+
341
+ For each resolved issue number, run:
342
+
343
+ ```bash
344
+ gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
345
+ ```
346
+
347
+ Build a snapshot object for each issue:
348
+ - `number`: integer issue number
349
+ - `title`: issue title string
350
+ - `state`: `"open"` or `"closed"`
351
+ - `assignees`: array of assignee login names, sorted alphabetically
352
+ - `labels`: array of label names, sorted alphabetically
353
+ - `body_sha`: SHA-256 of the raw body string — compute with:
354
+ ```bash
355
+ echo -n "{body}" | sha256sum | cut -d' ' -f1
356
+ ```
357
+ If `sha256sum` is not available, fall back to `openssl dgst -sha256 -r` or `shasum -a 256`.
358
+ - `updated_at`: the `updatedAt` value from the GitHub API response
359
+ - `captured_at`: current local time in ISO 8601 format
360
+
361
+ Write the following JSON to `.claude/backlog-cache.json` (overwrite fully — this establishes a fresh baseline for this run):
362
+
363
+ ```json
364
+ {
365
+ "schema_version": "1",
366
+ "provider": "github",
367
+ "last_updated": "<ISO 8601 timestamp>",
368
+ "written_by": "implement",
369
+ "issues": {
370
+ "<number>": { <snapshot object> },
371
+ ...
372
+ }
373
+ }
374
+ ```
375
+
376
+ If the write succeeds: set `SNAPSHOTS_CAPTURED=true`.
377
+
378
+ If the write fails (e.g., `.claude/` directory does not exist): print `[backlog-cache] Warning: could not write cache. Conflict detection disabled for this run.` and set `SNAPSHOTS_CAPTURED=false`. Do NOT abort the pipeline.
379
+
380
+ ##### Otherwise (no backlog available or non-issue input):
381
+
382
+ Set `SNAPSHOTS_CAPTURED=false`. Print: `[conflict-check] Snapshot skipped — backlog unavailable or non-issue input.`
383
+
384
+ #### Gitignore advisory
385
+
386
+ If `SNAPSHOTS_CAPTURED=true`, check whether `.gitignore` already covers the cache file:
387
+
388
+ ```bash
389
+ grep -q "backlog-cache" .gitignore 2>/dev/null || \
390
+ grep -q "\.claude/" .gitignore 2>/dev/null
391
+ ```
392
+
393
+ If neither pattern is found, print:
394
+
395
+ ```
396
+ [backlog-cache] Suggestion: add '.claude/backlog-cache.json' to .gitignore to avoid committing ephemeral cache state.
397
+ ```
398
+
399
+ This advisory is non-blocking and suppressed when `.gitignore` already covers the file.
400
+
401
+ #### Pipeline state initialization
402
+
403
+ Set `PIPELINE_STATE_PATH=.claude/pipeline-state/<feature-name>.json` (use the same kebab-case feature name derived above).
404
+
405
+ Create the directory if it does not exist:
406
+
407
+ ```bash
408
+ mkdir -p .claude/pipeline-state
409
+ ```
410
+
411
+ Write the initial state file:
412
+
413
+ ```json
414
+ {
415
+ "schema_version": "1",
416
+ "feature": "<feature-name>",
417
+ "started_at": "<current ISO 8601 timestamp>",
418
+ "updated_at": "<current ISO 8601 timestamp>",
419
+ "phases": {
420
+ "architect": "pending",
421
+ "developer": "pending",
422
+ "test-writer": "<'pending' if sr-test-writer ∈ AVAILABLE_AGENTS, else 'skipped'>",
423
+ "doc-sync": "<'pending' if sr-doc-sync ∈ AVAILABLE_AGENTS, else 'skipped'>",
424
+ "reviewer": "pending",
425
+ "ship": "pending",
426
+ "ci": "pending"
427
+ },
428
+ "last_successful_phase": null,
429
+ "failed_phase": null,
430
+ "error_context": null,
431
+ "openspec_artifacts": "openspec/changes/<feature-name>/",
432
+ "implemented_files": [],
433
+ "input": {
434
+ "issues": [<issue numbers, or null for text-description mode>],
435
+ "flags": {
436
+ "dry_run": <DRY_RUN>,
437
+ "apply_mode": <APPLY_MODE>,
438
+ "single_mode": <SINGLE_MODE>
439
+ }
440
+ }
441
+ }
442
+ ```
443
+
444
+ If the write fails: print `[pipeline-state] Warning: could not write state file. Smart retry (/specrails:retry) will not be available for this run.` Set `PIPELINE_STATE_AVAILABLE=false`. Do NOT abort the pipeline.
445
+
446
+ If the write succeeds: set `PIPELINE_STATE_AVAILABLE=true`.
447
+
448
+ **State update helper** — used by all subsequent phases to record progress:
449
+
450
+ When a phase completes or fails, update `PIPELINE_STATE_PATH`:
451
+ 1. Read the current file.
452
+ 2. Set `phases.<phase-key>` to `"done"`, `"failed"`, or `"skipped"`.
453
+ 3. If `"done"`: set `last_successful_phase` to the phase key.
454
+ 4. If `"failed"`: set `failed_phase` to the phase key; set `error_context` to a one-line description of the failure (agent name, error type, exit code if known).
455
+ 5. Set `updated_at` to the current ISO 8601 timestamp.
456
+ 6. Overwrite the file.
457
+
458
+ If `PIPELINE_STATE_AVAILABLE=false`: skip all state updates silently.
459
+
460
+ **If the user passed area names**:
461
+ - Check for open backlog issues. If found, filter and pick top 3.
462
+ - If none, proceed to Phase 1.
463
+
464
+ ---
465
+
466
+ ## Phase 1: Explore (parallel)
467
+
468
+ **Only runs if Phase 0 found no backlog issues AND user passed area names AND `sr-product-manager` ∈ `AVAILABLE_AGENTS`.**
469
+
470
+ If `sr-product-manager` is not installed, skip Phase 1 and Phase 2 entirely. Print: `[phase-1] sr-product-manager not installed — skipping exploration. Proceeding with provided input.`
471
+
472
+ For each area, launch a **sr-product-manager** agent (`subagent_type: sr-product-manager`, `run_in_background: true`).
473
+
474
+ Wait for all to complete. Read their output.
475
+
476
+ ## Phase 2: Select
477
+
478
+ **Only runs if Phase 1 ran.**
479
+
480
+ Pick the single idea with the best impact/effort ratio from each exploration. Present to user and wait for confirmation.
481
+
482
+ ## Phase 3a.0: Pre-architect conflict check
483
+
484
+ **Guard:** If `SNAPSHOTS_CAPTURED=false` OR `DRY_RUN=true`, print `[conflict-check] Skipped — SNAPSHOTS_CAPTURED=false (or dry-run mode).` and proceed directly to Phase 3a.
485
+
486
+ Otherwise, re-fetch each issue in scope and diff against the Phase 0 snapshot:
487
+
488
+ **If `BACKLOG_PROVIDER=local`:** For each ticket ID in `ISSUE_REFS`, read `.specrails/local-tickets.json` and extract the ticket at `tickets["{id}"]`. If the ticket does not exist (deleted): treat as a CRITICAL conflict — field `"state"`, was `<cached state>`, now `"deleted"`. Otherwise, reconstruct a current snapshot using the same mapping as the Phase 0 local snapshot.
489
+
490
+ **If `BACKLOG_PROVIDER=github`:** For each issue number in `ISSUE_REFS`:
491
+
492
+ ```bash
493
+ gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
494
+ ```
495
+
496
+ If the `gh` command returns non-zero (issue deleted or inaccessible): treat as a CRITICAL conflict — field `"state"`, was `<cached state>`, now `"deleted"`.
497
+
498
+ In both cases, reconstruct a current snapshot (same shape as Phase 0: sort `assignees` and `labels`, compute `body_sha`).
499
+
500
+ **Short-circuit:** If `current.updatedAt == cached.updated_at`, mark the issue as clean and skip field comparison.
501
+
502
+ **Field comparison** (only when `updatedAt` differs):
503
+
504
+ | Field | Conflict if... | Severity |
505
+ |-------|----------------|----------|
506
+ | `state` | value differs (`open` → `closed`) | CRITICAL |
507
+ | `state` | value differs (`closed` → `open`) | WARNING |
508
+ | `title` | string differs | WARNING |
509
+ | `assignees` | sorted array differs | WARNING |
510
+ | `labels` | sorted array differs | INFO |
511
+ | `body_sha` | SHA differs | WARNING |
512
+
513
+ Collect all conflicts across all issues. If none: print `[conflict-check] All issues clean (Phase 3a.0). Proceeding.` and continue to Phase 3a.
514
+
515
+ **If conflicts exist**, print the following report and await user input:
516
+
517
+ ```
518
+ ## Backlog Conflict Detected
519
+
520
+ The following issues changed since Phase 0 snapshot (captured at <captured_at>):
521
+
522
+ | Issue | Field | Severity | Was | Now |
523
+ |-------|-------|----------|-----|-----|
524
+ | #N | state | CRITICAL | open | closed |
525
+ | #N | body | WARNING | <sha-prefix> | <sha-prefix> |
526
+
527
+ How would you like to proceed?
528
+ [A] Abort — stop the pipeline and exit cleanly
529
+ [C] Continue — proceed despite the conflicts (logged)
530
+
531
+ Enter A or C:
532
+ ```
533
+
534
+ For `body_sha` rows in the table, display only the first 8 characters of each SHA as the "Was" and "Now" values.
535
+
536
+ **Input handling:**
537
+ - Accept `A`, `a` (abort) or `C`, `c` (continue).
538
+ - Re-prompt on any other input, up to 3 times total.
539
+ - After 3 invalid inputs: print `[conflict-abort] Defaulting to abort after 3 invalid inputs.` and abort.
540
+
541
+ **On abort:** Print `[conflict-abort] Pipeline aborted. Re-run /specrails:implement after resolving the issues.` and exit. No git state is left behind.
542
+
543
+ **On continue:** Print `[conflict-override] Continuing. N conflict(s) logged.` Append each conflict to `CONFLICT_OVERRIDES` as `{phase: "3a.0", issue: "#N", field: "<field>", severity: "<severity>", was: "<was>", now: "<now>"}`. Proceed to Phase 3a.
544
+
545
+ ## Phase 3a: Architect (parallel, in main repo)
546
+
547
+ For each chosen idea, launch an **sr-architect** agent (`subagent_type: sr-architect`, `run_in_background: true`).
548
+
549
+ Each architect creates OpenSpec artifacts in `openspec/changes/<name>/`.
550
+
551
+ Each agent's prompt should include:
552
+ - Description of the feature
553
+ - Context from exploration (if applicable)
554
+ - Instructions to create: proposal.md, design.md, delta-spec, tasks.md, context-bundle.md
555
+ - Tags for each task:
556
+
557
+ ### 3a.1 Identify shared file conflicts
558
+
559
+ **Only runs in multi-feature mode** (more than one feature). Skip entirely if `SINGLE_MODE=true`.
560
+
561
+ After all architect agents complete, before launching any developer agent:
562
+
563
+ #### Step 1: Extract file references
564
+
565
+ For each `openspec/changes/<name>/tasks.md`, extract all paths listed under `**Files:**` entries (both `Create:` and `Modify:` lines). Normalize paths: strip leading `./`.
566
+
567
+ #### Step 2: Build the shared-file registry
568
+
569
+ Group file paths across all features. Any path appearing in two or more features' task lists is a **shared file**. Store as `SHARED_FILES` map: `{path: {features: [...], risk: ""}}`.
570
+
571
+ #### Step 3: Classify risk
572
+
573
+ For each shared file, classify risk based on file type and which regions each feature modifies (consult each feature's context-bundle.md "Exact Changes" section):
574
+
575
+ | Risk | Condition |
576
+ |------|-----------|
577
+ | `low` | Both features only append new named sections not present in the other feature's changes |
578
+ | `medium` | Both features modify structurally distinct regions (different `##` sections or different top-level YAML keys) |
579
+ | `high` | Both features modify the same region (same `##` section, same YAML key subtree, or any region in shell scripts) |
580
+
581
+ Shell scripts (`.sh`, `.bash`): always `high`.
582
+ Non-existent files that two features both create: always `high`.
583
+
584
+ #### Step 4: Derive MERGE_ORDER
585
+
586
+ Sort features so that for any pair sharing a `high`-risk file, one appears before the other. Use topological sort; break ties alphabetically. Set `MERGE_ORDER` = sorted feature list.
587
+
588
+ #### Step 5: Print pre-flight report
589
+
590
+ ```
591
+ ## Shared File Analysis
592
+
593
+ | File | Features | Risk |
594
+ |------|----------|------|
595
+ | <path> | <feature-a>, <feature-b> | <risk> |
596
+
597
+ Merge order: <feature-a> → <feature-b> → <feature-c>
598
+
599
+ High-risk files detected. These files will be merged sequentially.
600
+ Developers will still run in parallel — merge order applies at Phase 4a only.
601
+ ```
602
+
603
+ If no shared files: print `No shared files detected. All features modify independent files.`
604
+
605
+ ### 3a.2 Pre-validate architect output
606
+
607
+ Quick-check each architect's artifacts:
608
+ 1. tasks.md exists and has tasks
609
+ 2. context-bundle.md exists
610
+ 3. File references are real (>70% must exist)
611
+ 4. Layer tags present on tasks
612
+
613
+ **Pipeline state:** update `architect` → `done`. If any architect agent failed (skipped area): update `architect` → `failed` with error context `"sr-architect failed for: <area-names>"`.
614
+
615
+ ## Phase 3b: Implement
616
+
617
+ ### Pre-flight: Verify Bash permission
618
+
619
+ Before launching any developer agent, run a trivial Bash command to confirm Bash is allowed.
620
+
621
+ ### Launch developers
622
+
623
+ **Read reviewer learnings:** Check `.claude/agent-memory/sr-reviewer/common-fixes.md` and include in developer prompts.
624
+
625
+ #### Dry-Run: Redirect developer writes
626
+
627
+ **If `DRY_RUN=true`**, include the following in every developer agent prompt:
628
+
629
+ > IMPORTANT: This is a dry-run. Write all new or modified files under:
630
+ > .claude/.dry-run/\<feature-name\>/
631
+ >
632
+ > Mirror the real destination path within this directory. For example:
633
+ > Real path: src/utils/parser.ts
634
+ > Write to: .claude/.dry-run/\<feature-name\>/src/utils/parser.ts
635
+ >
636
+ > Do NOT write to real file paths. After writing each file, append an entry
637
+ > to .claude/.dry-run/\<feature-name\>/.cache-manifest.json using this JSON format:
638
+ > {"cached_path": "...", "real_path": "...", "operation": "create|modify"}
639
+
640
+ **If `DRY_RUN=false`**: developer agent instructions are unchanged.
641
+
642
+ #### Choosing the right developer agent
643
+
644
+ For each feature, read `openspec/changes/<name>/tasks.md` and classify every task by its layer tags and file references.
645
+
646
+ **Step 1 — Classify tasks into layers:**
647
+
648
+ For each task, determine its layer from:
649
+ 1. **Explicit layer tags** in tasks.md (e.g., `[frontend]`, `[backend]`, `[core]`, `[infra]`, `[docs]`, etc.)
650
+ 2. **File references** under `**Files:**` entries — apply the same extension/path rules used in Phase 4b:
651
+ - Frontend: `.jsx`, `.tsx`, `.vue`, `.svelte`, `.css`, `.scss`, `.html`, or paths under `components/`, `pages/`, `views/`, `ui/`, `client/`, `frontend/`, `app/`, `public/`, `static/`, `assets/`
652
+ - Backend: `.py`, `.go`, `.java`, `.rb`, `.php`, `.rs`, `.cs`, `.sql`, or paths under `server/`, `api/`, `routes/`, `controllers/`, `services/`, `models/`, `db/`, `backend/`, `migrations/`
653
+ - Mixed/other: everything else (shell scripts, config files, markdown, YAML, etc.)
654
+
655
+ Produce three sets: `FRONTEND_TASKS`, `BACKEND_TASKS`, `OTHER_TASKS`.
656
+
657
+ **Step 2 — Route tasks to developer agents:**
658
+
659
+ Routing operates in one of two modes depending on the value of `PROFILE_MODE` set in Phase -1.
660
+
661
+ ##### Profile mode (`PROFILE_MODE=profile`)
662
+
663
+ When a profile is active, apply `ROUTING` rules in their array order. For each task, collect its tag set (layer tags plus any explicit `[tag]` markers in tasks.md). The first rule whose `tags` array intersects the task's tag set wins. The terminal `default: true` rule catches tasks matched by no earlier rule.
664
+
665
+ Example (pseudocode):
666
+
667
+ ```bash
668
+ assigned_agent_for_task() {
669
+ local -a task_tags=("$@")
670
+ local rule_count
671
+ rule_count=$(jq 'length' <<<"$ROUTING")
672
+ local i=0
673
+ while [[ $i -lt $rule_count ]]; do
674
+ local is_default rule_tags agent
675
+ is_default=$(jq -r ".[$i].default // false" <<<"$ROUTING")
676
+ agent=$(jq -r ".[$i].agent" <<<"$ROUTING")
677
+ if [[ "$is_default" == "true" ]]; then
678
+ echo "$agent"
679
+ return
680
+ fi
681
+ rule_tags=$(jq -r ".[$i].tags[]" <<<"$ROUTING")
682
+ for rtag in $rule_tags; do
683
+ for ttag in "${task_tags[@]}"; do
684
+ if [[ "$rtag" == "$ttag" ]]; then
685
+ echo "$agent"
686
+ return
687
+ fi
688
+ done
689
+ done
690
+ i=$((i + 1))
691
+ done
692
+ }
693
+ ```
694
+
695
+ Produce `DEVELOPER_ROUTING` from the per-task decisions, grouping by assigned agent. An agent assigned by the profile SHALL only be used if it also appears in `AVAILABLE_AGENTS` (the profile's own `agents[]`). If the profile routes a task to an agent not present in `agents[]`, that is a profile configuration bug — **STOP** and print: `[error] profile routing references agent '<id>' which is not declared in profile.agents[]`.
696
+
697
+ ##### Legacy mode (`PROFILE_MODE=legacy`)
698
+
699
+ When no profile is active, evaluate available developer agents in `AVAILABLE_AGENTS` and apply these hardcoded rules in priority order:
700
+
701
+ | Condition | Agent(s) selected | Mode |
702
+ |-----------|-------------------|------|
703
+ | ALL tasks are frontend-only AND `sr-frontend-developer` ∈ `AVAILABLE_AGENTS` | **sr-frontend-developer** | Single agent for all tasks |
704
+ | ALL tasks are backend-only AND `sr-backend-developer` ∈ `AVAILABLE_AGENTS` | **sr-backend-developer** | Single agent for all tasks |
705
+ | Mix of frontend + backend tasks AND both layer-specific developers available | **sr-frontend-developer** for `FRONTEND_TASKS`, **sr-backend-developer** for `BACKEND_TASKS`, **sr-developer** for `OTHER_TASKS` | Parallel agents per layer |
706
+ | Frontend tasks exist AND `sr-frontend-developer` available, but no backend-specific developer | **sr-frontend-developer** for `FRONTEND_TASKS`, **sr-developer** for remaining | Parallel agents |
707
+ | Backend tasks exist AND `sr-backend-developer` available, but no frontend-specific developer | **sr-backend-developer** for `BACKEND_TASKS`, **sr-developer** for remaining | Parallel agents |
708
+ | No layer-specific developers available (fallback) | **sr-developer** | Single agent for all tasks |
709
+
710
+ Store the result as `DEVELOPER_ROUTING`: a map of `{agent_id: [task_list]}`.
711
+
712
+ ##### Routing trace (both modes)
713
+
714
+ After computing `DEVELOPER_ROUTING`, optionally emit a trace line to aid debugging:
715
+
716
+ ```
717
+ [phase-3b] routing decision: mode=$PROFILE_MODE profile=${PROFILE_NAME:-none} agents=[list]
718
+ ```
719
+
720
+ **Step 3 — Print routing decision:**
721
+
722
+ ```
723
+ ## Developer Routing
724
+
725
+ | Agent | Tasks | Reason |
726
+ |-------|-------|--------|
727
+ | sr-frontend-developer | Task 1, Task 3 | Frontend-only tasks (React components) |
728
+ | sr-backend-developer | Task 2, Task 4 | Backend-only tasks (API endpoints) |
729
+ | sr-developer | Task 5 | Mixed layer (config + infra) |
730
+ ```
731
+
732
+ Also store `DEVELOPER_AGENTS_USED` (the set of developer agent IDs actually launched) — Phase 4b will use this for reviewer selection.
733
+
734
+ #### Launch modes
735
+
736
+ For each entry in `DEVELOPER_ROUTING`, launch the assigned developer agent using its `subagent_type` (`sr:developer`, `sr:frontend-developer`, or `sr:backend-developer`) with its task subset.
737
+
738
+ **If `SINGLE_MODE` and only one agent in routing**: Launch in the main repo, foreground.
739
+ **If `SINGLE_MODE` but multiple agents in routing**: Launch agents sequentially in the main repo (one at a time, foreground), passing only their assigned tasks.
740
+ **If multiple features**: Launch in isolated worktrees (`isolation: worktree`, `run_in_background: true`).
741
+
742
+ Wait for all developers to complete.
743
+
744
+ **Summary timing (multi-feature mode):** When running multiple background developer agents, individual `task_notification` completions MUST NOT trigger a final Phase 3b summary. As each agent completes, emit only a brief one-line acknowledgment:
745
+ ```
746
+ [phase-3b] Developer for <feature> ✓ (<N> tool uses, <duration>)
747
+ ```
748
+ Only after the LAST background agent sends its completion notification, emit the consolidated summary:
749
+ ```
750
+ ## Phase 3b Complete
751
+
752
+ | Feature | Agent | Tool uses | Duration |
753
+ |---------|-------|-----------|----------|
754
+ | <feature-a> | sr-developer | 64 | 8m 02s |
755
+ | <feature-b> | sr-developer | 50 | 7m 35s |
756
+
757
+ All N developers complete. Proceeding to Phase 3c.
758
+ ```
759
+
760
+ This prevents stale "still waiting" text from appearing as the terminal result when the job completes.
761
+
762
+ **Pipeline state:** update `developer` → `done`. Also update `implemented_files` in the state file with the complete list of files created or modified by the developer agent(s). If developer failed: update `developer` → `failed` with error context `"<agent-id> failed: <exit code or error description>"`.
763
+
764
+ ## Phase 3c: Write Tests
765
+
766
+ **Guard:** If `sr-test-writer` ∉ `AVAILABLE_AGENTS`, skip this phase. Print: `[phase-3c] sr-test-writer not installed — skipping test generation.` Update pipeline state: `test-writer` → `skipped`. Proceed to Phase 3d.
767
+
768
+ Launch a **sr-test-writer** agent (`subagent_type: sr:test-writer`) for each feature immediately after its developer completes.
769
+
770
+ Construct the agent invocation prompt to include:
771
+ - **IMPLEMENTED_FILES_LIST**: the complete list of files the developer created or modified for this feature
772
+ - **TASK_DESCRIPTION**: the original task or feature description that drove the implementation
773
+
774
+ ### Launch modes
775
+
776
+ **If `SINGLE_MODE`**: Launch a single sr-test-writer agent in the foreground (`run_in_background: false`). Wait for it to complete before proceeding to Phase 4.
777
+
778
+ **If multiple features (worktrees)**: Launch one sr-test-writer agent per feature, each in its corresponding worktree (`isolation: worktree`, `run_in_background: true`). Wait for all sr-test-writer agents to complete before proceeding to Phase 4.
779
+
780
+ ### Dry-run behavior
781
+
782
+ **If `DRY_RUN=true`**, include in every test-writer agent prompt:
783
+
784
+ > IMPORTANT: This is a dry-run. Write all new or modified test files under:
785
+ > .claude/.dry-run/\<feature-name\>/
786
+ >
787
+ > Mirror the real destination path within this directory. After writing each file, append an entry
788
+ > to .claude/.dry-run/\<feature-name\>/.cache-manifest.json using:
789
+ > {"cached_path": "...", "real_path": "...", "operation": "create"}
790
+
791
+ ### Failure handling
792
+
793
+ If a test-writer agent fails or times out:
794
+ - Record `Tests: FAILED` for that feature in the Phase 4e report
795
+ - Continue to Phase 4 — the sr-test-writer failure is non-blocking
796
+ - Include in the reviewer agent prompt: "Note: the sr-test-writer failed for this feature. Check for coverage gaps."
797
+
798
+ **Pipeline state:** update `test-writer` → `done` (or `failed` with error context `"sr-test-writer timed out or errored"`). Failure does not block the pipeline.
799
+
800
+ ## Phase 3d: Doc Sync
801
+
802
+ **Guard:** If `sr-doc-sync` ∉ `AVAILABLE_AGENTS`, skip this phase. Print: `[phase-3d] sr-doc-sync not installed — skipping doc sync.` Update pipeline state: `doc-sync` → `skipped`. Proceed to Phase 4.
803
+
804
+ Launch a **sr-doc-sync** agent (`subagent_type: sr:doc-sync`) for each feature after its tests are written.
805
+
806
+ Construct the agent invocation prompt to include:
807
+ - **IMPLEMENTED_FILES_LIST**: the complete list of files the developer created or modified for this feature
808
+ - **TASK_DESCRIPTION**: the original task or feature description that drove the implementation
809
+
810
+ ### Launch modes
811
+
812
+ **If `SINGLE_MODE`**: Launch a single sr-doc-sync agent in the foreground (`run_in_background: false`). Wait for it to complete before proceeding to Phase 4.
813
+
814
+ **If multiple features (worktrees)**: Launch one sr-doc-sync agent per feature, each in its corresponding worktree (`isolation: worktree`, `run_in_background: true`). Wait for all sr-doc-sync agents to complete before proceeding to Phase 4.
815
+
816
+ ### Dry-run behavior
817
+
818
+ **If `DRY_RUN=true`**, include in every doc-sync agent prompt:
819
+
820
+ > IMPORTANT: This is a dry-run. Write all new or modified doc files under:
821
+ > .claude/.dry-run/\<feature-name\>/
822
+ >
823
+ > Mirror the real destination path within this directory. After writing each file, append an entry
824
+ > to .claude/.dry-run/\<feature-name\>/.cache-manifest.json using:
825
+ > {"cached_path": "...", "real_path": "...", "operation": "create|modify"}
826
+
827
+ ### Failure handling
828
+
829
+ If a doc-sync agent fails or times out:
830
+ - Record `Docs: FAILED` for that feature in the Phase 4e report
831
+ - Continue to Phase 4 — the sr-doc-sync failure is non-blocking
832
+ - Include in the reviewer agent prompt: "Note: the sr-doc-sync agent failed for this feature."
833
+
834
+ **Pipeline state:** update `doc-sync` → `done` (or `failed` with error context `"sr-doc-sync timed out or errored"`). Failure does not block the pipeline.
835
+
836
+ ## Phase 4: Merge & Review
837
+
838
+ **This phase is fully autonomous.**
839
+
840
+ ### 4a. Merge worktree changes to main repo
841
+
842
+ - If `SINGLE_MODE`: skip (no worktrees were used). Proceed to Phase 4b.
843
+ - If `DRY_RUN=true`: apply the merge algorithm below, writing all outputs to `CACHE_DIR/<file-path>` instead of the main repo working tree. Do NOT clean up worktrees in dry-run mode.
844
+ - Otherwise: apply the merge algorithm below, writing outputs to the main repo working tree. Clean up worktrees at the end.
845
+
846
+ #### Merge Algorithm
847
+
848
+ Process features in `MERGE_ORDER` sequence. For each feature:
849
+
850
+ **Step 1: Identify changed files**
851
+
852
+ ```bash
853
+ git -C <worktree-path> diff main --name-only
854
+ ```
855
+
856
+ Split into `exclusive_files` (only this feature modifies them) and `shared_files_for_this_feature` (also modified by another feature in MERGE_ORDER).
857
+
858
+ **Step 2: Merge exclusive files**
859
+
860
+ Copy directly from worktree to target:
861
+ ```bash
862
+ cp <worktree-path>/<file> <target>/<file>
863
+ ```
864
+ Log: `Copied (exclusive): <file>`
865
+
866
+ **Step 3: Merge shared files**
867
+
868
+ For each shared file, choose strategy by file type:
869
+
870
+ **Strategy A — Markdown section-aware merge** (`.md` files):
871
+ 1. Read base: current content of `<target>/<file>`.
872
+ 2. Read incoming: `<worktree-path>/<file>`.
873
+ 3. Parse both into sections using `##` heading boundaries (heading line + all content until next `##` or EOF).
874
+ 4. Build section maps: `{heading_text: content}` for base and incoming.
875
+ 5. Merge:
876
+ - Section in base only: keep.
877
+ - Section in incoming only: append to merged output.
878
+ - Section in both, content identical: keep base.
879
+ - Section in both, content differs: insert conflict markers:
880
+ ```
881
+ <<<<<<< <feature-name>
882
+ <incoming section content>
883
+ =======
884
+ <base section content>
885
+ >>>>>>> base
886
+ ```
887
+ Log: `CONFLICT: <file> — section "<heading>" requires manual resolution.`
888
+ 6. Write merged result to `<target>/<file>`.
889
+
890
+ **Strategy B — Unified diff sequential apply** (all other file types):
891
+ 1. Generate incoming diff against original `main`:
892
+ ```bash
893
+ git -C <worktree-path> diff main -- <file>
894
+ ```
895
+ 2. Apply to current target:
896
+ ```bash
897
+ patch --forward --fuzz=3 <target>/<file> < <diff>
898
+ ```
899
+ 3. If `patch` succeeds: log `Merged (diff-apply): <file>`.
900
+ 4. If `patch` fails: insert conflict markers around rejected hunks. Log: `CONFLICT: <file> — N hunks rejected.`
901
+
902
+ If `patch` is not available (detected in Phase -1): use Strategy A for all file types and print: `[warn] patch not available — using section-aware fallback for all shared files.`
903
+
904
+ **Step 4: Record outcomes**
905
+
906
+ Maintain `MERGE_REPORT`:
907
+ - `cleanly_merged`: exclusive files + shared files with no conflicts
908
+ - `auto_resolved`: shared files merged without conflict markers
909
+ - `requires_resolution`: `{file, feature, regions}` for files with conflict markers
910
+
911
+ **Step 5: Emit initial merge report**
912
+
913
+ After all features are processed, print the preliminary report:
914
+
915
+ ```
916
+ ## Phase 4a Merge Report (preliminary)
917
+
918
+ ### Cleanly Merged
919
+ - <file> (exclusive to <feature>)
920
+
921
+ ### Auto-Resolved
922
+ - <file> (features: <a>, <b> — distinct sections)
923
+
924
+ ### Requires Resolution (N file(s))
925
+ - <file> (features: <a>, <b> — conflicting section: "<heading>")
926
+ ```
927
+
928
+ **Step 5a: Smart conflict resolution** (skip if `SINGLE_MODE=true` or `DRY_RUN=true` or `sr-merge-resolver` ∉ `AVAILABLE_AGENTS`)
929
+
930
+ If `sr-merge-resolver` is not installed, print: `[smart-merge] sr-merge-resolver not installed — skipping merge conflict resolution agent. Fix conflicts manually.` and skip to Step 5b.
931
+
932
+ If `MERGE_REPORT.requires_resolution` is non-empty:
933
+
934
+ ```
935
+ [smart-merge] N file(s) have conflict markers. Launching sr-merge-resolver…
936
+ ```
937
+
938
+ Build `CONTEXT_BUNDLES` from the features in `MERGE_ORDER`:
939
+ ```
940
+ { "<feature-a>": "openspec/changes/<feature-a>/context-bundle.md", "<feature-b>": "openspec/changes/<feature-b>/context-bundle.md" }
941
+ ```
942
+
943
+ Load merge resolver config from `.claude/merge-resolver-config.json` if it exists. Extract `confidence_threshold` (default: 70) and `mode` (default: `auto`).
944
+
945
+ Construct the `sr-merge-resolver` agent prompt with:
946
+ - `CONFLICTED_FILES`: all file paths in `MERGE_REPORT.requires_resolution`
947
+ - `CONTEXT_BUNDLES`: the map above
948
+ - `CONFIDENCE_THRESHOLD`: from config or default (70)
949
+ - `RESOLUTION_MODE`: from config or default (`auto`)
950
+ - `REPORT_PATH`: `openspec/changes/<first-feature-in-MERGE_ORDER>/merge-resolution-report.md`
951
+
952
+ Launch the **sr-merge-resolver** agent (`subagent_type: sr-merge-resolver`, foreground, `run_in_background: false`). Wait for it to complete.
953
+
954
+ Read `MERGE_RESOLUTION_STATUS` from the agent's output (`CLEAN`, `PARTIAL`, or `UNRESOLVED`).
955
+
956
+ **Post-resolution: update MERGE_REPORT**
957
+
958
+ For each file in `MERGE_REPORT.requires_resolution`:
959
+ - Re-scan the file for remaining `<<<<<<<` markers.
960
+ - If none remain: move the file from `requires_resolution` → `auto_resolved` (with note: `smart-resolver`).
961
+ - If markers remain: keep in `requires_resolution`.
962
+
963
+ **Step 5b: Emit final merge report**
964
+
965
+ ```
966
+ ## Phase 4a Merge Report
967
+
968
+ ### Cleanly Merged
969
+ - <file> (exclusive to <feature>)
970
+
971
+ ### Auto-Resolved
972
+ - <file> (features: <a>, <b> — distinct sections)
973
+ - <file> (smart-resolver: additive-concat, confidence 92)
974
+
975
+ ### Requires Manual Resolution
976
+ - <file> (features: <a>, <b> — low-confidence: see merge-resolution-report.md)
977
+ Search for `<<<<<<< <feature-name>` to locate conflict markers.
978
+
979
+ Pipeline will continue. Fix remaining conflicts before the reviewer runs CI.
980
+ Resolution report: openspec/changes/<feature>/merge-resolution-report.md
981
+ ```
982
+
983
+ If `MERGE_REPORT.requires_resolution` is now empty: print `All conflicts resolved by smart resolver.` and omit the "Requires Manual Resolution" section.
984
+
985
+ **Step 6: Clean up worktrees** (skip if `DRY_RUN=true`)
986
+
987
+ ```bash
988
+ git worktree remove <worktree-path> --force
989
+ ```
990
+
991
+ Pass `MERGE_REPORT` to the Phase 4b reviewer agent prompt, listing any files in `requires_resolution`. If the smart resolver ran, also pass the path to `merge-resolution-report.md` so the reviewer can inspect resolution decisions for correctness.
992
+
993
+ ### 4b. Layer Dispatch and Review
994
+
995
+ #### Step 1: Layer Classification
996
+
997
+ Before launching any reviewer, classify `MODIFIED_FILES_LIST` into layer-specific file sets.
998
+
999
+ **Frontend files** — a file is frontend if any of these conditions match:
1000
+ - Extension is one of: `.jsx`, `.tsx`, `.vue`, `.svelte`, `.css`, `.scss`, `.sass`, `.less`, `.html`, `.htm`
1001
+ - Extension is `.js` or `.ts` AND path contains one of: `components/`, `pages/`, `views/`, `ui/`, `client/`, `frontend/`, `app/`
1002
+ - Path starts with: `public/`, `static/`, `assets/`
1003
+
1004
+ Set `FRONTEND_FILES` = files matching frontend rules.
1005
+
1006
+ **Backend files** — a file is backend if any of these conditions match:
1007
+ - Extension is one of: `.py`, `.go`, `.java`, `.rb`, `.php`, `.rs`, `.cs`, `.sql`
1008
+ - Extension is `.js` or `.ts` AND path contains one of: `server/`, `api/`, `routes/`, `controllers/`, `services/`, `models/`, `db/`, `backend/`
1009
+ - Path is under: `migrations/`, `alembic/`, `db/migrate/`
1010
+
1011
+ Set `BACKEND_FILES` = files matching backend rules.
1012
+
1013
+ **Overlap rule:** a file may appear in both `FRONTEND_FILES` and `BACKEND_FILES` (e.g., a Next.js API route at `pages/api/`). Both reviewers will scan it independently.
1014
+
1015
+ #### Step 2: Determine which reviewers to launch
1016
+
1017
+ A layer reviewer is launched when **both** conditions are met:
1018
+ 1. There are files to review for that layer (file classification) **OR** the corresponding layer developer was used in Phase 3b (`DEVELOPER_AGENTS_USED`)
1019
+ 2. The reviewer agent is installed (`∈ AVAILABLE_AGENTS`)
1020
+
1021
+ | Reviewer | Launch condition | Skip reason |
1022
+ |----------|-----------------|-------------|
1023
+ | sr-frontend-reviewer | (`FRONTEND_FILES` non-empty OR `sr-frontend-developer` ∈ `DEVELOPER_AGENTS_USED`) AND installed | No frontend files + no frontend developer used, or not installed |
1024
+ | sr-backend-reviewer | (`BACKEND_FILES` non-empty OR `sr-backend-developer` ∈ `DEVELOPER_AGENTS_USED`) AND installed | No backend files + no backend developer used, or not installed |
1025
+ | sr-security-reviewer | Installed | Not installed |
1026
+ | sr-performance-reviewer | Installed | Not installed |
1027
+
1028
+ If a reviewer is skipped, set its report variable to `"SKIPPED"` and note the reason.
1029
+
1030
+ #### Step 3: Launch Layer Reviewers in Parallel
1031
+
1032
+ Launch all applicable layer reviewers in parallel (`run_in_background: true`), using the corresponding `subagent_type` for each (`sr:frontend-reviewer`, `sr:backend-reviewer`, `sr:security-reviewer`, `sr:performance-reviewer`):
1033
+
1034
+ **sr-frontend-reviewer** (`subagent_type: sr:frontend-reviewer`, if applicable per Step 2):
1035
+ - Pass `FRONTEND_FILES_LIST`: the list of files in `FRONTEND_FILES`
1036
+ - Pass `PIPELINE_CONTEXT`: brief description of what was implemented
1037
+
1038
+ **sr-backend-reviewer** (`subagent_type: sr:backend-reviewer`, if applicable per Step 2):
1039
+ - Pass `BACKEND_FILES_LIST`: the list of files in `BACKEND_FILES`
1040
+ - Pass `PIPELINE_CONTEXT`: brief description of what was implemented
1041
+
1042
+ **sr-security-reviewer** (`subagent_type: sr:security-reviewer`, if applicable per Step 2):
1043
+ - Pass `MODIFIED_FILES_LIST`: the complete list of all files created or modified during this run
1044
+ - Pass `PIPELINE_CONTEXT`: brief description of what was implemented
1045
+ - Pass the exemptions config path: `.claude/security-exemptions.yaml`
1046
+
1047
+ **sr-performance-reviewer** (`subagent_type: sr:performance-reviewer`, if applicable per Step 2):
1048
+ - Pass `MODIFIED_FILES_LIST`: the complete list of all files created or modified during this run
1049
+ - Pass `PIPELINE_CONTEXT`: brief description of what was implemented
1050
+
1051
+ Wait for all launched layer reviewers to complete before proceeding to Step 4.
1052
+
1053
+ Parse status lines from each completed reviewer:
1054
+ - `FRONTEND_REVIEW_STATUS: ISSUES_FOUND` or `CLEAN` → set `FRONTEND_STATUS`
1055
+ - `BACKEND_REVIEW_STATUS: ISSUES_FOUND` or `CLEAN` → set `BACKEND_STATUS`
1056
+ - `SECURITY_STATUS: BLOCKED | WARNINGS | CLEAN` → set `SECURITY_BLOCKED=true` if `BLOCKED`, otherwise `false`
1057
+
1058
+ If a layer reviewer fails or times out: set the relevant report variable to `"ERROR: reviewer did not complete"` and continue.
1059
+
1060
+ #### Step 4: Launch Generalist Reviewer
1061
+
1062
+ Construct the generalist reviewer's invocation prompt with layer reports injected. Set each variable to the full output of the corresponding reviewer, or to the string `"SKIPPED"` if that reviewer was not launched:
1063
+
1064
+ - `FRONTEND_REVIEW_REPORT`: full output of frontend-reviewer (or `"SKIPPED"`)
1065
+ - `BACKEND_REVIEW_REPORT`: full output of backend-reviewer (or `"SKIPPED"`)
1066
+ - `SECURITY_REVIEW_REPORT`: full output of security-reviewer
1067
+
1068
+ Include in the reviewer prompt:
1069
+ - Full CI commands
1070
+ - Cross-feature merge issue checks
1071
+ - Instruction to record learnings to `common-fixes.md`
1072
+ - Instruction to archive completed changes via OpenSpec
1073
+ - The three layer report variables substituted into the `[injected]` slots in the reviewer agent template
1074
+
1075
+ Note: if total layer report length is very large, truncate each layer report to its findings tables only (omit skipped-file logs) to stay within prompt limits.
1076
+
1077
+ **The security gate (blocking ship on `SECURITY_STATUS: BLOCKED`) is enforced in Phase 4c.** Do not apply it here.
1078
+
1079
+ Launch the **sr-reviewer** agent (`subagent_type: sr:reviewer`, foreground, `run_in_background: false`). Wait for it to complete.
1080
+
1081
+ **Pipeline state:** update `reviewer` → `done` (or `failed` with error context `"sr-reviewer timed out or did not complete"` if the agent errored out).
1082
+
1083
+ **If `DRY_RUN=true`**, add the following to the reviewer agent prompt:
1084
+
1085
+ > Note: This is a dry-run review. Developer files are under .claude/.dry-run/\<feature-name\>/.
1086
+ > Read modified files from there. Write any reviewer fixes back to CACHE_DIR (not real paths).
1087
+ > CI commands may be run — they read the real repo, but be aware developer changes are not
1088
+ > yet applied to real paths.
1089
+
1090
+ ### 4b-conf. Confidence Gate
1091
+
1092
+ After the generalist reviewer agent completes, evaluate the confidence score before proceeding to Phase 4c.
1093
+
1094
+ **In multi-feature mode (worktrees):** run this gate once per feature immediately after that feature's reviewer completes. Each feature is evaluated independently — a block on one feature does not prevent another feature's gate from running.
1095
+
1096
+ #### Step 1 — Read score file
1097
+
1098
+ Path: `openspec/changes/<name>/confidence-score.json`
1099
+
1100
+ - If the file does not exist:
1101
+ - Set `CONFIDENCE_STATUS=MISSING`
1102
+ - Print: `[confidence] Warning: confidence-score.json not found. Proceeding without gate.`
1103
+ - Continue to Phase 4c.
1104
+
1105
+ #### Step 2 — Read config
1106
+
1107
+ Path: `.claude/confidence-config.json`
1108
+
1109
+ - If the file does not exist:
1110
+ - Use built-in defaults (overall: 70; type_correctness: 60; pattern_adherence: 60; test_coverage: 60; security: 75; architectural_alignment: 60).
1111
+ - Print:
1112
+ ```
1113
+ [confidence] No confidence-config.json found. Using built-in defaults.
1114
+ [confidence] To customize thresholds, create .claude/confidence-config.json.
1115
+ ```
1116
+ - If `enabled: false` in the config:
1117
+ - Print: `[confidence] Gate disabled. Skipping.`
1118
+ - Set `CONFIDENCE_STATUS=DISABLED`
1119
+ - Continue to Phase 4c.
1120
+
1121
+ #### Step 3 — Compare scores
1122
+
1123
+ - Check `overall` against `thresholds.overall`.
1124
+ - Check each of the five aspects against `thresholds.aspects.<aspect>`.
1125
+ - Collect all breaches as a list: `{aspect, actual_score, threshold, delta}`.
1126
+
1127
+ #### Step 4 — Apply on_breach
1128
+
1129
+ **If no breaches:**
1130
+ - Print: `[confidence] All scores meet thresholds. Proceeding.`
1131
+ - Set `CONFIDENCE_STATUS=PASS`
1132
+ - Continue to Phase 4c.
1133
+
1134
+ **If breaches exist and `on_breach: "block"`:**
1135
+
1136
+ 1. Check for `--confidence-override`:
1137
+ - If `CONFIDENCE_OVERRIDE_REASON` is non-empty and `override_allowed: true` in the config:
1138
+ - Print: `[confidence] Override accepted. Reason: <CONFIDENCE_OVERRIDE_REASON>. Proceeding with gate bypassed.`
1139
+ - Set `CONFIDENCE_STATUS=OVERRIDE`
1140
+ - Continue to Phase 4c.
1141
+ - If `CONFIDENCE_OVERRIDE_REASON` is non-empty but `override_allowed: false` in the config:
1142
+ - Print: `[confidence] Override is disabled in confidence-config.json.`
1143
+ - (Fall through to block below.)
1144
+ - If `CONFIDENCE_OVERRIDE_REASON` is empty or override was rejected:
1145
+ - Print the Breach Report (see format below).
1146
+ - Set `CONFIDENCE_BLOCKED=true`
1147
+ - Set `CONFIDENCE_STATUS=BLOCKED`
1148
+ - **Halt: do not proceed to Phase 4c.**
1149
+
1150
+ **If breaches exist and `on_breach: "warn"`:**
1151
+ - Print the Breach Report.
1152
+ - Set `CONFIDENCE_STATUS=WARN`
1153
+ - Continue to Phase 4c.
1154
+
1155
+ #### Breach Report Format
1156
+
1157
+ ```
1158
+ ## Confidence Gate: BLOCKED
1159
+
1160
+ The reviewer's confidence scores do not meet configured thresholds.
1161
+
1162
+ | Aspect | Score | Threshold | Delta |
1163
+ |--------|-------|-----------|-------|
1164
+ | <aspect> | <actual> | <threshold> | <delta (negative)> |
1165
+
1166
+ ### Reviewer Notes on Low-Scoring Aspects
1167
+
1168
+ **<aspect> (<score>):** <note from confidence-score.json>
1169
+
1170
+ ### Flags
1171
+
1172
+ - <flag-1>
1173
+ - <flag-2>
1174
+ (omit this section if flags array is empty)
1175
+
1176
+ ### Next Steps
1177
+
1178
+ 1. Address the concerns above and re-run `/specrails:implement`.
1179
+ 2. Or, if you have reviewed the concerns and accept the risk, re-run with an override:
1180
+ `/specrails:implement #N --confidence-override "reason"`
1181
+
1182
+ Pipeline halted. No git operations have been performed.
1183
+ ```
1184
+
1185
+ #### Dry-Run Behavior
1186
+
1187
+ When `DRY_RUN=true`, the reviewer still writes `confidence-score.json` (it is an OpenSpec artifact, not a git artifact). Phase 4b-conf still evaluates the score. If `CONFIDENCE_BLOCKED=true`, add to `.cache-manifest.json` under `skipped_operations`:
1188
+ ```
1189
+ "confidence-gate: blocked — Phase 4c skipped"
1190
+ ```
1191
+
1192
+ ### Phase 4c.0: Pre-ship conflict check
1193
+
1194
+ **Guard:** If `SNAPSHOTS_CAPTURED=false` OR `DRY_RUN=true`, print `[conflict-check] Skipped — SNAPSHOTS_CAPTURED=false (or dry-run mode).` and proceed directly to Phase 4c.
1195
+
1196
+ This check is independent of Phase 3a.0. Even if the user chose to continue through a conflict at Phase 3a.0, this gate re-checks all in-scope issues against the Phase 0 snapshot. It is the final gate before any code reaches git.
1197
+
1198
+ Re-fetch each issue in `ISSUE_REFS` and diff against `.claude/backlog-cache.json` using the same algorithm as Phase 3a.0:
1199
+
1200
+ **If `BACKLOG_PROVIDER=local`:** Read `.specrails/local-tickets.json` and extract each ticket by ID.
1201
+
1202
+ **If `BACKLOG_PROVIDER=github`:**
1203
+ ```bash
1204
+ gh issue view {number} --json number,title,state,assignees,labels,body,updatedAt
1205
+ ```
1206
+
1207
+ If the cache file is missing or malformed JSON at this point: log `[conflict-check] Warning: cache file missing or unreadable. Skipping diff for this run.` and proceed to Phase 4c (treat as clean).
1208
+
1209
+ Apply the same short-circuit (`updatedAt` match → clean), field comparison, and severity classification as Phase 3a.0.
1210
+
1211
+ If all issues are clean: print `[conflict-check] All issues clean (Phase 4c.0). Proceeding.` and continue.
1212
+
1213
+ If conflicts exist: print the same conflict report format as Phase 3a.0 (with `Phase 4c.0` context) and await `A`/`C` input (same re-prompt and default-abort logic).
1214
+
1215
+ **On abort:** Print `[conflict-abort] Pipeline aborted. Re-run /specrails:implement after resolving the issues.` and exit. No git operations have been performed at this point.
1216
+
1217
+ **On continue:** Print `[conflict-override] Continuing. N conflict(s) logged.` Append each conflict to `CONFLICT_OVERRIDES` as `{phase: "4c.0", issue: "#N", field: "<field>", severity: "<severity>", was: "<was>", now: "<now>"}`. Proceed to Phase 4c.
1218
+
1219
+ ### 4c. Ship — Git & backlog updates
1220
+
1221
+ **Security gate:** If `SECURITY_BLOCKED=true`:
1222
+ 1. Print all Critical findings from the security-reviewer output
1223
+ 2. Do NOT create a branch, commit, push, or PR
1224
+ 3. Print: "Pipeline blocked by security findings. Fix the Critical issues listed above and re-run /specrails:implement."
1225
+ 4. Skip to Phase 4e.
1226
+
1227
+ ### Dry-Run Gate
1228
+
1229
+ **If `DRY_RUN=true`:**
1230
+ Print: `[dry-run] Skipping all git and backlog operations.`
1231
+ Record skipped operations to `.cache-manifest.json` under `skipped_operations`:
1232
+ - `"git: branch creation (feat/<name>)"`
1233
+ - `"git: commit"`
1234
+ - `"git: push"`
1235
+ - `"github: pr creation"` (if `GH_AVAILABLE=true`)
1236
+ - If `BACKLOG_PROVIDER=local` and `BACKLOG_WRITE=true`:
1237
+ - `"local: ticket comment #{id}"` for each ticket in scope
1238
+ - `"local: ticket status update #{id}"` for each fully resolved ticket
1239
+ - If `BACKLOG_PROVIDER=github` and `BACKLOG_WRITE=true`:
1240
+ - `"github: issue comment #N"` for each issue in scope
1241
+ - `"github: issue close #N (via PR merge)"` for each fully resolved issue
1242
+
1243
+ Then skip the rest of Phase 4c and proceed directly to Phase 4e.
1244
+
1245
+ **If `APPLY_MODE=true`:**
1246
+ 1. Read `.cache-manifest.json` from `CACHE_DIR`.
1247
+ 2. For each entry in `files`: copy `cached_path` to `real_path`, creating directories as needed.
1248
+ 3. Print: `[apply] Copied N files from .claude/.dry-run/<feature-name>/ to real locations.`
1249
+ 4. Then proceed with Phase 4c normally (GIT_AUTO logic, backlog updates) using the real files.
1250
+ 5. On successful completion of Phase 4c: delete `CACHE_DIR` and print `[apply] Cache cleaned up.`
1251
+ If Phase 4c fails: preserve `CACHE_DIR` for re-run.
1252
+
1253
+ **Otherwise:** proceed as normal.
1254
+
1255
+ ---
1256
+
1257
+ This phase respects the `GIT_AUTO` and `BACKLOG_WRITE` settings from configuration.
1258
+
1259
+ #### If `GIT_AUTO=true` (automatic shipping)
1260
+
1261
+ 1. Create branch from `main`: `git checkout -b feat/<descriptive-name>`
1262
+ 2. One commit per feature with descriptive messages
1263
+ 3. If the reviewer modified files, create an additional commit: `fix: resolve CI issues (reviewer)`
1264
+ 4. Push with `-u` flag: `git push -u origin <branch-name>`
1265
+ 5. Create PR (if GitHub CLI is available):
1266
+ ```bash
1267
+
1268
+ ```
1269
+ If `gh` is not authenticated, print a compare URL for manual PR creation.
1270
+
1271
+ #### If `GIT_AUTO=false` (manual shipping)
1272
+
1273
+ Do NOT create branches, commits, or push. Instead display a summary:
1274
+
1275
+ ```
1276
+ ## Changes Ready for Review
1277
+
1278
+ All implementation is complete and CI checks pass.
1279
+
1280
+ ### Files Changed
1281
+ - [list all modified/created files per feature]
1282
+
1283
+ ### Suggested Next Steps
1284
+ 1. Review the changes: `git diff`
1285
+ 2. Create a branch: `git checkout -b feat/<name>`
1286
+ 3. Stage and commit: `git add <files> && git commit -m "feat: ..."`
1287
+ 4. Push and create PR manually
1288
+ ```
1289
+
1290
+ #### Backlog updates (both modes)
1291
+
1292
+ **If `BACKLOG_WRITE=true`:**
1293
+ - For fully resolved issues/tickets: add a comment noting completion and reference the PR:
1294
+ ```bash
1295
+
1296
+ ```
1297
+ - **Local:** Update the ticket status to `"done"` using `` and add a comment: `"Implemented in PR #XX. All acceptance criteria met."` via ``. Local tickets are closed directly — there is no auto-close-on-merge mechanism.
1298
+ - **GitHub:** `gh issue comment {number} --body "Implemented in PR #XX. All acceptance criteria met."` — do NOT close the issue explicitly. Use `Closes #N` in the PR body so GitHub auto-closes on merge.
1299
+ - **JIRA:** `jira issue comment {key} --message "Implemented in PR #XX. All acceptance criteria met."`
1300
+ - For GitHub/JIRA: ensure the PR body includes `Closes #N` for each fully resolved issue (auto-closes on merge)
1301
+ - For partially resolved issues/tickets: add a comment noting progress:
1302
+ ```bash
1303
+
1304
+ ```
1305
+ - **Local:** Additionally update the ticket status to `"in_progress"` via `` if it is still `"todo"`.
1306
+
1307
+ **If `BACKLOG_WRITE=false`:**
1308
+ - Do NOT create, modify, or comment on any issues/tickets.
1309
+ - Instead, display what the user should update manually:
1310
+ ```
1311
+ ## Backlog Updates (manual)
1312
+
1313
+ The following tickets should be updated:
1314
+ | Ticket | Status | Suggested Action |
1315
+ |--------|--------|-----------------|
1316
+ | #85 / PROJ-85 | Fully implemented | Close / move to Done |
1317
+ | #71 / PROJ-71 | Partial progress | Comment: "X completed, Y remaining" |
1318
+ ```
1319
+
1320
+ **Pipeline state:** update `ship` → `done` if git operations and PR creation succeeded, or `failed` with error context describing which step failed (e.g. `"git push failed: <exit code>"`, `"gh pr create failed"`, `"security gate blocked ship"`). If `DRY_RUN=true`: update `ship` → `skipped`.
1321
+
1322
+ ### 4d. Monitor CI
1323
+
1324
+ **Only if `GIT_AUTO=true` and code was pushed.**
1325
+
1326
+ Check CI status after pushing. Fix failures (up to 2 retries).
1327
+
1328
+ **Pipeline state:** update `ci` → `done` if CI passed, or `failed` with error context `"CI failed after 2 retries: <summary>"`. If CI was not run (`GIT_AUTO=false` or dry-run): update `ci` → `skipped`.
1329
+
1330
+ If `GIT_AUTO=false`: skip — the user will push and monitor CI themselves.
1331
+
1332
+ ### 4e. Report
1333
+
1334
+ **If `DRY_RUN=true`**, show this report instead of the standard pipeline table:
1335
+
1336
+ ---
1337
+
1338
+ ## Dry-Run Preview Report
1339
+
1340
+ ### Artifacts Generated
1341
+
1342
+ | Type | Location |
1343
+ |------|----------|
1344
+ | OpenSpec proposal | openspec/changes/\<name\>/proposal.md |
1345
+ | OpenSpec design | openspec/changes/\<name\>/design.md |
1346
+ | OpenSpec tasks | openspec/changes/\<name\>/tasks.md |
1347
+ | OpenSpec context-bundle | openspec/changes/\<name\>/context-bundle.md |
1348
+ | Developer files | .claude/.dry-run/\<name\>/ (N files) |
1349
+
1350
+ ### What Would Change
1351
+
1352
+ [For each file in `.cache-manifest.json` `files` array:]
1353
+ - `<real_path>` — [new file / modified] ([approximate line delta if available])
1354
+
1355
+ ### Confidence
1356
+
1357
+ | | |
1358
+ |-|--|
1359
+ | Score file | `openspec/changes/<name>/confidence-score.json` |
1360
+ | Gate result | `<CONFIDENCE_STATUS>` (PASS / WARN / BLOCKED / OVERRIDE / MISSING / DISABLED) |
1361
+ | Overall score | `<overall score from confidence-score.json, or N/A if MISSING/DISABLED>` |
1362
+
1363
+ ### Operations Skipped
1364
+
1365
+ [List items from `.cache-manifest.json` `skipped_operations` array]
1366
+
1367
+ ### Next Steps
1368
+
1369
+ To apply these changes and ship:
1370
+ ```
1371
+ /specrails:implement --apply <feature-name>
1372
+ ```
1373
+
1374
+ To discard this dry run:
1375
+ ```
1376
+ rm -rf .claude/.dry-run/<feature-name>/
1377
+ ```
1378
+
1379
+ ---
1380
+
1381
+ **Otherwise**, show the standard pipeline table:
1382
+
1383
+ ```
1384
+ | Area | Feature | Change Name | Architect | Developer | Tests | Docs | Reviewer | Frontend | Backend | Confidence | Security | CI | Conflicts | Status |
1385
+ |------|---------|-------------|-----------|-----------|-------|------|----------|----------|---------|------------|----------|----|-----------|--------|
1386
+ ```
1387
+
1388
+ Confidence column values:
1389
+
1390
+ | Value | Meaning |
1391
+ |-------|---------|
1392
+ | `PASS (82)` | All scores met thresholds; overall score shown in parens |
1393
+ | `WARN (62)` | Scores below threshold but `on_breach=warn`; overall score in parens |
1394
+ | `BLOCKED (62)` | Gate blocked the pipeline; overall score in parens |
1395
+ | `OVERRIDE (62)` | Gate bypassed by `--confidence-override`; overall score in parens |
1396
+ | `MISSING` | `confidence-score.json` not found after reviewer completed |
1397
+ | `DISABLED` | Gate disabled via `enabled: false` in config |
1398
+
1399
+ If `CONFIDENCE_OVERRIDE_REASON` is non-empty, append a `### Confidence Override` section below the table:
1400
+
1401
+ ```
1402
+ ### Confidence Override
1403
+
1404
+ **Reason:** <CONFIDENCE_OVERRIDE_REASON>
1405
+ ```
1406
+
1407
+ Column values:
1408
+ - **Frontend**: `CLEAN`, `ISSUES`, or `SKIPPED` (no frontend files in changeset)
1409
+ - **Backend**: `CLEAN`, `ISSUES`, or `SKIPPED` (no backend files in changeset)
1410
+ - **Security**: `CLEAN`, `WARNINGS`, `BLOCKED`, or `SKIPPED`
1411
+
1412
+ The `Conflicts` column values:
1413
+ - `skipped` — `SNAPSHOTS_CAPTURED=false` (non-issue input or GH unavailable)
1414
+ - `clean` — both conflict checks ran and found no changes
1415
+ - `overridden (N)` — user chose Continue at one or both gates; N is the total number of conflict records in `CONFLICT_OVERRIDES`
1416
+
1417
+ If `MERGE_REPORT.requires_resolution` is non-empty, print an additional section:
1418
+
1419
+ ```
1420
+ ### Merge Conflicts Requiring Resolution
1421
+
1422
+ | File | Features | Conflicting Region | Resolver Status |
1423
+ |------|----------|--------------------|-----------------|
1424
+ | <file> | <feature-a>, <feature-b> | <section heading or hunk description> | LOW_CONFIDENCE / SKIPPED |
1425
+
1426
+ Fix these conflicts (search for `<<<<<<<` in each file), then commit the resolved files.
1427
+ To retry smart resolution after addressing context: `/specrails:merge-resolve --files <file>`
1428
+ ```
1429
+
1430
+ If `CONFLICT_OVERRIDES` is non-empty, print:
1431
+
1432
+ ```
1433
+ ## Conflict Overrides
1434
+
1435
+ The following backlog conflicts were detected but overridden by the user:
1436
+
1437
+ | Phase | Issue | Field | Severity | Was | Now |
1438
+ |-------|-------|-------|----------|-----|-----|
1439
+ | 3a.0 | #42 | state | CRITICAL | open | closed |
1440
+ ```
1441
+
1442
+ If `CONFLICT_OVERRIDES` is empty or `SNAPSHOTS_CAPTURED=false`: omit the `## Conflict Overrides` section entirely. Do not print an empty table or a "No conflict overrides" line.
1443
+
1444
+ Include the shipping mode in the report:
1445
+ - If automatic: show PR URL, CI status, backlog updates made
1446
+ - If manual: show summary of changes, suggested git commands, backlog updates pending
1447
+
1448
+ ---
1449
+
1450
+ ## Error Handling
1451
+
1452
+ - If a sr-product-manager fails: skip that area, continue with others
1453
+ - If a sr-architect fails: skip that area, report the failure
1454
+ - If a sr-developer fails: report which phase it failed at
1455
+ - If the sr-reviewer finds unfixable issues: report them, push what works
1456
+ - If Phase 4c (ship) fails: report the failure
1457
+ - Never block the entire pipeline on a single agent failure. Always produce a final report.