@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
@@ -49,10 +49,10 @@ This is the single source of truth. When a contributor or model is unsure where
49
49
  ## Code & Commit Rules
50
50
 
51
51
  - **NEVER** put "Copilot", "AI", "generated by", or similar attribution in code, comments, commit messages, PR descriptions, or issue comments. The pipeline is a tool - it writes on behalf of the configured Git identity, not as itself.
52
- - **NEVER** commit without passing build (all gates in Phase 4 Step 1 must be green).
52
+ - **NEVER** commit without passing build (all gates in Phase 3 Step 1 must be green).
53
53
  - **NEVER** commit without passing review (at least one AI reviewer must return `approved: true` with no blocking findings).
54
54
  - **NEVER** skip tests. Every public method, every error path, every edge case.
55
- - **NEVER** delete, rename, or weaken an existing test to get a green run. Existing tests are immutable during a task; one may change only when the task changes the spec it encodes, and the commit body names both. Deterministic backstop: the `test_lines_removed` diff-risk signal (Phase 4 Step 1.75) flags test files that shrink. A pass only on retry is a flake signal, not a pass: Phase 3 repeats new and changed tests (`testStability.repeatCount`, default 3) and logs `test.flake_signal` when runs disagree.
55
+ - **NEVER** delete, rename, or weaken an existing test to get a green run. Existing tests are immutable during a task; one may change only when the task changes the spec it encodes, and the commit body names both. Deterministic backstop: the `test_lines_removed` diff-risk signal (Phase 3 Step 1.75) flags test files that shrink. A pass only on retry is a flake signal, not a pass: Phase 3 repeats new and changed tests (`testStability.repeatCount`, default 3) and logs `test.flake_signal` when runs disagree.
56
56
  - **Follow existing code style and conventions.** Read neighbor files before writing new ones - match naming, structure, import order.
57
57
  - **Use design tokens, no magic numbers.** `16` → `.Spacing.spacing16`. `#E31837` → `Color.Primary.primary`. `.font(.system(size: 14))` → `.typographyStyle(.body1)`.
58
58
  - **Design system primitives before custom views.** Before writing a new View / Configuration triplet in a feature module, grep the shared component library (e.g. `Common/UIComponents/`, `core-ui/`, `packages/ui/`) for a primitive that already solves it. Domain-level wrappers, custom modals, buttons or toasts are forbidden when the design system has an equivalent. If the primitive exists but lacks a modifier (placeholder, size, error binding), **add the modifier to the primitive** in its `+Modifiers` extension; never fork it into the consumer domain. The Figma `CodeConnectSnippet` is the authoritative pointer to which primitive to use.
@@ -158,7 +158,7 @@ This is the single source of truth. When a contributor or model is unsure where
158
158
 
159
159
  ## Provider CLI Invocations
160
160
 
161
- Provider tools that print failed argv on retry leak credentials into the conversation transcript. Every Vercel call from the pipeline (Phase 6 deploy hooks, Phase 7 site updates, manual `vercel deploy` shells) MUST go through the wrapper:
161
+ Provider tools that print failed argv on retry leak credentials into the conversation transcript. Every Vercel call from the pipeline (Phase 4 deploy hooks, Phase 5 site updates, manual `vercel deploy` shells) MUST go through the wrapper:
162
162
 
163
163
  ```bash
164
164
  # CORRECT - the wrapper resolves the token itself, via the logical key `vercel`
@@ -193,13 +193,13 @@ These rules govern when and how the pipeline asks the user, and when it must NOT
193
193
 
194
194
  ## Figma Access Tier (pipeline-wide, BLOCKING)
195
195
 
196
- When any task references a Figma frame (URL, node ID, or free-text "from the design"), the pipeline MUST establish a Figma ground-truth artefact via a 3-tier fallback chain before any UI line is written. The tier in use is persisted as `state.figmaAccess.tier` and read by every phase that consumes or verifies the reference (Phase 0 intake, Phase 1 analysis, Phase 2 planning, Phase 3 dev, Phase 4 review, Phase 5 manual test, Phase 7 channels).
196
+ When any task references a Figma frame (URL, node ID, or free-text "from the design"), the pipeline MUST establish a Figma ground-truth artefact via a 3-tier fallback chain before any UI line is written. The tier in use is persisted as `state.figmaAccess.tier` and read by every phase that consumes or verifies the reference (Phase 0 intake, Phase 1 analysis, Phase 1 planning, Phase 2 dev, Phase 3 review, Phase 5 manual test, Phase 5 channels).
197
197
 
198
198
  | Tier | Source | When chosen | Code Connect available |
199
199
  |---|---|---|---|
200
200
  | 1 | Figma MCP server (`mcp__claude_ai_Figma__get_design_context`, `get_screenshot`, `get_metadata`); MCP token resolves through `prefs.global.keychainMapping.figma_mcp` (for MCP server config bootstrap) | The host serves the `mcp__claude_ai_Figma__*` tools AND MCP auth succeeds (after one re-auth retry; on continued auth failure the user is asked: recreate the MCP token or continue with the PAT - never a silent fallthrough) | yes (`CodeConnectSnippet` blocks) |
201
201
  | 2 | Figma REST API (`GET /v1/files/{fileKey}/nodes`, `GET /v1/images/{fileKey}`) with Personal Access Token resolved via `~/.claude/lib/credential-store.sh get <logical-key>` where `<logical-key>` = `prefs.global.keychainMapping.figma` | Tier 1 unreachable AND PAT is mapped; on a 401/403 the user is asked the Expired-token decision (regenerate / different token / skip) before moving to Tier 3 | no, fall back to repo `*.figma.swift` / `*.figma.kt` mappings keyed by `fileKey` + `nodeId` |
202
- | 3 | User-attached screenshot in chat or task attachment | Tiers 1 + 2 both unreachable AND user has provided a screenshot | no - record an Open Question, pick the closest existing primitive WITH user confirmation, set Phase 4 reviewer flag to `review_blocking` |
202
+ | 3 | User-attached screenshot in chat or task attachment | Tiers 1 + 2 both unreachable AND user has provided a screenshot | no - record an Open Question, pick the closest existing primitive WITH user confirmation, set Phase 3 reviewer flag to `review_blocking` |
203
203
 
204
204
  **Tier 1 availability is per host, and "unavailable" is not "auth failed".** Tools absent (the normal case on Copilot CLI and Codex CLI, where the installer registers only the toolkit MCP) means Tier 2 is the expected entry point: record `figmaAccess.tier1Unavailable = "host"`, skip the re-auth retry, and never raise the MCP-token question. Tools present but failing auth is `"auth"`, where the retry does apply. Probe mechanics: `phases/phase-0-init.md`.
205
205
 
@@ -211,9 +211,9 @@ Full chain definition, REST endpoints, URL parsing, Code Connect snippet rules,
211
211
 
212
212
  ### Figma Access by Phase (pipeline-wide BLOCKING, v9.0.0)
213
213
 
214
- Per Locked decision 30 of `/multi-agent:analysis` and the parallel rule in `$HOME/.claude/rules/figma-pipeline.md`, Figma MCP / REST is allowed only in the analysis phase. Phase 2 through Phase 7 in every orchestrator mode (Full or Short, `--local`, autopilot) consume the analysis document + repo Code Connect mappings.
214
+ Per Locked decision 30 of `/multi-agent:analysis` and the parallel rule in `$HOME/.claude/rules/figma-pipeline.md`, Figma MCP / REST is allowed only in the analysis phase. Phase 2 through Phase 5 in every orchestrator mode (Full or Short, `--local`, autopilot) consume the analysis document + repo Code Connect mappings.
215
215
 
216
- The ban is **Figma**-shaped, not MCP-shaped: the multi-agent-toolkit MCP (simulator, screenshot, xcodebuild, accessibility) is unaffected in every phase, and `smoke-no-mcp-in-dev-phases.sh` agrees - it matches `figma` in the tool name and nothing else. A bare "MCP forbidden" has been read as banning the screenshot and UI-test tools, which is how a run reaches Phase 7 with no evidence.
216
+ The ban is **Figma**-shaped, not MCP-shaped: the multi-agent-toolkit MCP (simulator, screenshot, xcodebuild, accessibility) is unaffected in every phase, and `smoke-no-mcp-in-dev-phases.sh` agrees - it matches `figma` in the tool name and nothing else. A bare "MCP forbidden" has been read as banning the screenshot and UI-test tools, which is how a run reaches Phase 5 with no evidence.
217
217
 
218
218
  The per-phase matrix (which phase may fetch Figma, and what its sole design source is instead) lives in `rules/figma-pipeline.md` "Phase access matrix". It was copied here as a seven-row table for several releases, two paragraphs below this file's own instruction not to duplicate that rule file. Violation of either copy: `smoke-no-mcp-in-dev-phases.sh` fails the run.
219
219
 
@@ -17,7 +17,7 @@
17
17
  - [Figma URL Given](#figma-url-given)
18
18
  <!-- /toc -->
19
19
 
20
- > **MUST: Figma MCP-first (BLOCKING).** If the task references any Figma frame (URL, node ID, or "from the design"), the Dev phase MUST call `mcp__claude_ai_Figma__get_design_context` for every frame BEFORE writing a single UI line. Use the `CodeConnectSnippet` component name verbatim - no sound-alike substitutions. Authentication failure is not a skip path. Full rule, trigger conditions, and gate failure modes: `$HOME/.claude/rules/figma-pipeline.md` "MUST: Figma MCP-first (BLOCKING)". Phase wiring: `$HOME/.claude/multi-agent-refs/phases/phase-3-dev.md` "MUST: Figma MCP-first (BLOCKING pre-step)".
20
+ > **MUST: Figma MCP-first (BLOCKING).** If the task references any Figma frame (URL, node ID, or "from the design"), the Dev phase MUST call `mcp__claude_ai_Figma__get_design_context` for every frame BEFORE writing a single UI line. Use the `CodeConnectSnippet` component name verbatim - no sound-alike substitutions. Authentication failure is not a skip path. Full rule, trigger conditions, and gate failure modes: `$HOME/.claude/rules/figma-pipeline.md` "MUST: Figma MCP-first (BLOCKING)". Phase wiring: `$HOME/.claude/multi-agent-refs/phases/phase-2-dev.md` "MUST: Figma MCP-first (BLOCKING pre-step)".
21
21
 
22
22
  When the task involves creating a SwiftUI component (any project), follow this architecture.
23
23
  These practices come from the battle-tested Figma-to-SwiftUI pipeline - apply them in every iOS project.
@@ -270,4 +270,4 @@ FLEXManager.shared.showExplorer()
270
270
 
271
271
  If user provides a Figma URL, use Figma MCP tools (get_design_context, get_screenshot) to fetch design data, map to project tokens, and apply Configuration/View/Modifiers pattern.
272
272
 
273
- For figma project specifically: multi-agent reads `.instructions/figma/` SKILL.md files for the full 8-phase pipeline.
273
+ For figma project specifically: multi-agent reads `.instructions/figma/` SKILL.md files for the full 6-phase pipeline.
@@ -66,7 +66,7 @@ Two constraints on `update_plan`, both of which fail quietly if ignored:
66
66
  - **It is unavailable in Codex plan mode.** Fall back to
67
67
  `bash phase-tracker.sh render` there rather than skipping the visual channel.
68
68
 
69
- The plan step is the phase label, not a restatement of the work: `Phase 4 - Review`
69
+ The plan step is the phase label, not a restatement of the work: `Phase 3 - Review`
70
70
  in the step list, with detail going to the agent log. A plan that mirrors the phase
71
71
  list is legible; one that mirrors the task list duplicates what the log already
72
72
  holds.
@@ -89,10 +89,10 @@ Phases by mode:
89
89
 
90
90
  | Mode | Phases |
91
91
  |---|---|
92
- | `/multi-agent` | 0,1,2,3,4,5,6,7 |
93
- | `/multi-agent:local` | 0,1,2,3,4,6,7 (Phase 5 User Test needs a worktree checkout; local has none) |
94
- | `/multi-agent:autopilot`, `/multi-agent:local-autopilot` | 0,1,2,3,4,6,7 (always Full; autopilot drops the interactive Phase 5 gate) |
95
- | `/multi-agent:analysis` | 0,1,2,4,6,7 (no code is written, so no Dev and no Test) |
92
+ | `/multi-agent` | 0,1,2,3,4,5 |
93
+ | `/multi-agent:local` | 0,1,2,3,4,5 (the user test needs a worktree checkout and local has none, so that STEP inside Review is skipped - the phase is not) |
94
+ | `/multi-agent:autopilot`, `/multi-agent:local-autopilot` | 0,1,2,3,4,5 (always Full; autopilot drops the interactive user test inside Review) |
95
+ | `/multi-agent:analysis` | 0,1,3,4,5 (no code is written, so Dev is not in the set) |
96
96
 
97
97
  The two picker entries (`/multi-agent`, `:local`) register in two batches, because at Step -1 they do not yet know which set is theirs: see "Deferred registration" below. Every other mode registers its whole set at Step -1.
98
98
 
@@ -107,7 +107,7 @@ bash $HOME/.claude/scripts/phase-tracker.sh add 1 "Analysis"
107
107
  ### Claude Code - also register a TaskList tile per phase
108
108
 
109
109
  ```text
110
- For each phase in the current mode, IN PHASE-NUMBER ORDER (0 → 1 → 2 → ... → 7):
110
+ For each phase in the current mode, IN PHASE-NUMBER ORDER (0 → 1 → 2 → ... → 5):
111
111
  TaskCreate({
112
112
  subject: "Phase 0: Init",
113
113
  description: "Repo discovery, branch, worktree, identity bind",
@@ -178,39 +178,37 @@ The correct sequence is **always**:
178
178
  ```text
179
179
  # Step A - register every phase tile in the ACTIVE MODE'S SET, in phase-number
180
180
  # order. A phase outside the mode's set gets no TaskCreate at all - the example
181
- # below is the full pipeline, whose set happens to be all eight.
181
+ # below is the full pipeline, whose set happens to be all six.
182
182
  TaskCreate(Phase 0) → taskId₀
183
183
  TaskCreate(Phase 1) → taskId₁
184
184
  TaskCreate(Phase 2) → taskId₂
185
185
  TaskCreate(Phase 3) → taskId₃
186
186
  TaskCreate(Phase 4) → taskId₄
187
187
  TaskCreate(Phase 5) → taskId₅
188
- TaskCreate(Phase 6) → taskId₆
189
- TaskCreate(Phase 7) → taskId₇
190
188
 
191
189
  # Step B - only AFTER every tile is created, apply status updates
192
190
  TaskUpdate(taskId₀, status="in_progress") # Phase 0 starts
193
191
  # A phase that IS in the set but short-circuits at runtime flips here, e.g. a
194
- # full-pipeline run whose Phase 5 test gate is suppressed by autopilot:
195
- TaskUpdate(taskId₅, status="completed", activeForm="[SKIPPED]")
192
+ # full-pipeline run whose Phase 3 user test is suppressed by autopilot:
193
+ TaskUpdate(taskId₃, status="completed", activeForm="[SKIPPED]")
196
194
  ```
197
195
 
198
196
  Mode-specific phase sets:
199
197
 
200
198
  | Mode | TaskCreate set (in order) |
201
199
  |---|---|
202
- | `/multi-agent` | 0 at Step -1; then at Step 7.5 either 1 → 2 → 3 → 4 → 5 → 6 → 7 (Full) or 3 → 4 → 5 → 6 → 7 (Short) |
203
- | `:local` | same two batches, with Phase 5 in neither |
204
- | `:autopilot`, `:local-autopilot` | 0 → 1 → 2 → 3 → 4 → 6 → 7 (7 phases - always Full, and the interactive Phase 5 gate is dropped) |
205
- | `:analysis` | 0 → 1 → 2 → 4 → 6 → 7 (6 phases - no code is written, so 3 and 5 are not in the set) |
200
+ | `/multi-agent` | 0 at Step -1; then at Step 7.5 either 1 → 2 → 3 → 4 → 5 (Full) or 2 → 3 → 4 → 5 (Short) |
201
+ | `:local` | same two batches; nothing is dropped, because the user test that needs a worktree checkout is a step inside Review rather than a phase of its own |
202
+ | `:autopilot`, `:local-autopilot` | 0 → 1 → 2 → 3 → 4 → 5 (6 phases - always Full; the user test is inside Review now, so no phase is dropped) |
203
+ | `:analysis` | 0 → 1 → 3 → 4 → 5 (5 phases - no code is written, so Dev is not in the set) |
206
204
 
207
- A phase outside the mode's set gets no TaskCreate at all; the `[SKIPPED]` pattern applies only to a phase that IS in the set and short-circuits at runtime. Phase 4 is in every mode's set as of v14.0.0. The authoritative per-mode set is the `for p in ...` init block in each mode's own entry doc, generated by `gen-mode-dispatch.mjs`; this table mirrors those blocks.
205
+ A phase outside the mode's set gets no TaskCreate at all; the `[SKIPPED]` pattern applies only to a phase that IS in the set and short-circuits at runtime. Phase 3 is in every mode's set as of v14.0.0. The authoritative per-mode set is the `for p in ...` init block in each mode's own entry doc, generated by `gen-mode-dispatch.mjs`; this table mirrors those blocks.
208
206
 
209
207
  #### Deferred registration - the depth picker
210
208
 
211
209
  `/multi-agent` and `:local` cannot know their phase set at Step -1. Depth decides it, and the depth picker cannot run before Step 7.5: its recommendation needs `taskType`, which needs the fetched issue and the branch.
212
210
 
213
- Until v17.5.0 they registered all eight anyway and flipped 1 and 2 to `skipped` at 7.5. That put a widget reading "8 tasks, 7 open - Phase 1 Analysis, Phase 2 Planning, ..." on screen *beside* the question asking whether to run Analysis and Planning at all, and a Short answer then contradicted a list the user had just been shown. The widget was asserting a shape the run had not chosen.
211
+ Until v17.5.0 they registered all eight anyway and flipped 1 and 2 to `skipped` at 7.5. That put a widget reading "8 tasks, 7 open - Phase 1 Plan, Phase 1 Plan, ..." on screen *beside* the question asking whether to run Analysis and Planning at all, and a Short answer then contradicted a list the user had just been shown. The widget was asserting a shape the run had not chosen.
214
212
 
215
213
  So registration splits at the moment the shape is known:
216
214
 
@@ -222,9 +220,10 @@ bash $HOME/.claude/scripts/phase-tracker.sh tiles # -> TaskCreate(Phase 0
222
220
  bash $HOME/.claude/scripts/phase-tracker.sh update 0 in_progress
223
221
 
224
222
  # Step 7.5, immediately after the depth answer:
225
- # Full -> 1 2 3 4 5 6 7 Short -> 3 4 5 6 7
226
- # :local drops 5 from either (no worktree to check out from)
227
- for p in "3:Dev" "4:Review" "5:Test" "6:Commit" "7:Report"; do
223
+ # Full -> 1 2 3 4 5 Short -> 2 3 4 5
224
+ # :local drops nothing - the user test lives inside Review now, so there is
225
+ # no separate phase for it to skip
226
+ for p in "1:Plan" "2:Dev" "3:Review" "4:Commit" "5:Report"; do
228
227
  bash $HOME/.claude/scripts/phase-tracker.sh add "${p%%:*}" "${p#*:}"
229
228
  done
230
229
  bash $HOME/.claude/scripts/phase-tracker.sh tiles --new # -> TaskCreate for the new tiles only
@@ -232,7 +231,7 @@ bash $HOME/.claude/scripts/phase-tracker.sh tiles --new # -> TaskCreate for th
232
231
 
233
232
  `tiles --new` emits `TaskCreate` only for phases that carry no `tasklist_id` yet, so the Phase 0 tile is not created twice. It is the same ordering rule, applied per batch: every tile in a batch is created in ascending phase order, and a deferred batch only ever appends phases numbered above everything already registered. Nothing is pre-marked, and a phase the run will not execute never gets a tile at all.
234
233
 
235
- A phase that IS registered and short-circuits later still flips with `[SKIPPED]` - autopilot suppressing Phase 5, for instance. That is a runtime outcome, not an unknown set.
234
+ A phase that IS registered and short-circuits later still flips with `[SKIPPED]` - autopilot suppressing the Phase 3 user test, for instance. That is a runtime outcome, not an unknown set.
236
235
 
237
236
  **Enforcement**: `smoke-tasklist-ordering.sh` scans the dispatcher (`commands/multi-agent/SKILL.md`) and every mode entry point doc (`commands/multi-agent/{autopilot,local,local-autopilot,analysis,resume-local}/SKILL.md` + the Copilot full-inline orchestrator mirror) for the explicit "in phase-number order" rule. Inventory drift fails the smoke.
238
237
 
@@ -300,12 +299,12 @@ Throttling rules: mirror only canonical-set lines (`verbose`-tier internals are
300
299
 
301
300
  ### Delegated phases - mirror limitation + chunked dispatch (required)
302
301
 
303
- When a phase's work is delegated to a subagent (Phase 3 Dev on Opus in a Short run, `create-component` plugin dispatch, Phase 1 explorers, Phase 4 reviewers), the visual channel freezes for the duration of the Agent call: the orchestrator is blocked while the call is in flight, so it cannot fire `TaskUpdate` / `now` / `tokens`, and a subagent cannot drive the parent session's TaskList (its own TaskCreate/TaskUpdate calls land on an invisible child list). The progress-line mirror above can therefore only fire while the orchestrator holds control. Rules:
302
+ When a phase's work is delegated to a subagent (Phase 2 Dev on Opus in a Short run, `create-component` plugin dispatch, Phase 1 explorers, Phase 3 reviewers), the visual channel freezes for the duration of the Agent call: the orchestrator is blocked while the call is in flight, so it cannot fire `TaskUpdate` / `now` / `tokens`, and a subagent cannot drive the parent session's TaskList (its own TaskCreate/TaskUpdate calls land on an invisible child list). The progress-line mirror above can therefore only fire while the orchestrator holds control. Rules:
304
303
 
305
304
  1. **Pre-dispatch marker.** Immediately before every Agent call, set the active-phase line to the delegation itself, so the frozen interval at least states what is running and on which model:
306
305
  - Claude Code: `TaskUpdate({activeForm: "Dev subagent (opus): <task subject>"})`
307
306
  - Other CLIs: `phase-tracker.sh now <N> "dev subagent (opus): <task subject>"`
308
- 2. **Chunk long delegations.** A phase whose delegated work spans multiple tasks MUST NOT go out as one monolithic Agent call. Dispatch per task (the Phase 2 task graph, or in a Short run the self-generated task list, is the natural chunk boundary) so the orchestrator regains control at each boundary and refreshes `activeForm`, `tokens`, and `now` between chunks. Single-task phases and inherently atomic dispatches (one reviewer, one explorer) are exempt.
307
+ 2. **Chunk long delegations.** A phase whose delegated work spans multiple tasks MUST NOT go out as one monolithic Agent call. Dispatch per task (the Phase 1 task graph, or in a Short run the self-generated task list, is the natural chunk boundary) so the orchestrator regains control at each boundary and refreshes `activeForm`, `tokens`, and `now` between chunks. Single-task phases and inherently atomic dispatches (one reviewer, one explorer) are exempt.
309
308
  3. **Post-chunk accounting.** When each chunk returns, record its token estimate (`phase-tracker.sh tokens <N> <in> <out>`) before dispatching the next chunk - not accumulated once at phase end.
310
309
 
311
310
  ### 5. Token accounting - automatic (manual top-up optional)
@@ -322,7 +321,7 @@ Token counts are additive - multiple calls accumulate. `input_count` is FRESH
322
321
  **Required: per-phase token narration on completion (v9.10.2).** The native
323
322
  TaskList widget cannot display per-phase tokens - it shows name, status, and
324
323
  duration only. Without this rule the user sees durations and nothing else
325
- until the Phase 7 Cost Breakdown. So whenever a phase transitions to
324
+ until the Phase 5 Cost Breakdown. So whenever a phase transitions to
326
325
  `completed`, in addition to the `TaskUpdate` call, print ONE narrator line in
327
326
  `outputLanguage` immediately after, using the same totals just written via
328
327
  `phase-tracker.sh tokens`:
@@ -344,7 +343,7 @@ fixed at TaskCreate time). So on phase completion, in addition to the
344
343
  narration line, append the spend to the tile subject:
345
344
 
346
345
  ```text
347
- TaskUpdate({taskId: <phase_task>, subject: "Phase 3: Dev · ~35k tok · ~$0.26"})
346
+ TaskUpdate({taskId: <phase_task>, subject: "Phase 2: Dev · ~35k tok · ~$0.26"})
348
347
  ```
349
348
 
350
349
  Skip the suffix when the phase recorded zero tokens (subject stays clean).
@@ -353,7 +352,7 @@ Skip the suffix when the phase recorded zero tokens (subject stays clean).
353
352
  usage metering, so per-phase counts are content-size estimates (chars/4 for
354
353
  prompts dispatched + responses received, subagent payloads included). Prefix
355
354
  estimates with `~`. The authoritative end-of-run numbers remain the state file
356
- and the Phase 7 Cost Breakdown; the narration line exists so the user sees
355
+ and the Phase 5 Cost Breakdown; the narration line exists so the user sees
357
356
  live per-phase spend instead of duration-only tiles.
358
357
 
359
358
  ### 6. Phase context - rich summaries via `meta`
@@ -393,19 +392,19 @@ TaskUpdate({taskId: <phase_task>, activeForm: "Running explorer: repo-map"})
393
392
 
394
393
  ## The plan is part of the list
395
394
 
396
- Phase 2 computes `tasks[]`, their order and their `dependsOn[]` edges, stores
397
- them, and uses them to drive Phase 3's ready-task picker. For releases the card
395
+ Phase 1 computes `tasks[]`, their order and their `dependsOn[]` edges, stores
396
+ them, and uses them to drive Phase 2's ready-task picker. For releases the card
398
397
  drew them as sub-phases and the widget did not, which meant the one surface the
399
398
  user actually watches was the one place the plan did not exist.
400
399
 
401
- Phase 2 Step 4.45 calls `phase-tracker.sh plan 3` with the planning-output
400
+ Phase 1 Step 4.45 calls `phase-tracker.sh plan 3` with the planning-output
402
401
  document on stdin. Each task becomes a sub-phase of the phase that will execute
403
- it, `pending`, carrying its `dependsOn[]` as `deps`. Phase 3 moves them with
402
+ it, `pending`, carrying its `dependsOn[]` as `deps`. Phase 2 moves them with
404
403
  `sub` as it works.
405
404
 
406
405
  **A rebuild, not an append.** Creation order is the only ordering the native
407
406
  widget has - there is no parent field and no insert - so steps arriving at
408
- Phase 2 cannot be appended without landing after Phase 7. `tiles` detects that
407
+ Phase 2 cannot be appended without landing after Phase 5. `tiles` detects that
409
408
  sub-steps exist and asks for the list to be deleted and recreated. That is one
410
409
  rebuild at one boundary, and it is the same thing Resume already does below for
411
410
  a different reason.
@@ -439,7 +438,7 @@ A pre-existing `tracker-state.json` for the task is never re-initialized. Rules
439
438
 
440
439
  1. `init` runs ONLY when no state file exists for the task. Otherwise the existing file is kept - phase history (elapsed, tokens, model, meta) survives.
441
440
  2. The continuing command re-declares its phase set with `add` - `add` is idempotent, so existing phases keep their name, status, and token history; only genuinely new phases are appended. The card renders phases sorted by numeric id, so mixed sets stay in order.
442
- 3. If Phase 5 was left `in_progress` with `Now: awaiting local test (user)`, the continuing command marks it `update 5 completed` + `meta 5 Result "local test done (user)"` before its own work starts (finish may re-open it with `update 5 in_progress` when its build+test gate runs; elapsed keeps the original `started_at`, which is acceptable).
441
+ 3. If Phase 3 was left `in_progress` with `Now: awaiting local test (user)`, the continuing command marks it `update 5 completed` + `meta 5 Result "local test done (user)"` before its own work starts (finish may re-open it with `update 5 in_progress` when its build+test gate runs; elapsed keeps the original `started_at`, which is acceptable).
443
442
  4. On Claude Code, rebuild the FULL TaskList from the state file (completed tiles included) in phase order before any `TaskUpdate`, refreshing every `tasklist_id` meta - exactly the Resume behaviour above.
444
443
  5. Print ONE line in `outputLanguage` summarizing the inherited history, e.g. `Continuing PROJ-12345: phases 0-3 finished earlier (12m, 38.4k tok, ~$0.74)` (USD via `cost total`), then `render`.
445
444
 
@@ -0,0 +1,129 @@
1
+ # Unattended contract (`MULTI_AGENT_UNATTENDED=1`)
2
+
3
+ <!-- toc -->
4
+ - [What the variable means](#what-the-variable-means)
5
+ - [The three effects](#the-three-effects)
6
+ - [What it does NOT do](#what-it-does-not-do)
7
+ - [Who honours it](#who-honours-it)
8
+ - [The model side already has a contract](#the-model-side-already-has-a-contract)
9
+ - [Default behaviour is unchanged, and a gate says so](#default-behaviour-is-unchanged-and-a-gate-says-so)
10
+ - [The permission posture](#the-permission-posture)
11
+ <!-- /toc -->
12
+
13
+ ## What the variable means
14
+
15
+ `MULTI_AGENT_UNATTENDED=1` is the operator stating that **nobody is watching
16
+ this process**, and it is the only way to state it reliably.
17
+
18
+ The usual test for that is `[ -t 0 ]`: no terminal, no human. It is wrong in
19
+ both directions on a server. A run under `screen`, `tmux`, `ssh -t` or a login
20
+ shell HAS a terminal and still has nobody in front of it, so the test says
21
+ "ask" and the process waits for an answer that will never come - printing
22
+ nothing, exiting never, and looking exactly like slow work. That is the failure
23
+ this contract exists to remove, and it is not hypothetical: two setup scripts
24
+ shipped that way.
25
+
26
+ The variable is opt-in and defaults to absent. Nothing in this file describes
27
+ behaviour that changes on a machine that does not set it.
28
+
29
+ ## The three effects
30
+
31
+ **1. No prompt blocks.** Every shell entry point that asks a question either
32
+ resolves it from a documented default or refuses with a reason on stderr and a
33
+ non-zero exit. Waiting is never one of the outcomes. Refusing beats hanging:
34
+ one of them can be read in a log.
35
+
36
+ **2. Output is greppable.** Colour is off even when stdout is a terminal.
37
+ ANSI escapes in a log file make it unsearchable, and on a server the terminal
38
+ that is attached is not the one anyone reads.
39
+
40
+ **3. A secret is never a prompt.** Credentials arrive through stdin or a file
41
+ path, never through an interactive read and never through an environment
42
+ variable. An env value is inherited by every child process and is visible to
43
+ `ps e` on some systems; a pipe stays in the one process that needs it.
44
+
45
+ ## What it does NOT do
46
+
47
+ - It does not grant permissions. An unattended run still needs a permission
48
+ posture, which is a separate opt-in (`install --unattended`) and a separate
49
+ doctor check.
50
+ - It does not suppress errors. A run that cannot proceed still fails; it just
51
+ fails visibly instead of hanging.
52
+ - It does not change any default. With the variable unset, every script below
53
+ behaves exactly as it did before this contract existed.
54
+
55
+ ## Who honours it
56
+
57
+ Paths below are install-relative: `lib/` and `scripts/` under the host root,
58
+ which is `~/.claude`, `~/.copilot` or `~/.codex` depending on the install. A
59
+ ref that ships to users must not name a checkout path, because a run happens
60
+ in the user's worktree and the checkout is not there.
61
+
62
+ | Entry point | Without the variable | With `MULTI_AGENT_UNATTENDED=1` |
63
+ |---|---|---|
64
+ | `lib/ask-choice.sh` | TTY: renders the menu and reads. No TTY: first option, notice on stderr | First option (or `ASK_CHOICE_DEFAULT`), never prompts |
65
+ | `scripts/github-ssh-setup.sh` | TTY: three questions. No TTY: refuses, naming `SSH_SETUP_EMAIL` | Refuses the same way even with a terminal |
66
+ | `scripts/keychain-save.sh` | TTY: menu + secret prompt. No TTY: refuses, naming `--stdin` / `--json` | Refuses the same way even with a terminal |
67
+ | `scripts/phase-banner.sh` | Colour when stdout is a TTY and `TERM != dumb` | Plain text |
68
+
69
+ Anything not in this table does not read the variable. That is deliberate: a
70
+ list of four that is true beats a claim of coverage that is not.
71
+
72
+ ## The model side already has a contract
73
+
74
+ The prompt-level question - what an agent does when it would call
75
+ `AskUserQuestion` and no one can answer - is `refs/picker-contract.md`, section
76
+ "Autopilot / non-interactive contract", and it predates this file. It resolves
77
+ from the remembered choice first, then the documented default, and records
78
+ which rule fired so the run stays readable afterwards.
79
+
80
+ The two are different layers and should not be merged. The picker contract
81
+ governs a model deciding; this file governs a process waiting. A run on a
82
+ server needs both, and only one of them can be enforced by a gate.
83
+
84
+ ## Default behaviour is unchanged, and a gate says so
85
+
86
+ `smoke-unattended-profile.sh` (a maintainer gate, not shipped) asserts both directions. With the variable set,
87
+ each entry point above resolves or refuses under a hard timeout. With it unset,
88
+ each one produces byte-identical output to the behaviour it had before - the
89
+ assertion that matters most, because the whole point is that a local
90
+ interactive machine is not affected by any of this.
91
+
92
+ ## The permission posture
93
+
94
+ Everything above concerns a process that would otherwise WAIT. There is a second
95
+ way an unattended run stops, and it does not wait at all.
96
+
97
+ autopilot spawns its child with `--permission-prompts none`. That stops Claude
98
+ Code from ASKING; it grants nothing. The tools the child then calls still have
99
+ to be allowed, and on a fresh machine they are not - so the run stops at the
100
+ first tool call, with no prompt anywhere for a person to answer. From the
101
+ outside it is indistinguishable from a queue with nothing to do.
102
+
103
+ `install --unattended` writes the profile that closes it:
104
+
105
+ ```bash
106
+ npx @mmerterden/multi-agent-pipeline install --unattended --dry-run # show it
107
+ npx @mmerterden/multi-agent-pipeline install --unattended # write it
108
+ ```
109
+
110
+ Three properties, each one a promise to somebody who did not ask for this:
111
+
112
+ 1. A DEFAULT install writes no permissions at all. Widening a permission set is
113
+ not something an installer does to a person who wanted files copied.
114
+ 2. The profile is printed in full, with a reason per line, BEFORE anything is
115
+ written. "The installer changed my permissions" must never be a thing
116
+ discovered afterwards.
117
+ 3. It is additive and idempotent. An entry a person added by hand survives, a
118
+ narrower rule is kept alongside, unrelated settings are untouched, and a
119
+ second run changes nothing. A `settings.json` that does not parse is refused
120
+ rather than overwritten.
121
+
122
+ The entries are broad, and that breadth is what unattended operation costs
123
+ rather than an oversight: a run builds and tests whatever the target repo uses,
124
+ so an allowlist narrow enough to be interesting is one the first unfamiliar repo
125
+ stops at. `doctor --profile=server` reports `unattended-permissions` against the
126
+ same rule the writer applies, so the two cannot disagree.
127
+
128
+ `smoke-unattended-install-profile.sh` asserts all of it, including that a plain
129
+ install still writes nothing.
@@ -11,9 +11,9 @@
11
11
  - [Cross-CLI parity](#cross-cli-parity)
12
12
  <!-- /toc -->
13
13
 
14
- > **TLDR** - Component tasks can auto-generate wiki docs + Figma screenshots. The Wiki adapter is invoked from `/multi-agent:channels` (Phase 7 delegates, or user invokes post-hoc). Four layouts supported (`submodule`, `in-repo`, `github-wiki`, `separate-repo`) - adapter picked from `figmaConfig.wiki.mode`. Non-blocking: failures log a warning and channels continues to other adapters. The Wiki adapter supports scope multi-select (Case A) and a precondition-failure menu (Case B) - see below.
14
+ > **TLDR** - Component tasks can auto-generate wiki docs + Figma screenshots. The Wiki adapter is invoked from `/multi-agent:channels` (Phase 5 delegates, or user invokes post-hoc). Four layouts supported (`submodule`, `in-repo`, `github-wiki`, `separate-repo`) - adapter picked from `figmaConfig.wiki.mode`. Non-blocking: failures log a warning and channels continues to other adapters. The Wiki adapter supports scope multi-select (Case A) and a precondition-failure menu (Case B) - see below.
15
15
 
16
- This doc is referenced from `commands/multi-agent/channels/SKILL.md` (Wiki adapter) and indirectly from `$HOME/.claude/multi-agent-refs/phases/phase-7-report.md` (which delegates all external delivery to channels). Keeping it separate keeps both files under their token budgets and gives the contract a stable location for Claude-side + Copilot-side implementations.
16
+ This doc is referenced from `commands/multi-agent/channels/SKILL.md` (Wiki adapter) and indirectly from `$HOME/.claude/multi-agent-refs/phases/phase-5-report.md` (which delegates all external delivery to channels). Keeping it separate keeps both files under their token budgets and gives the contract a stable location for Claude-side + Copilot-side implementations.
17
17
 
18
18
  ## Applicability
19
19
 
@@ -43,7 +43,7 @@ What should I update in the wiki? (space = toggle, enter = confirm)
43
43
  Pre-ticks from `prefs.global.wikiScope` (array of scope IDs). Saved after selection for next run.
44
44
 
45
45
  - Selecting a subset (e.g. only Screenshots) → adapter runs with `scope=["screenshots"]`, skipping main/iOS/index writes.
46
- - Selecting "Other" alone → adapter dispatch is skipped entirely. Phase 7 / channels logs `Wiki: manual override - skipped by user`. No git push, no file changes.
46
+ - Selecting "Other" alone → adapter dispatch is skipped entirely. Phase 5 / channels logs `Wiki: manual override - skipped by user`. No git push, no file changes.
47
47
  - Selecting nothing and confirming → same as "Other" alone (explicit skip).
48
48
 
49
49
  The adapter receives `scope: string[]` alongside `{componentName, componentPath, figmaConfig, agentState}` and writes only the requested artifacts.
@@ -53,7 +53,7 @@ The adapter receives `scope: string[]` alongside `{componentName, componentPath,
53
53
  When preconditions fail, the gap is surfaced with a fix menu instead of a silent no-op:
54
54
 
55
55
  ```
56
- Phase 7 · Wiki - preconditions not met
56
+ Phase 5 · Wiki - preconditions not met
57
57
 
58
58
  taskType: {current} ({component expected} ✗)
59
59
  figma-config.json: {found/missing}
@@ -67,11 +67,11 @@ Phase 7 · Wiki - preconditions not met
67
67
  ```
68
68
 
69
69
  - **[1]** dispatches to `setup.md` Token Save Flow for Figma, then bootstraps `figma-config.json` from `preferences-template.json` `_figmaConfigTemplate`. After success, re-check preconditions - if met, fall into Case A. If user cancels the setup, fall back to [2].
70
- - **[2]** `phase-tracker.sh sub 7 1 "Channels/Wiki" skipped`, log line: `Wiki skipped - preconditions not met (this run only)`. Next run re-prompts.
70
+ - **[2]** `phase-tracker.sh sub 5 1 "Channels/Wiki" skipped`, log line: `Wiki skipped - preconditions not met (this run only)`. Next run re-prompts.
71
71
  - **[3]** write `figmaConfig.wiki.enabled = false` to the project config. Subsequent runs silently skip Wiki (no menu, no prompt) - exactly the pre-v5.7 behavior for projects that don't want wiki.
72
72
  - **[4]** free-text prompt, user's note appended to agent-log under `### Wiki Manual Override`. No adapter action.
73
73
 
74
- Autopilot in Phase 7 pauses at the channels menu (per modes.md contract) - if user selects Wiki and preconditions fail, Case B opens, user picks. Post-hoc `/multi-agent:channels` with `--channels wiki` + failed preconditions: Case B opens non-negotiably (autopilot rules don't apply to post-hoc invocations).
74
+ Autopilot in Phase 5 pauses at the channels menu (per modes.md contract) - if user selects Wiki and preconditions fail, Case B opens, user picks. Post-hoc `/multi-agent:channels` with `--channels wiki` + failed preconditions: Case B opens non-negotiably (autopilot rules don't apply to post-hoc invocations).
75
75
 
76
76
  ## Legacy prompt + preference flow (pre-v5.7, still supported for backward compat)
77
77
 
@@ -91,23 +91,23 @@ Save the answer to `prefs.global.wikiDefault` for next run. Migration script (`m
91
91
  1. Resolve wiki mode from `figmaConfig.wiki.mode` - one of `submodule`, `in-repo`, `github-wiki`, `separate-repo`. Each has a dedicated adapter inside the `figma-component-wiki` skill; see the `ai-ios-toolkit:figma-component-wiki` plugin skill for per-mode path layout and push semantics.
92
92
  2. Emit progress line: `→ writing wiki {componentName} (mode: {mode})`.
93
93
  3. Dispatch to the plugin skill `ai-ios-toolkit:figma-component-wiki` (iOS) or `ai-android-toolkit:figma-component-wiki` (Android), passing `{componentName, componentPath, figmaConfig}`.
94
- 4. Skill returns `{ writtenPaths[], committedSha?, pushedRemote? }`. Write `writtenPaths` to Phase 7 summary's "Files written" section and push metadata (if any) to "External publishes".
95
- 5. On adapter failure - log the adapter + mode + error, continue Phase 7. Wiki is a non-blocking augmentation; the Jira comment in Step 3 already carries the component summary, so the developer is never left in the dark if wiki misfires.
94
+ 4. Skill returns `{ writtenPaths[], committedSha?, pushedRemote? }`. Write `writtenPaths` to Phase 5 summary's "Files written" section and push metadata (if any) to "External publishes".
95
+ 5. On adapter failure - log the adapter + mode + error, continue Phase 5. Wiki is a non-blocking augmentation; the Jira comment in Step 3 already carries the component summary, so the developer is never left in the dark if wiki misfires.
96
96
 
97
97
  ## Skip conditions (explicit log lines)
98
98
 
99
99
  Explicit logs help the developer understand why wiki did or did not run:
100
100
 
101
101
  - `state.taskType !== "component"` → skip silently (no log).
102
- - `figmaConfig.wiki.enabled === false` → log `Phase 7: wiki disabled in figma-config.json`.
103
- - `figmaConfig` missing entirely → log `Phase 7: wiki skipped (no figma-config for this project)`.
104
- - User declined at prompt → log `Phase 7: wiki skipped by user`.
105
- - Autopilot with `wikiDefault=false` → log `Phase 7: wiki skipped (autopilot + wikiDefault=false)`.
102
+ - `figmaConfig.wiki.enabled === false` → log `Phase 5: wiki disabled in figma-config.json`.
103
+ - `figmaConfig` missing entirely → log `Phase 5: wiki skipped (no figma-config for this project)`.
104
+ - User declined at prompt → log `Phase 5: wiki skipped by user`.
105
+ - Autopilot with `wikiDefault=false` → log `Phase 5: wiki skipped (autopilot + wikiDefault=false)`.
106
106
  - Short run: DO prompt - wiki is cheap and keeps docs fresh on the fast path; skip only if the user says no.
107
107
 
108
108
  ## Success log
109
109
 
110
- `Phase 7: Component wiki generated - {componentName} via {mode} ({paths.length} files)`
110
+ `Phase 5: Component wiki generated - {componentName} via {mode} ({paths.length} files)`
111
111
 
112
112
  ## Cross-CLI parity
113
113
 
@@ -118,6 +118,6 @@ Claude Code and Copilot CLI MUST:
118
118
  - Render byte-identical Case A / Case B menus (spacing, brackets, numbering).
119
119
  - Respect `prefs.global.wikiScope` array. Legacy `wikiDefault` boolean is migrated on first v5.7 load.
120
120
  - Treat adapter failures as non-blocking with the same log shape.
121
- - Pause the Case A / Case B menu in autopilot - per Phase 7 autopilot exception (`$HOME/.claude/multi-agent-refs/phases/modes.md`). 30-min timeout ends session cleanly; resume re-opens menu.
121
+ - Pause the Case A / Case B menu in autopilot - per Phase 5 autopilot exception (`$HOME/.claude/multi-agent-refs/phases/modes.md`). 30-min timeout ends session cleanly; resume re-opens menu.
122
122
 
123
123
  `smoke-wiki-integration.sh` asserts every contract item documented above.
@@ -1,5 +1,5 @@
1
1
  {
2
- "schemaVersion": "2.6.0",
2
+ "schemaVersion": "2.7.0",
3
3
  "global": {
4
4
  "identities": [],
5
5
  "keychainMapping": {
@@ -67,6 +67,14 @@
67
67
  "fableEnabled": false,
68
68
  "onDispatchError": true
69
69
  },
70
+ "modelRouting": {
71
+ "enabled": false,
72
+ "strategy": "manual",
73
+ "scope": ["subagent"],
74
+ "rules": [],
75
+ "budgetCeilingUsd": null,
76
+ "recordDecisions": true
77
+ },
70
78
  "costBudget": {
71
79
  "enabled": true,
72
80
  "maxUsd": 5.0,
@@ -1,7 +1,7 @@
1
1
  ## Outside a pipeline run
2
2
 
3
3
  `/multi-agent` is not the only way to use what the install set up. Reach for
4
- these when the work calls for it - not eagerly, and not by starting an 8-phase
4
+ these when the work calls for it - not eagerly, and not by starting a 6-phase
5
5
  run to read one ticket. Detail, commands and the safety contract:
6
6
  `$HOME/.claude/multi-agent-refs/outside-the-pipeline.md` - absent on a host that
7
7
  installs no refs tree, in which case the summary below is the contract.