@mmerterden/multi-agent-pipeline 16.28.0 → 16.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 (52) hide show
  1. package/CHANGELOG.md +119 -2
  2. package/README.md +4 -4
  3. package/README.tr.md +3 -3
  4. package/docs/architecture.md +3 -3
  5. package/docs/ecosystem.md +5 -5
  6. package/docs/features.md +14 -0
  7. package/install/claude.mjs +17 -0
  8. package/package.json +1 -1
  9. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +93 -0
  10. package/pipeline/commands/multi-agent/design-check/SKILL.md +6 -5
  11. package/pipeline/commands/multi-agent/doctor/SKILL.md +78 -0
  12. package/pipeline/commands/multi-agent/help/SKILL.md +15 -12
  13. package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -1
  14. package/pipeline/commands/multi-agent/setup/SKILL.md +14 -1
  15. package/pipeline/commands/multi-agent/sync/SKILL.md +12 -9
  16. package/pipeline/commands/multi-agent/update/SKILL.md +12 -0
  17. package/pipeline/lib/_jira-auth.sh +99 -0
  18. package/pipeline/lib/analysis-jira-write.sh +203 -0
  19. package/pipeline/lib/issue-fetcher.sh +4 -4
  20. package/pipeline/multi-agent-refs/analysis/render.md +1 -1
  21. package/pipeline/multi-agent-refs/channels/pr.md +37 -1
  22. package/pipeline/multi-agent-refs/cross-cli-contract.md +3 -3
  23. package/pipeline/multi-agent-refs/features/analysis-jira.md +128 -0
  24. package/pipeline/multi-agent-refs/features/doctor.md +197 -0
  25. package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
  26. package/pipeline/multi-agent-refs/features/visual-evidence.md +103 -20
  27. package/pipeline/multi-agent-refs/phases/phase-0-init.md +38 -7
  28. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +13 -1
  29. package/pipeline/multi-agent-refs/phases/phase-5-test.md +11 -1
  30. package/pipeline/multi-agent-refs/phases/phase-6-commit.md +23 -0
  31. package/pipeline/multi-agent-refs/picker-contract.md +35 -0
  32. package/pipeline/multi-agent-refs/tracker-contract.md +5 -1
  33. package/pipeline/preferences-template.json +1 -1
  34. package/pipeline/schemas/agent-state.schema.json +84 -1
  35. package/pipeline/schemas/analysis-spec.schema.json +336 -95
  36. package/pipeline/schemas/prefs.schema.json +80 -3
  37. package/pipeline/schemas/token-budget.json +10 -10
  38. package/pipeline/scripts/analysis-story-tree.mjs +441 -0
  39. package/pipeline/scripts/capture-evidence.sh +170 -5
  40. package/pipeline/scripts/doctor.mjs +758 -0
  41. package/pipeline/scripts/evidence-gate.mjs +31 -2
  42. package/pipeline/scripts/phase-tracker.sh +97 -17
  43. package/pipeline/scripts/probe-evidence-capability.sh +250 -0
  44. package/pipeline/scripts/run-ui-tests.sh +380 -0
  45. package/pipeline/scripts/scan-agent-config.sh +48 -10
  46. package/pipeline/scripts/skill-siblings.mjs +1 -1
  47. package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +94 -0
  48. package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +79 -0
  49. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +10 -1
  50. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +13 -0
  51. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +9 -6
  52. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +18 -0
package/CHANGELOG.md CHANGED
@@ -14,6 +14,125 @@ Internal file-layout changes that don't affect the slash-command surface are sti
14
14
 
15
15
  ---
16
16
 
17
+ ## [16.30.0] - 2026-09-12
18
+
19
+ The flow video existed as a contract with no recorder, no UI test ever ran, and the PR carried filenames where a reviewer needed a picture. This release makes the evidence real and asks the user what it is worth paying for.
20
+
21
+ ### Added
22
+
23
+ - **`capture-evidence.sh video start|stop`** - the recorder the contract has described since 16.24.0 and nothing implemented. iOS records through `simctl io recordVideo --codec h264` (hevc does not play in the Jira attachment preview or several browsers) and stops on SIGINT, which is the only signal that makes simctl close the container; a TERM leaves an mp4 every player refuses. Android uses `screenrecord` with its own 180s ceiling, which the script clamps to and reports, because one preference honoured on one platform and silently halved on the other is worse than a stated limit. Shell rather than MCP, like the still capture beside it: a host with no toolkit MCP registered still produces evidence.
24
+
25
+ **Both recorders encode on change**, so a flow over a screen that never moved is a valid two-frame file a fraction of a second long. That file is kept - it is not broken - but `stop` says on stderr that nothing moved, and the caller records it as a gap rather than presenting a still as a flow. Nothing asserts the duration against wall clock anywhere, because that check fails a correct capture of a static screen.
26
+
27
+ - **`run-ui-tests.sh`** - finds the repo's own UI test target, picks the tests covering the changed files, and runs them. Exit 3 (target present, nothing matches) and exit 4 (no target) are reasons to fall to the next video tier; only exit 1 is a red test, and the log is the evidence, since a runner that died before reaching the tests also exits non-zero.
28
+
29
+ **The signal is `XCUIApplication`, not a folder named `*UITests`.** In the reference iOS app 477 files sit under such a path and exactly 2 drive the UI; the other 475 are snapshot tests that render a view and compare pixels without launching the app. Recording video around one of those produces a still frame and files it as a flow. And a real app has many candidates - 17 UI test directories there, 8 instrumentation modules in the Android app - so detection reports the whole set and lets the changed files choose. Taking the first off a `find` is a guess wearing a measurement's clothes.
30
+
31
+ Detection reads the filesystem and never calls `xcodebuild -list`, which resolves the SPM graph first and took 72 seconds on the reference workspace. It also found a target the `xcodebuild` path had missed entirely. The scheme, which only a run needs, is resolved in `run` behind a timeout.
32
+
33
+ - **`probe-evidence-capability.sh`** - measures before the user is asked. Offering "unit + UI test with a screen recording" and discovering afterwards that there is no target or no booted device spends the user's answer on something that was never going to happen. Every absent value carries its reason, because `no booted simulator, but one is available to boot` and `no iOS simulator available on this machine` close the same menu row and ask for completely different things. A value it could not measure is `null`, never `false`: with no `adb` on the PATH, "no device attached" is a negative nobody looked for and reads exactly like one somebody checked.
34
+
35
+ - **Test depth is a question** (Phase 0 Step 7.7): unit only, unit plus the UI test with a recording, or unit plus an MCP-driven flow. The options are built from the probe; a closed one keeps its row and states why, and when every option but the first is closed nothing is asked at all and `testDepthSource` records `forced` - a one-option question has no answer in it. Asked at intake rather than in Phase 5 because Phase 5 is absent from four of the eight modes, and a question asked where it cannot be reached is a question nobody answers. `prefs.global.testDepth.default` serves both autopilot entries.
36
+
37
+ - **The tier is re-checked at capture time.** A simulator booted at intake can be gone by the time the build goes green, so Phase 3 re-measures the device row alone and records the transition it came down from.
38
+
39
+ - **`state.visualEvidence.host`, and a PR that shows the picture.** Resolved in Phase 6: Jira takes both stills and video as attachments; with no Jira the stills go to an orphan `evidence/<task-id>` branch and the PR body embeds them. There is no GitHub API that attaches a file to an issue or a PR - the web uploader needs a browser session - so a branch is the only mechanism a script has that neither touches the PR diff nor publishes a release. **A private repo gets a blob permalink rather than an embed**: GitHub renders markdown images through a proxy that has no credentials for a private repo, and a broken image reads as missing evidence. Video stays Jira-only, and on a GitHub run none is recorded at all rather than paying UI-test minutes for a download nobody opens.
40
+
41
+ - **The probe's output contract**, settled by its own review. `--json-out <path>` writes the JSON the state records while stdout stays `KEY=VALUE`, so one run serves both the shell that builds the menu and the state that keeps the measurement; two runs meant two repo scans and two chances to disagree. Every value is **shell-quoted**, because Phase 0 evals that output and the reasons are prose: unquoted, `EVIDENCE_DEVICE_REASON=no booted simulator, but one is available to boot` makes `eval` run `booted` as a command and keep only the first word. That bug is invisible on any machine where the reasons happen to come back empty, which is the machine it was first tested on. `--only device` skips the detection scan for the Phase 3 re-check, and reports tier 1 as **unknown** rather than closed there - a tier that was never probed is not a tier that was ruled out, which is the same rule the probe states about every other field.
42
+
43
+ - **`smoke-ui-test-runner.sh`** (24 assertions) and **`smoke-evidence-probe.sh`** (33). The first caught a real bug while being written: `run` keyed its "no target" exit off the single chosen target, which is deliberately empty while several candidates exist, so "this repo has nothing to record" and "nothing covers what changed" collapsed into one code.
44
+
45
+ ### Fixed
46
+
47
+ - **`smoke-no-mcp-in-dev-phases.sh` failed the pipeline's own prescribed calls.** It rejected every `mcpCalls[]` entry at phase >= 2 regardless of tool, while the rule it enforces (Locked 30, `rules/figma-pipeline.md`, `phase-3-dev.md` item 7) names `mcp__claude_ai_Figma__*` and nothing else, because what it protects is a single source of design truth, not MCP as a transport. `phase-3-dev.md` builds with `ios_xcodebuild` and `phase-5-test.md` audits with the accessibility tools, both at phase >= 2 and neither reading a design; the first person to record telemetry honestly is the one the gate would have failed. Now filtered on the tool name, with three assertions covering both directions.
48
+
49
+ - **The design-check MCP probe had never run.** `design-check/SKILL.md` read `mcpServers[...].args[0]` as a script path and `cd`'d to its parent. The registration is the npx form, so `args[0]` is `-y`, the `cd` failed every time, and a gate that exists to catch a stale tool list was inert. It now launches the server exactly as it is registered, which is what `doctor.mjs` already did.
50
+
51
+ - **`evidence-gate.mjs` never read the `screenshot` field** it has carried in the manual-test document shape since the gate shipped, so a criterion with `"screenshot": null` passed as a verified manual test on a UI change - the one case the picture was added for. New `--require-screenshot` flag, set by Phase 5 when visual evidence is required: a passing criterion must name a file that is actually on disk, since a path pointing nowhere is not evidence.
52
+
53
+ - **The derived `multi-agent-manual-test` skill had no evidence gate at all**, while its command sibling had one. Two copies of a command that disagree about whether a claim needs proof is the drift `skill-siblings.mjs` exists to surface.
54
+
55
+ ### Changed
56
+
57
+ - `features/visual-evidence.md` section 4 rewritten around probe -> question -> run, plus a new host section carrying the two GitHub constraints that shape the PR rendering.
58
+ - Four phase docs gained a step, so `token-budget.json` moves with them: phase 0 (probe + depth question), 3 and 5 (recording), 6 (host resolution). The docs were compressed first and the new numbers are the measured residual, not headroom - these files are read into context on every run, so the budget is the place that cost is recorded rather than absorbed.
59
+ - `smoke-visual-evidence.sh` now records two seconds on a booted device and verifies the h264 file instead of grepping this repo's own markdown for the words "Tier 1" and `agent_run_steps`. A gate that asserts what we print proves nothing. Where no device is present the skip is printed as its own assertion, because `run-smokes.mjs` counts a silent suite as zero assertions and treats it as inert. It also holds the host to its two constraints: the public shape must embed an image, and the private shape must **not** - an embedded raw URL from a private repo renders broken for every reader, which looks like missing evidence rather than a link nobody clicked.
60
+
61
+ ## [16.29.0] - 2026-09-11
62
+
63
+ ### Added
64
+
65
+ - **Two release guards that had stopped working, found by running them.** The sync leak backstop matched `ai-ios(-engineering)?-toolkit:`, so it fired on `ai-ios-toolkit`, the GENERIC marketplace plugin, and aborted the sync over a legitimate reference that had been in main for months. It now names the corporate plugins only, and is asserted in both directions - the corporate name still caught, the generic one ignored.
66
+
67
+ `scan-agent-config.sh` resolved its root as `$0/../..`, which is the repo from a checkout and the HOME directory from an install: from `~/.claude/scripts` it found zero shipped config files, then died on `"${TARGETS[@]}"` under bash 3.2's `set -u` rather than saying so. Same defect class as the one `skill-siblings.mjs` carried, so it gets the same two-candidate resolution, and zero targets is now a HIGH finding instead of a clean bill. The installed layout deliberately excludes `settings.json`: that file is the user's, not something the pipeline ships, and scanning it turned a personal permission choice into a release blocker.
68
+
69
+ - **`/multi-agent:doctor` - would a run work on this machine, and if not, what is the one next step.** Every failure it reports has already reached a user, and each arrived the same way: late, mid-run, after the pickers had been answered. A missing script fails at the call. Malformed preferences fail after Phase 0 has asked five questions. A token in a remote URL does not fail at all - it leaks. The pipeline's own answer to "is this set up correctly" was to start a run and find out.
70
+
71
+ **The exit code is the product**, not the report: 0 healthy, 1 degraded, 2 blocked, 3 usage, **4 indeterminate**. The fourth is the one usually collapsed into 0 or 2, and collapsing it means a resolver that could not look borrows the code for a clean bill. `/multi-agent:sync` stops on 2 and on 4 - syncing a blocked install copies one fault onto five surfaces, and the copies are what people then debug. `/multi-agent:setup` runs it first and last, so "setup complete" has evidence behind it. `/multi-agent:update` runs it after the install, because that is when the layout changed.
72
+
73
+ **BLOCK is a closed definition** - a state where a run will fail or leak, never one where it will merely be worse - and only five checks may produce it. That rule is enforced, not just written: a sixth check returning BLOCK is downgraded and the downgrade is reported, because a rule nothing enforces is a comment.
74
+
75
+ **Absence is printed.** `SKIP` is a fourth severity in the same list at the same position, and the summary always carries its count, so "healthy" and "not looked at" are never the same output. Without `--probe` the liveness check prints `SKIP` and says why; a network check is the user's decision to spend.
76
+
77
+ **It recommends, it never fixes.** A remote carrying a token may be the only credential that repo has, the remote may be a mirror a script depends on verbatim, and doctor can run inside a checkout the user does not own. For an embedded credential the honest step is not "hide it" - a token that reached `.git/config` is already burned - so the step is to revoke it at its host. The line carries the repo, the key, the host, a shape and a length bucket; never the value, and not the prefix either, since `ghp_` plus a length is already a fingerprint and this prints to a shared terminal.
78
+
79
+ Fourteen checks, each with a `### <id>` entry in `features/doctor.md`, and `--list-checks` is asserted equal to that set in **both** directions: a check cannot ship without its entry, and an entry cannot outlive its check.
80
+
81
+ Running it against this machine immediately paid for itself twice - it reported a missing git identity on a machine with two (the key is `identities[]`, a list, because work and personal both exist) and told the user to sync seven commands that are local-only and excluded from sync by design. Both were fixed before the gate was written; a health check that is wrong about a healthy machine is worse than none.
82
+
83
+ - **`/multi-agent:analysis-jira` - an analysis document, read as work.** A finished analysis already contains the breakdown: `BR-<slug>-NN` in the global profile, `FG-NN` in the corporate one, both guaranteed by Locked 31. The tree is derived from those ids, never from a reading of the prose.
84
+
85
+ **Coverage runs in both directions, and the second one is the reason.** Forward catches a dropped requirement. Backward catches an INVENTED story - a node with no requirement behind it - and no forward check can see one. `coverageOf()` is exported and tested against itself: the planner cannot emit an invented id, so a test that fabricates one and re-checks it with its own logic proves nothing about the shipped code.
86
+
87
+ **An unverifiable run is allowed; looking verified is not.** A lite document with no ids cannot be coverage-checked, so the verdict is `unverifiable` - on its own line in the preview, as a separate fourth approval option rather than a reworded `Approve`, in the writer's output, and beside every key in the ledger. Such a document still plans work from its user-story sub-sections; without that the no-atom case produced no stories at all and the `unverifiable` branch was unreachable, a state the code claimed to handle and never could.
88
+
89
+ **Identity is a label, not a title.** Each node carries a hash of the document's `evidence_digest` plus its own source ids, and a second run finds its tree back with one JQL search. Titles were the obvious key and are the wrong one: they get edited, and matching on them breaks exactly when someone improves the wording. The label is server-side, so it survives a new machine, a deleted `~/.claude`, and a second analyst - who is precisely the person positioned to open a duplicate tree.
90
+
91
+ **The write is ledgered.** An `intent` line before each POST, the key after the response; a crash between them leaves an intent with no key, and the next run searches by label before sending anything. The failure that matters is not "the run stopped" but "the run stopped and the retry made a second tree". An existing node is skipped, never updated: Jira has no backup path for fields other than description.
92
+
93
+ The marker gate runs before any network call - zero `EKLENECEK`, zero `TBD`, no open Section 20 row - because a tree built from an open question publishes the gap as work somebody is now assigned.
94
+
95
+ Every site-specific name lives in `prefs.global.issueTree` as a map VALUE, never a schema key: a key is a published literal and this schema ships to everyone. `subtaskRoles` ships empty on purpose, and `subtaskIssueType: null` means discover it from `createmeta` rather than assume a name.
96
+
97
+ - **`lib/_jira-auth.sh`** - one resolution of host and token, and one `-K` curl idiom, for Jira callers to share. The twelve lines existed twice and a third writer was about to make it three; the part most worth getting right (the token never reaching argv, a log, or `ps`) is the part most easily retyped badly. Only the new writer consumes it so far - `jira-publish.sh` and `issue-fetcher.sh` still carry their own resolution, and `issue-fetcher.sh`'s per-account token keys are not modelled here yet, so retrofitting them is a refactor rather than a rename and is not in this release. The leak property is asserted on all three independently, which is the part that has to hold either way.
98
+
99
+ - **`outputs.confluencePages[]`** records each emitted page's identity - `pageId`, `title`, `space`, `channel` - not only its URL. A write-back needs the id, and a `/display/SPACE/Title` URL cannot be parsed for one, so a URL-only record works on some sites and silently does not on others.
100
+
101
+ - **`install/templates/` now reaches the user tree.** It shipped in the tarball and was never copied, so `setup` told people to merge `install/templates/claude-hooks.json` - a path that exists only in a checkout. From an install the instruction named a file the reader did not have, and nothing said so. The doctor's `hook-coverage` check would have been a permanent `SKIP` for the same reason.
102
+
103
+
104
+ ### Fixed
105
+
106
+ - **The widget came back empty of everything except the phase name.** The native tile renders exactly one string, its subject, so whatever a reader wants from the card has to travel in that subject. It carried `Phase 1 Analysis` and nothing else, while the tracker already held the model, the elapsed time, the tokens and the cost for that phase and the fallback card printed all four. `phase-tracker.sh subjects [id]` now renders the same values in the one shape the host accepts, `tiles` builds its `TaskCreate` calls from it, and every boundary hint re-reads it so the numbers advance instead of freezing at creation time. A phase with nothing to report is still just its name - no empty separators.
107
+
108
+ - **The base branch stopped being asked.** Step 3 is marked not skippable and the run skipped it anyway, because the filter left one candidate and "there is only one option" read like a legitimate reason. It is not one: the filter is narrow by design, `Other` is a real choice on every picker, and announcing the pick in prose is the same skip with a sentence in front of it. The rule is now written where pickers are defined rather than only in this step, together with the ordering it depends on - project, then repo, then base branch, because a branch is a property of a repo and an answer given before the repo is settled cannot be told apart from a correct one.
109
+
110
+ Autopilot changed in the same pass. It resolved pickers to a sort order; it now reads `recentBranches[{projectKey}]` first and falls back to the order only when the record is empty, stale or gone from the remote, recording which rule fired. A remembered branch is evidence about this user and this repo; an option order is a guess that happens to be sorted.
111
+
112
+ - **Corporate stories all claimed every requirement.** The planner attributed `FG` ids by section containment, and the corporate template states the mapping in a COLUMN - the functional-requirement table carries a source-UC cell and the traceability matrix repeats the chain - so both of those sections name every use case and every group harvested every atom. Three use cases produced three stories with identical sources, identical titles and, since the label hashes the sources, one identical label: the second run found all three under that label and collapsed the tree onto a single issue, while coverage reported `ok` throughout because a set check cannot see misattribution. Attribution is now read from the row, which is where the template states it, with no column name hardcoded - an atom and a group sharing a table row IS the mapping, in whatever language the site writes its headers. The node's group is also in the identity hash now, because source ids alone are not an identity: two groups may legitimately cite the same atoms.
113
+
114
+ - **A failed story still wrote its sub-tasks.** `create_issue` omits the parent field when the parent key is empty, so when Jira refused a story the writer logged the error, set the exit code, and went on to POST its sub-tasks - which landed as live, parentless issues from a run that had already reported a failure.
115
+
116
+ - **Three gates that could not fail.** `smoke-analysis-jira.sh` asserted no token is interpolated into a curl argument using `[^\n]` inside a bracket expression, which BSD grep reads as the two literal characters `\` and `n`: the class excluded every header name containing an "n", `Authorization` among them, so on macOS the assertion could not fire for any header a caller would really write. The same file printed a green "no caller puts a token on a curl command line" unconditionally after the loop that checks it, so the report could contradict its own red line. And `smoke-doctor.sh` asserted the `MAY_BLOCK` downgrade with a regex over `doctor.mjs`'s own source, which a nearby comment satisfied as well as the code did - the enforcement could be deleted outright with the gate still green. The downgrade is now driven rather than read: the engine is importable behind a main guard and the gate calls `report()` with an out-of-set id and measures what comes back.
117
+
118
+ - **`smoke-command-inventory.sh` aborted instead of reporting.** It parsed the inventory block with a hardcoded `/^analysis, analysis-resolve/` trigger, so a command sorting between those two names left the parse empty - and under `set -e` the empty assignment killed the whole gate before its own "could not parse the inventory block" guard, before the shared-core counterpart check, and before it printed its tally. A publish-blocking gate that exits silently is worse than one that fails. The block is now anchored on the tree's own first and last command, and the parse failure is reported as a finding.
119
+
120
+ - **`doctor`'s script-surface check could not see one directory down.** Its pattern excluded `/` from the path segment, so a reference to `$HOME/.claude/scripts/nested/bar.mjs` was truncated to the directory; as long as that directory existed, a genuinely missing file inside it reported OK - the exact case the check exists to catch.
121
+
122
+ - **Maturity warnings named the jargon instead of the gap.** "Bug icin repro adimlari yok" tells a reader what is missing only if they already know what repro steps are. The two warnings that get read most now say what is absent in plain terms: what was done, what was expected, what happened; and, for acceptance criteria, that nothing says what "done" looks like.
123
+
124
+ - **Stale surface counts.** `docs/architecture.md` and `docs/ecosystem.md` still described Copilot CLI as carrying 51 skills while naming 53 for the other two hosts in the same diagram and the same table row; the installed tree has 53. `skill-siblings.mjs` carried the same stale number in a comment.
125
+
126
+ - **The phase widget disappeared because the task tools now depend on the model.** Claude Code provides `TaskCreate` / `TaskUpdate` by default only on Claude 3.x, Opus 4 through 4.7, Sonnet 4 through 4.6 and Haiku 4.5; on any newer model it leaves them out unless the user opts in, and that default arrived in v2.1.268. This contract named those calls in the very first release and was right for years, so nothing noticed the default change: a run wrote its tracker state correctly, advanced all eight phases, and drew nothing on screen for the whole run.
127
+
128
+ It went unnoticed because the gate asserted the wrong thing. `smoke-tracker-widget.sh` checked that `tiles` PRINTS five `TaskCreate(` lines - a claim about our own output, not about the tool existing - and no run log in the local tree has ever recorded a `TaskCreate` call. That is the same shape as the `tokens` defect described one entry below it in 16.23.0: a gate that lints prose rather than a run.
129
+
130
+ Both `tiles` and every phase boundary now name the fallback on the same output: the bordered card IS the widget there, reprinted inside the reply exactly as on Copilot CLI, and `tiles` renders the card itself so the content is already on screen. They also print the one command that brings the native widget back - `CLAUDE_CODE_ENABLE_TODO_TOOLS=1 claude` - because a user staring at a missing widget needs the command, not the diagnosis. The branch is taken by the agent, which knows its own tool list; a shell script cannot see it.
131
+
132
+ **Naming the fallback was not enough: the card came back in the wrong shape.** With the instruction reading "reprint the card", a run redrew it as two compact lines and dropped exactly what a reader watches for - the per-phase rows, the elapsed time and the running token count. The card was on screen and the information was not, which is the failure the fallback existed to prevent. Both the `tiles` banner and the per-boundary hint now say to run `render` and paste its output VERBATIM inside a code block, and forbid the three ways it was lost: redrawing it, folding phases onto one line, dropping the columns. The gate asserts the wording on both surfaces and asserts `render` itself still emits one line per phase, a token column and a total row.
133
+
134
+ ---
135
+
17
136
  ## [16.28.0] - 2026-09-10
18
137
 
19
138
  ### Added
@@ -70,8 +189,6 @@ Internal file-layout changes that don't affect the slash-command surface are sti
70
189
 
71
190
  - `smoke-install-layout.sh` fixture regenerated: `council-view.mjs` and `features/jira-context.md` moved the installed counts.
72
191
 
73
- - **The phase widget could not render on a Claude Code build without the tile API.** `TaskCreate` and `TaskUpdate` are not in every build, and `phase-tracker.sh` cannot see the model's tool list, so both the bootstrap and every phase boundary named a tool the host does not have and neither named what to do instead. The tracker state was written correctly, every phase advanced, and the screen stayed empty for the whole run. Both outputs now carry the fallback on the same line - the bordered card IS the widget on such a build, reprinted inside the reply at every boundary, which is what Copilot has always done - and `tiles` renders the card itself so the fallback content is already on screen. The branch is taken where the information lives: the model knows which tools it has, the shell does not.
74
-
75
192
  - **The closure gate read the wrong row, and then read it wrongly.** `status: final` decided whether an `AS-NN` was still open by taking the first table row in the document that mentioned the id. The corporate template writes `| **Request** | EKLENECEK (AS-NN) |` in the body, so that row won and a final document shipped with live placeholders. Openness now comes from the Section 20 row only, and from its status CELL located by header - and where there is no status column (the corporate Section 20 has none) an `EKLENECEK` still stamped with the id is itself the signal.
76
193
 
77
194
  The second half of the same line was a substring search: `açıklama` contains `Açık`, so a correctly closed Turkish row reading `Karar verildi / Decided` whose question text said "hata açıklaması" was reported as open and blocked. The status vocabulary is now matched per token across the bilingual `/`, never as a substring. English had the same trap in "reopened".
package/README.md CHANGED
@@ -89,7 +89,7 @@ Depth, autopilot and `--local` are the only knobs on the run itself; everything
89
89
 
90
90
  ## Commands
91
91
 
92
- `/multi-agent` plus 51 sub-commands. `/multi-agent:help` renders the same catalog in your terminal, in your `outputLanguage`.
92
+ `/multi-agent` plus 53 sub-commands. `/multi-agent:help` renders the same catalog in your terminal, in your `outputLanguage`.
93
93
 
94
94
  ### Pipeline entries
95
95
 
@@ -207,13 +207,13 @@ This enables the matching plugin (+ the shared `ai-common` plugin) in the repo's
207
207
 
208
208
  ## Tool support
209
209
 
210
- The pipeline runs natively on **Claude Code**, **Copilot CLI** and **Codex CLI** - all three install from the same `pipeline/` source and get the same 51 commands.
210
+ The pipeline runs natively on **Claude Code**, **Copilot CLI** and **Codex CLI** - all three install from the same `pipeline/` source and get the same 53 commands.
211
211
 
212
212
  | Tool | Flag | What it installs |
213
213
  |---|---|---|
214
214
  | Claude Code | `--claude` (default) | slash commands + skills + agents + three `PreToolUse` hooks (secret scan, agent-guard, read-size gate) |
215
- | Copilot CLI | `--copilot` | instructions + 51 sub-command skills + scripts |
216
- | Codex CLI | `--codex` | one router skill + 51 specs as refs + 8 agent TOML + `AGENTS.md` block + `codex mcp add` |
215
+ | Copilot CLI | `--copilot` | instructions + 53 sub-command skills + scripts |
216
+ | Codex CLI | `--codex` | one router skill + 53 specs as refs + 8 agent TOML + `AGENTS.md` block + `codex mcp add` |
217
217
 
218
218
  Filter skills by stack with `--platform=ios\|android\|all`.
219
219
 
package/README.tr.md CHANGED
@@ -207,13 +207,13 @@ Bu, ilgili plugin'i (+ ortak `ai-common` plugin'ini) repo'nun `.claude/settings.
207
207
 
208
208
  ## Araç desteği
209
209
 
210
- Pipeline **Claude Code**, **Copilot CLI** ve **Codex CLI** üzerinde native çalışır - üçü de aynı `pipeline/` kaynağından kurulur ve aynı 51 komutu alır.
210
+ Pipeline **Claude Code**, **Copilot CLI** ve **Codex CLI** üzerinde native çalışır - üçü de aynı `pipeline/` kaynağından kurulur ve aynı 53 komutu alır.
211
211
 
212
212
  | Araç | Bayrak | Ne kurar |
213
213
  |---|---|---|
214
214
  | Claude Code | `--claude` (varsayılan) | slash komutları + skill'ler + agent'lar + üç `PreToolUse` hook'u (secret scan, agent-guard, okuma-boyutu geçidi) |
215
- | Copilot CLI | `--copilot` | talimatlar + 51 alt-komut skill'i + script'ler |
216
- | Codex CLI | `--codex` | bir router skill + ref olarak 51 spec + 8 agent TOML + `AGENTS.md` bloğu + `codex mcp add` |
215
+ | Copilot CLI | `--copilot` | talimatlar + 53 alt-komut skill'i + script'ler |
216
+ | Codex CLI | `--codex` | bir router skill + ref olarak 53 spec + 8 agent TOML + `AGENTS.md` bloğu + `codex mcp add` |
217
217
 
218
218
  Skill'leri stack'e göre filtrele: `--platform=ios\|android\|all`.
219
219
 
@@ -117,7 +117,7 @@ graph TB
117
117
  end
118
118
 
119
119
  subgraph "Pipeline Specs"
120
- CMD[commands/<br/>51 command files]
120
+ CMD[commands/<br/>53 command files]
121
121
  AGT[agents/<br/>8 agent personas]
122
122
  RUL[rules/<br/>12 domain rules]
123
123
  PHS[multi-agent-refs/phases/<br/>phase specs + contracts]
@@ -169,8 +169,8 @@ revisions of this diagram - Codex CLI and the two independently-shipped repos
169
169
  ```mermaid
170
170
  graph TD
171
171
  CC["Claude Code<br/>(source of truth)"]
172
- COP["Copilot CLI<br/>(instructions + 51 skills)"]
173
- COD["Codex CLI<br/>(1 router skill + 51 refs)"]
172
+ COP["Copilot CLI<br/>(instructions + 53 skills)"]
173
+ COD["Codex CLI<br/>(1 router skill + 53 refs)"]
174
174
  REPO["Pipeline Repo<br/>(npm package)"]
175
175
  WEB["Website"]
176
176
  PLUGREPO["multi-agent-plugins<br/>(5 stack plugins, own repo)"]
package/docs/ecosystem.md CHANGED
@@ -5,7 +5,7 @@ separately, wired together at install time and at run time:
5
5
 
6
6
  | Repo | What it owns | Ships as |
7
7
  |---|---|---|
8
- | **`multi-agent-pipeline`** (this repo) | Orchestration: the 8-phase flow, the 51 slash commands, quality gates, review/triage, cross-CLI parity | npm package (`@mmerterden/multi-agent-pipeline`), installs itself onto Claude Code / Copilot CLI / Codex CLI |
8
+ | **`multi-agent-pipeline`** (this repo) | Orchestration: the 8-phase flow, the 53 slash commands, quality gates, review/triage, cross-CLI parity | npm package (`@mmerterden/multi-agent-pipeline`), installs itself onto Claude Code / Copilot CLI / Codex CLI |
9
9
  | **`multi-agent-plugins`** | Stack knowledge: per-platform component/lifecycle skills (iOS, Android, Frontend, Backend) + shared knowledge | Claude Code marketplace, 5 independently-versioned plugins |
10
10
  | **`multi-agent-toolkit-mcp`** | The pipeline's hands on devices and browsers: 80 MCP tools across 6 categories (simulator/emulator control, accessibility audit, store compliance, web automation, Figma-vs-mock design audit, an agent-DSL batch runner) | npm package, registered as a standard stdio MCP server on every host |
11
11
 
@@ -18,7 +18,7 @@ Either can be swapped or removed without touching the other two's source.
18
18
  graph LR
19
19
  subgraph PIPE ["multi-agent-pipeline (orchestrator)"]
20
20
  direction TB
21
- PHASES["8 phases · 51 commands"]
21
+ PHASES["8 phases · 53 commands"]
22
22
  GATES["deterministic gates + review triage"]
23
23
  end
24
24
 
@@ -64,8 +64,8 @@ only those:
64
64
  graph TD
65
65
  CC["Claude Code<br/>~/.claude/commands/multi-agent/<br/>(source of truth)"]
66
66
 
67
- CC -->|"Step 2: copy + reformat<br/>51 sub-command skills"| COP["Copilot CLI<br/>~/.copilot/skills/"]
68
- CC -->|"Step 2b: transform<br/>(install.js --codex)"| COD["Codex CLI<br/>1 router skill + 51 refs<br/>+ 8 agent TOML"]
67
+ CC -->|"Step 2: copy + reformat<br/>53 sub-command skills"| COP["Copilot CLI<br/>~/.copilot/skills/"]
68
+ CC -->|"Step 2b: transform<br/>(install.js --codex)"| COD["Codex CLI<br/>1 router skill + 53 refs<br/>+ 8 agent TOML"]
69
69
  CC -->|"Step 3: genericize<br/>(strip personal data)"| REPO["multi-agent-pipeline repo<br/>pipeline/"]
70
70
  CC -->|"Step 4: version + feature sync"| WEB["Website<br/>projects.ts / i18n.tsx"]
71
71
 
@@ -153,7 +153,7 @@ measurements behind this table):
153
153
 
154
154
  | | Claude Code | Copilot CLI | Codex CLI |
155
155
  |---|---|---|---|
156
- | **Pipeline commands** | 51 slash-command skills, native | 51 skills, `multi-agent-{cmd}` naming, copied in | 1 router skill (`multi-agent`) + 51 command specs as reference files - Codex silently truncates its skills block past a few dozen entries, so sub-commands are not peer skills here |
156
+ | **Pipeline commands** | 53 slash-command skills, native | 53 skills, `multi-agent-{cmd}` naming, copied in | 1 router skill (`multi-agent`) + 53 command specs as reference files - Codex silently truncates its skills block past a few dozen entries, so sub-commands are not peer skills here |
157
157
  | **Stack plugins** | Marketplace plugin, loaded natively, resolved by `.claude/settings.json` enabled-list | Enabled plugin's authored skills copied flat into `~/.copilot/skills/`; `knowledge/` **not** re-copied (already delivered via `shared/external`) | Copied as reference files under `~/.codex/multi-agent-refs/skills/`, plugin-prefixed on name clash (e.g. `architecture` → `ai-ios-toolkit-architecture`) |
158
158
  | **Component dispatch (Phase 3)** | Marketplace plugin's `create-component`/`create-screen` skill via the Skill tool | No plugin loader - the enabled stack plugin's authored skills (incl. `create-component`) are copied flat into `~/.copilot/skills/` at install time (the old frozen `figma-*` copies are pruned, they were never a fallback) | Not part of the enforced parity axis; classification + state-shape must match, skill *inventory* does not |
159
159
  | **multi-agent-toolkit-mcp** | `claude mcp add multi-agent-toolkit -- npx -y @mmerterden/multi-agent-toolkit-mcp` | `copilot mcp add multi-agent-toolkit -- npx -y @mmerterden/multi-agent-toolkit-mcp` | `codex mcp add multi-agent-toolkit -- npx -y @mmerterden/multi-agent-toolkit-mcp` (skipped with a warning if `codex` isn't on `PATH`) |
package/docs/features.md CHANGED
@@ -271,6 +271,20 @@ Signals + weights: `security_path` ×3, `migration` ×4, `public_api` ×2, `no_t
271
271
 
272
272
  `pipeline/scripts/test-gap-scan.mjs` runs at Phase 5 Step 0. Walks the diff for newly added public symbols and reports those with no paired test. Stack-specific rules ship for iOS, Android, Python, Node.js. iOS Views and Android `@Composable` symbols default to `important`; other public API additions to `suggestion`. Optional gating via `prefs.testGap.blockingThreshold` - when set, the report becomes a Phase 4 rework finding once `important + blocking` count exceeds the threshold.
273
273
 
274
+ ### Visual Evidence (UI changes)
275
+
276
+ A UI change carries its own picture. `state.visualEvidence.required` is decided mechanically from `taskType` plus the changed-file list, never from a reading of the task.
277
+
278
+ **Stills.** The "before" is the reporter's own ticket attachment, harvested in Phase 0; the pipeline never rebuilds the old state to photograph it. The "after" is captured in Phase 3 right after the build goes green, not Phase 5, which autopilot and both local modes drop. `capture-evidence.sh` cleans the status bar and downscales to 1242px so two captures of one screen differ by the change and not by the clock.
279
+
280
+ **The flow video rides on a test run.** `probe-evidence-capability.sh` measures the UI test target, the tests matching this change, the device, the recorder and the MCP registration; Phase 0 Step 7.7 then asks the depth with the options built from that measurement, and a closed option keeps its row and states why. Tier 1 runs the repo's own UI test and records around it, tier 2 drives the flow through `agent_run_steps`, tier 3 records nothing and says so. The tier is re-checked before the recording starts, because a simulator booted at intake can be gone by Phase 3.
281
+
282
+ UI test detection keys on `XCUIApplication` rather than on a folder named `*UITests`: in a real app the overwhelming majority of files under such a path are snapshot tests, which never launch the app and would produce a still frame filed as a flow.
283
+
284
+ **Where it lands.** Jira takes both stills and video as attachments. With no Jira the stills go to an orphan `evidence/<task-id>` branch and the PR body embeds them, or links them with a blob permalink when the repo is private (GitHub's image proxy has no credentials for a private repo, and a broken image reads as missing evidence). Phase 6 blocks when a required artefact is neither published nor explained; the gate is against silence, not against an honest "the ticket carries no image".
285
+
286
+ Toggle via `prefs.global.visualEvidence.enabled` (default ON), `visualEvidence.githubHost`, `visualEvidence.maxAttachmentMb`, `visualEvidence.maxVideoSeconds`, `prefs.global.testDepth.default`.
287
+
274
288
  ### Triage Memory
275
289
 
276
290
  Per-repo append-only JSONL corpus at `~/.claude/memory/multi-agent/<repo-slug>/triage-corpus.jsonl`. Phase 7 ingests every triage output (idempotent), Phase 1 enriches the analysis with similar past tasks, Phase 4 triage attaches prior-art hits to each raw finding with an explicit bias hedge. Token-overlap recall, zero deps, Node-18-compatible. `/multi-agent:search "<text>" --semantic` routes the query to the corpus instead of agent-log grep. Toggle via `prefs.global.priorArtEnrichment.enabled` (default ON).
@@ -80,6 +80,7 @@ export function installClaude(ctx) {
80
80
  const CLAUDE_SCHEMAS = join(home, ".claude", "schemas");
81
81
  const CLAUDE_LIB = join(home, ".claude", "lib");
82
82
  const CLAUDE_MA_REFS = join(home, ".claude", "multi-agent-refs");
83
+ const CLAUDE_TEMPLATES = join(home, ".claude", "templates");
83
84
 
84
85
  // Before laying anything down: drop trees an older install created that no
85
86
  // current installer manages. Wipe-before-copy only protects trees still being
@@ -96,6 +97,7 @@ export function installClaude(ctx) {
96
97
  installRules(pipelineSrc, CLAUDE_RULES, useSymlinks);
97
98
  installSchemas(pipelineSrc, CLAUDE_SCHEMAS, useSymlinks);
98
99
  installLib(pipelineSrc, CLAUDE_LIB, useSymlinks);
100
+ installTemplates(pipelineSrc, CLAUDE_TEMPLATES, useSymlinks);
99
101
  runPreDeployScans(pipelineSrc);
100
102
  installSkills({
101
103
  pipelineSrc,
@@ -324,6 +326,21 @@ function installLib(pipelineSrc, dest, useSymlinks) {
324
326
  console.log(` -> ${countFiles(libSrc)} files copied to ${dest}`);
325
327
  }
326
328
 
329
+ function installTemplates(pipelineSrc, dest, useSymlinks) {
330
+ // The templates shipped in the tarball but never reached the user tree, so
331
+ // `setup` told people to merge `install/templates/claude-hooks.json` - a path
332
+ // that exists only in a checkout. From an install the instruction named a file
333
+ // the reader did not have, and nothing said so.
334
+ console.log(" [Claude Code] Installing templates...");
335
+ const templatesSrc = join(dirname(pipelineSrc), "install", "templates");
336
+ if (!existsSync(templatesSrc)) return;
337
+ // Wipe-before-copy - templates/ is a 100% pipeline-managed tree.
338
+ if (!useSymlinks) ensureRealDir(dest);
339
+ wipeDir(dest);
340
+ copyDir(templatesSrc, dest, { useSymlinks });
341
+ console.log(` -> ${countFiles(templatesSrc)} files copied to ${dest}`);
342
+ }
343
+
327
344
  function runPreDeployScans(pipelineSrc) {
328
345
  // Pre-deploy security scan - warn-only, never halts install on its own.
329
346
  const scanScript = join(pipelineSrc, "scripts", "scan-skills.sh");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "16.28.0",
3
+ "version": "16.30.0",
4
4
  "description": "8-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",
@@ -0,0 +1,93 @@
1
+ ---
2
+ description: "Turn a rendered analysis document into a Jira story tree: derive stories from the document's own rule ids, check coverage both ways, preview every byte, then create only what does not already exist. Use when an analysis is final and the work needs tickets."
3
+ description-tr: "Yazılmış bir analiz dokümanını Jira story ağacına çevirir: story'leri dokümanın kendi kural kimliklerinden türetir, kapsamı iki yönlü kontrol eder, yazılacak her baytı önizler, sonra yalnız var olmayanı açar."
4
+ allowed-tools: Bash, Read, AskUserQuestion
5
+ argument-hint: "[analysis.md] [--project KEY] - optional; with no argument, pick from the documents this run emitted"
6
+ not-for: create-jira, jira
7
+ ---
8
+
9
+ # multi-agent analysis-jira
10
+
11
+ **Input**: $ARGUMENTS
12
+
13
+ Reads an analysis document as a work breakdown and creates the tree. It never
14
+ invents a story: every node comes from an id the document defines.
15
+
16
+ Contract, severities and reasoning:
17
+ `$HOME/.claude/multi-agent-refs/features/analysis-jira.md`.
18
+
19
+ ## Phase 1 - Plan, offline
20
+
21
+ ```bash
22
+ node "$HOME/.claude/scripts/analysis-story-tree.mjs" "<analysis.md>" --json > /tmp/ma-plan.json
23
+ node "$HOME/.claude/scripts/analysis-story-tree.mjs" "<analysis.md>"
24
+ ```
25
+
26
+ Exit 4 means the document still carries an open placeholder. Stop and report it:
27
+ the step is `/multi-agent:analysis-resolve`, and a tree built from an open
28
+ question publishes the gap as work somebody is now assigned.
29
+
30
+ Exit 2 means nothing could be derived. Say so; do not improvise a tree.
31
+
32
+ ## Phase 2 - Preview, in full
33
+
34
+ Show the human-readable output verbatim, in `outputLanguage`. It already carries
35
+ what makes a preview meaningful:
36
+
37
+ - every node, its source ids and its identity label
38
+ - the coverage verdict **on its own line**
39
+ - every field beside the pref key it came from, so a wrong setting shows here
40
+ rather than in Jira afterwards
41
+ - the write count
42
+
43
+ Then the dry run, which is what proves the writer agrees with the plan:
44
+
45
+ ```bash
46
+ bash "$HOME/.claude/lib/analysis-jira-write.sh" \
47
+ --plan /tmp/ma-plan.json --project "<KEY>" --dry-run
48
+ ```
49
+
50
+ ## Phase 3 - Approve
51
+
52
+ One `AskUserQuestion`. When the verdict is `ok` or `incomplete`:
53
+
54
+ - **Create the tree** - proceed
55
+ - **Show a node in full** - print one node's body, ask again
56
+ - **Cancel** - stop, write nothing
57
+
58
+ When the verdict is `unverifiable`, the approve option is **replaced**, never
59
+ reworded:
60
+
61
+ - **Create it, unverified** - the tree will be written and recorded as unchecked
62
+ - **Show a node in full**
63
+ - **Cancel**
64
+
65
+ A run that could not be checked is allowed. One that looks checked when it was
66
+ not is the defect, so the approval has to name it and a plain "Approve" must not
67
+ be reachable.
68
+
69
+ `incomplete` prints its uncovered and invented ids before the question. An
70
+ invented id means the plan cites something the document does not define - treat
71
+ that as a defect in the plan, not a warning to click past.
72
+
73
+ ## Phase 4 - Write
74
+
75
+ ```bash
76
+ bash "$HOME/.claude/lib/analysis-jira-write.sh" \
77
+ --plan /tmp/ma-plan.json --project "<KEY>"
78
+ ```
79
+
80
+ It searches by label first and skips what exists. Re-running is safe and is the
81
+ intended recovery from any failure: the ledger makes a half-written tree
82
+ findable rather than duplicable.
83
+
84
+ **Never pass `--force`-like flags, and never update an existing node.** Jira has
85
+ no backup path for fields other than description.
86
+
87
+ ## Phase 5 - Report
88
+
89
+ Keys created, keys skipped, the coverage verdict, and the ledger path. If the
90
+ verdict was `unverifiable`, say that in the report too - not only at approval
91
+ time, because the report is what gets pasted elsewhere.
92
+
93
+ **Stop. No worktree, no branch, no dev chain.**
@@ -79,23 +79,24 @@ Every Phase 0 / Phase 2 decision uses a native `AskUserQuestion` picker (numbere
79
79
 
80
80
  a. **Session** - `mcp__multi-agent-toolkit__design_scenario_inventory` must be present in the tools available to you, and `mcp__multi-agent-toolkit__design_visual_compare` must accept `live_region`. Absent → the session is bound to a stale process.
81
81
 
82
- b. **Disk** - probe the configured server directly, which reports what a fresh connection WOULD serve:
82
+ b. **Disk** - probe what a fresh connection WOULD serve. Launch it as registered; under npx `args[0]` is `-y`, not a path.
83
83
  ```bash
84
- cd "$(python3 -c "import json,os;print(json.load(open(os.path.expanduser('~/.claude.json')))['mcpServers']['multi-agent-toolkit']['args'][0].rsplit('/',1)[0])")" && \
84
+ MA_MCP_CMD=$(python3 -c "import json,os,shlex;e=json.load(open(os.path.expanduser('~/.claude.json')))['mcpServers']['multi-agent-toolkit'];print(shlex.join([e['command']]+e.get('args',[])))")
85
85
  printf '%s\n%s\n' \
86
86
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
87
87
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
88
- | node index.js 2>/dev/null | python3 -c "
88
+ | eval "$MA_MCP_CMD" 2>/dev/null | python3 -c "
89
89
  import sys,json
90
90
  for l in sys.stdin:
91
91
  try: m=json.loads(l)
92
92
  except: continue
93
- if m.get('id')==1: print('version', m['result']['serverInfo']['version'])
93
+ if m.get('id')==1: print('version',m['result']['serverInfo']['version'])
94
94
  if m.get('id')==2:
95
95
  n=[t['name'] for t in m['result']['tools']]
96
- print('tools', len(n), 'inventory', 'design_scenario_inventory' in n)"
96
+ print('tools',len(n),'inventory','design_scenario_inventory' in n)"
97
97
  ```
98
98
 
99
+
99
100
  Branch on the two results:
100
101
  - **disk OK, session missing the tool** → **HALT** and tell the user to reconnect: `/mcp` → `multi-agent-toolkit` → Reconnect. Note the tool-count tell (a stale build advertises one fewer `design_*` tool). If a reconnect does not take, stale server processes may be lingering - `pgrep -f multi-agent-toolkit-mcp/index.js` with `ps -o lstart=` shows their start times, and any that predate the code's mtime cannot serve the current tools.
101
102
  - **disk itself stale** (older version, or `inventory False`) → **HALT**: the checkout needs updating before a reconnect can help.
@@ -0,0 +1,78 @@
1
+ ---
2
+ description: "Health check for the installed pipeline: layout, preferences, credentials, hooks and host capabilities, each with one actionable step. Exit code is the verdict. Use when a run failed for an environmental reason, before a sync, or after an update."
3
+ description-tr: "Kurulu pipeline için sağlık kontrolü: yerleşim, tercihler, kimlik bilgileri, hook'lar ve host yetenekleri; her biri tek uygulanabilir adımla. Çıkış kodu verdiktin kendisi."
4
+ allowed-tools: Bash, Read
5
+ argument-hint: "[--probe] [--explain] [--json] [--list-checks] - optional; --probe also makes one network request per configured service"
6
+ not-for: scan, setup
7
+ ---
8
+
9
+ # multi-agent doctor
10
+
11
+ **Input**: $ARGUMENTS
12
+
13
+ Answers one question about this machine: **would a run work here, and if not,
14
+ what is the single next step?**
15
+
16
+ Every failure it reports has already reached a user, and each one arrived the
17
+ same way - late, mid-run, after the pickers had been answered. A missing script
18
+ fails at the call. Malformed preferences fail after Phase 0 has asked five
19
+ questions. A token in a remote URL does not fail at all; it leaks.
20
+
21
+ ## Run it
22
+
23
+ ```bash
24
+ node "$HOME/.claude/scripts/doctor.mjs" $ARGUMENTS
25
+ ```
26
+
27
+ Then report the output in `outputLanguage`. Do not re-word the steps: each line
28
+ already carries one imperative step, and paraphrasing is how a step turns into
29
+ advice.
30
+
31
+ **Answer the one check a script cannot.** `task-tools` asks whether THIS session
32
+ carries `TaskCreate` / `TaskUpdate`, and only the agent can see its own tool
33
+ list. Pass what you know:
34
+
35
+ ```bash
36
+ node "$HOME/.claude/scripts/doctor.mjs" --task-tools=yes # they are in your tools
37
+ node "$HOME/.claude/scripts/doctor.mjs" --task-tools=no # they are not
38
+ ```
39
+
40
+ Without the flag that check prints `SKIP`, which is correct - reporting "absent"
41
+ from a script that never looked is the defect this check is about.
42
+
43
+ ## The exit code is the product
44
+
45
+ | Code | Meaning |
46
+ |---|---|
47
+ | 0 | healthy |
48
+ | 1 | degraded - at least one WARN |
49
+ | 2 | blocked - a run will fail or leak |
50
+ | 3 | usage error |
51
+ | 4 | indeterminate - the layout did not resolve, so nothing was checked |
52
+
53
+ 4 matters as much as 2. Without it, "I could not look" borrows the code for
54
+ "I looked and it is fine".
55
+
56
+ ## What it does not do
57
+
58
+ It recommends; it never fixes. It does not rewrite a remote URL, edit
59
+ `settings.json`, or touch a credential. A remote carrying a token may be the only
60
+ credential that repo has, the remote may be a mirror a script depends on
61
+ verbatim, and this can run inside a checkout the user does not own.
62
+
63
+ For an embedded credential the honest step is **not** "hide it". A token that
64
+ reached `.git/config` is already burned - it is in the shell history and readable
65
+ by anything that can read the working tree. The step is to revoke it at its host.
66
+
67
+ ## Flags
68
+
69
+ | Flag | Effect |
70
+ |---|---|
71
+ | `--probe` | also make one authenticated request per configured service, and start the MCP server to count its tools. Off by default: a network check is the user's decision to spend. |
72
+ | `--explain` | print the detail behind a finding (which scripts, which repos) |
73
+ | `--json` | the same verdict in machine form, same exit code |
74
+ | `--list-checks` | the check ids, one per line |
75
+ | `--task-tools=yes\|no` | answer the check only the caller can see |
76
+
77
+ Every check, its severity and its reasoning:
78
+ `$HOME/.claude/multi-agent-refs/features/doctor.md`.
@@ -119,6 +119,7 @@ Post-Hoc & Side-Channel:
119
119
  /multi-agent:analysis ["analysis-name"] Feature-spec analysis (Figma + Swagger + Confluence + repos). Asks the standard first: global (23-section dev handoff) or corporate (IG→UC→FG requirements doc). Stack optional; References built from the evidence record
120
120
  /multi-agent:analysis-resolve [doc] Resolve Section 20 open questions of an analysis doc, one at a time with source-labeled candidates
121
121
  /multi-agent:review-analysis [doc] Review a written analysis; findings cite the rule they break
122
+ /multi-agent:analysis-jira [doc] A final analysis -> a Jira story tree; coverage two-way, existing nodes skipped
122
123
  /multi-agent:complaint-analysis ["run-name"] [--file path] Customer-complaint triage: Graylog evidence per trx/conv id + read-only repo correlation → client/bff root cause + fix plan + dev prompt, or core routing recommendation
123
124
  /multi-agent:build-optimize iOS-only Xcode build perf wrapper → benchmark + analyze + recommend-first .build-benchmark/optimization-plan.md
124
125
  /multi-agent:create-jira ["desc"] [figma-url] [swagger-url] Create a Jira Task/Bug/Story matching team conventions (asks type + mining + active sprint + auto-sizing sections + preview & approval)
@@ -126,6 +127,7 @@ Post-Hoc & Side-Channel:
126
127
  /multi-agent:graph Build and query the repo code graph (symbols, imports, references), LLM-free
127
128
  /multi-agent:search Cross-task log search with smart ranking; --semantic queries triage corpus
128
129
  /multi-agent:scan Skill security scan against tiered pattern catalog
130
+ /multi-agent:doctor Would a run work here? Layout, prefs, credentials, hooks; exit code is the verdict
129
131
  /multi-agent:refactor Best practices + bug hunt + upstream drift + toolkit MCP research -> one plan, approval, dev + sync
130
132
  /multi-agent:refactor backlog Decide the friction already recorded about the pipeline itself, nothing re-derived
131
133
  /multi-agent:store-ready [repo] [--archive=|--ipa=|--aab=|--apk=] [--skip-sweep] Pre-submission store readiness, iOS + Android, local-only: three symmetric gates per platform plus the running-app sweep. A skipped gate is never a pass. Validates only, never uploads.
@@ -241,24 +243,25 @@ Key Features:
241
243
  Multi-Platform iOS, Android, Backend, Web - auto-detected
242
244
  Build Queue xcodebuild/Gradle serialized with lock file - parallel safe
243
245
  Stack Aware Auto-detects iOS/Android/Python/Node/Go/Docker, uses the enabled stack plugin's skills
244
- Det. Gates Build + lint + test + secret scan BEFORE AI review
245
- Multi-Repo Per-repo worktrees, per-repo identity, integration build before commit
246
- Identity Routing Git identity auto-picked from repo origin URL (corporate vs personal)
247
- Issue Safety Never auto-closes issues (4 approvals required, GitHub + Jira)
248
- Store Compliance /multi-agent:test "store-ready" runs 18-rule iOS audit (ITMS / Privacy Manifest /
249
- code signing / debug-tool leak / IPv6 / SDK list / etc.) and 21-rule Android audit
246
+ Det. Gates Build + lint + test + secret scan before AI review
247
+ Multi-Repo Per-repo worktrees + identity, integration build before commit
248
+ Identity Routing Git identity picked from the repo origin URL (corporate vs personal)
249
+ Issue Safety Never auto-closes issues (4 approvals, GitHub + Jira)
250
+ Store Compliance /multi-agent:test "store-ready" - 18-rule iOS audit (ITMS, Privacy Manifest,
251
+ signing, debug leaks, IPv6, SDK list) + 21-rule Android audit
250
252
  Bilingual EN + TR - outputLanguage toggles assistant explanations; promptLanguage is locked en
251
253
 
252
254
  Quality & Telemetry (advisory, on by default - flip prefs.global.* to disable):
253
255
 
254
256
  Diff Risk Score Phase 4 Step 1.75 ranks files before reviewer dispatch (security paths,
255
- schema migrations, no-test-change, complexity delta) - heuristic, sub-second
257
+ migrations, no-test-change, complexity) - heuristic, sub-second
256
258
  Test Gap Report Phase 5 Step 0 surfaces public symbols added in this branch with no paired test
257
- Cost Breakdown Phase 7 appends per-phase tokens (in/out) + estimated USD to agent-log.md
258
- Triage Memory Phase 7 ingests accepted/deferred/rejected findings into a per-repo corpus
259
- Prior-Art Lookup Phase 1 + Phase 4 query the corpus for similar past findings, inject as context
260
- Per-Persona Reviewer/agent dispatch reads `preferredModel` from persona file; per-call override
261
- via PHASE_MODEL_OVERRIDE; ladder fable -> opus -> sonnet -> haiku
259
+ Visual Evidence before/after stills + flow video on UI changes; Step 7.7 asks the depth
260
+ Cost Breakdown Phase 7 appends per-phase tokens + estimated USD to agent-log.md
261
+ Triage Memory Phase 7 ingests accepted/deferred/rejected findings into a repo corpus
262
+ Prior-Art Lookup Phase 1 + Phase 4 query the corpus for similar findings, inject as context
263
+ Per-Persona Dispatch reads `preferredModel` from the persona file; override per call via
264
+ PHASE_MODEL_OVERRIDE; ladder fable -> opus -> sonnet -> haiku
262
265
 
263
266
  ------------------------------------------------------------
264
267
 
@@ -51,5 +51,5 @@ Lets you switch to the task branch for manual testing in Xcode before the PR is
51
51
  ```json
52
52
  {"criteria":[{"spec":"<quote>","source":"analysis 15.2 | plan task 3 | user","observed":"<what was seen>","verdict":"pass|fail|not-tested","reason":"<required when not-tested>","screenshot":"<path or null>"}],"verdict":"passed|failed"}
53
53
  ```
54
- then run `node $HOME/.claude/scripts/evidence-gate.mjs --claim manual --status passed --evidence "$WORKTREE/.pipeline/manual-test.json"`. Exit 1 means the "ok" is not accepted: name the criterion that is missing evidence and wait for the next reply. Exit 0 → `phase-tracker.sh update 5 completed` + `phase-tracker.sh meta 5 Result "local test passed (user)"`, recreate the worktree, continue to Phase 6. Full contract: `$HOME/.claude/multi-agent-refs/phases/phase-5-test.md` step 5.
54
+ then run `node $HOME/.claude/scripts/evidence-gate.mjs --claim manual --status passed --evidence "$WORKTREE/.pipeline/manual-test.json"`, adding `--require-screenshot` when `state.visualEvidence.required` is true (a passing criterion then has to name a screenshot that is actually on disk). Exit 1 means the "ok" is not accepted: name the criterion that is missing evidence and wait for the next reply. Exit 0 → `phase-tracker.sh update 5 completed` + `phase-tracker.sh meta 5 Result "local test passed (user)"`, recreate the worktree, continue to Phase 6. Full contract: `$HOME/.claude/multi-agent-refs/phases/phase-5-test.md` step 5.
55
55
  - **Fix needed** → `phase-tracker.sh now 5 "applying fix: <summary>"`, recreate the worktree, apply the fix