@mmerterden/multi-agent-pipeline 17.6.0 → 19.0.0

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 (272) hide show
  1. package/CHANGELOG.md +310 -0
  2. package/README.md +76 -18
  3. package/README.tr.md +55 -16
  4. package/docs/adr/0002-instruction-driven-flag.md +1 -0
  5. package/docs/adr/0005-lazy-phase-docs.md +11 -1
  6. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +1 -0
  7. package/docs/adr/0010-own-code-graph.md +1 -0
  8. package/docs/adr/0011-dormant-ci.md +25 -1
  9. package/docs/adr/0014-six-phase-consolidation.md +134 -0
  10. package/docs/adr/README.md +2 -1
  11. package/docs/architecture.md +37 -38
  12. package/docs/best-practices.md +1 -1
  13. package/docs/ecosystem.md +37 -26
  14. package/docs/engineering.md +1 -1
  15. package/docs/facts.json +45 -0
  16. package/docs/features.md +54 -53
  17. package/docs/performance.md +5 -5
  18. package/docs/recovery-guide.md +9 -9
  19. package/docs/server-readiness.md +188 -0
  20. package/docs/token-budget-history.md +3 -1
  21. package/index.js +18 -3
  22. package/install/_codex-agents.mjs +1 -1
  23. package/install/_common.mjs +42 -17
  24. package/install/_dev-only-files.mjs +8 -0
  25. package/install/_unattended-profile.mjs +113 -0
  26. package/install/index.mjs +48 -0
  27. package/install/templates/claude-hooks.json +1 -1
  28. package/install/templates/codex-instructions.md +1 -1
  29. package/install/templates/copilot-instructions.md +28 -28
  30. package/manifest.json +1065 -0
  31. package/package.json +6 -3
  32. package/pipeline/agents/dev-critic.md +3 -3
  33. package/pipeline/commands/figma-to-swiftui.md +1 -1
  34. package/pipeline/commands/multi-agent/SKILL.md +8 -8
  35. package/pipeline/commands/multi-agent/analysis/SKILL.md +9 -9
  36. package/pipeline/commands/multi-agent/autopilot/SKILL.md +7 -7
  37. package/pipeline/commands/multi-agent/channels/SKILL.md +15 -15
  38. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +6 -6
  39. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  40. package/pipeline/commands/multi-agent/graph/SKILL.md +1 -1
  41. package/pipeline/commands/multi-agent/help/SKILL.md +62 -62
  42. package/pipeline/commands/multi-agent/language/SKILL.md +2 -2
  43. package/pipeline/commands/multi-agent/local/SKILL.md +11 -11
  44. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +13 -13
  45. package/pipeline/commands/multi-agent/log/SKILL.md +2 -2
  46. package/pipeline/commands/multi-agent/manual-test/SKILL.md +9 -9
  47. package/pipeline/commands/multi-agent/model/SKILL.md +69 -0
  48. package/pipeline/commands/multi-agent/refactor/SKILL.md +3 -3
  49. package/pipeline/commands/multi-agent/resume/SKILL.md +4 -4
  50. package/pipeline/commands/multi-agent/resume-local/SKILL.md +19 -17
  51. package/pipeline/commands/multi-agent/review/SKILL.md +1 -1
  52. package/pipeline/commands/multi-agent/route-off/SKILL.md +36 -0
  53. package/pipeline/commands/multi-agent/route-on/SKILL.md +74 -0
  54. package/pipeline/commands/multi-agent/route-status/SKILL.md +56 -0
  55. package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
  56. package/pipeline/commands/multi-agent/status/SKILL.md +54 -23
  57. package/pipeline/commands/multi-agent/steer/SKILL.md +2 -2
  58. package/pipeline/commands/multi-agent/sync/SKILL.md +12 -13
  59. package/pipeline/commands/multi-agent/test/SKILL.md +1 -1
  60. package/pipeline/lib/_jira-auth.sh +8 -0
  61. package/pipeline/lib/analysis-jira-write.sh +32 -0
  62. package/pipeline/lib/ask-choice.sh +13 -2
  63. package/pipeline/lib/autopilot-state.sh +8 -0
  64. package/pipeline/lib/credential-inventory.sh +1 -1
  65. package/pipeline/lib/fatal.mjs +129 -0
  66. package/pipeline/lib/fetch-fortify.sh +1 -1
  67. package/pipeline/lib/figma-mcp-refresh.sh +18 -0
  68. package/pipeline/lib/figma-screenshot.sh +18 -0
  69. package/pipeline/lib/invoked-directly.mjs +43 -0
  70. package/pipeline/lib/jira-publish.sh +42 -0
  71. package/pipeline/lib/md2confluence-v3.py +47 -0
  72. package/pipeline/lib/model-rung.sh +142 -0
  73. package/pipeline/lib/outbound-gate.mjs +175 -0
  74. package/pipeline/lib/phase-schema.mjs +88 -0
  75. package/pipeline/lib/plan-todos.sh +32 -11
  76. package/pipeline/lib/post-pr-review.sh +77 -8
  77. package/pipeline/lib/repo-hygiene.sh +8 -3
  78. package/pipeline/lib/require-jq.sh +40 -0
  79. package/pipeline/lib/route-state.sh +161 -0
  80. package/pipeline/lib/run-paths.sh +335 -0
  81. package/pipeline/multi-agent-refs/_account-picker.md +1 -1
  82. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  83. package/pipeline/multi-agent-refs/_input-parser.md +1 -1
  84. package/pipeline/multi-agent-refs/analysis/evidence.md +0 -9
  85. package/pipeline/multi-agent-refs/analysis/intake.md +1 -1
  86. package/pipeline/multi-agent-refs/analysis/locked.md +21 -22
  87. package/pipeline/multi-agent-refs/analysis/render.md +1 -1
  88. package/pipeline/multi-agent-refs/analysis/synthesis.md +12 -6
  89. package/pipeline/multi-agent-refs/android-guide.md +1 -1
  90. package/pipeline/multi-agent-refs/audit-guide.md +13 -13
  91. package/pipeline/multi-agent-refs/channels/issue-comment.md +2 -2
  92. package/pipeline/multi-agent-refs/channels/jira.md +3 -3
  93. package/pipeline/multi-agent-refs/channels/pr.md +4 -4
  94. package/pipeline/multi-agent-refs/channels/wiki.md +1 -1
  95. package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
  96. package/pipeline/multi-agent-refs/cross-cli-contract.md +31 -6
  97. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +74 -4
  98. package/pipeline/multi-agent-refs/features/code-graph.md +5 -5
  99. package/pipeline/multi-agent-refs/features/cost-analysis.md +93 -0
  100. package/pipeline/multi-agent-refs/features/design-conformance.md +1 -1
  101. package/pipeline/multi-agent-refs/features/dev-critic.md +3 -3
  102. package/pipeline/multi-agent-refs/features/doctor.md +47 -2
  103. package/pipeline/multi-agent-refs/features/external-context-injection.md +3 -3
  104. package/pipeline/multi-agent-refs/features/maturity-followup.md +3 -3
  105. package/pipeline/multi-agent-refs/features/model-fallback.md +5 -5
  106. package/pipeline/multi-agent-refs/features/plan-todos.md +1 -1
  107. package/pipeline/multi-agent-refs/features/repo-map.md +1 -1
  108. package/pipeline/multi-agent-refs/features/review-delta.md +3 -3
  109. package/pipeline/multi-agent-refs/features/review-multi-repo.md +1 -1
  110. package/pipeline/multi-agent-refs/features/scope-check.md +4 -4
  111. package/pipeline/multi-agent-refs/features/skill-conformance.md +2 -2
  112. package/pipeline/multi-agent-refs/features/stack-skill-routing.md +1 -1
  113. package/pipeline/multi-agent-refs/features/verify-by-test.md +4 -4
  114. package/pipeline/multi-agent-refs/features/verify.md +83 -0
  115. package/pipeline/multi-agent-refs/features/visual-evidence.md +19 -19
  116. package/pipeline/multi-agent-refs/features/worktree-finalize.md +6 -6
  117. package/pipeline/multi-agent-refs/issue-jira-triad.md +10 -10
  118. package/pipeline/multi-agent-refs/knowledge.md +11 -11
  119. package/pipeline/multi-agent-refs/multi-repo-integration-build.md +13 -13
  120. package/pipeline/multi-agent-refs/payload-contracts.md +8 -8
  121. package/pipeline/multi-agent-refs/phases/log-format.md +10 -10
  122. package/pipeline/multi-agent-refs/phases/modes.md +30 -30
  123. package/pipeline/multi-agent-refs/phases/operations.md +21 -10
  124. package/pipeline/multi-agent-refs/phases/phase-0-init.md +25 -25
  125. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +599 -0
  126. package/pipeline/multi-agent-refs/phases/{phase-3-dev.md → phase-2-dev.md} +129 -49
  127. package/pipeline/multi-agent-refs/phases/{phase-4-review.md → phase-3-review.md} +225 -107
  128. package/pipeline/multi-agent-refs/phases/{phase-6-commit.md → phase-4-commit.md} +23 -23
  129. package/pipeline/multi-agent-refs/phases/{phase-7-report.md → phase-5-report.md} +29 -29
  130. package/pipeline/multi-agent-refs/phases.md +44 -48
  131. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  132. package/pipeline/multi-agent-refs/progress-contract.md +6 -6
  133. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  134. package/pipeline/multi-agent-refs/rules.md +7 -7
  135. package/pipeline/multi-agent-refs/swiftui-guide.md +2 -2
  136. package/pipeline/multi-agent-refs/tracker-contract.md +31 -32
  137. package/pipeline/multi-agent-refs/unattended-contract.md +129 -0
  138. package/pipeline/multi-agent-refs/wiki-capture.md +14 -14
  139. package/pipeline/preferences-template.json +9 -1
  140. package/pipeline/rules/outside-the-pipeline.md +1 -1
  141. package/pipeline/schemas/agent-state.schema.json +50 -50
  142. package/pipeline/schemas/analysis-output.schema.json +2 -2
  143. package/pipeline/schemas/autopilot-config.schema.json +1 -1
  144. package/pipeline/schemas/code-graph.schema.json +1 -1
  145. package/pipeline/schemas/criteria-manifest.schema.json +1 -1
  146. package/pipeline/schemas/dev-critic-output.schema.json +1 -1
  147. package/pipeline/schemas/diff-risk.schema.json +1 -1
  148. package/pipeline/schemas/migrations/prefs-2.4.0-to-2.5.0.mjs +2 -2
  149. package/pipeline/schemas/migrations/prefs-2.6.0-to-2.7.0.mjs +31 -0
  150. package/pipeline/schemas/migrations/state-2.1.0-to-2.2.0.mjs +129 -0
  151. package/pipeline/schemas/phases.json +105 -0
  152. package/pipeline/schemas/plan-todos.schema.json +5 -5
  153. package/pipeline/schemas/planning-output.schema.json +1 -1
  154. package/pipeline/schemas/prefs.schema.json +100 -56
  155. package/pipeline/schemas/reviewer-output.schema.json +3 -3
  156. package/pipeline/schemas/route-config.schema.json +74 -0
  157. package/pipeline/schemas/scope-check.schema.json +1 -1
  158. package/pipeline/schemas/test-gap.schema.json +1 -1
  159. package/pipeline/schemas/token-budget.json +12 -18
  160. package/pipeline/schemas/triage-output.schema.json +6 -6
  161. package/pipeline/scripts/README.md +3 -3
  162. package/pipeline/scripts/_code-graph.mjs +2 -2
  163. package/pipeline/scripts/_run-paths.mjs +372 -0
  164. package/pipeline/scripts/_smoke-root.sh +1 -1
  165. package/pipeline/scripts/aggregate-metrics.mjs +65 -65
  166. package/pipeline/scripts/autopilot-arming.mjs +2 -1
  167. package/pipeline/scripts/autopilot-intake.mjs +2 -1
  168. package/pipeline/scripts/autopilot-runner.mjs +206 -2
  169. package/pipeline/scripts/build-references.mjs +2 -1
  170. package/pipeline/scripts/build-stack-plugins.mjs +10 -2
  171. package/pipeline/scripts/capture-evidence.sh +7 -2
  172. package/pipeline/scripts/capture-flush.sh +8 -8
  173. package/pipeline/scripts/capture-resume.sh +3 -3
  174. package/pipeline/scripts/classify-plan-safety.mjs +3 -2
  175. package/pipeline/scripts/cost-analyze.mjs +600 -0
  176. package/pipeline/scripts/cost-budget-check.mjs +4 -12
  177. package/pipeline/scripts/council-view.mjs +2 -1
  178. package/pipeline/scripts/crush-json.mjs +2 -1
  179. package/pipeline/scripts/diff-explain.mjs +7 -10
  180. package/pipeline/scripts/diff-risk-score.mjs +2 -1
  181. package/pipeline/scripts/doctor.mjs +140 -6
  182. package/pipeline/scripts/evidence-gate.mjs +9 -3
  183. package/pipeline/scripts/feedback-send.mjs +12 -2
  184. package/pipeline/scripts/gc-abandoned.sh +32 -16
  185. package/pipeline/scripts/gc-tmp.sh +1 -1
  186. package/pipeline/scripts/gc-worktrees.sh +12 -5
  187. package/pipeline/scripts/gen-facts.mjs +175 -0
  188. package/pipeline/scripts/gen-mode-dispatch.mjs +32 -37
  189. package/pipeline/scripts/gen-ref-toc.mjs +1 -1
  190. package/pipeline/scripts/github-ssh-setup.sh +64 -7
  191. package/pipeline/scripts/graph-mermaid.mjs +4 -2
  192. package/pipeline/scripts/graph-report.mjs +1 -1
  193. package/pipeline/scripts/jira-attach.sh +1 -1
  194. package/pipeline/scripts/keychain-save.sh +101 -30
  195. package/pipeline/scripts/learn-from-transcripts.mjs +3 -2
  196. package/pipeline/scripts/learning-curve.mjs +36 -31
  197. package/pipeline/scripts/log-metric.sh +17 -4
  198. package/pipeline/scripts/make-manifest.mjs +199 -0
  199. package/pipeline/scripts/memory-save.sh +1 -1
  200. package/pipeline/scripts/migrate-prefs.mjs +24 -6
  201. package/pipeline/scripts/migrate-state.mjs +94 -4
  202. package/pipeline/scripts/phase-banner.sh +26 -22
  203. package/pipeline/scripts/phase-tracker.sh +48 -10
  204. package/pipeline/scripts/plan-coverage-gate.mjs +8 -4
  205. package/pipeline/scripts/pre-commit-check.sh +7 -0
  206. package/pipeline/scripts/pre-push-check.sh +7 -0
  207. package/pipeline/scripts/purge.sh +23 -6
  208. package/pipeline/scripts/render-agent-log-cost.sh +10 -3
  209. package/pipeline/scripts/render-cost-summary.sh +9 -2
  210. package/pipeline/scripts/render-work-summary.sh +14 -7
  211. package/pipeline/scripts/review-file-filter.mjs +5 -3
  212. package/pipeline/scripts/review-scope.mjs +2 -1
  213. package/pipeline/scripts/routine-registry.mjs +2 -1
  214. package/pipeline/scripts/run-aggregator.mjs +26 -20
  215. package/pipeline/scripts/run-metrics.mjs +4 -2
  216. package/pipeline/scripts/runs-index.mjs +353 -0
  217. package/pipeline/scripts/scorecard-snapshot.mjs +178 -0
  218. package/pipeline/scripts/search-logs.sh +18 -0
  219. package/pipeline/scripts/smoke-cross-cli-behavior.sh +6 -6
  220. package/pipeline/scripts/smoke-schema-validation.sh +26 -7
  221. package/pipeline/scripts/test-gap-scan.mjs +2 -1
  222. package/pipeline/scripts/test-integrity-gate.mjs +2 -1
  223. package/pipeline/scripts/token-budget-report.mjs +13 -2
  224. package/pipeline/scripts/triage-memory.mjs +2 -2
  225. package/pipeline/scripts/update-issue-progress.sh +56 -7
  226. package/pipeline/scripts/usage-report.mjs +12 -1
  227. package/pipeline/scripts/validate-analysis-doc.mjs +75 -18
  228. package/pipeline/scripts/validate-code-graph.mjs +6 -3
  229. package/pipeline/scripts/validate-complaint-doc.mjs +2 -1
  230. package/pipeline/scripts/validate-diff-risk.mjs +6 -3
  231. package/pipeline/scripts/validate-planning.mjs +1 -1
  232. package/pipeline/scripts/validate-reviewer.mjs +1 -1
  233. package/pipeline/scripts/validate-state.mjs +45 -5
  234. package/pipeline/scripts/validate-test-gap.mjs +6 -3
  235. package/pipeline/scripts/validate-triage.mjs +6 -4
  236. package/pipeline/scripts/verify-citations.mjs +4 -2
  237. package/pipeline/scripts/verify.mjs +327 -0
  238. package/pipeline/scripts/worktree-finalize.sh +18 -9
  239. package/pipeline/scripts/write-state.mjs +154 -15
  240. package/pipeline/skills/.skill-manifest.json +37 -21
  241. package/pipeline/skills/.skills-index.json +104 -5
  242. package/pipeline/skills/shared/README.md +15 -6
  243. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +2 -2
  244. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +2 -2
  245. package/pipeline/skills/shared/core/multi-agent/SKILL.md +69 -71
  246. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +3 -3
  247. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +14 -14
  248. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +5 -5
  249. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +1 -1
  250. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +25 -23
  251. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -2
  252. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +2 -2
  253. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +8 -8
  254. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +6 -6
  255. package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +71 -0
  256. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +3 -3
  257. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
  258. package/pipeline/skills/shared/core/multi-agent-resume-local/SKILL.md +7 -7
  259. package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +39 -0
  260. package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +76 -0
  261. package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +59 -0
  262. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
  263. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +35 -11
  264. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -2
  265. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +6 -5
  266. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/package_app.sh +4 -1
  267. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +4 -1
  268. package/pipeline/skills/shared/external/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +2 -1
  269. package/pipeline/skills/skills-index.md +13 -4
  270. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +0 -263
  271. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +0 -344
  272. package/pipeline/multi-agent-refs/phases/phase-5-test.md +0 -182
@@ -16,12 +16,22 @@
16
16
  *
17
17
  * # Replace: full overwrite from stdin JSON
18
18
  * cat new-state.json | node write-state.mjs --replace /path/to/agent-state.json
19
+ * cat patch.json | node write-state.mjs --if-rev=7 /path/to/agent-state.json
20
+ *
21
+ * `--if-rev=<n>` is compare-and-swap: write only if the record on disk is
22
+ * still at revision n. The lock closes the window between two WRITERS; it does
23
+ * nothing about the one between a read and a write, which is where an editor
24
+ * lives - `/multi-agent:steer` reads the state, a human thinks, and the run may
25
+ * move three phases before the edit lands. Without this the edit merges over
26
+ * the top and reinstates decisions the run already replaced.
19
27
  *
20
28
  * Exit codes:
21
29
  * 0 - write succeeded
22
30
  * 1 - invalid JSON on stdin
23
31
  * 2 - lock timeout (another writer held the lock past the acquire window)
32
+ * 4 - the lock was taken from us mid-write; nothing was written, retry
24
33
  * 3 - I/O error (disk full, permission denied, parent dir missing)
34
+ * 5 - --if-rev did not match; the record moved, nothing was written
25
35
  *
26
36
  * Tunables (env):
27
37
  * WRITE_STATE_LOCK_TIMEOUT_MS acquire window before exit 2 (default 15000)
@@ -52,9 +62,11 @@ import {
52
62
  } from "fs";
53
63
  import { dirname, basename } from "path";
54
64
  import { Buffer } from "node:buffer";
65
+ import { runMain } from "../lib/fatal.mjs";
66
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
55
67
 
56
68
  /**
57
- * @typedef {{ replace: boolean, path: string }} ParsedArgs
69
+ * @typedef {{ replace: boolean, path: string, ifRev: number|null }} ParsedArgs
58
70
  */
59
71
 
60
72
  /** @returns {ParsedArgs} */
@@ -62,18 +74,26 @@ function parseArgs() {
62
74
  const args = process.argv.slice(2);
63
75
  let replace = false;
64
76
  let path = null;
77
+ let ifRev = null;
65
78
  for (const a of args) {
66
79
  if (a === "--replace") replace = true;
67
- else if (a.startsWith("--")) {
80
+ else if (a.startsWith("--if-rev=")) {
81
+ const v = Number(a.slice("--if-rev=".length));
82
+ if (!Number.isInteger(v) || v < 0) {
83
+ console.error(`write-state: --if-rev takes a non-negative integer, got ${a.slice(9)}`);
84
+ process.exit(3);
85
+ }
86
+ ifRev = v;
87
+ } else if (a.startsWith("--")) {
68
88
  console.error(`write-state: unknown flag ${a}`);
69
89
  process.exit(3);
70
90
  } else path = a;
71
91
  }
72
92
  if (!path) {
73
- console.error("usage: write-state.mjs [--replace] <path>");
93
+ console.error("usage: write-state.mjs [--replace] [--if-rev=<n>] <path>");
74
94
  process.exit(3);
75
95
  }
76
- return { replace, path };
96
+ return { replace, path, ifRev };
77
97
  }
78
98
 
79
99
  /**
@@ -103,8 +123,13 @@ async function acquireLock(
103
123
  try {
104
124
  writeFileSync(stagePath, String(process.pid));
105
125
  linkSync(stagePath, lockPath); // fails EEXIST if another writer holds it
126
+ // The inode of the lock WE created. Everything after this point checks
127
+ // against it: a lock at the same path with a different inode is somebody
128
+ // else's, and both releasing it and writing under it are the same bug the
129
+ // reclaim path below already refuses to commit.
130
+ const ino = statSync(lockPath).ino;
106
131
  unlinkSync(stagePath);
107
- return;
132
+ return ino;
108
133
  } catch (err) {
109
134
  try {
110
135
  unlinkSync(stagePath);
@@ -208,16 +233,46 @@ function lockIdentityIfStale(lockPath, staleMs) {
208
233
  // Path whose lock this process currently holds (null when none). Lets the
209
234
  // top-level error handler release our lock on unexpected failures.
210
235
  let heldLockFor = null;
236
+ // The inode of that lock. The path alone does not identify it: a lock deleted
237
+ // and re-created at the same path is a different file and a different owner.
238
+ let heldLockIno = null;
239
+
240
+ /**
241
+ * True when the lock at `path` is still the one this process created.
242
+ *
243
+ * @param {string} path
244
+ * @param {number | null} ino
245
+ * @returns {boolean}
246
+ */
247
+ function stillOurs(path, ino) {
248
+ if (ino === null) return true; // nothing was ever locked; nothing to lose
249
+ try {
250
+ return statSync(`${path}.lock`).ino === ino;
251
+ } catch {
252
+ return false; // our lock is gone, which means somebody removed it
253
+ }
254
+ }
211
255
 
212
256
  /** @param {string} path */
213
- function releaseLock(path) {
257
+ function releaseLock(path, ino = heldLockIno) {
214
258
  const lockPath = `${path}.lock`;
215
259
  try {
260
+ // By identity, never by path - the same rule acquireLock states and this
261
+ // function used to break. If our lock was reclaimed as stale while we were
262
+ // starved (the abandon ceiling, or the unreadable-PID window), the lock now
263
+ // at this path belongs to a LIVE writer, and unlinking it puts two writers
264
+ // inside at once and loses one update. That is the third point in this
265
+ // cycle where "delete by path" produces the same data loss; the other two
266
+ // are documented in acquireLock.
267
+ if (ino !== null && statSync(lockPath).ino !== ino) return;
216
268
  unlinkSync(lockPath);
217
269
  } catch {
218
270
  /* already gone - fine */
219
271
  }
220
- if (heldLockFor === path) heldLockFor = null;
272
+ if (heldLockFor === path) {
273
+ heldLockFor = null;
274
+ heldLockIno = null;
275
+ }
221
276
  }
222
277
 
223
278
  /**
@@ -225,6 +280,22 @@ function releaseLock(path) {
225
280
  * @param {object} patch
226
281
  * @returns {object}
227
282
  */
283
+ /**
284
+ * The version a NEWLY created state document is stamped with, read from the
285
+ * schema so the writer and the schema cannot disagree. The literal is a
286
+ * fallback for an unreadable schema, which validate-schemas.mjs would already
287
+ * have failed on.
288
+ */
289
+ const STATE_SCHEMA_VERSION = (() => {
290
+ try {
291
+ const schemaPath = new URL("../schemas/agent-state.schema.json", import.meta.url);
292
+ const sv = JSON.parse(readFileSync(schemaPath, "utf-8"))?.properties?.schemaVersion;
293
+ return sv?.const ?? sv?.enum?.at(-1) ?? "2.1.0";
294
+ } catch {
295
+ return "2.1.0";
296
+ }
297
+ })();
298
+
228
299
  function deepMerge(base, patch) {
229
300
  if (Array.isArray(patch)) return patch; // arrays replace
230
301
  if (typeof patch !== "object" || patch === null) return patch;
@@ -236,7 +307,7 @@ function deepMerge(base, patch) {
236
307
  }
237
308
 
238
309
  async function main() {
239
- const { replace, path } = parseArgs();
310
+ const { replace, path, ifRev } = parseArgs();
240
311
 
241
312
  // Read stdin
242
313
  const chunks = [];
@@ -257,7 +328,7 @@ async function main() {
257
328
  }
258
329
 
259
330
  try {
260
- await acquireLock(path);
331
+ heldLockIno = await acquireLock(path);
261
332
  heldLockFor = path;
262
333
  } catch (err) {
263
334
  if (err.code === "LOCK_TIMEOUT") {
@@ -272,6 +343,8 @@ async function main() {
272
343
  // here must release OUR lock explicitly before exiting - otherwise a corrupt
273
344
  // state file (or any I/O error) leaks agent-state.json.lock and blocks the
274
345
  // next writer until the stale-lock window elapses.
346
+ const fileExistedBefore = existsSync(path);
347
+
275
348
  try {
276
349
  let next;
277
350
  if (replace) {
@@ -304,16 +377,67 @@ async function main() {
304
377
  // carries a `rev` from before the record moved, and following it down
305
378
  // would tell the next reader that nothing changed.
306
379
  let priorRev = Number.isInteger(next.rev) ? next.rev : 0;
380
+ let diskRev = null;
307
381
  if (existsSync(path)) {
308
382
  try {
309
383
  const parsed = JSON.parse(readFileSync(path, "utf-8"));
310
- if (Number.isInteger(parsed?.rev)) priorRev = Math.max(priorRev, parsed.rev);
384
+ if (Number.isInteger(parsed?.rev)) {
385
+ diskRev = parsed.rev;
386
+ priorRev = Math.max(priorRev, parsed.rev);
387
+ }
311
388
  } catch {
312
389
  /* unreadable on disk - the merge path above already threw for that */
313
390
  }
314
391
  }
392
+
393
+ // Compare-and-swap. `rev` already told a reader whether the record moved;
394
+ // --if-rev is what lets it ACT on that instead of merging over the top.
395
+ //
396
+ // The lock closes the window between two writers. It does not close the
397
+ // one between a READ and a write, and `/multi-agent:steer` puts a second
398
+ // writer in exactly that window on purpose: it reads the state, a human
399
+ // thinks, and by the time the edit lands the run may have moved three
400
+ // phases. A merge then reinstates decisions the run already replaced.
401
+ //
402
+ // Refusing costs a re-read. Merging costs a phase that silently reverts.
403
+ if (ifRev !== null) {
404
+ const seen = diskRev ?? 0;
405
+ if (seen !== ifRev) {
406
+ console.error(
407
+ `write-state: rev is ${seen}, expected ${ifRev} - the record moved since you read it; re-read and retry`,
408
+ );
409
+ releaseLock(path);
410
+ process.exit(5);
411
+ }
412
+ }
413
+
315
414
  next.rev = priorRev + 1;
316
415
 
416
+ // schemaVersion is stamped only when this call CREATES the document. The
417
+ // migration runner keys on it, and a document that never carries one can
418
+ // never be migrated - measured on a real install, 43 of 43 state files had
419
+ // no schemaVersion, so pipeline/schemas/migrations/ was unreachable code.
420
+ // A merge into an existing unstamped file is deliberately left alone:
421
+ // stamping there would claim a conformance nothing verified.
422
+ if (!fileExistedBefore && typeof next.schemaVersion !== "string") {
423
+ next.schemaVersion = STATE_SCHEMA_VERSION;
424
+ }
425
+
426
+ // Last check before the write lands: is the lock still ours? Everything
427
+ // above read the file under a lock we believed we held, and if that belief
428
+ // stopped being true the rename would overwrite a concurrent writer's
429
+ // update with a merge that never saw it. Reporting success while losing an
430
+ // update is the one outcome this script exists to prevent, so it refuses
431
+ // instead - a caller that sees exit 4 can read and retry, which a caller
432
+ // that saw exit 0 never will.
433
+ if (!stillOurs(path, heldLockIno)) {
434
+ console.error(
435
+ `write-state: the lock was taken from us mid-write (${path}.lock). ` +
436
+ `Nothing was written. Re-read the state and retry.`,
437
+ );
438
+ process.exit(4);
439
+ }
440
+
317
441
  const tmp = `${dirname(path)}/.${basename(path)}.${process.pid}.tmp`;
318
442
  writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
319
443
  renameSync(tmp, path); // atomic on POSIX
@@ -327,8 +451,23 @@ async function main() {
327
451
  process.exit(0);
328
452
  }
329
453
 
330
- main().catch((err) => {
331
- console.error(`write-state: unhandled - ${err.message}`);
332
- if (heldLockFor) releaseLock(heldLockFor);
333
- process.exit(3);
334
- });
454
+ // Only run when invoked as a program. The lock helpers are the part with the
455
+ // subtle behaviour and they are unreachable from a test otherwise: the window
456
+ // they guard is microseconds wide, so a test that drives this file as a CLI
457
+ // measures the scheduler rather than the code.
458
+ const isDirectRun = invokedDirectly(import.meta.url);
459
+ if (isDirectRun) {
460
+ // Exit 3 is this file's documented "died without writing" code, and the
461
+ // cleanup is the reason the handler exists at all: a writer that dies holding
462
+ // the advisory lock makes the NEXT writer wait out the acquire window and
463
+ // then decide, on nothing but age, whether to take a lock that may still be
464
+ // live. Releasing on the abnormal path keeps that decision from arising.
465
+ runMain("write-state", main, {
466
+ code: 3,
467
+ cleanup: () => {
468
+ if (heldLockFor) releaseLock(heldLockFor);
469
+ },
470
+ });
471
+ }
472
+
473
+ export { acquireLock, releaseLock, stillOurs, lockIdentityIfStale };
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-09-15T20:06:53Z",
4
- "skillCount": 212,
3
+ "generatedAt": "2026-09-18T07:17:50Z",
4
+ "skillCount": 216,
5
5
  "entries": [
6
6
  {
7
7
  "path": "shared/core/apple-archive-compliance/SKILL.md",
8
- "sha256": "0d2f81825bf1610c765a4a7a223247703812e86a642e78f4f367cfc35cea76af"
8
+ "sha256": "e5c38c240a674903acf3f32e5b492a4a6c5dc438a323bb3ca9adc361b41a6884"
9
9
  },
10
10
  {
11
11
  "path": "shared/core/google-play-compliance/SKILL.md",
12
- "sha256": "356ff2b30f414e582bb215c4728696af8e249dfe924e16a550294e48fd9bdcf9"
12
+ "sha256": "49412b53af57ba31fe7d19983144043a2333249d075ff90a9fde9a9d3482ce83"
13
13
  },
14
14
  {
15
15
  "path": "shared/core/multi-agent-analysis-jira/SKILL.md",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  {
39
39
  "path": "shared/core/multi-agent-autopilot/SKILL.md",
40
- "sha256": "c02525ad003c34d53834ecd04eb150764b36779f4e08941c9016926418e74333"
40
+ "sha256": "7446424d3dd480751358a0e3de917f3d22bb4f1ce6dec1b99217877c6b217e76"
41
41
  },
42
42
  {
43
43
  "path": "shared/core/multi-agent-build-optimize/SKILL.md",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  {
47
47
  "path": "shared/core/multi-agent-channels/SKILL.md",
48
- "sha256": "fa128726aa0009699e7ac2de566812e7192681db98c90dfc5da501ad50a05583"
48
+ "sha256": "414eead38b461c8aa95f6af3175366be905338233e6872313f5d4f59a02351af"
49
49
  },
50
50
  {
51
51
  "path": "shared/core/multi-agent-complaint-analysis/SKILL.md",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "path": "shared/core/multi-agent-diff-explain/SKILL.md",
64
- "sha256": "7cb37a224e61d66e350202ecfc5fbc6c33da3fe0718504a093602f5cde5b648f"
64
+ "sha256": "ec3827e0457c693812d11b3a96f88f0e2d186af369c353e1b5c40795d96933dd"
65
65
  },
66
66
  {
67
67
  "path": "shared/core/multi-agent-doctor/SKILL.md",
@@ -81,11 +81,11 @@
81
81
  },
82
82
  {
83
83
  "path": "shared/core/multi-agent-graph/SKILL.md",
84
- "sha256": "918feff1a0a691535901c20a0625340a0f88cd5294cff1a1da20f799f6746f2a"
84
+ "sha256": "d6781a34d98a542aac3df4ce9c7c52d83902851de2d239bed022ac382716a26e"
85
85
  },
86
86
  {
87
87
  "path": "shared/core/multi-agent-help/SKILL.md",
88
- "sha256": "87d45a04c782b03569b0ab9ee54da8414cbadd5a2a82a7701f38dc8a3ee94627"
88
+ "sha256": "6ebe7d4de1a1ff815f572abb5d5db5d5af9ea507b3047ec60597a54455176da5"
89
89
  },
90
90
  {
91
91
  "path": "shared/core/multi-agent-ios-coding-standard/SKILL.md",
@@ -105,15 +105,15 @@
105
105
  },
106
106
  {
107
107
  "path": "shared/core/multi-agent-language/SKILL.md",
108
- "sha256": "c44d951996a208d962d969b0ac309ce88a38c048a2d8b332546c532045c189fc"
108
+ "sha256": "63e746bc63ec9963c54e852e6ca5cdb30afd9309a02ee3fdb35965eb931d0300"
109
109
  },
110
110
  {
111
111
  "path": "shared/core/multi-agent-local-autopilot/SKILL.md",
112
- "sha256": "b0fac3509c2fa513b3fea9bfde4f2554642cb60373a5b570ef29ba8bf760e2a1"
112
+ "sha256": "5e367258e57fa710d16a1ad6363d5974b89aa99fb0ac791d1ce0070c81191f6b"
113
113
  },
114
114
  {
115
115
  "path": "shared/core/multi-agent-local/SKILL.md",
116
- "sha256": "90dd95a0dc569f1451bf095a77cffccae607e4dedd271a3362cce32b53b5d819"
116
+ "sha256": "0a5f20782de81ac3376088579ff6fbc3a6f3781cb285860aae796408aa57e6aa"
117
117
  },
118
118
  {
119
119
  "path": "shared/core/multi-agent-log/SKILL.md",
@@ -121,7 +121,11 @@
121
121
  },
122
122
  {
123
123
  "path": "shared/core/multi-agent-manual-test/SKILL.md",
124
- "sha256": "e7f7f8004d286c5b5b596f8659bcf57b2350eb9c67a55470bb2e9b714513a3a4"
124
+ "sha256": "53e1d58848673690aa0b146908eae98a2de9861dae8b613f63f63672adf6d69b"
125
+ },
126
+ {
127
+ "path": "shared/core/multi-agent-model/SKILL.md",
128
+ "sha256": "eb66f48b4772f41b395b0aff0c3d0303e29da0a470abae8b61a602b93ba7335c"
125
129
  },
126
130
  {
127
131
  "path": "shared/core/multi-agent-prune-logs/SKILL.md",
@@ -137,15 +141,15 @@
137
141
  },
138
142
  {
139
143
  "path": "shared/core/multi-agent-refactor/SKILL.md",
140
- "sha256": "56b49a8216086961bc407a60b559942252a1aae3005b73811b1d40668758cc84"
144
+ "sha256": "56eb2be076a6840ddfbf57b8e82c8b4bcf76209553d41a06cc71e56dc894364e"
141
145
  },
142
146
  {
143
147
  "path": "shared/core/multi-agent-resume-local/SKILL.md",
144
- "sha256": "a4bedf949ab648d977dd1409339d08af204341f555d69f71f58c1a54dffaff6d"
148
+ "sha256": "9f5089c748a8f0ae5983a3f392879a86017a33c883a87607169e32705c68c5e9"
145
149
  },
146
150
  {
147
151
  "path": "shared/core/multi-agent-resume/SKILL.md",
148
- "sha256": "5e80eb098996fdea36f013acc8ddec44d462cace031c78341f11f0b59592a6ba"
152
+ "sha256": "6701424edde0a19b55a7de62bb5ba5f9dbaef7d9fb9ea2bce632374863145774"
149
153
  },
150
154
  {
151
155
  "path": "shared/core/multi-agent-review-analysis/SKILL.md",
@@ -163,6 +167,18 @@
163
167
  "path": "shared/core/multi-agent-review/SKILL.md",
164
168
  "sha256": "f3903b07fa7176ff9430f46cc1e981a0f0d06ab028df5ef1d45ad9271bada1e5"
165
169
  },
170
+ {
171
+ "path": "shared/core/multi-agent-route-off/SKILL.md",
172
+ "sha256": "c569e9ba1fbbebc879b69229cf2154edc89998fcdcfe74fb4220f5af70daafa0"
173
+ },
174
+ {
175
+ "path": "shared/core/multi-agent-route-on/SKILL.md",
176
+ "sha256": "40fab187a6054b90c9b8f1e8ad198a08ab94fdfd9cd89eef9b439e59b570d821"
177
+ },
178
+ {
179
+ "path": "shared/core/multi-agent-route-status/SKILL.md",
180
+ "sha256": "f104d3de6974837b8ebbcc6242269c06ea78a0d97a3e216c1b62cf6d91a72fd8"
181
+ },
166
182
  {
167
183
  "path": "shared/core/multi-agent-routines/SKILL.md",
168
184
  "sha256": "a8cc83140b5d84365348a2b0858f06a9e92808f608544eea61ab5760c82f9f97"
@@ -181,7 +197,7 @@
181
197
  },
182
198
  {
183
199
  "path": "shared/core/multi-agent-setup/SKILL.md",
184
- "sha256": "d475f14de5db9ffe0c8ae5b3b83374d5f82a41c29da5271c7399d151e6bd4c1d"
200
+ "sha256": "d2c167082f40af3c2a7cbb0be55a8cdf8076a4f06a3df54c89b1318759421a29"
185
201
  },
186
202
  {
187
203
  "path": "shared/core/multi-agent-stack/SKILL.md",
@@ -189,11 +205,11 @@
189
205
  },
190
206
  {
191
207
  "path": "shared/core/multi-agent-status/SKILL.md",
192
- "sha256": "436d1716ce5fc4977dadfce8a85b09877f93c626953739a7ad70eefbbcd25869"
208
+ "sha256": "ae9a7507e0a0291d8e786820b1a0394363f416fd7715f2deb162c9f542ae5351"
193
209
  },
194
210
  {
195
211
  "path": "shared/core/multi-agent-steer/SKILL.md",
196
- "sha256": "a5988d6945dabea45d9827c76e270bb3d12fb2b7689e8893ea09f650ae97baa9"
212
+ "sha256": "d2a3602c1acbd1a01b30fcba65fbbe669ac825ec4ac9b0d6679bba07e0d1207c"
197
213
  },
198
214
  {
199
215
  "path": "shared/core/multi-agent-store-ready/SKILL.md",
@@ -201,7 +217,7 @@
201
217
  },
202
218
  {
203
219
  "path": "shared/core/multi-agent-sync/SKILL.md",
204
- "sha256": "51e9a8a9053ce9d0450bcaf66555075f83c340203bb753946938f4b29cf93b79"
220
+ "sha256": "3d3331d34f9610ea02b96ee27c8029734f3a3447d2857fc0dca92d5b43d0f8e2"
205
221
  },
206
222
  {
207
223
  "path": "shared/core/multi-agent-test-accessibility/SKILL.md",
@@ -237,7 +253,7 @@
237
253
  },
238
254
  {
239
255
  "path": "shared/core/multi-agent/SKILL.md",
240
- "sha256": "faac7ceb535d18778efe0ea91c19534c8e076bc709e7b1dbc567f5e71692bbbd"
256
+ "sha256": "849a2c7db9fb779d9919c7ed6cf3e0c3c6fd105ff961c45af31055ad21fd181c"
241
257
  },
242
258
  {
243
259
  "path": "shared/external/accessibility-compliance-accessibility-audit/SKILL.md",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "skillCount": 207,
3
+ "skillCount": 216,
4
4
  "entries": [
5
5
  {
6
6
  "name": "accessibility-compliance-accessibility-audit",
@@ -959,6 +959,17 @@
959
959
  "triggerPaths": [],
960
960
  "relativePath": "shared/core/multi-agent-analysis/SKILL.md"
961
961
  },
962
+ {
963
+ "name": "multi-agent-analysis-jira",
964
+ "description": "Turn a rendered analysis document into a Jira story tree: derive stories from the document's own rule ids, check coverage both ways, preview every byte, then create only what does not already exist. Use when an analysis is final and the work needs tickets.",
965
+ "platform": null,
966
+ "group": "core",
967
+ "plugin": null,
968
+ "invokeAs": "multi-agent-analysis-jira",
969
+ "triggerKeywords": [],
970
+ "triggerPaths": [],
971
+ "relativePath": "shared/core/multi-agent-analysis-jira/SKILL.md"
972
+ },
962
973
  {
963
974
  "name": "multi-agent-analysis-resolve",
964
975
  "description": "Resolve the Section 20 Risks and Open Questions of an analysis v3 document one row at a time: up to 3 source-labeled answer candidates per row (evidence / repo / AI reasoned), chosen answer merged into the target section, doc updated in place with a changelog bump. Same locked decisions as /multi-ag",
@@ -981,6 +992,39 @@
981
992
  "triggerPaths": [],
982
993
  "relativePath": "shared/core/multi-agent-autopilot/SKILL.md"
983
994
  },
995
+ {
996
+ "name": "multi-agent-autopilot-off",
997
+ "description": "Turn off continuous mode on this machine: the schedule is removed, work already running finishes, the repo selection is kept. Use when the machine should stop picking work up.",
998
+ "platform": null,
999
+ "group": "core",
1000
+ "plugin": null,
1001
+ "invokeAs": "multi-agent-autopilot-off",
1002
+ "triggerKeywords": [],
1003
+ "triggerPaths": [],
1004
+ "relativePath": "shared/core/multi-agent-autopilot-off/SKILL.md"
1005
+ },
1006
+ {
1007
+ "name": "multi-agent-autopilot-on",
1008
+ "description": "Turn on continuous mode on THIS machine: pick the repos it watches; labelled GitHub issues and assigned+labelled Jira items then run in a worktree and stop at an open PR. Use when the machine should pick work up unattended.",
1009
+ "platform": null,
1010
+ "group": "core",
1011
+ "plugin": null,
1012
+ "invokeAs": "multi-agent-autopilot-on",
1013
+ "triggerKeywords": [],
1014
+ "triggerPaths": [],
1015
+ "relativePath": "shared/core/multi-agent-autopilot-on/SKILL.md"
1016
+ },
1017
+ {
1018
+ "name": "multi-agent-autopilot-status",
1019
+ "description": "Show what continuous mode is doing here: what runs at which phase, what is queued, what waits for an answer, what PRs it opened today. Use when asked whether autopilot is on.",
1020
+ "platform": null,
1021
+ "group": "core",
1022
+ "plugin": null,
1023
+ "invokeAs": "multi-agent-autopilot-status",
1024
+ "triggerKeywords": [],
1025
+ "triggerPaths": [],
1026
+ "relativePath": "shared/core/multi-agent-autopilot-status/SKILL.md"
1027
+ },
984
1028
  {
985
1029
  "name": "multi-agent-build-optimize",
986
1030
  "description": "Wrapper that dispatches to xcode-build-orchestrator on iOS repos. Benchmarks the current Xcode build, runs compilation / project / SPM analyzers, produces a recommend-first optimization plan in .build-benchmark/, and re-benchmarks after the developer approves changes. Fails fast on non-iOS stacks. U",
@@ -994,7 +1038,7 @@
994
1038
  },
995
1039
  {
996
1040
  "name": "multi-agent-channels",
997
- "description": "Multi-channel reporter - Jira/Confluence/Wiki/PR description. Multi-select channels + content, humanizer pass, reviewer-preserving Bitbucket PR PUT. Phase 7 delegates to this skill; users can invoke post-hoc by Jira ID / PR URL / branch.",
1041
+ "description": "Multi-channel reporter - Jira/Confluence/Wiki/PR description. Multi-select channels + content, humanizer pass, reviewer-preserving Bitbucket PR PUT. Phase 5 delegates to this skill; users can invoke post-hoc by Jira ID / PR URL / branch.",
998
1042
  "platform": null,
999
1043
  "group": "core",
1000
1044
  "plugin": null,
@@ -1038,7 +1082,7 @@
1038
1082
  },
1039
1083
  {
1040
1084
  "name": "multi-agent-diff-explain",
1041
- "description": "Map Phase 4 triage findings to branch diff lines. Read-only post-hoc command, used after review to answer 'which finding lines up with which code change'. Use when a review finding has to be traced to the exact lines that caused it.",
1085
+ "description": "Map Phase 3 triage findings to branch diff lines. Read-only post-hoc command, used after review to answer 'which finding lines up with which code change'. Use when a review finding has to be traced to the exact lines that caused it.",
1042
1086
  "platform": null,
1043
1087
  "group": "core",
1044
1088
  "plugin": null,
@@ -1047,6 +1091,17 @@
1047
1091
  "triggerPaths": [],
1048
1092
  "relativePath": "shared/core/multi-agent-diff-explain/SKILL.md"
1049
1093
  },
1094
+ {
1095
+ "name": "multi-agent-doctor",
1096
+ "description": "Health check for the installed pipeline: layout, preferences, credentials, hooks and host capabilities, each with one actionable step. Exit code is the verdict. Use when a run failed for an environmental reason, before a sync, or after an update.",
1097
+ "platform": null,
1098
+ "group": "core",
1099
+ "plugin": null,
1100
+ "invokeAs": "multi-agent-doctor",
1101
+ "triggerKeywords": [],
1102
+ "triggerPaths": [],
1103
+ "relativePath": "shared/core/multi-agent-doctor/SKILL.md"
1104
+ },
1050
1105
  {
1051
1106
  "name": "multi-agent-feedback",
1052
1107
  "description": "Send one message to the maintainer: a bug, an idea or a question. Only the text you type is sent - no logs, no repo names, no paths. Shows the payload and asks before sending. Use when a run went wrong and the maintainer should know.",
@@ -1170,7 +1225,7 @@
1170
1225
  },
1171
1226
  {
1172
1227
  "name": "multi-agent-local-autopilot",
1173
- "description": "Full pipeline + local + autopilot - no worktree, no confirmations, all 8 phases run end-to-end on the current branch. Use when the full pipeline should run on the current branch with no worktree and no prompts.",
1228
+ "description": "Full pipeline + local + autopilot - no worktree, no confirmations, all 6 phases run end-to-end on the current branch. Use when the full pipeline should run on the current branch with no worktree and no prompts.",
1174
1229
  "platform": null,
1175
1230
  "group": "core",
1176
1231
  "plugin": null,
@@ -1201,6 +1256,17 @@
1201
1256
  "triggerPaths": [],
1202
1257
  "relativePath": "shared/core/multi-agent-manual-test/SKILL.md"
1203
1258
  },
1259
+ {
1260
+ "name": "multi-agent-model",
1261
+ "description": "Turn the top model rung on or off and keep the cost ledger's pricing in step with it. Use when asked to enable or disable Fable, or which model the pipeline dispatches.",
1262
+ "platform": null,
1263
+ "group": "core",
1264
+ "plugin": null,
1265
+ "invokeAs": "multi-agent-model",
1266
+ "triggerKeywords": [],
1267
+ "triggerPaths": [],
1268
+ "relativePath": "shared/core/multi-agent-model/SKILL.md"
1269
+ },
1204
1270
  {
1205
1271
  "name": "multi-agent-prune-logs",
1206
1272
  "description": "Delete per-task project logs under ~/.claude/logs/multi-agent (filter by age/project/task). Audit trail + metrics are preserved. Dry-run first; confirms before deleting. Use when task logs have built up and need trimming by age, project or task.",
@@ -1258,7 +1324,7 @@
1258
1324
  },
1259
1325
  {
1260
1326
  "name": "multi-agent-resume-local",
1261
- "description": "Continue already-done LOCAL work through the pipeline tail: Review → Build+Test → Commit/PR → Report (technical analysis + Jira test-scenario comment). No dev phase. Use when local work is already done and only review, build, commit and reporting remain.",
1327
+ "description": "Continue already-done LOCAL work through the pipeline tail: Review (with its build gate) → Commit/PR → Report (technical analysis + Jira test-scenario comment). No dev phase. Use when local work is already done and only review, build, commit and reporting remain.",
1262
1328
  "platform": null,
1263
1329
  "group": "core",
1264
1330
  "plugin": null,
@@ -1311,6 +1377,39 @@
1311
1377
  "triggerPaths": [],
1312
1378
  "relativePath": "shared/core/multi-agent-review-jira/SKILL.md"
1313
1379
  },
1380
+ {
1381
+ "name": "multi-agent-route-off",
1382
+ "description": "Disable model routing and keep its rules, so turning it back on does not re-ask for the same configuration. Use when asked to turn model routing off.",
1383
+ "platform": null,
1384
+ "group": "core",
1385
+ "plugin": null,
1386
+ "invokeAs": "multi-agent-route-off",
1387
+ "triggerKeywords": [],
1388
+ "triggerPaths": [],
1389
+ "relativePath": "shared/core/multi-agent-route-off/SKILL.md"
1390
+ },
1391
+ {
1392
+ "name": "multi-agent-route-on",
1393
+ "description": "Enable policy-driven model routing: pick a strategy, a scope, and the rules that say which rung a call lands on. Use when asked to turn model routing on.",
1394
+ "platform": null,
1395
+ "group": "core",
1396
+ "plugin": null,
1397
+ "invokeAs": "multi-agent-route-on",
1398
+ "triggerKeywords": [],
1399
+ "triggerPaths": [],
1400
+ "relativePath": "shared/core/multi-agent-route-on/SKILL.md"
1401
+ },
1402
+ {
1403
+ "name": "multi-agent-route-status",
1404
+ "description": "Report model routing: whether it is armed, which rule applies where, which rung the last dispatches took, and what this run has cost. Use when asked which model is being used or why.",
1405
+ "platform": null,
1406
+ "group": "core",
1407
+ "plugin": null,
1408
+ "invokeAs": "multi-agent-route-status",
1409
+ "triggerKeywords": [],
1410
+ "triggerPaths": [],
1411
+ "relativePath": "shared/core/multi-agent-route-status/SKILL.md"
1412
+ },
1314
1413
  {
1315
1414
  "name": "multi-agent-routines",
1316
1415
  "description": "List your saved /multi-agent routines (from /multi-agent:save) with what each one does, rendered in outputLanguage. Use when asked which saved routines exist or what one of them does.",