@yemi33/minions 0.1.2448 → 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 +58 -4
  7. package/dashboard/js/detail-panel.js +36 -0
  8. package/dashboard/js/memory-panel.js +59 -12
  9. package/dashboard/js/qa.js +179 -20
  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 +13 -2
  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/docs/watches.md CHANGED
@@ -20,41 +20,41 @@ A watch is a record persisted in `engine/state.db`. It binds:
20
20
  | `requires` | Optional guard: array of predicate objects evaluated against `state` / `entity` / `prevState`; trigger is suppressed when any guard fails (false-or-error). Used to gate a watch on "PR is mergeable AND build passing" etc. |
21
21
  | `status` | `WATCH_STATUS.ACTIVE` \| `PAUSED` \| `TRIGGERED` \| `EXPIRED` |
22
22
 
23
- `createWatch()` allocates a `watch-<uid>` id, defaults the fields above, and persists through the watch store *(source: `engine/watches.js` and `engine/watches-store.js`)*.
23
+ `createWatch()` allocates a `watch-<uid>` id, defaults the fields above, and persists through the watch store *(source: `engine/watches/index.js` and `engine/watches/store.js`)*.
24
24
 
25
25
  ## Lifecycle (`WATCH_STATUS`)
26
26
 
27
- Defined in `engine/shared.js` (`WATCH_STATUS`):
27
+ Defined in `engine/core/shared.js` (`WATCH_STATUS`):
28
28
 
29
29
  | Status | Meaning |
30
30
  |-------------|-------------------------------------------------------------------------|
31
31
  | `active` | Eligible for evaluation each tick |
32
32
  | `paused` | Skipped by `checkWatches`; persists indefinitely until resumed/deleted |
33
33
  | `triggered` | Reserved status (set on demand by callers; not auto-applied) |
34
- | `expired` | Auto-set when `stopAfter` is reached, or on first trigger for absolute conditions when `stopAfter === 0`. The watch is left on disk for audit but no longer evaluated *(source: `engine/watches.js:499-513`)* |
34
+ | `expired` | Auto-set when `stopAfter` is reached, or on first trigger for absolute conditions when `stopAfter === 0`. The watch is retained for audit but no longer evaluated *(source: `engine/watches/index.js`)* |
35
35
 
36
- Pause/resume flips the `status` field via `POST /api/watches/update` *(source: `engine/watches.js` `updateWatch`, `dashboard.js` `handleWatchesUpdate`)*.
36
+ Pause/resume flips the `status` field via `POST /api/watches/update` *(source: `engine/watches/index.js` `updateWatch`, `dashboard.js` `handleWatchesUpdate`)*.
37
37
 
38
38
  ## Conditions (`WATCH_CONDITION`)
39
39
 
40
- Defined in `engine/shared.js` (`WATCH_CONDITION`). Conditions split into two families:
40
+ Defined in `engine/core/shared.js` (`WATCH_CONDITION`). Conditions split into two families:
41
41
 
42
42
  ### Absolute conditions (`WATCH_ABSOLUTE_CONDITIONS`)
43
- *(source: `engine/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*
43
+ *(source: `engine/core/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*
44
44
 
45
45
  `merged`, `build-fail`, `build-pass`, `completed`, `failed`, `concluded`, `approved`, `rejected`, `ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`.
46
46
 
47
- When `stopAfter === 0`, these are **fire-once** — the engine flips the watch to `expired` after the first trigger so a permanently-merged PR (or a permanently-true compound state assertion like `ready-for-merge`) doesn't keep notifying *(source: `engine/watches.js:499-513`)*.
47
+ When `stopAfter === 0`, these are **fire-once** — the engine flips the watch to `expired` after the first trigger so a permanently-merged PR (or a permanently-true compound state assertion like `ready-for-merge`) doesn't keep notifying *(source: `engine/watches/index.js`)*.
48
48
 
49
49
  > **Per-target override (W-mp7hg58e000b5212):** the global `WATCH_ABSOLUTE_CONDITIONS` set is the legacy fallback. Each target type now declares its own `absoluteConditions: [...]` array in its spec; `registerTargetType` normalizes that into a `Set` that takes precedence at evaluation time. The plugin contract (see below) uses this to keep absolute-vs-change semantics local to each target type. Plugins that omit `absoluteConditions` get an empty set (all change-based).
50
50
 
51
51
  ### Change-based conditions
52
- `status-change`, `any`, `new-comments`, `vote-change`, `stage-complete`, `ran`, `enabled`, `disabled`, `activity-change`, plus the predicate conditions added under P-w4e2f6a1 / P-w5b8d2c9 for the `pr`, `work-item`, `plan`, and `pipeline` target types (`head-commit-change`, `mergeable-flipped`, `behind-master`, `draft-flipped`, `stalled`, `dependency-met`, `stage-advanced`, `stuck-in-stage`). See `engine/shared.js` `WATCH_CONDITION` for the canonical enum.
52
+ `status-change`, `any`, `new-comments`, `vote-change`, `stage-complete`, `ran`, `enabled`, `disabled`, `activity-change`, plus the predicate conditions added under P-w4e2f6a1 / P-w5b8d2c9 for the `pr`, `work-item`, `plan`, and `pipeline` target types (`head-commit-change`, `mergeable-flipped`, `behind-master`, `draft-flipped`, `stalled`, `dependency-met`, `stage-advanced`, `stuck-in-stage`). See `engine/core/shared.js` `WATCH_CONDITION` for the canonical enum.
53
53
 
54
- These compare the live entity against the watch's `_lastState` snapshot and run forever when `stopAfter === 0`. Baseline `_lastState` is captured on the first check so the very next change triggers the watch *(source: `engine/watches.js:436-440, 558-559`)*.
54
+ These compare the live entity against the watch's `_lastState` snapshot and run forever when `stopAfter === 0`. Baseline `_lastState` is captured on the first check so the very next change triggers the watch *(source: `engine/watches/index.js`)*.
55
55
 
56
56
  ### Tick-counted conditions
57
- `stalled`, `stuck-in-stage` — require N consecutive unchanged captures (default `WATCH_STALLED_DEFAULT_TICKS = 12`, `WATCH_STUCK_STAGE_DEFAULT_TICKS = 12`, both in `engine/shared.js`). Counters (`_unchangedTicks`, `_stuckStageTicks`) are recomputed inside `_captureState` by comparing the fresh snapshot against `prevState`.
57
+ `stalled`, `stuck-in-stage` — require N consecutive unchanged captures (default `WATCH_STALLED_DEFAULT_TICKS = 12`, `WATCH_STUCK_STAGE_DEFAULT_TICKS = 12`, both in `engine/core/shared.js`). Counters (`_unchangedTicks`, `_stuckStageTicks`) are recomputed inside `_captureState` by comparing the fresh snapshot against `prevState`.
58
58
 
59
59
  ### Predicate conditions
60
60
 
@@ -65,11 +65,11 @@ Several condition keys evaluate a derived predicate on the captured entity/state
65
65
  - **plan** — `all-items-done` (`items_done === items_total > 0`), `item-failed-n-times` (any `missing_features[*]._retryCount >= ENGINE_DEFAULTS.maxRetries`).
66
66
  - **pipeline** — `stage-advanced` (`current_stage_id` changed within the same `runId`), `stuck-in-stage` (current stage unchanged for `WATCH_STUCK_STAGE_DEFAULT_TICKS` checks, default 12).
67
67
 
68
- Compound state-assertion predicates (`ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`) live in `WATCH_ABSOLUTE_CONDITIONS` so they fire-once when `stopAfter === 0` — without that they would re-fire every tick while the assertion holds *(source: `engine/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*.
68
+ Compound state-assertion predicates (`ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`) live in `WATCH_ABSOLUTE_CONDITIONS` so they fire-once when `stopAfter === 0` — without that they would re-fire every tick while the assertion holds *(source: `engine/core/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*.
69
69
 
70
70
  ## Target Types — `TARGET_TYPES` Registry
71
71
 
72
- Target-type behavior in `engine/watches.js` is **data-driven via a registry** *(source: `engine/watches.js:122-174`)*. Each spec uses the following fields; entries are required unless marked optional:
72
+ Target-type behavior in `engine/watches/index.js` is **data-driven via a registry**. Each spec uses the following fields; entries are required unless marked optional:
73
73
 
74
74
  - `label` — human name shown in dashboard pickers
75
75
  - `description` — **(optional)** short help text; defaults to `''` in `listTargetTypes()`
@@ -78,22 +78,22 @@ Target-type behavior in `engine/watches.js` is **data-driven via a registry** *(
78
78
  - `fetchEntity(target, state)` — entity-or-null lookup; must return the fetched resource or null
79
79
  - `captureState(entity, prevState)` — snapshot object used for change-detection diffs; `prevState` parameter lets counters and custom fields carry across checks
80
80
  - `evaluate(condition, entity, prevState, target)` — returns `{ triggered: boolean, message: string }`; core condition-check logic
81
- - `isTerminalForCondition(condition, entity, prevState)` — *(optional)* W-mqa63opd000ha836. When a watch's `condition` cannot possibly fire again because the target reached a permanent terminal state (e.g. a PR was merged/closed/abandoned and the watch is on `build-fail`, `build-pass`, `vote-change`, `new-comments`, `head-commit-change`, `mergeable-flipped`, `behind-master`, `ready-for-merge`, or `draft-flipped`), return `true` and the engine auto-expires the watch. Default returns `false` so existing target types keep polling forever. The main check loop invokes this only when `triggerCount > 0` **or** the prev-state status already matched current entity — so a watch armed on an already-terminal PR with `condition: merged` still fires once via the absolute-condition fire-once path *(source: `engine/watches.js:150-158, 537-550`)*.
81
+ - `isTerminalForCondition(condition, entity, prevState)` — *(optional)* W-mqa63opd000ha836. When a watch's `condition` cannot possibly fire again because the target reached a permanent terminal state (e.g. a PR was merged/closed/abandoned and the watch is on `build-fail`, `build-pass`, `vote-change`, `new-comments`, `head-commit-change`, `mergeable-flipped`, `behind-master`, `ready-for-merge`, or `draft-flipped`), return `true` and the engine auto-expires the watch. Default returns `false` so existing target types keep polling forever. The main check loop invokes this only when `triggerCount > 0` **or** the prev-state status already matched current entity — so a watch armed on an already-terminal PR with `condition: merged` still fires once via the absolute-condition fire-once path *(source: `engine/watches/index.js`)*.
82
82
  - `contextVars(entity, prevState, newState)` — *(optional)* returns object with extra action-template variables contributed by the target type (e.g., `{ httpStatus: 200, prevExtracted: 'foo' }`)
83
83
 
84
- The registry IS the allowlist for `createWatch` and `/api/watches/target-types`; the old hardcoded "pr or work-item" check is gone. Add a new target type at runtime with `registerTargetType(type, spec)` and look one up with `getTargetType(type)`. `listTargetTypes()` returns the serializable form used by the dashboard *(source: `engine/watches.js:122-174`)*.
84
+ The registry IS the allowlist for `createWatch` and `/api/watches/target-types`; the old hardcoded "pr or work-item" check is gone. Add a new target type at runtime with `registerTargetType(type, spec)` and look one up with `getTargetType(type)`. `listTargetTypes()` returns the serializable form used by the dashboard.
85
85
 
86
- ### User-extensible via `watches.d/` (W-mp7hg58e000b5212)
86
+ ### User-extensible via `watch-plugins/`
87
87
 
88
- At engine boot, every `*.js` file in `<MINIONS_DIR>/watches.d/` is auto-loaded **after** the built-in registrations *(source: `engine/watches.js:1401-1436`)*, so plugins can both add new target types and override built-ins. A plugin file exports either `{ name, spec }` or an array of such objects. Failures are logged-and-skipped — one bad plugin must not break boot or block other plugins. Reloads require an engine restart.
88
+ At engine boot, every `*.js` file in `<MINIONS_DIR>/watch-plugins/` is auto-loaded **after** the built-in registrations. Plugins can add target types but cannot replace an existing type. A plugin file exports either `{ name, spec }` or an array of such objects. Failures are logged-and-skipped — one bad plugin must not break boot or block other plugins. Reloads require an engine restart.
89
89
 
90
- Canonical example: `watches.d/http.js` (W-mp7i22mu00191b07) — a generic HTTP poller covering the full plugin contract including `captureState` (custom snapshot fields) and `contextVars` (custom action-template vars like `{{httpStatus}}`, `{{prevExtracted}}`).
90
+ Canonical example: `watch-plugins/http.js` — a generic HTTP poller covering the full plugin contract including `captureState` and `contextVars`.
91
91
 
92
- This source checkout also includes `ado-author-prs`, `gh-author-prs`, and `teams-channel` plugins under `watches.d/`. They are dynamically loaded plugins, not members of the eight built-in target types; `GET /api/watches/target-types` is the authoritative list for the running installation.
92
+ This source checkout also includes `ado-author-prs`, `gh-author-prs`, and `teams-channel` plugins under `watch-plugins/`. They are dynamically loaded plugins, not members of the eight built-in target types; `GET /api/watches/target-types` is the authoritative list for the running installation.
93
93
 
94
94
  ### Built-in target types
95
95
 
96
- The eight built-ins are registered at module load *(source: `engine/watches.js` — the long `registerTargetType(...)` block)*. Constants live in `WATCH_TARGET_TYPE` in `engine/shared.js`.
96
+ The eight built-ins are registered at module load *(source: `engine/watches/index.js`)*. Constants live in `WATCH_TARGET_TYPE` in `engine/core/shared.js`.
97
97
 
98
98
  | `targetType` | Target value | Conditions | Notes |
99
99
  |---------------|--------------------------------------|----------------------------------------------------------------------------|-------|
@@ -106,13 +106,13 @@ The eight built-ins are registered at module load *(source: `engine/watches.js`
106
106
  | `dispatch` | Dispatch entry id | `completed`, `failed`, `status-change`, `any` | Looks across `pending` / `active` / `completed` lists |
107
107
  | `agent` | Agent id | `activity-change`, `status-change`, `any` | `activity-change` fires only on transitions in/out of `'working'` |
108
108
 
109
- `evaluateWatch` dispatches to `tt.evaluate(...)`; unknown target types return `"Unknown target type: ..."` and unknown conditions return `"Unknown condition: ..."` — both are non-triggering *(source: `engine/watches.js:320-365`)*.
109
+ `evaluateWatch` dispatches to `tt.evaluate(...)`; unknown target types return `"Unknown target type: ..."` and unknown conditions return `"Unknown condition: ..."` — both are non-triggering *(source: `engine/watches/index.js`)*.
110
110
 
111
- ### Plugin folder (`watches.d/`) — user-extensible target types
111
+ ### Plugin folder (`watch-plugins/`) — user-extensible target types
112
112
 
113
- W-mp7hg58e000b5212 added a **plugin folder** so operators can register new target types without editing engine source. At engine boot, `engine/watches.js` scans `<MINIONS_DIR>/watches.d/*.js` *after* the eight built-ins are registered (so plugins can override a built-in by re-using its key — last-write-wins) and calls `registerTargetType()` for each export *(source: `engine/watches.js:1401-1436`)*.
113
+ The plugin folder lets operators register new target types without editing engine source. At engine boot, `engine/watches/index.js` scans `<MINIONS_DIR>/watch-plugins/*.js` after the eight built-ins are registered and calls `registerTargetType()` for each unique export. Duplicate names are logged and skipped.
114
114
 
115
- Each `watches.d/<name>.js` file must export `{ name, spec }` (or an array of those):
115
+ Each `watch-plugins/<name>.js` file must export `{ name, spec }` (or an array of those):
116
116
 
117
117
  ```js
118
118
  module.exports = {
@@ -132,9 +132,9 @@ module.exports = {
132
132
  };
133
133
  ```
134
134
 
135
- Resolution is `path.join(shared.MINIONS_DIR, 'watches.d')` so it works in both dev checkouts and installed `~/.minions/` layouts. Missing folder is silent; per-file failures are isolated (load errors log a `WARN` line, don't abort boot). Tests can re-scan via the exported `_loadPluginTargetTypes()`.
135
+ Resolution is `path.join(shared.MINIONS_DIR, 'watch-plugins')` so it works in both dev checkouts and installed `~/.minions/` layouts. Missing folder is silent; per-file failures are isolated. Legacy custom plugins under `watches.d/` remain compatibility-loaded with a warning until operators move them. Tests can re-scan via the exported `_loadPluginTargetTypes()`. Plugins are unsandboxed trusted code; see [`watch-plugins/README.md`](../watch-plugins/README.md) before adding one.
136
136
 
137
- **Canonical plugin example:** [`watches.d/http.js`](../watches.d/http.js) (W-mp7i22mu00191b07) ships a generic `http` target type — point a watch at any URL or `{ url, method, headers, body, extract, expected, regex, timeoutMs }` config and the plugin exposes `status-change`, `value-change`, `value-equals`, `value-matches`, and `http-error` conditions. Auth headers support `{{env.GH_TOKEN}}`-style substitution at fetch time (secrets are never persisted in watch records). All conditions are change-based (`absoluteConditions: []`).
137
+ **Canonical plugin example:** [`watch-plugins/http.js`](../watch-plugins/http.js) ships a generic `http` target type — point a watch at any URL or `{ url, method, headers, body, extract, expected, regex, timeoutMs }` config and the plugin exposes `status-change`, `value-change`, `value-equals`, `value-matches`, and `http-error` conditions. Auth headers support `{{env.GH_TOKEN}}`-style substitution at fetch time. All conditions are change-based.
138
138
 
139
139
  ## Tick Integration
140
140
 
@@ -159,11 +159,11 @@ Resolution is `path.join(shared.MINIONS_DIR, 'watches.d')` so it works in both d
159
159
  6. On non-trigger: writes a per-poll inbox note when `onNotMet === 'notify'`.
160
160
  7. Refreshes `_lastState` for the next check.
161
161
 
162
- I/O happens **outside the lock**. Trigger actions, including the implicit inbox notification, run through `_runActionTask`. Only `onNotMet === 'notify'` polling notes use the direct notification queue and `writeToInbox`. Each action result is persisted back onto the watch as `_lastActionResult` in a follow-up locked write. An implicit notify makes the effective action array-shaped, so its result uses the `type: 'chain'` / `steps[]` shape; an explicit action without an implicit notify preserves the legacy single-action result shape *(source: `engine/watches.js:459-495,515-521,601-684`)*.
162
+ I/O happens **outside the lock**. Trigger actions, including the implicit inbox notification, run through `_runActionTask`. Only `onNotMet === 'notify'` polling notes use the direct notification queue and `writeToInbox`. Each action result is persisted back onto the watch as `_lastActionResult` in a follow-up locked write. An implicit notify makes the effective action array-shaped, so its result uses the `type: 'chain'` / `steps[]` shape; an explicit action without an implicit notify preserves the legacy single-action result shape *(source: `engine/watches/index.js`)*.
163
163
 
164
164
  ## Follow-Up Actions on Trigger
165
165
 
166
- `watch.action` is an optional structured action (or action chain). When the implicit inbox notification is enabled, configured actions follow it in the same effective chain. Action types live in a sibling registry in `engine/watch-actions.js` and are validated at create/update time *(source: `engine/watches.js:189-245` `createWatch`, `engine/watch-actions.js:95-105` `registerActionType`)*. `GET /api/watches/action-types` returns the live list for dashboard pickers.
166
+ `watch.action` is an optional structured action (or action chain). When the implicit inbox notification is enabled, configured actions follow it in the same effective chain. Action types live in `engine/watches/actions.js` and are validated at create/update time. `GET /api/watches/action-types` returns the live list for dashboard pickers.
167
167
 
168
168
  ### Built-in actions
169
169
 
@@ -180,11 +180,11 @@ I/O happens **outside the lock**. Trigger actions, including the implicit inbox
180
180
  | `resume-plan` | Set PRD `status=PLAN_STATUS.ACTIVE` and clear `planStale` |
181
181
  | `cc-triage` | Invoke Command Center headlessly via the loopback `POST /api/command-center/triage` endpoint with the trigger context (and optional completion-report / live-output artifacts). Wraps the prompt in `<UNTRUSTED-INPUT>`, uses a default 10-min timeout (capped at 1 h), and is isolated from the user CC session |
182
182
 
183
- Constants live in `WATCH_ACTION_TYPE` (`engine/shared.js`); handlers in `engine/watch-actions.js`.
183
+ Constants live in `WATCH_ACTION_TYPE` (`engine/core/shared.js`); handlers live in `engine/watches/actions.js`.
184
184
 
185
185
  ### Templating
186
186
 
187
- Action params support `{{var}}` substitution from the trigger context *(source: `engine/watch-actions.js:133-230`)*. Built-in vars from `buildTriggerContext`:
187
+ Action params support `{{var}}` substitution from the trigger context *(source: `engine/watches/actions.js`)*. Built-in vars from `buildTriggerContext`:
188
188
 
189
189
  - Always: `target`, `targetType`, `condition`, `watchId`, `triggerCount`, `message`
190
190
  - All scalar fields from `newState` (e.g. `status`, `buildStatus`, `reviewStatus`, `lastRun`)
@@ -194,7 +194,7 @@ Unknown vars are left as `{{var}}` so callers can detect them downstream.
194
194
 
195
195
  ### Failure isolation
196
196
 
197
- Action handlers must return `{ ok: false, summary }` rather than throw — `runWatchAction` wraps them in try/catch as a backstop *(source: `engine/watch-actions.js:262-293`)*. A bad action never blocks other watches in the same tick, and the failed result is persisted onto the watch as `_lastActionResult` for debugging. Multi-step action chains run via `runWatchActionChain` *(source: `engine/watch-actions.js:310-355`)* — each step's `{ok, summary, result}` is templated into the next step's params as `{{steps.N.result.<field>}}`.
197
+ Action handlers must return `{ ok: false, summary }` rather than throw — `runWatchAction` wraps them in try/catch as a backstop. A bad action never blocks other watches in the same tick, and the failed result is persisted onto the watch as `_lastActionResult` for debugging. Multi-step action chains run via `runWatchActionChain` in `engine/watches/actions.js`.
198
198
 
199
199
  ## Dashboard Surface
200
200
 
@@ -227,8 +227,8 @@ CC will discover the endpoints from `GET /api/routes` and `POST /api/watches` wi
227
227
  When a watch fires:
228
228
 
229
229
  - The SQL watch record gets `triggerCount++`, `last_triggered=<ISO>`, `_lastTriggerMessage=<message>`, and a refreshed `_lastState`.
230
- - When `notify === 'inbox'`, the engine prepends an implicit `{type: 'notify'}` action to the action chain (if present) or runs notify standalone, so the inbox alert participates in action-chain execution and `_lastActionResult` *(source: `engine/watches.js:459-496`)*. This is the **trigger-time notify**, paired with an optional explicit `action`.
231
- - When `onNotMet === 'notify'` (and the condition has NOT yet fired), the engine instead queues a direct poll notification outside the action chain — independent of any `action` field *(source: `engine/watches.js:515-521`)*. This is a separate **onNotMet-notify**, useful for "still watching, condition not met yet" progress updates.
230
+ - When `notify === 'inbox'`, the engine prepends an implicit `{type: 'notify'}` action to the action chain (if present) or runs notify standalone, so the inbox alert participates in action-chain execution and `_lastActionResult` *(source: `engine/watches/index.js`)*. This is the **trigger-time notify**, paired with an optional explicit `action`.
231
+ - When `onNotMet === 'notify'` (and the condition has NOT yet fired), the engine instead queues a direct poll notification outside the action chain — independent of any `action` field *(source: `engine/watches/index.js`)*. This is a separate **onNotMet-notify**, useful for "still watching, condition not met yet" progress updates.
232
232
  - If an action runs, `_lastActionResult` stores either the single-action shape (`{ type, ok, summary, dispatchedItemId, at }`) or the chain shape (`{ type: "chain", ok, summary, aborted, steps, at }`).
233
233
  - The SQL engine log gets `Watch triggered: <id> — <message>` and `Watch <id> action <type-or-chain[N]>: <summary>`.
234
234
 
@@ -241,21 +241,22 @@ Absolute conditions firing under `stopAfter === 0` flip `status` to `expired`; `
241
241
  | Watch never fires | Check `status === 'active'`; check `last_checked` advancing each cycle; confirm engine tick is running and `interval` isn't longer than your test window |
242
242
  | `evaluateWatch` returns `"<label> <target> not found"` | `fetchEntity` got nothing back — wrong `target` (e.g. PR display id vs canonical id), the target type isn't loaded, or the underlying file (PR cache, plan PRD) doesn't exist |
243
243
  | `"Unknown target type"` / `"Unknown condition"` | The registry doesn't recognise the value. Check `GET /api/watches/target-types` to see what's registered server-side; condition must be in that target type's `conditions[]` |
244
- | Change condition fires immediately on first tick | Won't happen — baseline `_lastState` is captured on the first check before `evaluate` runs *(source: `engine/watches.js`)*. If you see this, inspect the persisted watch through the API |
244
+ | Change condition fires immediately on first tick | Won't happen — baseline `_lastState` is captured on the first check before `evaluate` runs *(source: `engine/watches/index.js`)*. If you see this, inspect the persisted watch through the API |
245
245
  | Absolute watch fires forever instead of once | `stopAfter` is set to a non-zero value; only `stopAfter === 0` triggers fire-once expiration |
246
246
  | Action runs but inbox notification doesn't | `notify` field isn't `'inbox'`, or `owner` is empty. `notify` and `action` are independent — both can fire, or only one |
247
247
  | `_lastActionResult.ok === false` with `"unknown action type"` | The `action.type` isn't registered. List with `listActionTypes()` / `GET /api/watches/action-types` |
248
- | Webhook action returns `"only http/https allowed"` | URLs must use `http://` or `https://` schemes; other protocols are rejected by design *(source: `engine/watch-actions.js` `WEBHOOK` handler)* |
248
+ | Webhook action returns `"only http/https allowed"` | URLs must use `http://` or `https://` schemes; other protocols are rejected by design *(source: `engine/watches/actions.js` `WEBHOOK` handler)* |
249
249
  | Trigger fires but follow-up `dispatch-work-item` is missing | Check the engine log for `Watch <id> action <type>: <summary>`. Common reasons: missing `title`, a project-scope write failed, or the WI landed in the central scope because no project was specified |
250
- | Watch `_lastActionResult` shows `"timeout"` for webhook | Webhooks have a 10s safety timeout to keep the watches tick fast *(source: `engine/watch-actions.js:550-553`)* |
250
+ | Watch `_lastActionResult` shows `"timeout"` for webhook | Webhooks have a 10s safety timeout to keep the watches tick fast *(source: `engine/watches/actions.js`)* |
251
251
  | `checkWatches` block crashes silently | Wrapped in `safe('checkWatches', ...)` so one failure doesn't abort the tick. Inspect the engine log for `Watch check error (<id>)` lines. Regression #1088: the block must use `getProjects(config)`, never the long-removed `PROJECTS` constant |
252
252
 
253
253
  ## See Also
254
254
 
255
- - `engine/shared.js` — `WATCH_STATUS`, `WATCH_TARGET_TYPE`, `WATCH_CONDITION`, `WATCH_ABSOLUTE_CONDITIONS`, `WATCH_ACTION_TYPE` constants
256
- - `engine/watches.js` — registry, lifecycle, tick integration, `watches.d/` plugin loader
257
- - `engine/watch-actions.js` — action registry and built-in handlers (including `minions-api`)
258
- - `watches.d/http.js` — canonical user-extensible target type plugin
255
+ - `engine/core/shared.js` — `WATCH_STATUS`, `WATCH_TARGET_TYPE`, `WATCH_CONDITION`, `WATCH_ABSOLUTE_CONDITIONS`, `WATCH_ACTION_TYPE` constants
256
+ - `engine/watches/index.js` — registry, lifecycle, tick integration, `watch-plugins/` loader
257
+ - `engine/watches/actions.js` — action registry and built-in handlers
258
+ - `engine/watches/store.js` — SQL-backed watch persistence
259
+ - `watch-plugins/http.js` — canonical user-extensible target type plugin
259
260
  - `dashboard/pages/watches.html`, `dashboard/js/render-watches.js` — dashboard UI
260
261
  - `test/unit/watches-module.test.js`, `test/unit/watch-actions.test.js`, `test/unit/watches-plugin-loader.test.js` — module-level tests
261
262
  - [`auto-discovery.md`](auto-discovery.md) — overall tick cycle context
@@ -38,7 +38,7 @@ A manifest lives on each agent definition under `workspace_manifest`. All fields
38
38
  The defaults are deliberately permissive so the manifest can be rolled out incrementally:
39
39
 
40
40
  ```js
41
- // engine/shared.js
41
+ // engine/core/shared.js
42
42
  const WORKSPACE_MANIFEST_DEFAULTS = {
43
43
  allowed_tools: null, // no tool restriction
44
44
  allowed_repos: null, // no repo restriction
@@ -59,13 +59,13 @@ A config that never mentions `workspace_manifest` produces the exact same dispat
59
59
  | **URL fetch** | Advisory today | `allowed_external_urls` is validated at config load. No runtime helper function — a future runtime adapter hook can wire URL-fetch intercepts against the manifest. |
60
60
  | **Memory scope** | Advisory today | `memory_scope` field is stored in the manifest (`private` = agent only sees its own `knowledge/agents/<id>.md`; `shared` = full team knowledge (current default); `read-only-shared` = reads shared memory but should not write inbox/notes). No runtime enforcement helper — full enforcement at the consolidation layer is future work. |
61
61
 
62
- ## Helpers (in `engine/shared.js`)
62
+ ## Helpers (in `engine/core/shared.js`)
63
63
 
64
64
  ```js
65
65
  const { MEMORY_SCOPES, WORKSPACE_MANIFEST_DEFAULTS,
66
66
  validateWorkspaceManifest, resolveAgentManifest,
67
67
  agentCanUseRepo,
68
- mergeManifestAllowedTools, formatManifestRejection } = require('./engine/shared');
68
+ mergeManifestAllowedTools, formatManifestRejection } = require('./engine/core/shared');
69
69
  ```
70
70
 
71
71
  - `validateWorkspaceManifest(manifest)` → `{ ok, errors }`. `null`/`undefined` is valid (uses defaults).
@@ -95,7 +95,7 @@ Because rejections route through the standard `completeDispatch(... ERROR ...)`
95
95
 
96
96
  ## Related
97
97
 
98
- - `engine/shared.js` — manifest helpers and `FAILURE_CLASS`.
98
+ - `engine/core/shared.js` — manifest helpers and `FAILURE_CLASS`.
99
99
  - `engine.js spawnAgent()` — dispatch-time enforcement.
100
100
  - `test/unit/workspace-manifest.test.js` — full validator + gate + integration tests.
101
101
  - [`completion-reports.md`](completion-reports.md) — how the dispatch failure surfaces in the standard completion contract.