@mmerterden/multi-agent-pipeline 20.28.0 → 20.30.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 (186) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +19 -6
  3. package/README.tr.md +5 -5
  4. package/docs/architecture.md +3 -3
  5. package/docs/ecosystem.md +5 -5
  6. package/docs/facts.json +7 -7
  7. package/install/catalog-history.json +1 -1
  8. package/install/claude.mjs +122 -1
  9. package/install/codex.mjs +2 -0
  10. package/install/copilot.mjs +13 -0
  11. package/install/templates/claude-hooks.json +30 -1
  12. package/manifest.json +189 -77
  13. package/package.json +2 -1
  14. package/pipeline/commands/multi-agent/analysis/SKILL.md +3 -1
  15. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +13 -15
  16. package/pipeline/commands/multi-agent/office-off/SKILL.md +27 -0
  17. package/pipeline/commands/multi-agent/office-on/SKILL.md +50 -0
  18. package/pipeline/commands/multi-agent/office-status/SKILL.md +29 -0
  19. package/pipeline/commands/multi-agent/resume/SKILL.md +2 -1
  20. package/pipeline/commands/multi-agent/serve/SKILL.md +4 -2
  21. package/pipeline/commands/multi-agent/stack/SKILL.md +15 -8
  22. package/pipeline/commands/multi-agent/steer/SKILL.md +10 -9
  23. package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
  24. package/pipeline/contract/CHANGELOG.md +62 -0
  25. package/pipeline/contract/README.md +52 -6
  26. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  27. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  28. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  29. package/pipeline/contract/manifest.json +367 -22
  30. package/pipeline/contract/types/index.d.ts +531 -4
  31. package/pipeline/lib/hook-registration.mjs +252 -0
  32. package/pipeline/lib/prefs-value.mjs +44 -0
  33. package/pipeline/lib/run-completion.mjs +148 -0
  34. package/pipeline/multi-agent-refs/analysis/render.md +4 -4
  35. package/pipeline/multi-agent-refs/cross-cli-contract.md +5 -4
  36. package/pipeline/multi-agent-refs/features/doctor.md +11 -0
  37. package/pipeline/multi-agent-refs/features/office-threat-model.md +91 -0
  38. package/pipeline/multi-agent-refs/help/en.md +3 -0
  39. package/pipeline/multi-agent-refs/help/tr.md +3 -0
  40. package/pipeline/multi-agent-refs/phases/operations.md +17 -0
  41. package/pipeline/multi-agent-refs/phases/phase-0-init.md +6 -2
  42. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +2 -2
  43. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +1 -1
  44. package/pipeline/multi-agent-refs/phases/phase-3-review.md +2 -2
  45. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +7 -6
  46. package/pipeline/multi-agent-refs/phases/phase-5-report.md +5 -4
  47. package/pipeline/office/NOTICE.md +42 -0
  48. package/pipeline/office/assets/BIN.png +0 -0
  49. package/pipeline/office/assets/BOOKSHELF.png +0 -0
  50. package/pipeline/office/assets/CACTUS.png +0 -0
  51. package/pipeline/office/assets/CLOCK.png +0 -0
  52. package/pipeline/office/assets/COFFEE.png +0 -0
  53. package/pipeline/office/assets/COFFEE_TABLE.png +0 -0
  54. package/pipeline/office/assets/CUSHIONED_BENCH.png +0 -0
  55. package/pipeline/office/assets/CUSHIONED_CHAIR_BACK.png +0 -0
  56. package/pipeline/office/assets/CUSHIONED_CHAIR_FRONT.png +0 -0
  57. package/pipeline/office/assets/CUSHIONED_CHAIR_SIDE.png +0 -0
  58. package/pipeline/office/assets/DESK_FRONT.png +0 -0
  59. package/pipeline/office/assets/DESK_SIDE.png +0 -0
  60. package/pipeline/office/assets/DOUBLE_BOOKSHELF.png +0 -0
  61. package/pipeline/office/assets/HANGING_PLANT.png +0 -0
  62. package/pipeline/office/assets/LARGE_PAINTING.png +0 -0
  63. package/pipeline/office/assets/LARGE_PLANT.png +0 -0
  64. package/pipeline/office/assets/PC_BACK.png +0 -0
  65. package/pipeline/office/assets/PC_FRONT_OFF.png +0 -0
  66. package/pipeline/office/assets/PC_FRONT_ON_1.png +0 -0
  67. package/pipeline/office/assets/PC_FRONT_ON_2.png +0 -0
  68. package/pipeline/office/assets/PC_FRONT_ON_3.png +0 -0
  69. package/pipeline/office/assets/PC_SIDE.png +0 -0
  70. package/pipeline/office/assets/PLANT.png +0 -0
  71. package/pipeline/office/assets/PLANT_2.png +0 -0
  72. package/pipeline/office/assets/POT.png +0 -0
  73. package/pipeline/office/assets/SMALL_PAINTING.png +0 -0
  74. package/pipeline/office/assets/SMALL_PAINTING_2.png +0 -0
  75. package/pipeline/office/assets/SMALL_TABLE_FRONT.png +0 -0
  76. package/pipeline/office/assets/SMALL_TABLE_SIDE.png +0 -0
  77. package/pipeline/office/assets/SOFA_BACK.png +0 -0
  78. package/pipeline/office/assets/SOFA_FRONT.png +0 -0
  79. package/pipeline/office/assets/SOFA_SIDE.png +0 -0
  80. package/pipeline/office/assets/TABLE_FRONT.png +0 -0
  81. package/pipeline/office/assets/WHITEBOARD.png +0 -0
  82. package/pipeline/office/assets/WOODEN_BENCH.png +0 -0
  83. package/pipeline/office/assets/WOODEN_CHAIR_BACK.png +0 -0
  84. package/pipeline/office/assets/WOODEN_CHAIR_FRONT.png +0 -0
  85. package/pipeline/office/assets/WOODEN_CHAIR_SIDE.png +0 -0
  86. package/pipeline/office/assets/char_0.png +0 -0
  87. package/pipeline/office/assets/char_1.png +0 -0
  88. package/pipeline/office/assets/char_2.png +0 -0
  89. package/pipeline/office/assets/char_3.png +0 -0
  90. package/pipeline/office/assets/char_4.png +0 -0
  91. package/pipeline/office/assets/char_5.png +0 -0
  92. package/pipeline/office/assets/floor_0.png +0 -0
  93. package/pipeline/office/assets/floor_1.png +0 -0
  94. package/pipeline/office/assets/floor_2.png +0 -0
  95. package/pipeline/office/assets/floor_3.png +0 -0
  96. package/pipeline/office/assets/floor_4.png +0 -0
  97. package/pipeline/office/assets/floor_5.png +0 -0
  98. package/pipeline/office/assets/floor_6.png +0 -0
  99. package/pipeline/office/assets/floor_7.png +0 -0
  100. package/pipeline/office/assets/floor_8.png +0 -0
  101. package/pipeline/office/assets/wall_0.png +0 -0
  102. package/pipeline/office/index.html +5319 -0
  103. package/pipeline/preferences-template.json +7 -0
  104. package/pipeline/rules/figma-pipeline.md +2 -0
  105. package/pipeline/schemas/activity-chat.schema.json +78 -0
  106. package/pipeline/schemas/activity-roles.json +48 -0
  107. package/pipeline/schemas/activity-roles.schema.json +49 -0
  108. package/pipeline/schemas/activity.schema.json +429 -0
  109. package/pipeline/schemas/agent-state.schema.json +20 -5
  110. package/pipeline/schemas/autopilot-on-request.schema.json +33 -0
  111. package/pipeline/schemas/autopilot-on.schema.json +111 -0
  112. package/pipeline/schemas/contract-error.schema.json +33 -3
  113. package/pipeline/schemas/issue-maturity.schema.json +68 -0
  114. package/pipeline/schemas/ledger.schema.json +202 -0
  115. package/pipeline/schemas/permissions.schema.json +47 -0
  116. package/pipeline/schemas/phases.json +3 -2
  117. package/pipeline/schemas/phases.schema.json +5 -1
  118. package/pipeline/schemas/prefs.schema.json +56 -0
  119. package/pipeline/schemas/prs.schema.json +73 -0
  120. package/pipeline/schemas/review-verdict-request.schema.json +20 -0
  121. package/pipeline/schemas/review-verdict.schema.json +62 -0
  122. package/pipeline/schemas/routine-delete.schema.json +59 -0
  123. package/pipeline/schemas/routines.schema.json +38 -0
  124. package/pipeline/schemas/run-evidence.schema.json +29 -0
  125. package/pipeline/schemas/run-results.schema.json +218 -0
  126. package/pipeline/schemas/runs-index.schema.json +1 -1
  127. package/pipeline/schemas/service-read.schema.json +58 -0
  128. package/pipeline/schemas/stack-change.schema.json +82 -0
  129. package/pipeline/schemas/stack-request.schema.json +33 -0
  130. package/pipeline/schemas/stack.schema.json +59 -0
  131. package/pipeline/schemas/steer-request.schema.json +25 -0
  132. package/pipeline/schemas/steer.schema.json +59 -0
  133. package/pipeline/schemas/tool-call-request.schema.json +19 -0
  134. package/pipeline/schemas/tool-call.schema.json +47 -0
  135. package/pipeline/schemas/tools.schema.json +60 -0
  136. package/pipeline/scripts/_active-run.mjs +158 -0
  137. package/pipeline/scripts/_autopilot-outcomes.mjs +1 -0
  138. package/pipeline/scripts/_cost.mjs +66 -1
  139. package/pipeline/scripts/_guard_rules.py +605 -0
  140. package/pipeline/scripts/_office-smoke-lib.sh +115 -0
  141. package/pipeline/scripts/_spawn-async.mjs +73 -0
  142. package/pipeline/scripts/_transcript-tail.mjs +274 -0
  143. package/pipeline/scripts/activity-snapshot.mjs +1027 -0
  144. package/pipeline/scripts/agent-guard.py +118 -7
  145. package/pipeline/scripts/agent-guard.sh +50 -3
  146. package/pipeline/scripts/argv-secret-scan.mjs +114 -0
  147. package/pipeline/scripts/autopilot-control.mjs +214 -9
  148. package/pipeline/scripts/autopilot-runner.mjs +8 -2
  149. package/pipeline/scripts/confirm-command.mjs +70 -0
  150. package/pipeline/scripts/contract-server.mjs +1178 -48
  151. package/pipeline/scripts/cost-analyze.mjs +2 -53
  152. package/pipeline/scripts/cost-table.json +1 -0
  153. package/pipeline/scripts/doctor.mjs +54 -0
  154. package/pipeline/scripts/evidence-gate.mjs +8 -4
  155. package/pipeline/scripts/gate-ledger.mjs +163 -7
  156. package/pipeline/scripts/office-build.mjs +89 -0
  157. package/pipeline/scripts/office-control.mjs +383 -0
  158. package/pipeline/scripts/office-ledger.mjs +409 -0
  159. package/pipeline/scripts/plan-coverage-gate.mjs +9 -8
  160. package/pipeline/scripts/pre-commit-check.sh +12 -0
  161. package/pipeline/scripts/routine-registry.mjs +42 -6
  162. package/pipeline/scripts/run-results.mjs +373 -0
  163. package/pipeline/scripts/run-scope-guard.mjs +188 -0
  164. package/pipeline/scripts/run-scope-guard.sh +23 -0
  165. package/pipeline/scripts/run-stop-guard.mjs +246 -0
  166. package/pipeline/scripts/run-stop-guard.sh +25 -0
  167. package/pipeline/scripts/service-read.mjs +244 -0
  168. package/pipeline/scripts/stack-toggle.mjs +285 -0
  169. package/pipeline/scripts/steer-run.mjs +97 -0
  170. package/pipeline/scripts/toolkit-tools.mjs +599 -0
  171. package/pipeline/scripts/uninstall.mjs +4 -0
  172. package/pipeline/scripts/validate-state.mjs +26 -0
  173. package/pipeline/scripts/work-items.mjs +304 -0
  174. package/pipeline/scripts/write-state.mjs +114 -0
  175. package/pipeline/skills/.skill-manifest.json +19 -7
  176. package/pipeline/skills/.skills-index.json +34 -1
  177. package/pipeline/skills/shared/README.md +6 -3
  178. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +13 -15
  179. package/pipeline/skills/shared/core/multi-agent-office-off/SKILL.md +16 -0
  180. package/pipeline/skills/shared/core/multi-agent-office-on/SKILL.md +22 -0
  181. package/pipeline/skills/shared/core/multi-agent-office-status/SKILL.md +17 -0
  182. package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +4 -2
  183. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +14 -6
  184. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +10 -9
  185. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
  186. package/pipeline/skills/skills-index.md +4 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "20.28.0",
3
+ "version": "20.30.0",
4
4
  "description": "6-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -86,6 +86,7 @@
86
86
  "CHANGELOG.md",
87
87
  "LICENSE",
88
88
  "SECURITY.md",
89
+ "!pipeline/office-src/**",
89
90
  "!pipeline/scripts/smoke-figma-config-schema.sh",
90
91
  "!pipeline/scripts/smoke-personal-data.sh",
91
92
  "!pipeline/scripts/validate-prefs.mjs",
@@ -66,7 +66,9 @@ The template is platform-agnostic (Locked 22). It speaks in concepts (state hold
66
66
 
67
67
  ### Phase 0 - Intake
68
68
 
69
- Full picker chain: `$HOME/.claude/multi-agent-refs/analysis/intake.md`. Sequential `AskUserQuestion` steps filling `state.analysisSpec.*`: analysis name, analysis profile, account, platform multi-select, repos per platform, the six-question source batch (Figma / Swagger / Confluence / Jira / Standards / Firebase) and the two coverage opt-ins. Step narration is required - the chain length is known up front, so every step prints its breadcrumb.
69
+ First, record the run so its hooks see an analysis run: `S="$HOME/.claude/logs/multi-agent/$TASK_ID"; mkdir -p "$S"; printf '{"taskId":"%s","mode":"analysis","status":"in_progress","currentPhase":0}' "$TASK_ID" | node $HOME/.claude/scripts/write-state.mjs "$S/agent-state.json"`.
70
+
71
+ Full picker chain: `$HOME/.claude/multi-agent-refs/analysis/intake.md`. Sequential `AskUserQuestion` steps filling `state.analysisSpec.*`: analysis name, analysis profile, account, platform multi-select, repos per platform, the six-question source batch (Figma / Swagger / Confluence / Jira / Standards / Firebase) and the two coverage opt-ins. Every step prints its breadcrumb.
70
72
 
71
73
  ### Phases 1, 1b, 1b.1, 1c - Evidence gathering
72
74
 
@@ -206,25 +206,23 @@ installer puts it; the runner tries the captured path first, then that `PATH`.
206
206
  "Configure only" is a real answer and the safe default to offer first: the queue
207
207
  can be watched with `autopilot-status` for a while before anything runs.
208
208
 
209
- On **Start**:
209
+ On **Start**, load the schedule and the awake agent with the same script the
210
+ office panel's `POST /v1/autopilot/on` calls, naming every repo selected in step 3:
210
211
 
211
212
  ```bash
212
- launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.multi-agent.autopilot.plist" 2>/dev/null \
213
- || launchctl load "$HOME/Library/LaunchAgents/com.multi-agent.autopilot.plist"
213
+ node "$HOME/.claude/scripts/autopilot-control.mjs" on --repo <owner/name> [--repo <owner/name>...]
214
214
  ```
215
215
 
216
- Then the awake agent, rendered from
217
- `templates/multi-agent-autopilot-awake.plist.template` with the `awake.display`
218
- answer saved above:
219
-
220
- ```bash
221
- . "$HOME/.claude/lib/autopilot-state.sh"
222
- node "$(ma_ap_asset scripts/autopilot-awake.mjs)" install
223
- ```
224
-
225
- A non-zero exit means launchd refused the job: say so, with its path, and say
226
- the Mac may sleep between ticks until it is fixed. The schedule itself stays on.
227
- "Configure only" installs neither.
216
+ It keeps exactly those repos in `config.json`, probes their credentials again
217
+ (`autopilot-arming.mjs probeCredentials`), renders
218
+ `templates/multi-agent-autopilot.plist.template` with its seven placeholders
219
+ (NODE, TICK, LABEL, ROOT, INTERVAL, HOME, CLAUDE), loads it with `launchctl
220
+ bootstrap` (falling back to `load`) and installs the awake agent with the
221
+ `awake.display` answer saved above. `scheduled: false` with probe problems means
222
+ nothing was loaded; say so with the problems. Exit 1 with `launchd refused`
223
+ means launchd refused the job: say so, with its path, and say the Mac may sleep
224
+ between ticks until it is fixed. "Configure only" is `--configure-only`, which
225
+ saves the selection and installs neither.
228
226
 
229
227
  ### 9. Report what is now true
230
228
 
@@ -0,0 +1,27 @@
1
+ ---
2
+ description: "Close the office panel and stop its local server. Use when done with the panel."
3
+ description-tr: "Ofis panelini hemen kapatır: office-on'un başlattığı yerel sözleşme sunucusunu durdurur. Arkada hiçbir şey kalmaz (relay yok, oturum yok, izleyici yok)."
4
+ argument-hint: "(no arguments)"
5
+ parameters: []
6
+ gui: button
7
+ destructive: false
8
+ confirm: none
9
+ allowed-tools: Bash
10
+ ---
11
+
12
+ # multi-agent office-off - close the panel
13
+
14
+ Stops the server `office-on` started, through the same script:
15
+
16
+ ```bash
17
+ node "$HOME/.claude/scripts/office-control.mjs" off --json
18
+ ```
19
+
20
+ Only the pid `office-on` recorded is signalled (SIGTERM), and only when its
21
+ token file still names it, its command is `contract-server.mjs` and its start
22
+ time matches; no other process is looked up or touched. The server removes its
23
+ token file on the way out, so the old page stops working.
24
+
25
+ Report in `outputLanguage`: whether a server was stopped (`stopped`), and the
26
+ `remote` line as the script gives it. A panel that was already closed is not
27
+ an error.
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: "Open the office panel: a local browser page with agents at work, their chats, cost ledger and new runs. Use when you want to watch or drive runs from a browser."
3
+ description-tr: "Ofis panelini açar: çalışan her ajanı (koşu başına bir masa, ekip faz sırasıyla oturur), sohbetlerini, maliyet defterini, autopilot'u, rutinleri, stack'leri, toolkit araçlarını ve yeni koşu başlatmayı gösteren yerel web sayfası. Yerel sözleşme sunucusunu gerektiğinde başlatır; panel kapanınca hiçbir şey çalışmaz."
4
+ argument-hint: "(no arguments)"
5
+ parameters: []
6
+ gui: button
7
+ destructive: false
8
+ confirm: none
9
+ allowed-tools: Bash
10
+ ---
11
+
12
+ # multi-agent office-on - open the panel
13
+
14
+ The panel is a page (`$HOME/.claude/office/index.html`) served by the
15
+ pipeline's local contract server (`contract-server.mjs`, 127.0.0.1 only, a
16
+ fresh bearer token per start). This command and `office-off` /
17
+ `office-status` share one script, `office-control.mjs`.
18
+
19
+ ## Steps
20
+
21
+ 1. **Start or reuse the server and open the browser:**
22
+
23
+ ```bash
24
+ node "$HOME/.claude/scripts/office-control.mjs" on --json
25
+ ```
26
+
27
+ It starts `contract-server.mjs` in the background with the panel page, or
28
+ reuses the one it started earlier, then opens the browser at `/office` with
29
+ a one-time code in the URL fragment (valid 10 seconds, one use, handed over
30
+ through a 0600 launcher file, never on a command line), which the
31
+ page trades for the token. The token is never printed; do not read the
32
+ token file or pass `--print-token` yourself, since anything printed lands
33
+ in this transcript.
34
+
35
+ 2. **Report** (in `outputLanguage`): the page URL (`url`, without a code),
36
+ whether a server was started or reused, that it stops by itself after
37
+ `idleMinutes` without a request (and after 8 hours in any case), and that
38
+ `/multi-agent:office-off` stops it now. If `opened` is false, tell the user
39
+ to run the command again from a desktop session; a link works once, so a
40
+ reload of the page needs a new `office-on`.
41
+
42
+ ## What it does not do
43
+
44
+ - No daemon, hook or file watcher: when the page is closed, the server exits
45
+ after its idle time and nothing else runs.
46
+ - The panel's writes call the same scripts the terminal commands call; it adds
47
+ no behaviour of its own.
48
+ - The server listens on 127.0.0.1 only. Remote access is not part of this
49
+ installation; `office-status` says whether a separate remote layer is
50
+ present.
@@ -0,0 +1,29 @@
1
+ ---
2
+ description: "Whether the office panel is running, its URL (never the token) and its last actions. Use when unsure if the panel is open."
3
+ description-tr: "Ofis panelinin durumunu raporlar: yerel sunucu çalışıyor mu, sayfa adresi (token asla), boşta kapanma süresi, uzak erişim, eşleşmiş telefonlar ve panelden yapılan son işlemler."
4
+ argument-hint: "(no arguments)"
5
+ parameters: []
6
+ gui: button
7
+ destructive: false
8
+ confirm: none
9
+ allowed-tools: Bash
10
+ ---
11
+
12
+ # multi-agent office-status - what the panel is doing
13
+
14
+ ```bash
15
+ node "$HOME/.claude/scripts/office-control.mjs" status --json
16
+ ```
17
+
18
+ Report in `outputLanguage`:
19
+
20
+ - `running`, and when it is, `url` and `idleMinutes`;
21
+ - `remote`: "not available in this installation" unless a separate remote
22
+ layer is installed; report the line as given;
23
+ - `pairedDevices`: the devices the phone registry lists; revoking one is
24
+ `phone-devices.mjs revoke`;
25
+ - `recentActions`: the last writes taken through the server (route, step,
26
+ status, when, and whether from the panel page), from
27
+ `office-actions.jsonl`. They carry no request body.
28
+
29
+ Never print the token or read the token file.
@@ -99,8 +99,9 @@ Read `state.waitingFor` FIRST: when it names a step, the run re-enters THAT step
99
99
  | `maturity` | Phase 0, the maturity step, with the item **re-fetched** and re-scored - an edit is a reason to look again, never proof the gap closed (`$HOME/.claude/multi-agent-refs/features/maturity-followup.md`); after a research pass that proceeded, re-scored through `research-gate.mjs --recheck` |
100
100
  | `user-channels-choice` | Phase 5, the channels multi-select, with the stored `channelsInput` |
101
101
  | `local-test` | Phase 3, the user-test gate, with the checkout the gate was waiting on |
102
+ | `attended-reply` | `currentPhase`, at the step that asked for a typed reply: ask it again |
102
103
  | `question` | The step `state.pendingQuestion.stepId` names, after the answer is recorded (below) |
103
- | absent | `currentPhase + 1`, as before (same pipeline as the main multi-agent command) |
104
+ | absent or `null` | `currentPhase + 1`, as before (same pipeline as the main multi-agent command) |
104
105
 
105
106
  **`--answer <optionId>`** answers `state.pendingQuestion` ({id, stepId, text, kind, options[]}) without a picker, which is how a client or a second terminal replies to a run parked on a question:
106
107
 
@@ -61,5 +61,7 @@ environment `launch.json` declares; the client starts the process.
61
61
  `POST /v1/runs/{id}/answer` accepts only an option the run's pending question
62
62
  offered. `POST /v1/runs/{id}/kill` and `POST /v1/gc` act only on a second
63
63
  request carrying the single-use confirm token the first one returned, and a
64
- kill never deletes the remote branch or the logs. Autopilot can be turned off
65
- over HTTP, never on.
64
+ kill never deletes the remote branch or the logs. Autopilot on, a stack change
65
+ and a routine removal take the same two steps, accept no browser origin but
66
+ the server's own page, and are tagged `local-only` for any future remote
67
+ carrier.
@@ -105,14 +105,21 @@ ON=$(MP="$MP" node -e 'import(process.env.HOME+"/.claude/scripts/_stack-routing.
105
105
  })' "$@") || exit 1
106
106
  ```
107
107
 
108
- After resolving `$ON`, edit `.claude/settings.json` (create `{ "enabledPlugins": {} }` if absent) so that:
109
- - every plugin in `$ON` is set to `true`,
110
- - every stack toolkit **not** in `$ON` is set to `false` (leave non-`@multi-agent-plugins` entries untouched),
111
- - `ai-common-toolkit@multi-agent-plugins` and `ai-analyst-toolkit@multi-agent-plugins` are always `true`,
112
- - every `ai-*-engineering-toolkit@multi-agent-plugins` key is **deleted** (retired names).
113
- - `xcode-integration@xcode-apple` follows `ios` (`true` with it, `false` without), only when `~/.claude/xcode-apple-marketplace` exists.
114
-
115
- Use the Read + Edit/Write tools (JSON must stay valid). Then print the resulting `enabledPlugins` block and run step 5 (Copilot/Codex refresh offer).
108
+ Then write it with the one writer of these rules (the office panel's
109
+ `POST /v1/stack` calls the same script):
110
+
111
+ ```bash
112
+ node "$HOME/.claude/scripts/stack-toggle.mjs" set --repo "$PWD" "$@" --json
113
+ ```
114
+
115
+ `stack-toggle.mjs` applies the write rules above (selection `true`, every other
116
+ stack toolkit `false`, `ai-common-toolkit` and `ai-analyst-toolkit` always
117
+ `true`, retired `ai-*-engineering-toolkit` keys deleted, `xcode-integration@xcode-apple`
118
+ following `ios` when the Apple marketplace is linked, every other key kept),
119
+ writes the file atomically and prints the resulting `enabledPlugins`. It refuses
120
+ an empty selection and an unknown stack (exit 1) and never hand-edits the JSON.
121
+ `stack-toggle.mjs status --repo "$PWD" --json` is the read for status mode.
122
+ Then print the resulting `enabledPlugins` block and run step 5 (Copilot/Codex refresh offer).
116
123
 
117
124
  ## Notes
118
125
 
@@ -71,18 +71,19 @@ is being replaced.
71
71
  and `$INSTRUCTION` the text from step 3:
72
72
 
73
73
  ```bash
74
- printf '{"pendingSteer":{"text":%s,"at":"%s","appliedAt":null,"appliedPhase":null}}' \
75
- "$(node -e 'process.stdout.write(JSON.stringify(process.argv[1]))' "$INSTRUCTION")" \
76
- "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
77
- | node $HOME/.claude/scripts/write-state.mjs "$STATE_FILE"
74
+ node "$HOME/.claude/scripts/steer-run.mjs" "$STATE_FILE" --text "$INSTRUCTION"
78
75
  ```
79
76
 
80
- The instruction is JSON-encoded by `node -e`, not by hand: it is arbitrary
81
- user text, and a quote or newline in it would otherwise produce invalid JSON
82
- or, worse, a payload that merges into fields nobody meant to touch.
77
+ `steer-run.mjs` takes the same lock `write-state.mjs` owns and merges
78
+ `pendingSteer` (`text`, `at`, `appliedAt: null`, `appliedPhase: null`) into
79
+ the state; the instruction is passed as one argument and JSON-encoded by the
80
+ script, never by hand, so a quote or newline in it cannot produce invalid
81
+ JSON or a payload that merges into other fields. It refuses a finished run
82
+ (exit 1) and prints the unconsumed instruction it replaced, if any. The
83
+ office panel's `POST /v1/runs/{id}/steer` calls the same function.
83
84
 
84
- Exit 2 (lock timeout) → the task is mid-write. Retry once, then report it
85
- rather than forcing the write.
85
+ Exit 2 (usage) or a lock timeout → the task is mid-write. Retry once, then
86
+ report it rather than forcing the write.
86
87
 
87
88
  6. **Confirm**: `🧭 Steer queued for #N - applies at the entry to Phase {N+1}`
88
89
 
@@ -73,7 +73,7 @@ Run every step automatically:
73
73
  ```
74
74
  Step 0: DOCTOR doctor.mjs - exit 2 or 4 stops the sync
75
75
  Step 1.5: DETECT Compare timestamps, find stale targets
76
- Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 66 sub-command skills)
76
+ Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 69 sub-command skills)
77
77
  Step 2b: CODEX Claude Code -> Codex CLI (1 router skill + sub-command specs as refs + agent TOML)
78
78
  Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
79
79
  Step 3c: PLUGINS pipeline shared/external -> multi-agent-plugins marketplace (rebuild knowledge/,
@@ -241,14 +241,14 @@ same specs as reference files rather than as peer skills, via Step 2b - see
241
241
  |-------------|-------------|
242
242
  | `~/.claude/commands/multi-agent/{cmd}/SKILL.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
243
243
 
244
- **66 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
244
+ **69 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
245
245
 
246
246
  ```
247
247
  analysis, analysis-jira, analysis-resolve, autopilot, autopilot-off, autopilot-on,
248
248
  autopilot-status, bug-bash, build-optimize, channels, complaint-analysis, create-jira,
249
249
  design-check, diff-explain, doctor, estimate, feedback, forget, garbage-collect, graph, help,
250
250
  ios-coding-standard, issue, jira, kill, language, log,
251
- manual-test, model, postmortem, prune-logs, prune-prompts, purge, refactor, research, resume, review, review-analysis, review-issue, review-jira, route-off, route-on, route-status,
251
+ manual-test, model, office-off, office-on, office-status, postmortem, prune-logs, prune-prompts, purge, refactor, research, resume, review, review-analysis, review-issue, review-jira, route-off, route-on, route-status,
252
252
  routines, save, scaffold, scan, scenario-audit, search, security-review, serve, setup, stack, status, steer, store-ready, sync, test,
253
253
  test-accessibility, test-dark-mode, test-dynamic-type, test-gen, test-screenshots,
254
254
  testflight-validation, uninstall, update
@@ -3,6 +3,68 @@
3
3
  Versions of the client contract (`manifest.json` `contractVersion`), separate
4
4
  from the package version. See `README.md` for what counts as minor and major.
5
5
 
6
+ ## 1.4.0
7
+
8
+ Added. Nothing existing changes shape; one narrowing for browser pages.
9
+
10
+ - `remote` and `risk` on every surface in `manifest.json` and every route in
11
+ `ROUTES`: the scope a remote carrier would require (`read`, `answer`,
12
+ `launch`, `local-only`) and the confirmation tier (`read`, `low`, `high`).
13
+ - `GET /v1/activity` and `GET /v1/activity/stream` (`activity.schema.json`):
14
+ a room per repository, a table (team) per run, a seat per agent; the stream is
15
+ `text/event-stream`, at most 4 at once (429 `too-many-streams`).
16
+ - `GET /v1/agents/{sessionId}/{agentId}/chat` (`activity-chat.schema.json`):
17
+ one page of an agent's transcript, redacted; `before`, `limit`.
18
+ - `POST /v1/autopilot/on` (two steps, `autopilot-on.schema.json`), `POST
19
+ /v1/runs/{id}/steer` (two steps, `launch`/`high`: the text and a preview
20
+ with a token bound to the run and the text, then the token alone;
21
+ `steer.schema.json`), `GET /v1/routines`, `DELETE /v1/routines/{name}` (two
22
+ steps), `GET /v1/stack`, `POST /v1/stack` (two steps).
23
+ - `GET /v1/ledger` (`ledger.schema.json`): tokens and estimated USD today, this
24
+ week and this month, by run, repository, model and phase, each amount with
25
+ its source; an unmeasurable run is `not-measured`, never 0.
26
+ - `GET /v1/runs/{id}/results` and `/evidence/{name}`: diff summary, review
27
+ findings, test outcome, screenshots and analysis documents from the run's
28
+ own files; a document is read only inside the run's roots (log directory,
29
+ artifacts, a worktree git lists) and only as Markdown or HTML.
30
+ - `GET /v1/issues/{key}/maturity` (lib/issue-fetcher.sh), `GET /v1/prs`
31
+ (GitHub; Bitbucket reported as not implemented), `POST
32
+ /v1/runs/{id}/review-verdict` (two steps, lib/post-pr-review.sh; only for a
33
+ finished review with every finding triaged, 409 `review-incomplete`
34
+ otherwise; the token is bound to the decision and `findingsDigest`, 409
35
+ `confirm-mismatch` when they changed).
36
+ - `GET /v1/tools`, `POST /v1/tools/{name}/call` (`local-only`): the
37
+ registered toolkit MCP server's tools, arguments checked against each
38
+ inputSchema, risk from each tool's annotations, and `allowed`/`reason`:
39
+ calls are denied by default (403 `tool-not-allowed`) except for read-only
40
+ tools that take no location and are outside the web and context families;
41
+ a `confirm` argument is refused; the toolkit child always runs with
42
+ `MULTI_AGENT_UNATTENDED=1` and `MCP_TOOLKIT_URL_POLICY=strict`.
43
+ - `GET /v1/services/confluence`, `/crashlytics`, `/figma`: one page, issue or
44
+ frame through the pipeline's existing clients; a Confluence URL only on the
45
+ configured host (409 `host-not-allowed`); one request per service at a time
46
+ (429 `busy`).
47
+ - `GET /v1/permissions`: the shape for pending host permission prompts;
48
+ `available: false` until the host records them readably.
49
+ - `GET /office`: the optional panel page, 404 when none is installed;
50
+ `POST /office/code` and `POST /office/exchange` hand the page the token
51
+ through a one-time 10 second code instead of a URL; `GET
52
+ /office/assets/<name>.png` serves its sprites.
53
+ - `--max-hours` (default 8): an absolute lifetime for the server.
54
+ - `contract-error.schema.json`: `no-selection`, `repo-not-configured`,
55
+ `invalid-config`, `not-installed`, `repo-ambiguous`, `unreadable-settings`,
56
+ `not-removable`, `not-steerable`, `too-many-streams`, `no-review`,
57
+ `upstream-failed`, `tool-not-allowed`, `busy`, `review-incomplete`,
58
+ `host-not-allowed`.
59
+ - Narrowed: a write (POST, DELETE) from a page on an `--allow-origin` origin is
60
+ now 403 `forbidden-origin`; only the server's own page may write. A native
61
+ client sends no Origin and is unaffected.
62
+ - `?repo=` also takes a repository name from `GET /v1/repos` (on the stack
63
+ route and on `POST /v1/launch`), since a browser reads that list redacted,
64
+ without paths. The repository must still be a configured or registered one:
65
+ an unknown name is 403 `repo-not-allowed`, an ambiguous one 409
66
+ `repo-ambiguous`. A relative path is no longer 400 but resolved as a name.
67
+
6
68
  ## 1.3.0
7
69
 
8
70
  Added. Every new field is optional for a decoder: a run written before this
@@ -51,6 +51,31 @@ same bytes (`test/contract-parity.test.mjs`):
51
51
  | Garbage-collect (two steps) | `gc-plan.mjs preview [--scope S,...]`, then `gc-plan.mjs apply < items` | `POST /v1/gc` |
52
52
  | Autopilot status | `autopilot-control.mjs status` | `GET /v1/autopilot` |
53
53
  | Autopilot off | `autopilot-control.mjs off [--now]` | `POST /v1/autopilot/off` |
54
+ | Autopilot on (two steps) | `autopilot-control.mjs on-preview --repo R...`, then `on --repo R... [--configure-only]` | `POST /v1/autopilot/on` |
55
+ | Steer a run (two steps on the server) | `steer-run.mjs STATE --text T` | `POST /v1/runs/{id}/steer` |
56
+ | Agent activity | `activity-snapshot.mjs --json` | `GET /v1/activity`, `GET /v1/activity/stream` (SSE) |
57
+ | An agent's chat | `activity-snapshot.mjs chat SESSION [AGENT] [--before N] [--limit N]` | `GET /v1/agents/{sessionId}/{agentId}/chat` |
58
+ | Cost ledger | `office-ledger.mjs --json` | `GET /v1/ledger` |
59
+ | What a run produced | `run-results.mjs ID --json` | `GET /v1/runs/{id}/results` |
60
+ | One screenshot | `run-results.mjs ID --evidence NAME` | `GET /v1/runs/{id}/evidence/{name}` |
61
+ | Post a review verdict (two steps) | `work-items.mjs verdict ID [--post]` | `POST /v1/runs/{id}/review-verdict` |
62
+ | An issue's maturity | `work-items.mjs maturity KEY` | `GET /v1/issues/{key}/maturity` |
63
+ | Open pull requests | `work-items.mjs prs` | `GET /v1/prs` |
64
+ | Toolkit MCP tools | `toolkit-tools.mjs list` | `GET /v1/tools` |
65
+ | Call an allowed toolkit tool (read-only, no location argument) | `toolkit-tools.mjs call NAME JSON` | `POST /v1/tools/{name}/call` |
66
+ | A Confluence page, a Crashlytics issue, a Figma frame | `service-read.mjs confluence\|crashlytics\|figma ...` | `GET /v1/services/{confluence,crashlytics,figma}` |
67
+ | Pending host permission prompts | (none can be read yet) | `GET /v1/permissions` |
68
+ | Routines | `routine-registry.mjs list --json` | `GET /v1/routines` |
69
+ | Remove a routine (two steps) | `routine-registry.mjs remove --name N` | `DELETE /v1/routines/{name}` |
70
+ | A repo's stacks | `stack-toggle.mjs status --repo P --json` | `GET /v1/stack?repo=R` |
71
+ | Set a repo's stacks (two steps) | `stack-toggle.mjs set --repo P STACK... --json` | `POST /v1/stack` |
72
+
73
+ Every surface in `manifest.json` carries `remote` (the scope a remote carrier
74
+ would require: `read`, `answer`, `launch`, or `local-only` for anything that
75
+ widens what runs on this machine: autopilot on, stack, routine removal, kill,
76
+ gc) and `risk` (the confirmation tier: `read`, `low`, `high`). Locally the
77
+ bearer token is the only credential; nothing enforces the tags yet. They are
78
+ there so a later carrier reuses these routes without redefining them.
54
79
 
55
80
  Starting a run is always the client's act. `POST /v1/launch` validates the
56
81
  request, writes it (0600) and returns the argv, environment and working
@@ -90,7 +115,8 @@ Resuming is the client's act too: `POST /v1/runs/{id}/resume` returns the plan
90
115
  root, `409 not-resumable` for any other, a finished or a killed one, and `409
91
116
  run-active` while its session runs.
92
117
 
93
- Kill and gc remove things, so each takes two requests. The first (no
118
+ Kill, gc, autopilot on and a stack change take two requests (a routine
119
+ removal takes its token as `?confirm=`). The first (no
94
120
  `confirmToken`) returns the preview with `confirmToken` and `expiresAt`; the
95
121
  second sends the token back and acts on exactly what was previewed. A token is
96
122
  single use, lives 120 seconds in the server's memory only, and is bound to the
@@ -113,14 +139,34 @@ answer to the old one.
113
139
  that spawned the server can pass `--print-token` to get it on the ready line.
114
140
  - Every request sends `Authorization: Bearer <token>` and a `Host` of
115
141
  `127.0.0.1:<port>` or `localhost:<port>`.
116
- - A browser page is allowed only from an origin passed with `--allow-origin`;
117
- CORS is off without one. A request carrying an `Origin` is always served
118
- redacted.
142
+ - A browser page is allowed only from the server's own origin (the optional
143
+ panel at `GET /office`) or an origin passed with `--allow-origin`; CORS is
144
+ off without one. A write (POST, DELETE) and the chat route accept no Origin
145
+ but the server's own, even an allowed one. A request carrying an `Origin` is
146
+ always served redacted.
147
+ - The token is read from the `Authorization` header only, never from a cookie
148
+ or a query parameter.
149
+ - `GET /office` serves the panel page (`MA_OFFICE_PAGE`, else
150
+ `prefs.global.office.page`, else the installed `office/index.html` beside the
151
+ package) without a token, with a per-response CSP nonce, and is 404 when no
152
+ page exists. The page never sees the token in a URL: `POST /office/code`
153
+ (bearer, no Origin) mints a code valid for 10 seconds and one use, the page
154
+ is opened with it in the fragment, and trades it at `POST /office/exchange`
155
+ (own Origin only, no bearer); a used, expired or unknown code is 401.
156
+ `GET /office/assets/<name>.png` serves the page's sprites, also without a
157
+ token: a plain file name, a PNG of at most 256 KiB directly in the assets
158
+ directory beside the page, and 404 for anything else.
159
+ - Every write route appends one line (who, route, step, status; never a body
160
+ or token) to `~/.claude/logs/multi-agent/office-actions.jsonl`.
119
161
  - Bodies are JSON, at most 64 KiB, and must satisfy the route's schema.
120
162
  - Errors follow `contract-error.schema.json`; switch on `error`, never on
121
163
  `message`.
122
- - The server exits after 15 idle minutes (`--idle-minutes`) or on SIGTERM. It
123
- is never a service; start it when you need it.
164
+ - Service reads, the work list, the review verdict and autopilot control run
165
+ in child processes and never block other routes; a second request for the
166
+ same one while the first runs is 429 `busy`.
167
+ - The server exits after 15 idle minutes (`--idle-minutes`), after 8 hours in
168
+ any case (`--max-hours`, an open event stream does not extend it) or on
169
+ SIGTERM. It is never a service; start it when you need it.
124
170
 
125
171
  A client that relays anything off this machine uses `redact=1` (or
126
172
  `--redact`) for every read.
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.3.0",
2
+ "contractVersion": "1.4.0",
3
3
  "error": "invalid-request",
4
4
  "message": "the launch request was refused",
5
5
  "errors": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.3.0",
2
+ "contractVersion": "1.4.0",
3
3
  "error": "unauthorized",
4
4
  "message": "a bearer token is required"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "contractVersion": "1.3.0",
2
+ "contractVersion": "1.4.0",
3
3
  "error": "unsigned",
4
4
  "message": "a device signature is required"
5
5
  }