@iceinvein/agent-skills 0.10.1 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
package/skills/index.json CHANGED
@@ -221,7 +221,7 @@
221
221
  "name": "magpie",
222
222
  "description": "Interactive PR review pipeline. Runs five parallel specialist subagents (security, bugs, performance, code-smells, architecture), dedupes findings, applies a critic rubric, peer-reviews via codex exec (falling back to a Claude second opinion when codex is unavailable), and serves an interactive HTML report for selecting findings to post via gh. Bundles a Bun CLI installed onto PATH via the skill's postinstall step. Use when the user asks to review a GitHub pull request. Splits oversized diffs into budgeted shards and rebuilds the diff from the local clone when gh pr diff refuses it.",
223
223
  "type": "prompt",
224
- "version": "0.10.1"
224
+ "version": "0.11.0"
225
225
  },
226
226
  {
227
227
  "name": "migrate",
@@ -283,7 +283,7 @@
283
283
  "name": "sluice",
284
284
  "description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries seven rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment and one status command can answer where the run is, and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Claude Code only; stands down where the superpowers pipeline governs the repo.",
285
285
  "type": "prompt",
286
- "version": "0.12.1"
286
+ "version": "0.12.2"
287
287
  },
288
288
  {
289
289
  "name": "temporal-coupling-detector",
@@ -12,7 +12,7 @@ Given a GitHub PR number, dispatches five specialist subagents in parallel (secu
12
12
  - `gh` on PATH, authenticated (`gh auth status`)
13
13
  - `git` on PATH
14
14
  - `codex` on PATH, authenticated (optional; if absent the peer-review stage falls back to a Claude second-opinion subagent)
15
- - the code-intelligence MCP server, with a completed index for the repo under review (optional; if absent the specialists review from the diff and worktree alone)
15
+ - code intelligence, with a completed index for the repo under review (optional; if absent the specialists review from the diff and worktree alone). Either interface works: the `code-intel` CLI on PATH, which is preferred because it takes `--repo` per call and needs no session binding, or the code-intelligence MCP server
16
16
 
17
17
  ## Install
18
18
 
@@ -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). 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"]}`).
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. Code intelligence is not pre-flighted: stage 3 probes for it, over either the `code-intel` CLI or the code-intelligence MCP server, and the run continues without it. 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
 
@@ -85,16 +85,17 @@ magpie render "$RUN_DIR" progress
85
85
 
86
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
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.
88
+ **Probe.** Code intelligence reaches the same on-device daemon through two interfaces. Prefer the `code-intel` CLI: it takes `--repo` on every call, so it holds no session binding to leak past cleanup and the specialists can query in parallel without clobbering each other's workspace. `$RUN_DIR/worktree` is a linked git worktree either way, so an already-indexed base repo seeds its index instead of re-indexing.
89
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.
90
+ - **CLI**, when `command -v code-intel` succeeds. Run `code-intel index status --repo "$RUN_DIR/worktree" --json` and read `.status`: `ok` sets `CODE_INTELLIGENCE=cli`. `indexing_started` or `indexing_in_progress` means the seed took, so poll the same command every 5s for at most 60s and set `CODE_INTELLIGENCE=cli` either way. Exit 3 is a stopped daemon: run `code-intel start`, re-probe once. **Never run `code-intel index approve`.**
91
+ - **MCP**, when the CLI is absent but `mcp__code-intelligence__*` tools are in your tool list. Call `bind_workspace` with `$RUN_DIR/worktree` and apply the same rules, polling `get_index_stats` instead, to set `CODE_INTELLIGENCE=mcp`. **Never call `approve_indexing`.**
92
+ - `consent_required` on either interface means the base repo has never completed an index, and starting one is a full GPU pass the user did not ask for. That, no interface at all, or any other error that survives one retry, sets `CODE_INTELLIGENCE=unavailable`; print one line: "Code intelligence is unavailable (<reason>); specialists will review from the diff alone."
93
+
94
+ Never block the pipeline on a still-running index. The scout and specialist contracts both handle a tool that is not ready yet.
94
95
 
95
96
  **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
 
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
+ Append `{stage: context, status: done, codeIntelligence: true|false, interface: "cli"|"mcp"|"none"}` and re-render progress. If the scout returned without writing `brief.json`, append `{stage: context, status: skipped, codeIntelligence: true|false, interface: ...}` 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, and `interface` is what stage 10 reads to decide whether there is a session to rebind.
98
99
 
99
100
  ### 4. Specialists
100
101
 
@@ -147,8 +148,8 @@ gate is expected to have none. `magpie dedupe` re-checks this against the manife
147
148
  names every missing pair on stdout, as a backstop rather than a substitute.
148
149
 
149
150
  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}`.
151
+ `{stage: specialists, status: error}`, rebind code intelligence to `$REPO` if
152
+ `CODE_INTELLIGENCE=mcp` (stage 10), and stop. Otherwise mark `{stage: specialists, status: done}`.
152
153
 
153
154
  ### 5. Dedupe
154
155
 
@@ -240,7 +241,7 @@ magpie render "$RUN_DIR" findings
240
241
  magpie cleanup "$RUN_DIR" --repo "$REPO"
241
242
  ```
242
243
 
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
+ If the context stage set `CODE_INTELLIGENCE=mcp`, rebind the session now: call `bind_workspace` with `$REPO`. MCP 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. A `cli` run has nothing to rebind, because `--repo` names the workspace on every call. Either way the daemon prunes the seeded index once the worktree is gone.
244
245
 
245
246
  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.
246
247
 
@@ -261,7 +262,7 @@ magpie status "$RUN_DIR"
261
262
 
262
263
  The JSON output tells you `lastCompleted` and `next`. Resume from `next`:
263
264
 
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.
265
+ - `context` re-runs by redoing the 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.
265
266
  - Any other stage: run it as written in the walkthrough.
266
267
  - If a specialist focus has no findings file but its sibling stages are done,
267
268
  re-dispatch only that focus. On a sharded run the unit is the `(focus, shard)` pair:
@@ -274,4 +275,4 @@ The original server is gone. Restart it with `magpie serve "$RUN_DIR"` (step 2)
274
275
 
275
276
  ## Aborting
276
277
 
277
- If the user types `abort` mid-run, rebind code intelligence to `$REPO` if bound (stage 10), then run `magpie cleanup` and exit.
278
+ If the user types `abort` mid-run, rebind code intelligence to `$REPO` if `CODE_INTELLIGENCE=mcp` (stage 10), then run `magpie cleanup` and exit.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magpie",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -6,9 +6,10 @@ with `<<RUN_DIR>>` and `<<PR_NUMBER>>` replaced by the real values first. The
6
6
  subagent has no shell variables from your session, so an unexpanded path means it
7
7
  writes the brief where nothing will read it.
8
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.
9
+ Substitute `<<CODE_INTELLIGENCE>>` with the value stage 3's probe assigned: `cli` for
10
+ the `code-intel` CLI, `mcp` for the code-intelligence MCP tools, `unavailable` for
11
+ neither. The scout still runs when code intelligence is unavailable; only the
12
+ subsystem map degrades.
12
13
 
13
14
  ```magpie-scout
14
15
  You are a senior engineer building the orienting brief that five specialist
@@ -30,19 +31,33 @@ Code intelligence: <<CODE_INTELLIGENCE>>
30
31
 
31
32
  ## Code intelligence
32
33
 
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.
34
+ Unless the line above says `unavailable`, an index of `<<RUN_DIR>>/worktree`, seeded
35
+ from the base repository, is queryable. Use it for two things only: name the subsystem
36
+ each touched directory belongs to and what it is responsible for, then say what depends
37
+ on those modules.
38
+
39
+ When the line says `cli`, run the `code-intel` CLI. Every call names the workspace, so
40
+ there is nothing to bind first:
41
+
42
+ code-intel investigate --repo <<RUN_DIR>>/worktree --mode module --file-path <dir> \
43
+ --json "what is this module responsible for"
44
+ code-intel dependency-graph --repo <<RUN_DIR>>/worktree --json <symbol>
45
+
46
+ `code-intel repo-map --repo <<RUN_DIR>>/worktree --json` is the cheaper first look when
47
+ you do not yet know which directories matter. Exit 5 means no results, which is an
48
+ answer. Exit 3 means the daemon is down: stop querying and write `"subsystems": []`.
49
+
50
+ When the line says `mcp`, call `bind_workspace` with `<<RUN_DIR>>/worktree` before your
51
+ first query, then `get_module_summary` on each touched directory and
52
+ `explore_dependency_graph` on the touched modules.
53
+
54
+ If a query reports `indexing_in_progress` (the CLI returns
55
+ `error.code: workspace_unavailable` with that prefix), finish reading the diff and retry
56
+ once. If it still is not ready, or the line above says `unavailable`, write
57
+ `"subsystems": []` and carry on. Never call `approve_indexing` and never run
58
+ `code-intel index approve`; never call `refresh_index` and never run
59
+ `code-intel index refresh`. Triggering a full index is a consent-gated operation that
60
+ is not yours to start.
46
61
 
47
62
  ## How to reason
48
63
 
@@ -41,9 +41,11 @@ in an excluded file (a migration implies a model snapshot, a schema change impli
41
41
  generated types), open it and cross-check rather than treating it as out of scope.
42
42
  ```
43
43
 
44
- 5. The `magpie-codebase-intelligence` block below, verbatim, **only** when the context
45
- stage logged `codeIntelligence: true`. Omit it entirely otherwise: telling a
46
- specialist to use tools it does not have wastes a turn per specialist on discovery.
44
+ 5. One `magpie-codebase-intelligence-*` block below, verbatim, **only** when the
45
+ context stage logged `codeIntelligence: true`: the `-cli` block for
46
+ `interface: "cli"`, the `-mcp` block for `interface: "mcp"`. Omit it entirely
47
+ otherwise, and never send both: telling a specialist to use tools it does not have
48
+ wastes a turn per specialist on discovery.
47
49
  6. The brief, when `<RUN_DIR>/brief.json` exists, rendered as:
48
50
 
49
51
  ```
@@ -130,7 +132,7 @@ Good:
130
132
  - `Observation: <one idea, what the diff actually does and where>`
131
133
  - `Why it matters: <impact at realistic scale or on a real user path>`
132
134
  - `Suggested direction: <one concrete next step, optional if the fix isn't obvious>`
133
- - `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. When the codebase-intelligence tools are available and one of them could answer the question, look before you hedge. A question you resolved is not a `Needs verification:` paragraph, it is evidence: cite the file:line you found under `Observation:` and omit the paragraph entirely.
135
+ - `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. When codebase intelligence is available, over either interface, and one query could answer the question, look before you hedge. A question you resolved is not a `Needs verification:` paragraph, it is evidence: cite the file:line you found under `Observation:` and omit the paragraph entirely.
134
136
 
135
137
  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.
136
138
 
@@ -145,9 +147,67 @@ If you have no findings, write []. Return as your final tool result a single lin
145
147
 
146
148
  ## Codebase intelligence
147
149
 
148
- Include this block as part 5 only when the context stage logged `codeIntelligence: true`.
150
+ Include one of these blocks as part 5 when the context stage logged
151
+ `codeIntelligence: true`: the `-cli` block when it logged `interface: "cli"`, the
152
+ `-mcp` block when it logged `interface: "mcp"`. Both reach the same index. Never send
153
+ both: a specialist told about a verb it cannot invoke wastes turns discovering that.
149
154
 
150
- ```magpie-codebase-intelligence
155
+ ```magpie-codebase-intelligence-cli
156
+ ## Codebase intelligence
157
+
158
+ The `code-intel` CLI queries an index of this exact worktree, including the PR's own
159
+ changes. Every invocation names the workspace with `--repo <RUN_DIR>/worktree`, so
160
+ there is nothing to bind and nothing another agent can change under you. Always pass
161
+ `--json`.
162
+
163
+ These answer the cross-file questions a diff cannot:
164
+
165
+ code-intel ask --repo <RUN_DIR>/worktree --json "<question>"
166
+ A natural-language question answered with grounded evidence. Start here when you
167
+ do not yet know which symbol to pivot on.
168
+ code-intel search --repo <RUN_DIR>/worktree --context snippets --json "<query>"
169
+ Hybrid semantic and literal search. Use to check whether something already
170
+ exists before claiming the PR should add it. Hits carry `id`s.
171
+ code-intel hydrate --repo <RUN_DIR>/worktree --ids <id,id> --json
172
+ The exact bodies behind ids a search returned, without re-reading whole files.
173
+ code-intel definition --repo <RUN_DIR>/worktree --json <symbol>
174
+ The body of a symbol the diff calls but does not show.
175
+ code-intel references --repo <RUN_DIR>/worktree --json <symbol>
176
+ code-intel call-hierarchy --repo <RUN_DIR>/worktree --json <symbol>
177
+ Who calls this, and what does it call. Use for reachability: is the path you are
178
+ worried about actually reachable. Add `--direction callers|callees`, `--depth N`.
179
+ code-intel investigate --repo <RUN_DIR>/worktree --mode impact --target <symbol> --json "<question>"
180
+ The reverse-dependency set for a symbol. Use for blast radius before claiming a
181
+ change is safe or unsafe.
182
+ code-intel investigate --repo <RUN_DIR>/worktree --mode data --target <symbol> --json "<question>"
183
+ Follow a value from its origin to where it is used. Use to confirm that
184
+ untrusted input actually reaches the sink you are worried about.
185
+ code-intel dependency-graph --repo <RUN_DIR>/worktree --json <symbol>
186
+ Module-level edges. Use for cycles and boundaries.
187
+
188
+ There is no test-coverage command: to find out whether the symbol you are flagging is
189
+ covered, run `references` on it and read the paths for test files.
190
+
191
+ Exit codes are the contract, not the prose: 5 means no results, which is an answer and
192
+ not a reason to fall back to grep. 3 means the daemon is down and 4 means the workspace
193
+ is not queryable; either way, stop querying and review from the diff and worktree.
194
+
195
+ Rules:
196
+
197
+ - Cite what you find as ordinary `file:line` evidence under `Observation:`. Do not
198
+ say "code intelligence told me"; the location is the evidence.
199
+ - Verify before you report. A finding you could have refuted with one query and did
200
+ not is worse than no finding: it costs the author trust and the critic a slot.
201
+ - Verify before you hedge. If a query can answer the question, a `Needs verification:`
202
+ paragraph is a failure to look, not honest uncertainty.
203
+ - If a command fails with `error.code: workspace_unavailable` and an
204
+ `indexing_in_progress` message, finish reading the diff and retry once. If it is
205
+ still not ready, review from the diff and worktree alone. Do not block.
206
+ - Never run `code-intel index approve`. Never run `code-intel index refresh`. Starting
207
+ a full index is a consent-gated operation that is not yours to start.
208
+ ```
209
+
210
+ ```magpie-codebase-intelligence-mcp
151
211
  ## Codebase intelligence
152
212
 
153
213
  You have code-intelligence MCP tools against an index of this exact worktree,
@@ -237,7 +297,7 @@ For each potential finding:
237
297
  2. Identify the trust boundary: is this crossing from untrusted to trusted context?
238
298
  3. Assess exploitability: can an attacker realistically trigger this?
239
299
  4. Evaluate impact: what's the blast radius if exploited?
240
- 5. Confirm the flow with `trace_data_flow` from the entry point to the sink before reporting. A taint path you asserted but did not trace is a guess.
300
+ 5. Confirm the flow from the entry point to the sink before reporting, with `code-intel investigate --mode data --target <symbol>` or `trace_data_flow` depending on which interface your intelligence block describes. A taint path you asserted but did not trace is a guess.
241
301
 
242
302
  **Risk guide:**
243
303
  - blocker: Realistic path to remote code execution, auth bypass, data breach, or privilege escalation
@@ -302,7 +362,7 @@ For each potential bug:
302
362
  3. What's the consequence: crash, data corruption, silent wrong behavior?
303
363
  4. Is there an existing guard I'm not seeing?
304
364
 
305
- Question 4 is answerable: `get_call_hierarchy` on the changed symbol shows every caller, and `find_references` shows where the guard would have to live. Check before you file.
365
+ Question 4 is answerable: a call hierarchy on the changed symbol shows every caller, and its references show where the guard would have to live (`code-intel call-hierarchy` / `code-intel references`, or `get_call_hierarchy` / `find_references` on MCP). Check before you file.
306
366
 
307
367
  **Risk guide:**
308
368
  - blocker: Data loss, data corruption, broken auth/session behavior, or consistently crashing a major workflow
@@ -362,7 +422,7 @@ For each potential issue:
362
422
  2. How often does this code path execute? (once on init vs. every keystroke)
363
423
  3. What's the measurable impact? (milliseconds vs. seconds)
364
424
  4. Is the optimization worth the complexity cost?
365
- 5. Establish the call frequency with `find_affected_code` before claiming a path is hot. "Called from one cold init path" and "called per keystroke" are different findings.
425
+ 5. Establish the call frequency before claiming a path is hot, with `code-intel investigate --mode impact --target <symbol>` or `find_affected_code`. "Called from one cold init path" and "called per keystroke" are different findings.
366
426
 
367
427
  **Risk guide:**
368
428
  - blocker: Change can make a major workflow unusable or cause unbounded production resource exhaustion
@@ -424,7 +484,7 @@ For each potential smell:
424
484
  2. Confirm the smell is introduced or materially worsened by this PR, not merely pre-existing nearby code.
425
485
  3. Suggest the smallest refactor that fits the surrounding codebase patterns.
426
486
  4. Weigh the cost: do not ask for a new abstraction unless it reduces real duplication, coupling, or reasoning burden now.
427
- 5. Before claiming the PR duplicates something or should reuse an existing helper, find it with `search_code`. Name the file:line of the thing it should have reused, or do not make the claim.
487
+ 5. Before claiming the PR duplicates something or should reuse an existing helper, find it: `code-intel search --context snippets` or `search_code`. Name the file:line of the thing it should have reused, or do not make the claim.
428
488
 
429
489
  **Risk guide:**
430
490
  - blocker: Smell creates a high-risk maintenance trap likely to cause defects across modules soon
@@ -483,7 +543,7 @@ For each potential issue:
483
543
  2. Is this coupling necessary or incidental?
484
544
  3. Would a new team member understand where to make changes?
485
545
  4. Is this over-engineered for the current requirements, or appropriately future-proofed?
486
- 5. Confirm boundary and cycle claims with `explore_dependency_graph` on the touched modules. A cycle you inferred from import statements in the diff may already be broken by an interface you cannot see.
546
+ 5. Confirm boundary and cycle claims on the touched modules with `code-intel dependency-graph` or `explore_dependency_graph`. A cycle you inferred from import statements in the diff may already be broken by an interface you cannot see.
487
547
 
488
548
  **Risk guide:**
489
549
  - blocker: Change introduces a serious boundary violation or contract break likely to cascade across subsystems
@@ -117,16 +117,63 @@ test('SKILL.md no longer inlines the prompt bodies it moved out', async () => {
117
117
  expect(text).not.toContain(`\`\`\`${tag}`)
118
118
  }
119
119
  // The walkthrough is the always-read part; keep it small enough to be cheap.
120
- // Raised from 2600 when the sharded-dispatch and fallback-diff prose was added:
121
- // that's real, load-bearing procedure, not bloat.
122
- expect(text.split(/\s+/).length).toBeLessThan(3000)
120
+ // Raised from 2600 when the sharded-dispatch and fallback-diff prose was added,
121
+ // then from 3000 for the two code-intelligence interfaces: that's real,
122
+ // load-bearing procedure, not bloat.
123
+ expect(text.split(/\s+/).length).toBeLessThan(3250)
123
124
  })
124
125
 
125
126
  test('SKILL.md never instructs the agent to approve indexing', async () => {
126
127
  const text = await readFile(SKILL, 'utf8')
127
128
  // A full index is a consent-gated GPU pass. The context stage degrades instead.
129
+ // Both interfaces expose the same footgun under different names, so both are named.
128
130
  expect(text).toContain('approve_indexing')
129
131
  expect(text).toMatch(/never call `approve_indexing`|do not call `approve_indexing`/i)
132
+ expect(text).toMatch(
133
+ /never run `code-intel index approve`|do not run `code-intel index approve`/i,
134
+ )
135
+ })
136
+
137
+ test('SKILL.md stage 3 probes the code-intel CLI before the MCP tools', async () => {
138
+ const text = await readFile(SKILL, 'utf8')
139
+ const start = text.indexOf('### 3. Context')
140
+ expect(start).toBeGreaterThan(-1)
141
+ const section = text.slice(start, text.indexOf('\n### 4.', start))
142
+ // Both interfaces drive the same daemon, but the CLI names the workspace on every
143
+ // call, so it carries no session binding to leak past cleanup. Prefer it.
144
+ expect(section).toContain('command -v code-intel')
145
+ expect(section).toContain('mcp__code-intelligence__')
146
+ expect(section.indexOf('code-intel')).toBeLessThan(section.indexOf('mcp__code-intelligence__'))
147
+ })
148
+
149
+ test('SKILL.md gives CODE_INTELLIGENCE a value per interface', async () => {
150
+ const text = await readFile(SKILL, 'utf8')
151
+ // The scout and specialist prompts branch on this, so all three values must be
152
+ // spelled out where the probe assigns them.
153
+ for (const value of [
154
+ 'CODE_INTELLIGENCE=cli',
155
+ 'CODE_INTELLIGENCE=mcp',
156
+ 'CODE_INTELLIGENCE=unavailable',
157
+ ]) {
158
+ expect(text).toContain(value)
159
+ }
160
+ })
161
+
162
+ test('the rebind instruction is scoped to the MCP interface everywhere it appears', async () => {
163
+ const text = await readFile(SKILL, 'utf8')
164
+ // A CLI run holds no session binding, so an unconditional rebind sends the agent
165
+ // after an MCP tool that is not in its tool list.
166
+ const spans: ReadonlyArray<readonly [string, string]> = [
167
+ ['### 4. Specialists', '\n### 5.'],
168
+ ['### 10. Cleanup', '\n## '],
169
+ ['## Aborting', ''],
170
+ ]
171
+ for (const [from, to] of spans) {
172
+ const start = text.indexOf(from)
173
+ expect(start).toBeGreaterThan(-1)
174
+ const section = to ? text.slice(start, text.indexOf(to, start)) : text.slice(start)
175
+ expect(section).toMatch(/CODE_INTELLIGENCE=mcp|MCP path/)
176
+ }
130
177
  })
131
178
 
132
179
  test('SKILL.md logs codeIntelligence on both the done and skipped context outcomes', async () => {
@@ -295,34 +342,69 @@ test('SKILL.md has the stage walkthrough', async () => {
295
342
  expect(text).toMatch(/magpie cleanup/)
296
343
  })
297
344
 
298
- test('references/specialists.md carries the codebase-intelligence block', async () => {
345
+ const intelligenceBlock = (text: string, iface: 'cli' | 'mcp') => {
346
+ const fence = `\`\`\`magpie-codebase-intelligence-${iface}`
347
+ const start = text.indexOf(fence)
348
+ expect(start).toBeGreaterThan(-1)
349
+ return text.slice(start, text.indexOf('\n```', start + fence.length))
350
+ }
351
+
352
+ test('references/specialists.md carries a codebase-intelligence block per interface', async () => {
353
+ const text = await readFile(ref('specialists.md'), 'utf8')
354
+ for (const iface of ['cli', 'mcp'] as const) {
355
+ const block = intelligenceBlock(text, iface)
356
+ expect(block).toContain('indexing_in_progress')
357
+ // The one operation a specialist must never perform, under either name.
358
+ expect(block).toMatch(/never (call `approve_indexing`|run `code-intel index approve`)/i)
359
+ }
360
+ })
361
+
362
+ test('the CLI intelligence block names the workspace per call instead of binding', async () => {
363
+ const text = await readFile(ref('specialists.md'), 'utf8')
364
+ const block = intelligenceBlock(text, 'cli')
365
+ // The CLI has no bind_workspace: every invocation carries --repo, which is what
366
+ // lets the five specialists query the same worktree in parallel without a
367
+ // session binding they could clobber for each other.
368
+ expect(block).not.toContain('bind_workspace')
369
+ expect(block).toContain('--repo')
370
+ expect(block).toContain('--json')
371
+ })
372
+
373
+ test('the MCP intelligence block still binds the workspace first', async () => {
299
374
  const text = await readFile(ref('specialists.md'), 'utf8')
300
- expect(text).toContain('```magpie-codebase-intelligence')
301
- const start = text.indexOf('```magpie-codebase-intelligence')
302
- const block = text.slice(start, text.indexOf('```', start + 32))
303
- expect(block).toContain('bind_workspace')
304
- expect(block).toContain('indexing_in_progress')
305
- // The one operation a specialist must never perform.
306
- expect(block).toMatch(/never call `approve_indexing`|do not call `approve_indexing`/i)
375
+ expect(intelligenceBlock(text, 'mcp')).toContain('bind_workspace')
307
376
  })
308
377
 
309
- test('every focus block names the code-intelligence tool for its focus', async () => {
378
+ test('every focus block names its intelligence capability on both interfaces', async () => {
310
379
  const text = await readFile(ref('specialists.md'), 'utf8')
311
- const tools: Record<(typeof FOCUSES)[number], string> = {
312
- security: 'trace_data_flow',
313
- bugs: 'get_call_hierarchy',
314
- performance: 'find_affected_code',
315
- 'code-smells': 'search_code',
316
- architecture: 'explore_dependency_graph',
380
+ // A focus block reaches whichever interface the probe found, so naming only the
381
+ // MCP tool leaves a CLI specialist with a verb it cannot invoke.
382
+ const tools: Record<(typeof FOCUSES)[number], readonly [string, string]> = {
383
+ security: ['trace_data_flow', 'investigate --mode data'],
384
+ bugs: ['get_call_hierarchy', 'code-intel call-hierarchy'],
385
+ performance: ['find_affected_code', 'investigate --mode impact'],
386
+ 'code-smells': ['search_code', 'code-intel search'],
387
+ architecture: ['explore_dependency_graph', 'code-intel dependency-graph'],
317
388
  }
318
389
  for (const focus of FOCUSES) {
319
390
  const fence = `\`\`\`magpie-specialist-${focus}`
320
391
  const start = text.indexOf(fence)
321
392
  const block = text.slice(start, text.indexOf('```', start + fence.length))
322
- expect(block).toContain(tools[focus])
393
+ for (const tool of tools[focus]) expect(block).toContain(tool)
323
394
  }
324
395
  })
325
396
 
397
+ test('references/scout.md documents both intelligence interfaces', async () => {
398
+ const text = await readFile(ref('scout.md'), 'utf8')
399
+ // The scout is dispatched with the same <<CODE_INTELLIGENCE>> value the
400
+ // specialists get, so it has to know what `cli` and `mcp` each mean.
401
+ expect(text).toContain('`cli`')
402
+ expect(text).toContain('`mcp`')
403
+ expect(text).toContain('code-intel ')
404
+ expect(text).toContain('bind_workspace')
405
+ expect(text).toMatch(/never (call `approve_indexing`|run `code-intel index approve`)/i)
406
+ })
407
+
326
408
  test('the output contract tells specialists to look before they hedge', async () => {
327
409
  const text = await readFile(ref('specialists.md'), 'utf8')
328
410
  const contract = text.slice(0, text.indexOf('```magpie-specialist-'))
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magpie",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "Interactive PR review pipeline. Runs five parallel specialist subagents (security, bugs, performance, code-smells, architecture), dedupes findings, applies a critic rubric, peer-reviews via codex exec (falling back to a Claude second opinion when codex is unavailable), and serves an interactive HTML report for selecting findings to post via gh. Bundles a Bun CLI installed onto PATH via the skill's postinstall step. Use when the user asks to review a GitHub pull request. Splits oversized diffs into budgeted shards and rebuilds the diff from the local clone when gh pr diff refuses it.",
5
5
  "author": "iceinvein",
6
6
  "type": "prompt",
@@ -36,9 +36,11 @@ follow from that being worth guaranteeing: a value beginning with `--` is
36
36
  rejected rather than accepted as a value, and a flag with no value at all is
37
37
  rejected rather than taking the next flag as one.
38
38
 
39
- Gitignore `.sluice/`. It is working state, and everything durable in it lands
40
- somewhere else anyway: the commits are in git and the reasons are in the record,
41
- which is the file that does get committed.
39
+ The directory ignores itself: `init` drops a `.gitignore` holding `*` next to
40
+ the state, so no project has to add a line of its own. It is working state, and
41
+ everything durable in it lands somewhere else anyway: the commits are in git and
42
+ the reasons are in the record, which is the file that does get committed. Delete
43
+ that `.gitignore` if you want a run tracked; it is only written when absent.
42
44
 
43
45
  Open it with `init` when you open the run record, at the same point and for the
44
46
  same reason, then seed the rows with `plan.sh import <plan>` rather than a
@@ -19,7 +19,8 @@
19
19
  # status.sh close
20
20
  #
21
21
  # --dir <path> selects the tree to read (default: $PWD). State lives at
22
- # <dir>/.sluice/run.json and closed runs at <dir>/.sluice/archive/.
22
+ # <dir>/.sluice/run.json and closed runs at <dir>/.sluice/archive/. The
23
+ # directory ignores itself, so no project needs a .gitignore line for it.
23
24
  #
24
25
  # Exit: 0 ok, 1 the state could not be written, 2 no live run, 3 a run is
25
26
  # already live, 4 bad arguments, 5 jq missing, 6 the state file is unreadable.
@@ -220,6 +221,17 @@ require_readable() {
220
221
  }
221
222
  }
222
223
 
224
+ # The run state is working state, not history: the run record is what gets
225
+ # committed. So the directory ignores itself, rather than every repo sluice ever
226
+ # runs in having to add a line to its own .gitignore. `*` matches the .gitignore
227
+ # file too, so the whole directory drops out of `git status`. An existing file is
228
+ # left alone, and a tree that refuses the write still gets its run.
229
+ mk_dir() { # <directory to create under .sluice>
230
+ mkdir -p "$1" || { err "could not create $1"; exit 1; }
231
+ local ignore="$DIR/.sluice/.gitignore"
232
+ [ -e "$ignore" ] || printf '*\n' >"$ignore" 2>/dev/null || true
233
+ }
234
+
223
235
  # Written through a temporary file so an interrupted write cannot leave the
224
236
  # run state half-serialised, which would read as a corrupted run rather than
225
237
  # as a failed command.
@@ -263,7 +275,7 @@ case "$SUB" in
263
275
  exit 3
264
276
  fi
265
277
 
266
- mkdir -p "$DIR/.sluice"
278
+ mk_dir "$DIR/.sluice"
267
279
  jq -n \
268
280
  --arg topic "$TOPIC" \
269
281
  --arg channel "$CHANNEL" \
@@ -526,7 +538,7 @@ case "$SUB" in
526
538
  stamp="$(printf '%s' "$started" | tr -cd '0-9TZ')"
527
539
  slug="$(printf '%s' "${topic:-run}" | tr -cs 'A-Za-z0-9._-' '-')"
528
540
  [ -n "$stamp" ] || stamp="unknown"
529
- mkdir -p "$ARCHIVE"
541
+ mk_dir "$ARCHIVE"
530
542
 
531
543
  # The archive holds the only copy of a closed run, and two runs sharing a
532
544
  # start second and a topic name the same file. mv would leave one of them,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sluice",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries seven rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment and one status command can answer where the run is, and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Claude Code only; stands down where the superpowers pipeline governs the repo.",
5
5
  "author": "iceinvein",
6
6
  "type": "prompt",