@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
@@ -41,32 +41,19 @@ Bias toward senior-engineer restraint:
41
41
  - Clean up only artifacts introduced by your own work, such as now-unused imports, variables, helpers, docs, or tests. Mention unrelated dead code instead of deleting it.
42
42
  - Turn the task into verifiable goals before editing. For bugs, prefer a reproducing test or command first; for features, identify the acceptance behavior and the smallest relevant check. Keep iterating until that check passes or you have concrete evidence for a blocker.
43
43
 
44
- ## Branch Naming Convention
44
+ ## Branch ownership
45
45
 
46
- All branches use the format:
47
-
48
- user/<loginname>/<wi-id>-<slug>
49
-
50
- - `<loginname>` is the **human operator's platform login** — never the AI agent's persona (`dallas`, `ripley`, `lambert`, …). Resolve in this order:
51
- 1. GitHub repos: `gh api user --jq .login` (e.g. `yemi33`, `yemishin_microsoft`)
52
- 2. Azure DevOps repos: `az account show --query user.name -o tsv` and take the localpart before `@` (e.g. `yemishin`)
53
- 3. Fallback: `git config user.email` localpart, then `$USER` / `$USERNAME`
54
- - `<wi-id>` is the work-item or PRD-item id verbatim (`W-mp7abc123`, `P-a1b2c3d4`, `PL-…`).
55
- - `<slug>` is a short lowercase kebab-case summary derived from the title. ASCII only, words separated by `-`, ≤ 40 chars, no leading/trailing hyphens.
56
-
57
- Examples:
58
- - `user/yemi33/W-mp7abc123-fix-login-redirect`
59
- - `user/yemishin/P-a1b2c3d4-shared-schemas`
60
- - `user/yemishin_microsoft/PL-feature-rollout-stage-1`
61
-
62
- Application:
63
- - The engine pre-creates your worktree on a branch matching this convention. Push to that branch as injected via `{{branch_name}}` — do not create or rename branches.
64
- - When you create a work item programmatically (API, plan-to-prd, scripts), set the WI's `branch` (or PRD `feature_branch`) to the conventional name so the engine creates the worktree on the right branch from the start. `dashboard.js` derives this automatically when callers omit `branch`.
65
- - The legacy `feat/<id>-<slug>` and bare `work/<id>` formats are deprecated; the engine no longer falls back to them.
46
+ The engine pre-creates the task worktree and injects its branch as
47
+ `{{branch_name}}`. Push that exact branch; do not derive a branch from a user,
48
+ create or rename branches, or infer ownership from the active platform account.
49
+ When a caller omits a branch, the canonical engine fallback is `work/<wi-id>`.
50
+ Shared-branch plans use the PRD's explicit `feature_branch`.
66
51
 
67
52
  ### PR-fix exception (DO NOT branch off master)
68
53
 
69
- For a `type: "fix"` work item that targets an existing PR, the engine reuses the PR's **source branch** (e.g. `yemishin/task-hub-symphony-gate`) instead of derivingthe `user/<loginname>/<wi-id>-<slug>` form. PR pointers are detected from any of:
54
+ For a `type: "fix"` work item that targets an existing PR, the engine reuses the
55
+ PR's **source branch** instead of deriving a new task branch. PR pointers are
56
+ detected from any of:
70
57
 
71
58
  - Structured fields: `targetPr`, `pr_id`, `prUrl`, `prNumber`, `pullRequest`, `sourcePr`
72
59
  - `references[*].url` (manual `/api/work-items` callers usually pass the PR pointer here)
@@ -167,12 +154,16 @@ For the canonical schema — every field, the `failure_class` enum, `noop:true`
167
154
 
168
155
  ## Minions API access
169
156
 
170
- The Minions dashboard runs at `http://localhost:7331` whenever the engine is up. Agents may call its HTTP endpoints when (and only when) the playbook explicitly authorizes it for a particular task — most dispatches do not need any API access, and uninvited writes to engine-managed state are still prohibited (see "Do NOT write to `agents/*/status.json`" above).
157
+ The resolved Minions dashboard for this dispatch is
158
+ `http://localhost:{{dashboard_port}}`. Agents may call its HTTP endpoints when
159
+ (and only when) the playbook explicitly authorizes it for a particular task.
160
+ Most dispatches do not need API access, and uninvited writes to engine-managed
161
+ state are prohibited.
171
162
 
172
163
  When a playbook authorizes an API call (e.g. follow-up work-item dispatch from `playbooks/templates/followup-dispatch.md`), use the standard `curl` shape:
173
164
 
174
165
  ```bash
175
- curl -sS -X POST http://localhost:7331/api/<route> \
166
+ curl -sS -X POST http://localhost:{{dashboard_port}}/api/<route> \
176
167
  -H 'Content-Type: application/json' \
177
168
  -H 'X-Minions-Agent: <your-agent-id>' \
178
169
  -H 'X-Minions-Origin-Wi: <current-work-item-id>' \
@@ -181,7 +172,7 @@ curl -sS -X POST http://localhost:7331/api/<route> \
181
172
 
182
173
  Conventions:
183
174
 
184
- - The full live route surface is available at `GET http://localhost:7331/api/routes` (the route registry includes method, path, and a one-line description for every handler).
175
+ - The full live route surface is available at `GET http://localhost:{{dashboard_port}}/api/routes` (the route registry includes method, path, and a one-line description for every handler).
185
176
  - **Identification headers (for traceability, not auth).** Set `X-Minions-Agent` to your agent id and `X-Minions-Origin-Wi` to the work-item id you were dispatched against. Endpoints that persist these (e.g. `POST /api/work-items`) store them as `_originAgent` / `_originWi` for the dashboard timeline. Agents do **not** have a `X-CC-Turn-Id` — that header is reserved for Command Center turns.
186
177
  - The dashboard binds to `127.0.0.1` only; no auth token is required for localhost calls.
187
178
  - Treat HTTP 4xx as a contract violation: surface the response body in your completion summary instead of retrying blindly.
@@ -208,7 +199,7 @@ Concretely:
208
199
  - Do not sleep or busy-wait for `mergeStatus`, `buildStatus`, or any ADO/GitHub API to flip from `running` to `passing`.
209
200
  - If you skipped local validation, say so in the completion JSON (e.g. `tests: skipped — relying on PR pipeline`) and still exit.
210
201
  - Holding a slot to watch a pipeline is wasted capacity; the engine has its own pipeline-monitoring path.
211
- - **Screenshots are a MANDATORY completion gate for UI-surface diffs.** Any PR whose diff changes a rendered dashboard/UI surface (files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or anything that alters what a page/route renders) MUST embed AFTER screenshots in the PR description (full recipe: `_pr-description-audit.md`) skips are allowed only on a recorded hard failure (dev server won't start, Playwright MCP unavailable, route 404s, upload auth fails). Backend/engine/text/analysis/docs diffs get NO screenshots.
202
+ - **Visual evidence (screenshots + recordings) is a DEFAULT completion behavior for UI changes on ANY project.** By default, when your diff alters a **rendered UI surface in any project** — web front-ends, dashboards, mobile webviews, or any view a user sees — capture and embed visual evidence in the PR description: BEFORE/AFTER screenshots for visual fixes (AFTER-only for new UI), plus a **screen recording/video** for interactive, animated, or multi-step flows. Decide "is this a visual change?" from whether the diff changes a rendered surface, NOT from repo-specific paths. **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 harness plumbing read-only via `engine/agents/harness-context.js` and `GET /api/harness/diagnostics`); (2) **fall back** to Minions' own project-agnostic Playwright skill `capture-web-evidence` (`.claude/skills/capture-web-evidence/SKILL.md`) when the repo has no visual-evidence instructions. As ONE concrete example, the **minions dashboard gate stays MANDATORY**: any PR whose diff changes a rendered dashboard/UI surface (files under `dashboard/`, `dashboard/slim/`, `dashboard/pages/`, `dashboard/js/`, `dashboard/styles.css`, or anything that alters what a page/route renders) MUST embed AFTER screenshots in the PR description (full recipe: `_pr-description-audit.md`). Skips are allowed only on a recorded hard failure (dev server won't start, Playwright MCP unavailable, route 404s, upload auth fails). Save PNGs/videos ONLY under `agents/<id>/screenshots/` (recordings under a `recordings/` subdir) — NEVER `git add` a screenshot or video. Backend/engine/text/analysis/docs diffs get NO visual evidence.
212
203
 
213
204
  ## Resolving Review Threads — No Silent Closures
214
205
 
@@ -317,7 +308,9 @@ gh pr view <prNumber> --json number,title,state,mergeable,reviewDecision,headRef
317
308
 
318
309
  ## Posting PR Comments and Reviews (MANDATORY MARKER)
319
310
 
320
- Every PR comment or review you post is sent through the shared `gh` PAT identity (`yemi33`). The engine has no way to tell your post apart from a real human comment unless you embed the minions marker. Without the marker, the engine queues a redundant fix-dispatch every time you post — see PR #2440 (3 consecutive noop dispatches on a single rebase status comment).
311
+ PR comments and reviews may be sent through a platform credential shared by
312
+ multiple agents. The engine cannot infer Minions agent identity from that
313
+ platform login, so every agent-authored post must include the Minions marker.
321
314
 
322
315
  **Preferred path — `minions pr comment` (auto-prepends the marker):**
323
316
  ```bash
@@ -349,7 +342,7 @@ The marker is an HTML comment on its own line — GitHub's renderer strips it be
349
342
  ```
350
343
  So write `Fixed by [Minions](https://icy-water-0224cc51e.2.azurestaticapps.net/minions)`, not a bare `Fixed by Minions`. This applies to GitHub and ADO comments alike. Do **not** link occurrences inside the HTML marker line, code blocks, or file paths — only the human-readable prose mention. Link the first occurrence per comment; subsequent repeats in the same comment may stay plain.
351
344
 
352
- > **Engine safety net.** When you post via `minions pr comment` (GitHub: `minions pr comment <repo> <number> …`; ADO: `minions pr comment <number> --host ado --ado-org … --ado-project … --repo-id … …`), the engine deterministically hyperlinks the first bare `… by Minions` signature trailer for you (`engine/comment-format.js#linkifyBrandTrailer`, applied in the shared `buildMinionsCommentBody` consumed by both `engine/gh-comment.js` and `engine/ado-comment.js`) — a no-op if you already linked the first mention. This is a backstop, not a license to skip the link: the **raw fallbacks** (`gh pr comment`, `az repos pr comment`, ADO REST) do NOT pass through that chokepoint, so you must link the brand mention yourself there. Subject-form mentions like "Minions rebased this branch" are still your responsibility on both hosts.
345
+ > **Engine safety net.** When you post via `minions pr comment` (GitHub: `minions pr comment <repo> <number> …`; ADO: `minions pr comment <number> --host ado --ado-org … --ado-project … --repo-id … …`), the engine deterministically hyperlinks the first bare `… by Minions` signature trailer for you (`engine/providers/comment-format.js#linkifyBrandTrailer`, applied in the shared `buildMinionsCommentBody` consumed by both `engine/providers/gh-comment.js` and `engine/ado/comment.js`) — a no-op if you already linked the first mention. This is a backstop, not a license to skip the link: the **raw fallbacks** (`gh pr comment`, `az repos pr comment`, ADO REST) do NOT pass through that chokepoint, so you must link the brand mention yourself there. Subject-form mentions like "Minions rebased this branch" are still your responsibility on both hosts.
353
346
 
354
347
  ## GitHub Tooling and Auth
355
348
 
@@ -379,13 +372,13 @@ Read `GET http://localhost:{{dashboard_port}}/api/pull-requests` and find the pr
379
372
 
380
373
  **Live status (when engine isn't running or you need up-to-the-moment results):**
381
374
  ```bash
382
- node engine/ado-status.js <prNumber> # reads the cached SQL PR store
383
- node engine/ado-status.js <prNumber> --live # fresh ADO API call
384
- node engine/ado-status.js <prNumber> --live --project MyProject
375
+ node engine/ado/status.js <prNumber> # reads the cached SQL PR store
376
+ node engine/ado/status.js <prNumber> --live # fresh ADO API call
377
+ node engine/ado/status.js <prNumber> --live --project MyProject
385
378
  ```
386
379
  Output is JSON with the same fields. Exit 0 on success, 1 if not found.
387
380
 
388
- **Never make raw `curl` calls to ADO APIs directly.** Use `node engine/ado-status.js` which routes through `ado.js` — authenticated, retried, circuit-broken. Raw `azureauth` + curl bypasses all of that.
381
+ **Never make raw `curl` calls to ADO APIs directly.** Use `node engine/ado/status.js`, which routes through `engine/ado/index.js` — authenticated, retried, circuit-broken. Raw `azureauth` + curl bypasses all of that.
389
382
 
390
383
  **If you must run `azureauth` directly, ALWAYS include `--timeout 1`.** Without this flag, `azureauth ado token` can hang indefinitely waiting for interactive broker UI that never appears in headless agent sessions. This causes the Claude Code process to silently exit and the engine to declare the agent orphaned. Example: `azureauth ado token --mode iwa --mode broker --output token --timeout 1`.
391
384
 
@@ -34,11 +34,12 @@ and explain your reasoning — don't manufacture work.
34
34
 
35
35
  ## The API call
36
36
 
37
- The Minions dashboard runs on `http://localhost:7331`. Create a follow-up work
38
- item with `POST /api/work-items`:
37
+ Use the dashboard resolved for this dispatch at
38
+ `http://localhost:{{dashboard_port}}`. Create a follow-up work item with
39
+ `POST /api/work-items`:
39
40
 
40
41
  ```bash
41
- curl -sS -X POST http://localhost:7331/api/work-items \
42
+ curl -sS -X POST http://localhost:{{dashboard_port}}/api/work-items \
42
43
  -H 'Content-Type: application/json' \
43
44
  -H 'X-Minions-Agent: <your-agent-id>' \
44
45
  -H 'X-Minions-Origin-Wi: <current-wi-id>' \
@@ -78,7 +78,7 @@ A green E2E build proves the code compiles and the existing tests still pass. It
78
78
  2. **Identify the silent failure modes.** A change that adds a guard, demotes a fallback, or removes a field has a *what-used-to-happen-here* shadow. Name it. For removals: which call sites read the removed field, and what do they fall back to now? For added guards: what input previously passed and now gets rejected — is that input ever produced legitimately? For demoted fallbacks: which production path relied on the fallback, and is the new primary path actually populated there?
79
79
  3. **Check the test additions cover the new branch, not just the happy path.** A test that only asserts the new behavior on a freshly constructed input is half a test. The other half is: does an *existing* fixture that exercised the old behavior still pass, and does it pass for the right reason (not because the assertion got loosened)? Cite the test by file:line and the fixture it uses.
80
80
  4. **Read the comments in the diff with suspicion.** Comments like "this also handles X" or "the gate at Y skips this path" are claims the agent made. Verify each one by opening Y and confirming the gate actually does what the comment says. If the claim is wrong, the change has a hole.
81
- 5. **Schema/contract changes deserve a grep across language boundaries.** A field added to a JSON contract in `engine/shared.js` may also be referenced in `dashboard/js/*.js`, `playbooks/*.md`, `test/**`, and any external consumer. Run a literal grep for the field name across the whole tree, not just the PR's touched files.
81
+ 5. **Schema/contract changes deserve a grep across language boundaries.** A field added to a JSON contract in `engine/core/shared.js` may also be referenced in `dashboard/js/*.js`, `playbooks/*.md`, `test/**`, and any external consumer. Run a literal grep for the field name across the whole tree, not just the PR's touched files.
82
82
 
83
83
  Record one verdict per engine-touching PR in the form: `PR-####: <safe | risk: <description with path:line citation> | needs human review: <question>>`. "Looks fine" without per-call-site evidence is not acceptable. If you cannot complete the audit in the time available, say so explicitly and list the unaudited PRs in the Merge Decisions section under "PRs requiring human decision".
84
84
 
@@ -41,14 +41,18 @@ Minions runtime state lives in `{{minions_dir}}/engine/state.db` and is accessed
41
41
 
42
42
  ## Your skills
43
43
 
44
- Your runtime is the **Copilot CLI**, not Claude Code. Your installed skills live in:
44
+ Your runtime is the **Copilot CLI**, not Claude Code. The registry below is the complete list of what is available to you, and it mixes two sources that you use in **different ways**.
45
+
46
+ **1. Runtime-registered skills — invoke them with the `skill` tool.** These have no `<path>` element and live in:
45
47
 
46
48
  - `~/.copilot/skills/<name>/SKILL.md` — user-level skills (yours)
47
49
  - `~/.copilot/installed-plugins/<marketplace>/<plugin>/skills/<name>/SKILL.md` — plugin-provided skills (also yours)
48
50
 
49
- To invoke a skill, call your `skill` tool with the skill name (the directory name). The skill body then guides the next steps. **Both user-level and plugin-level skills are invokable the same way** — the `<location>` tag in the registry is metadata, not a permission gate. If the registry below lists a skill, you can load it.
51
+ Call your `skill` tool with the skill name (the directory name); the skill body then guides the next steps. **Both user-level and plugin-level skills are invokable the same way** — the `<location>` tag is metadata, not a permission gate.
52
+
53
+ **2. Project-embedded skills — read the `<path>`, do NOT call the `skill` tool.** Minions discovers these under the configured project checkouts (including nested `.claude/skills`, `.github/skills`, and `.agents/skills` directories) and injects them below with a `project:<name>` `<location>` and an on-disk `<path>`. Your runtime never registered them — your working directory is the Minions root, not that project — so invoking one by name will fail. Instead, read the `SKILL.md` at its `<path>` and follow the steps yourself. When the skill belongs to a project repo, prefer delegating the actual work to an agent on that project (see "Role: Orchestrator" below) and let the agent's own runtime pick the skill up natively.
50
54
 
51
- When asked "what skills do you have", answer from the registry below — do NOT grep/glob `.claude/skills/`. Those belong to a different runtime (Claude Code) and are not available to you, even if the directory exists in cwd or `$HOME`.
55
+ When asked "what skills do you have", answer from the registry below — do NOT grep/glob for skill directories. The registry already enumerates the project-embedded ones (`.claude/skills` included) with their on-disk `<path>`, so a filesystem search adds nothing.
52
56
 
53
57
  {{available_skills}}
54
58
 
@@ -228,7 +232,7 @@ If the endpoint returns `matched:"none"`, you may also enumerate first-level are
228
232
 
229
233
  ## Read-only PR actions on ANY PR — POST /api/pr-action
230
234
 
231
- When the user asks you to **review / summarize / comment-on / triage a specific PR by URL or id** — including PRs in repos that are NOT a configured Minions project (e.g. "review this PR https://github.com/some/repo/pull/42", "summarize ado:org/proj/repo#5215493", "triage github:yemi33/minions#2702") — route it through `POST /api/pr-action` instead of dispatching a `review`/`explore` work item. This path is **projectless and read-only**: it resolves the PR, fetches its diff + metadata with NO clone/worktree, and reasons over the (untrusted-fenced) content. Use it for one-off, look-don't-touch asks on an arbitrary PR.
235
+ When the user asks you to **review / summarize / comment-on / triage a specific PR by URL or id** — including PRs in repos that are NOT a configured Minions project (e.g. "review this PR https://github.com/owner/repo/pull/42", "summarize ado:org/project/repo#123", "triage github:owner/repo#42") — route it through `POST /api/pr-action` instead of dispatching a `review`/`explore` work item. This path is **projectless and read-only**: it resolves the PR, fetches its diff + metadata with NO clone/worktree, and reasons over the (untrusted-fenced) content. Use it for one-off, look-don't-touch asks on an arbitrary PR.
232
236
 
233
237
  - `url` — REQUIRED. A PR URL (`https://github.com/owner/repo/pull/N`, ADO PR URL) or canonical id (`github:owner/repo#N`, `ado:org/proj/repo#N`).
234
238
  - `action` — REQUIRED. One of `review`, `summarize`, `comment`, `triage` (read-only only; a code-mutating `fix` is intentionally NOT accepted here).
@@ -269,10 +273,10 @@ When the user describes a UI/E2E flow they want validated against a *live, runni
269
273
  - The user wants a code change, unit/integration tests in the repo, or an investigation. Keep using `/api/work-items` with `type: "fix"`, `"implement"`, `"test"`, `"explore"`.
270
274
  - The user explicitly says "QA …", "smoke test …", "test the … flow", "validate the … journey", or names a concrete UI walkthrough against a live app. Use `/api/qa/session`.
271
275
 
272
- **Body shape (mirrors `engine/qa-sessions.js#validateSpec`):**
276
+ **Body shape (mirrors `engine/qa/sessions.js#validateSpec`):**
273
277
 
274
278
  - `target` — REQUIRED object describing what to QA against. `target.kind` is one of:
275
- - `pr` — needs `target.prId` (e.g. `"github:yemi33/minions#2911"` or `"ado:office/iss/constellation#5215493"`).
279
+ - `pr` — needs `target.prId` (e.g. `"github:owner/repo#42"` or `"ado:org/project/repo#123"`).
276
280
  - `branch` — needs `target.branch` (e.g. `"develop"`).
277
281
  - `commit` — needs `target.sha` (full 40-char SHA).
278
282
  - `current` — uses the user's current worktree. `target.worktree` is optional; the SETUP agent falls back to `MINIONS_AGENT_CWD` when empty.
@@ -287,7 +291,7 @@ When the user describes a UI/E2E flow they want validated against a *live, runni
287
291
  curl -s -X POST http://localhost:{{dashboard_port}}/api/qa/session \
288
292
  -H 'Content-Type: application/json' \
289
293
  -H 'X-CC-Turn-Id: {{cc_turn_id}}' \
290
- -d '{"target":{"kind":"pr","prId":"github:yemi33/MyApp#1234"},"flowsRaw":"Open the homepage, click Login, enter test@example.com / hunter2, and verify the dashboard renders with the user'\''s name in the header.","mode":"confirm","capture":{"screenshots":true,"logs":true},"projects":["MyApp"]}'
294
+ -d '{"target":{"kind":"pr","prId":"github:owner/MyApp#1234"},"flowsRaw":"Open the homepage, click Login, enter test@example.com / hunter2, and verify the dashboard renders with the user'\''s name in the header.","mode":"confirm","capture":{"screenshots":true,"logs":true},"projects":["MyApp"]}'
291
295
  ```
292
296
 
293
297
  **Worked example — current worktree, auto mode, video capture, single project:**
@@ -312,7 +316,7 @@ curl -s -X POST http://localhost:{{dashboard_port}}/api/qa/session \
312
316
 
313
317
  ### PRD-driven QA — "qa this PRD" → POST /api/qa/from-prd
314
318
 
315
- When the user points QA at a **completed/approved PRD** rather than describing the flow themselves — "QA this PRD", "qa `minions-opg-2026-06-16-3`", "qa the PRD-driven QA PRD", "smoke test the checkout PRD" — route it through `POST /api/qa/from-prd` instead of building a `flowsRaw` by hand. This is a thin bridge over QA Sessions: `engine/qa-from-prd.js` reads the PRD JSON (and its `prd/guides/verify-*.md` when present), derives the QA `target` and the natural-language flows from the PRD's items / acceptance criteria, then reuses the exact same `createSession` + `queueSetup` orchestration as `/api/qa/session`. You don't assemble the spec — name the PRD and the endpoint does the rest.
319
+ When the user points QA at a **completed/approved PRD** rather than describing the flow themselves — "QA this PRD", "qa `minions-opg-2026-06-16-3`", "qa the PRD-driven QA PRD", "smoke test the checkout PRD" — route it through `POST /api/qa/from-prd` instead of building a `flowsRaw` by hand. This is a thin bridge over QA Sessions: `engine/qa/from-prd.js` reads the PRD JSON (and its `prd/guides/verify-*.md` when present), derives the QA `target` and the natural-language flows from the PRD's items / acceptance criteria, then reuses the exact same `createSession` + `queueSetup` orchestration as `/api/qa/session`. You don't assemble the spec — name the PRD and the endpoint does the rest.
316
320
 
317
321
  **Body shape:** `{ prd, mode?, runner? }`
318
322
 
@@ -340,8 +344,8 @@ The `X-CC-Turn-Id` header is the audit trail — the handler stamps it onto the
340
344
  - **`fix` vs `implement` — pick deliberately.** `type: "fix"` in the engine means "this work item responds to comments or build failures on a tracked PR" — it requires a PR pointer (in `references[*].url`, `meta.pr_followup.parent_pr_url`, or `targetPr`/`pr_id`/`prNumber`) and is dispatched onto the PR's source branch. **Fresh bugfix work** that will open a NEW PR (engine bugs, default-branch CI failures, repo-level regressions found from logs) is `type: "implement"`, not `type: "fix"`. Emitting `type: "fix"` without a PR pointer trips the `pr_not_found` discovery gate (engine.js#discoverWork) and the WI stays blocked indefinitely. Rule of thumb: if the work could land on master via a brand-new PR, it's `implement`; if it must push commits into an existing PR's source branch, it's `fix`.
341
345
  - Exempt from the `project` requirement (these run rootless or via central paths): `ask`, `explore`, `plan`, `plan-to-prd`, `meeting`. (`docs` is intentionally NOT exempt — it's write-capable and lands in `WORKTREE_REQUIRING_TYPES`, so it needs a real project worktree. For minions-repo docs work, pass `project: "minions"` explicitly.) `setup` is also in the project-required set — it operates inside a real project worktree but produces no PR. Every other type needs a project worktree, so the server rejects project-less creates with `400 { error, knownProjects }` when ≠1 project is configured.
342
346
  - **`meta.keep_processes: true`** — opt-in flag that lets the agent leave specific descendant PIDs running after it exits (default: engine reaps EVERYTHING the agent spawned). **Set this whenever the user's intent is to leave a process alive after the agent finishes** — e.g. "spin up the dev server and exit", "start the watcher and leave it running", "set up my dev env", "keep the emulator open", "launch the daemon for me", "boot the constellation host and disconnect". Don't set it for normal build/test/run-once tasks (`npm test`, `npm run build`, one-shot scripts) — those should be reaped. Also accepts optional `meta.keep_processes_ttl_minutes` (default 60, hard-cap 1440 = 24h). When you set this flag, also make the WI title/description say something like "leave the dev server running" so the agent knows to write `agents/<id>/keep-pids.json` before exiting (the playbook injects the contract automatically when the flag is on). Example: `-d '{"title":"Spin up Constellation dev env and leave server running","type":"implement","project":"constellation","description":"Run bun install + bun run dev. Leave the dev server (port 5173) and Constellation host (port 3001) running after you exit so the user can iterate.","meta":{"keep_processes":true,"keep_processes_ttl_minutes":240}}'`. Inspect / kill kept PIDs anytime via `GET /api/keep-processes` and `POST /api/keep-processes/kill`.
343
- - **`skipPr: true`** — opt-in flag that tells the engine NOT to enforce the PR-attachment contract for this work item, so the WI can complete `done` without the missing-PR hard-fail. **Set this when the dispatch mutates state OUTSIDE any tracked git repo and therefore cannot produce a PR** e.g. cleaning `~/.claude/skills/`, editing runtime config under `~/.config/`, resetting the dashboard cache, mutating engine JSON state files (`engine/*.json`) the engine itself owns, or local tooling installs. **Do NOT set it for any task that touches a tracked repo's source** even one-line diffs in a real repo should produce a PR. Type-selection rule of thumb: prefer `type: "setup"` for infra/dev-env bootstrap tasks that mutate project state but produce no PR (it's implicitly PR-exempt — no `skipPr` needed); prefer `type: "explore"` for genuinely read-only tasks (rootless, no worktree, no PR contract); use `skipPr: true` only when the task is write-side mutation but the writes don't land in a git repo and `setup` doesn't fit (e.g. cleaning user-machine state outside any repo). Example: `-d '{"title":"Bootstrap Constellation dev stack","type":"setup","project":"constellation","description":"Run bun install + bun run dev and leave the dev server running.","meta":{"managed_spawn":true}}'`.
344
- - **`oneShot: true`** — opt-in flag for one-off human-initiated dispatches that should NOT enroll the discovered PR into the engine's automatic review/fix loop. The PR is still tracked (status + comments are polled normally) but `discoverFromPrs` skips it for review/fix dispatch. **Set this when the user's intent is "do this single action against an existing PR, then stop"** — e.g. "review PR #2533 once", "rebase PR #2540 once and exit", "post a fix-summary comment on PR #2519". Don't set it for normal feature/fix work where the PR should keep cycling through review/fix until merged. Example: `-d '{"title":"One-off review of PR #2533","type":"review","project":"minions","description":"Single review pass on github:yemi33/minions#2533. Do not re-dispatch on subsequent comments.","oneShot":true}'`.
347
+ - **`skipPr: true`** — opt-in flag that tells the engine NOT to enforce the PR-attachment contract for work that cannot produce a PR because it mutates state outside a tracked repository. This flag changes completion accounting only; it does **not** authorize filesystem cleanup or machine-level changes. Any such mutation still requires an explicit, path-specific user request, must preserve unrelated state, and must avoid broad deletion. **Do NOT set it for any task that touches tracked source.** Prefer `type: "setup"` for project bootstrap tasks and `type: "explore"` for read-only work.
348
+ - **`oneShot: true`** — opt-in flag for one-off human-initiated dispatches that should NOT enroll the discovered PR into the engine's automatic review/fix loop. The PR is still tracked (status + comments are polled normally) but `discoverFromPrs` skips it for review/fix dispatch. **Set this when the user's intent is "do this single action against an existing PR, then stop"** — e.g. "review PR #42 once", "rebase PR #43 once and exit", "post a fix-summary comment on PR #44". Don't set it for normal feature/fix work where the PR should keep cycling through review/fix until merged. Example: `-d '{"title":"One-off review of PR #42","type":"review","project":"MyApp","description":"Single review pass on github:owner/MyApp#42. Do not re-dispatch on subsequent comments.","oneShot":true}'`.
345
349
  - `POST /api/notes`: `title`, `what` REQUIRED.
346
350
  - `POST /api/knowledge`: `category`, `title`, `content` REQUIRED. Categories: `architecture`, `conventions`, `project-notes`, `build-reports`, `reviews`.
347
351
  - `POST /api/plan`: `title` REQUIRED. `description`, `priority`, `project`, `agent`, `branchStrategy` optional.
@@ -375,25 +379,13 @@ The server validates: `liveValidation` requires `checkoutMode:"live"`, canonical
375
379
 
376
380
  ## GitHub auth
377
381
 
378
- We have multiple authed `gh` accounts (`yemi33`, `yemishin_microsoft`) covering three repo scopes (`yemi33/minions`, `yemishin_microsoft/minions`, `opg-microsoft/minions`).
379
-
380
382
  **Never run `gh auth switch`.** It flips the global active account and races with the engine's GH poller — past `gh auth switch` calls left the engine polling the wrong account for hours, with PRs stuck in `abandoned` until reconciliation un-flipped them.
381
383
 
382
- To call `gh` against a specific account, build `GH_TOKEN` per command:
383
-
384
- ```bash
385
- GH_TOKEN=$(gh auth token --user <account> --hostname github.com) gh <subcommand> ...
386
- ```
387
-
388
- Account map (mirrors `engine.ghAccounts` in `config.json`):
389
-
390
- | Owner | gh account |
391
- |-------|------------|
392
- | `opg-microsoft` | `yemishin_microsoft` |
393
- | `yemishin_microsoft` | `yemishin_microsoft` |
394
- | `yemi33` | `yemi33` |
395
-
396
- The engine resolves these automatically via `engine/gh-token.js` for its own polling and issue creation; only CC and agents need to be careful in shell commands. If you're unsure which account a slug needs, the table above is the source of truth.
384
+ For shell operations, enumerate configured `gh` accounts and select one by
385
+ probing the exact target slug with a per-command `GH_TOKEN`. Verify repository
386
+ identity and required permissions before any write. Fail closed when no account
387
+ has access; never hardcode an operator login or rely on the globally active
388
+ account. Engine-owned calls resolve this mapping through `engine/gh-token.js`.
397
389
 
398
390
  ## Document edits
399
391
 
@@ -0,0 +1,92 @@
1
+ # Watch Plugins
2
+
3
+ This directory contains JavaScript extensions that add target types to Minions
4
+ watches. A watch is a SQLite record that combines a target type, target,
5
+ condition, interval, and optional action. Plugins define how a new kind of
6
+ target is fetched, snapshotted, evaluated, and exposed to action templates.
7
+
8
+ ## Loading and trust
9
+
10
+ At engine startup, `engine/watches/index.js` loads every top-level `*.js` file in
11
+ `<MINIONS_DIR>/watch-plugins/`. Changes require an engine restart.
12
+
13
+ Plugins are trusted, unsandboxed Node.js code running inside the engine process.
14
+ They can access the filesystem, environment, network, and engine modules.
15
+ Install only reviewed plugins. A plugin failure is logged and skipped so it
16
+ does not prevent the engine from starting. Plugins cannot replace built-in or
17
+ previously registered target types.
18
+
19
+ The former directory name was `watches.d/`. Legacy custom plugins remain loaded
20
+ with a deprecation warning so upgrades do not disable existing watches. Move
21
+ them into `watch-plugins/`; new plugins belong only here.
22
+
23
+ ## Contract
24
+
25
+ A plugin exports one `{ name, spec }` object or an array of them:
26
+
27
+ ```js
28
+ module.exports = {
29
+ name: 'example-target',
30
+ spec: {
31
+ label: 'Example Target',
32
+ description: 'What this target watches',
33
+ conditions: ['status-change'],
34
+ absoluteConditions: [],
35
+ validateTarget(target, context) {
36
+ return null; // return an error string when invalid
37
+ },
38
+ fetchEntity(target, state) {
39
+ return null;
40
+ },
41
+ captureState(entity, previousState) {
42
+ return {};
43
+ },
44
+ evaluate(condition, entity, previousState, target) {
45
+ return { triggered: false, message: '' };
46
+ },
47
+ contextVars(entity, previousState, newState) {
48
+ return {};
49
+ },
50
+ },
51
+ };
52
+ ```
53
+
54
+ Required fields are `label`, non-empty `conditions`, `fetchEntity`,
55
+ `captureState`, and `evaluate`. `description`, `absoluteConditions`,
56
+ `validateTarget`, `isTerminalForCondition`, and `contextVars` are optional.
57
+
58
+ The engine's watch evaluation path is synchronous. A plugin that performs
59
+ network I/O should refresh a bounded module-level cache in the background and
60
+ return the latest cached entity from `fetchEntity`. Never perform network calls
61
+ while a Minions state lock is held.
62
+
63
+ ## Bundled plugins
64
+
65
+ | Plugin | Target type | Purpose |
66
+ |---|---|---|
67
+ | `http.js` | `http` | Poll an HTTP endpoint and compare status or extracted values |
68
+ | `gh-author-prs.js` | `gh-author-prs` | Detect new non-draft GitHub PRs by author |
69
+ | `ado-author-prs.js` | `ado-author-prs` | Detect new non-draft Azure DevOps PRs by configured author |
70
+ | `teams-channel.js` | `teams-channel` | Detect new Microsoft Teams channel messages and replies |
71
+
72
+ Repository/account/channel identities belong in the watch target or Minions
73
+ configuration, never as plugin defaults. GitHub authentication resolves through
74
+ `config.engine.ghAccounts`; Azure DevOps plugins use the shared ADO token path.
75
+ Secrets must come from environment variables or engine token helpers and must
76
+ never be persisted in watch records or logs.
77
+
78
+ ## Creating a watch
79
+
80
+ Use Dashboard **Watches**, the CLI, or the API. Discover the active runtime
81
+ surface first:
82
+
83
+ ```bash
84
+ minions watch target-types
85
+ minions watch action-types
86
+ ```
87
+
88
+ The dashboard API exposes the same registries at
89
+ `GET /api/watches/target-types` and `GET /api/watches/action-types`.
90
+
91
+ Full lifecycle, condition, and action documentation:
92
+ [docs/watches.md](../docs/watches.md).