@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
@@ -35,10 +35,10 @@ This section is the factual baseline the design must respect. Citations are `fil
35
35
 
36
36
  ### 2.1 Agent object — already id-keyed
37
37
 
38
- Agents live under `config.agents` keyed by a **stable lowercase id** (the object key). `name` is a **separate display field** — there is no explicit `id` field inside the object; the key *is* the id, and `getAgents()` materializes it as `{ id, ...info }` (`engine/queries.js:764-845`). Defaults are hard-coded:
38
+ Agents live under `config.agents` keyed by a **stable lowercase id** (the object key). `name` is a **separate display field** — there is no explicit `id` field inside the object; the key *is* the id, and `getAgents()` materializes it as `{ id, ...info }` (`engine/core/queries.js:764-845`). Defaults are hard-coded:
39
39
 
40
40
  ```js
41
- // engine/shared.js:4728-4734
41
+ // engine/core/shared.js:4728-4734
42
42
  const DEFAULT_AGENTS = {
43
43
  ripley: { name: 'Ripley', emoji: '🏗️', role: 'Lead / Explorer', expertise: ['architecture', 'codebase-exploration', 'design-review'] },
44
44
  dallas: { name: 'Dallas', emoji: '🔧', role: 'Engineer', expertise: ['implementation', 'typescript', 'docker', 'testing'] },
@@ -48,9 +48,9 @@ const DEFAULT_AGENTS = {
48
48
  };
49
49
  ```
50
50
 
51
- Crucially, **nothing derives the id from the name** — `id === lowercase(name)` is coincidental, not enforced. Routing only lowercases routing-table cells, not names (`engine/routing.js:31-52`); agent lookup is by key with case-insensitive normalization against existing keys (`engine/routing.js:160-189`). So `name !== lowercase(id)` is already safe. This is the foundation that makes **rename = change `name`, keep `id`** trivial (see §2.8; full treatment in [`agent-rename.md`](agent-rename.md)).
51
+ Crucially, **nothing derives the id from the name** — `id === lowercase(name)` is coincidental, not enforced. Routing only lowercases routing-table cells, not names (`engine/orchestration/routing.js:31-52`); agent lookup is by key with case-insensitive normalization against existing keys (`engine/orchestration/routing.js:160-189`). So `name !== lowercase(id)` is already safe. This is the foundation that makes **rename = change `name`, keep `id`** trivial (see §2.8; full treatment in [`agent-rename.md`](agent-rename.md)).
52
52
 
53
- Runtime / budget fields are **optional per-agent overrides** resolved against `engine.*` fleet defaults via helpers in `engine/shared.js`:
53
+ Runtime / budget fields are **optional per-agent overrides** resolved against `engine.*` fleet defaults via helpers in `engine/core/shared.js`:
54
54
 
55
55
  | Field | Resolver | Falls back to |
56
56
  |-------|----------|---------------|
@@ -68,15 +68,15 @@ Runtime / budget fields are **optional per-agent overrides** resolved against `e
68
68
  Two unrelated concepts previously shared the word "skill"; Phase 0b made `agent.expertise` canonical while retaining `agent.skills` as a compatibility alias:
69
69
 
70
70
  1. **`agent.expertise`** — a string array of descriptive expertise tags. It is *not* linked to any executable capability or on-disk skill file. Readers tolerate legacy configs with `agent.expertise ?? agent.skills`:
71
- - **Display:** the `Expertise: …` line in the system prompt (`engine/playbook.js:1094`).
72
- - **Soft routing:** `pickReReviewAgentHints()` (`engine/lifecycle.js:5311-5321`) prefers agents tagged `code-review` / `design-review`.
73
- 2. **Real `SKILL.md` files** — discovered from disk by `collectSkillFiles()` / `getSkills()` (`engine/queries.js:1363-1498`), scoped global/project/plugin. These are **not** bound to a specific agent or role; every agent sees the same discovered catalog, and expertise metadata has **no relationship** to them.
71
+ - **Display:** the `Expertise: …` line in the system prompt (`engine/agents/playbook.js:1094`).
72
+ - **Soft routing:** `pickReReviewAgentHints()` (`engine/orchestration/lifecycle.js:5311-5321`) prefers agents tagged `code-review` / `design-review`.
73
+ 2. **Real `SKILL.md` files** — discovered from disk by `collectSkillFiles()` / `getSkills()` (`engine/core/queries.js:1363-1498`), scoped global/project/plugin. These are **not** bound to a specific agent or role; every agent sees the same discovered catalog, and expertise metadata has **no relationship** to them.
74
74
 
75
75
  The canonical rename has shipped. The legacy alias remains only for compatible reads until the removal gate in `docs/deprecated.json` clears.
76
76
 
77
77
  ### 2.4 Charter = the real "agent definition"
78
78
 
79
- The substantive persona/instructions for an agent is `agents/<id>/charter.md`, served by `getAgentDetail()` (`engine/queries.js:847-850`) and read directly by `buildSystemPrompt()` before injection as `## Your Charter` (`engine/playbook.js:1084-1099`). The system prompt is:
79
+ The substantive persona/instructions for an agent is `agents/<id>/charter.md`, served by `getAgentDetail()` (`engine/core/queries.js:847-850`) and read directly by `buildSystemPrompt()` before injection as `## Your Charter` (`engine/agents/playbook.js:1084-1099`). The system prompt is:
80
80
 
81
81
  ```
82
82
  # You are {name} ({role})
@@ -86,7 +86,7 @@ Expertise: {expertise joined}
86
86
  ## Your Charter
87
87
  {charter.md contents}
88
88
  ```
89
- (`engine/playbook.js:1084-1099`)
89
+ (`engine/agents/playbook.js:1084-1099`)
90
90
 
91
91
  Charter is already editable today, but only from the **agent detail panel → Charter tab** (`dashboard/js/detail-panel.js:115-126`) via `POST /api/agents/charter` (`dashboard.js:13205-13211`). It is disconnected from the Settings → Agents table.
92
92
 
@@ -94,11 +94,11 @@ Charter is already editable today, but only from the **agent detail panel → Ch
94
94
 
95
95
  ### 2.5 Routing
96
96
 
97
- `routing.md` is a markdown table mapping work-type → preferred/fallback **agent id** (`routing.md:8-27`), parsed by `engine/routing.js:31-52`. `resolveAgent()` (`engine/routing.js:192`) resolves the route, honoring `_author_` / `_any_` tokens, idleness, budget, and the self-review ban. Routing is edited via `POST /api/settings/routing`, which overwrites `routing.md` wholesale (`dashboard.js:10799-10805`).
97
+ `routing.md` is a markdown table mapping work-type → preferred/fallback **agent id** (`routing.md:8-27`), parsed by `engine/orchestration/routing.js:31-52`. `resolveAgent()` (`engine/orchestration/routing.js:192`) resolves the route, honoring `_author_` / `_any_` tokens, idleness, budget, and the self-review ban. Routing is edited via `POST /api/settings/routing`, which overwrites `routing.md` wholesale (`dashboard.js:10799-10805`).
98
98
 
99
99
  ### 2.6 Config read / write surface
100
100
 
101
- - **Read:** `queries.getConfig()` (`engine/queries.js:181-225`); Settings read endpoint returns `{ engine, claude, agents, projects, routing }` (`dashboard.js:10362-10391`).
101
+ - **Read:** `queries.getConfig()` (`engine/core/queries.js:181-225`); Settings read endpoint returns `{ engine, claude, agents, projects, routing }` (`dashboard.js:10362-10391`).
102
102
  - **Write:** `POST /api/settings` edits `engine`, `claude`, **existing** `agents[id]` (role, expertise, cli, model, budget — `dashboard.js:11242-11262`; **note: `name` is NOT editable today**), and projects, then saves `config.json`. Legacy `skills` input is normalized to `expertise`; unknown ids are skipped.
103
103
  - **Reset:** restores `engine` defaults + `shared.DEFAULT_AGENTS` (`dashboard.js:11434-11440`).
104
104
  - **UI:** Settings → Runtime pane has an **edit-only** Agents table (Role, Expertise, CLI, Model, Budget). No add/remove/rename.
@@ -182,7 +182,7 @@ The **durable** persona resolves entirely from the role; the **variable** expert
182
182
 
183
183
  A single registry flag gates everything user-visible in this spec:
184
184
 
185
- - Register `agent-library` in the `FEATURES` registry (`engine/features.js`) as `{ description, default: false, addedIn, expires }`.
185
+ - Register `agent-library` in the `FEATURES` registry (`engine/core/features.js`) as `{ description, default: false, addedIn, expires }`.
186
186
  - **Engine** gates new behavior with `features.isFeatureOn('agent-library', config)`; **dashboard JS** gates new UI with `MinionsFeatures.isOn('agent-library')`.
187
187
  - Toggle via Settings → Experimental flags, `config.features['agent-library']: true`, or `MINIONS_FEATURE_AGENT_LIBRARY=1`. Resolution order: env → `config.features` → registry default (default OFF).
188
188
  - **What the flag gates:** the Library page/API (`/api/roles*`), agent rename UI, role/agent CRUD UI, and the role-tier resolution layer.
@@ -229,7 +229,7 @@ Why this matters:
229
229
  - **Rename touches only the per-agent identity** (`name`/`emoji`); neither expertise nor the role charter is affected (§5.4).
230
230
  - **Two agents of one role share the durable charter but differ in the variable expertise.** Dallas and Ralph both resolve the Engineer charter, yet Dallas carries `typescript/docker` and Ralph `bug-fixes/scaffolding` — the payoff of the durable/variable split (§3).
231
231
 
232
- This formalizes what `buildSystemPrompt` already does loosely today (the `# You are {name}` / `Agent ID` / `Expertise` lines are a proto short-form; `engine/playbook.js:1092-1099`); the spec elevates it to named dimensions. Whether the short-form is rendered as prose lines or an explicit JSON card is an open question (§9).
232
+ This formalizes what `buildSystemPrompt` already does loosely today (the `# You are {name}` / `Agent ID` / `Expertise` lines are a proto short-form; `engine/agents/playbook.js:1092-1099`); the spec elevates it to named dimensions. Whether the short-form is rendered as prose lines or an explicit JSON card is an open question (§9).
233
233
 
234
234
  ## 4. Phase 0 — Prerequisite migrations
235
235
 
@@ -251,7 +251,7 @@ The stable-id invariant (id = immutable key, name = display-only) and its guard
251
251
 
252
252
  - **Read shim (always on):** everywhere that reads agent expertise resolves `agent.expertise ?? agent.skills`. Old configs with `skills` keep working untouched — no disk rewrite forced. (Expertise is the per-agent **variable** layer, §3.3 — it lives on the agent, not the role.)
253
253
  - **Writers / defaults:** `DEFAULT_AGENTS` use `expertise`. The Settings write path accepts legacy `skills`, persists the value as `expertise`, and deletes the old key.
254
- - **Readers:** the `Expertise:` line (`engine/playbook.js:1094`), `pickReReviewAgentHints` (`engine/lifecycle.js:5311-5321`), and `getAgents` (`engine/queries.js:830-832`) all prefer `expertise` and tolerate `skills`.
254
+ - **Readers:** the `Expertise:` line (`engine/agents/playbook.js:1094`), `pickReReviewAgentHints` (`engine/orchestration/lifecycle.js:5311-5321`), and `getAgents` (`engine/core/queries.js:830-832`) all prefer `expertise` and tolerate `skills`.
255
255
  - **Dashboard:** the Agents table uses `expertise` (`dashboard/js/settings.js:73`); settings writes normalize legacy `skills` input to `expertise` (`dashboard.js:11245-11252`).
256
256
  - **Deprecation:** `docs/deprecated.json` tracks the compatibility alias and its removal gate.
257
257
 
@@ -278,7 +278,7 @@ All UI/API in this phase is gated by `agent-library` (§3.1). The **rename** cap
278
278
 
279
279
  ### 5.2 Data model (Phase 1)
280
280
 
281
- - Add `DEFAULT_ROLES` to `engine/shared.js`, one per distinct `role` label in `DEFAULT_AGENTS` (`Lead / Explorer`, `Engineer`, `Analyst`, `Architect`). Author each role's **durable `charter`** name-agnostic (§4.3c), seeded from the sanitized union of the corresponding agents' existing `charter.md` files. Each agent keeps its current per-agent **`expertise`** (the variable layer), so two Engineers retain distinct specializations while sharing one role charter. (Where two agents of the same label have materially different *personas* today, split them into two roles instead — but the default four collapse cleanly.)
281
+ - Add `DEFAULT_ROLES` to `engine/core/shared.js`, one per distinct `role` label in `DEFAULT_AGENTS` (`Lead / Explorer`, `Engineer`, `Analyst`, `Architect`). Author each role's **durable `charter`** name-agnostic (§4.3c), seeded from the sanitized union of the corresponding agents' existing `charter.md` files. Each agent keeps its current per-agent **`expertise`** (the variable layer), so two Engineers retain distinct specializations while sharing one role charter. (Where two agents of the same label have materially different *personas* today, split them into two roles instead — but the default four collapse cleanly.)
282
282
  - Migrate `agent.role` free-text → role key on first load (in-memory, mirroring `applyLegacyCcModelMigration`'s no-disk-rewrite pattern) by slugifying the label and matching against `roles{}`. Unmatched strings remain legacy free text rendered as an ad-hoc role.
283
283
  - Resolution rules (§3) sit behind the existing resolver helpers and the feature flag so engine behavior is unchanged when `roles` is absent or the flag is OFF.
284
284
 
@@ -343,7 +343,7 @@ Flag-gated like Phase 1.
343
343
  ### 7.2 Data model / engine
344
344
 
345
345
  - New agent ids validated: lowercase slug, unique, not colliding with `temp-*` reserved prefix, and **immutable thereafter** (§2.8).
346
- - `resolveAgent` already iterates `config.agents` generically, so new agents are picked up with no engine change (`engine/routing.js:192-249`). Deleting an agent must also cancel/skip pending dispatches targeting it and leave its history intact (mirror the conservative posture of project removal in `engine/projects.js`).
346
+ - `resolveAgent` already iterates `config.agents` generically, so new agents are picked up with no engine change (`engine/orchestration/routing.js:192-249`). Deleting an agent must also cancel/skip pending dispatches targeting it and leave its history intact (mirror the conservative posture of project removal in `engine/planning/projects.js`).
347
347
  - A new agent with no `charter.md` inherits its role's **durable charter** automatically — the payoff of §3 — and carries its own **variable expertise**.
348
348
 
349
349
  ### 7.3 API (Phase 2)
@@ -394,11 +394,11 @@ Flag-gated like Phase 1.
394
394
  - Stable-id formalization, name-agnostic charters, and the `POST /api/agents/rename` capability ship there (its `AR-a…AR-f` breakdown). This Library's Phase 1 depends on it.
395
395
 
396
396
  **Phase 0 — prerequisites (owned here)**
397
- - P0-a: Register `agent-library` feature flag (`engine/features.js`) + Settings toggle.
397
+ - P0-a: Register `agent-library` feature flag (`engine/core/features.js`) + Settings toggle.
398
398
  - P0-b: **Shipped** — `skills`→`expertise` with an unconditional back-compat alias across playbook, lifecycle, queries, Settings, defaults, and `docs/deprecated.json`.
399
399
 
400
400
  **Phase 1 — expose & edit**
401
- - P1-a: `DEFAULT_ROLES` (durable charter per role) + per-agent `expertise` (variable) + in-memory legacy role migration + role-tier resolver (engine/shared.js, playbook.js), flag-gated. Seeds role charters from the prerequisite's sanitized `agents/<id>/charter.md`.
401
+ - P1-a: `DEFAULT_ROLES` (durable charter per role) + per-agent `expertise` (variable) + in-memory legacy role migration + role-tier resolver (engine/core/shared.js, playbook.js), flag-gated. Seeds role charters from the prerequisite's sanitized `agents/<id>/charter.md`.
402
402
  - P1-b: `GET /api/roles`, `POST /api/roles/update` (charter/label/runtime), agent `expertise`/`role` on `POST /api/settings` (dashboard.js). (Rename endpoint comes from the prerequisite.)
403
403
  - P1-c: Library UI (role list + role-charter editor + nested agents with per-agent expertise chips + role reassignment + inline rename surfacing the prerequisite's endpoint) reusing the charter editor pattern, flag-gated.
404
404
  - P1-d: Tests (resolver, durable/variable split, source-inspection) + `docs/deprecated.json` updates + settings-parity note in CLAUDE.md.
@@ -25,10 +25,10 @@ Citations are `file:line` against the repo at spec-authoring time.
25
25
 
26
26
  ### 2.1 Agents are already id-keyed
27
27
 
28
- Agents live under `config.agents` keyed by a **stable lowercase id** (the object key). `name` is a **separate display field** — there is no explicit `id` field inside the object; the key *is* the id, and `getAgents()` materializes it as `{ id, ...info }` (`engine/queries.js:764`).
28
+ Agents live under `config.agents` keyed by a **stable lowercase id** (the object key). `name` is a **separate display field** — there is no explicit `id` field inside the object; the key *is* the id, and `getAgents()` materializes it as `{ id, ...info }` (`engine/core/queries.js:764`).
29
29
 
30
30
  ```js
31
- // engine/shared.js:4728-4734
31
+ // engine/core/shared.js:4728-4734
32
32
  const DEFAULT_AGENTS = {
33
33
  ripley: { name: 'Ripley', emoji: '🏗️', role: 'Lead / Explorer', expertise: [...] },
34
34
  dallas: { name: 'Dallas', emoji: '🔧', role: 'Engineer', expertise: [...] },
@@ -36,32 +36,32 @@ const DEFAULT_AGENTS = {
36
36
  };
37
37
  ```
38
38
 
39
- Crucially, **nothing derives the id from the name** — `id === lowercase(name)` is coincidental, not enforced. Routing only lowercases routing-table cells, not names (`engine/routing.js:31-52`); agent lookup is by key with case-insensitive normalization against existing keys (`engine/routing.js:160-189`). So `name !== lowercase(id)` is already safe — the foundation that makes **rename = change `name`, keep `id`** trivial.
39
+ Crucially, **nothing derives the id from the name** — `id === lowercase(name)` is coincidental, not enforced. Routing only lowercases routing-table cells, not names (`engine/orchestration/routing.js:31-52`); agent lookup is by key with case-insensitive normalization against existing keys (`engine/orchestration/routing.js:160-189`). So `name !== lowercase(id)` is already safe — the foundation that makes **rename = change `name`, keep `id`** trivial.
40
40
 
41
41
  ### 2.2 Every agent-scoped state is keyed by id
42
42
 
43
43
  | State | Keyed by id at |
44
44
  |-------|----------------|
45
- | Charter file | `agents/<id>/charter.md` (`engine/queries.js:847-850`) |
46
- | Per-agent memory | `knowledge/agents/<id>.md`; inbox routes by `agent:` frontmatter → filename prefix (`engine/consolidation.js:106-129,159-182`) |
47
- | Metrics / spend / error rate | `metrics[id]`, `perAgent[id]` (`engine/routing.js:66-92`) |
48
- | Dispatch records | `dispatch.active[].agent` (`engine/queries.js:587-605`) |
49
- | PR records | `pr.agent` (`engine/queries.js:431-446`) |
50
- | Inbox files | `notes/inbox/<id>-…` filename prefix (`engine/queries.js:700-713`) |
51
- | Routing | preferred/fallback agent ids (`routing.md`, `engine/routing.js:31-52`) |
45
+ | Charter file | `agents/<id>/charter.md` (`engine/core/queries.js:847-850`) |
46
+ | Per-agent memory | `knowledge/agents/<id>.md`; inbox routes by `agent:` frontmatter → filename prefix (`engine/memory/consolidation.js:106-129,159-182`) |
47
+ | Metrics / spend / error rate | `metrics[id]`, `perAgent[id]` (`engine/orchestration/routing.js:66-92`) |
48
+ | Dispatch records | `dispatch.active[].agent` (`engine/core/queries.js:587-605`) |
49
+ | PR records | `pr.agent` (`engine/core/queries.js:431-446`) |
50
+ | Inbox files | `notes/inbox/<id>-…` filename prefix (`engine/core/queries.js:700-713`) |
51
+ | Routing | preferred/fallback agent ids (`routing.md`, `engine/orchestration/routing.js:31-52`) |
52
52
 
53
53
  The display `name` is consumed by `buildSystemPrompt`, dashboard text, and the soft free-text matcher in `resolveTaskContext()` (§2.3), but no persistent state is keyed by it. So renaming the display name is safe and needs no state migration **as long as the id key is never mutated**. Changing the id key would orphan every row above — the id must be immutable.
54
54
 
55
55
  ### 2.3 Names are load-bearing in two places (the part that must change)
56
56
 
57
57
  1. **Charters hardcode names.** The shipped charters bake the agent's own name and peers' names into the prose — e.g. `agents/ripley/charter.md` opens `# Ripley — Lead / Explorer`, `**Name:** Ripley`, and says "Handing off structured findings to **Dallas** (Engineer) and **Lambert** (Analyst)". A rename would strew the old name through the prompt.
58
- 2. **Playbook context-resolution matches by name.** `resolveTaskContext()` (`engine/playbook.js:171-256`) matches referenced plans/notes by agent `id` and display `name` (e.g. "Ripley's plan"). After a rename, artifacts that referenced the old *name* stop auto-linking (id-based matches still resolve).
58
+ 2. **Playbook context-resolution matches by name.** `resolveTaskContext()` (`engine/agents/playbook.js:171-256`) matches referenced plans/notes by agent `id` and display `name` (e.g. "Ripley's plan"). After a rename, artifacts that referenced the old *name* stop auto-linking (id-based matches still resolve).
59
59
 
60
60
  These are the two reasons "names are load-bearing" — §4.2 and §4.3 neutralize them.
61
61
 
62
62
  ## 3. Feature flag
63
63
 
64
- - Register `agent-rename` in the `FEATURES` registry (`engine/features.js`) as `{ description, default: false, addedIn, expires }`.
64
+ - Register `agent-rename` in the `FEATURES` registry (`engine/core/features.js`) as `{ description, default: false, addedIn, expires }`.
65
65
  - **Engine/dashboard** gate the rename **endpoint + UI** with `features.isFeatureOn('agent-rename', config)` / `MinionsFeatures.isOn('agent-rename')`.
66
66
  - Toggle via Settings → Experimental flags, `config.features['agent-rename']: true`, or `MINIONS_FEATURE_AGENT_RENAME=1`. Resolution order: env → `config.features` → registry default (default OFF).
67
67
  - **What the flag gates:** the `POST /api/agents/rename` endpoint and the rename UI affordance.
@@ -83,7 +83,7 @@ Agents are **already** id-keyed (§2.1–2.2); this step makes the invariant exp
83
83
 
84
84
  A charter that hardcodes a proper name (§2.3) breaks the moment an agent is renamed (and later blocks a role-level charter being shared across agents — the configurability payoff). Make the charter body **name-agnostic** so the identity line is the single source of the name:
85
85
 
86
- - **Single source of prompt identity.** The agent's name appears in the engine-injected `# You are {name} ({label})` block (`engine/playbook.js:1092-1094`). The charter prose must use the **second person** ("you", "your") and **never** restate its own proper name (no `# Ripley`, no `**Name:** Ripley`). The agent still knows its name — it reads it from the identity block — so **name-agnostic ≠ name-blind**.
86
+ - **Single source of prompt identity.** The agent's name appears in the engine-injected `# You are {name} ({label})` block (`engine/agents/playbook.js:1092-1094`). The charter prose must use the **second person** ("you", "your") and **never** restate its own proper name (no `# Ripley`, no `**Name:** Ripley`). The agent still knows its name — it reads it from the identity block — so **name-agnostic ≠ name-blind**.
87
87
  - **Refer to peers by role, not name.** "hand off to **Dallas** (Engineer)" becomes "hand off to the **Engineer** role" — roles are stable; names are mutable. This keeps a charter valid when *any* agent is renamed.
88
88
  - **Rewrite the shipped defaults.** Sanitize the repo's `agents/<id>/charter.md` files name-agnostic. (The configurability spec later seeds role charters from these — but the sanitization lands here, unconditionally.)
89
89
  - **Legacy user charters are not auto-rewritten.** A user-authored `charter.md` that still contains a name renders verbatim (back-compat, non-breaking) — it just reads stale after a rename. A **soft, dismissible warning** flags a name embedded in an editable charter, nudging toward second person / role references. No hard block, no silent rewrite of user content.
@@ -100,20 +100,20 @@ A rename changes the agent's **display identity** (`name`, and optionally `emoji
100
100
  - **Concurrency & audit:** writes through `mutateJsonFileLocked` on `config.json` (never `safeWrite`); logs `old → new`.
101
101
 
102
102
  **What updates (display only, picked up live)**
103
- - The system-prompt identity line `# You are {name} ({label})` on the **next** dispatch (`engine/playbook.js:1092-1094`).
103
+ - The system-prompt identity line `# You are {name} ({label})` on the **next** dispatch (`engine/agents/playbook.js:1092-1094`).
104
104
  - Dashboard display: team cards, agent detail panel, history attribution, Command Center state preamble — all read `name` live on next render.
105
105
  - The rename invalidates the system-prompt / status / CC-preamble caches so the new name surfaces promptly.
106
106
 
107
107
  **What does NOT change (id-keyed, untouched — §2.2)**
108
108
  - Charter/memory paths, metrics/spend/error-rate buckets, dispatch records, PR `agent` refs, inbox prefixes, routing.
109
- - **Author matching is id-based:** `_author_` routing resolves to the author *agent id* and `pr.agent` groups by id (`engine/queries.js:431-446`), so rename never breaks self-review bans or PR-author follow-ups.
109
+ - **Author matching is id-based:** `_author_` routing resolves to the author *agent id* and `pr.agent` groups by id (`engine/core/queries.js:431-446`), so rename never breaks self-review bans or PR-author follow-ups.
110
110
 
111
111
  **In-flight dispatches**
112
112
  - A currently-running agent finishes under the system prompt it was **already spawned with** — rename does **not** kill or re-spawn it. The new name applies to the **next** dispatch. Live-output, completion reports, and history are id-keyed, so they attribute correctly throughout.
113
113
 
114
114
  **Stale name references in historical free-text (known, accepted, non-breaking)**
115
115
  - Rename does **not** cascade into pre-existing free-text: `notes.md`, `pinned.md`, the knowledge base, per-agent memory, and plan/PRD prose keep the old name (non-breaking — just stale).
116
- - Concrete engine consequence (§2.3): playbook context-resolution matches referenced plans/notes by both `id` and `name` (`engine/playbook.js:171-256`); after a rename, old-name artifacts stop auto-linking to the agent (id matches still resolve). §4.2's guidance minimizes future name-baking.
116
+ - Concrete engine consequence (§2.3): playbook context-resolution matches referenced plans/notes by both `id` and `name` (`engine/agents/playbook.js:171-256`); after a rename, old-name artifacts stop auto-linking to the agent (id matches still resolve). §4.2's guidance minimizes future name-baking.
117
117
  - A **soft, non-blocking** "old name still appears in N place(s)" hint may follow a rename; it **never** auto-rewrites user/historical content.
118
118
 
119
119
  **UI**
@@ -147,8 +147,8 @@ A rename changes the agent's **display identity** (`name`, and optionally `emoji
147
147
 
148
148
  ## 8. Work breakdown (suggested PRD seeds)
149
149
 
150
- - AR-a: Register `agent-rename` feature flag (`engine/features.js`) + Settings toggle.
151
- - AR-b: Formalize stable-id invariant + rename-safety guard + regression tests (`engine/shared.js`, `engine/queries.js`, tests). *(Unconditional.)*
150
+ - AR-a: Register `agent-rename` feature flag (`engine/core/features.js`) + Settings toggle.
151
+ - AR-b: Formalize stable-id invariant + rename-safety guard + regression tests (`engine/core/shared.js`, `engine/core/queries.js`, tests). *(Unconditional.)*
152
152
  - AR-c: Sanitize shipped `agents/<id>/charter.md` to be name-agnostic (second person, peers-by-role) + content test (no proper names) + post-rename render test. *(Unconditional.)*
153
153
  - AR-d: `POST /api/agents/rename` (full §4.3 contract: name+emoji, validation, idempotency, duplicate-warning, cache invalidation, in-flight safety, audit log) — flag-gated.
154
154
  - AR-e: Rename UI in the Settings agents table / detail panel (inline validation + soft duplicate-name warning) — flag-gated; soft name-in-charter warning.
@@ -74,7 +74,7 @@ remain intentionally file-backed documents and coordination artifacts.
74
74
  ### Offline review-learning backfill
75
75
 
76
76
  `minions memory backfill-review-learnings [--dry-run] [--limit <N>] [--project <p>]`
77
- (module `engine/review-learning-backfill.js`) is a strict, offline recovery
77
+ (module `engine/memory/review-learning-backfill.js`) is a strict, offline recovery
78
78
  command that reconstructs durable review-learning lessons from legacy artifacts
79
79
  (trusted completion artifacts + their dispatch context, tracked PR records,
80
80
  legacy feedback inbox/archive files, and migration-027 quarantined candidates).
@@ -290,7 +290,7 @@ project, agent, normalized area, disposition, work-item/dispatch references,
290
290
  compact metadata, and timestamp. Event replay is idempotent. Event pruning
291
291
  removes only old event rows and never deletes a memory record.
292
292
 
293
- The boundary in `engine/review-learning.js` redacts secret-shaped values and
293
+ The boundary in `engine/memory/review-learning.js` redacts secret-shaped values and
294
294
  enforces these UTF-8/count limits:
295
295
 
296
296
  | Value | Limit |
@@ -335,7 +335,7 @@ IDs, hashes, reason codes, and bounded traces (never raw prompt/reviewer bodies)
335
335
  plus per-event-type counters for a finding/memory/project.
336
336
  - `GET /api/memory-records/rollout` returns the bounded rollout aggregates above.
337
337
 
338
- Retention is folded into the periodic `engine/cleanup.js` cadence and is
338
+ Retention is folded into the periodic `engine/orchestration/cleanup.js` cadence and is
339
339
  deliberately decoupled from KB file TTL: unresolved review-learning candidates
340
340
  expire (`status: expired`) after 180 days; compact lifecycle events are pruned
341
341
  past one year and above the 50,000-row cap; active procedural lessons persist
@@ -345,7 +345,7 @@ record emits a `retracted`/`restored` lifecycle event for the operator timeline.
345
345
 
346
346
  ### Query construction and selection
347
347
 
348
- `engine/memory-retrieval.js` builds a task query from the work-item title,
348
+ `engine/memory/memory-retrieval.js` builds a task query from the work-item title,
349
349
  description, work type, failure class, source plan, references, PR title, and PR
350
350
  branch. The SQL store:
351
351
 
@@ -373,7 +373,7 @@ dashboard's structured-memory search.
373
373
  ### Reserved deterministic review-lesson recall
374
374
 
375
375
  Review-learning records are recalled through a dedicated path that never depends
376
- on an FTS hit (`engine/memory-retrieval.js#retrieveApplicableReviewLearnings`),
376
+ on an FTS hit (`engine/memory/memory-retrieval.js#retrieveApplicableReviewLearnings`),
377
377
  and they are **globally excluded** from the generic FTS pack
378
378
  (`searchMemoryRecords` drops `source_type='review-learning'` unless a caller
379
379
  passes `includeReviewLearning`, which only the operator dashboard search does).
@@ -389,22 +389,39 @@ project context, the path:
389
389
  scoping preventing any cross-project leak;
390
390
  3. derives normalized affected-file, symbol, and tag hints from the same task
391
391
  context (`deriveReviewFacetHints`, mirroring the capture-side normalization);
392
- 4. ranks exact **symbol → file → tag** overlap first, then lexical relevance,
393
- confidence, and recency, keeping only applicable lessons; and
392
+ 4. ranks exact **symbol → file → tag** overlap first, then **feature-branch
393
+ affinity** (descriptive tokens shared between the current dispatch's PR
394
+ branch / PR title and the lesson), then lexical relevance, confidence, and
395
+ recency, keeping only applicable lessons — so a lesson from a prior PR on the
396
+ same branch or feature outranks one that merely shares an incidental token;
397
+ and
394
398
  5. injects at most **4 records or 4 KiB** (independent of the generic memory
395
399
  budget) as a separately fenced `## Applicable Prior Review Lessons` section,
396
- wrapped with `engine/untrusted-fence.js`.
400
+ wrapped with `engine/core/untrusted-fence.js`.
401
+
402
+ For PR-authoring dispatches (every non read-only work type — implement, fix,
403
+ test, verify, decompose, docs, review), the section is framed as an explicit
404
+ **pre-PR checklist**: a trusted, un-fenced directive above the fenced lessons
405
+ instructs the agent to confirm each recalled finding is addressed (or does not
406
+ apply) against the live code before opening or updating the PR, and to record
407
+ one `reviewLearningApplications` entry per lesson (`applied`,
408
+ `considered-not-applicable`, or `contradicted`) in its completion report. Read-
409
+ only dispatches (ask, explore, plan, meeting) open no PR and keep the plain
410
+ informational framing. The checklist reuses the existing recalled-lesson
411
+ selection and the `reviewLearningApplications` contract — no new payload or
412
+ retrieval budget.
397
413
 
398
414
  Each run records bounded telemetry through `recordRetrievalRun` with
399
415
  `retrieval_kind='review-learning'`, the dispatch and work-item ids, selected
400
416
  record ids, per-record scores, and reason codes (`exact-symbol`, `exact-file`,
401
- `exact-tag`, `lexical`, `not-applicable`, `record-cap`, `byte-cap`) — never any
402
- prompt or comment body. Projectless Command Center / unrelated central work
403
- receive no section.
417
+ record ids, per-record scores, and reason codes (`exact-symbol`, `exact-file`,
418
+ `exact-tag`, `feature-branch`, `lexical`, `not-applicable`, `record-cap`,
419
+ `byte-cap`) — never any prompt or comment body. Projectless Command Center /
420
+ unrelated central work receive no section.
404
421
 
405
422
  ## Prompt assembly and fallback
406
423
 
407
- `engine/playbook.js` renders the requested playbook, adds shared rules, then
424
+ `engine/agents/playbook.js` renders the requested playbook, adds shared rules, then
408
425
  appends memory context in this order:
409
426
 
410
427
  1. **Pinned Context**, when `pinned.md` is non-empty.
@@ -447,7 +464,7 @@ or XML-like wrapper overhead added to the final prompt.
447
464
 
448
465
  Memory content is evidence, not a new instruction channel. Before prompt
449
466
  insertion, pinned context, retrieved records, team notes, and personal memory
450
- are wrapped with `engine/untrusted-fence.js`:
467
+ are wrapped with `engine/core/untrusted-fence.js`:
451
468
 
452
469
  ```text
453
470
  <UNTRUSTED-INPUT source="kind:provenance">...</UNTRUSTED-INPUT>
@@ -578,7 +595,7 @@ restart-ordering, or data cleanup is involved.
578
595
  ### Promotion into repository guidance
579
596
 
580
597
  A verified, **repeatedly observed** lesson can be promoted (human-approved) into
581
- guidance that vanilla runtimes discover natively (`engine/promotion.js`,
598
+ guidance that vanilla runtimes discover natively (`engine/memory/promotion.js`,
582
599
  `POST /api/memory-records/<id>/promote`). Promotion is eligible only at confidence
583
600
  ≥ `0.8` and ≥ 2 distinct valid findings (the rule recurred at least once). It never
584
601
  edits an operator checkout: every promotion queues a normal project-bound work item
@@ -699,25 +716,25 @@ Markdown tiers are automatically copied into the prompt.
699
716
 
700
717
  ## Implementation map
701
718
 
702
- - [`engine/consolidation.js`](../engine/consolidation.js) - inbox digest,
719
+ - [`engine/memory/consolidation.js`](../engine/memory/consolidation.js) - inbox digest,
703
720
  classification, personal routing, pruning, reconciliation, and summary.
704
721
  - [`engine/db/migrations/017-agent-memory.js`](../engine/db/migrations/017-agent-memory.js)
705
722
  - schema and one-time Markdown backfill.
706
723
  - [`engine/db/migrations/027-review-learning-lifecycle.js`](../engine/db/migrations/027-review-learning-lifecycle.js)
707
724
  - in-place retrieval/lifecycle schema extension and exact legacy-feedback
708
725
  quarantine.
709
- - [`engine/review-learning.js`](../engine/review-learning.js) - dispositions,
726
+ - [`engine/memory/review-learning.js`](../engine/memory/review-learning.js) - dispositions,
710
727
  stable finding/area identities, redaction, bounds, record validation, event
711
728
  keys, and candidate transitions.
712
- - [`engine/memory-store.js`](../engine/memory-store.js) - record validation,
729
+ - [`engine/memory/memory-store.js`](../engine/memory/memory-store.js) - record validation,
713
730
  lifecycle, FTS5 query, candidate/lesson helpers, bounded telemetry, and
714
731
  rollout aggregates.
715
- - [`engine/memory-retrieval.js`](../engine/memory-retrieval.js) - task query,
732
+ - [`engine/memory/memory-retrieval.js`](../engine/memory/memory-retrieval.js) - task query,
716
733
  reranking, deduplication, provenance formatting, and byte packing.
717
- - [`engine/playbook.js`](../engine/playbook.js) - pinned/retrieved/legacy prompt
734
+ - [`engine/agents/playbook.js`](../engine/agents/playbook.js) - pinned/retrieved/legacy prompt
718
735
  assembly and fallback.
719
- - [`engine/lifecycle.js`](../engine/lifecycle.js) - episodic completion capture.
720
- - [`engine/untrusted-fence.js`](../engine/untrusted-fence.js) - provenance fence
736
+ - [`engine/orchestration/lifecycle.js`](../engine/orchestration/lifecycle.js) - episodic completion capture.
737
+ - [`engine/core/untrusted-fence.js`](../engine/core/untrusted-fence.js) - provenance fence
721
738
  and UTF-8-safe truncation.
722
739
  - [`dashboard.js`](../dashboard.js) and
723
740
  [`dashboard/js/memory-search.js`](../dashboard/js/memory-search.js) -
@@ -4,25 +4,78 @@ What kills (or doesn't kill) a live agent. CLAUDE.md → Timeouts & Liveness
4
4
  keeps the core invariant; the spawn-phase watchdog, steering safety nets,
5
5
  and stale-orphan detection details live here.
6
6
 
7
- > Source of truth: `engine/timeout.js`, `engine/spawn-phase-watchdog.js`,
8
- > `engine/shared.js` (`ENGINE_DEFAULTS`, `getProcessCpuSeconds`,
9
- > `killImmediate`), `engine/steering-store.js`. See also:
10
- > [engine-restart.md](engine-restart.md). Last verified: 2026-06-09.
7
+ > Source of truth: `engine/orchestration/timeout.js`, `engine/agents/spawn-phase-watchdog.js`,
8
+ > `engine/core/shared.js` (`ENGINE_DEFAULTS`, `getProcessCpuSeconds`,
9
+ > `terminateProcess`), `engine/persistence/steering-store.js`. See also:
10
+ > [engine-restart.md](engine-restart.md). Last verified: 2026-07-29.
11
11
 
12
12
  ## Core invariant
13
13
 
14
14
  **A live tracked agent is never killed for being silent.** Long builds,
15
15
  installs, multi-file edits routinely produce no stdout for many minutes.
16
16
 
17
- Only two things kill a live tracked process (`engine/timeout.js`):
17
+ Only two things terminate a live tracked process (`engine/orchestration/timeout.js`):
18
18
 
19
19
  1. **Hard wall-clock timeout** `engine.agentTimeout` (default 5h from
20
20
  `startedAt`; per-fan-out `meta.deadline`).
21
- 2. **Steering kill** — explicit human steering → `killImmediate()` so the
22
- agent re-spawns with `--resume <session>`.
21
+ 2. **Steering termination** — explicit human steering → the registered
22
+ tracked-process gateway so the agent re-spawns with `--resume <session>`.
23
23
 
24
24
  **Don't add output-silence timers for live tracked processes.**
25
25
 
26
+ ## Completion boundary: terminal exit + a dispatch-owned report (W-ms9tcs3o01y03383)
27
+
28
+ The invariant above governs when a **live** agent may be killed. Its mirror
29
+ image governs when a **finished** agent must be released: a dispatch is done the
30
+ moment BOTH halves hold.
31
+
32
+ 1. The tracked child exited terminally and successfully (`code === 0` from the
33
+ `close` event, so exit is confirmed by construction), and
34
+ 2. a structurally valid completion report exists whose `nonce` proves it was
35
+ written by *this* dispatch (minted per spawn, carried across steering
36
+ resumes).
37
+
38
+ `engine.js#resolveCloseCompletionBoundary` answers that question through the
39
+ single shared trust predicate `shared.acceptCompletionReportForNonce`, which the
40
+ resume-stall watchdog in `engine/orchestration/timeout.js` uses too. It **fails
41
+ closed** on every other shape — non-zero exit, missing report, malformed report,
42
+ missing or mismatched nonce — so no existing failure or timeout path is
43
+ weakened.
44
+
45
+ When the boundary holds, queued resume bookkeeping is **released, not spawned**
46
+ (`engine.js#releasePendingSteeringResumeForCompletedTurn`). A completed turn can
47
+ never produce the first-output heartbeat that a `--resume` spawn is waiting for,
48
+ so starting one only parks the dispatch for a full
49
+ `engine.resumeHeartbeatTimeout`. Real incident
50
+ (`lambert-plan-to-prd-ms9skh2q01a91a35`): the agent finished at 03:19:20Z with a
51
+ valid report on disk, the engine spawned a resume purely to deliver a deferred
52
+ human steering message, and the dispatch did not terminalize until 03:24:32Z —
53
+ 310 seconds of pure bookkeeping.
54
+
55
+ Releasing the resume does **not** drop the human's message. The steering files
56
+ stay UNREAD on disk, so the agent's next dispatch picks them up through
57
+ `steering.buildPendingSteeringPrompt` — the same durability contract as the
58
+ no-sessionId `[steering-pending]` branch, and exactly what the operator was told
59
+ when the message was deferred ("queued until the agent reaches a resumable
60
+ checkpoint **or the next dispatch**").
61
+
62
+ ### Completion-path observability
63
+
64
+ Completed dispatch records carry `completionPath`, drawn from the closed
65
+ `shared.DISPATCH_COMPLETION_PATH` vocabulary, so the three outcomes stay
66
+ distinguishable after the fact:
67
+
68
+ | Value | Meaning |
69
+ |-------|---------|
70
+ | `process-close` | Normal completion: the close handler finalized the dispatch. |
71
+ | `report-recovery-immediate` | Terminal exit + dispatch-owned report; queued resume bookkeeping was released instead of spawned. |
72
+ | `output-detection` | Close event never reached the engine (restart/reattach); recovered from the `[process-exit]` sentinel. |
73
+ | `resume-stall-report` | A **still-live** resume blew its heartbeat budget, but a dispatch-owned report proved the turn had succeeded. |
74
+ | `resume-stall-timeout` | A still-live resume genuinely stalled with no durable evidence. |
75
+
76
+ `resume-stall-*` now means what it says: a live resume that really did stall.
77
+ A finished turn no longer masquerades as one.
78
+
26
79
  ## Stale-orphan detection
27
80
 
28
81
  `engine.heartbeatTimeout` (default 5 min) is the **grace window after the
@@ -48,9 +101,50 @@ Bypassed when `canReapDeadProcess` is true (confirmed-dead at restart).
48
101
  After engine restart, gated on `engineRestartGraceUntil` (default
49
102
  20 min) — see [engine-restart.md](engine-restart.md).
50
103
 
104
+ Dispatches whose PID is positively dead at startup bypass that wait and are
105
+ classified as `engine-restart`. They retry against a separate bounded
106
+ infrastructure counter, so a daemon restart cannot exhaust the task's semantic
107
+ agent retry budget.
108
+
109
+ ### Evidence gate: "unobservable" is not "dead" (W-ms6dmv99005o26f4)
110
+
111
+ Every liveness observation is **tri-state** — alive, conclusively absent, or
112
+ unobservable — and only *conclusive absence* may drive a destructive decision.
113
+ Collapsing the third state into "dead" caused the fleet-wide false-orphan storm
114
+ of 2026-07-29T17:44Z, where a dozen live dispatches were orphaned within ~10s
115
+ (`Orphaned — no process, silent for 5s/6s/11s/12s/27s`) and had retries consumed
116
+ and worktrees GC'd, while the agent processes were still running.
117
+
118
+ | Probe | Helper | Conclusive absence | Unobservable |
119
+ |-------|--------|--------------------|--------------|
120
+ | `process.kill(pid, 0)` | `shared.inspectPidLiveness` | `ESRCH` | any other errno. `EPERM` means the kernel **found** the process and refused the signal → `alive: true` |
121
+ | Fleet enumeration | `shared.captureProcessSnapshot` | a snapshot containing the observing process | `listAllProcesses()` threw, returned `[]`, or omitted `selfPid` → `{ ok: false }` |
122
+ | Start-time identity | `shared.inspectProcessIdentity` | PID absent from a trusted snapshot | no usable snapshot, or the platform reported no creation time |
123
+ | Command line | `shared.inspectProcessCommandLineForAgent` | a readable command line, or absence from a trusted snapshot | the per-PID probe threw or returned empty |
124
+
125
+ Two decisions are gated on `conclusive`:
126
+
127
+ - **Restart reattach** (`engine/operations/cli.js`). `evaluateReattachEvidence` still
128
+ *refuses* to reattach an unverified PID — that part is unchanged and must stay
129
+ fail-closed — but `shouldMarkConfirmedDeadAtRestart` only sets
130
+ `engineRestartGraceExempt` when the refusal was conclusive. An inconclusive
131
+ refusal falls back to the normal `minAliveBeforeOrphanMs` +
132
+ `engineRestartGraceUntil` window instead of orphaning on the next tick.
133
+ - **Orphan cmdline cross-check** (`engine/orchestration/timeout.js`).
134
+ `evaluateLivePidCommandLine` demotes an alive OS PID to "dead" only on an
135
+ *observed* non-agent command line. A failed probe keeps the dispatch, exactly
136
+ as if the cross-check had not run. This link needs no engine restart at all — a
137
+ PowerShell/`ps` probe outage under fleet load was enough on its own.
138
+
139
+ Genuine recycled PIDs, observed non-agent command lines, and `ESRCH` PIDs are
140
+ still reaped immediately; the bounded grace window is unchanged. Boolean facades
141
+ (`isPidAlive`, `isProcessCommandLineMatchingAgent`, `getProcessIdentity`) keep
142
+ their historical "false/null == not known to be alive" contract, which leaves
143
+ fail-closed kill guards such as `isRecordedAgentProcess` conservative.
144
+
51
145
  ## Steering safety nets (W-mq066js7000fff1f-c)
52
146
 
53
- Three knobs backstop the steering pipeline. `engine/timeout.js`
147
+ Three knobs backstop the steering pipeline. `engine/orchestration/timeout.js`
54
148
  defensively requires `./steering-store` and swallows `MODULE_NOT_FOUND`
55
149
  only, so the gates work even before the store has shipped.
56
150
 
@@ -76,6 +170,20 @@ without a `sessionId` is **stranded** — `[steering-warn]` +
76
170
  `status='stranded'`. Re-warn is guarded by
77
171
  `_deferredSteeringStrandedFiles`.
78
172
 
173
+ ### Completed-turn resume release (W-ms9tcs3o01y03383)
174
+
175
+ Checkpoint promotion is skipped entirely when the close handler's completion
176
+ boundary holds (terminal exit 0 + dispatch-owned report). Any resume intent a
177
+ live steering kill already staged (`_steeringMessage` / `_steeringSessionId` /
178
+ `_steeringEntry` / `_steeringDeferredCheckpoint`) is cleared, rows already moved
179
+ to `re_spawning` roll back to `queued`, and `[steering-pending]` is appended to
180
+ `live-output.log`. The `_steeringNoSession` re-queue (#1014) is released the same
181
+ way: re-queueing to `pending` is right for an agent interrupted mid-work and
182
+ wrong for one that provably finished, because it discards a real success and
183
+ re-runs completed work. The message files are never acked or deleted, so
184
+ delivery moves to the agent's next dispatch instead of blocking terminalization.
185
+ See [Completion boundary](#completion-boundary-terminal-exit--a-dispatch-owned-report-w-ms9tcs3o01y03383).
186
+
79
187
  ### Stale-session purge
80
188
 
81
189
  `onAgentClose` clears `session.json` on `No conversation found`.
@@ -91,7 +199,7 @@ dropped, please re-send.
91
199
 
92
200
  ## Spawn-phase watchdog (W-mq0e2dae000a003d)
93
201
 
94
- `engine/spawn-phase-watchdog.js#checkSpawnPhaseStalls` runs every tick
202
+ `engine/agents/spawn-phase-watchdog.js#checkSpawnPhaseStalls` runs every tick
95
203
  alongside `checkTimeouts` / `checkSteering` and kills children wedged
96
204
  in MCP-init. Four gates, **ALL** required:
97
205
 
@@ -110,7 +218,7 @@ in MCP-init. Four gates, **ALL** required:
110
218
 
111
219
  On fire:
112
220
 
113
- - Kill via `shared.killImmediate`.
221
+ - Terminate via the registered `engine.spawn-phase.stall` gateway site.
114
222
  - Write a structured `spawn-phase-stall-<id>` inbox note with the
115
223
  live-output tail.
116
224
  - Complete the dispatch with
@@ -37,7 +37,7 @@ The installer validates feed access, installs the package, and then runs the
37
37
  supported `minions init --force` synchronization — so no separate `minions init`
38
38
  is needed. It authenticates with a short-lived token from your existing `az`
39
39
  login; no PAT is created, accepted, or stored. See
40
- [internal-install.md](internal-install.md) for options and troubleshooting.
40
+ [internal-install.md](../internal-install.md) for options and troubleshooting.
41
41
 
42
42
  If you do not have access to the ISS `ProjectFeed-ISS` feed, install the public
43
43
  package from npm instead (a separate release channel, not the OPG path):