@iceinvein/agent-skills 0.1.38 → 0.1.39

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.
@@ -17,7 +17,15 @@ Stop reading and follow these steps in order. Do not skip stages. Use the exact
17
17
 
18
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 repository path into `$REPO` (default: current working directory).
19
19
 
20
- Compute the run directory:
20
+ Then check whether an earlier run on this PR is still unfinished, before minting a new id:
21
+
22
+ ```
23
+ magpie --list-runs
24
+ ```
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" instead of starting over; ask the user first if it is unclear whether they want to resume or review from scratch. (`archived` ids are finished runs, not resumable.)
27
+
28
+ Otherwise compute a fresh run directory:
21
29
 
22
30
  ```
23
31
  RUN_ID="pr-${PR_NUMBER}-$(date +%s)"
@@ -38,7 +46,7 @@ When a prior run exists for the same PR (active or archived under `~/.magpie/`),
38
46
 
39
47
  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 written to `$RUN_DIR/findings/tests.json`. This is a sixth domain that flows through dedupe/critic/peer-review alongside the five LLM specialists. No specialist subagent is dispatched for it.
40
48
 
41
- The pipeline has no separate context-indexing stage, but `magpie status` and the progress page track one. After setup succeeds, append `{stage: context, status: skipped}` to `$RUN_DIR/log.jsonl` so both advance past `context`.
49
+ The pipeline has no separate context-indexing stage, but `magpie status` and the progress page track one. After setup succeeds, append `{stage: context, status: skipped}` to `$RUN_DIR/log.jsonl`; both treat a skipped stage as behind them, so the pipeline advances to `specialists`.
42
50
 
43
51
  ### 2. Serve
44
52
 
@@ -50,6 +58,8 @@ magpie serve "$RUN_DIR"
50
58
 
51
59
  Read `$RUN_DIR/state/server-info` for the URL; the server writes it asynchronously at startup, so if the file doesn't exist yet, wait a moment and re-read (it appears within ~1s). Print to the user: "Open <url> in your browser to follow along."
52
60
 
61
+ The server shuts down after 30 minutes with no requests (an open report tab heartbeats every 30s, so it stays up while the user is looking at it) and deletes `state/server-info` on the way out. Nothing in the pipeline depends on it staying alive: re-run `magpie serve "$RUN_DIR"` to bring the report back.
62
+
53
63
  Render the first progress paint:
54
64
 
55
65
  ```
@@ -58,75 +68,9 @@ magpie render "$RUN_DIR" progress
58
68
 
59
69
  ### 3. Specialists
60
70
 
61
- Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress, so the served page shows the stage as active rather than "Paused". Then dispatch the five specialist subagents in a single message using five Agent tool calls in parallel. For each focus in (security, bugs, performance, code-smells, architecture), the prompt is:
62
-
63
- ````
64
- <specialist block for focus from this SKILL.md>
65
-
66
- You are reviewing PR #<PR_NUMBER>.
67
- Working directory: $RUN_DIR/worktree
68
- Diff: $RUN_DIR/diff.patch
69
-
70
- ## Output Contract
71
-
72
- Write findings to $RUN_DIR/findings/<focus>.json before returning. The file MUST be a JSON array. Each entry MUST conform to this schema exactly (no extra top-level keys, no renamed keys):
73
-
74
- {
75
- "id": string, // e.g. "<focus>-1", "<focus>-2"; unique per focus
76
- "file": string, // path relative to worktree
77
- "line": number | null, // single integer; use null if not anchorable. NOT "lines", NOT a range string
78
- "severity": "blocker" | "high" | "medium" | "low",
79
- "risk": { // OBJECT, not a flat string
80
- "impact": "critical" | "high" | "medium" | "low",
81
- "likelihood": "likely" | "possible" | "edge-case" | "unknown",
82
- "confidence": "high" | "medium" | "low",
83
- "action": "must-fix" | "should-fix" | "consider" | "optional"
84
- },
85
- "title": string, // one line
86
- "description": string, // 2-4 short labelled paragraphs (see below). Cite code with file:line.
87
- "suggestion": { // OPTIONAL; omit the key entirely if not applicable. NOT "recommendation"
88
- "body": string, // LITERAL replacement source code for lines startLine..endLine. NOT prose. See rules below.
89
- "startLine": number,
90
- "endLine": number
91
- },
92
- "domain": "<focus>" // literal focus id, copied verbatim
93
- }
94
-
95
- **Enum values are exact strings, not free-form prose.** Every value above between `"..."` and `|` markers is a literal token. Copy them verbatim. Specifically:
96
-
97
- - `severity`, `risk.impact`, `risk.confidence` use category names (e.g. `high`, `low`), not sentences.
98
- - `risk.likelihood` describes frequency, not impact. Valid values are exactly `likely`, `possible`, `edge-case`, `unknown`. NEVER use `high`/`medium`/`low` here (those are likelihood-as-impact and will be auto-corrected, but pick the right axis).
99
- - `risk.action` is the disposition tag, not the recommendation text. Valid values are exactly `must-fix`, `should-fix`, `consider`, `optional`. The recommendation prose belongs in `description` under `Suggested direction:`, never in `risk.action`.
100
- - Keep `severity` coherent with `risk`. `severity` is the headline label: use `blocker`/`high` only with `risk.impact` of `critical`/`high` and `risk.action` of `must-fix`/`should-fix`. A `low` severity paired with `must-fix`, or a `blocker` paired with `optional`, is contradictory. The 0-10 score that gates the drop threshold is derived from `risk`, not from `severity`, so an inflated `severity` on a weak `risk` is still dropped. Set `risk` accurately rather than leaning on `severity`.
101
-
102
- Bad (will be silently coerced, do not rely on this):
103
- ```
104
- "risk": { "impact": "blocker", "likelihood": "high", "confidence": "very high", "action": "Fix this immediately before merging." }
105
- ```
106
-
107
- Good:
108
- ```
109
- "risk": { "impact": "critical", "likelihood": "likely", "confidence": "high", "action": "must-fix" }
110
- ```
111
-
112
- `description` MUST be a sequence of short labelled paragraphs separated by blank lines, using these exact prefixes when they apply:
113
-
114
- - `Observation: <one idea, what the diff actually does and where>`
115
- - `Why it matters: <impact at realistic scale or on a real user path>`
116
- - `Suggested direction: <one concrete next step, optional if the fix isn't obvious>`
117
- - `Needs verification: <what you couldn't confirm from the bundle, optional, low/medium severity only>` This labelled paragraph is the only channel for uncertainty: never hedge inside another section, and never raise `severity` to compensate for what you couldn't verify (a blocker/high you cannot stand behind is not a blocker/high). Use the exact `Needs verification:` prefix, not inline phrasing.
118
-
119
- One idea per paragraph. Do not collapse them into a single wall of text. Do not invent extra labels. If a section doesn't apply, omit it. The interactive report and the GitHub comment both parse these labels and render them as section headers, so missing labels degrade the output.
120
-
121
- **`suggestion.body` rules.** When present, `body` MUST be the literal source code that should replace lines `startLine..endLine` verbatim. It is fenced as `` ```suggestion `` on GitHub and rendered as a one-click "Apply" button; the bytes you write here get committed as-is to the PR. Therefore:
122
-
123
- - Write code only. No leading "Strip the delimiter...", "Add a check that...", or other prose. The prose explanation belongs in `description` under `Suggested direction:`.
124
- - Match the file's existing indentation and language exactly. Include only the lines being replaced; do not include unchanged surrounding context.
125
- - If you cannot produce an exact, copy-pasteable replacement (you don't know the surrounding code, the fix spans multiple files, or the change is conceptual), OMIT the `suggestion` key entirely. A prose `Suggested direction:` in `description` is the right channel for that.
126
- - Wrapping the code in a `` ``` `` fence inside `body` is tolerated (the poster hoists the inner code out), but bare code is preferred.
71
+ Read `references/specialists.md` now, before dispatching anything. It holds the five focus blocks and the output contract that every specialist prompt is built from. Assemble the prompts from that file verbatim: prompts written from memory drift off the JSON contract, and `magpie dedupe` drops findings it cannot parse.
127
72
 
128
- If you have no findings, write []. Return as your final tool result a single line: `<focus>: <N> findings (<blocker>/<high>/<medium>/<low>)`. Do not include other prose.
129
- ````
73
+ Append `{stage: specialists, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress, so the served page shows the stage as active rather than "Paused". Then dispatch the five specialist subagents in a single message using five Agent tool calls in parallel, one per focus in (security, bugs, performance, code-smells, architecture), each carrying the prompt that `references/specialists.md` describes.
130
74
 
131
75
  After each subagent returns, append `{stage: specialist, focus: <focus>, status: done, findings: <count>}` to `$RUN_DIR/log.jsonl` and re-render progress. (Per-focus `specialist` entries are diagnostic; only the aggregate `specialists` entry advances `magpie status`.)
132
76
 
@@ -146,13 +90,13 @@ Re-render progress.
146
90
 
147
91
  ### 5. Critic
148
92
 
149
- Read `$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.
93
+ 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.
150
94
 
151
95
  ### 6. Peer review
152
96
 
153
97
  Append `{stage: peer-review, status: running}` to `$RUN_DIR/log.jsonl` and re-render progress. This stage always runs. `codex` is the preferred reviewer because it is a different model from the Claude agents that produced the findings; when `codex` is unavailable, a Claude second-opinion subagent stands in.
154
98
 
155
- Build the peer-review prompt first: take the `magpie-peer-review` block from this SKILL.md and substitute the placeholders listed in its `## Substitute before use` preamble. Write the substituted prompt to `$RUN_DIR/peer-prompt.md`.
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. Write the substituted prompt to `$RUN_DIR/peer-prompt.md`.
156
100
 
157
101
  **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 with the prompt piped on stdin:
158
102
 
@@ -164,7 +108,7 @@ codex exec < "$RUN_DIR/peer-prompt.md" > "$RUN_DIR/peer.out"
164
108
 
165
109
  If codex returns non-zero, do not abort: record `{stage: peer-review, provider: codex, status: fallback, error: "<first line of stderr>"}` and fall through to the Claude path. (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.)
166
110
 
167
- **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 this SKILL.md to the substituted peer-review prompt (the preamble forces genuine independence, since the reviewer shares a model family with the primary reviewers). Dispatch one subagent (Agent tool, `general-purpose`) whose entire task is that combined prompt, and instruct it to return only the fenced `review-peer-review` JSON block. Write its output to `$RUN_DIR/peer.out`, extract the `review-peer-review` block to `$RUN_DIR/peer.json`, and append `{stage: peer-review, status: done, provider: claude}`.
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 the substituted peer-review prompt (the preamble forces genuine independence, since the reviewer shares a model family with the primary reviewers). Dispatch one subagent (Agent tool, `general-purpose`) whose entire task is that combined prompt, and instruct it to return only the fenced `review-peer-review` JSON block. Write its output to `$RUN_DIR/peer.out`, extract the `review-peer-review` block to `$RUN_DIR/peer.json`, and append `{stage: peer-review, status: done, provider: claude}`.
168
112
 
169
113
  **Apply the verdicts (both paths).** Parse the verdicts JSON and apply the `update` / `add` entries (an empty array means no change). For each `add`, mint a unique `id` on the new finding before merging (`peer-1`, `peer-2`, ...): the peer contract does not include ids, but every finding in `findings.final.json` must carry one or the report render and post stages will crash. Then write `findings.final.json`. Re-render progress.
170
114
 
@@ -176,15 +120,15 @@ magpie render "$RUN_DIR" findings
176
120
 
177
121
  Append `{stage: report, status: done}` to `$RUN_DIR/log.jsonl` and re-render progress (the render CLI does not log this itself, and `magpie status` needs the `done` entry to resume past `report`).
178
122
 
179
- Print to the terminal: "Findings ready at <url>. Click checkboxes to select what to post, then reply with `post`."
123
+ Print to the terminal: "Findings ready at <url>. Tick the ones you want and click **Post Selected**, or reply `post` here and I'll post whatever you've ticked."
180
124
 
181
125
  End the turn.
182
126
 
183
127
  ### 8. Post
184
128
 
185
- Most users will tick the checkboxes in the served report and click "Post to PR"; the report server handles the rest. The agent only handles posts when the user explicitly types `post` (optionally `post 1,3,7` for indices) in the conversation.
129
+ Most users will tick the checkboxes in the served report and click **Post Selected** (or **Post Recommended**, which takes every finding whose `risk.action` is `must-fix` or `should-fix`, skipping the `consider`/`optional` ones); the report server handles the rest and posts the batch as one GitHub review with inline threads. The agent only handles posts when the user explicitly types `post` (optionally `post 1,3,7` for indices) in the conversation, 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.
186
130
 
187
- When that happens, read `$RUN_DIR/state/events`. Fold the events 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 then deselect then select again must resolve to selected.) Merge with any explicit indices the user named (1-based, against `findings.final.json` in file order). Then post via the CLI:
131
+ When the user types `post`, read `$RUN_DIR/state/events`. Fold the events 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 then deselect then select again must resolve to selected.) Merge with any explicit indices the user named (1-based, against `findings.final.json` in file order). If that leaves nothing selected, say so and ask rather than posting an empty batch. Then post via the CLI:
188
132
 
189
133
  ```
190
134
  magpie post "$RUN_DIR" --ids id1,id2,id3
@@ -218,467 +162,22 @@ The archived `findings.html` is self-contained and auto-switches to read-only "a
218
162
  - `magpie serve <id>` re-spins the Bun server against an archived run if the user wants the live interactive surface back (posts still work because `pr.json` retains the head SHA).
219
163
  - `magpie --list-runs` enumerates all runs in `~/.magpie/`.
220
164
 
221
- ## Specialist prompts
222
-
223
- ### security
224
-
225
- ```magpie-specialist-security
226
- You are a senior application security engineer reviewing this pull request.
227
-
228
- ## What to look for
229
-
230
- Inspect every changed line for these vulnerability classes:
231
-
232
- **Injection attacks**
233
- - SQL injection: string concatenation in queries, missing parameterized statements
234
- - Command injection: user input flowing into shell commands, execFile(), spawn()
235
- - Template injection: unsanitized data in template engines
236
- - XSS: unescaped output in HTML/JSX, unsafe innerHTML usage, React dangerouslySetInnerHTML
237
- - Path traversal: user-controlled file paths without canonicalization or allowlist
238
- - SSRF: user-controlled URLs passed to fetch/http requests without validation
239
- - Deserialization: untrusted data passed to JSON.parse in security-sensitive contexts
240
-
241
- **Authentication & authorization**
242
- - Missing auth checks on new endpoints or IPC handlers
243
- - Privilege escalation: actions that bypass permission boundaries
244
- - Broken access control: one user accessing another's resources
245
- - Session management issues: predictable tokens, missing expiry, no invalidation
246
- - Tenant isolation violations in multi-user contexts
247
-
248
- **Secrets & credentials**
249
- - Hardcoded API keys, tokens, passwords, or connection strings
250
- - Secrets logged to console or persisted in plaintext
251
- - Credentials in URLs or query parameters
252
- - Missing encryption for sensitive data at rest or in transit
253
-
254
- **Cryptography**
255
- - Weak algorithms (MD5, SHA1 for security purposes, DES)
256
- - Missing or predictable IVs/nonces
257
- - Custom crypto implementations instead of vetted libraries
258
- - Insufficient key lengths
259
-
260
- **Data safety**
261
- - Sensitive data in error messages or logs (PII, tokens, passwords)
262
- - Missing input validation at system boundaries (user input, external APIs, IPC)
263
- - Missing output encoding when crossing trust boundaries
264
- - Overly permissive CORS, CSP, or security headers
265
- - Insecure defaults that require opt-in for safety
266
-
267
- ## How to reason
268
-
269
- For each potential finding:
270
- 1. Trace the data flow: where does the input originate, how does it reach the sink?
271
- 2. Identify the trust boundary: is this crossing from untrusted to trusted context?
272
- 3. Assess exploitability: can an attacker realistically trigger this?
273
- 4. Evaluate impact: what's the blast radius if exploited?
274
-
275
- **Risk guide:**
276
- - blocker: Realistic path to remote code execution, auth bypass, data breach, or privilege escalation
277
- - high: Exploitable vulnerability or secrets exposure that should be fixed before merge
278
- - medium: Defense-in-depth concern or validation gap with limited or uncertain exploitability
279
- - low: Minor hardening opportunity with low impact
280
-
281
- Report only credible concerns grounded in code shown. If a concern depends on context you can't see, surface it in a `Needs verification:` paragraph (see the orchestrator's Output Contract) rather than inflating severity to compensate. Do not invent vulnerabilities without evidence.
282
-
283
- Boundary with Architecture: report missing input validation here when it enables an attack (injection, path traversal, SSRF, auth bypass). Leave purely structural questions of where validation should live to Architecture.
284
-
285
- Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
286
- ```
287
-
288
- ### bugs
289
-
290
- ```magpie-specialist-bugs
291
- You are a senior software engineer specialized in finding bugs through code review.
292
-
293
- ## What to look for
294
-
295
- **Logic errors**
296
- - Off-by-one mistakes in loops, slicing, indexing, and boundary checks
297
- - Inverted or missing conditions (wrong boolean logic, missing null checks)
298
- - Incorrect operator precedence or type coercion surprises
299
- - State machine violations: impossible states that aren't prevented
300
-
301
- **Concurrency & timing**
302
- - Race conditions in async code: check-then-act without atomicity
303
- - Shared mutable state accessed from multiple async paths
304
- - Missing await on promises (fire-and-forget that should be awaited)
305
- - Event listener leaks: subscriptions without cleanup
306
-
307
- **Null safety & type issues**
308
- - Null/undefined dereferences hidden by optional chaining that should fail loudly
309
- - Type assertions (as) that mask real type mismatches
310
- - Array access without bounds checking on dynamic indices
311
- - Destructuring that assumes shape of external data
312
-
313
- **Error handling**
314
- - Catch blocks that swallow errors silently (empty catch, catch that only logs)
315
- - Error recovery that leaves state inconsistent (partial updates before throw)
316
- - Missing error propagation: async errors that vanish
317
- - Try-catch scope too broad: catching exceptions meant for callers
318
-
319
- **Resource management**
320
- - File handles, connections, or subscriptions not cleaned up in finally/dispose
321
- - Missing cleanup on component unmount or session end
322
- - Unbounded growth: arrays/maps that grow without eviction
323
-
324
- **Data integrity**
325
- - Stale closures capturing outdated state
326
- - Mutation of objects that should be immutable (shared references)
327
- - Incorrect merge/spread that drops or overwrites fields
328
- - JSON.parse without error handling on untrusted input
329
-
330
- ## How to reason
331
-
332
- For each potential bug:
333
- 1. What's the precondition that triggers it?
334
- 2. Is this reachable in normal usage or only edge cases?
335
- 3. What's the consequence: crash, data corruption, silent wrong behavior?
336
- 4. Is there an existing guard I'm not seeing?
337
-
338
- **Risk guide:**
339
- - blocker: Data loss, data corruption, broken auth/session behavior, or consistently crashing a major workflow
340
- - high: Reachable incorrect behavior, race, resource leak, or crash in a meaningful workflow
341
- - medium: Edge-case bug or missing guard with limited blast radius
342
- - low: Very small correctness cleanup with low user impact
343
-
344
- Prioritize bugs that cause silent wrong behavior over those that crash (crashes are at least visible). When you can't determine reachability from the diff alone, say so in a `Needs verification:` paragraph (see the orchestrator's Output Contract) rather than inflating severity.
345
-
346
- Boundary with Performance: report leaks, unbounded growth, and missing cleanup here only when the primary consequence is incorrect behavior, a crash, or resource exhaustion that breaks a workflow. When the primary consequence is latency, throughput, or memory cost at scale, leave it to Performance.
347
-
348
- Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
349
- ```
350
-
351
- ### performance
352
-
353
- ```magpie-specialist-performance
354
- You are a senior performance engineer reviewing this pull request.
355
-
356
- ## What to look for
357
-
358
- **Algorithmic complexity**
359
- - O(n squared) or worse patterns hidden in nested loops over data that could grow
360
- - Repeated linear scans where a Map/Set lookup would be O(1)
361
- - Sorting or filtering the same dataset multiple times unnecessarily
362
- - Missing early exits in search/filter operations
363
-
364
- **Rendering & reactivity (frontend)**
365
- - Components re-rendering on every parent render due to missing memoization
366
- - New object/array/function references created every render (inline objects in JSX props, arrow functions in render)
367
- - useMemo/useCallback with incorrect or missing dependency arrays
368
- - Large lists rendered without virtualization
369
- - Layout thrashing: reads and writes to DOM interleaved in loops
370
-
371
- **Data fetching & I/O**
372
- - N+1 query patterns: fetching related data in a loop instead of batch
373
- - Missing pagination or unbounded result sets
374
- - Redundant API calls: same data fetched multiple times without caching
375
- - Synchronous I/O on hot paths that could be async
376
- - Missing request deduplication for concurrent identical requests
377
-
378
- **Memory**
379
- - Unbounded caches or maps that grow without eviction strategy
380
- - Large data structures held in memory when only a subset is needed
381
- - Closures capturing large scopes unnecessarily
382
- - Event listeners or subscriptions never removed
383
-
384
- **Bundling & loading**
385
- - Large dependencies imported for small utility functions
386
- - Missing code splitting for routes or heavy components
387
- - Synchronous imports that could be lazy-loaded
388
-
389
- ## How to reason
390
-
391
- For each potential issue:
392
- 1. What's the data size at scale? (10 items is fine, 10,000 is not)
393
- 2. How often does this code path execute? (once on init vs. every keystroke)
394
- 3. What's the measurable impact? (milliseconds vs. seconds)
395
- 4. Is the optimization worth the complexity cost?
396
-
397
- **Risk guide:**
398
- - blocker: Change can make a major workflow unusable or cause unbounded production resource exhaustion
399
- - high: Realistic scale causes visible latency, memory growth, redundant network/database load, or render jank
400
- - medium: Likely worthwhile performance improvement on a warm path
401
- - low: Tiny cleanup only when it removes clear waste without added complexity
402
-
403
- Only flag issues that would have noticeable impact at realistic scale. Don't suggest micro-optimizations on cold paths.
404
-
405
- Boundary with Bugs: focus on cost at realistic scale. Leave correctness failures and crashes caused by the same leak or unbounded growth to Bugs.
406
-
407
- Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
408
- ```
409
-
410
- ### code-smells
411
-
412
- ```magpie-specialist-code-smells
413
- You are a senior engineer reviewing this pull request for code smells and maintainability risks.
414
-
415
- ## What to look for
416
-
417
- **Duplication & parallel change**
418
- - Copy-pasted logic that will drift across files, handlers, components, or tests
419
- - Parallel conditionals or switch branches that should share a table, helper, or data model
420
- - Same validation, parsing, mapping, or formatting rules reimplemented in multiple places
421
- - Tests duplicating implementation details instead of describing behavior
422
-
423
- **Brittle complexity**
424
- - Long functions with multiple responsibilities or several levels of branching
425
- - Boolean flag parameters or mode strings that create hidden behavior matrices
426
- - Deeply nested control flow where guard clauses or extracted steps would make failure paths clear
427
- - Large expressions that encode domain logic without named concepts
428
- - Accidental complexity added for a narrow case where simpler local code would be easier to maintain
429
-
430
- **Poor abstractions**
431
- - Primitive obsession: repeated raw strings, numbers, or object shapes that should be typed or named
432
- - Stringly typed state, event names, or IDs where an enum/union/constant already exists or is warranted
433
- - Leaky abstractions that force callers to know storage, transport, UI, or framework details
434
- - Abstractions that are too broad, too generic, or have only one real caller
435
- - Data clumps: the same group of parameters passed through multiple functions
436
-
437
- **Coupling & side effects**
438
- - Hidden mutation of shared data, module-level state, or objects owned by callers
439
- - Temporal coupling: functions that only work if called in a specific undocumented order
440
- - Action at a distance: changes in one branch unexpectedly affecting unrelated behavior
441
- - Feature envy: code reaching into another module/component instead of asking through a clear interface
442
- - Shotgun surgery: a small future change would require edits in many unrelated places
443
-
444
- **Testability & local reasoning**
445
- - Code that is hard to unit test because I/O, time, randomness, or global state is embedded in logic
446
- - Missing seams around expensive or external dependencies when the change adds non-trivial branching
447
- - Invariants that are implied by comments or call order instead of represented in types or checks
448
- - Error paths that are hard to exercise or reason about because responsibilities are tangled
449
-
450
- ## How to reason
451
-
452
- For each potential smell:
453
- 1. Identify the concrete maintenance failure it creates: drift, fragile edits, unclear ownership, or hard-to-test behavior.
454
- 2. Confirm the smell is introduced or materially worsened by this PR, not merely pre-existing nearby code.
455
- 3. Suggest the smallest refactor that fits the surrounding codebase patterns.
456
- 4. Weigh the cost: do not ask for a new abstraction unless it reduces real duplication, coupling, or reasoning burden now.
457
-
458
- **Risk guide:**
459
- - blocker: Smell creates a high-risk maintenance trap likely to cause defects across modules soon
460
- - high: Meaningful maintainability issue that should be addressed before merge
461
- - medium: Local refactor that would materially improve clarity or reduce future drift
462
- - low: Minor cleanup only when the fix is trivial and directly tied to changed code
463
-
464
- Do not flag formatting, naming, or stylistic preference unless it is evidence of a deeper maintainability problem. Avoid duplicating bug, security, or performance findings unless the primary issue is the maintainability smell behind them.
465
-
466
- Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
467
- ```
468
-
469
- ### architecture
470
-
471
- ```magpie-specialist-architecture
472
- You are a senior software architect reviewing this pull request for design quality.
473
-
474
- ## What to look for
475
-
476
- **Separation of concerns**
477
- - Business logic mixed with UI rendering or I/O
478
- - Data access scattered instead of centralized behind a clear interface
479
- - Cross-cutting concerns (logging, auth, validation) tangled into business logic
480
- - Single file or function taking on too many responsibilities
481
-
482
- **Coupling & cohesion**
483
- - Tight coupling: module A reaching deep into module B's internals
484
- - Inappropriate dependencies: lower-level module depending on higher-level one
485
- - Circular dependencies between modules
486
- - Shared mutable state that couples otherwise independent components
487
- - Leaky abstractions: implementation details exposed in public interfaces
488
-
489
- **API & contract design**
490
- - Inconsistent API contracts across similar endpoints/handlers
491
- - Missing input validation at module boundaries
492
- - Overly permissive interfaces that accept more than needed
493
- - Return types that force callers to handle implementation details
494
- - Breaking changes to existing contracts without migration path
495
-
496
- **Extensibility & change readiness**
497
- - Hardcoded values that should be configurable
498
- - Switch/if-else chains that will grow with each new variant (should be polymorphic or data-driven)
499
- - Missing abstraction layers that would isolate from future changes
500
- - Over-engineering: abstractions for things that don't vary
501
-
502
- **Data flow & state management**
503
- - Unclear ownership of state (who is the source of truth?)
504
- - Derived state stored separately instead of computed
505
- - Prop drilling through many layers instead of proper state management
506
- - Inconsistent data flow direction (sometimes push, sometimes pull)
507
-
508
- ## How to reason
509
-
510
- For each potential issue:
511
- 1. What change would be hard because of this design decision?
512
- 2. Is this coupling necessary or incidental?
513
- 3. Would a new team member understand where to make changes?
514
- 4. Is this over-engineered for the current requirements, or appropriately future-proofed?
515
-
516
- **Risk guide:**
517
- - blocker: Change introduces a serious boundary violation or contract break likely to cascade across subsystems
518
- - high: Design issue that will make near-term feature work, integration, or migration materially harder
519
- - medium: Local design adjustment that clarifies ownership, contracts, or state flow
520
- - low: Avoid for architecture findings unless the design cleanup is nearly free
521
-
522
- Boundary with Code Smells: focus on module boundaries, public contracts, ownership, and system-level data flow. Leave local implementation smells such as duplicate branches, long functions, and primitive obsession to Code Smells.
523
-
524
- Boundary with Security: flag validation gaps as design/contract issues (where validation belongs, which boundary should enforce it). Leave exploitability assessment to Security.
525
-
526
- Focus on design decisions introduced or materially worsened by this PR that affect the long-term health of the codebase. Don't flag things that are "technically impure" but work well in practice.
527
-
528
- Use the JSON schema defined in the orchestrator's `## Output Contract` block; do not invent fields.
529
- ```
530
-
531
- ## Critic rubric
532
-
533
- The main agent runs this in-conversation against `findings.deduped.json` and writes the kept subset to `findings.kept.json`.
534
-
535
- ## Substitute before use
536
-
537
- The block below contains two placeholders. Replace both before running the rubric. (The `jq` one-liners here and in the peer-review substitutions assume `jq` is on PATH; it is not preflighted. If missing, read the JSON with any tool you have and produce the same shape.)
538
-
539
- - `<<DEDUPED_FINDINGS_COMPACT>>` — pretty-printed JSON array of the deduped candidates with only the fields the critic needs. Each candidate carries `onChangedLine` (set deterministically during dedupe: `true` = anchored inside a changed hunk, `false` = anchored on code the PR did not touch, `null` = not anchorable). Build with:
540
- ```
541
- jq '[.[] | {id, file, line, onChangedLine, severity, risk, domain, title, description}]' "$RUN_DIR/findings.deduped.json"
542
- ```
543
- - `<<DIFF_EXCERPT>>` — the diff hunks for the files referenced by the candidates. For small PRs the full `diff.patch` is fine; for larger PRs, narrow to the files named in the candidate set.
544
-
545
- ````magpie-critic
546
- You are a senior code reviewer auditing a list of candidate review findings produced by other agents on a pull request. Your only job is to keep the findings that a busy reviewer would genuinely thank you for surfacing, and drop the rest. You see each candidate's claim, anchor, and risk fields, plus the diff hunks around them. Use the hunks only to validate or refute the candidate in front of you: do not surface new findings or broaden the review (adding issues is the peer-review stage's job). Treat each candidate skeptically.
547
-
548
- Drop a finding if any of the following hold:
549
- - The description sounds speculative, hedged, or "needs verification" without strong evidence in the title or anchor.
550
- - The finding is a stylistic preference, micro-optimization, or "nice to have" cleanup with no concrete user or maintenance impact.
551
- - Its `onChangedLine` is `false` and the description does not explain why the PR newly triggers a pre-existing concern (i.e. it is anchored on code this PR did not change).
552
- - The finding is a theoretical risk that requires unlikely preconditions, or defense-in-depth on code the supplied hunks show is already guarded.
553
- - The finding belongs to a category the repository's linter already enforces (naming, formatting, unused imports).
554
- - The finding is on a test file or a generated/vendored file unless it materially affects test correctness.
555
-
556
- Keep a finding if it points to a concrete defect on a changed line, with enough specificity that a reviewer could decide to act on it without re-reading the entire PR.
557
-
558
- When in doubt, drop. The cost of a false positive is several minutes of reviewer attention; the cost of a false negative is the issue surfacing in human review or production.
559
-
560
- For each candidate below, decide whether to keep it or drop it.
561
-
562
- ## Output Contract
563
-
564
- Output a JSON array inside a fenced code block tagged `review-critic`. Each entry must be:
565
- - `id`: the candidate id (string, copied verbatim)
566
- - `verdict`: "keep" or "drop"
567
- - `reason`: one short sentence (under 18 words) explaining why
568
-
569
- Output every candidate exactly once. Do not invent ids. Do not output anything outside the fenced block.
570
-
571
- ```review-critic
572
- [
573
- { "id": "<copy id from input>", "verdict": "keep", "reason": "concrete null-deref on changed line, anchored, low ambiguity" },
574
- { "id": "<copy id from input>", "verdict": "drop", "reason": "stylistic preference, no behavioural impact" }
575
- ]
576
- ```
577
-
578
- ## Candidates
579
- ```json
580
- <<DEDUPED_FINDINGS_COMPACT>>
581
- ```
582
-
583
- ## Diff Hunks For Those Candidates
584
- ```diff
585
- <<DIFF_EXCERPT>>
586
- ```
587
- ````
588
-
589
- ## Peer-review prompt
590
-
591
- The agent substitutes the placeholders below and writes the result to `<run-dir>/peer-prompt.md`. Step 6 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.
592
-
593
- Either way, extract the fenced `review-peer-review` block from `peer.out` and save it to `<run-dir>/peer.json`.
594
-
595
- ## Substitute before use
596
-
597
- Replace each `<<NAME>>` placeholder in the block below:
598
-
599
- - `<<PRIMARY_PROVIDER>>` — the agent that produced the findings (e.g. `claude`).
600
- - `<<PEER_PROVIDER>>` — the agent auditing the review (e.g. `codex`).
601
- - `<<PR_TITLE>>` — `jq -r .title < $RUN_DIR/pr.json`
602
- - `<<PR_AUTHOR>>` — `jq -r .author.login < $RUN_DIR/pr.json`
603
- - `<<PR_HEAD_BRANCH>>` — `jq -r .headRefName < $RUN_DIR/pr.json`
604
- - `<<PR_BASE_BRANCH>>` — `jq -r .baseRefName < $RUN_DIR/pr.json`
605
- - `<<PR_FILES_CHANGED>>` — `grep -c '^diff --git' $RUN_DIR/diff.patch`
606
- - `<<KEPT_FINDINGS_COMPACT>>` — pretty-printed JSON array of kept findings with the fields codex needs:
607
- ```
608
- jq '[.[] | {id, file, line, severity, risk, domain, title, description}]' "$RUN_DIR/findings.kept.json"
609
- ```
610
- - `<<DIFF_EXCERPT>>` — the diff hunks containing the kept findings. For small PRs, the full `diff.patch` is fine. For larger PRs, narrow to the files referenced by `findings.kept.json`.
611
-
612
- ````magpie-peer-review
613
- You are the second-opinion reviewer for a PR review. <<PRIMARY_PROVIDER>> produced the findings; <<PEER_PROVIDER>> is auditing that review.
614
-
615
- Do not run a broad PR review. Inspect only the listed findings and the supplied diff hunks around them.
616
- Return no changes unless a finding has a material issue or a directly adjacent issue is clearly visible while validating it.
617
- Do not rewrite for tone, preference, or completeness. Do not emit confirmations.
618
- Use "update" only when an existing finding is materially wrong, under/overstates risk, has a wrong anchor, or is missing a crucial correction.
619
- Use "add" only for a clear, actionable issue visible in the provided hunks that is absent from the current findings.
620
- Do not drop findings in this pass. If nothing needs changing, return an empty array.
621
-
622
- Review this review, not the full PR.
623
-
624
- ## PR
625
- - Title: <<PR_TITLE>>
626
- - Author: <<PR_AUTHOR>>
627
- - Branch: <<PR_HEAD_BRANCH>> -> <<PR_BASE_BRANCH>>
628
- - Files changed: <<PR_FILES_CHANGED>>
629
-
630
- ## Current Findings
631
- ```json
632
- <<KEPT_FINDINGS_COMPACT>>
633
- ```
634
-
635
- ## Diff Hunks For Those Findings
636
- ```diff
637
- <<DIFF_EXCERPT>>
638
- ```
639
-
640
- ## Output Contract
641
-
642
- Output a JSON array inside a fenced code block tagged `review-peer-review`.
643
-
644
- Allowed entries:
645
- - Update an existing finding:
646
- { "type": "update", "id": "<existing finding id>", "reason": "material reason", "fields": { "severity": "medium", "risk": { "impact": "medium", "likelihood": "possible", "confidence": "high", "action": "consider" }, "line": 42, "title": "...", "description": "...", "suggestion": null } }
647
- - Add a missing adjacent issue:
648
- { "type": "add", "reason": "why the original review missed a real issue", "finding": { "file": "src/app.ts", "line": 42, "severity": "high", "risk": { "impact": "high", "likelihood": "possible", "confidence": "high", "action": "should-fix" }, "domain": "bugs", "title": "...", "description": "Observation: ...\n\nWhy it matters: ...\n\nSuggested direction: ..." } }
649
-
650
- Rules:
651
- - Output [] when the existing review is acceptable.
652
- - Do not include unchanged findings.
653
- - Do not add issues outside the supplied hunks.
654
- - Do not use "add" to express a general opinion about review quality.
655
-
656
- ```review-peer-review
657
- []
658
- ```
659
- ````
660
-
661
- ## Claude peer-review preamble
662
-
663
- Used only by the Claude fallback path in step 6. 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.
664
-
665
- ````magpie-peer-review-claude-preamble
666
- 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.
667
-
668
- Ground every verdict in the diff hunks provided, not in the prose of the finding. For each finding, independently re-derive whether the described problem is actually present on the cited line before you accept it. If a finding's reasoning does not hold against the hunk, or the anchor is wrong, or the severity is off, say so with "update"; if you can see a clearly actionable adjacent issue in the same hunks that was missed, add it. When the existing finding survives your own check unchanged, leave it alone.
669
-
670
- Hold yourself to the exact same output contract and constraints described below. Return [] when the review is already sound.
671
- ````
672
-
673
165
  ## Resuming a crashed run
674
166
 
675
- If the user re-invokes the skill and a `$RUN_DIR/state/server-info` exists:
167
+ A run is resumable while `$RUN_DIR/log.jsonl` exists and the run has not been archived. Do not test for `state/server-info`: the server deletes it whenever it stops, so a perfectly resumable run fails that check. Step 0 finds the run directory via `magpie --list-runs` when you don't already have it in `$RUN_DIR`.
676
168
 
677
169
  ```
678
170
  magpie status "$RUN_DIR"
679
171
  ```
680
172
 
681
- The JSON output tells you `lastCompleted` and `next`. Resume from `next`. If a specialist focus has no findings file but its sibling stages are done, re-dispatch only that focus.
173
+ The JSON output tells you `lastCompleted` and `next`. Resume from `next`:
174
+
175
+ - `context` is a no-op. Append `{stage: context, status: skipped}` and continue at `specialists`.
176
+ - 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, re-dispatch only that focus.
178
+ - Non-null `error` means the run stopped on a failed stage. Report which stage to the user and confirm before re-running it.
179
+
180
+ The server from the original run is gone. Restart it with `magpie serve "$RUN_DIR"` (step 2) before re-rendering, so the user gets a live URL again.
682
181
 
683
182
  ## Aborting
684
183
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magpie",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {