@iceinvein/agent-skills 0.1.39 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/cli/index.js +105 -28
- package/package.json +1 -1
- package/skills/index.json +14 -2
- package/skills/magpie/README.md +2 -1
- package/skills/magpie/SKILL.md +138 -45
- package/skills/magpie/bin/magpie.ts +43 -0
- package/skills/magpie/fixtures/example-pr/brief.json +18 -0
- package/skills/magpie/fixtures/fake-gh-nodiff.sh +38 -0
- package/skills/magpie/fixtures/fake-gh.sh +14 -0
- package/skills/magpie/package.json +1 -1
- package/skills/magpie/references/peer-review.md +7 -2
- package/skills/magpie/references/scout.md +90 -0
- package/skills/magpie/references/specialists.md +117 -6
- package/skills/magpie/scripts/__tests__/cli.test.ts +101 -1
- package/skills/magpie/scripts/__tests__/dedupe-cmd.test.ts +187 -0
- package/skills/magpie/scripts/__tests__/diff-chunks.test.ts +51 -0
- package/skills/magpie/scripts/__tests__/filter-diff-preservation.test.ts +54 -0
- package/skills/magpie/scripts/__tests__/findings-files.test.ts +35 -0
- package/skills/magpie/scripts/__tests__/gh.test.ts +90 -0
- package/skills/magpie/scripts/__tests__/git-diff.test.ts +83 -0
- package/skills/magpie/scripts/__tests__/helpers/git-fixture.ts +47 -0
- package/skills/magpie/scripts/__tests__/path-filter.test.ts +27 -0
- package/skills/magpie/scripts/__tests__/preview-cmd.test.ts +16 -0
- package/skills/magpie/scripts/__tests__/refresh.test.ts +45 -0
- package/skills/magpie/scripts/__tests__/render-cmd.test.ts +173 -1
- package/skills/magpie/scripts/__tests__/render-findings.test.ts +151 -1
- package/skills/magpie/scripts/__tests__/render-progress.test.ts +42 -0
- package/skills/magpie/scripts/__tests__/setup-cmd.test.ts +83 -1
- package/skills/magpie/scripts/__tests__/shard.test.ts +165 -0
- package/skills/magpie/scripts/__tests__/skill-lint.test.ts +207 -7
- package/skills/magpie/scripts/__tests__/types.test.ts +47 -0
- package/skills/magpie/scripts/dedupe-cmd.ts +58 -3
- package/skills/magpie/scripts/diff-chunks.ts +28 -0
- package/skills/magpie/scripts/findings-files.ts +32 -0
- package/skills/magpie/scripts/gh.ts +68 -14
- package/skills/magpie/scripts/git-diff.ts +111 -0
- package/skills/magpie/scripts/path-filter.ts +9 -5
- package/skills/magpie/scripts/preview-cmd.ts +11 -1
- package/skills/magpie/scripts/refresh.ts +32 -3
- package/skills/magpie/scripts/render-cmd.ts +35 -11
- package/skills/magpie/scripts/render-findings.ts +78 -2
- package/skills/magpie/scripts/render-progress.ts +6 -1
- package/skills/magpie/scripts/setup-cmd.ts +38 -1
- package/skills/magpie/scripts/shard.ts +171 -0
- package/skills/magpie/scripts/status-cmd.ts +7 -4
- package/skills/magpie/scripts/types.ts +50 -0
- package/skills/magpie/skill.json +2 -2
- package/skills/magpie/templates/styles.css +66 -0
- package/skills/migrate/README.md +194 -0
- package/skills/migrate/SKILL.md +197 -0
- package/skills/migrate/bin/migrate +15 -0
- package/skills/migrate/bin/migrate.ts +309 -0
- package/skills/migrate/biome.json +35 -0
- package/skills/migrate/bun.lock +24 -0
- package/skills/migrate/docs/architecture.md +294 -0
- package/skills/migrate/docs/reference.md +590 -0
- package/skills/migrate/fixtures/tiny-express/GROUND-TRUTH.md +39 -0
- package/skills/migrate/fixtures/tiny-express/app.js +29 -0
- package/skills/migrate/fixtures/tiny-express/cron.js +6 -0
- package/skills/migrate/fixtures/tiny-express/reports/daily-users.json +6 -0
- package/skills/migrate/fixtures/tiny-express/schema.sql +12 -0
- package/skills/migrate/fixtures/tiny-express/settings.json +4 -0
- package/skills/migrate/fixtures/tiny-express/views/users.html +9 -0
- package/skills/migrate/fixtures/tiny-webforms/Controllers/UsersController.cs +68 -0
- package/skills/migrate/fixtures/tiny-webforms/Default.aspx +7 -0
- package/skills/migrate/fixtures/tiny-webforms/Default.aspx.cs +14 -0
- package/skills/migrate/fixtures/tiny-webforms/GROUND-TRUTH.md +50 -0
- package/skills/migrate/fixtures/tiny-webforms/Integrations/BillingClient.cs +16 -0
- package/skills/migrate/fixtures/tiny-webforms/Jobs/NightlyDigestJob.cs +33 -0
- package/skills/migrate/fixtures/tiny-webforms/Reports/DailyUsers.rdl +11 -0
- package/skills/migrate/fixtures/tiny-webforms/Schema.sql +12 -0
- package/skills/migrate/fixtures/tiny-webforms/Site.master +16 -0
- package/skills/migrate/fixtures/tiny-webforms/Users.aspx +8 -0
- package/skills/migrate/fixtures/tiny-webforms/Users.aspx.cs +14 -0
- package/skills/migrate/fixtures/tiny-webforms/web.config +10 -0
- package/skills/migrate/install.sh +68 -0
- package/skills/migrate/package.json +17 -0
- package/skills/migrate/references/phases/enumerate.md +291 -0
- package/skills/migrate/references/phases/extract.md +652 -0
- package/skills/migrate/references/phases/parity.md +275 -0
- package/skills/migrate/references/phases/probe.md +135 -0
- package/skills/migrate/references/phases/queue.md +242 -0
- package/skills/migrate/references/phases/seam.md +416 -0
- package/skills/migrate/references/recipes/README.md +116 -0
- package/skills/migrate/references/recipes/aspnet.md +287 -0
- package/skills/migrate/references/run-ops.md +280 -0
- package/skills/migrate/scripts/__tests__/census.test.ts +775 -0
- package/skills/migrate/scripts/__tests__/check.test.ts +458 -0
- package/skills/migrate/scripts/__tests__/citations.test.ts +156 -0
- package/skills/migrate/scripts/__tests__/cli.test.ts +183 -0
- package/skills/migrate/scripts/__tests__/concurrency.test.ts +164 -0
- package/skills/migrate/scripts/__tests__/config.test.ts +112 -0
- package/skills/migrate/scripts/__tests__/e2e-express.test.ts +1093 -0
- package/skills/migrate/scripts/__tests__/e2e-webforms.test.ts +1276 -0
- package/skills/migrate/scripts/__tests__/e2e.test.ts +320 -0
- package/skills/migrate/scripts/__tests__/ids.test.ts +38 -0
- package/skills/migrate/scripts/__tests__/import.test.ts +155 -0
- package/skills/migrate/scripts/__tests__/init.test.ts +192 -0
- package/skills/migrate/scripts/__tests__/leaks.test.ts +176 -0
- package/skills/migrate/scripts/__tests__/lock.test.ts +183 -0
- package/skills/migrate/scripts/__tests__/paths.test.ts +129 -0
- package/skills/migrate/scripts/__tests__/phase-cmd.test.ts +151 -0
- package/skills/migrate/scripts/__tests__/phases.test.ts +70 -0
- package/skills/migrate/scripts/__tests__/queue.test.ts +475 -0
- package/skills/migrate/scripts/__tests__/report.test.ts +150 -0
- package/skills/migrate/scripts/__tests__/run-state.test.ts +136 -0
- package/skills/migrate/scripts/__tests__/status-reset.test.ts +318 -0
- package/skills/migrate/scripts/__tests__/store.test.ts +132 -0
- package/skills/migrate/scripts/__tests__/validate.test.ts +54 -0
- package/skills/migrate/scripts/census-cmd.ts +109 -0
- package/skills/migrate/scripts/census.ts +342 -0
- package/skills/migrate/scripts/check-cmd.ts +24 -0
- package/skills/migrate/scripts/check.ts +376 -0
- package/skills/migrate/scripts/citations.ts +92 -0
- package/skills/migrate/scripts/config.ts +237 -0
- package/skills/migrate/scripts/ids.ts +31 -0
- package/skills/migrate/scripts/import-cmd.ts +141 -0
- package/skills/migrate/scripts/init-cmd.ts +118 -0
- package/skills/migrate/scripts/leaks.ts +184 -0
- package/skills/migrate/scripts/lock.ts +188 -0
- package/skills/migrate/scripts/paths.ts +103 -0
- package/skills/migrate/scripts/phase-cmd.ts +63 -0
- package/skills/migrate/scripts/phases.ts +113 -0
- package/skills/migrate/scripts/queue-cmd.ts +98 -0
- package/skills/migrate/scripts/queue.ts +258 -0
- package/skills/migrate/scripts/report-cmd.ts +47 -0
- package/skills/migrate/scripts/report.ts +131 -0
- package/skills/migrate/scripts/reset-cmd.ts +120 -0
- package/skills/migrate/scripts/status-cmd.ts +52 -0
- package/skills/migrate/scripts/store.ts +159 -0
- package/skills/migrate/scripts/types.ts +137 -0
- package/skills/migrate/scripts/validate.ts +221 -0
- package/skills/migrate/skill.json +33 -0
- package/skills/migrate/templates/config.toml +27 -0
- package/skills/migrate/templates/queue-item.md +17 -0
- package/skills/migrate/tsconfig.json +18 -0
- package/skills/migrate/uninstall.sh +31 -0
- package/skills/sluice/SKILL.md +82 -0
- package/skills/sluice/references/deep-channel.md +94 -0
- package/skills/sluice/references/finish.md +35 -0
- package/skills/sluice/references/intent.md +29 -0
- package/skills/sluice/references/review.md +42 -0
- package/skills/sluice/references/root-cause.md +38 -0
- package/skills/sluice/references/show-or-say.md +36 -0
- package/skills/sluice/references/test-first.md +35 -0
- package/skills/sluice/references/verify.md +26 -0
- package/skills/sluice/skill.json +32 -0
package/skills/magpie/SKILL.md
CHANGED
|
@@ -7,7 +7,7 @@ description: Use when the user asks to review a GitHub pull request (a PR number
|
|
|
7
7
|
|
|
8
8
|
## Prerequisites
|
|
9
9
|
|
|
10
|
-
The skill pre-flights `bun`, `gh`, `git` (required) and `codex` (optional).
|
|
10
|
+
The skill pre-flights `bun`, `gh`, `git` (required) and `codex` (optional). A missing required binary aborts the run with a single install hint line. Without `codex` the run continues and peer review falls back to a Claude second-opinion subagent (setup prints a one-line notice and logs `{stage: preflight, status: done, missingOptional: ["codex"]}`).
|
|
11
11
|
|
|
12
12
|
## Stage walkthrough
|
|
13
13
|
|
|
@@ -15,15 +15,15 @@ Stop reading and follow these steps in order. Do not skip stages. Use the exact
|
|
|
15
15
|
|
|
16
16
|
### 0. Identify the PR
|
|
17
17
|
|
|
18
|
-
Parse the user's request for a PR number, URL, or "this PR" (current branch). If ambiguous, ask one clarifying terminal question. Capture the PR number into `$PR_NUMBER` and the
|
|
18
|
+
Parse the user's request for a PR number, URL, or "this PR" (current branch). If ambiguous, ask one clarifying terminal question. Capture the PR number into `$PR_NUMBER` and the repo path into `$REPO` (default: the current working directory).
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Before minting a new id, check whether an earlier run on this PR is unfinished:
|
|
21
21
|
|
|
22
22
|
```
|
|
23
23
|
magpie --list-runs
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Each line is `<id>\t<active|archived>\t<path>`. If an `active` id matches `pr-${PR_NUMBER}-*`, that run was interrupted rather than cleaned up. Set `RUN_DIR` to its path and go to "Resuming a crashed run"
|
|
26
|
+
Each line is `<id>\t<active|archived>\t<path>`. If an `active` id matches `pr-${PR_NUMBER}-*`, that run was interrupted rather than cleaned up. Set `RUN_DIR` to its path and go to "Resuming a crashed run"; ask the user first if it is unclear whether they want to resume or start over. (`archived` ids are finished runs, not resumable.)
|
|
27
27
|
|
|
28
28
|
Otherwise compute a fresh run directory:
|
|
29
29
|
|
|
@@ -38,15 +38,30 @@ RUN_DIR="$HOME/.magpie/$RUN_ID"
|
|
|
38
38
|
magpie setup "$RUN_DIR" --pr $PR_NUMBER --repo "$REPO"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
If exit is non-zero, surface stderr verbatim and stop. The CLI removes the worktree and subdirs on failure
|
|
41
|
+
If exit is non-zero, surface stderr verbatim and stop. The CLI removes the worktree and subdirs on failure, keeping the run directory and `log.jsonl` for diagnostics.
|
|
42
42
|
|
|
43
|
-
Setup
|
|
43
|
+
Setup filters lockfiles, build output, generated source, and snapshot fixtures from `diff.patch` before specialists see it. Users override with `.magpie.json` at the repo root: `{"exclude": [...glob], "include": [...glob], "useDefaults": true|false}`. When anything is filtered, the raw diff is kept as `$RUN_DIR/diff.full.patch` and the exclusion list as `$RUN_DIR/excluded-files.json`.
|
|
44
44
|
|
|
45
|
-
When
|
|
45
|
+
When `gh pr diff` refuses the diff (HTTP 406 above roughly 300 files) or returns an
|
|
46
|
+
empty diff for a PR with changed files, setup rebuilds it from the local clone instead
|
|
47
|
+
of aborting: it fetches `pull/<n>/head` and diffs from the merge base against the PR's
|
|
48
|
+
base branch, reproducing the three-dot semantics `gh pr diff` uses. A local head that
|
|
49
|
+
does not match the PR's `headRefOid` is a hard error, not a silently stale review. The
|
|
50
|
+
`fetch-pr` log entry records `source: "gh" | "git"` and the merge base, and
|
|
51
|
+
`$RUN_DIR/diff-source.json` carries the same for the report.
|
|
52
|
+
|
|
53
|
+
Setup then splits the filtered diff into shards, writing `$RUN_DIR/shards/manifest.json`
|
|
54
|
+
and, when more than one shard results, `$RUN_DIR/shards/shard-<n>.patch`. `diff.patch`
|
|
55
|
+
itself is never modified: shards are views over it. Re-split with a different budget
|
|
56
|
+
using `magpie shard "$RUN_DIR" --budget <lines> --max-files <n>` (defaults: 6000 patch
|
|
57
|
+
lines, 80 files). Re-splitting invalidates every existing
|
|
58
|
+
`findings/<focus>.shard-<n>.json`, since a shard id then names a different file set:
|
|
59
|
+
delete those files first, or stage 4's resume rule counts a pair as covered that
|
|
60
|
+
nothing reviewed.
|
|
46
61
|
|
|
47
|
-
|
|
62
|
+
When a prior run exists for the same PR (active or archived under `~/.magpie/`), setup writes `$RUN_DIR/incremental.json` with `{previousRunId, previousSha, currentSha, sameSha}`. The post stage surfaces this as a "Incremental review since `<sha>`" trailer on the summary comment.
|
|
48
63
|
|
|
49
|
-
|
|
64
|
+
Setup also runs a deterministic test-coverage check: when the diff contains zero test or spec files anywhere, each non-test source file with `>= 10` added code lines gets a `domain: "tests"` finding in `$RUN_DIR/findings/tests.json`. That sixth domain flows through dedupe/critic/peer-review alongside the five LLM specialists; no subagent is dispatched for it.
|
|
50
65
|
|
|
51
66
|
### 2. Serve
|
|
52
67
|
|
|
@@ -56,9 +71,9 @@ Start the HTML server in the background using the Bash tool with `run_in_backgro
|
|
|
56
71
|
magpie serve "$RUN_DIR"
|
|
57
72
|
```
|
|
58
73
|
|
|
59
|
-
Read `$RUN_DIR/state/server-info` for the URL; the server writes it asynchronously
|
|
74
|
+
Read `$RUN_DIR/state/server-info` for the URL; the server writes it asynchronously, so if it is missing, wait a moment and re-read (it appears within ~1s). Print to the user: "Open <url> in your browser to follow along."
|
|
60
75
|
|
|
61
|
-
The server shuts down after 30 minutes
|
|
76
|
+
The server shuts down after 30 idle minutes (an open report tab heartbeats every 30s, so it stays up while the user is looking) and deletes `state/server-info` on the way out. Nothing in the pipeline depends on it: re-run `magpie serve "$RUN_DIR"` to bring the report back.
|
|
62
77
|
|
|
63
78
|
Render the first progress paint:
|
|
64
79
|
|
|
@@ -66,53 +81,125 @@ Render the first progress paint:
|
|
|
66
81
|
magpie render "$RUN_DIR" progress
|
|
67
82
|
```
|
|
68
83
|
|
|
69
|
-
### 3.
|
|
84
|
+
### 3. Context
|
|
85
|
+
|
|
86
|
+
Append `{stage: context, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress. This stage has two steps and never aborts the run.
|
|
87
|
+
|
|
88
|
+
**Bind probe.** If the `mcp__code-intelligence__*` tools are not in your tool list, skip straight to the scout with `CODE_INTELLIGENCE=unavailable`. Otherwise call `bind_workspace` with `$RUN_DIR/worktree`: it is a linked git worktree, so an already-indexed base repo seeds its index instead of re-indexing.
|
|
89
|
+
|
|
90
|
+
- `consent_required` means the base repo has never completed an index. **Never call `approve_indexing`**: that is a full GPU pass the user did not ask for. Set `CODE_INTELLIGENCE=unavailable`, and print one line: "Code intelligence is unavailable (the base repo has no index); specialists will review from the diff alone."
|
|
91
|
+
- `indexing_started` or `indexing_in_progress` means the seed took. Poll `get_index_stats` every 5s for at most 60s, then set `CODE_INTELLIGENCE=available` either way. Do not block the pipeline on completion; the specialist contract handles a still-indexing tool.
|
|
92
|
+
- A ready result sets `CODE_INTELLIGENCE=available`.
|
|
93
|
+
- Any other error sets `CODE_INTELLIGENCE=unavailable`. Do not retry.
|
|
94
|
+
|
|
95
|
+
**Scout.** Read `references/scout.md` and dispatch one subagent (Agent tool, `general-purpose`) carrying the `magpie-scout` block with `<<RUN_DIR>>`, `<<PR_NUMBER>>`, and `<<CODE_INTELLIGENCE>>` substituted. It writes `$RUN_DIR/brief.json`.
|
|
96
|
+
|
|
97
|
+
Append `{stage: context, status: done, codeIntelligence: true|false}` and re-render progress. If the scout returned without writing `brief.json`, append `{stage: context, status: skipped, codeIntelligence: true|false}` instead and continue: the brief is optional everywhere it is read. Both entries carry the probe's result, which is known whatever the scout did.
|
|
98
|
+
|
|
99
|
+
### 4. Specialists
|
|
70
100
|
|
|
71
|
-
Read `references/specialists.md` now, before dispatching anything
|
|
101
|
+
Read `references/specialists.md` now, before dispatching anything: it holds the five focus blocks and the output contract every specialist prompt is built from. Assemble prompts from that file verbatim; written from memory they drift off the JSON contract, and `magpie dedupe` drops findings it cannot parse.
|
|
72
102
|
|
|
73
|
-
Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render
|
|
103
|
+
Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render
|
|
104
|
+
progress, so the served page shows the stage as active rather than "Paused". Then read
|
|
105
|
+
`$RUN_DIR/shards/manifest.json`.
|
|
74
106
|
|
|
75
|
-
|
|
107
|
+
**One shard, zero shards, or no manifest** (a diff filtered down to nothing, e.g. a
|
|
108
|
+
lockfile-only PR, yields `shards: []` in an otherwise normal manifest; a run predating
|
|
109
|
+
this feature has no manifest at all): dispatch the five specialists in a single message,
|
|
110
|
+
five parallel Agent calls, one per focus in (security, bugs, performance, code-smells,
|
|
111
|
+
architecture), each carrying the prompt `references/specialists.md` describes with the
|
|
112
|
+
unsharded run header. The shard gate and the wave dispatch below do not apply; the
|
|
113
|
+
logging and the file check at the end of this stage still do.
|
|
76
114
|
|
|
77
|
-
|
|
115
|
+
**More than one shard:** each focus reviews every shard, so the run dispatches
|
|
116
|
+
`5 × <shard count>` subagents in total.
|
|
78
117
|
|
|
79
|
-
|
|
118
|
+
**More than four shards: stop and ask the user once, before dispatching anything.**
|
|
119
|
+
State the shard count, the resulting agent count, and the three options: proceed as
|
|
120
|
+
sharded; re-shard for fewer, larger chunks with
|
|
121
|
+
`magpie shard "$RUN_DIR" --budget <lines> --max-files <n>`, raising both flags (a PR of
|
|
122
|
+
many small files is split by the 80-file cap, so a larger `--budget` alone changes
|
|
123
|
+
nothing); or review only the highest-risk shards, which means appending
|
|
124
|
+
`{stage: shard-coverage, status: partial, reviewed: [<ids>], skipped: [<ids>]}` to
|
|
125
|
+
`$RUN_DIR/log.jsonl` and telling the user in the terminal which shards go unreviewed.
|
|
126
|
+
That log entry is the only record of the gap: the report has no unreviewed marker.
|
|
127
|
+
Wait for the answer. This is the only interactive gate in the pipeline before the
|
|
128
|
+
report, and it exists so that neither the cost nor a coverage gap is ever silent.
|
|
129
|
+
|
|
130
|
+
Dispatch by wave, one shard per wave, the five focuses in parallel within a wave,
|
|
131
|
+
re-rendering progress between waves. That holds in-flight agents at five and makes a
|
|
132
|
+
crash cheap to resume: only the `(focus, shard)` pairs whose findings file is missing
|
|
133
|
+
need re-dispatching.
|
|
134
|
+
|
|
135
|
+
After each subagent returns, append
|
|
136
|
+
`{stage: specialist, focus: <focus>, shard: <n>, status: done, findings: <count>}` to
|
|
137
|
+
`$RUN_DIR/log.jsonl` and re-render progress. Omit `shard` on the unsharded path (one
|
|
138
|
+
shard, zero shards, or no manifest).
|
|
139
|
+
(Per-focus `specialist` entries are diagnostic; only the aggregate `specialists` entry
|
|
140
|
+
advances `magpie status`.)
|
|
141
|
+
|
|
142
|
+
Before leaving this stage, list `$RUN_DIR/findings` and confirm one file per expected
|
|
143
|
+
`(focus, shard)` pair: `5 × <shard count>` named `findings/<focus>.shard-<n>.json` when
|
|
144
|
+
sharded, five `findings/<focus>.json` otherwise, plus `findings/tests.json` from setup.
|
|
145
|
+
Re-dispatch any pair missing from a shard you meant to review; a shard skipped at the
|
|
146
|
+
gate is expected to have none. `magpie dedupe` re-checks this against the manifest and
|
|
147
|
+
names every missing pair on stdout, as a backstop rather than a substitute.
|
|
148
|
+
|
|
149
|
+
If every specialist fails (no findings files written), log
|
|
150
|
+
`{stage: specialists, status: error}`, rebind code intelligence to `$REPO` if bound
|
|
151
|
+
(stage 10), and stop. Otherwise mark `{stage: specialists, status: done}`.
|
|
152
|
+
|
|
153
|
+
### 5. Dedupe
|
|
80
154
|
|
|
81
155
|
```
|
|
82
156
|
magpie dedupe "$RUN_DIR" [--threshold <0-10>]
|
|
83
157
|
```
|
|
84
158
|
|
|
85
|
-
`magpie dedupe` also runs a deterministic evidence check against the worktree: findings whose `file` is missing or whose `line` is out of range are dropped
|
|
159
|
+
`magpie dedupe` also runs a deterministic evidence check against the worktree: findings whose `file` is missing or whose `line` is out of range are dropped, logged, and recorded to `$RUN_DIR/evidence-dropped.json`. The check is skipped when the worktree is gone (archived run replay).
|
|
86
160
|
|
|
87
|
-
Each finding
|
|
161
|
+
Each finding gets a derived 0-10 `score` from its risk fields; those below `--threshold` (default 3) are dropped before the critic LLM runs and recorded to `$RUN_DIR/threshold-dropped.json`. Pass `--threshold 0` to keep everything.
|
|
88
162
|
|
|
89
163
|
Re-render progress.
|
|
90
164
|
|
|
91
|
-
###
|
|
165
|
+
### 6. Critic
|
|
92
166
|
|
|
93
167
|
Read `references/critic.md` and `$RUN_DIR/findings.deduped.json`. Substitute both placeholders in the critic rubric (the compact candidate list including each finding's `onChangedLine`, and the `<<DIFF_EXCERPT>>` hunks for the referenced files), then apply the rubric verbatim (one verdict per finding). Write the kept subset to `$RUN_DIR/findings.kept.json`. Append `{stage: critic, status: done}` and re-render progress.
|
|
94
168
|
|
|
95
|
-
|
|
169
|
+
When `findings.deduped.json` holds more than 40 findings, run the rubric in batches of
|
|
170
|
+
30 rather than one prompt: a sharded run can produce more candidates than fit alongside
|
|
171
|
+
their diff excerpts. Apply the same rubric verbatim per batch and concatenate the kept
|
|
172
|
+
subsets into `findings.kept.json`.
|
|
173
|
+
|
|
174
|
+
### 7. Peer review
|
|
96
175
|
|
|
97
|
-
Append `{stage: peer-review, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress. This stage always runs. `codex` is
|
|
176
|
+
Append `{stage: peer-review, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress. This stage always runs. `codex` is preferred because it is a different model from the Claude agents that produced the findings; without it, a Claude second-opinion subagent stands in.
|
|
98
177
|
|
|
99
|
-
Build the peer-review prompt first: read `references/peer-review.md`, take the `magpie-peer-review` block from it, and substitute the placeholders listed in that file's `## Substitute before use` preamble.
|
|
178
|
+
Build the peer-review prompt first: read `references/peer-review.md`, take the `magpie-peer-review` block from it, and substitute the placeholders listed in that file's `## Substitute before use` preamble.
|
|
100
179
|
|
|
101
|
-
|
|
180
|
+
One batch carries up to 40 findings; above that, split them 30 at a time, as in stage 6.
|
|
181
|
+
Write each batch's prompt, its `<<KEPT_FINDINGS_COMPACT>>` narrowed to that batch, to
|
|
182
|
+
`$RUN_DIR/peer-prompt-<k>.md`, `<k>` counting from 1. **When there is a single batch, drop `-<k>` throughout** (`peer-prompt.md`,
|
|
183
|
+
`peer.out`), which is the common case. Keep the `add` id counter running across batches
|
|
184
|
+
(`peer-1`, `peer-2`, ...): restarting it per batch produces colliding ids, and every
|
|
185
|
+
finding in `findings.final.json` must have a unique one or the report and post stages
|
|
186
|
+
crash.
|
|
187
|
+
|
|
188
|
+
**Codex path (preferred).** If `codex` is available (setup did not log `missingOptional: ["codex"]` and `command -v codex` succeeds), set `<<PEER_PROVIDER>>` to `codex` and run codex once per batch, that batch's prompt piped on stdin:
|
|
102
189
|
|
|
103
190
|
```
|
|
104
|
-
codex exec < "$RUN_DIR/peer-prompt
|
|
191
|
+
codex exec < "$RUN_DIR/peer-prompt-<k>.md" > "$RUN_DIR/peer-<k>.out"
|
|
105
192
|
```
|
|
106
193
|
|
|
107
|
-
`peer
|
|
194
|
+
Each `peer-<k>.out` is codex's full transcript; extract the fenced JSON block tagged `review-peer-review` from each. Write the concatenated verdict arrays to `$RUN_DIR/peer.json` once, after the last batch: writing `peer.json` per batch keeps only the last batch's verdicts and silently discards the rest. Then append `{stage: peer-review, status: done, provider: codex}` and apply the verdicts as described below.
|
|
108
195
|
|
|
109
|
-
If codex returns non-zero, do not abort: record `{stage: peer-review, provider: codex, status: fallback, error: "<first line of stderr>"}` and
|
|
196
|
+
If codex returns non-zero on a batch, do not abort: record `{stage: peer-review, provider: codex, status: fallback, batch: <k>, error: "<first line of stderr>"}` and take the Claude path for that batch. (Never log `status: error` for a recoverable codex failure: `magpie status` stops at the first `error` entry and would report the run as poisoned even after the Claude fallback succeeds.)
|
|
110
197
|
|
|
111
|
-
**Claude path (fallback).** When `codex` is unavailable or failed, get the second opinion from a Claude subagent instead. Set `<<PEER_PROVIDER>>` to `claude`, then prepend the `magpie-peer-review-claude-preamble` block from `references/peer-review.md` to
|
|
198
|
+
**Claude path (fallback).** When `codex` is unavailable or failed, get the second opinion from a Claude subagent instead, one per batch. Set `<<PEER_PROVIDER>>` to `claude`, then prepend the `magpie-peer-review-claude-preamble` block from `references/peer-review.md` to each batch's substituted prompt (the preamble forces genuine independence, since the reviewer shares a model family with the primary reviewers). Dispatch one subagent (Agent tool, `general-purpose`) per batch whose entire task is that combined prompt, and instruct it to return only the fenced `review-peer-review` JSON block. Write each output to `$RUN_DIR/peer-<k>.out`, extract each `review-peer-review` block, merge into `$RUN_DIR/peer.json` after the last batch as above, and append `{stage: peer-review, status: done, provider: claude}` (`provider: mixed` if codex handled some batches).
|
|
112
199
|
|
|
113
|
-
**Apply the verdicts (both paths).** Parse the verdicts
|
|
200
|
+
**Apply the verdicts (both paths).** Parse the merged verdicts and apply the `update` / `add` entries (an empty array means no change). Mint each `add`'s `id` as above before merging, since the peer contract does not carry ids. Then write `findings.final.json`. Re-render progress.
|
|
114
201
|
|
|
115
|
-
###
|
|
202
|
+
### 8. Report
|
|
116
203
|
|
|
117
204
|
```
|
|
118
205
|
magpie render "$RUN_DIR" findings
|
|
@@ -124,11 +211,11 @@ Print to the terminal: "Findings ready at <url>. Tick the ones you want and clic
|
|
|
124
211
|
|
|
125
212
|
End the turn.
|
|
126
213
|
|
|
127
|
-
###
|
|
214
|
+
### 9. Post
|
|
128
215
|
|
|
129
|
-
Most users
|
|
216
|
+
Most users tick the checkboxes in the served report and click **Post Selected** (or **Post Recommended**, which takes every `must-fix`/`should-fix` finding and skips the `consider`/`optional` ones); the server posts that batch as one GitHub review with inline threads. The agent posts only when the user types `post` (optionally `post 1,3,7` for indices), which takes the CLI path below: separate inline comments plus a top-level summary comment. Either path records posted ids in `post-status.json`, so the two cannot double-post the same finding.
|
|
130
217
|
|
|
131
|
-
When the user types `post`, read `$RUN_DIR/state/events
|
|
218
|
+
When the user types `post`, read `$RUN_DIR/state/events` and fold them in order, keeping the LAST event per finding id; ids whose last event is `select` are selected. (Not union-minus: the UI emits one event per toggle, so select, deselect, select again resolves to selected.) Merge any explicit indices the user named (1-based, against `findings.final.json` in file order). If nothing is selected, say so and ask rather than posting an empty batch. Then post via the CLI:
|
|
132
219
|
|
|
133
220
|
```
|
|
134
221
|
magpie post "$RUN_DIR" --ids id1,id2,id3
|
|
@@ -136,30 +223,32 @@ magpie post "$RUN_DIR" --ids id1,id2,id3
|
|
|
136
223
|
|
|
137
224
|
That delegates to `runPost`, which:
|
|
138
225
|
|
|
139
|
-
-
|
|
140
|
-
- Falls back to `formatConversationBody` (same shape plus a `Location · <file>:<line>` metaline)
|
|
141
|
-
- When at least one new finding is
|
|
226
|
+
- For a finding with a `line`, picks `formatInlineBody` (severity heading, `<sub>` risk metaline, parsed `Observation`/`Why it matters`/`Suggested direction`/`Needs verification` sections, optional `` ```suggestion `` block, hidden `magpie:finding` marker) and opens an inline review thread via `gh api repos/<owner>/<repo>/pulls/<n>/comments`.
|
|
227
|
+
- Falls back to `formatConversationBody` (same shape plus a `Location · <file>:<line>` metaline) via `gh pr comment <n>` when there is no anchor, or GitHub rejects the inline anchor with 422.
|
|
228
|
+
- When at least one new finding is in the batch (default `auto` mode), prepends one top-level summary comment (verdict line, "Needs Attention" top three, `<details>` risk breakdown) and persists the `__summary__` sentinel in `post-status.json` so re-runs don't duplicate it. Override with `--include-summary always|never`.
|
|
142
229
|
- Appends `{stage: post, ...}` events to `log.jsonl` and updates `$RUN_DIR/post-status.json` per finding id.
|
|
143
230
|
|
|
144
|
-
Pass `--dry-run` to record the would-be gh commands without invoking gh. After posting, append `{stage: post, status: done}` to `$RUN_DIR/log.jsonl` (`runPost` logs per-finding `ok`/`failed` events but not the stage
|
|
231
|
+
Pass `--dry-run` to record the would-be gh commands without invoking gh. After posting, append `{stage: post, status: done}` to `$RUN_DIR/log.jsonl` (`runPost` logs per-finding `ok`/`failed` events but not the stage marker, and `magpie status` counts only `done`), then re-render the report so the badges update:
|
|
145
232
|
|
|
146
233
|
```
|
|
147
234
|
magpie render "$RUN_DIR" findings
|
|
148
235
|
```
|
|
149
236
|
|
|
150
|
-
###
|
|
237
|
+
### 10. Cleanup
|
|
151
238
|
|
|
152
239
|
```
|
|
153
240
|
magpie cleanup "$RUN_DIR" --repo "$REPO"
|
|
154
241
|
```
|
|
155
242
|
|
|
156
|
-
|
|
243
|
+
If the context stage bound code intelligence, rebind the session now: call `bind_workspace` with `$REPO`. Binding is per session with no per-call override, so ending a run without this leaves the session pointed at a worktree `cleanup` just deleted. The daemon prunes the seeded index once the worktree is gone.
|
|
244
|
+
|
|
245
|
+
The run directory is renamed to `<run-dir>.archived-<timestamp>` and the worktree is removed. The CLI prints two lines on success: `archived to <path>` and `view later: magpie open <archived-id>`. Surface that second line verbatim so the user has a one-command path back to the report.
|
|
157
246
|
|
|
158
247
|
The archived `findings.html` is self-contained and auto-switches to read-only "archived" mode when opened, so:
|
|
159
248
|
|
|
160
|
-
- `magpie open` (no args) opens the latest run in the
|
|
249
|
+
- `magpie open` (no args) opens the latest run in the default browser via `open`/`xdg-open`; `--dry-run` prints the command instead of spawning it.
|
|
161
250
|
- `magpie open <id>` opens a specific archived run.
|
|
162
|
-
- `magpie serve <id>` re-spins the Bun server against an archived run
|
|
251
|
+
- `magpie serve <id>` re-spins the Bun server against an archived run for the live interactive surface (posts still work: `pr.json` retains the head SHA).
|
|
163
252
|
- `magpie --list-runs` enumerates all runs in `~/.magpie/`.
|
|
164
253
|
|
|
165
254
|
## Resuming a crashed run
|
|
@@ -172,13 +261,17 @@ magpie status "$RUN_DIR"
|
|
|
172
261
|
|
|
173
262
|
The JSON output tells you `lastCompleted` and `next`. Resume from `next`:
|
|
174
263
|
|
|
175
|
-
- `context`
|
|
264
|
+
- `context` re-runs by redoing the bind probe, then dispatching the scout only if `$RUN_DIR/brief.json` is missing. The seeded index survives a crash, so the rebind is near-instant.
|
|
176
265
|
- Any other stage: run it as written in the walkthrough.
|
|
177
|
-
- If a specialist focus has no findings file but its sibling stages are done,
|
|
266
|
+
- If a specialist focus has no findings file but its sibling stages are done,
|
|
267
|
+
re-dispatch only that focus. On a sharded run the unit is the `(focus, shard)` pair:
|
|
268
|
+
read `shards/manifest.json`, and re-dispatch only the pairs with no
|
|
269
|
+
`findings/<focus>.shard-<n>.json`. Never re-shard mid-run without deleting those
|
|
270
|
+
files first (stage 1): the check would otherwise trust ids that moved.
|
|
178
271
|
- Non-null `error` means the run stopped on a failed stage. Report which stage to the user and confirm before re-running it.
|
|
179
272
|
|
|
180
|
-
The
|
|
273
|
+
The original server is gone. Restart it with `magpie serve "$RUN_DIR"` (step 2) before re-rendering, so the user gets a live URL again.
|
|
181
274
|
|
|
182
275
|
## Aborting
|
|
183
276
|
|
|
184
|
-
If the user types `abort` mid-run, run `magpie cleanup`
|
|
277
|
+
If the user types `abort` mid-run, rebind code intelligence to `$REPO` if bound (stage 10), then run `magpie cleanup` and exit.
|
|
@@ -10,6 +10,8 @@ Subcommands:
|
|
|
10
10
|
setup <run-dir> --pr <n> Pre-flight, fetch PR, create worktree
|
|
11
11
|
serve <run-dir-or-id> Start the HTML server (accepts active or archived run id)
|
|
12
12
|
dedupe <run-dir> Merge specialist findings into deduped set
|
|
13
|
+
shard <run-dir> [--budget N] [--max-files N]
|
|
14
|
+
Re-split diff.patch into budgeted shards
|
|
13
15
|
render <run-dir> <page> Render progress.html or findings.html
|
|
14
16
|
cleanup <run-dir> Remove worktree, stop server, archive run
|
|
15
17
|
status <run-dir> Print highest completed stage
|
|
@@ -116,6 +118,47 @@ const HANDLERS: Record<string, Handler> = {
|
|
|
116
118
|
const { runDedupe } = await import('../scripts/dedupe-cmd.ts')
|
|
117
119
|
return runDedupe(runDir, threshold !== undefined ? { threshold } : {})
|
|
118
120
|
},
|
|
121
|
+
shard: async (args) => {
|
|
122
|
+
const runDir = args[0]
|
|
123
|
+
if (!runDir) {
|
|
124
|
+
process.stderr.write('shard: missing <run-dir> [--budget <n>] [--max-files <n>]\n')
|
|
125
|
+
return 2
|
|
126
|
+
}
|
|
127
|
+
const numFlag = (name: string): number | undefined | null => {
|
|
128
|
+
const idx = args.indexOf(name)
|
|
129
|
+
if (idx === -1) return undefined
|
|
130
|
+
const n = Number(args[idx + 1])
|
|
131
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
132
|
+
process.stderr.write(`shard: invalid ${name} ${args[idx + 1]} (want a positive number)\n`)
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
return n
|
|
136
|
+
}
|
|
137
|
+
const budget = numFlag('--budget')
|
|
138
|
+
if (budget === null) return 2
|
|
139
|
+
const maxFiles = numFlag('--max-files')
|
|
140
|
+
if (maxFiles === null) return 2
|
|
141
|
+
// `shardDiff` tolerates a missing diff.patch (setup calls it before the diff
|
|
142
|
+
// can exist) and mkdirs `shards/` on the way, so a typo'd run directory would
|
|
143
|
+
// otherwise be invented on disk and reported as a successful zero-shard split.
|
|
144
|
+
const { stat } = await import('node:fs/promises')
|
|
145
|
+
const isRunDir = await stat(runDir)
|
|
146
|
+
.then((s) => s.isDirectory())
|
|
147
|
+
.catch(() => false)
|
|
148
|
+
if (!isRunDir) {
|
|
149
|
+
process.stderr.write(`shard: no such run directory: ${runDir}\n`)
|
|
150
|
+
return 2
|
|
151
|
+
}
|
|
152
|
+
const { shardDiff } = await import('../scripts/shard.ts')
|
|
153
|
+
const manifest = await shardDiff(runDir, {
|
|
154
|
+
...(budget !== undefined ? { budget } : {}),
|
|
155
|
+
...(maxFiles !== undefined ? { maxFiles } : {}),
|
|
156
|
+
})
|
|
157
|
+
process.stdout.write(
|
|
158
|
+
`${manifest.shards.length} shard(s), ${manifest.totalFiles} files, ${manifest.totalLines} patch lines\n`,
|
|
159
|
+
)
|
|
160
|
+
return 0
|
|
161
|
+
},
|
|
119
162
|
render: async (args) => {
|
|
120
163
|
const runDir = args[0]
|
|
121
164
|
const page = args[1]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"purpose": "Adds bounded retries to the upload path so transient S3 failures stop surfacing to end users as hard errors.",
|
|
3
|
+
"changes": [
|
|
4
|
+
"Wraps the S3 put call in a bounded retry with jittered backoff",
|
|
5
|
+
"Threads a per-request deadline through the storage client",
|
|
6
|
+
"Adds a metrics counter for exhausted retry budgets"
|
|
7
|
+
],
|
|
8
|
+
"subsystems": [
|
|
9
|
+
{ "name": "upload", "role": "owns the client-facing put path" },
|
|
10
|
+
{ "name": "storage-client", "role": "wraps the S3 SDK and owns timeouts" }
|
|
11
|
+
],
|
|
12
|
+
"watchItems": [
|
|
13
|
+
"The PR body claims the retry is idempotent, but no idempotency key is sent with the put"
|
|
14
|
+
],
|
|
15
|
+
"unclear": [
|
|
16
|
+
"Whether the new per-request deadline interacts correctly with the outer HTTP timeout"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Fake gh whose `pr diff` refuses to serve, the way GitHub does above ~300
|
|
3
|
+
# files. MAGPIE_FAKE_HEAD_OID lets a test point pr.json at a real local commit.
|
|
4
|
+
# MAGPIE_FAKE_DIFF_MODE=fail (default) exits non-zero; =empty exits 0 with no
|
|
5
|
+
# output, which is the truncation case fetchPr also has to catch.
|
|
6
|
+
case "$1 $2" in
|
|
7
|
+
"pr view")
|
|
8
|
+
cat <<JSON
|
|
9
|
+
{
|
|
10
|
+
"number": 7,
|
|
11
|
+
"title": "Fake big PR",
|
|
12
|
+
"headRefName": "feature-x",
|
|
13
|
+
"baseRefName": "main",
|
|
14
|
+
"headRefOid": "${MAGPIE_FAKE_HEAD_OID:-deadbeefdeadbeefdeadbeefdeadbeefdeadbeef}",
|
|
15
|
+
"baseRefOid": "cafebabecafebabecafebabecafebabecafebabe",
|
|
16
|
+
"author": { "login": "octocat" },
|
|
17
|
+
"body": "Fake body",
|
|
18
|
+
"url": "https://github.com/octocat/Hello-World/pull/7",
|
|
19
|
+
"files": [
|
|
20
|
+
{ "path": "a.ts", "additions": 1, "deletions": 1, "changeType": "modified" }
|
|
21
|
+
],
|
|
22
|
+
"commits": [],
|
|
23
|
+
"closingIssuesReferences": []
|
|
24
|
+
}
|
|
25
|
+
JSON
|
|
26
|
+
;;
|
|
27
|
+
"pr diff")
|
|
28
|
+
if [ "${MAGPIE_FAKE_DIFF_MODE:-fail}" = "empty" ]; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
echo "the diff exceeded the maximum number of files (300) (HTTP 406)" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
;;
|
|
34
|
+
*)
|
|
35
|
+
echo "fake-gh-nodiff: unsupported args: $*" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
;;
|
|
38
|
+
esac
|
|
@@ -19,6 +19,20 @@ case "$1 $2" in
|
|
|
19
19
|
"deletions": 0,
|
|
20
20
|
"changeType": "modified"
|
|
21
21
|
}
|
|
22
|
+
],
|
|
23
|
+
"commits": [
|
|
24
|
+
{
|
|
25
|
+
"oid": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
|
|
26
|
+
"messageHeadline": "Add retry handling to the upload path",
|
|
27
|
+
"messageBody": ""
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"closingIssuesReferences": [
|
|
31
|
+
{
|
|
32
|
+
"number": 42,
|
|
33
|
+
"title": "Uploads fail intermittently under load",
|
|
34
|
+
"url": "https://github.com/octocat/Hello-World/issues/42"
|
|
35
|
+
}
|
|
22
36
|
]
|
|
23
37
|
}
|
|
24
38
|
JSON
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Peer-review prompt
|
|
2
2
|
|
|
3
|
-
The agent substitutes the placeholders below and writes the result to `<run-dir>/peer-prompt.md`.
|
|
3
|
+
The agent substitutes the placeholders below and writes the result to `<run-dir>/peer-prompt.md`. Stage 7 then feeds that prompt to the peer reviewer: `codex exec < <run-dir>/peer-prompt.md > <run-dir>/peer.out` when codex is available, or a Claude `general-purpose` subagent (with the `magpie-peer-review-claude-preamble` prepended) writing to `<run-dir>/peer.out` when it is not.
|
|
4
4
|
|
|
5
5
|
Either way, extract the fenced `review-peer-review` block from `peer.out` and save it to `<run-dir>/peer.json`.
|
|
6
6
|
|
|
7
|
+
The filenames above are the single-batch case. Stage 7 batches above 40 findings, and
|
|
8
|
+
those runs use `peer-prompt-<k>.md` and `peer-<k>.out` per batch, one reviewer
|
|
9
|
+
invocation each, with every batch's verdicts merged into one `peer.json` after the
|
|
10
|
+
last batch. Everything below is per batch and otherwise unchanged.
|
|
11
|
+
|
|
7
12
|
## Substitute before use
|
|
8
13
|
|
|
9
14
|
Replace each `<<NAME>>` placeholder in the block below:
|
|
@@ -72,7 +77,7 @@ Rules:
|
|
|
72
77
|
|
|
73
78
|
## Claude peer-review preamble
|
|
74
79
|
|
|
75
|
-
Used only by the Claude fallback path in
|
|
80
|
+
Used only by the Claude fallback path in stage 7. Prepend this block verbatim (no substitutions) to the substituted `magpie-peer-review` prompt before dispatching the subagent. Its job is to buy back the independence you lose by using the same model family that produced the findings: the reviewer must re-derive each verdict from the diff rather than trusting the finding text, and must actively resist rubber-stamping.
|
|
76
81
|
|
|
77
82
|
````magpie-peer-review-claude-preamble
|
|
78
83
|
You are a fresh, independent second-opinion reviewer. You have no memory of, and no stake in, how the findings below were produced. They were generated by other agents that share your model family, so they may carry the same blind spots you would: do not defer to them, and do not assume they are correct because they sound confident.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Scout prompt
|
|
2
|
+
|
|
3
|
+
Stage 3 of the walkthrough dispatches one subagent from this file, before the five
|
|
4
|
+
specialists. Send the fenced `magpie-scout` block below as the agent's entire task,
|
|
5
|
+
with `<<RUN_DIR>>` and `<<PR_NUMBER>>` replaced by the real values first. The
|
|
6
|
+
subagent has no shell variables from your session, so an unexpanded path means it
|
|
7
|
+
writes the brief where nothing will read it.
|
|
8
|
+
|
|
9
|
+
Substitute `<<CODE_INTELLIGENCE>>` with `available` when the bind probe succeeded and
|
|
10
|
+
`unavailable` otherwise. The scout still runs when code-intelligence is unavailable;
|
|
11
|
+
only the subsystem map degrades.
|
|
12
|
+
|
|
13
|
+
```magpie-scout
|
|
14
|
+
You are a senior engineer building the orienting brief that five specialist
|
|
15
|
+
reviewers will read before they review PR #<<PR_NUMBER>>. You are not reviewing the
|
|
16
|
+
code. You are answering "what is this PR for, and what does it actually do".
|
|
17
|
+
|
|
18
|
+
Working directory: <<RUN_DIR>>/worktree
|
|
19
|
+
PR metadata: <<RUN_DIR>>/pr.json
|
|
20
|
+
Diff: <<RUN_DIR>>/diff.patch
|
|
21
|
+
Code intelligence: <<CODE_INTELLIGENCE>>
|
|
22
|
+
|
|
23
|
+
## What to read
|
|
24
|
+
|
|
25
|
+
1. `pr.json` for the author's stated intent: `title`, `body`, `commits[].messageHeadline`,
|
|
26
|
+
and `closingIssuesReferences[].title`. This is the claim.
|
|
27
|
+
2. `diff.patch` for what the change actually does. This is the evidence.
|
|
28
|
+
3. The worktree for surrounding context on any file the diff changes but does not
|
|
29
|
+
explain.
|
|
30
|
+
|
|
31
|
+
## Code intelligence
|
|
32
|
+
|
|
33
|
+
When the line above says `available`, the code-intelligence MCP tools are indexed
|
|
34
|
+
against `<<RUN_DIR>>/worktree`, seeded from the base repository. Call `bind_workspace`
|
|
35
|
+
with `<<RUN_DIR>>/worktree` before your first query. Use them to map where the change
|
|
36
|
+
lands:
|
|
37
|
+
|
|
38
|
+
- `get_module_summary` on each directory the diff touches, to name the subsystem and
|
|
39
|
+
say what it is responsible for.
|
|
40
|
+
- `explore_dependency_graph` on the touched modules, to say what depends on them.
|
|
41
|
+
|
|
42
|
+
If a tool returns `indexing_in_progress`, finish reading the diff and retry once. If
|
|
43
|
+
it still is not ready, or the line above says `unavailable`, write `"subsystems": []`
|
|
44
|
+
and carry on. Never call `approve_indexing`. Never call `refresh_index`. Triggering a
|
|
45
|
+
full index is a consent-gated operation that is not yours to start.
|
|
46
|
+
|
|
47
|
+
## How to reason
|
|
48
|
+
|
|
49
|
+
1. State the purpose in your own words, not the author's. If you cannot restate it
|
|
50
|
+
without quoting the PR body, you have not understood it yet.
|
|
51
|
+
2. Group the diff into 3-7 concerns. A concern is a thing a reviewer would evaluate
|
|
52
|
+
as a unit, not a file.
|
|
53
|
+
3. Compare the claim against the evidence. Where the diff does something the stated
|
|
54
|
+
intent does not cover, or omits something the stated intent implies, that is a
|
|
55
|
+
watch item.
|
|
56
|
+
4. Be honest about what you could not determine. An empty `unclear` on a large PR is
|
|
57
|
+
not credible.
|
|
58
|
+
|
|
59
|
+
## Output contract
|
|
60
|
+
|
|
61
|
+
Write `<<RUN_DIR>>/brief.json` before returning. The file MUST be a JSON object with
|
|
62
|
+
exactly these five keys:
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
"purpose": string, // 1-3 sentences: what this PR is for, in your words. Required
|
|
66
|
+
// and non-empty; a brief with no purpose is discarded whole.
|
|
67
|
+
"changes": string[], // 3-7 entries: what it actually does, grouped by concern.
|
|
68
|
+
// One clause each, no trailing period needed.
|
|
69
|
+
"subsystems": [ { "name": string, "role": string } ],
|
|
70
|
+
// Code-intelligence derived. `name` is the subsystem, `role`
|
|
71
|
+
// is one clause on what it is responsible for. [] when
|
|
72
|
+
// code intelligence is unavailable.
|
|
73
|
+
"watchItems": string[], // Where the diff and the stated intent diverge, or where the
|
|
74
|
+
// intent implies a risk the diff does not address. Often
|
|
75
|
+
// empty. See the boundary below.
|
|
76
|
+
"unclear": string[] // What you could not determine from the bundle.
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
A watch item is not a finding. You do not assign severity, you do not assign risk,
|
|
80
|
+
and you do not recommend a fix. A watch item is a pointer a specialist may escalate
|
|
81
|
+
into a finding in its own domain, with its own risk fields, or dismiss. Write it as
|
|
82
|
+
an observation: "the PR body claims X, but the diff does Y".
|
|
83
|
+
|
|
84
|
+
Do not add keys. Do not omit keys; write `[]` for an empty list. Do not transcribe
|
|
85
|
+
commit messages or issue titles into the brief: the report reads those from `pr.json`
|
|
86
|
+
directly, and repeating them wastes the specialists' attention.
|
|
87
|
+
|
|
88
|
+
Return as your final tool result a single line:
|
|
89
|
+
`brief: <N> changes, <M> subsystems, <K> watch items`. Do not include other prose.
|
|
90
|
+
```
|