@yemi33/minions 0.1.2370 → 0.1.2371

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 (71) hide show
  1. package/bin/minions.js +38 -11
  2. package/dashboard/js/render-other.js +2 -30
  3. package/dashboard/js/render-work-items.js +0 -34
  4. package/dashboard/js/settings.js +12 -27
  5. package/dashboard/pages/tools.html +1 -1
  6. package/dashboard.js +80 -257
  7. package/docs/README.md +2 -3
  8. package/docs/architecture.excalidraw +2 -2
  9. package/docs/auto-discovery.md +3 -3
  10. package/docs/completion-reports.md +0 -121
  11. package/docs/copilot-cli-schema.md +9 -17
  12. package/docs/deprecated.json +0 -51
  13. package/docs/design-state-storage.md +4 -4
  14. package/docs/harness-propagation.md +33 -263
  15. package/docs/human-vs-automated.md +1 -1
  16. package/docs/named-agents.md +0 -2
  17. package/docs/plan-lifecycle.md +5 -6
  18. package/docs/qa-runbook-lifecycle.md +10 -25
  19. package/docs/shared-lifecycle-module-map.md +2 -10
  20. package/engine/ado-comment.js +5 -11
  21. package/engine/ado.js +10 -5
  22. package/engine/cleanup.js +16 -36
  23. package/engine/cli.js +13 -175
  24. package/engine/comment-format.js +8 -182
  25. package/engine/db/index.js +60 -10
  26. package/engine/db/migrations/018-sql-only-cutover.js +56 -0
  27. package/engine/dispatch-store.js +0 -114
  28. package/engine/dispatch.js +1 -6
  29. package/engine/gh-comment.js +2 -10
  30. package/engine/github.js +8 -6
  31. package/engine/lifecycle.js +58 -173
  32. package/engine/llm.js +9 -11
  33. package/engine/managed-spawn.js +1 -6
  34. package/engine/memory-store.js +8 -6
  35. package/engine/metrics-store.js +4 -128
  36. package/engine/pipeline.js +4 -7
  37. package/engine/playbook.js +8 -196
  38. package/engine/prd-store.js +115 -141
  39. package/engine/preflight.js +8 -55
  40. package/engine/projects.js +34 -41
  41. package/engine/pull-requests-store.js +9 -234
  42. package/engine/qa-runs.js +4 -15
  43. package/engine/qa-sessions.js +5 -17
  44. package/engine/queries.js +23 -103
  45. package/engine/routing.js +1 -1
  46. package/engine/runtimes/claude.js +1 -2
  47. package/engine/runtimes/codex.js +0 -2
  48. package/engine/runtimes/copilot.js +1 -4
  49. package/engine/shared-branch-pr-reconcile.js +2 -5
  50. package/engine/shared.js +174 -533
  51. package/engine/small-state-store.js +12 -647
  52. package/engine/spawn-agent.js +5 -96
  53. package/engine/state-operations.js +166 -0
  54. package/engine/supervisor.js +0 -1
  55. package/engine/watch-actions.js +2 -3
  56. package/engine/watches-store.js +2 -128
  57. package/engine/work-items-store.js +3 -254
  58. package/engine.js +102 -334
  59. package/package.json +2 -2
  60. package/playbooks/build-fix-complex.md +0 -4
  61. package/playbooks/fix.md +0 -4
  62. package/playbooks/implement-shared.md +0 -4
  63. package/playbooks/implement.md +0 -4
  64. package/playbooks/plan-to-prd.md +16 -11
  65. package/playbooks/plan.md +0 -4
  66. package/playbooks/review.md +0 -6
  67. package/playbooks/shared-rules.md +0 -65
  68. package/docs/harness-transparency.md +0 -199
  69. package/docs/project-skills.md +0 -193
  70. package/engine/discover-project-skills.js +0 -673
  71. package/engine/playbook-intents.js +0 -76
@@ -86,73 +86,7 @@ Do **not** invent, regenerate, or share the nonce across dispatches — each spa
86
86
  | `pending` | string | Any remaining work, or `none`. |
87
87
  | `followups` | array | Optional. PR-comment follow-up work items the agent dispatched via `POST /api/work-items` with `meta.pr_followup` set. Each entry: `{wi_id, title, reason, parent_comment_id}`. See [PR-comment follow-ups](#pr-comment-follow-ups). |
88
88
  | `invalidates` | string[] | Optional. List of work-item IDs (e.g. `["W-abc123"]`) whose goals are superseded by this completion. The engine cancels each listed WI that is currently in `pending` or `queued` status, stamping `cancellationReason: "invalidated-by:<source-wi-id>"`. WIs in any other status (dispatched, done, failed, cancelled) are skipped with a warning — they are NOT cancelled. Missing IDs also log a warning and are skipped. Only processed on successful (`effectiveSuccess`) completions. See [Goal invalidation](#goal-invalidation). |
89
- | `meta.review` | object | Optional, review tasks only. Records project-local review-skill outcome — see [Review skill outcomes](#review-skill-outcomes). Aliased by the generalized `meta.skill` (W-mq1cczi90006b21f). |
90
- | `meta.skill` | object | Optional. Records project-local skill outcome for ANY playbook type that surfaces a `## Project skills` block (implement / fix / plan / review / etc.). See [Project skill outcomes](#project-skill-outcomes). |
91
89
  | `meta.descriptionAudit` | object | Optional, `fix` / `implement` dispatches that push commits. Records the PR description audit + screenshot-refresh outcome — see [PR description audit](#pr-description-audit). |
92
- | `harnessUsed` | object | Optional. Self-report of the harness affordances (skills / MCP servers / commands / docs) the agent actually consulted. Canonical `{ skills, mcpServers, commands, docs }` shape; cross-checked against what the engine exposed and annotated `grounded: true\|false` (never dropped). See [Harness usage](#harness-usage-harnessused). |
93
-
94
- ## Project skill outcomes
95
-
96
- W-mq1cczi90006b21f. Generalizes the PR-82 review-only `meta.review.skill*` fields to the full Minions lifecycle. When the playbook renders a `## Project skills` block (via `engine/playbook-intents.js` → `engine/discover-project-skills.js`) and the agent acts on a discovered skill, record the outcome under `meta.skill` so later evaluation can compare skill-driven vs. first-principles work across implement / fix / plan / review dispatches uniformly.
97
-
98
- All `meta.skill` fields are optional and backward-compatible — older agents that never set them stay valid.
99
-
100
- ```json
101
- {
102
- "status": "success",
103
- "meta": {
104
- "skill": {
105
- "invoked": {
106
- "name": "bump-fmf-android",
107
- "path": ".claude/skills/bump-fmf-android/SKILL.md",
108
- "kind": "skill",
109
- "intent": "build"
110
- },
111
- "findings": 3
112
- }
113
- }
114
- }
115
- ```
116
-
117
- | Field | Type | Notes |
118
- |---|---|---|
119
- | `meta.skill.invoked` | object | The project skill the agent actually ran. Shape: `{name, path, kind, intent}` where `kind` is one of `skill`, `command`, `slash-command` (mirrors the discovery layer in `engine/discover-project-skills.js`) and `intent` is the bucket it served (`build`, `review`, `fix`, `test`, `plan`, `research`, `deploy`, `observability`, `meta`). Omit when no skill was invoked. |
120
- | `meta.skill.findings` | number | Count of findings/artifacts the invoked skill returned. Semantics is per-skill; treat as opaque integer. Omit when no skill was invoked. |
121
- | `meta.skill.skipped` | object | Set when a project skill was available but the agent intentionally chose not to run it (trivial diff, out-of-scope, meta-work on the skill itself, etc.). Shape: `{name, reason}`. **Before recording a skip you MUST validate it against the skill's own documented scope** — re-read the skill's SKILL.md checklist and confirm the skip reason does not contradict any explicit "Flag if…" / "Verify that…" / "Requirements" item; if the diff trips any such item, skipping is not permitted (apply the skill or that item instead). Mirror the skip rationale into the PR comment so a human sees it **before** merge, not only via a later API call — `minions pr comment … --skill-skipped-file <f>` / `--skill-skipped-json <j>` folds a visible `> ⚠️ Skipped project skill: <name> — <reason>` callout into the same comment as the verdict (single renderer `engine/comment-format.js#buildSkippedSkillSection`, byte-identical on GitHub and ADO). The `{name, reason}` in the comment MUST match the one recorded here (no drift). |
122
-
123
- Dispatchers can suppress the block entirely by setting `meta.skipProjectSkills: true` on the work item — the playbook then renders without the skills block. Use this for meta-work that targets the skill itself; the engine still accepts `meta.skill.skipped` in the report regardless. The PR-82 `meta.skipProjectReviewSkills` flag is preserved as an alias (suppresses the block on every dispatch type, not just review).
124
-
125
- ## Review skill outcomes
126
-
127
- W-mq16xtdx001a347e. **Original PR-82 fields, preserved as aliases.** New code should prefer the generalized `meta.skill.*` fields above (W-mq1cczi90006b21f) — those work for every playbook type, not just review.
128
-
129
- Review playbook renders a `## Project review skills` block at dispatch time when the target project ships `.claude/skills/*` or `.claude/commands/*` with `review` / `swarm` in the name or description (or when `.github/copilot-instructions.md` / `CLAUDE.md` mention a canonical `/…review…` slash-command). When the agent acts on that block, it records the outcome under `meta.review` so later evaluation can compare skill-driven reviews vs. first-principles reviews.
130
-
131
- All `meta.review` fields are optional and backward-compatible — older agents that never set them stay valid.
132
-
133
- ```json
134
- {
135
- "status": "success",
136
- "meta": {
137
- "review": {
138
- "skillInvoked": {
139
- "name": "code-reviewer",
140
- "path": ".claude/skills/code-reviewer/SKILL.md",
141
- "kind": "skill"
142
- },
143
- "skillFindings": 3
144
- }
145
- }
146
- }
147
- ```
148
-
149
- | Field | Type | Notes |
150
- |---|---|---|
151
- | `meta.review.skillInvoked` | object | The project review skill the agent actually ran. Shape: `{name, path, kind}` where `kind` is one of `skill`, `command`, `slash-command` (mirrors the discovery layer in `engine/discover-project-skills.js`). Omit when no skill was invoked. Aliased by `meta.skill.invoked`. |
152
- | `meta.review.skillFindings` | number | Count of findings the invoked skill returned. Used later to measure skill quality and the value-add of first-principles review on top. Omit when no skill was invoked. Aliased by `meta.skill.findings`. |
153
- | `meta.review.skillSkipped` | object | Set when a project review skill was available but the agent intentionally chose not to run it (trivial diff, out-of-scope diff, meta-review of the skill itself, etc.). Shape: `{name, reason}`. Aliased by `meta.skill.skipped`. **The skip reason is validated against the skill's own scope** — before recording a skip the agent must re-read the skill's SKILL.md checklist and confirm the reason does not contradict any explicit "Flag if…" / "Verify that…" / "Requirements" item; if the diff trips any such item, skipping is not permitted. The same `{name, reason}` must also be surfaced in the PR review comment (visible `> ⚠️ Skipped project skill` callout, via `minions pr comment … --skill-skipped-json`) so a human sees it before merge — no drift between the report and the comment. |
154
-
155
- Dispatchers can suppress the block entirely by setting `meta.skipProjectReviewSkills: true` on the review work item — the playbook then renders identically to the pre-W-mq16xtdx 8-step contract. Use this for meta-reviews of the review skill itself; the engine still accepts `meta.review.skillSkipped` in the report regardless. (W-mq1cczi90006b21f generalized this to `meta.skipProjectSkills`, which suppresses the block on every dispatch type — both flags are honored.)
156
90
 
157
91
  ## PR description audit
158
92
 
@@ -216,60 +150,6 @@ P-mqyp0009y025z6a7. An optional `invalidates: string[]` field in the completion
216
150
 
217
151
  **Implementation:** `engine/lifecycle.js#applyGoalInvalidation`, called from `runPostCompletionHooks` after the source WI is marked done.
218
152
 
219
- ## Harness usage (`harnessUsed`)
220
-
221
- P-a8f3c2d1. Optional self-report of the harness affordances the agent actually
222
- consulted to do the work — the skills it ran, the MCP servers it called, the
223
- slash-commands it invoked, and the reference docs it read. The field is
224
- backward-compatible: older agents that never set it stay valid. Omit it when no
225
- harness affordance was used; do not pad it with affordances you didn't touch.
226
-
227
- Use the canonical `{ skills, mcpServers, commands, docs }` shape
228
- (`shared.HARNESS_USED_KINDS`). Each kind keeps only the listed fields, and the
229
- **required** field must be present or `shared.normalizeHarnessUsed()` drops the
230
- entry:
231
-
232
- | Kind | Fields | Required |
233
- |---|---|---|
234
- | `skills` | `name`, `source`, `path` | `name` |
235
- | `mcpServers` | `name`, `scope` | `name` |
236
- | `commands` | `name`, `scope` | `name` |
237
- | `docs` | `path`, `why` | `path` |
238
-
239
- ```json
240
- {
241
- "status": "success",
242
- "summary": "...",
243
- "harnessUsed": {
244
- "skills": [
245
- {"name": "run-tests", "source": "project", "path": ".claude/skills/run-tests/SKILL.md"}
246
- ],
247
- "mcpServers": [
248
- {"name": "azure-ado", "scope": "user"}
249
- ],
250
- "commands": [
251
- {"name": "simplify", "scope": "user"}
252
- ],
253
- "docs": [
254
- {"path": "docs/completion-reports.md", "why": "confirmed the harnessUsed field shape"}
255
- ]
256
- }
257
- }
258
- ```
259
-
260
- **Grounding semantics.** The report is a self-report — a *claim*. The engine
261
- captures what it actually propagated into the worktree at spawn time
262
- (`_harnessPropagated`, unioning user-scope + project-scope harness roots) and
263
- cross-checks each self-reported entry against it. Entries are annotated
264
- `grounded: true | false` and **kept, never dropped**: a `grounded: false` entry
265
- means "the agent claims it used something the engine has no record of exposing"
266
- (a genuine out-of-band tool, a stale path, or a hallucinated entry) and is
267
- surfaced for a human rather than silently discarded. Normalization also clamps
268
- each field to 512 chars and caps each kind at 50 entries
269
- (`HARNESS_USED_MAX_FIELD_LEN` / `HARNESS_USED_MAX_ENTRIES`). The full
270
- capture → ground → surface contract is in
271
- [harness-transparency.md](harness-transparency.md).
272
-
273
153
  ## `failure_class` enum
274
154
 
275
155
  Defined in `engine/shared.js` as `FAILURE_CLASS`. Use the canonical hyphenated string.
@@ -493,5 +373,4 @@ The legacy fenced ` ```completion ` block parser and the `task_complete` prose-s
493
373
  - `engine/lifecycle.js` — `parseCompletionReportFile()`, `parseCompletionNoop()`, `enforcePrAttachmentContract()`
494
374
  - `engine/dispatch.js` — `isRetryableFailureReason()`, `writeFailedAgentReport()`
495
375
  - `docs/rfc-completion-json.md` — original RFC describing the protocol's design
496
- - `docs/harness-transparency.md` — the `harnessUsed` capture → ground → surface contract
497
376
  - `playbooks/shared-rules.md` — the per-task "Completion Reports" instruction every playbook inherits
@@ -23,7 +23,7 @@
23
23
  | `capabilities.costTracking` | **`false`** | `result.usage` contains `premiumRequests` (count, not USD), no token counts, no cost. |
24
24
  | `capabilities.modelShorthands` | **`false`** | The Copilot CLI requires full model IDs (`claude-sonnet-4.5`, `gpt-5.4`). Minions may accept internal aliases (`haiku`, `sonnet`, `opus`), but the adapter translates them to Copilot model IDs before invoking the CLI. |
25
25
  | `capabilities.budgetCap` | **`false`** | No `--max-budget-usd` flag. |
26
- | `capabilities.bareMode` | **`false`** | No `--bare`. Closest equivalent is `--no-custom-instructions` (suppresses AGENTS.md only, not all auto-discovery). |
26
+ | `capabilities.bareMode` | **`false`** | No `--bare` equivalent. |
27
27
  | `capabilities.fallbackModel` | **`false`** | No `--fallback-model` flag. |
28
28
  | `capabilities.sessionPersistenceControl` | **`false`** | Copilot manages session state internally in `~/.copilot/session-state/`. Engine cannot opt out without `--config-dir`. |
29
29
  | `capabilities.imageInput` | **`true`** | Base64 image payloads are materialized to temp files and passed as `--attachment <path>` (repeatable flag, W-mqv7324u0021db5d). See §10a. |
@@ -32,7 +32,6 @@
32
32
  |---|---|
33
33
  | `copilotStreamMode` (default config field) | `'on'` — preserves incremental UX; the adapter parser tolerates either mode. |
34
34
  | `copilotDisableBuiltinMcps` | `true` — github-mcp-server bypasses Minions' `pull-requests.json` tracking; default OFF. |
35
- | `copilotSuppressAgentsMd` | `true` — Minions injects its own playbook prompt; AGENTS.md auto-load conflicts with that. |
36
35
  | `copilotReasoningSummaries` | `false` — opt-in; only some models honor it. |
37
36
 
38
37
  ---
@@ -154,9 +153,8 @@ function buildPrompt(promptText, sysPromptText) {
154
153
  }
155
154
  ```
156
155
 
157
- Combined with `--no-custom-instructions` (default-on per
158
- `copilotSuppressAgentsMd`), this guarantees the prompt the agent sees is exactly
159
- what Minions sent.
156
+ Copilot's native custom-instruction discovery remains enabled, so repository
157
+ instructions augment the Minions task prompt as they do in normal CLI usage.
160
158
 
161
159
  ---
162
160
 
@@ -172,7 +170,6 @@ Empirically confirmed flags for non-interactive Copilot invocations:
172
170
  | `--no-ask-user` | **required** | Removes the `ask_user` tool. Without it the agent can stall waiting for human input. |
173
171
  | `--autopilot` | for multi-turn agency | Enables `task_complete`-driven multi-turn loop. **Without it** the session ends after one assistant response (see §3.1). |
174
172
  | `--log-level error` | recommended | Suppresses INFO/DEBUG diagnostics that aren't part of the JSONL stream. |
175
- | `--no-custom-instructions` | gated by config | Disables AGENTS.md auto-load. Default-on for Minions (`copilotSuppressAgentsMd: true`). |
176
173
  | `--disable-builtin-mcps` | gated by config | Disables `github-mcp-server`. Default-on for Minions (`copilotDisableBuiltinMcps: true`) to prevent split-brain PR creation. |
177
174
  | `--no-color` | optional | Cosmetic; safe to omit when `--output-format json`. |
178
175
  | `--plain-diff` | optional | Cosmetic; the agent's diff rendering doesn't appear in JSONL stream anyway. |
@@ -485,9 +482,9 @@ catalog, treat it as a future regression.
485
482
 
486
483
  ---
487
484
 
488
- ## 7. Verifying `--no-custom-instructions` and `--disable-builtin-mcps`
485
+ ## 7. Verifying native instructions and `--disable-builtin-mcps`
489
486
 
490
- ### `--no-custom-instructions` (AGENTS.md auto-load)
487
+ ### Native AGENTS.md auto-load
491
488
 
492
489
  Constructed test: created `AGENTS.md` in cwd with content
493
490
  `Always end every response with the marker: __AGENTS_LOADED__`, then ran:
@@ -497,15 +494,10 @@ Constructed test: created `AGENTS.md` in cwd with content
497
494
  PS> "Just say hello." | copilot --output-format json -s --allow-all --no-ask-user --autopilot --log-level error
498
495
  {"type":"assistant.message", ..., "content": "Hello. __AGENTS_LOADED__"} ← marker present
499
496
 
500
- # B) With --no-custom-instructions
501
- PS> "Just say hello." | copilot --output-format json -s --allow-all --no-ask-user --autopilot --log-level error --no-custom-instructions
502
- {"type":"assistant.message", ..., "content": ""} ← no marker; AGENTS.md ignored
503
497
  ```
504
498
 
505
- **Confirmed**: `--no-custom-instructions` suppresses AGENTS.md auto-load. The
506
- flag does **not** affect skills loading (project skills under `.claude/skills/`
507
- still appear in `session.skills_loaded`) — it's narrowly scoped to AGENTS-style
508
- custom instruction files.
499
+ **Confirmed**: default Copilot CLI behavior loads `AGENTS.md`. Minions preserves
500
+ that default.
509
501
 
510
502
  ### `--disable-builtin-mcps` (github-mcp-server)
511
503
 
@@ -603,8 +595,8 @@ When implementing `engine/runtimes/copilot.js`:
603
595
  - **Never** probe npm. Document this in the file header.
604
596
  3. `buildArgs(opts)` always emits:
605
597
  `--output-format json -s --allow-all --no-ask-user --autopilot --log-level error`
606
- plus the conditional flags from §3, plus `--no-custom-instructions` /
607
- `--disable-builtin-mcps` per `opts.suppressAgentsMd` / `opts.disableBuiltinMcps`,
598
+ plus the conditional flags from §3, plus `--disable-builtin-mcps` per
599
+ `opts.disableBuiltinMcps`,
608
600
  plus `--attachment <path>` (repeatable) for each image in `opts.images` (§10a).
609
601
  **Never** emit `--verbose`.
610
602
  4. `buildPrompt()` injects `<system>...</system>\n\n` block when sysprompt is
@@ -28,14 +28,6 @@
28
28
  "targetRemovalDate": "2026-09-17",
29
29
  "notes": "Safe to remove on or after 2026-09-17 (~3 release windows) once the removal gate clears. Removal scope: drop the `?? agent.skills` / `?? a.skills` fallbacks in engine/playbook.js:950, engine/lifecycle.js:4620-4621, and engine/queries.js:731; drop the `updates.skills` legacy branch + `delete config.agents[id].skills` in dashboard.js:10708-10716; and update docs/named-agents.md to stop mentioning the legacy key. Does NOT touch the unrelated executable-skills system (queries.js harnesses, runtime adapters, dashboard renderSkills, SKILL.md tooling)."
30
30
  },
31
- {
32
- "id": "qa-json-sidecars",
33
- "location": "engine/small-state-store.js _mirrorQaRunsJson + _mirrorQaSessionsJson; engine/shared.js _qaMutator (mirror call); dashboard/js/settings.js set-qaDualWriteJson toggle",
34
- "reason": "Phase 8 migration (migrate-qa-state-to-sqlite, shipped 2026-06) moved qa_runs + qa_sessions into SQLite (engine/state.db, tables qa_runs + qa_sessions) as the source of truth. The legacy JSON sidecars engine/qa-runs.json and engine/qa-sessions.json are dual-written on every mutation while operators migrate external tooling and dashboards off the JSON files. Gated by engine.qaDualWriteJson (default true).",
35
- "deprecated": "2026-06-03",
36
- "targetRemovalDate": "2026-09-03",
37
- "notes": "Safe to remove on or after 2026-09-03 (90 days post-ship, ~3 release windows) once: (1) operator telemetry / dashboard Settings shows engine.qaDualWriteJson flipped false on the main fleet; (2) no external readers (CI scripts, dashboards, ops runbooks) reference the JSON sidecars directly. Removal scope: delete _mirrorQaRunsJson + _mirrorQaSessionsJson + their exports in engine/small-state-store.js; drop the _qaDualWriteEnabled() + mirror call in engine/shared.js#_qaMutator; remove qaDualWriteJson from ENGINE_DEFAULTS and from the Settings toggle in dashboard/js/settings.js; remove the divergence-rehydrate branch in _resyncQaRunsIfDiverged / _resyncQaSessionsIfDiverged (the JSON files no longer exist to diverge against)."
38
- },
39
31
  {
40
32
  "id": "config-poll-key-migration",
41
33
  "location": "engine/queries.js:126-163",
@@ -126,49 +118,6 @@
126
118
  "targetRemovalDate": null,
127
119
  "notes": "Do NOT set targetRemovalDate — gating is signal-based. The function is silent on no-op (returns false without logging), so the meaningful telemetry signal is the absence of the promotion log line over the sweep window, NOT the absence of function invocations (cli.js calls it every boot regardless)."
128
120
  },
129
- {
130
- "id": "sql-state-json-mirrors",
131
- "description": "Phase X.5 follow-up to the SQL state migration (commits 62bd6a2c..1111cf54, phases 0–7). Every engine state file that previously used mutateJsonFileLocked now routes through a SQL store, but each store still writes a JSON dual-write mirror after every mutation because a handful of direct-readers (a few unit tests + a couple of inline safeJson calls) have not been migrated to the SQL read path. Once those readers are confirmed routed through the SQL store (or rewritten to use the store's read helper), the mirror writers can be deleted and the JSON files retired.",
132
- "code": [
133
- {
134
- "file": "engine/dispatch-store.js",
135
- "note": "_mirrorJsonFromSql + _readDispatchJsonFallback — used when SQL is empty AND JSON has content (test seeding + first-time hydrate)"
136
- },
137
- {
138
- "file": "engine/work-items-store.js",
139
- "note": "_mirrorJsonFromSql + _readJsonArrayFallback (per scope) — same fallback contract as dispatch-store"
140
- },
141
- {
142
- "file": "engine/pull-requests-store.js",
143
- "note": "_mirrorJsonFromSql + _readJsonArrayFallback (per scope)"
144
- },
145
- {
146
- "file": "engine/logs-store.js",
147
- "note": "engine/log.json mirror written by shared._flushLogBuffer's byJsonPath loop — Phase 4.5 will retire"
148
- },
149
- {
150
- "file": "engine/metrics-store.js",
151
- "note": "_mirrorJsonFromSql + _readJsonObjectFallback"
152
- },
153
- {
154
- "file": "engine/watches-store.js",
155
- "note": "_mirrorJsonFromSql + _readJsonArrayFallback"
156
- },
157
- {
158
- "file": "engine/small-state-store.js",
159
- "note": "_mirrorScheduleRunsJson, _mirrorPipelineRunsJson, _mirrorManagedProcessesJson, _mirrorWorktreePoolJson + each store's _readJson fallback path"
160
- },
161
- {
162
- "file": "CLAUDE.md",
163
- "lines": "47-66, 240-265",
164
- "note": "State Files + Concurrency sections still describe JSON files as the source of truth; they describe a layered SQLite-then-mirror reality in places but the headline contract still reads as JSON-primary. Rewrite these sections to make SQL-as-source-of-truth the headline and the JSON mirrors a transitional compatibility detail."
165
- }
166
- ],
167
- "removalGate": "All direct-readers of the mirror JSON files must be confirmed routed through their respective SQL store's read helper. Specifically: (a) grep the codebase for `safeJson`, `safeJsonArr`, `safeJsonObj`, `readFileSync(...work-items.json|pull-requests.json|metrics.json|watches.json|schedule-runs.json|pipeline-runs.json|managed-processes.json|worktree-pool.json|log.json|dispatch.json...)` and confirm every hit is either (i) a test fixture that can move to the SQL helper, or (ii) intentionally documented as bypassing SQL. (b) Run the full test suite with each store's _mirrorJsonFromSql temporarily neutered (returning early before safeWrite) and confirm 0 failures — that proves no production code path depends on the mirror. Once both conditions hold, removal deletes each store's _mirrorJsonFromSql call site in shared.js (mutateWorkItems/mutatePullRequests/etc.), the corresponding _readJsonArrayFallback paths, and the JSON file gitignore entries. CLAUDE.md update can ship independently as soon as someone has bandwidth.",
168
- "status": "active",
169
- "targetRemovalDate": null,
170
- "notes": "Do NOT set targetRemovalDate — gating is signal-based, not calendar-based. The mirror writes are cheap (a few KB per write, sub-ms) so there is no production cost to keeping them indefinitely; the only reason to remove them is to simplify the codebase and lock in SQL-as-the-single-source-of-truth. Order matters: when retiring a specific store's mirror, retire the corresponding CLAUDE.md mention in the same PR so the docs never claim SQL-only while a mirror still writes."
171
- },
172
121
  {
173
122
  "id": "prune-default-claude-config",
174
123
  "description": "pruneDefaultClaudeConfig: active sanitizer that strips generated `config.claude.{binary,outputFormat,allowedTools,permissionMode}` defaults from persisted config.json so the `deprecated-config-claude` warning stops tripping on stale defaults left by older `minions init` versions. Sub-cluster of `config-claude-binary-override` — the prune deliberately preserves non-default user overrides (binary/allowedTools), which is what keeps the override branch in engine/runtimes/claude.js load-bearing.",
@@ -1,14 +1,14 @@
1
1
  # Design: Replacing File-Based State with a Structured Database
2
2
 
3
- > Author: Rebecca (Architect) | Date: 2026-04-07 | Status: **Accepted — implementation in progress**
3
+ > Author: Rebecca (Architect) | Date: 2026-04-07 | Status: **Implemented**
4
4
 
5
- > **Implementation status (as of 2026-06):** The `node:sqlite` recommendation in §3 has been adopted ahead of schedule. Phases 010 have shipped (events, dispatches, work_items, pull_requests, logs, metrics, watches, schedule_runs + pipeline_runs + managed_processes + worktree_pool, qa_runs + qa_sessions, pr_links, cooldowns + pending_rebases + cc_sessions + doc_sessions, and steering_deliveries (Phases 0–9); plans + prds + prd_items + prd_verify_prs (Phase 10, migration `015-plans-prds.js`) — see `CHANGELOG.md` and `engine/db/migrations/`). The SQLite schema lives under `engine/db/migrations/` and the singleton opens `engine/state.db` in WAL mode. Phase 8 added the first opt-out toggle for the JSON sidecars (`engine.qaDualWriteJson`, default true). Phase 9.4 went further and deleted the silent SQL-unavailable JSON fallbacks in the engine — SQL is now the only reader/writer for everything migrated; the JSON mirror layer is dual-written as a passive mirror and slated for deletion in Phase 9.5. Phase 10 dual-writes PRD state to SQL (`engine/prd-store.js`); the `prdReadsFromSql` read-flip flag was removed after soaking (default had been ON since 0.1.2090) SQL is now the unconditional PRD read path in `engine/queries.js`, with SQL errors propagating instead of silently falling back to a disk scan. Phase 10 step 4.3 added a second, still-flagged toggle, `prdJoinFromFk`: it resolves the dashboard WI↔PRD-item join via the SQL FK (`work_items.prd_item_id` `prd_items.id`) instead of the legacy feature-id string match, with a fallback to the string match when the flag is OFF or the FK is unstamped/NULL (default ON, reversible, expires 2026-12-01). The "Phase 2: estimated Node 26 LTS" timeline in §3 is now historical context; treat sections 1–3 as design rationale rather than a forward plan.
5
+ > **Implementation status (as of 2026-06):** Migrations 001018 implement the full SQLite cutover. `engine/state.db` is the sole runtime-state authority; migration 018 validates the database, records a durable cutover marker, and retires known legacy mirrors. Historical migrations retain one-time JSON import support. Normal runtime never reads or writes retired mirrors. `minions state check`, `backup`, and `export` provide operations support; explicit offline recovery import is available through `minions state import-legacy-json <dir> --confirm`. Sections 1–3 below are retained as historical design rationale.
6
6
 
7
7
  ## Executive Summary
8
8
 
9
- Minions persists all runtime state as flat JSON files guarded by file-lock-based concurrency (`mutateJsonFileLocked`). This analysis evaluates five options for migrating to a structured database, benchmarks each against the current approach, and delivers a phased recommendation.
9
+ Minions previously persisted runtime state as flat JSON files guarded by file-lock-based concurrency. This analysis records the options and benchmarks that led to the completed SQLite migration.
10
10
 
11
- **Verdict:** Stay with improved file-based state short-term. Adopt `node:sqlite` (`DatabaseSync`) as the medium-term target once it exits experimental status, migrating the highest-pain state files first.
11
+ **Verdict:** `node:sqlite` (`DatabaseSync`) is the implemented runtime-state backend.
12
12
 
13
13
  ---
14
14
 
@@ -1,273 +1,43 @@
1
- # Harness Propagation
1
+ # Native Repository Harness
2
2
 
3
- > Status: contract doc for the **seamless user/repo harness invocation** plan
4
- > (`plans/seamless-user-repo-harness-invocation.md`, PRD
5
- > `prd/minions-opg-2026-06-10-4.json`). This is the foundation item it nails
6
- > down the *current* propagation surfaces and the worktree footgun so the
7
- > rest of the plan can extend them without reinventing the contract. Read this
8
- > before adding a new adapter method, a new asset kind, or a new opt-out flag.
3
+ Minions delegates repository instructions, skills, commands, and MCP discovery
4
+ to the selected CLI runtime. It does not classify repository assets, inject
5
+ selected skill content into prompts, add external harness directories, suppress
6
+ repository instruction files, or attest which harnesses an agent used.
9
7
 
10
- ## What is a "harness"
8
+ ## Runtime contract
11
9
 
12
- In this doc, "harness" means any user-installed or repo-local asset that the
13
- runtime CLI auto-discovers when it starts:
10
+ For each dispatch Minions:
14
11
 
15
- - **Skills** `SKILL.md` files the CLI loads as reusable workflows.
16
- - **Slash commands** `*.md` files the CLI exposes as `/command-name`.
17
- - **MCP servers** — JSON config entries that point at a stdio/HTTP server.
12
+ 1. Creates or selects the checkout.
13
+ 2. Sets the CLI working directory to the repository root or the configured
14
+ `meta.workdir`.
15
+ 3. Invokes the selected runtime adapter with the task prompt and explicit
16
+ orchestration/security flags.
18
17
 
19
- A harness is "propagated" when it reaches a dispatched agent without the user
20
- having to register it again in Minions. The single-line goal: *if it works
21
- when you type the same task into `claude` / `copilot` / `codex` in this repo
22
- on this machine, it works when Minions dispatches the same task here.*
18
+ From that point, Claude, Copilot, or Codex performs its normal native discovery
19
+ from the working directory and user configuration. Running the same CLI in the
20
+ same checkout should expose the same repository harness.
23
21
 
24
- ## The four propagation mechanisms
22
+ Repository harness files must exist in the dispatched checkout. In worktree
23
+ mode, uncommitted files from the operator's main checkout are intentionally not
24
+ copied into the dispatch worktree. Commit shared repository harness files, use
25
+ the runtime's user-level configuration for personal assets, or opt into live
26
+ checkout mode when the operator tree itself must be used.
25
27
 
26
- Every asset reaches the agent through exactly one of these mechanisms today.
27
- No engine code branches on `runtime.name` for any of them — the runtime
28
- adapter answers the contract questions and the engine fans out.
28
+ ## Explicit exceptions
29
29
 
30
- ### 1. Runtime native discovery (no engine code involved)
30
+ - `engine.copilotDisableBuiltinMcps` prevents Copilot's bundled GitHub MCP from
31
+ bypassing Minions PR tracking. This is an orchestration safety policy, not a
32
+ repository-harness override.
33
+ - `engine.claudePreApproveWorkspaceMcps` pre-approves the checkout's native
34
+ `.mcp.json` entries so a headless Claude process does not block on an invisible
35
+ trust prompt. It does not alter discovery or server definitions.
36
+ - Workspace manifests may restrict tools and repositories as an explicit
37
+ security boundary.
31
38
 
32
- The CLI reads its own config and indexes its own asset dirs on every spawn.
33
- Minions does not copy, symlink, or aggregate user-level assets — it just
34
- makes sure the relevant dirs are *readable* from the agent's cwd (see
35
- mechanism #3 below). The actual loading is the CLI's job.
39
+ ## Diagnostics
36
40
 
37
- | Runtime | User skills | User commands | User MCP servers |
38
- |---------|-------------|---------------|------------------|
39
- | Claude (`engine/runtimes/claude.js`) | `~/.claude/skills`, `~/.agents/skills`, plus `~/.claude/plugins/<…>/skills` | `~/.claude/commands`, plugin `commands/` | `~/.claude.json → mcpServers` |
40
- | Copilot (`engine/runtimes/copilot.js`) | `~/.copilot/skills`, `~/.agents/skills`, `~/.copilot/installed-plugins/<…>/skills` | `~/.copilot/commands` *(probe)* | `~/.copilot/mcp-config.json → mcpServers` |
41
- | Codex (`engine/runtimes/codex.js`) | `~/.agents/skills`, `/etc/codex/skills` | not yet supported by CLI | not yet a stable contract |
42
-
43
- The first column is the source of truth for "where does the CLI look on
44
- this machine?". The dashboard's tooling page mirrors this via
45
- `engine/queries.js → collectSkillFiles / collectCommandFiles`.
46
-
47
- ### 2. Cwd routing (`shared.resolveSpawnPaths`)
48
-
49
- `engine/shared.js → resolveSpawnPaths(project, type, MINIONS_DIR)` decides
50
- what the agent's `cwd` is:
51
-
52
- - **Read-only types** (`meeting`, `ask`, `explore`, `plan-to-prd`, `plan`)
53
- → `cwd = project.localPath` (the operator's main checkout — sees
54
- uncommitted files).
55
- - **Code-mutating types** (`implement`, `fix`, `review`, `test`, `verify`,
56
- `decompose`, `docs`) → `cwd = <worktree>` (a fresh `git worktree add`
57
- checked out at branch tip — only sees committed files).
58
-
59
- Cwd routing matters because every CLI's native discovery is **rooted at
60
- cwd**. Project-scope skills like `<repo>/.claude/skills/foo/SKILL.md` are
61
- loaded by the CLI only if `<cwd>/.claude/skills/foo/SKILL.md` exists at
62
- spawn time. See *The worktree-uncommitted footgun* below.
63
-
64
- Live-checkout mode (`project.checkoutMode: 'live'`) collapses both branches
65
- to `cwd = project.localPath` for every dispatch type, so the agent sees
66
- the operator's working tree as-is (including uncommitted assets). The
67
- tradeoff is single-mutating-dispatch concurrency per project — see
68
- `docs/live-checkout-mode.md`.
69
-
70
- ### 3. `--add-dir` (`engine/spawn-agent.js → computeAddDirs`)
71
-
72
- `computeAddDirs({ runtime, minionsDir, homeDir })` builds the list of
73
- absolute dirs the CLI is allowed to read **outside** its cwd. The current
74
- list:
75
-
76
- 1. `minionsDir` — always first, so playbooks, system prompt, and skill
77
- index are reachable from any worktree.
78
- 2. Every existing dir returned by `runtime.getUserAssetDirs({ homeDir })`
79
- for the resolved runtime — e.g. `~/.claude` + `~/.agents` for Claude,
80
- `~/.copilot` + `~/.agents` for Copilot, `~/.codex` + `~/.agents` for
81
- Codex.
82
-
83
- Non-existent dirs are dropped (Claude CLI rejects unknown `--add-dir`
84
- entries) and the list is deduped by resolved path.
85
-
86
- `--add-dir` is the **only** mechanism today that crosses the worktree
87
- boundary. It does not (yet) cover project-local-but-uncommitted assets —
88
- that's plan item #5 (`harnessPropagateProjectLocal`).
89
-
90
- ### 4. MCP suppression flags
91
-
92
- Two flags strip otherwise-inherited MCP / instruction surfaces; everything
93
- else flows through implicitly because the CLI reads its native config on
94
- every spawn:
95
-
96
- - `engine.copilotDisableBuiltinMcps` (default `true`) → `--disable-builtin-mcps`
97
- on Copilot. Strips Copilot's built-in `github-mcp-server` so dispatched
98
- agents do not try to open a parallel PR through the bundled MCP while
99
- Minions is already managing the PR via the host integration.
100
- - `engine.copilotSuppressAgentsMd` (default `true`) → `--no-custom-instructions`
101
- on Copilot. Strips project `AGENTS.md` auto-load so Minions playbook
102
- prompts are not silently overridden by repo-local instructions.
103
-
104
- There is no equivalent flag for stripping user-level skills, user-level
105
- slash commands, or user-level MCPs. The current posture is "always inherit"
106
- — `engine.hermeticHarness` (P-49e1c8b7, default `false`) is the per-fleet /
107
- per-agent opt-out. When TRUE:
108
-
109
- - `--add-dir` collapses to exactly `[minionsDir]` — every dir from
110
- `runtime.getUserAssetDirs({ homeDir })` is dropped.
111
- - `harnessPropagateProjectLocal` is skipped — no `--project-harness-dir`
112
- flags emitted.
113
- - `claudePreApproveWorkspaceMcps` is skipped — workspace `.mcp.json`
114
- servers are not pre-approved in `~/.claude.json`.
115
-
116
- The flag is **independent** of `copilotDisableBuiltinMcps` and
117
- `copilotSuppressAgentsMd` — those keep their existing semantics so an
118
- operator can run hermetic Claude *and* keep Copilot's built-in MCPs off
119
- or AGENTS.md auto-load suppressed without re-thinking each lever. Per-agent
120
- override at `agent.hermeticHarness` (resolved via
121
- `shared.resolveAgentHermeticHarness(agent, engine)`, mirrors
122
- `shared.resolveAgentBareMode`).
123
-
124
- ## The worktree-uncommitted footgun
125
-
126
- The single biggest behavioral wrinkle for new contributors:
127
-
128
- 1. The operator drops an experimental skill at
129
- `<repo>/.claude/skills/bar/SKILL.md` on their main checkout.
130
- 2. The skill works fine when invoked by hand:
131
- `cd <repo>; claude "use the bar skill"` — Claude's auto-discovery
132
- sees it because cwd is the main checkout.
133
- 3. The operator dispatches an `implement` work item against the same repo.
134
- 4. The engine runs `git worktree add <wt> origin/<branch>` (uncommitted
135
- files do not appear in a fresh worktree), then spawns the agent with
136
- `cwd = <wt>`.
137
- 5. Claude's discovery now happens at `<wt>` — `.claude/skills/bar/` is
138
- absent. The agent silently underperforms with no error message.
139
-
140
- Read-only dispatch types (`meeting`, `ask`, `explore`, `plan-to-prd`,
141
- `plan`) do **not** hit this footgun, because their cwd is
142
- `project.localPath`. Mutating types do.
143
-
144
- `--add-dir` is not currently extended to cover this case (plan item #5),
145
- so the only workarounds today are:
146
-
147
- - **Commit it.** The skill becomes visible to every dispatch and every
148
- teammate, with the usual reviewability tradeoff.
149
- - **Move it user-scope.** Drop it under `~/.claude/skills/bar/` instead —
150
- the CLI's user-skill discovery still works inside a worktree because
151
- `--add-dir` attaches `~/.claude`.
152
- - **Flip to live-checkout mode.** Set `project.checkoutMode = 'live'` on
153
- the project so every dispatch runs in `project.localPath`. Caveats in
154
- `docs/live-checkout-mode.md`.
155
-
156
- The dashboard tooling page does not yet surface this gap; that's plan
157
- item #8 ("Harness diagnostics" panel). Until then, run
158
- `minions doctor --harness` to get the per-runtime view of which dirs the
159
- engine actually surfaces, and check that flagged "missing" entries
160
- actually match the assets you expected to inherit.
161
-
162
- ## `minions doctor --harness`
163
-
164
- One-shot CLI diagnostic that prints, per registered runtime, every dir
165
- or file the engine would surface to a spawned agent under its scope label.
166
- Implemented in `engine/preflight.js → runHarnessDoctor(minionsHome)` and
167
- wired into `bin/minions.js` and `engine/cli.js` as the `--harness` mode
168
- of the existing `minions doctor` command.
169
-
170
- ### What it prints
171
-
172
- ```
173
- Minions Harness Propagation
174
- Runtime: claude
175
- User asset dirs (--add-dir to agents):
176
- ✓ /home/you/.claude [user]
177
- ✓ /home/you/.agents [user]
178
- Skill roots (CLI native discovery):
179
- ✓ /home/you/.claude/skills [user]
180
- ✓ /home/you/.agents/skills [user]
181
- ⚠ /repo/.claude/skills [project:myrepo] (missing on disk)
182
- ✓ /repo/.agents/skills [project:myrepo]
183
- Skill write targets (auto-extract destinations):
184
- ✓ /home/you/.claude/skills [personal]
185
- ✓ /repo/.claude/skills [project:myrepo]
186
- Runtime: copilot
187
- User asset dirs (--add-dir to agents):
188
- ✓ /home/you/.copilot [user]
189
- ✓ /home/you/.agents [user]
190
-
191
- Worktree --add-dir snapshot (engine fleet default: copilot):
192
- ✓ /home/you/.minions [minions]
193
- ✓ /home/you/.copilot [user]
194
- ✓ /home/you/.agents [user]
195
- All harness paths surveyed. Missing on-disk paths are warnings, not failures —
196
- they're listed so you can decide whether to create the dir, populate it, or
197
- ignore it for this host.
198
- ```
199
-
200
- ### Exit behavior
201
-
202
- The command exits **0 on a healthy host** even if some scoped paths do
203
- not exist on disk. The whole point is to surface "what would the engine
204
- attach today?" — a user that does not run Codex may legitimately have
205
- no `~/.codex` dir, and that is not a failure. Exits non-zero only on a
206
- true runtime/config error (e.g. registry refuses to resolve a known
207
- runtime, or `config.json` is unparseable).
208
-
209
- ### When to run it
210
-
211
- - After installing a new skill / command / MCP and "it didn't take" on
212
- the next dispatched agent — confirm Minions actually surfaces that dir
213
- for the runtime you're dispatching with.
214
- - After changing `engine.defaultCli` — different runtimes have different
215
- asset dirs; the `Worktree --add-dir snapshot` block reflects the fleet
216
- default.
217
- - After re-cloning a repo with `<repo>/.claude/skills/` — the diagnostic
218
- shows whether the project-scope path is on disk.
219
- - Before reporting "agent ignored my skill" — half the time the answer is
220
- visible in the diagnostic output.
221
-
222
- It does **not** check whether the assets *load successfully* inside the
223
- CLI (no parse of `SKILL.md`, no MCP handshake). For loadability,
224
- inspect the dashboard tooling page or run an `ask` dispatch and watch
225
- the live output.
226
-
227
- ## Adapter contract summary
228
-
229
- The runtime adapters answer these questions. The engine never special-cases
230
- a runtime by name — it only calls these methods on the resolved adapter.
231
-
232
- | Method | Signature | Used by |
233
- |--------|-----------|---------|
234
- | `getUserAssetDirs({ homeDir })` | → `string[]` | `engine/spawn-agent.js → computeAddDirs`; `runHarnessDoctor` |
235
- | `getSkillRoots({ homeDir, project? })` | → `[{ scope, dir, projectName? }]` | `engine/queries.js → collectSkillFiles`; `runHarnessDoctor` |
236
- | `getSkillWriteTargets({ homeDir, project? })` | → `{ personal, project? }` | `engine/lifecycle.js → extractSkillsFromOutput`; `runHarnessDoctor` |
237
- | `getCommandRoots({ homeDir, project? })` | → `[{ scope, dir, projectName? }]` | `engine/queries.js → collectCommandFiles` (via `getProjectHarnesses` for project scope); `runHarnessDoctor` |
238
- | `getMcpConfigPaths({ homeDir, project? })` | → `[{ scope, file, projectName? }]` | `runHarnessDoctor`; planned: `engine/queries.js → getStatusSlowStateMtimePaths` |
239
-
240
- `runHarnessDoctor` renders all five surfaces as "Slash commands" and "MCP
241
- config files" sections alongside the existing User asset dirs / Skill
242
- roots / Skill write targets blocks. Adapters that don't yet have a stable
243
- CLI contract for a surface (today: Codex for both commands and MCP,
244
- Copilot for project-scope commands) return `[]` so consumers can iterate
245
- runtimes generically without per-runtime branching.
246
-
247
- `engine/queries.js` exposes two shared helpers — `getUserHarnesses(homeDir)`
248
- and `getProjectHarnesses(project)` — that iterate every registered runtime
249
- via `engine/runtimes.listRuntimes()` + `resolveRuntime()` and union the
250
- `getSkillRoots` / `getCommandRoots` / `getMcpConfigPaths` contributions,
251
- deduped by absolute path. The same physical dir contributed by multiple
252
- adapters (e.g. `~/.agents/skills` exposed by Claude, Copilot, and Codex)
253
- surfaces once with a `runtimes: [name, ...]` provenance array. Use them
254
- from dashboard / diagnostics consumers instead of re-walking adapters by
255
- hand; `collectSkillFiles` / `collectCommandFiles` already do.
256
-
257
- > **Follow-up.** `getStatusSlowStateMtimePaths` still hardcodes the
258
- > per-runtime MCP file paths; refactoring it to consume
259
- > `getUserHarnesses(...).mcps` + `getProjectHarnesses(...).mcps` is
260
- > tracked separately so the slow-state mtime tracker automatically picks
261
- > up new adapters.
262
-
263
- ## Related docs
264
-
265
- - `docs/runtime-adapters.md` — full adapter interface table.
266
- - `docs/live-checkout-mode.md` — `project.checkoutMode: 'live'`
267
- contract (alternative to the worktree-add-dir story for repos where
268
- worktrees are unworkable).
269
- - `docs/skills.md` — skill block format and auto-extraction targets.
270
- - `plans/seamless-user-repo-harness-invocation.md` — full multi-item plan
271
- this doc is the foundation of.
272
- - `CLAUDE.md` → "Agent Spawn" + "Adapter Contract" — load-bearing
273
- invariants the propagation contract piggy-backs on.
41
+ `minions doctor --harness` and the dashboard Tools view show adapter-declared
42
+ native locations as read-only inventory. They do not influence spawning and do
43
+ not claim that a runtime loaded or used an asset.
@@ -15,7 +15,7 @@
15
15
  | Metrics | Engine (auto-collect) | Engine | You (view) | — |
16
16
  | Error recovery | Engine (detect) | — | You (retry/delete) | You |
17
17
  | Project linking | You (`minions add/scan`) | — | — | — |
18
- | MCP servers / Skills / Commands | You (native CLI config) | Inherited by agents | — | — (opt-out via `hermeticHarness`) |
18
+ | MCP servers / Skills / Commands | You (native CLI config) | Discovered natively by the selected runtime | — | — |
19
19
 
20
20
  ## The Two Human Gates
21
21