@mmerterden/multi-agent-pipeline 10.5.0 → 10.6.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.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,38 @@ Internal file-layout changes that don't affect the slash-command surface are sti
14
14
 
15
15
  ---
16
16
 
17
+ ## [10.6.0] - 2026-07-02
18
+
19
+ Fable 5 restored as the top model tier; `stack-swap` fully removed; setup gains a default stack step.
20
+
21
+ ### Added
22
+
23
+ - **`multi-agent:setup` Step 9 — default stack plugin enablement.** First-run
24
+ setup detects the project stack from markers (`.xcodeproj`/`Package.swift` → iOS,
25
+ `build.gradle` → Android, `package.json`+react → Frontend, `requirements.txt`/
26
+ `pyproject.toml` → Backend) and enables the matching marketplace plugin plus the
27
+ always-on `ai-common-engineering-toolkit`. **No clear marker → default iOS.** So a
28
+ fresh install works out of the box and a repo at any org gets its correct stack.
29
+
30
+ ### Changed
31
+
32
+ - **Fable 5 is the top model tier again.** Architect (`ios/android/backend-architect`)
33
+ and Reviewer-1 (`code-reviewer`) personas declare `preferredModel: fable`. The tier
34
+ ladder is now `fable → opus → sonnet → haiku`: **if Fable 5 is unavailable, the first
35
+ fallback is Opus 4.8**, applied per-dispatch with no file edits. Security personas keep
36
+ opus. Reverses the 2026-06 "fable retired" state now that `claude-fable-5` is available.
37
+
38
+ ### Removed
39
+
40
+ - **`stack-swap.sh` + `smoke-stack-swap.sh` deleted.** The SessionStart skill-dir-swap
41
+ mechanic is gone entirely; stack selection is marketplace-plugin enablement
42
+ (`/multi-agent:stack`). No dead code or legacy hook remains.
43
+
44
+ ### Fixed
45
+
46
+ - Genericized a leaked corporate Jira key (`DIJITAL` → `PROJ`/`{JIRA_KEY}`) in the
47
+ `finish` command + skill so the personal-data gate passes.
48
+
17
49
  ## [10.5.0] - 2026-07-02
18
50
 
19
51
  Stack skills move from the local `stack-swap` mechanic to versioned marketplace plugins.
package/README.md CHANGED
@@ -578,7 +578,7 @@ Stack skills ship as versioned plugins in the `{owner}/multi-agent-plugins` mark
578
578
  /multi-agent:stack all multi-agent-stack all # all four toolkits + common
579
579
  ```
580
580
 
581
- Add the marketplace once with `claude marketplace add {owner}/multi-agent-plugins`. Newly published plugin versions are pulled by `/multi-agent:update`. The plugins are rebuilt from `pipeline/skills/shared/external/` via `pipeline/scripts/build-stack-plugins.mjs` (run by `multi-agent:sync` Step 3c), which bumps the patch version of any plugin whose skill set changed. `stack-swap.sh` is retained for manual/offline use but is no longer wired to any hook.
581
+ Add the marketplace once with `claude marketplace add {owner}/multi-agent-plugins`. Newly published plugin versions are pulled by `/multi-agent:update`. The plugins are rebuilt from `pipeline/skills/shared/external/` via `pipeline/scripts/build-stack-plugins.mjs` (run by `multi-agent:sync` Step 3c), which bumps the patch version of any plugin whose skill set changed. The old `stack-swap.sh` mechanic has been removed.
582
582
 
583
583
  ## Setup
584
584
 
@@ -639,7 +639,6 @@ Runs unit tests, smoke suites, eval fixtures, schema validation, and lint - the
639
639
  | ---------------------- | ------------------------------------------------ |
640
640
  | `pre-commit-check.sh` | Secret detection before commits |
641
641
  | `build-stack-plugins.mjs` | Rebuild stack plugins from `shared/external`, bump changed plugin versions |
642
- | `stack-swap.sh` | Legacy stack skill-dir swap (manual/offline; no longer hooked) |
643
642
  | `keychain-save.sh` | Save tokens/JSON to macOS Keychain (interactive) |
644
643
  | `keychain.py` | Deterministic Python Keychain helper (get/set/delete/list/doctor); shell driver auto-delegates on macOS/Linux |
645
644
  | `github-ssh-setup.sh` | GitHub SSH key generation + config |
@@ -785,7 +784,6 @@ pipeline/
785
784
  scripts/
786
785
  pre-commit-check.sh Secret detection hook
787
786
  build-stack-plugins.mjs Rebuild stack plugins + version bump
788
- stack-swap.sh Legacy stack swap (manual; no longer hooked)
789
787
  keychain-save.sh Save tokens/JSON to macOS Keychain
790
788
  github-ssh-setup.sh GitHub SSH key generation + setup
791
789
  ui-tree-dumper.swift iOS accessibility tree dumper
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "10.5.0",
3
+ "version": "10.6.0",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI, Cursor, Antigravity, and VS Code Copilot Chat. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Opus 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",
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  description: Android architect - evaluates design decisions, patterns, and module structure
3
- model: opus
4
- preferredModel: opus
5
- modelRationale: "Architecture decisions across Gradle modules, Compose stability, Hilt graphs, and migration paths run on opus (top available tier). No downgrade recommended."
3
+ model: fable
4
+ preferredModel: fable
5
+ modelRationale: "Architecture decisions across Gradle modules, Compose stability, Hilt graphs, and migration paths run on fable, the top tier (opus is the first fallback). No downgrade recommended."
6
6
  ---
7
7
 
8
8
  You are a senior Android architect with deep expertise in large-scale modular Android applications.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  description: Backend architect - evaluates API design, data modeling, and system architecture
3
- model: opus
4
- preferredModel: opus
5
- modelRationale: "API design + migration safety + scaling analysis are top-tier concerns; opus is the top available tier and handles concurrent-write / rollback edge cases in database migration reviews."
3
+ model: fable
4
+ preferredModel: fable
5
+ modelRationale: "API design + migration safety + scaling analysis are top-tier concerns; fable is the top tier (opus is the first fallback) and handles concurrent-write / rollback edge cases in database migration reviews."
6
6
  ---
7
7
 
8
8
  You are a senior backend architect with expertise in API design, distributed systems, and data modeling.
@@ -1,7 +1,7 @@
1
1
  ---
2
- description: "Code reviewer for multi-agent Phase 4 - security, architecture, quality, performance. Default model is opus; Phase 4 orchestrator overrides to sonnet for Reviewer 3."
3
- model: opus
4
- preferredModel: opus
2
+ description: "Code reviewer for multi-agent Phase 4 - security, architecture, quality, performance. Default model is fable (opus is the first fallback); Phase 4 orchestrator overrides to sonnet for Reviewer 3."
3
+ model: fable
4
+ preferredModel: fable
5
5
  modelRationale: "Reviewer 1 tier - deep security + architecture review runs on opus (top available intelligence tier). Phase 4 orchestrator overrides to sonnet for Reviewer 3 (quality/correctness focus) via CLAUDE_CODE_SUBAGENT_MODEL before dispatch. Copilot CLI adds Reviewer 2 on gpt-5.4 for cross-model diversity."
6
6
  ---
7
7
 
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  description: iOS architect - evaluates design decisions, patterns, and module structure
3
- model: opus
4
- preferredModel: opus
5
- modelRationale: "Architecture decisions require deep reasoning across modules, protocols, and migration paths - opus is the top available intelligence tier. No downgrade recommended; if cost is a concern, skip the architect consultation entirely."
3
+ model: fable
4
+ preferredModel: fable
5
+ modelRationale: "Architecture decisions require deep reasoning across modules, protocols, and migration paths - fable is the top tier (opus is the first fallback). No downgrade recommended; if cost is a concern, skip the architect consultation entirely."
6
6
  ---
7
7
 
8
8
  You are a senior iOS architect with deep expertise in large-scale modular iOS applications.
@@ -24,7 +24,7 @@ You already did the work locally - wrote code on the current branch and maybe
24
24
 
25
25
  ```bash
26
26
  /multi-agent:finish # current branch vs its base; resolve Jira id from branch name
27
- /multi-agent:finish DIJITAL-12345 # bind to an explicit Jira id for the Phase 7 comment
27
+ /multi-agent:finish PROJ-12345 # bind to an explicit Jira id for the Phase 7 comment
28
28
  /multi-agent:finish --base develop # override the base branch for the diff
29
29
  /multi-agent:finish autopilot # no gate prompts: auto-fix blocking findings, auto-PR, auto-comment
30
30
  ```
@@ -45,7 +45,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
45
45
 
46
46
  1. **Project + branch:** detect project (cwd), current branch (`git branch --show-current`). No worktree; work stays on the current branch.
47
47
  2. **Base + diff:** resolve base branch in order: `--base <arg>` → `figma-config.project.baseBranch` → `develop` → the branch's upstream/merge-base. The **work under review** is `git diff <base>...HEAD` PLUS uncommitted working-tree changes (`git status`). Abort with a clear message if the diff is empty (`ERR: no local work to finish on <branch> vs <base>`).
48
- 3. **Task binding:** Jira id from the `--`/positional arg, else parse the branch name (`bugfix/DIJITAL-XXXX` / `feature/DIJITAL-XXXX`); `taskType` inferred from the diff (bugfix/feature/refactor/chore) for the report wording. GitHub issue `#N` from branch/arg when present.
48
+ 3. **Task binding:** Jira id from the `--`/positional arg, else parse the branch name (`bugfix/PROJ-XXXX` / `feature/PROJ-XXXX`); `taskType` inferred from the diff (bugfix/feature/refactor/chore) for the report wording. GitHub issue `#N` from branch/arg when present.
49
49
  4. **Prior state (optional):** if an `agent-state.json` / tracker-state exists for this branch (left by a prior `dev-local`/`local` run), load its analysis summary + Jira/issue binding to enrich the report; otherwise synthesize a minimal state over the diff. Never require a prior full-pipeline run.
50
50
  5. Persist state under `.claude/logs/multi-agent/{project}/{taskId}/` (same as `--local`).
51
51
 
@@ -55,7 +55,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
55
55
  - interactive: present them and ask (`AskUserQuestion`) whether to fix now (loop back through a minimal Phase-3-style TDD fix) or proceed;
56
56
  - `autopilot` (or `prefs.global.finish.autoFix == true`): auto-fix accepted blocking/important findings, then re-review the fix, before advancing.
57
57
  - **Phase 5 Build+Test** — the **automated success gate** (this is what "build+test success" means here; the interactive device user-test is `/multi-agent:manual-test`). Stack-aware: build via `figma-config.build` (iOS scheme / Android gradle / detected backend/frontend build) and run the existing test suite if present (`swift test` / `xcodebuild test` / `./gradlew test` / `pytest` / `npm test` / `vitest`). Require success to advance; on failure, surface logs and (interactive) stop or (autopilot) attempt a bounded fix loop. **If the repo has no tests, report "no tests present" — never fabricate test results.**
58
- - **Phase 6 Commit/PR** — per `refs/phases/phase-6-commit.md`: stage + commit any remaining local changes with a conventional message (`{type}(scope): desc [DIJITAL-{id}]`), push, and open a PR **only if one does not already exist** for the branch. PR body per `refs/pipeline-output-formatting` and `rules/git-conventions` — `Ref: #N` / `Related: #N`, never `Closes/Fixes/Resolves`; NO AI/bot attribution anywhere.
58
+ - **Phase 6 Commit/PR** — per `refs/phases/phase-6-commit.md`: stage + commit any remaining local changes with a conventional message (`{type}(scope): desc [{JIRA_KEY}-{id}]`), push, and open a PR **only if one does not already exist** for the branch. PR body per `refs/pipeline-output-formatting` and `rules/git-conventions` — `Ref: #N` / `Related: #N`, never `Closes/Fixes/Resolves`; NO AI/bot attribution anywhere.
59
59
  - **Phase 7 Report** — per `refs/phases/phase-7-report.md` + `channels.md`: produce the **technical analysis** and **test scenarios**, then post to the configured channels. Default content for `finish`: a Jira **comment** carrying the technical analysis + the test scenarios (and, when the PR was opened, the PR description). Every body runs through the humanizer; bot/tool/AI signatures are FORBIDDEN in comments.
60
60
 
61
61
  ## Modes
@@ -92,7 +92,7 @@ No TaskList widget. After every state change call `bash $HOME/.claude/scripts/ph
92
92
  ## Examples
93
93
 
94
94
  ```bash
95
- /multi-agent:dev-local "DIJITAL-12345" # develop locally (Init→Dev→Commit→Report, no review/test)
95
+ /multi-agent:dev-local "PROJ-12345" # develop locally (Init→Dev→Commit→Report, no review/test)
96
96
  # … you inspect / hand-test the change …
97
97
  /multi-agent:finish # now: review + build/test + PR + Jira analysis & test scenarios
98
98
  ```
@@ -1,22 +1,30 @@
1
1
  # Model Fallback Contract (v10.1.0)
2
2
 
3
- Personas that declare `preferredModel: opus` route to the top available
4
- intelligence tier (`claude-opus-4-8`). Opus access can be quota-limited or
5
- temporarily unavailable. This contract defines when and how the orchestrator
6
- falls back, deterministically, without ever editing persona files at runtime.
3
+ Personas route to the top available intelligence tier they declare in
4
+ `preferredModel`. That tier can be quota-limited or temporarily unavailable.
5
+ This contract defines when and how the orchestrator falls back, deterministically,
6
+ without ever editing persona files at runtime.
7
7
 
8
- > **Fable retired (2026-06).** Earlier versions routed architect / Reviewer-1 /
9
- > triage personas to `claude-fable-5` as the top tier. Fable 5 is no longer
10
- > available, so opus is now the top tier and the persona frontmatter declares
11
- > `preferredModel: opus`. The `premiumTierUntil` date gate stays in the contract
12
- > as a generic mechanism for any future plan-window-limited premium tier.
8
+ > **Fable 5 available again (2026-07).** `claude-fable-5` is the top tier once
9
+ > more. Architect (`ios/android/backend-architect`), Reviewer-1 (`code-reviewer`),
10
+ > and triage personas declare `preferredModel: fable` the deepest-reasoning
11
+ > roles. **If Fable 5 is unavailable, the first fallback is opus (`claude-opus-4-8`).**
12
+ > Security and other `preferredModel: opus` personas keep opus as their top tier.
13
+ > The `premiumTierUntil` date gate stays in the contract as a generic mechanism
14
+ > for any plan-window-limited premium tier.
13
15
 
14
16
  ## Tier ladder
15
17
 
16
18
  ```
17
- opus -> sonnet -> haiku
19
+ fable -> opus -> sonnet -> haiku
18
20
  ```
19
21
 
22
+ The orchestrator walks **one step down per trigger** from whichever tier a
23
+ persona prefers: a `fable` persona degrades `fable -> opus` first, then
24
+ `opus -> sonnet`, then `sonnet -> haiku`; an `opus` persona starts at
25
+ `opus -> sonnet`. So a Fable 5 outage transparently promotes Opus 4.8 into the
26
+ architect/reviewer roles with no file edits.
27
+
20
28
  One step down per trigger, walking the ladder until a tier dispatches or the
21
29
  floor (`haiku`) is reached. `haiku` is the last-resort floor: a run that reaches
22
30
  it is heavily degraded but still makes progress instead of hard-halting because
@@ -800,3 +800,21 @@ Offer to make the secret scan a HARD pre-commit gate (a non-zero exit blocks the
800
800
  - On Yes, deep-merge the template's `hooks.PreToolUse` into the user's `settings.json` (preserve any existing hooks; do not duplicate a matcher that already calls `pre-commit-check.sh`).
801
801
  - Honest note to show: this is the only deterministic gate that is OS-enforceable as a hook (it needs no run-specific arguments). The evidence / consensus / intent / learnings gates are invoked by the pipeline phases with per-run arguments, so they are enforced by the phase contract + the installed gate scripts, not by a hook.
802
802
  - On the adapter platforms (Cursor / Antigravity / VS Code Copilot Chat) there is no PreToolUse equivalent; the gate scripts live in `~/.multi-agent/` and are run as workflow steps. See `refs/picker-contract.md`.
803
+ ### Step 9 - Default stack plugin enablement
804
+
805
+ Stack skills ship as versioned plugins in the `{owner}/multi-agent-plugins` marketplace. On first setup, wire the stack so the pipeline works out of the box.
806
+
807
+ 1. Ensure the marketplace is known (idempotent):
808
+ ```bash
809
+ claude marketplace add {owner}/multi-agent-plugins 2>/dev/null || true
810
+ ```
811
+ 2. Detect the project stack from markers and enable the matching plugin(s) plus the always-on common plugin in the project's `.claude/settings.json` `enabledPlugins`:
812
+ - `.xcodeproj` / `Package.swift` / `*.xcworkspace` → `ai-ios-engineering-toolkit`
813
+ - `build.gradle` / `settings.gradle` → `ai-android-engineering-toolkit`
814
+ - `package.json` with `react`/`next` → `ai-frontend-engineering-toolkit`
815
+ - `requirements.txt` / `pyproject.toml` / server `package.json` → `ai-backend-toolkit`
816
+ - **no clear marker → default `ai-ios-engineering-toolkit`**
817
+ `ai-common-engineering-toolkit@multi-agent-plugins` is always set `true` alongside the stack plugin.
818
+ 3. Report the enabled set. To change later, run `/multi-agent:stack <ios|android|frontend|backend|...>` in the repo. Pipeline Phase 1 auto-detects the stack for its own routing regardless of enablement.
819
+
820
+ The marketplace repo name (`multi-agent-plugins`) is generic; a different org points `{owner}` at its own fork — nothing in the pipeline is coupled to a specific account.
@@ -91,4 +91,4 @@ Use the Read + Edit/Write tools (JSON must stay valid). Then print the resulting
91
91
  - Enablement is per-repo and declarative — commit `.claude/settings.json` so teammates get the same stack.
92
92
  - Restart the conversation (or reload the window) for Claude Code to pick up newly enabled plugins.
93
93
  - Pipeline Phase 1 stack detection is independent (it reads project files); `stack` only sets which plugin skill set is active.
94
- - Legacy: `~/.claude/scripts/stack-swap.sh` is retained for manual/offline use but is no longer wired to any hook. Prefer plugin enablement.
94
+ - The old `stack-swap.sh` skill-dir swap has been removed; stack selection is entirely plugin enablement.
@@ -217,7 +217,7 @@ Adapter sync orchestration goes through `pipeline/scripts/sync-adapters.mjs` -
217
217
  5. **Files NOT synced** (local-only, may contain personal data):
218
218
  - `~/.claude/multi-agent-preferences.json`
219
219
  - `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
220
- - `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh`, `stack-swap.sh` (legacy, retained for manual use), and `build-stack-plugins.mjs` (generic, synced)
220
+ - `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `build-stack-plugins.mjs` (generic, synced)
221
221
  - `~/.claude/settings.json`
222
222
 
223
223
  6. **Cross-platform smoke gate** (final step of the REPO sync, before push):
@@ -52,7 +52,6 @@ Validate contracts. Each emits `══ <name> smoke: N passed, M failed ══`
52
52
  - `smoke-prefs-language.sh` - `prefs.global.promptLanguage` contract
53
53
  - `smoke-progress-contract.sh` - progress-line quiet/normal/verbose
54
54
  - `smoke-search.sh` - `/multi-agent:search` log search + smart ranking
55
- - `smoke-stack-swap.sh` - `/multi-agent:stack` auto-detect + manual override
56
55
  - `smoke-subagent-validators.sh` - Phase 1/2 validator schemas
57
56
  - `smoke-telemetry.sh` - opt-in telemetry contract
58
57
  - `smoke-validator-contradiction.sh` - Phase 4 approved/blocking contradiction detection
@@ -13,7 +13,7 @@
13
13
  * plugin repo and are NEVER touched here — only the `knowledge/` layer + plugin.json
14
14
  * knowledge entries are regenerated.
15
15
  *
16
- * Routing mirrors pipeline/scripts/stack-swap.sh patterns. Genuinely cross-stack
16
+ * Routing uses the per-stack skill patterns (formerly carried by stack-swap.sh). Genuinely cross-stack
17
17
  * skills go to ai-common-engineering-toolkit (not into each stack plugin). Apple/
18
18
  * Xcode-only vendored skills that match no stack pattern belong to iOS only.
19
19
  *
@@ -45,7 +45,7 @@ const APPLE_ONLY = [
45
45
  'xcode-compilation-analyzer', 'xcode-project-analyzer',
46
46
  ];
47
47
 
48
- // stack → matching pattern (mirrors stack-swap.sh IOS/ANDROID/BACKEND/FRONTEND patterns)
48
+ // stack → matching pattern (per-stack routing patterns (formerly in stack-swap.sh))
49
49
  const STACK_PATTERNS = {
50
50
  'ai-ios-engineering-toolkit': /(swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments|help-skills)/i,
51
51
  'ai-android-engineering-toolkit': /(android|compose-|kotlin-|room-database|retrofit-|gradle-|play-store)/i,
@@ -62,19 +62,20 @@ echo "→ 3. Phase wiring references the contract"
62
62
  grep -q "model-fallback.md" "$P0" && ok "phase-0-init wires the date gate" || fail "phase-0-init missing fallback wiring"
63
63
  grep -q "model-fallback.md" "$P4" && ok "phase-4-review wires the per-dispatch triggers" || fail "phase-4-review missing fallback wiring"
64
64
 
65
- echo "→ 4. Personas declare opus as preferred (fallback is dispatch-time, not file-time)"
66
- OPUS_COUNT=$(grep -l "^preferredModel: opus" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
67
- if [ "$OPUS_COUNT" -ge 5 ]; then
68
- ok "opus personas intact ($OPUS_COUNT files)"
65
+ echo "→ 4. Top-tier personas declare their preferred model (fallback is dispatch-time, not file-time)"
66
+ # Fable 5 is the top tier again: architect + Reviewer-1 (+ triage) personas pin it.
67
+ FABLE_COUNT=$(grep -l "^preferredModel: fable" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
68
+ if [ "$FABLE_COUNT" -ge 4 ]; then
69
+ ok "fable top-tier personas present ($FABLE_COUNT files)"
69
70
  else
70
- fail "expected >=5 opus personas, found $OPUS_COUNT"
71
+ fail "expected >=4 fable personas (architects + Reviewer-1), found $FABLE_COUNT"
71
72
  fi
72
- # Fable 5 is retired - no persona should still pin it.
73
- FABLE_LEFT=$(grep -l "^preferredModel: fable" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
74
- if [ "$FABLE_LEFT" -eq 0 ]; then
75
- ok "no persona still pins retired fable tier"
73
+ # Opus stays a valid tier the first fallback below fable, and the top tier for security personas.
74
+ OPUS_COUNT=$(grep -l "^preferredModel: opus" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
75
+ if [ "$OPUS_COUNT" -ge 1 ]; then
76
+ ok "opus personas intact ($OPUS_COUNT files)"
76
77
  else
77
- fail "expected 0 fable personas (fable retired), found $FABLE_LEFT"
78
+ fail "expected >=1 opus persona (fallback tier / security), found $OPUS_COUNT"
78
79
  fi
79
80
 
80
81
  echo ""
@@ -35,7 +35,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - the branch's lo
35
35
 
36
36
  ```bash
37
37
  multi-agent finish # current branch vs base; Jira id from branch name
38
- multi-agent finish DIJITAL-12345 # explicit Jira id for the Phase 7 comment
38
+ multi-agent finish PROJ-12345 # explicit Jira id for the Phase 7 comment
39
39
  multi-agent finish --base develop # override base branch for the diff
40
40
  multi-agent finish autopilot # no gate prompts: auto-fix, auto-PR, auto-comment
41
41
  ```
@@ -47,4 +47,4 @@ multi-agent-stack all # all four stack toolkits + common
47
47
  - Enablement is per-repo and declarative — commit `.claude/settings.json` so teammates get the same stack.
48
48
  - Restart the conversation to pick up newly enabled plugins.
49
49
  - Pipeline Phase 1 stack detection is independent (it reads project files); `stack` only sets which plugin skill set is active.
50
- - Legacy: `stack-swap.sh` is retained for manual/offline use but is no longer wired to any hook.
50
+ - The old `stack-swap.sh` skill-dir swap has been removed; stack selection is entirely plugin enablement.
@@ -90,7 +90,7 @@ If nothing is stale -> report "All targets up to date" and stop.
90
90
  5. **Files NOT synced** (local-only, may contain personal data):
91
91
  - `~/.claude/multi-agent-preferences.json`
92
92
  - `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
93
- - `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh`, `stack-swap.sh` (legacy, retained), and `build-stack-plugins.mjs` (generic, synced)
93
+ - `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `build-stack-plugins.mjs` (generic, synced)
94
94
  - Step 3c (PLUGINS): rebuild the `{owner}/multi-agent-plugins` marketplace from `shared/external` via `build-stack-plugins.mjs` (bumps changed plugins' patch version), then commit + push the plugins repo
95
95
  - `~/.claude/settings.json`
96
96
 
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-stack-swap.sh - verify stack-swap.sh argument dispatch and skill movement.
3
- # Bootstraps a temp HOME with fixture skills, runs the script in forced mode for
4
- # each supported stack, asserts skills move between active and inactive
5
- # directories, and validates the JSON systemMessage output contract.
6
- #
7
- # Covers v5.3.4+ /multi-agent:stack command backend: ios, android, mobile,
8
- # backend, frontend, fullstack, all, status, and unknown-arg rejection.
9
-
10
- set -uo pipefail
11
-
12
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
13
- STACK_SWAP="$SCRIPT_DIR/stack-swap.sh"
14
-
15
- if [ ! -x "$STACK_SWAP" ]; then
16
- echo "FAIL: stack-swap.sh not found or not executable at $STACK_SWAP" >&2
17
- exit 1
18
- fi
19
-
20
- PASS=0
21
- FAIL=0
22
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
23
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
24
-
25
- TMPHOME=$(mktemp -d) || { echo "FAIL: mktemp" >&2; exit 1; }
26
- trap 'rm -rf "$TMPHOME"' EXIT
27
-
28
- export HOME="$TMPHOME"
29
- SKILLS="$TMPHOME/.claude/skills"
30
- INACTIVE="$TMPHOME/.claude/skills-inactive"
31
- mkdir -p "$SKILLS" "$INACTIVE"
32
-
33
- # Fixture skill dirs - one matching each stack's pattern catalog.
34
- bootstrap_fixtures() {
35
- rm -rf "$SKILLS" "$INACTIVE"
36
- mkdir -p "$SKILLS" "$INACTIVE"
37
- # iOS pattern hits
38
- mkdir -p "$SKILLS/swiftui-patterns" "$SKILLS/ios-networking" "$SKILLS/hig-foundations"
39
- # Android pattern hits
40
- mkdir -p "$SKILLS/android-security" "$SKILLS/compose-navigation" "$SKILLS/kotlin-coroutines-expert"
41
- # Backend pattern hits
42
- mkdir -p "$SKILLS/fastapi-patterns" "$SKILLS/nodejs-tips"
43
- # Frontend pattern hits
44
- mkdir -p "$SKILLS/react-best-practices" "$SKILLS/nextjs-app-router"
45
- # Unrelated skill that should never move
46
- mkdir -p "$SKILLS/general-writing"
47
- }
48
-
49
- echo "→ 1. status mode prints JSON with active+inactive counts, no file movement"
50
- bootstrap_fixtures
51
- COUNT_BEFORE=$(ls "$SKILLS" | wc -l | tr -d ' ')
52
- OUT=$("$STACK_SWAP" status 2>&1)
53
- if echo "$OUT" | grep -q '"systemMessage"'; then
54
- pass "status emits {\"systemMessage\": ...} JSON"
55
- else
56
- fail "status output missing systemMessage field: $OUT"
57
- fi
58
- COUNT_AFTER=$(ls "$SKILLS" | wc -l | tr -d ' ')
59
- if [ "$COUNT_BEFORE" = "$COUNT_AFTER" ]; then
60
- pass "status does not move files (before=$COUNT_BEFORE after=$COUNT_AFTER)"
61
- else
62
- fail "status moved files (before=$COUNT_BEFORE after=$COUNT_AFTER)"
63
- fi
64
-
65
- echo ""
66
- echo "→ 2. ios mode keeps iOS skills active, deactivates Android/backend/frontend"
67
- bootstrap_fixtures
68
- "$STACK_SWAP" ios >/dev/null 2>&1
69
- [ -d "$SKILLS/swiftui-patterns" ] && pass "iOS skill stays active: swiftui-patterns" || fail "swiftui-patterns missing from active"
70
- [ -d "$SKILLS/ios-networking" ] && pass "iOS skill stays active: ios-networking" || fail "ios-networking missing from active"
71
- [ -d "$INACTIVE/android-security" ] && pass "Android skill moved to inactive: android-security" || fail "android-security not in inactive"
72
- [ -d "$INACTIVE/react-best-practices" ] && pass "Frontend skill moved to inactive: react-best-practices" || fail "react-best-practices not in inactive"
73
- [ -d "$SKILLS/general-writing" ] && pass "Unrelated skill untouched: general-writing" || fail "general-writing was moved"
74
-
75
- echo ""
76
- echo "→ 3. android mode keeps Android skills active, deactivates iOS"
77
- bootstrap_fixtures
78
- "$STACK_SWAP" android >/dev/null 2>&1
79
- [ -d "$SKILLS/android-security" ] && pass "Android skill stays active" || fail "android-security missing from active"
80
- [ -d "$SKILLS/compose-navigation" ] && pass "Compose skill stays active" || fail "compose-navigation missing from active"
81
- [ -d "$INACTIVE/swiftui-patterns" ] && pass "iOS skill moved to inactive" || fail "swiftui-patterns not in inactive"
82
-
83
- echo ""
84
- echo "→ 4. mobile mode keeps iOS AND Android active, deactivates backend"
85
- bootstrap_fixtures
86
- "$STACK_SWAP" mobile >/dev/null 2>&1
87
- [ -d "$SKILLS/swiftui-patterns" ] && pass "mobile keeps iOS active" || fail "iOS deactivated by mobile"
88
- [ -d "$SKILLS/android-security" ] && pass "mobile keeps Android active" || fail "Android deactivated by mobile"
89
- [ -d "$INACTIVE/fastapi-patterns" ] && pass "backend moved to inactive under mobile" || fail "backend stayed active under mobile"
90
-
91
- echo ""
92
- echo "→ 5. all mode keeps every stack active"
93
- bootstrap_fixtures
94
- # Pre-deactivate something so "all" has work to do
95
- mv "$SKILLS/fastapi-patterns" "$INACTIVE/fastapi-patterns"
96
- "$STACK_SWAP" all >/dev/null 2>&1
97
- [ -d "$SKILLS/swiftui-patterns" ] && pass "all keeps iOS" || fail "all dropped iOS"
98
- [ -d "$SKILLS/android-security" ] && pass "all keeps Android" || fail "all dropped Android"
99
- [ -d "$SKILLS/fastapi-patterns" ] && pass "all re-activates backend" || fail "all did not re-activate backend"
100
-
101
- echo ""
102
- echo "→ 6. unknown arg returns exit 1 with error message"
103
- bootstrap_fixtures
104
- OUT=$("$STACK_SWAP" badstack 2>&1)
105
- RC=$?
106
- if [ "$RC" -eq 1 ]; then
107
- pass "unknown arg exits 1"
108
- else
109
- fail "unknown arg exit code was $RC, expected 1"
110
- fi
111
- if echo "$OUT" | grep -qi "unknown"; then
112
- pass "unknown arg error message mentions 'unknown'"
113
- else
114
- fail "unknown arg message lacks expected text: $OUT"
115
- fi
116
-
117
- echo ""
118
- echo "→ 7. exit code 0 on every valid mode"
119
- bootstrap_fixtures
120
- for arg in status ios android mobile backend frontend all; do
121
- "$STACK_SWAP" "$arg" >/dev/null 2>&1
122
- RC=$?
123
- if [ "$RC" -eq 0 ]; then
124
- pass "$arg exits 0"
125
- else
126
- fail "$arg exit code was $RC"
127
- fi
128
- done
129
-
130
- echo ""
131
- echo "══ stack-swap smoke: $PASS passed, $FAIL failed ══"
132
- [ "$FAIL" -eq 0 ] || exit 1
@@ -1,182 +0,0 @@
1
- #!/bin/bash
2
- # stack-swap.sh - Auto-detect project stack and swap skills
3
- # Called by SessionStart hook
4
- # Default: iOS. Swaps Android/backend in only when detected.
5
-
6
- set -uo pipefail
7
-
8
- SKILLS="$HOME/.claude/skills"
9
- INACTIVE="$HOME/.claude/skills-inactive"
10
- mkdir -p "$INACTIVE"
11
-
12
- # Skill group definitions (folder name prefixes/patterns)
13
- IOS_PATTERNS="swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments|help-skills"
14
- ANDROID_PATTERNS="android|compose-|kotlin-|room-database|retrofit-|gradle-|play-store"
15
- BACKEND_PATTERNS="fastapi|nodejs|docker|api-pattern|api-security|github-actions|observability|architecture|monorepo|clean-code|debugging-strategies|agentflow|closed-loop|context-compression|python-patterns|database-patterns|rest-api-design|testing-backend|ci-cd-pipelines"
16
- FRONTEND_PATTERNS="react-|nextjs-|typescript-|tailwind-|vue-|web-accessibility|web-performance|css-modern|web-testing|html-semantic"
17
-
18
- activate_stack() {
19
- local patterns="$1"
20
- # Move matching skills from inactive to active
21
- for dir in "$INACTIVE"/*/; do
22
- [ -d "$dir" ] || continue
23
- name=$(basename "$dir")
24
- if echo "$name" | grep -qiE "$patterns"; then
25
- mv "$dir" "$SKILLS/$name" 2>/dev/null
26
- fi
27
- done
28
- }
29
-
30
- deactivate_stack() {
31
- local patterns="$1"
32
- # Move matching skills from active to inactive
33
- for dir in "$SKILLS"/*/; do
34
- [ -d "$dir" ] || continue
35
- name=$(basename "$dir")
36
- if echo "$name" | grep -qiE "$patterns"; then
37
- mv "$dir" "$INACTIVE/$name" 2>/dev/null
38
- fi
39
- done
40
- }
41
-
42
- # Manual mode: if argument provided, force that stack
43
- FORCE_STACK="${1:-}"
44
-
45
- if [ -n "$FORCE_STACK" ]; then
46
- case "$FORCE_STACK" in
47
- ios)
48
- activate_stack "$IOS_PATTERNS"
49
- deactivate_stack "$ANDROID_PATTERNS"
50
- deactivate_stack "$BACKEND_PATTERNS"
51
- deactivate_stack "$FRONTEND_PATTERNS"
52
- ;;
53
- android)
54
- deactivate_stack "$IOS_PATTERNS"
55
- activate_stack "$ANDROID_PATTERNS"
56
- deactivate_stack "$BACKEND_PATTERNS"
57
- deactivate_stack "$FRONTEND_PATTERNS"
58
- ;;
59
- mobile)
60
- activate_stack "$IOS_PATTERNS"
61
- activate_stack "$ANDROID_PATTERNS"
62
- deactivate_stack "$BACKEND_PATTERNS"
63
- deactivate_stack "$FRONTEND_PATTERNS"
64
- ;;
65
- backend)
66
- deactivate_stack "$IOS_PATTERNS"
67
- deactivate_stack "$ANDROID_PATTERNS"
68
- activate_stack "$BACKEND_PATTERNS"
69
- deactivate_stack "$FRONTEND_PATTERNS"
70
- ;;
71
- frontend)
72
- deactivate_stack "$IOS_PATTERNS"
73
- deactivate_stack "$ANDROID_PATTERNS"
74
- deactivate_stack "$BACKEND_PATTERNS"
75
- activate_stack "$FRONTEND_PATTERNS"
76
- ;;
77
- fullstack)
78
- deactivate_stack "$IOS_PATTERNS"
79
- deactivate_stack "$ANDROID_PATTERNS"
80
- activate_stack "$BACKEND_PATTERNS"
81
- activate_stack "$FRONTEND_PATTERNS"
82
- ;;
83
- all)
84
- activate_stack "$IOS_PATTERNS"
85
- activate_stack "$ANDROID_PATTERNS"
86
- activate_stack "$BACKEND_PATTERNS"
87
- activate_stack "$FRONTEND_PATTERNS"
88
- ;;
89
- status)
90
- ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
91
- INACTIVE_COUNT=$(ls "$INACTIVE" 2>/dev/null | wc -l | tr -d ' ')
92
- echo "{\"systemMessage\": \"Active: $ACTIVE | Inactive: $INACTIVE_COUNT\"}"
93
- exit 0
94
- ;;
95
- *)
96
- echo "{\"systemMessage\": \"Unknown stack: $FORCE_STACK. Use: ios, android, mobile, backend, frontend, fullstack, all, status\"}"
97
- exit 1
98
- ;;
99
- esac
100
- ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
101
- echo "{\"systemMessage\": \"Stack switched to $FORCE_STACK ($ACTIVE skills active). Restart conversation for full effect.\"}"
102
- exit 0
103
- fi
104
-
105
- # Auto-detect mode (SessionStart hook)
106
- CWD=$(pwd)
107
-
108
- # If cwd is $HOME, skip detection - keep default (iOS)
109
- if [ "$CWD" = "$HOME" ]; then
110
- activate_stack "$IOS_PATTERNS"
111
- ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
112
- echo "{\"systemMessage\": \"Stack: iOS - default ($ACTIVE skills active)\"}"
113
- exit 0
114
- fi
115
-
116
- HAS_IOS=$(find "$CWD" -maxdepth 2 \( -name "*.xcodeproj" -o -name "Package.swift" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
117
- HAS_ANDROID=$(find "$CWD" -maxdepth 2 \( -name "build.gradle" -o -name "build.gradle.kts" \) -not -path "*/.claude/*" 2>/dev/null | head -1)
118
- HAS_FRONTEND=$(find "$CWD" -maxdepth 2 \( -name "next.config.*" -o -name "vite.config.*" -o -name "nuxt.config.*" -o -name "tailwind.config.*" -o -name "tsconfig.json" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
119
- HAS_BACKEND=$(find "$CWD" -maxdepth 2 \( -name "requirements.txt" -o -name "pyproject.toml" -o -name "Pipfile" -o -name "Dockerfile" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
120
-
121
- # Determine stack
122
- if [ -n "$HAS_IOS" ] && [ -n "$HAS_ANDROID" ]; then
123
- STACK="mobile"
124
- elif [ -n "$HAS_ANDROID" ]; then
125
- STACK="android"
126
- elif [ -n "$HAS_IOS" ]; then
127
- STACK="ios"
128
- elif [ -n "$HAS_FRONTEND" ] && [ -n "$HAS_BACKEND" ]; then
129
- STACK="fullstack"
130
- elif [ -n "$HAS_FRONTEND" ]; then
131
- STACK="frontend"
132
- elif [ -n "$HAS_BACKEND" ]; then
133
- STACK="backend"
134
- else
135
- STACK="ios" # default
136
- fi
137
-
138
- # Apply swap
139
- case "$STACK" in
140
- ios)
141
- activate_stack "$IOS_PATTERNS"
142
- deactivate_stack "$ANDROID_PATTERNS"
143
- deactivate_stack "$BACKEND_PATTERNS"
144
- MSG="iOS"
145
- ;;
146
- android)
147
- deactivate_stack "$IOS_PATTERNS"
148
- activate_stack "$ANDROID_PATTERNS"
149
- deactivate_stack "$BACKEND_PATTERNS"
150
- MSG="Android"
151
- ;;
152
- mobile)
153
- activate_stack "$IOS_PATTERNS"
154
- activate_stack "$ANDROID_PATTERNS"
155
- deactivate_stack "$BACKEND_PATTERNS"
156
- MSG="Mobile (iOS + Android)"
157
- ;;
158
- frontend)
159
- deactivate_stack "$IOS_PATTERNS"
160
- deactivate_stack "$ANDROID_PATTERNS"
161
- deactivate_stack "$BACKEND_PATTERNS"
162
- activate_stack "$FRONTEND_PATTERNS"
163
- MSG="Frontend"
164
- ;;
165
- fullstack)
166
- deactivate_stack "$IOS_PATTERNS"
167
- deactivate_stack "$ANDROID_PATTERNS"
168
- activate_stack "$BACKEND_PATTERNS"
169
- activate_stack "$FRONTEND_PATTERNS"
170
- MSG="Fullstack (Frontend + Backend)"
171
- ;;
172
- backend)
173
- deactivate_stack "$IOS_PATTERNS"
174
- deactivate_stack "$ANDROID_PATTERNS"
175
- activate_stack "$BACKEND_PATTERNS"
176
- deactivate_stack "$FRONTEND_PATTERNS"
177
- MSG="Backend"
178
- ;;
179
- esac
180
-
181
- ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
182
- echo "{\"systemMessage\": \"Stack: $MSG ($ACTIVE skills active)\"}"