---
name: multi-agent
language: en
description: "Task orchestrator: runs the full pipeline from a Jira ID or GitHub Issue URL  -  analysis → plan → TDD development → parallel review (Fable + Sonnet on Claude Code, GPT + Opus + Sonnet on Copilot CLI) → commit → log. Every step is written to agent-log.md. Use when given a Jira ID, a GitHub issue or a free-text task and the whole pipeline should run."
user-invocable: true
argument-hint: '"PROJ-12345" "feature/PROJ-12345-flight-filter" | "https://github.com/.../issues/316" | status | log #1 | resume #1 | kill #1 | clear-logs | purge | review'
---

Read and follow the instructions in this file's INSTRUCTION.md section below.

---

# Multi-Agent Task Orchestrator

## Project Detection

Detect project from cwd FIRST, then validate input format:

| cwd contains | Project | Accepted Input | Rejected Input |
|--------------|---------|----------------|----------------|
| `/my-ios-app` | my-app | `"PROJ-XXX" "branch"` | GitHub Issue URL |
| `/my-figma-app` | figma | `"https://github.com/.../issues/N"` | Jira ID + branch |
| Other | generic | Both formats |  -  |

If user gives wrong format for the project, warn:
- my-ios-app + GitHub URL → "This project expects a Jira ID + branch. Example: multi-agent \"PROJ-12345\" \"feature/PROJ-12345-desc\""
- my-figma-app + Jira → "This project expects a GitHub Issue URL. Example: multi-agent \"https://github.com/my-org/my-figma-app/issues/316\""

## Input Parsing

Classify user input into one of 5 types (matches the `commands/multi-agent/SKILL.md` dispatcher contract; cross-CLI parity is enforced by `smoke-cross-cli-behavior.sh`):

| # | Pattern | Type | Action |
|---|---------|------|--------|
| 1 | `#N` or bare `316` | github-issue-number | Fetch via gh after project selection |
| 2 | `https://github.com/.../issues/N` | github-issue-url | Extract org/repo/N, fetch via gh |
| 3 | `https://{JIRA_HOST}/browse/{JIRA_KEY}-XXXXX` | jira-url | Extract ID, fetch via Jira API |
| 4 | `{JIRA_KEY}-XXXXX` (bare) | jira-id | Fetch via Jira API |
| 5 | Anything else | free-text | No external fetch |

All types enter the same Phase 0 flow.

## Routing

Parse the user's input and route to the correct sub-command:

| Input Pattern | Action |
|---------------|--------|
| `"PROJ-XXX" "branch"` | **my-app only**  -  Jira ID + branch name → auto-assigned incremental ID |
| `"https://github.com/..."` | **figma only**  -  parse issue, extract Jira from title/body, auto-create branch |
| `status` | Show all tasks with ID, phase, status |
| `log [id]` | Show agent-log.md for task (latest if no id) |
| `resume [id]` | Resume paused/failed task from last successful phase |
| `kill [id]` | Stop task, delete worktree + branch + logs. Asks confirm first |
| `clear-logs` | Delete all agent-log.md and agent-state.json files, keep worktrees/branches |
| `purge` | Nuclear cleanup  -  delete ALL worktrees, branches, logs, state, counter. Full reset |
| `review` | Skip phases 0-3, review current diff only |
| `autopilot` flag | Add to any pipeline command  -  skip user confirmations except destructive ops |
| No args / `help` | Show usage guide (project-specific) |

---

## Autopilot Mode

Autopilot mode skips interactive confirmations and runs the pipeline end-to-end autonomously.

**Activation**: Add `autopilot` flag to any pipeline command:
```
multi-agent "PROJ-12345" "feature/PROJ-12345-desc" autopilot
multi-agent "https://github.com/.../issues/316" autopilot
multi-agent "LoginView dark mode fix" autopilot
```

**What changes in autopilot:**

| Phase | Normal | Autopilot |
|-------|--------|-----------|
| Phase 2 (Plan Approval Gate) | Clarification (max 2 rounds) + approval loop  -  user replies `onayla`/`iptal`/free-text | **Gate skip**  -  log the plan, go straight to Phase 3 (autopilot contract: zero interaction) |
| Phase 5 (User Test) | "Want to test it?" → wait | Skip → go straight to Phase 6 |
| Phase 6 (Commit) | "Want to commit?" → wait | Automatic commit + push |
| Phase 6 (PR) | "Want to open a PR?" → wait | Automatically create the PR |

**What NEVER skips (even in autopilot):**
- Phase 4 Review → if there is a blocking finding, return to Phase 3, fix + rebuild automatically (safety)
- Kill/Purge confirmations → destructive operations always ask
- Build fail → fix + rebuild automatically (max 3 retries). If it still fails after 3 retries → pause, ask the user

**State tracking**: `"autopilot": true` is added to `agent-state.json`. Autopilot continues on resume too.

---

## Task ID System

Every task gets an **auto-incremented short ID** for easy reference:

```
multi-agent "PROJ-12345" "feature/PROJ-12345-flight-filter"
→ ✅ Task #1 started  -  PROJ-12345

multi-agent "PROJ-67890" "feature/PROJ-67890-booking-flow"
→ ✅ Task #2 started  -  PROJ-67890
```

ID is stored in `agent-state.json` and shown in `multi-agent status`:

```
🤖 Multi-Agent Active Tasks

| ID | Jira | Branch | Phase | Status |
|----|------|--------|-------|--------|
| #1 | PROJ-12345 | feature/PROJ-12345-... | 3/7 Dev | ⚡ in progress |
| #2 | PROJ-67890 | feature/PROJ-67890-... | 1/7 Analysis | 📊 scanning |
```

ID counter stored at `.worktrees/.multi-agent-counter` (persists across sessions).

---

## Kill Logic

When `multi-agent kill [id]` is called:

1. **Find task**: Look up task by short ID (e.g. `#2`) or Jira ID (e.g. `PROJ-67890`)
2. **Confirm**: Ask user: `"PROJ-67890 (Task #2) will be deleted: worktree, branch, logs. Are you sure?"`
3. **Stop agents**: Kill any running background agents for this task
4. **Delete worktree**: `git worktree remove .worktrees/PROJ-{id} --force`
5. **Delete branch**: `git branch -D {branch-name}`
6. **Delete remote branch**: ONLY if user explicitly confirms: "Do you want to delete the remote branch too?"
7. **Archive log** (optional): Move `agent-log.md` to `.worktrees/.archive/PROJ-{id}/` before delete
   - Or delete completely if the user says "delete completely"
8. **Update counter**: Mark ID as available (or just skip  -  IDs are cheap)
9. **Confirm**: `❌ Task #2 (PROJ-67890) killed  -  worktree, branch, logs deleted`

---

## Clear Logs  -  superseded, redirect only

`multi-agent clear-logs`: **do not run it.** Say it was superseded, then route to
`multi-agent-prune-logs` (per-task logs, audit trail and metrics kept) or
`multi-agent-garbage-collect` (`/tmp` scratch + worktree residue).

It scanned `.worktrees/PROJ-*/`, which holds no logs  -  they live at
`$HOME/.claude/logs/multi-agent/{project}/{task-id}/`  -  so it deleted nothing and
reported success. The name stays as a redirect so an existing invocation still lands
somewhere correct.

---

## Purge (Full Reset)

When `multi-agent purge` is called:

1. **Confirm**: `"⚠️ WARNING: All worktrees, branches, logs and state will be deleted. This cannot be undone. Are you sure?"`
2. **List**: Show what will be deleted:
   ```
   To be deleted:
   - .worktrees/PROJ-12345/ (branch: feature/PROJ-12345-...)
   - .worktrees/PROJ-67890/ (branch: feature/PROJ-67890-...)
   - .worktrees/.multi-agent-counter
   Total: 2 worktrees, 2 branches, 2 logs
   ```
3. **Second confirm** (paranoia gate)  -  a native `AskUserQuestion` picker (no typed keyword):
   - `question`: "This is irreversible. Permanently wipe every worktree, branch, log, and state file now?" (`outputLanguage`)
   - `header`: "Purge" (English, <=12 chars) · `options`: `{ label: "Purge permanently", description: "Delete all worktrees, branches, logs, and state" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
   - Anything other than **Purge permanently** → cancel.
4. **Execute** (for each worktree):
   - `git worktree remove .worktrees/PROJ-{id} --force`
   - `git branch -D {branch-name}`
   - Remote branch delete ONLY if user explicitly confirms: "Do you want to delete the remote branches too?"
5. **Cleanup**: Remove `.worktrees/.multi-agent-counter` and `.worktrees/.archive/`
6. **Confirm**:
   ```
   🔥 Purge complete
   Deleted: {N} worktrees, {N} branches, {N} logs
   multi-agent is reset to clean state
   ```

---

## Resume Logic

When `multi-agent resume [id]` is called:

1. **Find state file**: `$HOME/.claude/logs/multi-agent/{project}/{task-id}/agent-state.json`  -  that is where Phase 0 writes it, not inside the worktree. A task finalized by Phase 6 keeps its state at `.../{task-id}/artifacts/agent-state.json`, so look there too before reporting not-found.
   - If no `id` given, take the most recent task dir with `status != "done"`
2. **Read state**: Parse `agent-state.json` → determine last completed phase
3. **Restore context**: Read `agent-log.md` for previous findings:
   - Phase 1 analysis findings → reuse in Phase 2+
   - Phase 2 plan/todos → reuse in Phase 3+
   - Phase 3 code changes → already on disk in worktree
   - Phase 4 review findings → reuse if re-reviewing
4. **Resume from next phase**: Skip completed phases, start from `currentPhase + 1`
5. **Log**: `🔄 Resumed PROJ-{id} from Phase {N}`

This works across sessions because:
- `agent-state.json` → persists phase progress on disk
- `agent-log.md` → persists findings, analysis, decisions on disk
- Git worktree → persists code changes on disk
- All state is file-based, nothing depends on in-memory session

---

## Agent dispatch  -  per-persona model routing

Every agent persona under `$HOME/.claude/agents/*.md` declares a `preferredModel` frontmatter field. The orchestrator MUST honor it on every dispatch, on both Claude Code and Copilot CLI  -  cross-CLI parity is enforced by `smoke-cross-cli-behavior.sh`.

| Persona | `preferredModel` | Rationale (condensed) |
|---|---|---|
| `explorer` | `sonnet` | Scan/pattern work, cost-efficient without quality loss |
| `code-reviewer` | `opus` | Tier 1 reviewer; Phase 4 overrides Reviewer 3 to `sonnet` |
| `security-auditor` | `opus` | False-negative cost is high; opus reduces miss rate |
| `ios-architect` | `opus` | Deep module/protocol/migration reasoning |
| `android-architect` | `opus` | Gradle modules, Compose stability, Hilt graphs |
| `backend-architect` | `opus` | API + migration + scaling reasoning |

**Dispatch contract (pseudo-code):**

```bash
persona_file="$HOME/.claude/agents/${persona}.md"
pref_model="$(awk '/^preferredModel:/ {print $2; exit}' "$persona_file")"
override="${PHASE_MODEL_OVERRIDE:-}"   # set by orchestrator per-dispatch (e.g. Phase 4 Reviewer 3 → sonnet)
resolved_model="${override:-${pref_model:-opus}}"

export CLAUDE_CODE_SUBAGENT_MODEL="$resolved_model"
# Claude Code honors the env var; Copilot CLI reads the same env + passes as --model flag.
```

**Precedence:** per-dispatch `PHASE_MODEL_OVERRIDE` > persona `preferredModel` > global default (`opus`).

**Observability:** emit `phase.agent.dispatch` OTel span with `{persona, resolved_model, override_source}` attributes when `MULTI_AGENT_OTEL_SPANS=1` (see `phase-tracker.sh`).

---

## Dynamic skill loading  -  trigger-based injection (v7.0.0+, opt-in)

**Gated by `prefs.global.dynamicSkillLoading` (default `false`).** When enabled, the orchestrator moves from eager-loading all 206 skills on every session to injecting only the skills that match the current task context. The match signal comes from three sources in descending weight:

1. `trigger-paths` globs in SKILL.md frontmatter vs. Phase 1 touched files (heaviest, +30 max)
2. `trigger-keywords` in SKILL.md frontmatter vs. task text (mid, +30 max)
3. `description` keyword overlap with task text (lightest fallback, +15 max)
4. Platform match vs. Phase 1 detected stack (+10)

**Runtime contract:**

```bash
# After Phase 1 produces analysis.json with {stack.primary, touchedAreas[].path}
task_text="$(jq -r '.summary' analysis.json)"
touched=$(jq -r '.touchedAreas | map(.path) | join(",")' analysis.json)
stack=$(jq -r '.stack.primary' analysis.json)

matched_skills=$(node "$HOME/.claude/scripts/match-skills.mjs" \
  "$task_text" \
  --touched-files "$touched" \
  --stack "$stack" \
  --limit 12 \
  --json)

# Inject only matched skills[] into subagent prompts for Phase 2-4.
# Skills not in the matched list are not loaded  -  saves ~10K-30K tokens
# per subagent dispatch on small tasks.
```

**Fallback:** every install ships `.skills-index.json` beside the skills. If it is absent anyway (a checkout before `build-skills-index.mjs` runs), the orchestrator eager-loads as pre-v7.0  -  dynamic loading never blocks the happy path.

**--index-only installs:** `node install.js --index-only` writes only the index, not the 206 SKILL.md payloads. Intended for:
- CI pipelines that fetch skill bodies on demand
- Disk-constrained users who accept the dynamic-load contract

When `dynamicSkillLoading=true` AND the target install is index-only, subagent prompts must include the matched skills' bodies inline (read from the pipeline source or a cached copy). The orchestrator resolves this by reading `{PIPELINE_SRC}/pipeline/skills/{relativePath}`  -  the pipeline source repo is always the source of truth; the install dir is a cache.

**Telemetry:** when `MULTI_AGENT_OTEL_SPANS=1`, emit `phase.skills.match` span with `{taskId, matchedCount, topN=[name,score]}` so post-hoc analysis can tune trigger-keywords / trigger-paths in SKILL.md frontmatter.

---

## Phase Pipeline

Run phases sequentially. Log every step to `agent-log.md`.
If any phase fails, mark task as `paused` and stop  -  user can `resume` later.

**The blocks below are the routing summary, not the specification.** Each phase's
full contract lives in `$HOME/.claude/multi-agent-refs/phases/phase-{n}-{name}.md`
(3200 lines across the set) and is read when that phase actually starts. Modes are
in `phases/modes.md`, operations in `phases/operations.md`, the log shape in
`phases/log-format.md`. Where a summary here and a ref disagree, the ref wins and
the summary is the bug: this file used to carry its own copy of the log format,
and the copy named a path the code had stopped using.

### Canonical phase labels (TaskCreate + banner)

Every user-facing phase title  -  TaskCreate cards, `phase-banner.sh` headers, and any status line rendered to the terminal  -  MUST come from this table. Labels are always English (`promptLanguage` is locked to `en`):

| # | Label                  |
|---|------------------------|
| 0 | Phase 0: Init          |
| 1 | Phase 1: Analysis      |
| 2 | Phase 2: Planning      |
| 3 | Phase 3: Dev           |
| 4 | Phase 4: Review        |
| 5 | Phase 5: Test          |
| 6 | Phase 6: Commit & PR   |
| 7 | Phase 7: Report        |

**Render rule:**

1. For TaskCreate, use the matching label as the task `subject`.
2. For terminal banners, call `phase-banner.sh` with the `auto` sentinel and `PHASE_LANG=en` env  -  or pass the literal label from the table. Never invent a new label.
3. Reviewer-count qualifiers (e.g. `(parallel + triage)`) stay English  -  they are technical artifacts, not user copy.

**Out of scope for localization** (always EN, per `prefs.schema.json`): reviewer/triage system prompts, commit messages, PR titles/bodies, Jira comments, wiki content, log payloads inside `agent-log.md`  -  these are external artifacts consumed by other tools and humans beyond this user.

#### TaskCreate ordering (strict)

All TaskCreate calls fire in strict phase-number order BEFORE any TaskUpdate is applied (Claude Code path; Copilot CLI does not have a TaskList widget so this rule is Claude-only). The native widget renders by creation order, not by phase-number metadata  -  out-of-order calls produce visually scrambled tile stacks (e.g. `1 ✓ · 2 ✓ · 4 ✓ · 0 ▶ · 3 ☐`) even when the underlying state file is correct. Pre-marking phases as completed/skipped before Phase 0 starts is FORBIDDEN: register the tile in order with default `pending` status, then flip via TaskUpdate when the phase actually short-circuits. Mode-specific phase sets:

- `multi-agent`: 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7
- `multi-agent-local`, `multi-agent-autopilot`, `multi-agent-local-autopilot`: 0 → 1 → 2 → 3 → 4 → 6 → 7 (the interactive Phase 5 gate needs a worktree checkout and an attended run)
- `multi-agent-analysis`: 0 → 1 → 2 → 4 → 6 → 7 (no code, so no Dev and no Test)

Depth does not change the SET. A Short run (the Phase 0 Step 7.5 answer) registers its command's full set and flips Phases 1 and 2 to `skipped` when the answer lands at Step 7.5 - the tracker boots at Step -1, long before the question can be asked.

Full contract: `refs/tracker-contract.md` section "TaskCreate ordering (strict)".

### Phase 0: Init

> **Contract (strict)**  -  Phase 0 has **8 sequential interactive steps** plus the
> Step 7.5 depth question (`/multi-agent` and `:local` only; the autopilot entries
> skip it and always run Full), defined in
> `refs/phases/phase-0-init.md`. Read it before every Phase 0 run and execute all of
> them. Do **NOT** short-circuit: even when the input is a Jira ID plus a branch, the
> prefs load, the multi-repo offer, the branch picker and the branch-name confirm are
> required UX checkpoints. A run once took a Jira ID and implemented straight onto the
> local checkout with neither the project nor the branch picker ever shown, and nothing
> failed, so nothing caught it. The walkthrough below covers input parsing and worktree
> creation only; it is not the contract.
>
> **Exit gate (BLOCKING).** Prose alone did not stop that run. Before marking Phase 0
> completed:
>
> ```bash
> node "$HOME/.copilot/scripts/phase0-exit-gate.mjs" "$TASK_ID" --input "$USER_INPUT"
> ```
>
> Non-zero means Phase 0 did not produce its own output - `taskType`, `baseBranch`,
> `baseFetchStatus`, a worktree path distinct from the project root, and a recorded Figma
> access tier when the input carries a Figma URL. Fix the missing step; do not proceed.
>
> **Credential inventory (Step 0).** Run
> `bash "$HOME/.copilot/lib/credential-inventory.sh" --json` and store the result in
> `agent-state.json.credentialInventory`. Per `refs/keychain.md` Rule 2, never ask the
> user for data a mapped credential can fetch: a run asked for a hand-pasted Crashlytics
> stack trace while a valid Firebase service account was mapped and resolving. Ask for
> the pointer (the issue URL) instead, and say what you will do with it.

**Step 1  -  Project detection + input parsing:**

#### my-ios-app (Jira + branch)
1. Input: `"PROJ-12345" "feature/PROJ-12345-flight-filter"`
2. Parse directly: `jiraId = PROJ-12345`, `branch = feature/PROJ-12345-flight-filter`
3. No GitHub interaction needed

#### my-figma-app (GitHub Issue URL)
1. Input: `"https://github.com/my-org/my-figma-app/issues/316"`
2. Parse issue via `gh issue view 316 --json title,body,labels,assignees`
3. Extract Jira ID from issue title or body (pattern: `PROJ-XXXXX`)
4. Auto-generate branch: `feature/PROJ-{jiraId}-GH{issueNo}-{component-kebab}`
5. Assign issue to self: `gh issue edit 316 --add-assignee @me`
6. Move to In Progress: `gh issue edit 316 --add-label "in progress"`

#### generic (any iOS project)
1. Accept multiple input formats:
   - **Free-text**: `"In LoginView the button color is invisible in dark mode, insufficient contrast"`
   - **GitHub Issue URL**: parse via `gh issue view`
   - **Jira ID + branch**: parse directly
2. If free-text:
   - Extract task summary from description
   - Auto-generate branch: `fix/{short-kebab-description}` or `feature/{short-kebab-description}`
   - Determine type from context: bug description → `fix/`, feature request → `feature/`
3. No Jira integration needed  -  task ID is enough for tracking

**Step 2  -  Worktree setup (all projects):**
1. **Fetch latest from remote**: `git fetch origin`
2. Determine worktree path:
   - Jira ID var: `.worktrees/PROJ-{id}/`
   - Jira ID yok (generic): `.worktrees/task-{shortId}/` (e.g. `.worktrees/task-3/`)
3. Create or switch to git worktree:
   - Residue guard first (idempotent; keeps `.worktrees/` gitlinks out of `git add -A` in the parent tree): `ex="$(git rev-parse --path-format=absolute --git-common-dir)/info/exclude"; grep -qxF '.worktrees/' "$ex" 2>/dev/null || printf '.worktrees/\n' >> "$ex"`
   - If remote branch exists: `git worktree add {worktree-path} origin/{branch} -b {branch}`
   - If new branch: `git worktree add {worktree-path} -b {branch}`
   - If worktree already exists: `cd {worktree-path} && git pull origin {branch}`
4. Set git author (resolved from `prefs.global.identities[]`  -  routed by `platformIdentityRouting`, see `setup.md`):
   ```
   git config user.name  "{identity.name}"
   git config user.email "{identity.email}"
   ```
4. Create log file: `$HOME/.claude/logs/multi-agent/{project}/{task-id}/agent-log.md` with header
5. Create state file: `$HOME/.claude/logs/multi-agent/{project}/{task-id}/agent-state.json` with:
   ```json
   {
     "taskId": "PROJ-12345",
     "branch": "feature/PROJ-12345-flight-filter",
     "project": "my-ios-app",
     "currentPhase": 0,
     "status": "in_progress",
     "startedAt": "2026-04-07T09:30:00Z",
     "phases": {
       "0": { "status": "done", "duration": "5s" },
       "1": { "status": "pending" },
       "2": { "status": "pending" },
       "3": { "status": "pending", "todos": [], "retryCount": 0 },
       "4": { "status": "pending", "reviewIteration": 0 },
       "5": { "status": "pending" },
       "6": { "status": "pending" },
       "7": { "status": "pending" }
     },
     "analysisFindings": [],
     "planTodos": [],
     "reviewConsensus": null
   }
   ```
6. Log: `✅ Phase 0: Init complete`

**IMPORTANT**: Update `agent-state.json` at EVERY phase transition. This file is the resume source of truth.

### Phase 1: Analysis (claude-fable-5)
1. Launch **explore agents** (parallel) to scan codebase:
   - Related files to the task
   - Existing patterns and conventions
   - Potential impact areas
2. Optionally launch **security-auditor** agent for pre-check
3. Summarize findings
4. Log: `📊 Phase 1: Analysis  -  {N} files identified, {summary}`

### Phase 2: Planning (claude-fable-5)
1. Create task breakdown → todos with dependencies
2. Launch **ios-architect** agent for architecture review (if structural changes)
3. Determine development approach per todo (new file, modify, refactor)
4. Log: `🧠 Phase 2: Plan  -  {N} todos created`
5. **Plan Approval Gate** (Full + interactive only  -  a Short run has no plan, autopilot may not ask). Full flow in `refs/phases/phase-2-planning.md` Step 5:
   - **5a  -  Clarification** (conditional, max 2 rounds): if the Jira/issue description is ambiguous (vague acceptance, UI task without Figma, API task without endpoint contract, `ambiguityScore >= 2`, parent-story scope drift), ask structured questions before rendering the plan. User answers → plan regenerated. If it is still unclear after the 2nd round, render the plan with a "best-effort" banner.
   - **5b  -  Approval loop**: render plan → user: `onayla`/`iptal`/free-text. A free-text edit request → the planning model (Fable) revises the plan → show it again. No iteration cap; user controls exit via `onayla` or `iptal`.
   - Persist `clarificationRounds`, `clarificationQuestions`, `clarificationAnswers`, `planIterations`, `planApprovedAt`, `planEditRequests` to `state.phases["2"]`.

### Phase 3: Dev (claude-sonnet-5)
For each todo (respecting dependency order):
1. Update todo status: `in_progress`
2. **TDD cycle**:
   - Write failing test → verify RED
   - Write minimal code → verify GREEN
   - Refactor if needed
3. Run build: `xcodebuild` via **task agent**
4. If build fails → fix → rebuild (max 3 attempts, track `retryCount` in `agent-state.json`)
5. Update todo status: `done`
6. Log: `⚡ Phase 3: {todo-id}  -  Test ✅ Build ✅`

### Phase 4: Review (parallel + triage)
0. **Diff Risk Scoring (advisory, v8.3+)**  -  before reviewer dispatch run `node $HOME/.claude/scripts/diff-risk-score.mjs --base "$BASE_BRANCH" --top 5` and inject the top-N risk-ranked files as a `${PRIORITY_FILES}` block into each reviewer's prompt. Heuristic, deterministic, sub-second, never gates the pipeline. Disabled when `prefs.global.diffRiskAdvisory = false`. Signals: security paths (×3), schema migrations (×4), public API surfaces (×2), no-test-change (×2.5), complexity delta (×1.5), UI-critical paths (×1.5), loc changed (×1).
1. Launch **code-reviewer** agents in parallel. Reviewer set depends on which CLI is hosting the pipeline:
   - **Claude Code** (2 reviewers): `claude-fable-5` (deep security + architecture) + `claude-sonnet-5` (quality + correctness)
   - **Copilot CLI** (3 reviewers): `gpt-5.4` (edge cases, different perspective) + `claude-opus-5` + `claude-sonnet-5` (Fable 5 is not offered on Copilot CLI)
   - Triage: single top-tier pass over merged findings (`claude-fable-5` on Claude Code, `claude-opus-5` on Copilot CLI)
2. Collect findings, classify:
   - 🔴 **Blocking** → must fix → back to Phase 3 (max 3 iterations)
   - 🟡 **Important** → fix and re-review
   - 🟢 **Suggestion** → apply if reasonable
3. Log: `🔍 Phase 4: Review  -  {consensus}`

### Phase 5: Test
Lets the user physically test the code before opening a PR. The prompt MUST make it explicit that saying yes **removes the worktree and checks the branch out locally**  -  otherwise the user is hit with an implicit side effect.

0. **Test Gap Report (advisory, v8.3+)**  -  before the local-checkout prompt run `node $HOME/.claude/scripts/test-gap-scan.mjs --base "$BASE_BRANCH" --stack <ios|android|python|node>` to surface public symbols added in this branch that have no paired test. Heuristic, deterministic, sub-second, never gates by default. iOS `*View.swift` / Android `@Composable` symbols default to `important` severity; other public API additions to `suggestion`. Optional gating via `prefs.testGap.blockingThreshold` (loops back to Phase 4 rework when the important+blocking count exceeds the threshold). Disabled when `prefs.testGap.enabled = false`.
1. **Ask** with a native `AskUserQuestion` picker (never a typed y/N prompt). The options MUST make the local-checkout side effect explicit  -  testing removes the worktree and checks the branch out into the main repo:
   - `question`: "Check out locally to test now?" (rendered in `outputLanguage`)
   - `header`: "Test" (English, <=12 chars)
   - `options`:
     - `{ label: "Test now", description: "Removes the worktree and checks the branch out into the main repo for Xcode / manual test" }`
     - `{ label: "Skip", description: "Stay in the worktree and go to Phase 6" }`
   - **Skip** → go to Phase 6
   - **Test now** → continue:
2. **Remove the worktree and switch to the branch** (automatic):
   ```bash
   cd {project-root}
   git worktree remove .worktrees/PROJ-{id}
   git checkout {branch-name}
   ```
3. **Give test instructions**:
   ```
   🧪 Switched to branch: {branch-name}

   To test:
     • SourceTree → check the commits and diff
     • Xcode → open the app's `.xcworkspace` → Cmd+B → Cmd+U
     • Manual test on the Simulator

   ✅ "tamam" → proceeds to Phase 6
   ❌ "fix: ..." → worktree is recreated, returns to Phase 3
   ```
4. **Pause and wait**: Wait for the user's response
5. **If a fix is needed**:
   - Recreate the worktree: `git worktree add .worktrees/PROJ-{id} {branch-name}`
   - Return to Phase 3
6. Log: `🧪 Phase 5: Test  -  {result}`

> ⚠️ Commits live on the branch  -  removing the worktree does NOT delete the commits.

### Phase 6: Commit & PR

**Project-specific commit strategy:**

#### my-figma-app
1. **Ask**: "Want to commit?"
   - **No** → Pause; the user continues with `resume` when ready
   - **Yes** → continue:
2. Run `/figma-iteration-commit {ComponentName}`
   - Build verification, test, key sync, code review, submodule commits to `iteration/develop`, push with rebase-retry, issue housekeeping, auto-unblock dependents  -  the skill handles all of it
   - Do NOT commit manually  -  the skill manages everything
3. Log: `📦 Phase 6: figma-iteration-commit  -  {ComponentName}`

#### my-app / generic
1. **Ask**: "Want to commit?"
   - **No** → Pause; the user continues with `resume` when ready
   - **Yes** → continue:
2. Stage changes: `git add` with specific files (NOT `git add -A`  -  avoid committing .env, credentials, or other sensitive files)
3. Commit with convention: `{type}({scope}): {description} [PROJ-{id}]`
   - Author: resolved from `prefs.global.identities[]` (e.g. `Ada Lovelace <ada@example.com>`)  -  NEVER hardcode.
4. Push to remote
5. **Ask**: "Want to open a Pull Request?"
   - **No** → go to Phase 7 (only commit + push will have been done)
   - **Yes** → create the PR (target: source branch)
6. **Issue body update** (if GitHub Issue exists):
   - Fill PR links in issue body: `- **common:** {PR URL}`, `- **uicomponents:** {PR URL}`
   - Update Progress flags: `Implementation 🟢`, `Testing 🟢`, `Code Connect 🟢`
   - Use `gh issue edit {issueNo} --body "{updated body}"`  -  preserve all existing sections
7. Log: `📦 Phase 6: Commit {sha}  -  PR #{number}`

### Phase 7 Report Step 2: WIKI + Figma Screenshots (for component tasks with GitHub Issue)

Skip this sub-step if the task is NOT a component implementation (e.g., bug fix, refactor).

**Wiki submodule location**: `~/my-figma-app/<project>Packages/Packages/my-ui-components-wiki`

1. **Determine wiki path** from component location:
   - `DesignSystemCore/SeatMap/SeatMapAircraftDetails/` → `{wikiRoot}/DesignSystemCore/SeatMap/SeatMapAircraftDetails/`
   - Pattern: `{wikiRoot}/{category}/{ComponentName}/`
2. **Create directory**: `mkdir -p {wikiComponentPath}/assets`
3. **Fetch Figma screenshot** via REST API:
   ```bash
   FIGMA_TOKEN=$(~/.copilot/lib/credential-store.sh get "Figma_Access_Token")
   curl -s "https://api.figma.com/v1/images/{fileKey}?ids={nodeId}&format=png&scale=2" \
     -H "X-Figma-Token: $FIGMA_TOKEN"
   # Download the image URL to {wikiComponentPath}/assets/screenshot.png
   ```
4. **Generate main wiki page** (`{ComponentName}.md`):
   - Follow existing wiki convention (see Tooltip.md, FileUploadFileDescription.md as references)
   - Sections: title, screenshot embed, Figma link, Screen/Section/Size, Overview, Testing Identifiers, Localization Keys, Accessibility, Analytics Events, Sub-Components, Platform Implementations, Changelog
   - Screenshot embed: `[[/{wikiCategory}/{ComponentName}/assets/screenshot.png|{ComponentName}]]`
5. **Generate iOS wiki page** (`{ComponentName}-iOS.md`):
   - Sections: Initializer (with code), Parameters table, Modifiers, Usage examples, Design Tokens table, Testing Identifiers iOS, Code Connect status, Snapshot Tests (with image embeds), Test Coverage, Changelog
   - Snapshot image embeds use `[[/{wikiCategory}/{ComponentName}/assets/ios_{variant}.png]]` format
   - Note: actual snapshot images are generated when tests run in CI/locally
6. **Commit and push wiki**:
   ```bash
   cd {wikiRoot}
   git add {wikiCategory}/{ComponentName}/
   git commit -m "docs({scope}): add {ComponentName} wiki pages [PROJ-{id}]"
   git fetch origin && git rebase origin/master
   git push origin HEAD:master
   ```
7. **Update issue Wiki flag**: Set `Wiki` → `🟢` in issue body
8. Log: `📖 Phase 7 Step 2: Wiki  -  {ComponentName}.md + {ComponentName}-iOS.md + screenshot`

### Phase 7: Report
1. Finalize `agent-log.md` with ALL sections:
   - **Timeline table**: phase, agent, model, duration, status, detail
   - **Agent Activity Report**: per-agent call count, total duration, models used, skill count
   - **Token Estimate**: estimated token usage per agent + total
   - **Per-Phase Time Distribution**: ASCII bar chart showing time per phase
   - **Review Iterations**: blocking/important/suggestion counts per iteration
   - **Files Changed**: `git diff --stat` output
   - **Review Consensus**: final 🔴/🟡/🟢 status
   - **Test Scenarios**: Turkish, for Jira (Precondition → Steps → Expected result)
2. Print compact summary to terminal:
   ```
   ✅ PROJ-{id} complete
   ⏱️  Total: 3m 18s | Agents: 12 calls | Files: 4 changed
   📦 Commit: abc1234 | PR: #87
   📖 Wiki: {ComponentName}.md pushed to wiki master
   📋 Full report: ~/.claude/logs/multi-agent/{project}/{task-id}/agent-log.md
   ```
3. Log: `📋 Phase 7: Report complete`

---

## Log File Format

Canonical shape, and the path the code actually uses, live in
`$HOME/.claude/multi-agent-refs/phases/log-format.md`. Read it when writing
the log; do not re-derive the format here.

This section used to carry its own copy of the whole template, and the copy
had gone stale in a way that mattered: it said the log lives at
`.worktrees/PROJ-{id}/agent-log.md`, while `prune-logs.sh` and the phase
tracker both use `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`. Two
answers for one path, and the wrong one was the one loaded on every run.

## Component Generation

Generic guide: `$HOME/.claude/multi-agent-refs/component-generation.md`.
Dispatch (which plugin skill handles it per CLI):
`$HOME/.claude/multi-agent-refs/component-dispatch.md`.

Loaded only for a task that generates a component from a design, which is
what it is for. It was previously inline and paid for on every run.

## Rules

- ❌ NEVER put "Copilot", "AI", "generated by" in code or commits
- ❌ NEVER commit without passing build
- ❌ NEVER commit without passing review
- ✅ Follow existing code style and conventions
- ✅ Use design tokens, no magic numbers
- ✅ Every public method must have tests
- ✅ Xcode header on new Swift files
- ✅ Commit message format:
  - With Jira: `{type}({scope}): description [PROJ-{id}]`
  - Without Jira (generic): `{type}({scope}): description [#{shortId}]`
- ✅ Git author: resolved from `prefs.global.identities[]` (e.g. `{identity.name} <{identity.email}>`)  -  NEVER hardcoded

---

## Skill Injection Strategy

Sub-agents have embedded skills in their `.agent.md` files. Each agent is pre-loaded with domain-specific knowledge:

### Agent ↔ Skill Matrix

| Agent | Embedded Skills | When Activated |
|-------|----------------|----------------|
| **code-reviewer** | Code Review Excellence, Security Audit, Performance Review, TDD Verification, Error Detective | Phase 4: Review |
| **ios-architect** | Spec-Driven Architecture, Context Management, Multi-Agent Coordination, API Design, Performance Architecture, Design System Governance | Phase 2: Planning |
| **security-auditor** | iOS Security Deep Dive, App Store Review Gates, Third-Party SDK Risk, Error Detective (Security) | Phase 1: Analysis (pre-check) + Phase 4: Review |

### Phase → Agent → Skills Flow

```
Phase 1: Analysis
  ├─ explore agents (no skills needed  -  pure file reading)
  └─ security-auditor agent
       └─ Skills: iOS Security Deep Dive, App Store Review Gates, SDK Risk

Phase 2: Planning
  └─ ios-architect agent
       └─ Skills: Spec-Driven Architecture, API Design, Performance Architecture

Phase 3: Dev
  └─ Ana agent (reads copilot-instructions.md directly)
       └─ TDD, token rules, code style  -  from global instructions

Phase 4: Review (parallel + triage)
  Claude Code  (2 parallel):
    ├─ code-reviewer (claude-opus)   → all 5 review skills
    └─ code-reviewer (claude-sonnet) → all 5 review skills
  Copilot CLI  (3 parallel):
    ├─ code-reviewer (gpt-5.4)       → all 5 review skills
    ├─ code-reviewer (claude-opus)   → all 5 review skills
    └─ code-reviewer (claude-sonnet) → all 5 review skills
  Triage (both): claude-opus over merged findings
```

### Context-Aware Skill Injection

When calling sub-agents, the ana agent SHOULD add task-specific context to the prompt:

```
For code-reviewer in Phase 4:
  "Review this diff for PROJ-{id}. Focus areas based on analysis:
   - {files changed summary from Phase 1}
   - {architecture decisions from Phase 2}
   - {specific risk areas identified}"

For ios-architect in Phase 2:
  "Evaluate architecture for PROJ-{id}. Context:
   - {task description from Jira/GitHub}
   - {affected modules from Phase 1 analysis}
   - {existing patterns found by explore agents}"
```

This ensures sub-agents get both their embedded skills AND task-specific context.

---

## Status Display Format

When `multi-agent status` is called, show:

```
🤖 Multi-Agent Tasks

| ID | Jira | Branch | Phase | Status | Duration |
|----|------|--------|-------|--------|----------|
| #1 | PROJ-12345 | feature/PROJ-12345-... | 3/7 Dev | ⚡ todo-2 in progress | 4m |
| #2 | PROJ-67890 | feature/PROJ-67890-... | 4/7 Review | 🔍 Waiting consensus | 7m |
| #3 | PROJ-11111 | feature/PROJ-11111-... | 7/7 DONE | ✅ Complete | 12m |

💡 kill #2  |  log #1  |  resume #3
```

---

## Help Display

Rendered by the `multi-agent-help` skill (`/multi-agent:help`), which owns
the full text in both languages. It used to be duplicated here in English
only, on a path this skill takes for exactly one input.
