@yemi33/minions 0.1.2447 → 0.1.2449

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 (315) hide show
  1. package/bin/cli-api-client.js +1 -1
  2. package/bin/install-internal-minions.js +1382 -44
  3. package/bin/install-layout.js +150 -0
  4. package/bin/minions.js +460 -167
  5. package/dashboard/docs/typography.md +65 -12
  6. package/dashboard/js/command-center.js +66 -7
  7. package/dashboard/js/detail-panel.js +36 -0
  8. package/dashboard/js/memory-panel.js +59 -12
  9. package/dashboard/js/qa.js +186 -45
  10. package/dashboard/js/refresh.js +148 -12
  11. package/dashboard/js/render-dispatch.js +3 -4
  12. package/dashboard/js/render-inbox.js +2 -2
  13. package/dashboard/js/render-other.js +3 -3
  14. package/dashboard/js/render-pipelines.js +14 -0
  15. package/dashboard/js/render-plans.js +57 -9
  16. package/dashboard/js/render-prd.js +132 -23
  17. package/dashboard/js/render-prs.js +195 -166
  18. package/dashboard/js/render-schedules.js +63 -3
  19. package/dashboard/js/render-utils.js +3 -3
  20. package/dashboard/js/render-watches.js +19 -3
  21. package/dashboard/js/render-work-items.js +238 -30
  22. package/dashboard/js/settings.js +205 -54
  23. package/dashboard/js/utils.js +51 -1
  24. package/dashboard/pages/home.html +1 -1
  25. package/dashboard/pages/qa.html +1 -16
  26. package/dashboard/pages/work.html +40 -0
  27. package/dashboard/shared/cc-limits.js +79 -0
  28. package/dashboard/shared/pr-filters.js +21 -38
  29. package/dashboard/shared/project-git-summary.js +1 -1
  30. package/dashboard/shared/record-filters.js +169 -0
  31. package/dashboard/shared/watches-source.js +1 -1
  32. package/dashboard/shared/welcome-popup.js +1 -1
  33. package/dashboard/shared/wi-filters.js +302 -0
  34. package/dashboard/slim/body.html +1 -0
  35. package/dashboard/slim/js/command-send.js +26 -0
  36. package/dashboard/slim/js/modals-tiles.js +380 -39
  37. package/dashboard/slim/js/status.js +13 -21
  38. package/dashboard/slim/layout.html +1 -0
  39. package/dashboard/slim/panel-bootstrap.js +6 -2
  40. package/dashboard/slim/styles.css +38 -0
  41. package/dashboard/styles.css +159 -55
  42. package/dashboard-build.js +52 -6
  43. package/dashboard.js +956 -423
  44. package/docs/README.md +11 -6
  45. package/docs/api-errors.md +2 -2
  46. package/docs/architecture-review-2026-07-09.md +1 -1
  47. package/docs/architecture.excalidraw +2 -2
  48. package/docs/auto-discovery.md +18 -9
  49. package/docs/branch-derivation.md +4 -4
  50. package/docs/capture-demos.js +39 -2
  51. package/docs/ci-runner-canary.md +123 -0
  52. package/docs/claude-md-propagation.md +2 -2
  53. package/docs/cloud-agent-dispatch.md +204 -0
  54. package/docs/command-center.md +7 -7
  55. package/docs/completion-reports.md +43 -20
  56. package/docs/constants.md +10 -3
  57. package/docs/constellation-bridge.md +134 -6
  58. package/docs/constellation-style-telemetry.md +4 -4
  59. package/docs/contracts/capability-protocol.v1.json +165 -0
  60. package/docs/cooldown-merge-semantics.md +12 -12
  61. package/docs/copilot-cli-schema.md +7 -7
  62. package/docs/cross-repo-plans.md +10 -10
  63. package/docs/dead-code-audit-retractions.md +5 -5
  64. package/docs/default-branch-ci.md +173 -0
  65. package/docs/deprecated.json +31 -31
  66. package/docs/design-inbox-entries-schema.md +3 -3
  67. package/docs/design-language.md +1051 -0
  68. package/docs/design-state-storage.md +11 -11
  69. package/docs/diagnostics-crash-reports.md +9 -9
  70. package/docs/diagnostics-memory.md +5 -5
  71. package/docs/documentation-audit-2026-07-09.md +7 -7
  72. package/docs/engine-restart.md +90 -5
  73. package/docs/harness-mode.md +1 -1
  74. package/docs/internal-install.md +338 -39
  75. package/docs/kb-dedup-duplicate-pair-investigation.md +5 -5
  76. package/docs/kb-pr3223-cascade-archiving.md +1 -1
  77. package/docs/kb-pr696-merge-conflict-docs.md +6 -6
  78. package/docs/kb-sweep.md +35 -35
  79. package/docs/keep-processes.md +1 -1
  80. package/docs/live-checkout-mode.md +30 -30
  81. package/docs/managed-spawn.md +18 -14
  82. package/docs/named-agents.md +7 -7
  83. package/docs/plan-lifecycle.md +69 -2
  84. package/docs/pr-author-identity.md +114 -0
  85. package/docs/pr-auto-fix-dispatch.md +19 -4
  86. package/docs/pr-comment-followup.md +6 -6
  87. package/docs/pr-review-fix-loop.md +59 -10
  88. package/docs/process-termination.md +40 -0
  89. package/docs/proposals/repo-pool-for-live-checkout.md +13 -13
  90. package/docs/qa-runbook-lifecycle.md +367 -17
  91. package/docs/qa-runbooks.md +3 -3
  92. package/docs/rfc-completion-json.md +18 -18
  93. package/docs/runtime-adapters.md +26 -21
  94. package/docs/security.md +6 -6
  95. package/docs/self-improvement.md +4 -4
  96. package/docs/shared-lifecycle-module-map.md +473 -472
  97. package/docs/skills.md +52 -3
  98. package/docs/slim-ux/concepts.md +121 -116
  99. package/docs/specs/agent-configurability.md +18 -18
  100. package/docs/specs/agent-rename.md +18 -18
  101. package/docs/team-memory.md +38 -21
  102. package/docs/timeouts-and-liveness.md +118 -10
  103. package/docs/tutorials/01-install-and-connect.md +1 -1
  104. package/docs/watches.md +40 -39
  105. package/docs/workspace-manifests.md +4 -4
  106. package/docs/worktree-lifecycle.md +293 -14
  107. package/engine/README.md +46 -0
  108. package/engine/{ado-comment.js → ado/comment.js} +8 -8
  109. package/engine/{ado-git-auth.js → ado/git-auth.js} +4 -4
  110. package/engine/{ado.js → ado/index.js} +417 -63
  111. package/engine/{ado-status.js → ado/status.js} +6 -8
  112. package/engine/{ado-token.js → ado/token.js} +1 -1
  113. package/engine/{acp-transport.js → agents/acp-transport.js} +62 -22
  114. package/engine/{agent-worker-pool.js → agents/agent-worker-pool.js} +17 -8
  115. package/engine/{cc-worker-pool.js → agents/cc-worker-pool.js} +16 -6
  116. package/engine/{claude-md-context.js → agents/claude-md-context.js} +5 -5
  117. package/engine/{harness-context.js → agents/harness-context.js} +5 -5
  118. package/engine/{harness.js → agents/harness.js} +3 -3
  119. package/engine/{llm.js → agents/llm.js} +18 -14
  120. package/engine/{model-discovery.js → agents/model-discovery.js} +2 -2
  121. package/engine/{playbook.js → agents/playbook.js} +155 -22
  122. package/engine/{pooled-agent-process.js → agents/pooled-agent-process.js} +14 -12
  123. package/engine/{preflight.js → agents/preflight.js} +29 -10
  124. package/engine/{spawn-agent.js → agents/spawn-agent.js} +25 -14
  125. package/engine/{spawn-phase-watchdog.js → agents/spawn-phase-watchdog.js} +16 -7
  126. package/engine/{steering.js → agents/steering.js} +5 -5
  127. package/engine/{tools-inventory.js → agents/tools-inventory.js} +2 -2
  128. package/engine/{agent-api-validation.js → api/agent-api-validation.js} +2 -2
  129. package/engine/{api-validation.js → api/api-validation.js} +1 -1
  130. package/engine/api/bridge.js +787 -0
  131. package/engine/{cc-api-validation.js → api/cc-api-validation.js} +1 -1
  132. package/engine/api/companion.js +560 -0
  133. package/engine/{content-api-validation.js → api/content-api-validation.js} +2 -2
  134. package/engine/{pr-issue-validation.js → api/pr-issue-validation.js} +33 -6
  135. package/engine/{settings-validation.js → api/settings-validation.js} +32 -4
  136. package/engine/api-contracts/agent-content.js +4 -4
  137. package/engine/api-contracts/capability-manifest.js +236 -0
  138. package/engine/api-contracts/capability-protocol.js +333 -0
  139. package/engine/api-contracts/cc-ops.js +1 -1
  140. package/engine/api-contracts/config-runtime.js +5 -0
  141. package/engine/api-contracts/core.js +28 -1
  142. package/engine/api-contracts/index.js +100 -0
  143. package/engine/api-contracts/orchestration.js +18 -5
  144. package/engine/api-contracts/pull-requests.js +37 -6
  145. package/engine/api-contracts/qa-process.js +29 -6
  146. package/engine/api-contracts/work-plan-prd.js +21 -1
  147. package/engine/cloud/contract.js +212 -0
  148. package/engine/cloud/index.js +159 -0
  149. package/engine/{execution-model.js → core/execution-model.js} +1 -1
  150. package/engine/{features.js → core/features.js} +4 -4
  151. package/engine/{operator-identity.js → core/operator-identity.js} +1 -1
  152. package/engine/{queries.js → core/queries.js} +201 -36
  153. package/engine/{safe-expr.js → core/safe-expr.js} +1 -1
  154. package/engine/{shared.js → core/shared.js} +1637 -175
  155. package/engine/{stdio-timestamps.js → core/stdio-timestamps.js} +1 -1
  156. package/engine/{untrusted-fence.js → core/untrusted-fence.js} +3 -3
  157. package/engine/db/index.js +11 -2
  158. package/engine/db/migrations/002-dispatches.js +3 -3
  159. package/engine/db/migrations/003-work-items.js +1 -1
  160. package/engine/db/migrations/004-pull-requests.js +1 -1
  161. package/engine/db/migrations/006-metrics.js +1 -1
  162. package/engine/db/migrations/007-watches.js +2 -2
  163. package/engine/db/migrations/008-small-state.js +1 -1
  164. package/engine/db/migrations/009-qa.js +1 -1
  165. package/engine/db/migrations/010-pr-links.js +1 -1
  166. package/engine/db/migrations/011-remaining-state.js +1 -1
  167. package/engine/db/migrations/012-steering-deliveries.js +2 -2
  168. package/engine/db/migrations/013-backfill-broken-note-links.js +1 -1
  169. package/engine/db/migrations/014-pr-fix-target-prefs.js +2 -2
  170. package/engine/db/migrations/015-plans-prds.js +0 -0
  171. package/engine/db/migrations/018-sql-only-cutover.js +2 -2
  172. package/engine/db/migrations/021-archived-work-items.js +1 -1
  173. package/engine/db/migrations/022-global-cc-session.js +1 -1
  174. package/engine/db/migrations/023-engine-state.js +1 -1
  175. package/engine/db/migrations/025-malformed-work-item-phantoms.js +1 -1
  176. package/engine/db/migrations/027-review-learning-lifecycle.js +1 -1
  177. package/engine/db/migrations/029-repair-reused-versions.js +20 -0
  178. package/engine/db/migrations/031-pr-author-identity.js +137 -0
  179. package/engine/{consolidation.js → memory/consolidation.js} +6 -6
  180. package/engine/{kb-sweep-runner.js → memory/kb-sweep-runner.js} +2 -2
  181. package/engine/{kb-sweep.js → memory/kb-sweep.js} +9 -7
  182. package/engine/{memory-retrieval.js → memory/memory-retrieval.js} +46 -4
  183. package/engine/{memory-store.js → memory/memory-store.js} +3 -3
  184. package/engine/{promotion.js → memory/promotion.js} +3 -3
  185. package/engine/{review-learning-backfill.js → memory/review-learning-backfill.js} +6 -6
  186. package/engine/{review-learning.js → memory/review-learning.js} +10 -5
  187. package/engine/{diagnostics-memory.js → observability/diagnostics-memory.js} +1 -1
  188. package/engine/{logs-store.js → observability/logs-store.js} +5 -5
  189. package/engine/{metrics-store.js → observability/metrics-store.js} +4 -4
  190. package/engine/{check-status.js → operations/check-status.js} +3 -3
  191. package/engine/{cli.js → operations/cli.js} +271 -113
  192. package/engine/{distribution.js → operations/distribution.js} +5 -6
  193. package/engine/{cleanup.js → orchestration/cleanup.js} +72 -45
  194. package/engine/{cooldown.js → orchestration/cooldown.js} +5 -5
  195. package/engine/{dispatch-events.js → orchestration/dispatch-events.js} +2 -2
  196. package/engine/{dispatch.js → orchestration/dispatch.js} +129 -36
  197. package/engine/orchestration/failed-scheduled-cleanup.js +274 -0
  198. package/engine/{lifecycle.js → orchestration/lifecycle.js} +198 -90
  199. package/engine/{meeting.js → orchestration/meeting.js} +6 -16
  200. package/engine/{pipeline.js → orchestration/pipeline.js} +12 -12
  201. package/engine/{pre-dispatch-eval.js → orchestration/pre-dispatch-eval.js} +10 -9
  202. package/engine/{routing.js → orchestration/routing.js} +3 -3
  203. package/engine/{schedule-bootstrap.js → orchestration/schedule-bootstrap.js} +4 -4
  204. package/engine/{scheduler.js → orchestration/scheduler.js} +38 -8
  205. package/engine/{timeout.js → orchestration/timeout.js} +158 -109
  206. package/engine/{db-events.js → persistence/db-events.js} +2 -2
  207. package/engine/{dispatch-store.js → persistence/dispatch-store.js} +7 -7
  208. package/engine/{inbox-store.js → persistence/inbox-store.js} +2 -2
  209. package/engine/{note-link-backfill.js → persistence/note-link-backfill.js} +4 -4
  210. package/engine/{pr-fix-target-store.js → persistence/pr-fix-target-store.js} +8 -8
  211. package/engine/{pull-requests-store.js → persistence/pull-requests-store.js} +21 -7
  212. package/engine/{small-state-store.js → persistence/small-state-store.js} +31 -31
  213. package/engine/persistence/state-operations.js +350 -0
  214. package/engine/{steering-store.js → persistence/steering-store.js} +6 -6
  215. package/engine/{issues.js → planning/issues.js} +2 -2
  216. package/engine/{plan-prd-validation.js → planning/plan-prd-validation.js} +8 -2
  217. package/engine/planning/prd-result-sidecar.js +190 -0
  218. package/engine/{prd-store.js → planning/prd-store.js} +17 -17
  219. package/engine/{project-discovery.js → planning/project-discovery.js} +5 -5
  220. package/engine/{projects.js → planning/projects.js} +10 -10
  221. package/engine/{resolve-area.js → planning/resolve-area.js} +1 -1
  222. package/engine/{work-item-validation.js → planning/work-item-validation.js} +39 -3
  223. package/engine/{work-items-store.js → planning/work-items-store.js} +29 -21
  224. package/engine/{keep-process-sweep.js → processes/keep-process-sweep.js} +57 -17
  225. package/engine/{managed-spawn-launcher.js → processes/managed-spawn-launcher.js} +3 -3
  226. package/engine/{managed-spawn.js → processes/managed-spawn.js} +97 -46
  227. package/engine/{process-utils.js → processes/process-utils.js} +599 -55
  228. package/engine/{abandoned-pr-reconciliation.js → providers/abandoned-pr-reconciliation.js} +17 -7
  229. package/engine/{comment-classifier.js → providers/comment-classifier.js} +85 -17
  230. package/engine/{comment-format.js → providers/comment-format.js} +5 -5
  231. package/engine/{gh-comment.js → providers/gh-comment.js} +15 -15
  232. package/engine/{gh-token.js → providers/gh-token.js} +4 -4
  233. package/engine/{github.js → providers/github.js} +131 -54
  234. package/engine/{pr-action.js → providers/pr-action.js} +13 -12
  235. package/engine/{pr-clone-keep.js → providers/pr-clone-keep.js} +7 -7
  236. package/engine/{pr-devbox.js → providers/pr-devbox.js} +6 -6
  237. package/engine/{pr-fix-target.js → providers/pr-fix-target.js} +13 -13
  238. package/engine/{pr-remote-patch.js → providers/pr-remote-patch.js} +4 -4
  239. package/engine/{pr-resolve.js → providers/pr-resolve.js} +7 -7
  240. package/engine/{pr-temp-clone.js → providers/pr-temp-clone.js} +5 -5
  241. package/engine/{pr-track.js → providers/pr-track.js} +11 -13
  242. package/engine/{shared-branch-pr-reconcile.js → providers/shared-branch-pr-reconcile.js} +4 -4
  243. package/engine/qa/auto-prd-qa.js +313 -0
  244. package/engine/{qa-from-prd.js → qa/from-prd.js} +42 -12
  245. package/engine/qa/prd-session.js +240 -0
  246. package/engine/{qa-process-validation.js → qa/process-validation.js} +14 -9
  247. package/engine/{qa-runbooks.js → qa/runbooks.js} +1 -1
  248. package/engine/{qa-runs.js → qa/runs.js} +286 -15
  249. package/engine/{qa-sessions.js → qa/sessions.js} +595 -49
  250. package/engine/qa/visual-journey.js +654 -0
  251. package/engine/{qa-runners.js → qa-runners/index.js} +7 -7
  252. package/engine/qa-runners/maestro.js +3 -3
  253. package/engine/qa-runners/playwright.js +2 -2
  254. package/engine/{restart-health.js → recovery/restart-health.js} +48 -4
  255. package/engine/recovery/stop-stack.js +607 -0
  256. package/engine/{supervisor.js → recovery/supervisor.js} +105 -175
  257. package/engine/{watchdog.js → recovery/watchdog.js} +136 -13
  258. package/engine/runtimes/claude.js +14 -12
  259. package/engine/runtimes/codex.js +8 -6
  260. package/engine/runtimes/copilot.js +17 -16
  261. package/engine/{watch-actions.js → watches/actions.js} +13 -13
  262. package/engine/{watches.js → watches/index.js} +43 -32
  263. package/engine/{watches-store.js → watches/store.js} +4 -4
  264. package/engine/{create-pr-worktree.js → worktrees/create-pr.js} +1 -1
  265. package/engine/{worktree-gc.js → worktrees/gc.js} +70 -22
  266. package/engine/worktrees/inventory.js +671 -0
  267. package/engine/{live-checkout.js → worktrees/live-checkout.js} +4 -4
  268. package/engine/{worktree-pool.js → worktrees/pool.js} +2 -2
  269. package/engine/{worktree-preflight.js → worktrees/preflight.js} +1 -0
  270. package/engine/worktrees/quarantine-refs.js +173 -0
  271. package/engine.js +1137 -208
  272. package/minions.js +147 -77
  273. package/package.json +10 -6
  274. package/playbooks/_pr-description-audit.md +110 -78
  275. package/playbooks/build-fix-complex.md +2 -0
  276. package/playbooks/fix.md +16 -12
  277. package/playbooks/implement-shared.md +2 -0
  278. package/playbooks/implement.md +19 -20
  279. package/playbooks/plan-to-prd.md +18 -3
  280. package/playbooks/qa-session-draft.md +136 -1
  281. package/playbooks/qa-session-execute.md +80 -2
  282. package/playbooks/qa-session-setup.md +17 -1
  283. package/playbooks/qa-validate.md +1 -1
  284. package/playbooks/setup.md +2 -0
  285. package/playbooks/shared-rules.md +25 -32
  286. package/playbooks/templates/followup-dispatch.md +4 -3
  287. package/playbooks/verify.md +1 -1
  288. package/prompts/cc-system.md +19 -27
  289. package/watch-plugins/README.md +92 -0
  290. package/watch-plugins/ado-author-prs.js +336 -0
  291. package/watch-plugins/gh-author-prs.js +375 -0
  292. package/watch-plugins/http.js +474 -0
  293. package/watch-plugins/teams-channel.js +869 -0
  294. package/docs/dev-composite-workflow.md +0 -101
  295. package/docs/pr-screenshots/pr-886/after-single-header.png +0 -0
  296. package/docs/pr-screenshots/pr-886/before-duplicate-header.png +0 -0
  297. package/docs/pr-screenshots/pr-895/01-cancellation-reason-detail.png +0 -0
  298. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
  299. package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
  300. package/docs/pr-screenshots/pr-901/projects-tab-default.png +0 -0
  301. package/docs/pr-screenshots/pr-901/projects-tab-fmf-selected.png +0 -0
  302. package/docs/pr-screenshots/pr-916/model-picker-AFTER-crop.png +0 -0
  303. package/docs/pr-screenshots/pr-916/model-picker-AFTER.png +0 -0
  304. package/docs/pr-screenshots/pr-916/model-picker-BEFORE-crop.png +0 -0
  305. package/docs/pr-screenshots/pr-916/model-picker-BEFORE.png +0 -0
  306. package/docs/pr-screenshots/pr-916/model-picker-dropdown-AFTER.png +0 -0
  307. package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
  308. package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
  309. package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
  310. package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
  311. package/docs/visual-evidence-ci.md +0 -103
  312. package/engine/bridge.js +0 -379
  313. package/engine/quarantine-refs.js +0 -103
  314. package/engine/state-operations.js +0 -178
  315. /package/engine/{steering-constraints.js → agents/steering-constraints.js} +0 -0
package/playbooks/fix.md CHANGED
@@ -75,9 +75,11 @@ Before editing, split the feedback into:
75
75
 
76
76
  Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
77
77
 
78
+ An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
79
+
78
80
  ### Branch-mismatch guard (issue #2999)
79
81
 
80
- If your task description, `references[]`, or the PR thread clearly identifies an existing PR but your checkout branch does **not** match the PR's source branch — for example you are on `work/W-…` while the task references PR `!5284819` (source branch `yemishin/task-hub-symphony-gate`) — **stop immediately**. Do not branch off master, do not replay the PR's commits onto a fresh branch, and do not open a duplicate PR. Emit a non-retryable completion (`failure_class: "branch-mismatch"`, `retryable: false`) with the referenced PR id and the actual branch you found, so the engine and the operator can re-dispatch on the correct branch. The canonical bad incident is in issue #2999 — manual fix WI `W-mpwxgd4v00078c06` opened duplicate ADO PR `!5288540` instead of patching `!5284819`.
82
+ If your task description, `references[]`, or the PR thread clearly identifies an existing PR but your checkout branch does **not** match the PR's source branch — for example you are on `work/W-…` while the task references a PR whose source branch is `<pr-source-branch>` — **stop immediately**. Do not branch off master, do not replay the PR's commits onto a fresh branch, and do not open a duplicate PR. Emit a non-retryable completion (`failure_class: "branch-mismatch"`, `retryable: false`) with the referenced PR id and the actual branch you found, so the engine and the operator can re-dispatch on the correct branch.
81
83
 
82
84
  ## Working Style
83
85
 
@@ -168,22 +170,24 @@ After you push commits to the PR's source branch and BEFORE you mark the work it
168
170
  - Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
169
171
  7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
170
172
 
171
- **Screenshot handling (introduce AND refresh for visual changes)**
173
+ **Visual evidence handling — screenshots + recordings (introduce AND refresh for visual changes)**
174
+
175
+ Visual evidence is a **default behavior for UI changes on ANY project**, not minions-only. For a PR that contains a **meaningful visual/UI change** (web front-ends, dashboards, mobile webviews, any rendered surface a user sees), proactively CAPTURE evidence and EMBED it directly in the PR description — do NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is and is minions-specific; this is additive PR-body evidence). Decide "is this visual?" from whether the diff changes a rendered UI surface, NOT from repo-specific paths. Capture BEFORE/AFTER screenshots (AFTER-only for new UI) AND a screen recording/video for interactive, animated, or multi-step flows. When the description already embeds `![alt](url)` refs for a view this dispatch touched, refresh them the same way.
172
176
 
173
- For a PR that contains a **meaningful visual/UI change**, proactively CAPTURE screenshots and EMBED them directly in the PR descriptiondo NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is; this is additive PR-body evidence). When the description already embeds `![alt](url)` refs for a view this dispatch touched, refresh them the same way.
177
+ **How to capture resolution order.** (1) **Harness first:** consult the TARGET repo's own instructions for how it runs its UI and captures evidence `AGENTS.md`, `CLAUDE.md`, `README`/`CONTRIBUTING`, a project-local playbook under `projects/<name>/playbooks/`, or a project-embedded skill under `.claude/skills` / `.github/skills` / `.agents/skills` (the engine surfaces this plumbing read-only via `engine/agents/harness-context.js` and `GET /api/harness/diagnostics`). (2) **Fall back** to Minions' project-agnostic Playwright skill `capture-web-evidence` (`.claude/skills/capture-web-evidence/SKILL.md`) when the repo has no visual-evidence instructions.
174
178
 
175
- **MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
179
+ **MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). This is the minions instance of the cross-project default above and is NOT weakened by it. For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
176
180
 
177
- **Scope guard — which changes get screenshots.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI.
181
+ **Scope guard — which changes get visual evidence.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS, and the equivalent rendered surfaces of other projects. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots or recordings (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI; add a recording only for interactive/animated flows.
178
182
 
179
- 1. If the project has a runnable dev server (detect via `package.json` scripts named `dev`, `start`, or `serve`) AND Playwright MCP is available, spin it up with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
180
- 2. Drive Playwright MCP to the changed route at a normal viewport and screenshot the section that changed. Save raw PNGs to `agents/<id>/screenshots/` ONLY. **NEVER `git add` a PNG** — committing a screenshot is a release-blocker bug. Stop the dev server with the recorded stop command when done.
183
+ 1. Detect the project's run command generically from the repo harness or a `package.json` script named `dev`, `start`, or `serve` (or the repo's documented preview command); do NOT hardcode a per-repo build command. With Playwright available, spin up the dev/preview server with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
184
+ 2. Drive Playwright to the changed route/view at a normal desktop viewport (and, for mobile webviews, also at a mobile device-emulation viewport, e.g. `devices['iPhone 13']`) and screenshot the section that changed. For interactive flows, enable video recording, drive the interaction, then save the video. Save raw PNGs/videos to `agents/<id>/screenshots/` ONLY (recordings under a `recordings/` subdir). **NEVER `git add` a PNG** or video — committing captured evidence is a release-blocker bug. Stop the dev server with the recorded stop command when done.
181
185
  3. Upload + embed:
182
- - **GitHub (release-asset CDN recipe):** publish the PNGs as assets on a per-PR prerelease and embed the asset CDN URLs (works on PRIVATE repos, never commits PNGs). Build a per-command `GH_TOKEN` for the repo owner's account (`opg-microsoft` `yemishin_microsoft`, `yemi33` `yemi33`); **NEVER run `gh auth switch`**.
183
- - bash: `GH_TOKEN=$(gh auth token --user yemishin_microsoft --hostname github.com)` then `GH_TOKEN=$GH_TOKEN gh release create "pr-${PR}-visual" agents/<id>/screenshots/*.png --repo <owner>/<repo> --title "PR #${PR} visual evidence" --prerelease --notes "..."` (on re-dispatch use `gh release upload "pr-${PR}-visual" … --clobber`). Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-${PR}-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
184
- - PowerShell: `$env:GH_TOKEN = (gh auth token --user yemishin_microsoft --hostname github.com); $pngs = Get-ChildItem agents/<id>/screenshots/*.png; gh release create "pr-$PR-visual" $pngs --repo <owner>/<repo> --title "PR #$PR visual evidence" --prerelease --notes "..."; if ($LASTEXITCODE -ne 0) { gh release upload "pr-$PR-visual" $pngs --repo <owner>/<repo> --clobber }` then `gh api ... --jq '...browser_download_url'`.
185
- - Embed as `![<view> (after)](<url>)` and patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
186
- - **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description (now for newly-introduced screenshots too).
186
+ - **GitHub (release-asset CDN recipe):** resolve and GET-verify the current PR's `<owner>/<repo>`. Enumerate configured `gh` accounts, select one with push permission by probing that exact slug through a per-command `GH_TOKEN`, and fail closed if none qualifies. **NEVER run `gh auth switch` or hardcode an operator login.**
187
+ - Query the exact `pr-<num>-visual` tag with `gh release view` first. Upload the explicitly listed current PNGs/videos with `gh release upload ... --clobber` only when that tag exists; create it only after a verified not-found response. Never treat an arbitrary create failure as authorization to overwrite.
188
+ - Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-<num>-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
189
+ - Embed images as `![<view> (after)](<url>)` and recordings as `[<view> (recording)](<url>)`, then patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
190
+ - **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG/video bytes, then reference the returned URL in the description (now for newly-introduced screenshots and recordings too).
187
191
  4. Degrade gracefully: if the dev server won't start, the route 404s, Playwright is unavailable, or the upload fails → SKIP without failing the work item and record the skip + reason in `meta.descriptionAudit` (e.g. `result: "screenshots-skipped (dev-server-unavailable)"`).
188
192
 
189
193
  **Out-of-scope guardrails**
@@ -47,6 +47,8 @@ Do ALL work in the worktree.
47
47
 
48
48
  Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{branch_name}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
49
49
 
50
+ An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
51
+
50
52
  ## Working Style
51
53
 
52
54
  Use subagents only for genuinely parallel, independent tasks. For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
@@ -10,16 +10,11 @@ TEAM ROOT: {{team_root}}
10
10
  Repository ID is injected as `{{ado_project}}` and `{{repo_name}}` template variables.
11
11
  Repo: {{repo_name}} | Org: {{ado_org}} | Project: {{ado_project}}
12
12
 
13
- ## Branch Naming Convention
14
- Branch format: `user/<loginname>/{{item_id}}-<slug>` — see the canonical "Branch Naming Convention" section in shared-rules above.
13
+ ## Branch ownership
15
14
 
16
- `<loginname>` is the **human operator's platform login** (e.g. `yemi33` on GitHub, `yemishin` on ADO), resolved via `gh api user --jq .login` or `az account show --query user.name -o tsv`. **Do NOT use the AI agent persona name** (`dallas`, `ripley`, …).
17
-
18
- Examples:
19
- - `user/yemi33/M001-hr-agent`
20
- - `user/yemishin/M013-multimodal-input`
21
-
22
- The engine pre-creates your worktree on a branch matching this convention. The branch is already injected as `{{branch_name}}` — push to that branch as-is; do not create or rename branches.
15
+ The engine pre-created this worktree on `{{branch_name}}`. Push that branch
16
+ as-is; do not derive a branch from a user or platform account, and do not create
17
+ or rename branches.
23
18
 
24
19
  ## Your Task
25
20
 
@@ -40,6 +35,8 @@ If this feature spans multiple projects, inspect the relevant repos, make change
40
35
 
41
36
  Before starting work, run `git status` and verify the worktree is clean and on the expected branch. If the worktree is dirty or on the wrong branch, report the issue and stop.
42
37
 
38
+ An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
39
+
43
40
  ## Working Style
44
41
 
45
42
  Use subagents only for genuinely parallel, independent tasks (e.g., editing files in unrelated modules simultaneously). For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
@@ -140,22 +137,24 @@ After you push commits to the PR's source branch and BEFORE you mark the work it
140
137
  - Azure DevOps: `az repos pr update --id <num> --description "$(Get-Content -Raw <file>)"`. If the body exceeds ~4 KB, fall back to `az rest --method patch` against `…/pullRequests/<id>?api-version=7.1` with `{ "description": "<body>" }`.
141
138
  7. GET-verify the description post-patch by re-running step 1 and confirming the body matches what you sent.
142
139
 
143
- **Screenshot handling (introduce AND refresh for visual changes)**
140
+ **Visual evidence handling — screenshots + recordings (introduce AND refresh for visual changes)**
141
+
142
+ Visual evidence is a **default behavior for UI changes on ANY project**, not minions-only. For a PR that contains a **meaningful visual/UI change** (web front-ends, dashboards, mobile webviews, any rendered surface a user sees), proactively CAPTURE evidence and EMBED it directly in the PR description — do NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is and is minions-specific; this is additive PR-body evidence). Decide "is this visual?" from whether the diff changes a rendered UI surface, NOT from repo-specific paths. Capture BEFORE/AFTER screenshots (AFTER-only for new UI) AND a screen recording/video for interactive, animated, or multi-step flows. When the description already embeds `![alt](url)` refs for a view this dispatch touched, refresh them the same way.
144
143
 
145
- For a PR that contains a **meaningful visual/UI change**, proactively CAPTURE screenshots and EMBED them directly in the PR descriptiondo NOT rely only on the OPG `Visual evidence capture` CI bot (it stays as-is; this is additive PR-body evidence). When the description already embeds `![alt](url)` refs for a view this dispatch touched, refresh them the same way.
144
+ **How to capture resolution order.** (1) **Harness first:** consult the TARGET repo's own instructions for how it runs its UI and captures evidence `AGENTS.md`, `CLAUDE.md`, `README`/`CONTRIBUTING`, a project-local playbook under `projects/<name>/playbooks/`, or a project-embedded skill under `.claude/skills` / `.github/skills` / `.agents/skills` (the engine surfaces this plumbing read-only via `engine/agents/harness-context.js` and `GET /api/harness/diagnostics`). (2) **Fall back** to Minions' project-agnostic Playwright skill `capture-web-evidence` (`.claude/skills/capture-web-evidence/SKILL.md`) when the repo has no visual-evidence instructions.
146
145
 
147
- **MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
146
+ **MANDATORY GATE — UI-surface diffs REQUIRE screenshots.** Screenshot capture + embed is a **required completion gate**, not a nicety, for any dispatch whose diff modifies a **rendered UI surface** — e.g. files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or ANY change that alters what a dashboard page/route renders (layout/CSS/markup/new UI). This is the minions instance of the cross-project default above and is NOT weakened by it. For such a diff you **MUST** capture and embed AFTER screenshots (BEFORE/AFTER for visual FIXES, AFTER-only for NEW UI) for the PR to be considered complete. Omitting screenshots on a UI-surface diff **without a recorded hard-failure reason makes the PR incomplete** — "I judged it not visual enough" is **NOT** a valid skip when the diff touches those paths. The ONLY legitimate skips are genuine hard failures: the dev server will not start after a real attempt, Playwright MCP is unavailable, the route 404s, or upload/attachment auth fails. Record any such skip in `meta.descriptionAudit.result` as `screenshots-skipped (<specific-reason>)`.
148
147
 
149
- **Scope guard — which changes get screenshots.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI.
148
+ **Scope guard — which changes get visual evidence.** Only meaningful visual/UI changes: dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS, and the equivalent rendered surfaces of other projects. Skip backend-only, engine-logic, text/prose-only, analysis, and docs changes — those get NO screenshots or recordings (they add no signal). BEFORE/AFTER pair for layout/visual FIXES; AFTER-only for NEW UI; add a recording only for interactive/animated flows.
150
149
 
151
- 1. If the project has a runnable dev server (detect via `package.json` scripts named `dev`, `start`, or `serve`) AND Playwright MCP is available, spin it up with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
152
- 2. Drive Playwright MCP to the changed route at a normal viewport and screenshot the section that changed. Save raw PNGs to `agents/<id>/screenshots/` ONLY. **NEVER `git add` a PNG** — committing a screenshot is a release-blocker bug. Stop the dev server with the recorded stop command when done.
150
+ 1. Detect the project's run command generically from the repo harness or a `package.json` script named `dev`, `start`, or `serve` (or the repo's documented preview command); do NOT hardcode a per-repo build command. With Playwright available, spin up the dev/preview server with a detached handoff per `shared-rules.md` → "Long-Running Commands" (record PID + log path + URL + stop command).
151
+ 2. Drive Playwright to the changed route/view at a normal desktop viewport (and, for mobile webviews, also at a mobile device-emulation viewport, e.g. `devices['iPhone 13']`) and screenshot the section that changed. For interactive flows, enable video recording, drive the interaction, then save the video. Save raw PNGs/videos to `agents/<id>/screenshots/` ONLY (recordings under a `recordings/` subdir). **NEVER `git add` a PNG** or video — committing captured evidence is a release-blocker bug. Stop the dev server with the recorded stop command when done.
153
152
  3. Upload + embed:
154
- - **GitHub (release-asset CDN recipe):** publish the PNGs as assets on a per-PR prerelease and embed the asset CDN URLs (works on PRIVATE repos, never commits PNGs). Build a per-command `GH_TOKEN` for the repo owner's account (`opg-microsoft` `yemishin_microsoft`, `yemi33` `yemi33`); **NEVER run `gh auth switch`**.
155
- - bash: `GH_TOKEN=$(gh auth token --user yemishin_microsoft --hostname github.com)` then `GH_TOKEN=$GH_TOKEN gh release create "pr-${PR}-visual" agents/<id>/screenshots/*.png --repo <owner>/<repo> --title "PR #${PR} visual evidence" --prerelease --notes "..."` (on re-dispatch use `gh release upload "pr-${PR}-visual" … --clobber`). Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-${PR}-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
156
- - PowerShell: `$env:GH_TOKEN = (gh auth token --user yemishin_microsoft --hostname github.com); $pngs = Get-ChildItem agents/<id>/screenshots/*.png; gh release create "pr-$PR-visual" $pngs --repo <owner>/<repo> --title "PR #$PR visual evidence" --prerelease --notes "..."; if ($LASTEXITCODE -ne 0) { gh release upload "pr-$PR-visual" $pngs --repo <owner>/<repo> --clobber }` then `gh api ... --jq '...browser_download_url'`.
157
- - Embed as `![<view> (after)](<url>)` and patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
158
- - **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG bytes, then reference the returned URL in the description (now for newly-introduced screenshots too).
153
+ - **GitHub (release-asset CDN recipe):** resolve and GET-verify the current PR's `<owner>/<repo>`. Enumerate configured `gh` accounts, select one with push permission by probing that exact slug through a per-command `GH_TOKEN`, and fail closed if none qualifies. **NEVER run `gh auth switch` or hardcode an operator login.**
154
+ - Query the exact `pr-<num>-visual` tag with `gh release view` first. Upload the explicitly listed current PNGs/videos with `gh release upload ... --clobber` only when that tag exists; create it only after a verified not-found response. Never treat an arbitrary create failure as authorization to overwrite.
155
+ - Resolve URLs via `gh api repos/<owner>/<repo>/releases/tags/pr-<num>-visual --jq '.assets[]|select(.name=="after.png")|.browser_download_url'`.
156
+ - Embed images as `![<view> (after)](<url>)` and recordings as `[<view> (recording)](<url>)`, then patch the body with `gh pr edit <num> --repo <owner>/<repo> --body-file <file>`.
157
+ - **ADO:** `PUT /pullRequests/<id>/attachments/<filename>` with the PNG/video bytes, then reference the returned URL in the description (now for newly-introduced screenshots and recordings too).
159
158
  4. Degrade gracefully: if the dev server won't start, the route 404s, Playwright is unavailable, or the upload fails → SKIP without failing the work item and record the skip + reason in `meta.descriptionAudit` (e.g. `result: "screenshots-skipped (dev-server-unavailable)"`).
160
159
 
161
160
  **Out-of-scope guardrails**
@@ -17,6 +17,16 @@ A user has provided a plan. Analyze it against the codebase and produce a struct
17
17
 
18
18
  {{retry_context}}
19
19
 
20
+ {{#revision_feedback}}
21
+ ## Revision Requested
22
+
23
+ This run is a **revision** of the existing PRD below, not a fresh conversion. An operator reviewed that PRD and asked for these changes:
24
+
25
+ {{revision_feedback}}
26
+
27
+ Apply this feedback on top of the "Reusing an Existing PRD" rules — preserve item IDs and `done` statuses for everything the feedback does not touch, and re-emit the PRD with the requested changes applied. Addressing every point above is the acceptance bar for this run.
28
+
29
+ {{/revision_feedback}}
20
30
  ## Instructions
21
31
 
22
32
  1. **Read the plan carefully** — understand the goals, scope, and requirements
@@ -38,12 +48,15 @@ The sidecar must be an envelope with the exact pre-generated filename:
38
48
  ```json
39
49
  {
40
50
  "filename": "{{prd_filename}}",
51
+ "work_item": "{{item_id}}",
41
52
  "prd": {
42
53
  "...": "the PRD object described below"
43
54
  }
44
55
  }
45
56
  ```
46
57
 
58
+ `filename` and `work_item` are the engine's authoritative contract for THIS dispatch — copy them verbatim from this playbook. If a `prd-result.json` from a previous attempt is already on disk, OVERWRITE it; never reuse or trust a filename, work item id, or PRD body found in it. The engine rejects a sidecar that declares any other filename or work item.
59
+
47
60
  The engine validates and imports this one-shot sidecar into SQLite when the dispatch completes, then deletes it. Do not write runtime state under `prd/`.
48
61
 
49
62
  ```json
@@ -115,12 +128,14 @@ Choose one of the following strategies based on how the items relate to each oth
115
128
  {{branch_strategy_hint}}
116
129
 
117
130
  When using `shared-branch`:
118
- - Generate a `feature_branch` name using the canonical convention: `user/<loginname>/PL-<short-kebab-description>` (≤ 120 chars, lowercase). `<loginname>` is the human operator's platform login (e.g. `yemi33` on GitHub) — never an AI agent persona. See `shared-rules.md` → "Branch Naming Convention".
131
+ - Generate a repository-neutral `feature_branch` as
132
+ `work/PL-<short-kebab-description>` (≤ 120 chars, lowercase). Do not embed a
133
+ user, agent, or platform account name.
119
134
  - Use `depends_on` to express the ordering — items execute in dependency order
120
135
  - Each item should be able to build on the prior items' work
121
136
 
122
137
  When using `parallel`:
123
- - Omit `feature_branch` (the engine derives per-item branches as `user/<loginname>/<wi-id>-<slug>`)
138
+ - Omit `feature_branch` (the engine derives each item as `work/<wi-id>`)
124
139
  - `depends_on` is still respected but items can dispatch concurrently if no deps
125
140
 
126
141
  Rules for items:
@@ -196,7 +211,7 @@ If the task description contains `mode: diff-aware-update`, you are updating an
196
211
  ## Important
197
212
 
198
213
  - Write ONLY the single result sidecar at `{{team_root}}/agents/{{agent_id}}/prd-result.json`
199
- - Wrap the PRD object in `{ "filename": "{{prd_filename}}", "prd": { ... } }`
214
+ - Wrap the PRD object in `{ "filename": "{{prd_filename}}", "work_item": "{{item_id}}", "prd": { ... } }`
200
215
  - Do NOT create a git branch, worktree, or PR — this playbook writes minions-internal state only
201
216
  - Do NOT modify any files in the project repo
202
217
  - The engine will dispatch implementation agents automatically once the sidecar is imported
@@ -31,8 +31,25 @@ natural-language flows into a runner-native test file.
31
31
  - **Managed-spawn target:** `{{managed_spawn_name}}` (live — query
32
32
  `{{managed_spawn_lookup_url}}`
33
33
  for the freshest port / base URL / health).
34
+ - **Session services (JSON):** `{{session_services_json}}`
34
35
  - **Test output directory (absolute):** `{{qa_test_dir}}`
35
36
 
37
+ ### Session services — every entry is a real, separately-reachable origin
38
+
39
+ `{{session_services_json}}` lists **every** managed-spawn this session owns, as
40
+ `[{ "name", "project", "primary", "health", "baseUrl", "ports" }]`. On a
41
+ multi-project session the engine started one service per project, and each one
42
+ is a **real, separately-reachable origin** — a distinct process listening on its
43
+ own `baseUrl` / `ports`, not a route on the primary. Address a co-service by
44
+ **its own** `baseUrl`; never assume the primary's origin proxies it.
45
+
46
+ `managed_spawn_name` above is always the **primary** entry (`primary: true`).
47
+ `health` is `healthy` | `unhealthy` | `down` | `missing` at render time — treat
48
+ anything other than `healthy` as not-yet-usable and re-check via
49
+ `{{managed_spawn_lookup_url}}` (swap the name in the path) before drafting
50
+ against it. An empty value means this session has no service inventory (a
51
+ single-project session already fully described by `managed_spawn_name`).
52
+
36
53
  {{additional_context}}
37
54
 
38
55
  ## What "qa-session-draft" means
@@ -81,6 +98,124 @@ Example:
81
98
  }
82
99
  ```
83
100
 
101
+ ## Visual-journey manifest (REQUIRED when capture asks for screenshots or video)
102
+
103
+ `{{capture}}` above is what the operator asked this session to capture. When it
104
+ contains `screenshots` or `video`, the completion report is **not** enough — you
105
+ must also declare **what the drafted test actually exercises** in a
106
+ visual-journey manifest sidecar:
107
+
108
+ ```
109
+ {{qa_draft_result_sidecar}}
110
+ ```
111
+
112
+ Write it as a single JSON object before you exit. The engine consumes it
113
+ **exactly once** (read-then-unlink) in `engine/orchestration/lifecycle.js`,
114
+ validates it in `engine/qa/visual-journey.js`, and **refuses to advance the
115
+ session to EXECUTE** when the declaration does not cover the session. The
116
+ manifest is a declaration, not a scan — describe the file you wrote, honestly.
117
+
118
+ ### Schema
119
+
120
+ ```json
121
+ {
122
+ "sessionId": "{{session_id}}",
123
+ "journeys": [
124
+ {
125
+ "id": "short-stable-id",
126
+ "name": "One line describing the user-visible flow",
127
+ "kind": "browser",
128
+ "projects": ["web"],
129
+ "services": ["{{managed_spawn_name}}"],
130
+ "origins": ["http://localhost:7346"],
131
+ "steps": ["open /login", "submit credentials"],
132
+ "assertions": ["dashboard header is visible"],
133
+ "evidence": { "screenshots": ["login.png"], "video": ["login.webm"] }
134
+ }
135
+ ]
136
+ }
137
+ ```
138
+
139
+ - `kind` is `browser` (drives a real rendered surface) or `api` (HTTP only).
140
+ - `projects` / `services` / `origins` say **which** project, managed-spawn, and
141
+ origin that journey touches. Take the names verbatim from
142
+ `{{session_services_json}}` — each entry there is a separately-reachable
143
+ origin, so a co-service journey names the **co-service's own** spawn and base
144
+ URL, never the primary's.
145
+ - `evidence` lists the artifact files the test is written to produce.
146
+ Screenshots must be planned as `.png`, video as `.webm`.
147
+ - Journeys, list lengths, and per-entry sizes are capped
148
+ (`engine/qa/visual-journey.js` `LIMITS`). Keep it to what the test covers.
149
+
150
+ ### What the gate rejects
151
+
152
+ When `{{capture}}` includes `screenshots` or `video`, DRAFT fails with
153
+ `failure_class: qa-session-draft-visual-coverage` — the session goes to
154
+ `failed`, EXECUTE is never queued — if any of these holds:
155
+
156
+ | Rejection | Fix |
157
+ |---|---|
158
+ | No manifest at all | Write the sidecar above. |
159
+ | No journey with `"kind": "browser"` | An API-only draft cannot produce screenshots or video. Draft a real browser flow. |
160
+ | A project in the session is in no journey's `projects` | Cover every project the session declared. |
161
+ | A managed-spawn the session owns is in no journey's `services` | Cover every entry of `{{session_services_json}}`, each at its own origin. |
162
+ | `screenshots` requested but no `.png` planned | Plan at least one `.png` under `evidence.screenshots`. |
163
+ | `video` requested but no `.webm` planned | Plan at least one `.webm` under `evidence.video`. |
164
+
165
+ Each rejection message names exactly what is missing, so read
166
+ `session.error` before re-drafting.
167
+
168
+ ### Worked example — multi-project session (`web` primary + `api` co-service)
169
+
170
+ Session `{{session_id}}` with `projects: ["web", "api"]`, primary `web`, and
171
+ `capture: video,screenshots`. `{{session_services_json}}` reports two live
172
+ services, so the manifest covers **both** origins and both projects:
173
+
174
+ ```json
175
+ {
176
+ "sessionId": "{{session_id}}",
177
+ "journeys": [
178
+ {
179
+ "id": "web-login",
180
+ "name": "Operator signs in on the web app and lands on the dashboard",
181
+ "kind": "browser",
182
+ "projects": ["web"],
183
+ "services": ["{{managed_spawn_name}}"],
184
+ "origins": ["http://localhost:7346"],
185
+ "steps": [
186
+ "goto http://localhost:7346/login",
187
+ "fill credentials and submit",
188
+ "wait for the dashboard route"
189
+ ],
190
+ "assertions": ["dashboard header is visible", "no console errors"],
191
+ "evidence": { "screenshots": ["web-login.png"], "video": ["web-login.webm"] }
192
+ },
193
+ {
194
+ "id": "api-backed-list",
195
+ "name": "Dashboard list renders records served by the api co-service",
196
+ "kind": "browser",
197
+ "projects": ["api"],
198
+ "services": ["{{managed_spawn_name}}-api"],
199
+ "origins": ["http://localhost:7346", "http://localhost:4000"],
200
+ "steps": [
201
+ "seed a record via POST http://localhost:4000/api/records",
202
+ "reload the dashboard list"
203
+ ],
204
+ "assertions": ["the seeded record appears in the list"],
205
+ "evidence": { "screenshots": ["api-backed-list.png"], "video": [] }
206
+ }
207
+ ]
208
+ }
209
+ ```
210
+
211
+ Note the second journey is still `"kind": "browser"`: it *uses* the co-service
212
+ origin but asserts on a rendered surface, which is what visual capture means.
213
+ A journey that only calls the API is `"kind": "api"` and does not satisfy the
214
+ browser requirement on its own.
215
+
216
+ If `{{capture}}` asks for neither screenshots nor video, the manifest is
217
+ optional and the session behaves exactly as before.
218
+
84
219
  ## No PR, no commit
85
220
 
86
221
  `qa-session-draft` is a test-authoring task. **Do not**:
@@ -112,7 +247,7 @@ write a partial test file**. Instead, write your completion report with:
112
247
  }
113
248
  ```
114
249
 
115
- The `engine/qa-sessions.js#handleDraftComplete` hook reads `failure_class`
250
+ The `engine/qa/sessions.js#handleDraftComplete` hook reads `failure_class`
116
251
  and the summary, transitions the session to `failed`, and surfaces the
117
252
  explanation in the dashboard session card so the human knows exactly why
118
253
  DRAFT gave up.
@@ -23,6 +23,7 @@ ingests.
23
23
  - **Managed-spawn target:** `{{managed_spawn_name}}` (live — query
24
24
  `{{managed_spawn_lookup_url}}`
25
25
  for the freshest port / base URL / health).
26
+ - **Session services (JSON):** `{{session_services_json}}`
26
27
  - **Test file (relative to `engine/qa-tests/{{session_id}}/`):** `{{test_file}}`
27
28
  - **Flows (for context):** {{flows_raw}}
28
29
  - **Runner hint (optional explicit runner):** `{{runner_hint}}`
@@ -30,6 +31,24 @@ ingests.
30
31
  - **Mode:** `{{session_mode}}`
31
32
  - **qa-runs record id (use this in the sidecar's `runId` field):** `{{qa_run_id}}`
32
33
 
34
+ ### Session services — every entry is a real, separately-reachable origin
35
+
36
+ `{{session_services_json}}` lists **every** managed-spawn this session owns, as
37
+ `[{ "name", "project", "primary", "health", "baseUrl", "ports" }]`. On a
38
+ multi-project session the engine started one service per project, and each one
39
+ is a **real, separately-reachable origin** — a distinct process listening on its
40
+ own `baseUrl` / `ports`, not a route on the primary. When the drafted test
41
+ targets a co-service, point the run at **that entry's** `baseUrl`; never assume
42
+ the primary's origin proxies it.
43
+
44
+ `managed_spawn_name` above is always the **primary** entry (`primary: true`).
45
+ `health` is `healthy` | `unhealthy` | `down` | `missing` at render time. If a
46
+ service the test needs is not `healthy`, re-check it via
47
+ `{{managed_spawn_lookup_url}}` (swap the name in the path) before running — do
48
+ not start or restart it yourself, the engine owns the lifecycle. An empty value
49
+ means this session has no service inventory (a single-project session already
50
+ fully described by `managed_spawn_name`).
51
+
33
52
  {{additional_context}}
34
53
 
35
54
  ## What "qa-session-execute" means
@@ -57,11 +76,21 @@ shape:
57
76
  "runId": "{{qa_run_id}}",
58
77
  "status": "passed",
59
78
  "summary": "1 sentence rollup the dashboard will render",
79
+ "journeyCoverage": [
80
+ {
81
+ "journeyId": "login",
82
+ "status": "passed",
83
+ "projects": ["web"],
84
+ "services": ["qa-session-{{session_id}}"]
85
+ }
86
+ ],
60
87
  "artifacts": [
61
88
  {
62
89
  "type": "screenshot",
63
90
  "path": "test-capture-layout/01-login-form.png",
64
91
  "label": "Login form rendered",
92
+ "journeyId": "login",
93
+ "project": "web",
65
94
  "capturedAt": "2026-05-20T20:42:00.000Z"
66
95
  }
67
96
  ]
@@ -78,12 +107,61 @@ Valid `status` values:
78
107
  unreachable mid-run (use this sparingly — distinguishes infra failure
79
108
  from real product-level failure).
80
109
 
81
- The engine consumes this sidecar in `engine/lifecycle.js` and calls
110
+ ### Journey coverage (REQUIRED when this session captures screenshots or video)
111
+
112
+ `journeyCoverage` reports what the run **actually exercised**, one entry per
113
+ journey the DRAFT phase declared in its visual-journey manifest:
114
+
115
+ - `journeyId` — the manifest journey id, verbatim.
116
+ - `status` — `passed` | `failed` | `skipped`.
117
+ - `projects` — every project this journey produced evidence for.
118
+ - `services` — every managed-spawn name this journey addressed **at its own
119
+ origin** (see the session services block above).
120
+
121
+ {{#visual_journey_manifest_json}}
122
+ The DRAFT phase's **accepted manifest** is injected below. These are the exact
123
+ `journeyId` values the engine grades you against — copy them verbatim, one
124
+ `journeyCoverage` entry per journey. Do not invent, rename, merge, or drop ids;
125
+ an id the manifest declared that never comes back `passed` fails the session.
126
+
127
+ ```json
128
+ {{visual_journey_manifest_json}}
129
+ ```
130
+
131
+ The `projects` / `services` shown per journey are what DRAFT **planned** to
132
+ exercise. Report what your run **actually** exercised: if a journey covered
133
+ more, list more; if it covered less, report it honestly with the status it
134
+ earned and let the gate fail the session rather than overstating coverage.
135
+ {{/visual_journey_manifest_json}}
136
+
137
+ Per-artifact `journeyId` and `project` are optional but expected on visual
138
+ sessions: they are what lets the dashboard join a PNG back to the journey and
139
+ project it proves. Both fields are ignored on legacy `qa-validate` runs.
140
+
141
+ **The engine verifies this — it is not paperwork.** When the session requested
142
+ `screenshots` or `video`,
143
+ `engine/qa/visual-journey.js#validateEvidenceCoverage` runs before the session
144
+ is allowed to reach `done` and fails the session with
145
+ `failure_class: 'qa-session-evidence-incomplete'` when:
146
+
147
+ - a requested capture type has **no** registered artifact of that type;
148
+ - a registered artifact does **not exist** on disk, is zero bytes, or resolves
149
+ **outside** `{{qa_artifacts_dir}}`;
150
+ - some project in the session appears in no **passed** journey's `projects`;
151
+ - some managed-spawn the session owns appears in no **passed** journey's
152
+ `services`;
153
+ - a journey the DRAFT manifest declared never reported `status: "passed"`.
154
+
155
+ So: capture real files, register them with paths relative to
156
+ `{{qa_artifacts_dir}}`, and report coverage honestly. A `passed` run that
157
+ cannot show its evidence is failed by the engine, not rounded up.
158
+
159
+ The engine consumes this sidecar in `engine/orchestration/lifecycle.js` and calls
82
160
  `qaRuns.completeRun({{qa_run_id}}, …)`. **If the sidecar is missing when
83
161
  you exit, the engine marks the run `errored`** — always write it, even on
84
162
  bail-out.
85
163
 
86
- The `engine/qa-sessions.js#handleExecuteComplete` hook then reads the
164
+ The `engine/qa/sessions.js#handleExecuteComplete` hook then reads the
87
165
  qa-runs terminal status and transitions the session to `done` / `failed`
88
166
  accordingly.
89
167
 
@@ -56,6 +56,22 @@ error) **fails the entire session** with `failure_class: 'qa-session-setup-faile
56
56
  and a per-project error JSON in `session.error`. The primary's WI does NOT
57
57
  get the DRAFT phase queued in that case.
58
58
 
59
+ ### Every origin you stand up must be journey-addressable (W-msb9kgs402813a97-b)
60
+
61
+ DRAFT must declare a **visual-journey manifest** naming every managed-spawn the
62
+ session owns, each addressed at **its own** origin — and the engine refuses to
63
+ advance to EXECUTE when a spawn is uncovered
64
+ (`failure_class: qa-session-draft-visual-coverage`). So your spawn is only
65
+ useful if the next agent can actually reach and identify it:
66
+
67
+ - declare a **deterministic** port in `managed-spawn.json` `ports[]` (never a
68
+ random/ephemeral one) so `{{session_services_json}}` reports a stable
69
+ `baseUrl` DRAFT can put in a journey's `origins`;
70
+ - expose a healthcheck that goes green only when the service is genuinely
71
+ serving, because DRAFT treats anything other than `healthy` as unusable;
72
+ - do **not** assume the primary proxies you — a co-service is a real,
73
+ separately-reachable origin and is journeyed as one.
74
+
59
75
  For single-project sessions (`{{co_services_json}}` empty or `[]`), ignore
60
76
  this section — the original single-WI flow applies unchanged.
61
77
 
@@ -148,7 +164,7 @@ sidecar**. Instead, write your completion report with:
148
164
  }
149
165
  ```
150
166
 
151
- The `engine/qa-sessions.js#handleSetupComplete` hook reads `failure_class`
167
+ The `engine/qa/sessions.js#handleSetupComplete` hook reads `failure_class`
152
168
  and the summary, transitions the session to `failed`, and surfaces the
153
169
  explanation in the dashboard session card so the human knows exactly why
154
170
  SETUP gave up.
@@ -63,7 +63,7 @@ block above) and registered a `qaRunId`. Your job:
63
63
  Valid `status` values: `passed` (all required artifacts produced and steps
64
64
  green), `failed` (at least one expected step failed — still write the sidecar
65
65
  with whatever artifacts you captured). The engine consumes this file in
66
- `engine/lifecycle.js` and calls `qaRuns.completeRun(runId, ...)`. **If the
66
+ `engine/orchestration/lifecycle.js` and calls `qaRuns.completeRun(runId, ...)`. **If the
67
67
  sidecar is missing when you exit, the engine marks the run `errored`** —
68
68
  always write it, even on bail-out.
69
69
 
@@ -86,6 +86,8 @@ as in `implement`.
86
86
  Before starting work, run `git status` to confirm the worktree is clean.
87
87
  If it's dirty or on an unexpected branch, report and stop.
88
88
 
89
+ An untracked root-level `.minions-worktree` entry is expected Minions orchestration metadata, not source dirt. Do not delete or modify the marker. Any other status entry, including staged, modified, deleted, or other untracked files, means the worktree is dirty.
90
+
89
91
  ## Working Style
90
92
 
91
93
  Use subagents only for genuinely parallel, independent tasks. For sequential