@mmerterden/multi-agent-pipeline 20.24.0 → 20.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/docs/facts.json +3 -3
- package/docs/features.md +9 -4
- package/install/catalog-history.json +1 -1
- package/install/templates/claude-hooks.json +1 -1
- package/install/templates/codex-hooks.json +18 -0
- package/manifest.json +71 -68
- package/package.json +1 -1
- package/pipeline/agents/task-clarifier.md +1 -1
- package/pipeline/commands/multi-agent/model/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/postmortem/SKILL.md +18 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/route-on/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +7 -5
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +2 -3
- package/pipeline/contract/fixtures/runs-failed.json +1 -1
- package/pipeline/contract/fixtures/runs-old-schema.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
- package/pipeline/contract/fixtures/runs-running.json +1 -1
- package/pipeline/lib/credential-inventory.sh +5 -5
- package/pipeline/lib/fetch-crashlytics.sh +6 -8
- package/pipeline/lib/model-rung.sh +1 -1
- package/pipeline/lib/plan-todos.sh +21 -4
- package/pipeline/lib/post-pr-review.sh +4 -6
- package/pipeline/lib/route-state.sh +1 -1
- package/pipeline/lib/shadow-git.sh +4 -5
- package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -5
- package/pipeline/multi-agent-refs/features/cost-analysis.md +4 -0
- package/pipeline/multi-agent-refs/features/model-fallback.md +17 -12
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +5 -5
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/tracker-contract.md +6 -6
- package/pipeline/schemas/plan-todos.schema.json +4 -4
- package/pipeline/schemas/prefs.schema.json +4 -4
- package/pipeline/scripts/_code-graph.mjs +2 -2
- package/pipeline/scripts/_transcript-hosts.mjs +406 -0
- package/pipeline/scripts/build-stack-plugins.mjs +3 -3
- package/pipeline/scripts/capture-flush.sh +7 -7
- package/pipeline/scripts/code-graph-rules/android.json +1 -1
- package/pipeline/scripts/cost-analyze.mjs +26 -19
- package/pipeline/scripts/cost-table.json +35 -19
- package/pipeline/scripts/edit-syntax-gate.mjs +151 -29
- package/pipeline/scripts/edit-syntax-gate.sh +9 -6
- package/pipeline/scripts/gc-abandoned.sh +2 -2
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/git-path.mjs +1 -2
- package/pipeline/scripts/host-hooks.mjs +265 -0
- package/pipeline/scripts/jira-attach.sh +1 -1
- package/pipeline/scripts/keychain.py +3 -3
- package/pipeline/scripts/output-quality-check.sh +1 -1
- package/pipeline/scripts/phase-tracker.sh +5 -6
- package/pipeline/scripts/phase0-exit-gate.mjs +3 -3
- package/pipeline/scripts/pre-push-check.sh +3 -6
- package/pipeline/scripts/transcript-index.mjs +423 -242
- package/pipeline/scripts/uninstall.mjs +90 -4
- package/pipeline/scripts/update-issue-progress.sh +4 -6
- package/pipeline/scripts/usage-report.mjs +2 -2
- package/pipeline/skills/.skill-manifest.json +8 -8
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +6 -6
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-postmortem/SKILL.md +10 -7
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +5 -5
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -3
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
XCODE_SKILLS_MANIFEST,
|
|
61
61
|
} from "../lib/xcode-plugin.mjs";
|
|
62
62
|
import { createInterface } from "readline";
|
|
63
|
+
import { removeHooks, templateCommands } from "./host-hooks.mjs";
|
|
63
64
|
|
|
64
65
|
const HOME = process.env.HOME;
|
|
65
66
|
|
|
@@ -104,6 +105,7 @@ export const PIPELINE_RETIRED_SKILL_DIRS = ["valven-rules"];
|
|
|
104
105
|
*/
|
|
105
106
|
export const PIPELINE_TEMPLATE_FILES = [
|
|
106
107
|
"claude-hooks.json",
|
|
108
|
+
"codex-hooks.json",
|
|
107
109
|
"codex-instructions.md",
|
|
108
110
|
"copilot-instructions.md",
|
|
109
111
|
"multi-agent-autopilot-awake.plist.template",
|
|
@@ -781,11 +783,14 @@ function stripManagedBlock(filePath, { hostFile = false } = {}) {
|
|
|
781
783
|
}
|
|
782
784
|
|
|
783
785
|
/**
|
|
784
|
-
* Remove the pipeline-added hooks + env from settings.json
|
|
785
|
-
*
|
|
786
|
+
* Remove the pipeline-added hooks + env from settings.json: the gates
|
|
787
|
+
* install/claude.mjs registers, and every handler whose full command is one
|
|
788
|
+
* claude-hooks.json registers (setup Step 8 merges those). Other hooks the
|
|
789
|
+
* user added stay intact, including one inside a group the pipeline uses.
|
|
786
790
|
* @param {string} settingsPath
|
|
791
|
+
* @param {Set<string>|null} templateCmds claude-hooks.json's commands
|
|
787
792
|
*/
|
|
788
|
-
function cleanClaudeSettings(settingsPath) {
|
|
793
|
+
function cleanClaudeSettings(settingsPath, templateCmds) {
|
|
789
794
|
if (!existsSync(settingsPath)) return;
|
|
790
795
|
let settings;
|
|
791
796
|
try {
|
|
@@ -831,6 +836,20 @@ function cleanClaudeSettings(settingsPath) {
|
|
|
831
836
|
if (settings.hooks && Object.keys(settings.hooks).length === 0) delete settings.hooks;
|
|
832
837
|
}
|
|
833
838
|
|
|
839
|
+
if (templateCmds && settings.hooks) {
|
|
840
|
+
try {
|
|
841
|
+
const { doc, removed } = removeHooks(settings, templateCmds);
|
|
842
|
+
if (removed) {
|
|
843
|
+
settings = doc;
|
|
844
|
+
touched = true;
|
|
845
|
+
}
|
|
846
|
+
} catch {
|
|
847
|
+
console.log(
|
|
848
|
+
` skipped the hook template pass (hooks not in the expected shape): ${settingsPath}`,
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
834
853
|
if (touched) {
|
|
835
854
|
if (dryRun) {
|
|
836
855
|
report("would update", settingsPath);
|
|
@@ -841,6 +860,63 @@ function cleanClaudeSettings(settingsPath) {
|
|
|
841
860
|
}
|
|
842
861
|
}
|
|
843
862
|
|
|
863
|
+
/**
|
|
864
|
+
* The commands a shipped hook template registers, read from the first copy
|
|
865
|
+
* found: the host's installed templates, the package this script runs from,
|
|
866
|
+
* or the templates directory beside an installed scripts/. Null when none is
|
|
867
|
+
* readable.
|
|
868
|
+
* @param {string} name template file name
|
|
869
|
+
* @param {string[]} dirs host template directories, searched first
|
|
870
|
+
*/
|
|
871
|
+
export function shippedHookCommands(name, dirs = []) {
|
|
872
|
+
const here = import.meta.dirname;
|
|
873
|
+
const candidates = [
|
|
874
|
+
...dirs.map((d) => join(d, name)),
|
|
875
|
+
join(here, "..", "..", "install", "templates", name),
|
|
876
|
+
join(here, "..", "templates", name),
|
|
877
|
+
];
|
|
878
|
+
for (const path of candidates) {
|
|
879
|
+
if (!existsSync(path)) continue;
|
|
880
|
+
try {
|
|
881
|
+
const commands = templateCommands(JSON.parse(readFileSync(path, "utf-8")), HOME);
|
|
882
|
+
if (commands.size) return commands;
|
|
883
|
+
} catch {
|
|
884
|
+
// An unreadable copy: try the next one.
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Take the pipeline's hook handlers out of Codex's hooks.json (host-hooks.mjs
|
|
892
|
+
* merged them in), matched by the template's full commands; the user's own
|
|
893
|
+
* hooks stay. Without a template the file is left as it is.
|
|
894
|
+
* @param {string} hooksPath
|
|
895
|
+
* @param {Set<string>|null} commands
|
|
896
|
+
*/
|
|
897
|
+
function cleanCodexHooks(hooksPath, commands) {
|
|
898
|
+
if (!existsSync(hooksPath)) return;
|
|
899
|
+
if (!commands) {
|
|
900
|
+
console.log(` skipped (no codex-hooks.json template to match against): ${hooksPath}`);
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
let doc;
|
|
904
|
+
try {
|
|
905
|
+
doc = JSON.parse(readFileSync(hooksPath, "utf-8"));
|
|
906
|
+
} catch {
|
|
907
|
+
console.log(` skipped (unparseable): ${hooksPath}`);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
const { doc: cleaned, removed } = removeHooks(doc, commands);
|
|
911
|
+
if (!removed) return;
|
|
912
|
+
if (dryRun) {
|
|
913
|
+
report("would update", hooksPath);
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
atomicWrite(hooksPath, JSON.stringify(cleaned, null, 2) + "\n");
|
|
917
|
+
console.log(` removed ${removed} pipeline hook(s) from: ${hooksPath}`);
|
|
918
|
+
}
|
|
919
|
+
|
|
844
920
|
async function confirm(question) {
|
|
845
921
|
if (skipPrompt || dryRun) return true;
|
|
846
922
|
return new Promise((resolve) => {
|
|
@@ -910,6 +986,9 @@ export async function main() {
|
|
|
910
986
|
console.log(" [Claude Code] Removing...");
|
|
911
987
|
deregisterClaudeMcpServer();
|
|
912
988
|
const CLAUDE = join(HOME, ".claude");
|
|
989
|
+
const claudeHookCommands = shippedHookCommands("claude-hooks.json", [
|
|
990
|
+
join(CLAUDE, "templates"),
|
|
991
|
+
]);
|
|
913
992
|
unlinkClaudeXcodePlugin(HOME);
|
|
914
993
|
rmCommandsPreservingLocalOnly(join(CLAUDE, "commands", "multi-agent"));
|
|
915
994
|
rmIfExists(join(CLAUDE, "scripts"));
|
|
@@ -961,7 +1040,7 @@ export async function main() {
|
|
|
961
1040
|
// Agent definitions are FILES; remove only the pipeline-shipped names so
|
|
962
1041
|
// user-authored agents survive.
|
|
963
1042
|
rmMatchingFiles(join(CLAUDE, "agents"), (name) => PIPELINE_AGENT_FILES.includes(name));
|
|
964
|
-
cleanClaudeSettings(join(CLAUDE, "settings.json"));
|
|
1043
|
+
cleanClaudeSettings(join(CLAUDE, "settings.json"), claudeHookCommands);
|
|
965
1044
|
}
|
|
966
1045
|
|
|
967
1046
|
if (forCopilot && HOME) {
|
|
@@ -1071,6 +1150,13 @@ export async function main() {
|
|
|
1071
1150
|
console.log(" [Codex CLI] Removing from ~/.codex...");
|
|
1072
1151
|
const CODEX = join(HOME, ".codex");
|
|
1073
1152
|
|
|
1153
|
+
// Codex reads hooks from $CODEX_HOME when set, so host-hooks.mjs may have
|
|
1154
|
+
// registered there as well as in ~/.codex.
|
|
1155
|
+
const codexHooks = shippedHookCommands("codex-hooks.json", [join(CODEX, "templates")]);
|
|
1156
|
+
const hooksFiles = new Set([join(CODEX, "hooks.json")]);
|
|
1157
|
+
if (process.env.CODEX_HOME) hooksFiles.add(join(process.env.CODEX_HOME, "hooks.json"));
|
|
1158
|
+
for (const hooksFile of hooksFiles) cleanCodexHooks(hooksFile, codexHooks);
|
|
1159
|
+
|
|
1074
1160
|
// Wholly pipeline-owned trees.
|
|
1075
1161
|
rmIfExists(join(CODEX, "multi-agent-refs"));
|
|
1076
1162
|
rmIfExists(join(CODEX, "scripts"));
|
|
@@ -135,12 +135,10 @@ if [ "$TASK_ID" = "--rewrite" ]; then
|
|
|
135
135
|
fi
|
|
136
136
|
|
|
137
137
|
# Resolve agent-state.json. multi-repo-pipeline.sh writes it under a
|
|
138
|
-
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/)
|
|
139
|
-
# -
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
# write flat, so on a real machine the majority of runs resolved to nothing and
|
|
143
|
-
# this script reported "no agent-state.json" for a run whose state existed.
|
|
138
|
+
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/),
|
|
139
|
+
# while phase-tracker.sh and most Phase 0 paths write it flat; no writer uses
|
|
140
|
+
# ~/.claude/projects/*/state/. ma_resolve_run_file checks both layouts, so a
|
|
141
|
+
# run whose state exists is always found.
|
|
144
142
|
AGENT_STATE="$(ma_resolve_run_file "$TASK_ID" agent-state.json 2>/dev/null || true)"
|
|
145
143
|
|
|
146
144
|
if [ -z "$AGENT_STATE" ]; then
|
|
@@ -235,8 +235,8 @@ function invokedCalls(state, { publicPlugins, manifestPath } = {}) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
// The package declares `os: ["darwin"]` and every entry point refuses a
|
|
238
|
-
// non-darwin host, so
|
|
239
|
-
// function and the field
|
|
238
|
+
// non-darwin host, so no other platform gets a branch of its own. The
|
|
239
|
+
// function and the field exist because the panel groups by `os` and a row with the key
|
|
240
240
|
// missing reads as "unknown host" rather than "macOS".
|
|
241
241
|
function detectOs() {
|
|
242
242
|
return platform() === "darwin" ? "macos" : platform();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-14T13:33:28Z",
|
|
4
4
|
"skillCount": 229,
|
|
5
5
|
"entries": [
|
|
6
6
|
{
|
|
@@ -125,11 +125,11 @@
|
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"path": "shared/core/multi-agent-model/SKILL.md",
|
|
128
|
-
"sha256": "
|
|
128
|
+
"sha256": "57ba710657d74176b0f19d4a97d3183df1f7b0c056eb1eef2792308914be836c"
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
"path": "shared/core/multi-agent-postmortem/SKILL.md",
|
|
132
|
-
"sha256": "
|
|
132
|
+
"sha256": "41edd907cbaae1523eab1cd716390c9e9cd889574141cb88c33966e221b0987d"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"path": "shared/core/multi-agent-prune-logs/SKILL.md",
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"path": "shared/core/multi-agent-review/SKILL.md",
|
|
172
|
-
"sha256": "
|
|
172
|
+
"sha256": "e3a673e13b9b7a227334afe79e20e2be837c0900e16e88003b4692a1d74dea41"
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
175
|
"path": "shared/core/multi-agent-route-off/SKILL.md",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
179
|
"path": "shared/core/multi-agent-route-on/SKILL.md",
|
|
180
|
-
"sha256": "
|
|
180
|
+
"sha256": "0435bb53d8c55d20cfdb1bd5ddbd0544bace68041ab45929904d1a38d2f608c6"
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
183
|
"path": "shared/core/multi-agent-route-status/SKILL.md",
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
},
|
|
218
218
|
{
|
|
219
219
|
"path": "shared/core/multi-agent-setup/SKILL.md",
|
|
220
|
-
"sha256": "
|
|
220
|
+
"sha256": "28e80bacb521b3c41aac18859ca3921735970b0bf27f064bfc2b496db9f85016"
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
223
|
"path": "shared/core/multi-agent-stack/SKILL.md",
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
"path": "shared/core/multi-agent-testflight-validation/SKILL.md",
|
|
264
|
-
"sha256": "
|
|
264
|
+
"sha256": "b6c360c330ef0094cd7e7d9624e89624446b048951e43a180766bbe67d1b725c"
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"path": "shared/core/multi-agent-uninstall/SKILL.md",
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
},
|
|
274
274
|
{
|
|
275
275
|
"path": "shared/core/multi-agent/SKILL.md",
|
|
276
|
-
"sha256": "
|
|
276
|
+
"sha256": "b2435de3df518efb8ddf9ac89b3089449e46bf55f29220e07a3aa95dfc8cd083"
|
|
277
277
|
},
|
|
278
278
|
{
|
|
279
279
|
"path": "shared/external/accessibility-compliance-accessibility-audit/SKILL.md",
|
|
@@ -206,12 +206,12 @@ Per-project input parsing (my-ios-app / my-figma-app / generic), worktree creati
|
|
|
206
206
|
### Phase 1: Plan
|
|
207
207
|
Two halves, one phase, one approval gate.
|
|
208
208
|
|
|
209
|
-
**1a - Analysis** (claude-sonnet-5, `explorer` persona)
|
|
209
|
+
**1a - Analysis** (claude-sonnet-5-5, `explorer` persona)
|
|
210
210
|
1. Launch **explore agents** (parallel) to scan the codebase: related files, existing patterns and conventions, potential impact areas
|
|
211
211
|
2. Summarize findings
|
|
212
212
|
3. Log: `📊 Phase 1: Plan (analysis) - {N} files identified, {summary}`
|
|
213
213
|
|
|
214
|
-
**1b - Planning** (claude-fable-5)
|
|
214
|
+
**1b - Planning** (claude-fable-5-1)
|
|
215
215
|
1. Create task breakdown → todos with dependencies
|
|
216
216
|
2. Launch **ios-architect** agent for architecture review (if structural changes)
|
|
217
217
|
3. Determine development approach per todo (new file, modify, refactor)
|
|
@@ -221,7 +221,7 @@ Two halves, one phase, one approval gate.
|
|
|
221
221
|
- **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`.
|
|
222
222
|
- Persist `clarificationRounds`, `clarificationQuestions`, `clarificationAnswers`, `planIterations`, `planApprovedAt`, `planEditRequests` to `state.phases["1"]`.
|
|
223
223
|
|
|
224
|
-
### Phase 2: Dev (claude-sonnet-5)
|
|
224
|
+
### Phase 2: Dev (claude-sonnet-5-5)
|
|
225
225
|
For each todo (respecting dependency order):
|
|
226
226
|
1. Update todo status: `in_progress`
|
|
227
227
|
2. **TDD cycle**: write failing test → verify RED; write minimal code → verify GREEN; refactor if needed
|
|
@@ -233,9 +233,9 @@ For each todo (respecting dependency order):
|
|
|
233
233
|
### Phase 3: Review (parallel + triage)
|
|
234
234
|
0. **Diff Risk Scoring (advisory)** - 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).
|
|
235
235
|
1. Launch **code-reviewer** agents in parallel. Reviewer set depends on which CLI is hosting the pipeline:
|
|
236
|
-
- **Claude Code** (3 reviewers): `claude-fable-5` (deep security + architecture) + `claude-opus-5` (edge cases, different perspective) + `claude-sonnet-5` (quality + correctness)
|
|
237
|
-
- **Copilot CLI** (3 reviewers): `gpt-5.4` (edge cases, different perspective) + `claude-opus-
|
|
238
|
-
- Triage: single top-tier pass over merged findings (`claude-fable-5` on Claude Code, `claude-opus-
|
|
236
|
+
- **Claude Code** (3 reviewers): `claude-fable-5-1` (deep security + architecture) + `claude-opus-5-5` (edge cases, different perspective) + `claude-sonnet-5-5` (quality + correctness)
|
|
237
|
+
- **Copilot CLI** (3 reviewers): `gpt-5.4` (edge cases, different perspective) + `claude-opus-4.7` + `claude-sonnet-4.6` (Fable is not offered on Copilot CLI)
|
|
238
|
+
- Triage: single top-tier pass over merged findings (`claude-fable-5-1` on Claude Code, `claude-opus-4.7` on Copilot CLI)
|
|
239
239
|
2. Collect findings, classify:
|
|
240
240
|
- 🔴 **Blocking** → must fix → back to Phase 2 (max 3 iterations)
|
|
241
241
|
- 🟡 **Important** → fix and re-review
|
|
@@ -44,8 +44,8 @@ because it does not mean the same thing on all three:
|
|
|
44
44
|
|
|
45
45
|
| Host | What `off` does | Why |
|
|
46
46
|
|---|---|---|
|
|
47
|
-
| Claude Code | every `preferredModel: fable` persona (architects, reviewer 1, triage) starts on `opus` | the only host where the rung is Fable 5 |
|
|
48
|
-
| Copilot CLI | nothing | Fable
|
|
47
|
+
| Claude Code | every `preferredModel: fable` persona (architects, reviewer 1, triage) starts on `opus` | the only host where the rung is Fable 5.1 |
|
|
48
|
+
| Copilot CLI | nothing | Fable is not offered there; its personas never sat on this rung |
|
|
49
49
|
| Codex CLI | nothing, deliberately | the `fable` rung there means `gpt-5.6 @ xhigh`, a different model on a different account - switching it from a knob named after an Anthropic model would surprise a Codex user |
|
|
50
50
|
|
|
51
51
|
So on two of the three hosts this command is a **status report**, not a switch,
|
|
@@ -18,23 +18,26 @@ deterministic indexer; the model only interprets it.
|
|
|
18
18
|
**Read-only.** Nothing is sent anywhere: no issue comment, no PR, no channel.
|
|
19
19
|
The one write is the report itself, saved under the run's log directory.
|
|
20
20
|
|
|
21
|
-
The indexer reads Claude Code session files (`~/.claude/projects/<dir>/<session>.jsonl`)
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
The indexer reads Claude Code session files (`~/.claude/projects/<dir>/<session>.jsonl`),
|
|
22
|
+
Copilot CLI session logs (`~/.copilot/session-state/<session>/events.jsonl`) and
|
|
23
|
+
Codex rollouts (`~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`), detecting the
|
|
24
|
+
format per file. Copilot CLI reports tokens per session, so its totals come from
|
|
25
|
+
the shutdown record. When a run id finds nothing (exit 3), say so and ask for a
|
|
26
|
+
transcript path rather than reporting an empty run.
|
|
24
27
|
|
|
25
28
|
## Steps
|
|
26
29
|
|
|
27
30
|
1. **Resolve the target.**
|
|
28
|
-
- A path ending in `.jsonl
|
|
29
|
-
included). There is no run directory, so nothing is saved unless the user
|
|
31
|
+
- A path ending in `.jsonl` (any of the three hosts): index that file
|
|
32
|
+
(Claude Code subagent files beside it are included). There is no run directory, so nothing is saved unless the user
|
|
30
33
|
names one.
|
|
31
34
|
- A task id or `#N`: locate the run and its transcripts:
|
|
32
35
|
```bash
|
|
33
36
|
node "$HOME/.claude/scripts/transcript-index.mjs" --run "<id>" --locate
|
|
34
37
|
```
|
|
35
38
|
`matchedBy: "session"` means the run recorded its session id and the match
|
|
36
|
-
is exact. `"time-window"` means it did not, so the files are the sessions
|
|
37
|
-
that ran in the run's worktree or checkout while it was active; say that
|
|
39
|
+
is exact. `"time-window"` means it did not, so the files are the sessions,
|
|
40
|
+
on any host, that ran in the run's worktree or checkout while it was active; say that
|
|
38
41
|
this match is a heuristic. Exit 3 with a `reason`: report the reason, and
|
|
39
42
|
offer to take a transcript path instead.
|
|
40
43
|
- No argument: take the most recent run from
|
|
@@ -43,14 +43,14 @@ Skip Phase 0-3 and review a diff only. Input shapes: a PR (`#N`, `repo#N`, GitHu
|
|
|
43
43
|
|
|
44
44
|
**Claude Code (3 in parallel while the fable rung is on, 2 while it is off).** Resolve the fable slots first; this command has no Phase 0:
|
|
45
45
|
`REVIEW_RUNG=$(bash "$HOME/.claude/lib/model-dispatch.sh" subagent --persona reviewer --default fable)` and the same with `--persona triage` for `TRIAGE_RUNG`. Anything but `fable` drops Agent 1 and runs triage on `TRIAGE_RUNG`.
|
|
46
|
-
- Agent 1: `claude-fable-5` → security + architecture (only when `REVIEW_RUNG` is `fable`)
|
|
47
|
-
- Agent 2: `claude-opus-5` → edge cases, different perspective
|
|
48
|
-
- Agent 3: `claude-sonnet-5` → general quality
|
|
46
|
+
- Agent 1: `claude-fable-5-1` → security + architecture (only when `REVIEW_RUNG` is `fable`)
|
|
47
|
+
- Agent 2: `claude-opus-5-5` → edge cases, different perspective
|
|
48
|
+
- Agent 3: `claude-sonnet-5-5` → general quality
|
|
49
49
|
|
|
50
50
|
**Copilot CLI (3 in parallel):**
|
|
51
|
-
- Agent 1: `claude-opus-
|
|
51
|
+
- Agent 1: `claude-opus-4.7` → security + architecture (Fable is not offered on Copilot CLI)
|
|
52
52
|
- Agent 2: `gpt-5.4` → edge cases, different perspective
|
|
53
|
-
- Agent 3: `claude-sonnet-
|
|
53
|
+
- Agent 3: `claude-sonnet-4.6` → general quality
|
|
54
54
|
|
|
55
55
|
**Codex CLI (3 in parallel, single vendor):**
|
|
56
56
|
- Agent 1: `gpt-5.6` @ `xhigh` → security + architecture
|
|
@@ -29,7 +29,7 @@ honoured only at `bulk-read` and `delegate` and only while `--free` is on.
|
|
|
29
29
|
|
|
30
30
|
**Rung names are the contract; model ids are not.** `opus` is a rung here and a
|
|
31
31
|
model id in `cost-table.json`, and the second can change without anyone editing
|
|
32
|
-
a rule. Writing `claude-opus-5` into a rule pins a decision to a string that will
|
|
32
|
+
a rule. Writing `claude-opus-5-5` into a rule pins a decision to a string that will
|
|
33
33
|
go stale.
|
|
34
34
|
|
|
35
35
|
Set rules with:
|
|
@@ -322,14 +322,16 @@ On a new machine: (1) `npx @{npm-scope}/multi-agent-pipeline install`; (2) `/mul
|
|
|
322
322
|
|
|
323
323
|
All tokens are optional in the sense that every service can be answered with Skip - but the ASKING is not optional: the Step 3 sequential loop still walks every missing service one by one (token → author → host). Phase 0 re-asks at runtime only for tokens the user skipped here.
|
|
324
324
|
|
|
325
|
-
### Step 8 - Enforcement hooks (optional
|
|
325
|
+
### Step 8 - Enforcement hooks (optional)
|
|
326
326
|
|
|
327
|
-
|
|
327
|
+
On Claude Code, offer to merge `$HOME/.claude/templates/claude-hooks.json`: three blocking `PreToolUse` gates (secret scan, agent-guard, read-size) plus four non-blocking hooks (`PreCompact`, `SessionEnd`, `SessionStart`, `PostToolUse`). What each does: `$HOME/.claude/multi-agent-refs/picker-contract.md`.
|
|
328
328
|
|
|
329
329
|
- Ask (picker): "Install the pipeline's hooks into `~/.claude/settings.json`?" Default Yes.
|
|
330
|
-
- On Yes, deep-merge EVERY event in the template's `hooks` object
|
|
331
|
-
- Say
|
|
332
|
-
- Say
|
|
330
|
+
- On Yes, deep-merge EVERY event in the template's `hooks` object (merging `PreToolUse` alone drops the capture hooks); keep existing hooks, never duplicate a matcher calling the same script.
|
|
331
|
+
- Say only the three gates are hookable (no run-specific arguments); the rest are phase-enforced.
|
|
332
|
+
- Say the read-size gate stays inert until `prefs.global.bulkRead.mode` is set; recommend `observe` first (why, and the Phase 3 exemption: `picker-contract.md`).
|
|
333
|
+
|
|
334
|
+
Codex: offer only the syntax gate, then run `node "$HOME/.codex/scripts/host-hooks.mjs" install --host codex`. Copilot CLI: offer no hook (it discards `postToolUse` output as of 1.0.45).
|
|
333
335
|
|
|
334
336
|
### Step 9 - Default stack plugin enablement
|
|
335
337
|
|
|
@@ -9,10 +9,9 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
# multi-agent-testflight-validation - iOS alias for store-ready
|
|
11
11
|
|
|
12
|
-
This skill is an alias. The implementation
|
|
12
|
+
This skill is an alias. The implementation lives in
|
|
13
13
|
`multi-agent-store-ready`, which runs the same three gates on iOS and adds the
|
|
14
|
-
Android side, so there is one flow to maintain instead of two that
|
|
15
|
-
started to drift.
|
|
14
|
+
Android side, so there is one flow to maintain instead of two that drift.
|
|
16
15
|
|
|
17
16
|
The name is kept because it is the one people reach for when the target is
|
|
18
17
|
TestFlight, and removing a surface is a breaking change.
|
|
@@ -704,7 +704,7 @@ rules:
|
|
|
704
704
|
enforcement: judgement
|
|
705
705
|
rationale: testability
|
|
706
706
|
check: >
|
|
707
|
-
Two
|
|
707
|
+
Two concerns meet in this rule, and conflating them pushes modules toward the wrong fix
|
|
708
708
|
in both directions. Separate them:
|
|
709
709
|
**The failure vocabulary is module-scoped.** The set of ways a call can fail - offline,
|
|
710
710
|
timeout, unauthorised, not-found, conflict, server, unknown - is one type the whole module
|
|
@@ -925,7 +925,7 @@ rules:
|
|
|
925
925
|
check: >
|
|
926
926
|
When the app ships a wrapper for a platform affordance - a sheet, a date picker, a toast -
|
|
927
927
|
a feature module calls the wrapper, never the OS API underneath. The wrapper exists
|
|
928
|
-
because the OS
|
|
928
|
+
because the OS changes the affordance between releases: iOS 26 forced a
|
|
929
929
|
Liquid-Glass inset onto partial-detent sheets with no opt-out, which put a gap down the
|
|
930
930
|
side and bottom of every raw `.sheet` and swallowed a pushed picker's selection.
|
|
931
931
|
The tell that this rule was skipped: one module's sheets look different from the rest of
|