@entelligentsia/forgecli 1.0.3 → 1.0.14

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 (497) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +2 -1
  3. package/dist/CHANGELOG-forge-plugin.md +250 -0
  4. package/dist/CHANGELOG-pi.md +94 -0
  5. package/dist/bin/forge.js +0 -0
  6. package/dist/extensions/forgecli/config-layer.d.ts +16 -0
  7. package/dist/extensions/forgecli/config-layer.js +5 -0
  8. package/dist/extensions/forgecli/config-layer.js.map +1 -1
  9. package/dist/extensions/forgecli/dashboard/component.d.ts +102 -0
  10. package/dist/extensions/forgecli/dashboard/component.js +882 -0
  11. package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
  12. package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
  13. package/dist/extensions/forgecli/dashboard/register.js +45 -0
  14. package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
  15. package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
  16. package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
  17. package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
  18. package/dist/extensions/forgecli/fix-bug.js +72 -7
  19. package/dist/extensions/forgecli/fix-bug.js.map +1 -1
  20. package/dist/extensions/forgecli/forge-artifact-tool.js +27 -4
  21. package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
  22. package/dist/extensions/forgecli/forge-cli-schema.json +4 -0
  23. package/dist/extensions/forgecli/forge-commands.js +1 -0
  24. package/dist/extensions/forgecli/forge-commands.js.map +1 -1
  25. package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
  26. package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
  27. package/dist/extensions/forgecli/forge-subagent.js +6 -4
  28. package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
  29. package/dist/extensions/forgecli/forge-tools.js +2 -2
  30. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  31. package/dist/extensions/forgecli/index.js +5 -0
  32. package/dist/extensions/forgecli/index.js.map +1 -1
  33. package/dist/extensions/forgecli/lib/halt-advisor.d.ts +54 -0
  34. package/dist/extensions/forgecli/lib/halt-advisor.js +90 -0
  35. package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
  36. package/dist/extensions/forgecli/migration-engine.js +25 -12
  37. package/dist/extensions/forgecli/migration-engine.js.map +1 -1
  38. package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +25 -0
  39. package/dist/extensions/forgecli/orchestrator-status-bar.js +183 -0
  40. package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
  41. package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
  42. package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
  43. package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
  44. package/dist/extensions/forgecli/project-orientation.js +12 -8
  45. package/dist/extensions/forgecli/project-orientation.js.map +1 -1
  46. package/dist/extensions/forgecli/regenerate.d.ts +16 -0
  47. package/dist/extensions/forgecli/regenerate.js +110 -0
  48. package/dist/extensions/forgecli/regenerate.js.map +1 -1
  49. package/dist/extensions/forgecli/run-sprint.js +33 -3
  50. package/dist/extensions/forgecli/run-sprint.js.map +1 -1
  51. package/dist/extensions/forgecli/run-task.d.ts +32 -0
  52. package/dist/extensions/forgecli/run-task.js +185 -12
  53. package/dist/extensions/forgecli/run-task.js.map +1 -1
  54. package/dist/extensions/forgecli/subagent/phase-guard.js +15 -5
  55. package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -1
  56. package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +1 -0
  57. package/dist/extensions/forgecli/subagent/phase-summary-map.js +17 -0
  58. package/dist/extensions/forgecli/subagent/phase-summary-map.js.map +1 -1
  59. package/dist/extensions/forgecli/thread-switcher.js +105 -764
  60. package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
  61. package/dist/extensions/forgecli/viewport-events.js +32 -0
  62. package/dist/extensions/forgecli/viewport-events.js.map +1 -1
  63. package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
  64. package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
  65. package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
  66. package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
  67. package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
  68. package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
  69. package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
  70. package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
  71. package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
  72. package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
  73. package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
  74. package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
  75. package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
  76. package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
  77. package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
  78. package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
  79. package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +29 -5
  80. package/dist/forge-payload/.base-pack/workflows/architect_approve.md +8 -10
  81. package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
  82. package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
  83. package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
  84. package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -7
  85. package/dist/forge-payload/.base-pack/workflows/commit_task.md +7 -9
  86. package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
  87. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +9 -9
  88. package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
  89. package/dist/forge-payload/.base-pack/workflows/plan_task.md +5 -6
  90. package/dist/forge-payload/.base-pack/workflows/review_code.md +8 -8
  91. package/dist/forge-payload/.base-pack/workflows/review_plan.md +8 -8
  92. package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
  93. package/dist/forge-payload/.base-pack/workflows/triage.md +13 -10
  94. package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
  95. package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
  96. package/dist/forge-payload/.base-pack/workflows/validate_task.md +6 -8
  97. package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
  98. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
  99. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
  100. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  101. package/dist/forge-payload/.schemas/_defs/locator.schema.json +13 -0
  102. package/dist/forge-payload/.schemas/bug.schema.json +1 -0
  103. package/dist/forge-payload/.schemas/config.schema.json +2 -3
  104. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  105. package/dist/forge-payload/.schemas/event.schema.json +16 -0
  106. package/dist/forge-payload/.schemas/migrations.json +299 -0
  107. package/dist/forge-payload/.schemas/sprint.schema.json +1 -0
  108. package/dist/forge-payload/.schemas/task.schema.json +1 -0
  109. package/dist/forge-payload/commands/health.md +29 -0
  110. package/dist/forge-payload/commands/rebuild.md +143 -15
  111. package/dist/forge-payload/commands/update.md +28 -27
  112. package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
  113. package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
  114. package/dist/forge-payload/integrity.json +7 -6
  115. package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
  116. package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
  117. package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
  118. package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
  119. package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
  120. package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
  121. package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
  122. package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
  123. package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
  124. package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
  125. package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
  126. package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
  127. package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +29 -5
  128. package/dist/forge-payload/meta/workflows/meta-approve.md +8 -10
  129. package/dist/forge-payload/meta/workflows/meta-bug-triage.md +13 -10
  130. package/dist/forge-payload/meta/workflows/meta-collate.md +6 -8
  131. package/dist/forge-payload/meta/workflows/meta-commit.md +7 -9
  132. package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
  133. package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
  134. package/dist/forge-payload/meta/workflows/meta-implement.md +18 -9
  135. package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
  136. package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
  137. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +175 -82
  138. package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
  139. package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
  140. package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
  141. package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
  142. package/dist/forge-payload/meta/workflows/meta-review-implementation.md +8 -8
  143. package/dist/forge-payload/meta/workflows/meta-review-plan.md +8 -8
  144. package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
  145. package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
  146. package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
  147. package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
  148. package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
  149. package/dist/forge-payload/meta/workflows/meta-validate.md +6 -8
  150. package/dist/forge-payload/schemas/_defs/locator.schema.json +13 -0
  151. package/dist/forge-payload/schemas/bug.schema.json +1 -0
  152. package/dist/forge-payload/schemas/config.schema.json +2 -3
  153. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  154. package/dist/forge-payload/schemas/event.schema.json +16 -0
  155. package/dist/forge-payload/schemas/sprint.schema.json +1 -0
  156. package/dist/forge-payload/schemas/structure-manifest.json +76 -73
  157. package/dist/forge-payload/schemas/task.schema.json +1 -0
  158. package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
  159. package/dist/forge-payload/tools/artifact-store.cjs +242 -0
  160. package/dist/forge-payload/tools/artifact.cjs +60 -120
  161. package/dist/forge-payload/tools/banners.cjs +29 -10
  162. package/dist/forge-payload/tools/check-structure.cjs +88 -7
  163. package/dist/forge-payload/tools/collate.cjs +16 -2
  164. package/dist/forge-payload/tools/lib/artifact-kinds.cjs +95 -0
  165. package/dist/forge-payload/tools/lib/store-nlp.cjs +6 -0
  166. package/dist/forge-payload/tools/lib/store-query-exec.cjs +39 -5
  167. package/dist/forge-payload/tools/lib/suggest.cjs +2 -1
  168. package/dist/forge-payload/tools/manage-config.cjs +5 -7
  169. package/dist/forge-payload/tools/parse-gates.cjs +73 -1
  170. package/dist/forge-payload/tools/postflight-gate.cjs +252 -0
  171. package/dist/forge-payload/tools/preflight-gate.cjs +102 -5
  172. package/dist/forge-payload/tools/store-cli.cjs +50 -15
  173. package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
  174. package/dist/forge-payload/tools/verify-phase.cjs +17 -0
  175. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
  176. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  177. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
  178. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  179. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  180. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
  181. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
  182. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +19 -24
  184. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  185. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
  186. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
  187. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
  188. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
  189. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
  190. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  191. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
  192. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  193. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +374 -122
  195. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  196. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +424 -232
  197. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  198. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
  199. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  200. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +38 -2
  201. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  202. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  203. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +21 -12
  204. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  205. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  206. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +6 -10
  207. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +3 -4
  216. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
  217. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
  218. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
  219. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
  220. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  221. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +159 -78
  222. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  223. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  224. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +16 -11
  225. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
  226. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  227. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +6 -10
  231. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
  234. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
  237. package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -4
  239. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  241. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
  242. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
  246. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
  248. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
  249. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  252. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  254. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
  257. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
  259. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  261. package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +94 -0
  262. package/node_modules/@earendil-works/pi-coding-agent/README.md +9 -0
  263. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +3 -0
  264. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  265. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
  266. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +15 -2
  269. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +1 -0
  271. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
  272. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
  273. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
  274. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -1
  275. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +28 -4
  277. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  279. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  280. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  281. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -1
  282. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  283. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  284. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  285. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +7 -5
  286. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  287. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  288. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  289. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
  290. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  291. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  292. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
  293. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  294. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts +9 -1
  295. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
  296. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
  297. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts +2 -0
  299. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +10 -6
  301. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts +6 -7
  303. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +75 -28
  305. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  306. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +2 -0
  307. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
  309. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  310. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  311. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
  312. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  313. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
  315. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  317. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  318. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  319. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  320. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  321. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
  322. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  323. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  324. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
  325. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts +5 -2
  327. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  328. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
  329. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  330. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  331. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
  332. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  333. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +2 -0
  334. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
  335. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
  336. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
  337. package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
  338. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
  339. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
  340. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  341. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
  342. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
  343. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -3
  344. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  345. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
  346. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  347. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  348. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  349. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  350. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  351. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  352. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
  353. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  354. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  355. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
  356. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  357. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  358. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -1
  359. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  360. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
  361. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  362. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  363. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts +4 -0
  364. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts.map +1 -0
  365. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
  366. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js.map +1 -0
  367. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts +3 -0
  368. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts.map +1 -0
  369. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
  370. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js.map +1 -0
  371. package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +13 -10
  372. package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +1 -1
  373. package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +12 -6
  374. package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -12
  375. package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +13 -5
  376. package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +1 -0
  377. package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +2 -1
  378. package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +6 -0
  379. package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +1 -1
  380. package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +8 -0
  381. package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +7 -3
  382. package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +2 -0
  383. package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +2 -2
  384. package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +9 -0
  385. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +1 -0
  386. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  387. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
  388. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
  389. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  390. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
  391. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
  392. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
  393. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
  394. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +443 -61
  395. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  396. package/node_modules/@earendil-works/pi-tui/README.md +2 -2
  397. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  398. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +24 -83
  399. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  400. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
  401. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +7 -55
  402. package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
  403. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +7 -1
  404. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
  405. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  406. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
  407. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  408. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  409. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  410. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
  411. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
  412. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
  413. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
  414. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
  415. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
  416. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
  417. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
  418. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +6 -1
  419. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  420. package/node_modules/@earendil-works/pi-tui/dist/utils.js +27 -15
  421. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  422. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
  423. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
  424. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
  425. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
  426. package/node_modules/@earendil-works/pi-tui/package.json +2 -2
  427. package/node_modules/@entelligentsia/forge-compress/LICENSE +21 -0
  428. package/node_modules/@entelligentsia/forge-compress/README.md +85 -0
  429. package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
  430. package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
  431. package/node_modules/@mariozechner/clipboard/index.js +546 -257
  432. package/node_modules/@mariozechner/clipboard/package.json +5 -6
  433. package/node_modules/@mariozechner/clipboard/package.json.prepack-backup +14 -14
  434. package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
  435. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
  436. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
  437. package/package.json +7 -7
  438. package/dist/bin/forgecli.d.ts +0 -2
  439. package/dist/bin/forgecli.js +0 -6
  440. package/dist/bin/forgecli.js.map +0 -1
  441. package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
  442. package/dist/extensions/forgecli/config-tui/index.js +0 -5
  443. package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
  444. package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
  445. package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
  446. package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
  447. package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
  448. package/dist/extensions/forgecli/loaders/template-render.js +0 -85
  449. package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
  450. package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
  451. package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
  452. package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
  453. package/dist/forge-payload/.base-pack/commands/quiz-agent.md +0 -6
  454. package/dist/forge-payload/.base-pack/commands/retrospective.md +0 -6
  455. package/dist/forge-payload/.base-pack/commands/sprint-intake.md +0 -6
  456. package/dist/forge-payload/.base-pack/commands/sprint-plan.md +0 -6
  457. package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
  458. package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -934
  459. package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
  460. package/dist/forge-payload/commands/calibrate.md +0 -10
  461. package/dist/forge-payload/commands/materialize.md +0 -119
  462. package/dist/forge-payload/commands/migrate.md +0 -12
  463. package/dist/forge-payload/commands/quiz-agent.md +0 -6
  464. package/dist/forge-payload/commands/regenerate.md +0 -6
  465. package/dist/forge-payload/commands/store-query.md +0 -6
  466. package/dist/forge-payload/commands/store-repair.md +0 -6
  467. package/dist/forge-payload/commands/update-tools.md +0 -10
  468. package/dist/forge-payload/meta/templates/meta-retrospective.md +0 -28
  469. package/dist/forge-payload/tools/prompts/sprint-plan-prompt.md +0 -70
  470. package/dist/forge-payload/tools/schemas/task-list.schema.json +0 -53
  471. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +0 -4
  472. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +0 -1
  473. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +0 -3
  474. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +0 -1
  475. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +0 -20
  476. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +0 -1
  477. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +0 -92
  478. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +0 -1
  479. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +0 -18
  480. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +0 -1
  481. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +0 -42
  482. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +0 -1
  483. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +0 -10
  484. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +0 -1
  485. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +0 -31
  486. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +0 -1
  487. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +0 -30
  488. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +0 -1
  489. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +0 -170
  490. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +0 -1
  491. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +0 -26
  492. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +0 -1
  493. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +0 -90
  494. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +0 -1
  495. package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +0 -3
  496. package/node_modules/@mariozechner/clipboard-linux-x64-musl/clipboard.linux-x64-musl.node +0 -0
  497. package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +0 -25
@@ -1,934 +0,0 @@
1
- ---
2
- requirements:
3
- reasoning: High
4
- context: High
5
- speed: Medium
6
- audience: orchestrator-only
7
- deps:
8
- personas: [architect, engineer, supervisor, bug-fixer, collator, qa-engineer]
9
- skills: [architect, engineer, supervisor, generic]
10
- templates: []
11
- sub_workflows: [plan_task, implement_plan, review_plan, review_code, fix_bug, architect_approve, commit_task, validate_task]
12
- kb_docs: [architecture/stack.md]
13
- context_pack: .forge/cache/context-pack.md
14
- config_fields: [paths.engineering]
15
- ---
16
-
17
-
18
- # Orchestrate Task
19
- ## Pipeline Phases
20
-
21
- Each phase has:
22
- - `name` — identifier
23
- - `agent` — which role executes
24
- - `workflow` — which workflow file to load
25
- - `requires` — prerequisite artifact
26
- - `produces` — output artifact
27
- - `max_iterations` — revision loop limit (for review phases)
28
- - `gate_checks` — conditions that must pass before proceeding
29
-
30
- ## Model Resolution
31
-
32
- Detect cluster from env vars at session start, then dispatch accordingly:
33
-
34
- | Env var | Purpose |
35
- |---------|---------|
36
- | `ANTHROPIC_DEFAULT_OPUS_MODEL` | What "opus" resolves to |
37
- | `ANTHROPIC_DEFAULT_SONNET_MODEL` | What "sonnet" resolves to |
38
- | `ANTHROPIC_DEFAULT_HAIKU_MODEL` | What "haiku" resolves to |
39
-
40
- - **Single cluster** — all three vars equal (or unset): omit `model` on Agent spawns; subagents inherit the parent.
41
- - **Tiered cluster** — vars differ: pass `model=tier` (opus/sonnet/haiku) based on ROLE_TIER mapping.
42
- - **Unknown cluster** — no `ANTHROPIC_DEFAULT_*` vars: pass the canonical model ID from ROLE_TIER_DEFAULTS.
43
- - **Per-phase override** — `model` field in `config.pipelines` phase takes highest precedence.
44
-
45
- ### Role-to-Tier Mapping
46
-
47
- | Role | Tier |
48
- |------|------|
49
- | `review-plan`, `review-code`, `validate`, `approve` | opus |
50
- | `plan`, `implement` | sonnet |
51
- | `commit`, `writeback` | haiku |
52
-
53
- Unknown cluster canonical defaults: opus → `claude-opus-4-5`, sonnet → `claude-sonnet-4-6`, haiku → `claude-haiku-4-5`.
54
-
55
- Phase announcement format: `→ TASK-ID [tier → resolved-model]` (e.g. `→ SPECT-T01 [opus → claude-opus-4-6]`).
56
- On single cluster, show the model directly. On unknown, show `tier → canonical`.
57
-
58
- ## Pipeline Resolution
59
-
60
- The orchestrator supports pluggable pipelines. When starting a task:
61
-
62
- 1. Read the task manifest from `.forge/store/tasks/{TASK_ID}.json`.
63
- 2. If `task.pipeline` is set, look up that key in `.forge/config.json` → `pipelines`.
64
- 3. If found, use the phases defined in that pipeline.
65
- 4. If `task.pipeline` is not set or the key is not found, use the `default` pipeline
66
- (either from `config.pipelines.default` or the hardcoded default below).
67
-
68
- Each phase in a pipeline has:
69
- - `command` — the slash command to invoke (passed the task ID as argument)
70
- - `role` — semantic role (`plan`, `review-plan`, `implement`, `review-code`, `approve`, `commit`)
71
- - `maxIterations` — for review roles, the revision loop limit (default 3)
72
- - `on_revision` — (optional) command name of the phase to re-invoke on "Revision Required";
73
- if absent, defaults to the nearest preceding phase whose role is not a review role
74
-
75
- ## Default Pipeline
76
-
77
- ```
78
- plan → review-plan → [loop max 3] → implement → review-code → [loop max 3] → validate → [loop max 3] → approve → writeback → commit
79
- ```
80
-
81
- When no `pipelines` section exists in config, the orchestrator uses this
82
- hardcoded default. Projects that define `config.pipelines.default` override it.
83
-
84
- ## Context Isolation
85
-
86
- **Each phase MUST run as a subagent (Agent tool call), NOT inline.**
87
-
88
- Invoking phases inline accumulates context from every prior phase and task into
89
- the orchestrator's window. This violates Forge's design principle of keeping
90
- context light and nimble. By the time a sprint reaches its third or fourth task,
91
- an inline orchestrator is carrying tens of thousands of tokens of prior work that
92
- is irrelevant to the current phase.
93
-
94
- The fix: use the Agent tool to spawn a subagent per phase. Each subagent:
95
- - Starts with a fresh context window
96
- - Receives only what it needs: the workflow file path and the task ID
97
- - Receives a PROJECT_OVERLAY (task-scoped index slice) instead of reading MASTER_INDEX.md directly
98
- - Writes results to disk (artifacts, task status updates)
99
- - Returns to the orchestrator, which then reads the verdict from disk
100
-
101
- The orchestrator itself stays minimal — it only holds the phase loop and event log.
102
-
103
- ## Token Self-Reporting
104
-
105
- Each phase subagent is responsible for reporting its own token usage via a sidecar file.
106
-
107
- **Before returning, every subagent MUST:**
108
-
109
- 1. Probe token usage for the session: invoke `/cost` if the host runtime
110
- supports it (Claude Code only); on any other runtime treat as unavailable.
111
- Do NOT shell out to a `cost-cli.cjs` — there is no such tool.
112
- 2. Parse the output for the five fields:
113
- `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens`, `estimatedCostUSD`.
114
- 3. Write the usage sidecar via `node "$FORGE_ROOT/tools/store-cli.cjs" emit {sprintId} '{sidecar-json}' --sidecar` with the exact format:
115
- ```json
116
- {
117
- "inputTokens": <integer>,
118
- "outputTokens": <integer>,
119
- "cacheReadTokens": <integer>,
120
- "cacheWriteTokens": <integer>,
121
- "estimatedCostUSD": <number>
122
- }
123
- ```
124
-
125
- The `eventId` is computed by the orchestrator before spawning and passed in the subagent prompt —
126
- it follows the format `{ISO_TIMESTAMP}_{TASK_ID}_{role}_{action}` (e.g.
127
- `20260415T141523000Z_ACME-S02-T03_engineer_implement`).
128
-
129
- The leading underscore on the sidecar filename marks it as ephemeral — `validate-store.cjs` skips
130
- files prefixed with `_`, so the sidecar will never be treated as a real event record. If `/cost` is
131
- unavailable or token data cannot be parsed, skip writing the sidecar silently — the orchestrator
132
- handles missing sidecars gracefully (see Execution Algorithm below).
133
-
134
- ## Role-to-Noun Mapping
135
-
136
- The orchestrator resolves persona and skill file lookups using **noun-based**
137
- filenames, not role-literal filenames. A role like `plan` maps to the noun
138
- `engineer`, so the persona file is `engineer.md`, not `plan.md`.
139
-
140
- ```
141
- ROLE_TO_NOUN = {
142
- "plan": "engineer",
143
- "implement": "engineer",
144
- "update-plan": "engineer",
145
- "update-impl": "engineer",
146
- "commit": "engineer",
147
- "review-plan": "supervisor",
148
- "review-code": "supervisor",
149
- "validate": "qa-engineer",
150
- "approve": "architect",
151
- "writeback": "collator",
152
- }
153
- ```
154
-
155
- The `.get(key, fallback)` pattern preserves the old role-literal behaviour for
156
- any role not yet in the table, which is a safe degradation path for custom
157
- pipeline roles.
158
-
159
- ## Persona Injection Modes
160
-
161
- Subagent prompts include a **role block** that tells the agent who it is
162
- and what capabilities it has. Two modes are supported, selected by the
163
- `FORGE_PROMPT_MODE` environment variable:
164
-
165
- | Mode | Behaviour | Default |
166
- |------|-----------|---------|
167
- | `reference` | Compact summary from `.forge/cache/persona-pack.json`, plus a file_ref pointer to the full persona/skill definitions. | ✅ |
168
- | `inline` | Legacy: inject the full verbatim persona and skill file contents. Kept for one version as a rollback path. | |
169
-
170
- The pack is built by `/forge:rebuild` via
171
- `forge/tools/build-persona-pack.cjs`. It compiles YAML frontmatter from
172
- `$FORGE_ROOT/meta/personas/meta-*.md` and `$FORGE_ROOT/meta/skills/meta-*.md`
173
- into `.forge/cache/persona-pack.json`.
174
-
175
- ### Helper: `compose_role_block(persona_noun)`
176
-
177
- ```
178
- def compose_role_block(persona_noun):
179
- mode = os.environ.get("FORGE_PROMPT_MODE", "reference")
180
-
181
- if mode == "inline":
182
- # Legacy behaviour — full persona + skill prose inline.
183
- persona_content = read_file(f".forge/personas/{persona_noun}.md")
184
- skill_content = read_file(f".forge/skills/{persona_noun}-skills.md")
185
- return f"{persona_content}\n\n{skill_content}"
186
-
187
- # Reference mode (default) — compact summary from the pack.
188
- pack = read_json(".forge/cache/persona-pack.json")
189
- persona = pack["personas"].get(persona_noun)
190
- skill = pack["skills"].get(f"{persona_noun}-skills")
191
-
192
- if not persona:
193
- # Fail loud rather than silently degrade. Missing pack entry is a
194
- # regeneration bug and should be reported via /forge:report-bug.
195
- raise OrchestratorError(
196
- f"persona '{persona_noun}' not in persona-pack. "
197
- "Run /forge:rebuild to rebuild the pack."
198
- )
199
-
200
- lines = [
201
- f"You are acting as the {persona['role']}.",
202
- "",
203
- f"Persona: {persona['id']} — {persona['summary']}",
204
- "",
205
- "Your responsibilities:",
206
- ]
207
- for r in persona.get("responsibilities", []):
208
- lines.append(f"- {r}")
209
- if persona.get("outputs"):
210
- lines.append("")
211
- lines.append(f"Your outputs: {', '.join(persona['outputs'])}")
212
-
213
- if skill:
214
- lines.append("")
215
- lines.append("Skill capabilities you have available:")
216
- for c in skill.get("capabilities", []):
217
- lines.append(f"- {c}")
218
-
219
- lines.append("")
220
- lines.append(
221
- f"Full persona definition: {persona['file_ref']}. "
222
- + (f"Full skill definition: {skill['file_ref']}. " if skill else "")
223
- + "The summary above is authoritative. If insufficient, escalate — "
224
- + "do not read the full persona or skill file."
225
- )
226
- return "\n".join(lines)
227
- ```
228
-
229
- **Rollback:** set `FORGE_PROMPT_MODE=inline`. No persisted state to revert.
230
- The `inline` branch will be removed one version after `reference` ships.
231
-
232
- ## Execution Algorithm
233
-
234
- The orchestrator MUST follow this procedure exactly. Do not deviate.
235
-
236
- ```
237
- # --- Persona symbol lookup (emoji, name, tagline) ---
238
- PERSONA_MAP = {
239
- "plan": ("🌱", "Engineer", "I plan what will be built before any code is written."),
240
- "implement": ("🌱", "Engineer", "I build what was planned. I do not move forward until the code is clean."),
241
- "update-plan": ("🌱", "Engineer", "I address what the Supervisor found. No more, no less."),
242
- "update-impl": ("🌱", "Engineer", "I address what the Supervisor found. No more, no less."),
243
- "commit": ("🌱", "Engineer", "I close out completed work with a clean, honest commit."),
244
- "review-plan": ("🌿", "Supervisor", "I review before things move forward. I read the actual task prompt, not just the plan."),
245
- "review-code": ("🌿", "Supervisor", "I review before things move forward. I read the actual code, not the report."),
246
- "validate": ("🍵", "QA Engineer", "I validate against what was promised. The code compiling is not enough."),
247
- "approve": ("🗻", "Architect", "I hold the shape of the whole. I give final sign-off before commit."),
248
- "writeback": ("🍃", "Collator", "I gather what exists and arrange it into views."),
249
- }
250
-
251
- # --- Banner identity map (banner name per phase role) ---
252
- # Maps each role to a banner in forge/tools/banners.cjs.
253
- # Displayed by the orchestrator ONLY (badge before spawn, exit signal after return).
254
- # Subagents do NOT display banners — the orchestrator owns phase announcements.
255
- BANNER_MAP = {
256
- "plan": "forge",
257
- "implement": "forge",
258
- "update-plan": "forge",
259
- "update-impl": "forge",
260
- "commit": "forge",
261
- "review-plan": "oracle",
262
- "review-code": "oracle",
263
- "validate": "lumen",
264
- "approve": "north",
265
- "writeback": "drift",
266
- }
267
-
268
- for each task in dependency_sorted(tasks):
269
- # --- Pre-task status guard ---
270
- # If a task is already blocked or escalated from a prior sprint/run,
271
- # skip it entirely rather than attempting any phase.
272
- task_record = read_json(f".forge/store/tasks/{task.taskId}.json")
273
- if task_record and task_record.get("status") in ("blocked", "escalated"):
274
- print(f" ⚠ {task.taskId} — status is {task_record['status']}, skipping\n")
275
- emit_event(task, phase=None, action="task_skipped",
276
- notes=f"task status is {task_record['status']}")
277
- continue
278
-
279
- phases = resolve_pipeline(task) # from config.pipelines or default
280
- iteration_counts = {} # keyed by phase command name
281
- retry_count = {} # keyed by phase command name (subagent retry tracking)
282
- i = 0
283
-
284
- # --- Detect execution cluster from env vars (see Model Resolution) ---
285
- opus_model = env("ANTHROPIC_DEFAULT_OPUS_MODEL", "")
286
- sonnet_model = env("ANTHROPIC_DEFAULT_SONNET_MODEL", "")
287
- haiku_model = env("ANTHROPIC_DEFAULT_HAIKU_MODEL", "")
288
- if opus_model and opus_model == sonnet_model == haiku_model:
289
- cluster = "single"
290
- resolved_model = opus_model # all tiers same model
291
- elif opus_model:
292
- cluster = "tiered"
293
- resolved_model = None # each tier resolves differently
294
- else:
295
- cluster = "unknown"
296
- resolved_model = env("CLAUDE_CODE_SUBAGENT_MODEL", "unknown")
297
-
298
- # --- Role-to-tier mapping for tiered cluster dispatch ---
299
- ROLE_TIER = {
300
- "review-plan": "opus",
301
- "review-code": "opus",
302
- "validate": "opus",
303
- "approve": "opus",
304
- "plan": "sonnet",
305
- "implement": "sonnet",
306
- "commit": "haiku",
307
- "writeback": "haiku",
308
- }
309
-
310
- # --- Clear progress log for this sprint ---
311
- progress_log_path = f".forge/store/events/{sprint_id}/progress.log"
312
- run_bash(f'FORGE_ROOT=$(node -e "console.log(require(\'./.forge/config.json\').paths.forgeRoot)") && node "$FORGE_ROOT/tools/store-cli.cjs" progress-clear {sprint_id}')
313
-
314
- while i < len(phases):
315
- phase = phases[i]
316
-
317
- # --- Resolve model for display and dispatch (see Model Resolution) ---
318
- if phase.model: # per-phase override from config
319
- display_model = phase.model
320
- dispatch_model = phase.model # pass override to Agent tool
321
- if env(f"ANTHROPIC_DEFAULT_{phase.model.upper()}_MODEL"):
322
- resolved = env(f"ANTHROPIC_DEFAULT_{phase.model.upper()}_MODEL")
323
- display_model = f"{phase.model} → {resolved}"
324
- elif cluster == "single" and resolved_model:
325
- display_model = resolved_model
326
- dispatch_model = None # inherit parent model
327
- elif cluster == "tiered":
328
- tier = ROLE_TIER.get(phase.role, "sonnet")
329
- resolved = env(f"ANTHROPIC_DEFAULT_{tier.upper()}_MODEL", tier)
330
- display_model = f"{tier} → {resolved}" if resolved != tier else tier
331
- dispatch_model = tier # pass tier name, Claude Code resolves
332
- else:
333
- # Unknown cluster: no ANTHROPIC_DEFAULT_*_MODEL vars set.
334
- # Fall back to ROLE_TIER with canonical model defaults so subagents
335
- # run on a predictable model instead of inheriting the orchestrator's own.
336
- ROLE_TIER_DEFAULTS = {
337
- "opus": "claude-opus-4-5",
338
- "sonnet": "claude-sonnet-4-6",
339
- "haiku": "claude-haiku-4-5",
340
- }
341
- tier = ROLE_TIER.get(phase.role, "sonnet")
342
- canonical = ROLE_TIER_DEFAULTS[tier]
343
- display_model = f"{tier} → {canonical}"
344
- dispatch_model = canonical # pass full model id to Agent tool
345
-
346
- # --- Compute eventId before spawning so the subagent can name its sidecar ---
347
- start_ts = current_iso_timestamp() # e.g. "20260415T141523000Z"
348
- event_id = f"{start_ts}_{task_id}_{phase.role}_{phase.action}"
349
- sidecar_path = f".forge/store/events/{sprint_id}/_{event_id}_usage.json" # used by merge-sidecar
350
-
351
- # --- Compute agent name for progress IPC ---
352
- persona_noun = ROLE_TO_NOUN.get(phase.role, phase.role)
353
- iteration = iteration_counts.get(phase.command, 0) + 1
354
- agent_name = f"{task_id}:{persona_noun}:{phase.role}:{iteration}"
355
-
356
- # --- Announce phase with identity banner (badge) + task context ---
357
- emoji, persona_name, tagline = PERSONA_MAP.get(phase.role, ("🌊", "Orchestrator", "I move tasks through their lifecycle."))
358
- banner_name = BANNER_MAP.get(phase.role, "forge")
359
- run_bash(f'FORGE_ROOT=$(node -e "console.log(require(\'./.forge/config.json\').paths.forgeRoot)") && node "$FORGE_ROOT/tools/banners.cjs" --badge {banner_name}')
360
- print(f" → {task_id} [{display_model}]\n")
361
-
362
- # --- Start progress Monitor before spawning subagent ---
363
- # The Monitor streams lines from the progress log as the subagent works.
364
- # New lines arrive as notifications while the Agent tool blocks on the subagent.
365
- start_monitor(
366
- command=f"tail -n +1 -F {progress_log_path} 2>/dev/null || true",
367
- description=f"Progress: {agent_name}",
368
- persistent=False
369
- )
370
-
371
- # --- Pre-flight gate check (see Phase Gates below) ---
372
- # Resolve FORGE_ROOT once so the CLI shim can locate the gate parser.
373
- FORGE_ROOT = resolve_forge_root()
374
- preflight_result = run_bash(
375
- f'node "$FORGE_ROOT/tools/preflight-gate.cjs" --phase {phase.role} --task {task_id}'
376
- )
377
- if preflight_result.exit_code == 1:
378
- # Gate failed: halt the orchestrator loop for THIS task. Do not retry,
379
- # do not spawn. Missing prerequisites are listed on stderr.
380
- print(f" ✗ {task_id} {phase.role} — gate failed\n{preflight_result.stderr}")
381
- append_progress(progress_log_path, f"❌ Gate failed for {phase.role}: {preflight_result.stderr}")
382
- emit_event(task, phase, action="gate_failed", notes=preflight_result.stderr)
383
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
384
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
385
- emit_event(task, phase, eventId=event_id, iteration=iteration,
386
- action="escalated", verdict="escalated",
387
- notes=f"gate_failed: {preflight_result.stderr}")
388
- print(f" ⚠ Task {task_id} escalated: gate_failed: {preflight_result.stderr}\n")
389
- print(f" Review artifact: {artifact_path}\n")
390
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
391
- break # stop processing this task
392
- elif preflight_result.exit_code == 2:
393
- # Misconfiguration (unknown phase, malformed gates block). Fail loud.
394
- print(f" ⚠ {task_id} {phase.role} — gate misconfigured\n{preflight_result.stderr}")
395
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
396
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
397
- emit_event(task, phase, eventId=event_id, iteration=iteration,
398
- action="escalated", verdict="escalated",
399
- notes=f"gate_misconfigured: {preflight_result.stderr}")
400
- print(f" ⚠ Task {task_id} escalated: gate_misconfigured: {preflight_result.stderr}\n")
401
- print(f" Review artifact: {artifact_path}\n")
402
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
403
- break
404
-
405
- # --- Invoke phase as subagent (fresh context per phase) ---
406
- emit_event(task, phase, eventId=event_id, iteration=iteration, action="start")
407
-
408
- # Symmetric Injection Assembly: Persona -> Skill -> Workflow
409
- # Mode is governed by FORGE_PROMPT_MODE (default: "reference").
410
- # See "Persona injection modes" below for the full helper definition.
411
- role_block = compose_role_block(persona_noun)
412
-
413
- # --- Compose prior-phase summary block (delta: last 3 phases only) ---
414
- # <!-- See _fragments/context-injection.md for canonical definition -->
415
- summary_block = compose_summary_block(task_id, record_type="task") if phase.context.prior_summaries != "none" else ""
416
-
417
- # --- Compose architecture context block (conditional on phase.context.architecture) ---
418
- # <!-- See _fragments/context-injection.md for canonical definition -->
419
- architecture_block = (
420
- compose_architecture_block(".forge/cache/context-pack.md", ".forge/cache/context-pack.json")
421
- if phase.context.architecture else ""
422
- )
423
-
424
- # --- Materialize project overlay (replaces MASTER_INDEX.md read in subagent) ---
425
- overlay_result = run_bash(
426
- f'node "$FORGE_ROOT/tools/build-overlay.cjs" --task {task_id} --format md'
427
- )
428
- overlay_md = overlay_result.stdout if overlay_result.exit_code == 0 else ""
429
-
430
- # --- Load finalize fragment (token reporting contract) ---
431
- finalize_fragment = read_file(f"{FORGE_ROOT}/meta/workflows/_fragments/finalize.md") if file_exists(f"{FORGE_ROOT}/meta/workflows/_fragments/finalize.md") else ""
432
-
433
- # --- Compose review loop context block (review-role phases only) ---
434
- # Injected between summary_block and role_block so reviewers know their
435
- # position in the revision loop at the moment they are spawned.
436
- # `iteration` is the current attempt number (pre-spawn, not post-increment).
437
- # `phase.maxIterations` is the configured limit (default 3).
438
- if phase.role in ("review-plan", "review-code", "validate"):
439
- review_loop_context = (
440
- f"### Review Loop Context\n"
441
- f"- Iteration: {iteration} of {phase.maxIterations}\n"
442
- f"- Is final iteration: {iteration >= phase.maxIterations}\n\n"
443
- )
444
- else:
445
- review_loop_context = ""
446
-
447
- spawn_kwargs = dict(
448
- prompt=(
449
- f"Append progress entries to {progress_log_path} via store-cli "
450
- f"(agent: {agent_name}, banner: {banner_name}) — see _fragments/progress-reporting.md.\n\n"
451
- f"---\n\n"
452
- f"{architecture_block}"
453
- f"{summary_block}"
454
- f"{review_loop_context}"
455
- f"{role_block}\n\n"
456
- f"### Project Context\n"
457
- f"{overlay_md}\n\n"
458
- f"### Current Working Context\n"
459
- f"- Sprint Root: {sprint_root_path}\n"
460
- f"- Task Root: {task_root_path}\n"
461
- f"- Store Root: {store_root_path}\n\n"
462
- f"Read `.forge/workflows/{phase.workflow}` and follow it. Task ID: {task_id}.\n\n"
463
- f"{finalize_fragment}"
464
- ),
465
- description=f"{emoji} {persona_name} — {phase.name} for {task_id}",
466
- )
467
- if dispatch_model:
468
- spawn_kwargs["model"] = dispatch_model
469
- spawn_subagent(**spawn_kwargs)
470
- # Subagent reads all context from disk, does its work, writes artifacts/status to disk, then exits.
471
-
472
- # --- Stop progress Monitor ---
473
- stop_monitor(progress_log_path)
474
-
475
- # --- Subagent response validation (retry once, escalate on second failure) ---
476
- # The subagent must produce a usable result. Three failure classes:
477
- # 1. Empty response: subagent returned nothing or whitespace-only output
478
- # 2. Subagent error: subagent exited non-zero (crash, OOM, tool error)
479
- # 3. Timeout: subagent did not return within the session timeout
480
- #
481
- # On first failure: retry once with a simplified prompt that strips
482
- # non-essential context (summary block, architecture block) and adds
483
- # a direct instruction to produce a verdict or error report.
484
- # On second failure: escalate to human — do NOT continue the phase loop.
485
-
486
- if subagent_failed_or_empty(result):
487
- if retry_count.get(phase.command, 0) == 0:
488
- # First failure: retry with simplified prompt
489
- retry_count[phase.command] = 1
490
- print(f" ⚠ {task_id} {phase.role} — subagent response empty or errored, retrying with simplified prompt\n")
491
- emit_event(task, phase, action="subagent_retry",
492
- notes=f"first failure: {subagent_failure_reason(result)}")
493
-
494
- # Simplify: remove summary_block and architecture_block from prompt
495
- simplified_kwargs = dict(spawn_kwargs)
496
- simplified_kwargs["prompt"] = (
497
- f"### Progress Reporting\n"
498
- f"- Agent name: {agent_name}\n"
499
- f"- Progress log: {progress_log_path}\n"
500
- f"- Banner key: {banner_name}\n\n"
501
- f"Append progress entries as you work.\n\n"
502
- f"---\n\n"
503
- f"{review_loop_context}"
504
- f"{role_block}\n\n"
505
- f"### Current Working Context\n"
506
- f"- Sprint Root: {sprint_root_path}\n"
507
- f"- Task Root: {task_root_path}\n"
508
- f"- Store Root: {store_root_path}\n\n"
509
- f"Read `.forge/workflows/{phase.workflow}` and follow it. Task ID: {task_id}.\n\n"
510
- f"{overlay_md}\n\n"
511
- f"IMPORTANT: You MUST produce a result. If the workflow cannot complete, "
512
- f"write a verdict or error report to the expected artifact path and return."
513
- )
514
- spawn_subagent(**simplified_kwargs)
515
- stop_monitor(progress_log_path)
516
-
517
- # Re-validate the retry result
518
- if subagent_failed_or_empty(result):
519
- # Second failure: escalate
520
- print(f" ✗ {task_id} {phase.role} — subagent failed after retry, escalating\n")
521
- emit_event(task, phase, action="subagent_escalated",
522
- notes=f"second failure: {subagent_failure_reason(result)}")
523
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
524
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
525
- emit_event(task, phase, eventId=event_id, iteration=iteration,
526
- action="escalated", verdict="escalated",
527
- notes=f"subagent failed after retry: {subagent_failure_reason(result)}")
528
- print(f" ⚠ Task {task_id} escalated: subagent {phase.role} failed after retry — {subagent_failure_reason(result)}\n")
529
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
530
- break
531
- else:
532
- # Already retried once — this is the second failure
533
- print(f" ✗ {task_id} {phase.role} — subagent failed after retry, escalating\n")
534
- emit_event(task, phase, action="subagent_escalated",
535
- notes=f"second failure: {subagent_failure_reason(result)}")
536
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
537
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
538
- emit_event(task, phase, eventId=event_id, iteration=iteration,
539
- action="escalated", verdict="escalated",
540
- notes=f"subagent failed after retry: {subagent_failure_reason(result)}")
541
- print(f" ⚠ Task {task_id} escalated: subagent {phase.role} failed after retry — {subagent_failure_reason(result)}\n")
542
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
543
- break
544
-
545
- # --- Sidecar merge: merge token usage written by subagent via custodian ---
546
- # The subagent wrote the sidecar via node "$FORGE_ROOT/tools/store-cli.cjs" emit {sprintId} '{sidecar-json}' --sidecar
547
- # Merge the sidecar into the canonical event and delete the sidecar file
548
- FORGE_ROOT = resolve_forge_root()
549
- run: node "$FORGE_ROOT/tools/store-cli.cjs" merge-sidecar {sprint_id} {event_id}
550
- # merge-sidecar reads the sidecar, merges token fields into the canonical event, and deletes the sidecar
551
- # If the sidecar does not exist, merge-sidecar exits 1 — treat as non-fatal (subagent may have skipped it)
552
- emit_event(task, phase, action="complete")
553
-
554
- # --- Phase-exit signal ---
555
- # Non-review phases always advance with a completion signal
556
- if phase.role not in ("review-plan", "review-code", "validate"):
557
- print(f" ✓ {task_id} {phase.role} — completed\n")
558
- i += 1
559
- # Compact context: all state is on disk; preserve loop bookkeeping in the summary
560
- print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
561
- /compact
562
- continue
563
-
564
- # --- Review phase: detect verdict via parse-verdict.cjs (see Verdict Detection below) ---
565
- # The CLI returns exit 0/1/2 for approved/revision/unknown. Never pattern-match
566
- # the **Verdict:** line manually — the closed vocabulary lives in the tool.
567
- verdict_result = run_bash(
568
- f'node "$FORGE_ROOT/tools/parse-verdict.cjs" {review_artifact_path(phase, task)}'
569
- )
570
- if verdict_result.exit_code == 0:
571
- verdict = "Approved"
572
- elif verdict_result.exit_code == 1:
573
- verdict = "Revision Required"
574
- else:
575
- # exit 2: malformed, missing verdict line, or missing artifact. Never guess.
576
- print(f" ⚠ {task_id} {phase.role} — verdict_malformed, escalating\n")
577
- emit_event(task, phase, action="verdict_malformed",
578
- notes=f"parse-verdict exit={verdict_result.exit_code}")
579
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
580
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
581
- emit_event(task, phase, eventId=event_id, iteration=iteration,
582
- action="escalated", verdict="escalated",
583
- notes="verdict_malformed: review artifact missing or verdict line unparseable")
584
- print(f" ⚠ Task {task_id} escalated: verdict_malformed — review artifact missing or verdict line unparseable\n")
585
- print(f" Review artifact: {review_artifact_path(phase, task)}\n")
586
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
587
- break
588
-
589
- if verdict == "Approved":
590
- print(f" ✓ {task_id} {phase.role} — Approved\n")
591
- i += 1 # advance to next phase
592
- # Compact context: all state is on disk; preserve loop bookkeeping in the summary
593
- print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
594
- /compact
595
-
596
- elif verdict == "Revision Required":
597
- iteration_counts[phase.command] = iteration_counts.get(phase.command, 0) + 1
598
- print(f" ↻ {task_id} {phase.role} — Revision Required (iteration {iteration_counts[phase.command]})\n")
599
-
600
- if iteration_counts[phase.command] >= phase.maxIterations: # default 3
601
- # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
602
- run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
603
- emit_event(task, phase, eventId=event_id, iteration=iteration,
604
- action="escalated", verdict="escalated",
605
- notes="max iterations reached")
606
- print(f" ⚠ Task {task_id} escalated: max iterations reached\n")
607
- print(f" Review artifact: {review_artifact_path(phase, task)}\n")
608
- print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
609
- break
610
- break # stop processing this task
611
-
612
- # Route back to the revision target
613
- target = phase.on_revision or nearest_preceding_non_review(phases, i)
614
- i = index_of(phases, target) # loop back
615
- # Compact context: all state is on disk; preserve loop bookkeeping in the summary
616
- print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
617
- /compact
618
-
619
- # No `else:` branch needed — parse-verdict.cjs already exhausts the
620
- # possibilities (approved | revision | verdict_malformed), and the
621
- # malformed case is handled above before this if/elif chain.
622
- ```
623
-
624
- ## Agent Naming Convention
625
-
626
- Each subagent is assigned a structured name at spawn time:
627
-
628
- ```
629
- {taskId}:{persona_noun}:{phase.role}:{iteration}
630
- ```
631
-
632
- | Component | Source | Example |
633
- |-----------|--------|---------|
634
- | `taskId` | Task ID from manifest | `FORGE-S09-T01` |
635
- | `persona_noun` | `ROLE_TO_NOUN` mapping | `engineer`, `supervisor`, `qa-engineer` |
636
- | `phase.role` | Pipeline phase role | `plan`, `review-plan`, `implement` |
637
- | `iteration` | 1-based revision count for this phase | `1`, `2`, `3` |
638
-
639
- Examples:
640
-
641
- - `FORGE-S09-T01:engineer:plan:1` — First plan attempt for T01
642
- - `FORGE-S09-T01:supervisor:review-plan:1` — First plan review for T01
643
- - `FORGE-S09-T01:engineer:update-impl:2` — Second implementation revision for T01
644
-
645
- The agent name is passed in the subagent prompt and used in every progress log
646
- entry the subagent writes. It provides identity and traceability for mid-task
647
- feedback.
648
-
649
- ## Progress Reporting
650
-
651
- <!-- See _fragments/progress-reporting.md for canonical definition -->
652
- > See `_fragments/progress-reporting.md` for the full progress log format and `store-cli progress` command reference.
653
-
654
- Log path: `.forge/store/events/{sprintId}/progress.log`. Format: `{ISO_TIMESTAMP}|{agent_name}|{banner_key}|{status}|{detail}`. Clear at task start: `store-cli progress-clear {sprintId}`.
655
-
656
- ## Phase-Exit Signals
657
-
658
- After each subagent returns, the orchestrator prints a phase-exit signal:
659
-
660
- | Outcome | Format |
661
- |---------|--------|
662
- | Non-review phase completed | ` ✓ {task_id} {phase_role} — completed` |
663
- | Review verdict: Approved | ` ✓ {task_id} {phase_role} — Approved` |
664
- | Review verdict: Revision Required | ` ↻ {task_id} {phase_role} — Revision Required (iteration {n})` |
665
- | Escalated | ` ⚠ {task_id} {phase_role} — escalated to human` |
666
-
667
- Examples:
668
-
669
- ```
670
- ✓ FORGE-S09-T01 plan — completed
671
- ✓ FORGE-S09-T01 review-plan — Approved
672
- ↻ FORGE-S09-T01 review-plan — Revision Required (iteration 2)
673
- ⚠ FORGE-S09-T01 validate — escalated to human
674
- ```
675
-
676
- ## Verdict Detection
677
-
678
- After each review phase completes, the orchestrator MUST read the verdict
679
- before branching. Do not infer the verdict from conversation context alone —
680
- always read the artifact.
681
-
682
- | Phase role | Artifact to read | Verdict field |
683
- |---------------|---------------------------------------------------------------------------|------------------------------|
684
- | `review-plan` | `{engineering}/sprints/{sprintDir}/{taskDir}/PLAN_REVIEW.md` | Line matching `**Verdict:**` |
685
- | `review-code` | `{engineering}/sprints/{sprintDir}/{taskDir}/CODE_REVIEW.md` | Line matching `**Verdict:**` |
686
- | `validate` | `{engineering}/sprints/{sprintDir}/{taskDir}/VALIDATION_REPORT.md` | Line matching `**Verdict:**` |
687
-
688
- The verdict line format is:
689
-
690
- ```
691
- **Verdict:** Approved
692
- ```
693
- or
694
- ```
695
- **Verdict:** Revision Required
696
- ```
697
-
698
- **Parse the verdict via `parse-verdict.cjs`** — do NOT pattern-match the
699
- line manually. The tool enforces a closed verdict vocabulary so typos, case
700
- drift, and reviewer prose cannot cause silent misclassification:
701
-
702
- ```
703
- FORGE_ROOT = resolve_forge_root()
704
- result = run_bash(f'node "$FORGE_ROOT/tools/parse-verdict.cjs" {artifact_path}')
705
- # exit 0 → approved (stdout "approved")
706
- # exit 1 → revision (stdout "revision")
707
- # exit 2 → unknown/malformed/missing (stdout "unknown")
708
- ```
709
-
710
- Recognised values (case-insensitive):
711
-
712
- - **approved** — `Approved`, `Approve`, `[Approved]`
713
- - **revision** — `Revision Required`, `Revision`, `Needs Revision`, `Changes Requested`
714
-
715
- Anything else — including free-form prose, missing bold markers, a missing
716
- verdict line, or a missing artifact — yields exit 2. Do NOT treat unknown
717
- as approved or revision; halt the loop and escalate via `verdict_malformed`.
718
-
719
- ## Escalation Procedure
720
-
721
- > **NOTE:** The Escalation Procedure is inlined at every call site in the
722
- > Execution Algorithm. This section remains as a reference. When adding new
723
- > escalation points, inline the full procedure — do NOT call `escalate_to_human()`
724
- > as a bare function name.
725
-
726
- When escalating to the human:
727
-
728
- 1. Update task status via `node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {taskId} status escalated`
729
- 2. Emit a final event with `verdict: "escalated"` and `notes` explaining the reason
730
- 3. Output a clear message:
731
- ```
732
- ⚠ Task {TASK_ID} escalated: {reason}
733
- Review artifact: {artifact_path}
734
- Resume with: /{phase.command} {TASK_ID} after addressing the issues.
735
- ```
736
- 4. Stop processing this task. Continue to the next task in the sprint.
737
-
738
- ## Phase Gates
739
-
740
- Declarative pre-flight gates for each phase. The orchestrator evaluates these
741
- via `forge/tools/preflight-gate.cjs` **before** every subagent spawn. A failing
742
- gate halts the loop for this task — no retry, no fall-through to the subagent,
743
- no silent recovery. Gates are data, not prose: the grammar is defined in
744
- `forge/tools/parse-gates.cjs` and validated by its test suite.
745
-
746
- Grammar (one directive per line):
747
- - `artifact <path> [min=<bytes>]` — file must exist and meet size floor. Path
748
- templates: `{sprint}` → sprintId, `{task}` → task suffix, `{bug}` → bugId.
749
- - `require <field> <op> <value>` — predicate must hold. Ops: `==`, `!=`,
750
- `in [v1, v2, ...]`. Fields are dotted paths against the store record, e.g.
751
- `task.status`.
752
- - `forbid <field> <op> <value>` — predicate must NOT hold.
753
- - `after <phase> = <approved|revision>` — predecessor phase's review artifact
754
- must carry the stated verdict (parsed by `parse-verdict.cjs`).
755
-
756
- ```gates phase=plan
757
- forbid task.status == committed
758
- forbid task.status == abandoned
759
- forbid task.status == blocked
760
- forbid task.status == escalated
761
- ```
762
-
763
- ```gates phase=implement
764
- artifact {engineering}/sprints/{sprint}/{task}/PLAN.md min=200
765
- after review-plan = approved
766
- forbid task.status == committed
767
- forbid task.status == blocked
768
- forbid task.status == escalated
769
- ```
770
-
771
- ```gates phase=review-plan
772
- artifact {engineering}/sprints/{sprint}/{task}/PLAN.md min=200
773
- forbid task.status == blocked
774
- forbid task.status == escalated
775
- ```
776
-
777
- ```gates phase=review-code
778
- after review-plan = approved
779
- forbid task.status == blocked
780
- forbid task.status == escalated
781
- ```
782
-
783
- ```gates phase=validate
784
- after review-code = approved
785
- forbid task.status == blocked
786
- forbid task.status == escalated
787
- ```
788
-
789
- ```gates phase=approve
790
- after review-code = approved
791
- forbid task.status == blocked
792
- forbid task.status == escalated
793
- ```
794
-
795
- ```gates phase=commit
796
- after approve = approved
797
- forbid task.status == blocked
798
- forbid task.status == escalated
799
- ```
800
-
801
- Adjusting a gate is a data change — edit the block above, regenerate workflows
802
- on the user side via `/forge:update`, and the new gate takes effect on the next
803
- orchestrator run. No code change required to relax or tighten a gate.
804
-
805
- ## Write-Boundary Contract
806
-
807
- You MAY write Forge-owned JSON (`task.json`, `sprint.json`, `bug.json`,
808
- events sidecars, `COLLATION_STATE.json`, `progress.log`) directly with the
809
- `Write` or `Edit` tools. You do NOT need to route every write through
810
- `store-cli` — the probabilistic layer is free to bypass deterministic tools.
811
-
812
- However, **every write to a Forge-owned path is schema-validated at the
813
- filesystem boundary** by the `PreToolUse` hook at
814
- `hooks/validate-write.js`. A malformed write is rejected with a message
815
- naming the offending field and pointing at the relevant
816
- `forge/schemas/<kind>.schema.json`. Fix the data and retry — do NOT try to
817
- disable the hook.
818
-
819
- `store-cli` is still the most convenient path (it handles ID allocation,
820
- referential integrity, ghost-event semantics, and sidecar merging), but it
821
- is one route among several. The schema invariant is preserved whichever
822
- route you take.
823
-
824
- **Emergency bypass.** For operator-driven repair, set
825
- `FORGE_SKIP_WRITE_VALIDATION=1` for a single turn. The hook will let the
826
- write through and append an audit line to the affected sprint's
827
- `progress.log`.
828
-
829
- <!-- See _fragments/iron-laws.md for Iron Laws section structure guidance (orchestrate uses orchestrator-special deferral to generic-skills.md § Orchestrator Iron Laws) -->
830
- ## Iron Laws
831
-
832
- <!-- Shared orchestrator laws live in generic-skills.md § Orchestrator Iron Laws. -->
833
- > See `generic-skills.md § Orchestrator Iron Laws` for the six universal laws that apply to all orchestrators.
834
-
835
- **Additional law specific to this pipeline:**
836
-
837
- **YOU MUST NOT silently work around a blocker.** If a phase fails, a subagent
838
- returns empty, a gate fails, or a verdict cannot be parsed, the orchestrator
839
- MUST either retry once (for recoverable failures) or escalate to the human.
840
- Skipping the phase, fabricating a result, assuming success without evidence,
841
- or continuing with a degraded response is NEVER acceptable. Every failure MUST
842
- produce a visible signal (✗ or ⚠) and a structured event. Silent continuation
843
- is a violation of the Iron Laws.
844
-
845
- ## Error Recovery
846
-
847
- - Test/build failure: pass error to Engineer revision workflow, retry once
848
- - Verdict "Revision Required": enter revision loop (up to max_iterations)
849
- - Subagent empty/crash/timeout response: retry once with simplified prompt
850
- (strip summary and architecture blocks). Escalate on second failure.
851
- See Subagent Response Validation in the Execution Algorithm.
852
- - Subagent non-zero exit code (not parse-verdict): same as above — retry
853
- once, escalate on second failure. The crash reason is captured in the
854
- escalation event notes.
855
- - Verdict malformed or missing: escalate to human immediately. Never guess.
856
- - Revision loop exhaustion: escalate to human immediately. Never approve
857
- to unblock.
858
- - Gate failure (preflight): escalate to human. No retry, no fall-through.
859
- - Gate misconfiguration: escalate to human. No retry, no fall-through.
860
- - Git hook failure: diagnose, fix, create new commit
861
- - Merge conflict: escalate to human
862
- - Task status is blocked or escalated: skip the task entirely. Do not
863
- attempt any phase on it.
864
-
865
- ## Event Emission
866
-
867
- <!-- See _fragments/event-emission-schema.md for canonical contract -->
868
- > See `_fragments/event-emission-schema.md` for the actor split (subagent
869
- > writes judgement-only SUMMARY; orchestrator composes the canonical event
870
- > from runtime telemetry + SUMMARY and emits it).
871
-
872
- The **orchestrator** is the only actor that calls `store-cli emit` for phase
873
- events. Phase subagents write `{PHASE}-SUMMARY.json` and return. After each
874
- subagent returns, the orchestrator:
875
-
876
- 1. Captures the subagent's runtime attribution (`model`, `provider`, token
877
- usage) from the runtime stream.
878
- 2. Records bracketed wall times around the spawn call (`startTimestamp`,
879
- `endTimestamp`, `durationMinutes`).
880
- 3. Reads the SUMMARY for the judgement blob (`verdict`, `notes`, `findings`).
881
- 4. Composes the canonical event with `eventId`, `taskId`, `sprintId`, `role`,
882
- `action`, `phase`, `iteration` from its own task state and `tokenSource:
883
- "reported"` when the runtime surfaced usage.
884
- 5. Calls `node "$FORGE_ROOT/tools/store-cli.cjs" emit {sprintId} '{event-json}'`
885
- with the complete record.
886
-
887
- Do not include hardcoded example `model` or `provider` strings in the
888
- generated orchestrator prose — they are the seed of LLM hallucination.
889
- Refer subagents to `.forge/schemas/event.schema.json` instead.
890
-
891
- <!-- See _fragments/generation-instructions.md for Generation Instructions template (orchestrate uses orchestrator-special long-form prose — cannot be reduced to standard subsections) -->
892
- ## Friction Emit
893
-
894
- When the Orchestrator detects skill friction during orchestrate-task — a referenced skill is unused, fails on invocation, is missing from the registry, has gone stale relative to current architecture, or is redundant with another skill — emit a `friction` event so `/forge:rebuild --enrich` (phase 2) can act on the signal. This is the writer side of the channel whose reader landed in S13-T08; the reader is empty without these emits.
895
-
896
- **Trigger conditions** (set `issue` to the matching token):
897
-
898
- | Token | When to emit |
899
- |--------------------|----------------------------------------------------------------------------------|
900
- | `skill_unused` | A skill listed in the persona's skill block was loaded but never consulted. |
901
- | `skill_failed` | A skill was consulted but its guidance produced an error or required correction. |
902
- | `skill_missing` | The workflow needed guidance the available skills did not cover. |
903
- | `skill_stale` | A skill's guidance contradicts current architecture / supersedes its own advice. |
904
- | `skill_redundant` | Two skills provided overlapping or conflicting guidance for the same decision. |
905
-
906
- **Two flavours of friction in orchestrate-task:**
907
-
908
- 1. **Subagent-experienced friction** (the persona running plan / implement /
909
- validate / etc. detects skill friction). The subagent records the signal
910
- via `node "$FORGE_ROOT/tools/friction-emit.cjs" --workflow {wf} --persona {p}
911
- --issue {token} [--subkind {token}] [--evidence '{...}']`, which appends a
912
- judgement-only record to `.forge/cache/FRICTION-{wf}.jsonl`. After the
913
- subagent returns, the orchestrator drains this file, stamps the
914
- subagent's captured runtime attribution (model, provider, usage, wall
915
- times, eventId) onto each record, and emits the resulting events via
916
- `store-cli emit` as event type `"friction"`. The orchestrator truncates
917
- the file only after all emits succeed.
918
-
919
- 2. **Orchestrator-experienced friction** (spawn failure, sidecar missing,
920
- FSM rejection, verdict malformed). The orchestrator emits inline using
921
- its own model/provider attribution (`persona: "orchestrator"`,
922
- `workflow: "orchestrate"`, `phase: "orchestrate"`). Same `store-cli emit`
923
- path; no example record is reproduced here because the orchestrator
924
- owns the field values — consult `.forge/schemas/event.schema.json` for
925
- the required shape.
926
-
927
- The schema enforces `{workflow, persona, issue}` as required when
928
- `type === "friction"`. `subkind` is the frozen enum
929
- `skill_unused|skill_failed|skill_missing|skill_stale|skill_redundant` or
930
- experimental `^x_[a-z_]+$`. Emit one record per distinct friction signal
931
- — do not coalesce.
932
-
933
- The generated `orchestrate_task.md` MUST carry this section verbatim —
934
- `/forge:rebuild --enrich` (phase 2) greps for it.