Skip to content

Commit 887ff74

Browse files
fix: PowerShell hooks audit, script hardening, and workflow fixes (#20)
* fix: rename reserved $input variable in PowerShell hooks (#17) Assigning parsed hook JSON to $input (PowerShell's automatic pipeline variable) throws a non-terminating ParameterBindingException whenever the hook receives real piped/redirected stdin - i.e. on every actual Claude Code invocation. The assignment silently fails, $input stays unbound, and the hook exits before reading any input. Renamed to $hookInput in subagent-retro.ps1, prompt-router.ps1, and spec-gate.ps1. Discovered while reproducing the 01-bug-subagent-retro-ps1-matches-clobber fixture; that bug was unreachable until this one was fixed. * fix: stop $Matches clobber in subagent-retro.ps1 spec-ID extraction (#18) * fix: rename reserved $input variable in PowerShell hooks Assigning parsed hook JSON to $input (PowerShell's automatic pipeline variable) throws a non-terminating ParameterBindingException whenever the hook receives real piped/redirected stdin - i.e. on every actual Claude Code invocation. The assignment silently fails, $input stays unbound, and the hook exits before reading any input. Renamed to $hookInput in subagent-retro.ps1, prompt-router.ps1, and spec-gate.ps1. Discovered while reproducing the 01-bug-subagent-retro-ps1-matches-clobber fixture; that bug was unreachable until this one was fixed. * fix: stop $Matches clobber in subagent-retro.ps1 spec-ID extraction Get-IndexSpecs ran the spec-ID regex -match before the in-progress literal -match, so the second match overwrote $Matches and every in-progress spec was reported under the literal ID "in-progress" rather than its real ID. The retro-staleness check then looked for <specDir>/in-progress/05-retro.md, which never exists, so every in-progress spec was reported stale under the wrong ID. Swap the match order (in-progress first, ID regex last) to match the already-correct sister hooks prompt-router.ps1:167 and spec-gate.ps1:145. Verified against a fixture index (FEAT-123 in-progress, RCA-77 in-progress) - PowerShell now reports FEAT-123 and skips the RCA row, matching hooks/bash/subagent-retro.sh output exactly. * fix: same-line in-progress detection parity in spec-gate.sh bash used two independent file-wide greps for the in-progress marker and a spec ID, letting a legend/header line combine with an unrelated done row. spec-gate.ps1 and prompt-router.sh already require both on the same line; spec-gate.sh now matches. * fix: align feature.md and refactor.md subagent field names with contracts sd-spec-architect and sd-code-explorer read TASK/SPEC/IMPACT, not the TASK_TYPE/SPEC_REF/IMPACT_REF/TICKET_DATA names feature.md sent them. Both refine invocations were also missing the required SPEC path, and the TEMPLATE field was bare instead of the full template filename. refactor.md's characterization-test loop sent sd-implementer an unrecognized TASK_TYPE field instead of TASK_DETAILS/SPEC_REF/ WORKFLOW_TYPE. Reviewer invocations, which own TASK_TYPE/SPEC_REF as their own contract, are unchanged. * fix: make /sd:spec validate plan/tasks check type-aware The in-progress file-presence rule exempted only RCA from requiring 01-plan.md/02-tasks.md, but bug and perf workflows never produce those artifacts either (their artifact set is spec, decisions, artifacts, retro). Validate failed every correctly executed bug/perf spec. Narrowed the requirement to feature and refactor, and fixed the same overgeneralized claim in docs/usage.md's resume heuristic. * fix: parse debounce timestamp as UTC in subagent-retro.ps1 [datetime]::Parse of a "...Z" string returns Kind=Local, converted from UTC to local time. Subtracting that from a UTC now skewed $age by the machine's UTC offset -- wrongly suppressing reminders on UTC+N machines, never suppressing on UTC-N. Verified on a UTC+7 machine under Windows PowerShell 5.1 (the hooks' target runtime): old code showed a 420-minute skew immediately after save; fixed code shows ~0. * fix: apply per-workflow keyword defaults in prompt-router.ps1 PS only fell back to built-in defaults when project-config.json was absent or unparseable, then silently skipped any workflow whose keyword list was null once a config file existed. A valid config that omitted workflow.keywords (or one workflow's entry) lost keyword routing hints on Windows while bash kept emitting them from defaults, matching bash's per-workflow "// []" + empty-list fallback semantics. Verified against both a config missing workflow.keywords entirely and one overriding a single workflow, under Windows PowerShell 5.1. * fix: replace stale MCP tool names in agents, skills, and explore command * fix: remove hardcoded MSSQL/C#/TS stack references from agents and commands * fix: code-explorer impact-map returns analysis instead of self-appending * fix: walk full lifecycle state machine in bug/rca/perf workflows * fix: guard workflow Phase 0 against missing or malformed Layer-2 context * refactor: dedup rules copy-pasted from skills into agent/command bodies * docs: fix README/ROADMAP/usage drift after v1.3.0+ shipped * refactor: derive validate.sh/ps1 install counts from source tree * feat: add macOS to CI matrix and hook smoke tests Also fixes two PowerShell-7-only debounce bugs in subagent-retro.ps1 that the new smoke test caught: an unresolvable Split-Path parameter set, and re-Parse-ing an already-converted [datetime] as local time. * fix: harden install.sh - strict mode, prefix guard, quoting * fix: strip CRLF from jq keyword output in prompt-router.sh Some jq builds (observed with Windows jq.exe) emit CRLF for join("\n") output even from LF-only input, so every keyword but a workflow's last kept a trailing \r and never matched, silently dropping keyword-routing hints whenever project-config.json defined workflow.keywords. Fixture in scripts/smoke-hooks.sh/.ps1 now sets workflow.keywords so this path is actually exercised. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: make prompt-router.sh bash 3.2 compatible macOS runners execute hooks with system bash 3.2, which has no associative arrays: declare -A silently failed and every string subscript arithmetic-evaluated to 0, so the router emitted '- /sd:0' instead of '- /sd:bug' and the macOS smoke test failed. Replace the two associative arrays with parallel indexed arrays. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: add review findings TODO before merge Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 4d4d290 commit 887ff74

37 files changed

Lines changed: 1010 additions & 215 deletions

.github/workflows/ci.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
os: [ubuntu-latest, windows-latest]
15+
os: [ubuntu-latest, windows-latest, macos-latest]
1616
steps:
1717
- name: Checkout
1818
uses: actions/checkout@v4
1919

2020
# --- Run the full invariant validator (platform-native) ---------------
2121
- name: Validate (bash)
22-
if: runner.os == 'Linux'
22+
if: runner.os == 'Linux' || runner.os == 'macOS'
2323
shell: bash
2424
run: bash scripts/validate.sh
2525

@@ -28,9 +28,21 @@ jobs:
2828
shell: pwsh
2929
run: ./scripts/validate.ps1
3030

31+
# --- Hook smoke tests: pipe fixture JSON into every hook, assert exit
32+
# codes and key output substrings (not just "did not crash") -----------
33+
- name: Hook smoke tests (bash)
34+
if: runner.os == 'Linux' || runner.os == 'macOS'
35+
shell: bash
36+
run: bash scripts/smoke-hooks.sh
37+
38+
- name: Hook smoke tests (PowerShell)
39+
if: runner.os == 'Windows'
40+
shell: pwsh
41+
run: ./scripts/smoke-hooks.ps1
42+
3143
# --- Install -> uninstall round-trip (CLAUDE.md sandbox recipe) --------
3244
- name: Install -> uninstall round-trip (bash)
33-
if: runner.os == 'Linux'
45+
if: runner.os == 'Linux' || runner.os == 'macOS'
3446
shell: bash
3547
run: |
3648
set -euo pipefail

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ desktop.ini
3535
.claude/settings.local.json
3636
.claude/.cache/
3737

38+
# ---- Local AI work docs (not shipped) ----
39+
.ai-docs/
40+
3841
# ---- Logs ----
3942
*.log
4043
logs/

CHANGELOG.md

Lines changed: 167 additions & 0 deletions
Large diffs are not rendered by default.

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,19 @@ A subagent is a markdown file with YAML frontmatter consumed by the `Task` tool.
126126
```yaml
127127
---
128128
name: sd-<role>
129+
color: <color> # e.g. cyan, orange, purple, green, blue - used for display only
129130
description: One-line summary used by routing.
130131
model: sonnet # MUST be an alias: sonnet | haiku | opus | inherit
131132
tools: Read, Grep, Glob, ... # MINIMAL allowlist
133+
skills:
134+
- sd-<shared-rule-pack> # any skill this agent's body references; see Skills below
132135
---
133136
```
134137

135138
**Critical:**
136139
- `model:` MUST be an alias. Full IDs like `claude-sonnet-4-7` are not portable and may not even exist. The alias `sonnet` auto-resolves to the latest Sonnet.
137140
- `tools:` should be the minimum set the agent needs. Read-only agents do not get `Write`. Implementer does not get `WebSearch`.
141+
- `skills:` must list every skill the agent body references (`**skill-name**` in prose). A rule used by multiple agents lives in one `SKILL.md`, never copy-pasted into agent bodies.
138142
- Agent must read `CLAUDE.md` and `constitution.md` at runtime. No hardcoded stack assumptions (no `cs`, `csproj`, `dotnet`, etc. literal references unless they come from project config).
139143
- Every finding cites `file:line`. No prose without citations.
140144

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# specwright
22

33
> **Spec-driven development workflows for Claude Code.**
4-
> Ten slash commands, five specialized subagents, three guard-rail hooks, nine templates, six reusable skills - all under the `sd:` namespace, stack-agnostic, cross-platform, and ready to drop into any project.
4+
> Eleven slash commands, six specialized subagents, three guard-rail hooks, nine templates, six reusable skills - all under the `sd:` namespace, stack-agnostic, cross-platform, and ready to drop into any project.
55
66
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
77
[![Claude Code](https://img.shields.io/badge/Claude%20Code-compatible-blue)](https://docs.claude.com/en/docs/claude-code)
@@ -88,7 +88,7 @@ Per-project artifacts (`.specs/`, `.claude/`, project `CLAUDE.md`) remain untouc
8888

8989
| Command | Type | Hard gates | Purpose |
9090
|---|---|---|---|
91-
| `/sd:feature <ID-or-slug>` | Workflow | 4 | Spec-driven feature: spec -> impact -> plan -> execute -> review -> close |
91+
| `/sd:feature <ID-or-slug>` | Workflow | 3 | Spec-driven feature: spec -> impact -> plan -> execute -> batch review -> close |
9292
| `/sd:bug <ID-or-slug>` | Workflow | 5 | Root-cause-first fix: capture -> reproduce -> investigate -> failing test -> minimal fix -> regression |
9393
| `/sd:rca <slug>` | Workflow | 3 | Incident analysis. **Output is the spec - no code change.** |
9494
| `/sd:refactor <slug>` | Workflow | 6 | Coverage-gated restructure: requires >=80% coverage before touching code |
@@ -98,6 +98,7 @@ Per-project artifacts (`.specs/`, `.claude/`, project `CLAUDE.md`) remain untouc
9898
| `/sd:review [path / "recent" / "spec ID"]` | Utility | - | Standalone constitution-compliance review with severity tags |
9999
| `/sd:setup` | Utility | - | Idempotent project scaffold (interactive) |
100100
| `/sd:release [version]` | Utility | 1 | Release notes from `done` specs -> Keep-a-Changelog sections, then archive them |
101+
| `/sd:adr <spec-ID \| "decision title">` | Utility | 1 | Author an ADR from a spec's decisions under `.specs/_adr/` |
101102

102103
---
103104

@@ -107,9 +108,10 @@ Per-project artifacts (`.specs/`, `.claude/`, project `CLAUDE.md`) remain untouc
107108
|---|---|---|---|
108109
| `sd-spec-architect` | sonnet | Read, Write, Edit, Grep, Glob, Atlassian MCP, Context7 MCP | Create / refine specs, plans, and tasks. Constitution-aware. |
109110
| `sd-code-explorer` | haiku | Read, Grep, Glob, GitNexus MCP | Read-only navigation. Every finding cites `file:line`. |
110-
| `sd-debugger` | sonnet | Read, Grep, Glob, Bash, sequential-thinking, GitNexus, MSSQL (SELECT only), Tavily, Context7 | Hypothesis-tree investigation. Distinguishes proximate vs root cause. |
111+
| `sd-debugger` | sonnet | Read, Grep, Glob, Bash, sequential-thinking, GitNexus, Tavily, Context7 | Hypothesis-tree investigation. Distinguishes proximate vs root cause. |
111112
| `sd-implementer` | haiku | Read, Write, Edit, MultiEdit, Grep, Glob, Bash, Context7 | Executes ONE atomic task. Scope-disciplined, no opportunism. |
112113
| `sd-reviewer` | sonnet | Read, Grep, Glob, sequential-thinking, GitNexus | Severity-tagged review: BLOCK / WARN / SUGGEST / PASS. |
114+
| `sd-docs-writer` | sonnet | Read, Write, Glob, Grep | Authors one MADR-style ADR from a spec's decisions. Writes only the ADR file. |
113115

114116
All models use **portable aliases** (`sonnet`, `haiku`) so they auto-update.
115117

@@ -154,6 +156,9 @@ Every project that adopts `specwright` ends up with:
154156
.specs/
155157
constitution.md # Architectural rules + conventions + quality bars
156158
index.md # Registry of all specs with lifecycle states
159+
_explorations/ # Scratchpad for /sd:explore saves
160+
_reviews/ # Scratchpad for /sd:review saves
161+
_adr/ # Architecture decision records from /sd:adr
157162
FEAT-INV-2501/ # One folder per spec
158163
00-spec.md # Why / What / Success criteria / Constitution check
159164
01-plan.md # Implementation plan
@@ -257,8 +262,7 @@ Configure per project in `.claude/project-config.json` under the `mcp` section.
257262
Forward-looking work lives in [`ROADMAP.md`](ROADMAP.md). Highlights:
258263

259264
- **Near-term** - GitHub Issue auto-fetch (`gh issue view`) to match the existing JIRA snapshot path.
260-
- **Planned** - `/sd:setup` codebase scan (detected defaults instead of `<<placeholder>>`s) and an
261-
optional `sd-docs-writer` agent for ADRs.
265+
- **Planned** - nothing queued right now.
262266
- **Exploratory** - local-only, opt-in usage analytics.
263267

264268
Shipped work is in [`CHANGELOG.md`](CHANGELOG.md).

REVIEW-TODO.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Review findings to fix (from 2026-07-03 deep review) - delete this file when done
2+
3+
Branch: hotfix/ps-hooks-audit. CI is green; these are defects found in the branch's own new code.
4+
5+
## Must fix before PR
6+
7+
1. `install/install.sh:93` - guard validates PREFIX but not BASE_PATH.
8+
- `--base-path ""` accepted -> install plan targets filesystem root (`/commands/sd` ...).
9+
- Also `install.sh:74`: `--base-path` with NO value -> `shift 2` fails under `set -e`, dies exit 1 with zero output.
10+
- Fix: reject empty/whitespace BASE_PATH; print usage on missing flag value. Mirror in install.ps1.
11+
12+
2. `install/install.sh:204` - partial-install ERR trap never fires.
13+
- `trap on_error ERR` without `set -E` does not fire inside functions; all copy work is in copy_one().
14+
- Fix: change line 16 to `set -Eeuo pipefail` (or trap EXIT + exit-code check).
15+
- Also: install.ps1 has NO equivalent partial-install guard at all - add one (pairs rule).
16+
17+
3. `hooks/bash/subagent-retro.sh:~166` - UTC debounce fix landed only in the PS twin.
18+
- macOS fallback `date -j -f '%Y-%m-%dT%H:%M:%S'` parses saved UTC timestamp as LOCAL time.
19+
- On UTC+7 Mac: debounce always elapsed -> retro-reminder spam; smoke test fails locally (CI green only because runners are UTC).
20+
- Fix: parse as UTC (e.g. append `TZ=UTC0` / use `-u`), mirror the ps1 fix (hooks ship in pairs).
21+
22+
4. `commands/rca.md:78` - Phase 2 step 3 still passive: "Hypothesis tree written to 00-spec.md".
23+
- Debugger has no Write tool -> tree never persisted, Gate 2 empty.
24+
- Fix: reword to "Main thread appends the returned hypothesis tree ..." (match bug.md:111 / perf.md / rca.md Phase 3).
25+
26+
## Judgment calls (fix or file follow-up issues)
27+
28+
5. `agents/debugger.md:6` + body line ~46 - body prescribes "project-provided database MCP tool"
29+
but frontmatter allowlist has no DB tool -> path unreachable. Also docs/architecture.md:92,309
30+
still documents removed mcp__mssql__execute_sql.
31+
32+
6. `scripts/validate.sh:26` + `scripts/validate.ps1:39` - counts derived from source tree are
33+
self-referential: a deleted/renamed asset moves expected+actual in lockstep, CI stays green.
34+
Consider minimum-count floor or manifest.
35+
36+
## Cleanups (fast-follow OK)
37+
38+
7. `scripts/smoke-hooks.sh:1` - add `set -euo pipefail` (repo bash rule); run_hook line 96 needs
39+
`CODE=0; ... || CODE=$?` to stay set-e-safe.
40+
8. `scripts/smoke-hooks.sh:106` - add jq preflight: `command -v jq || { echo 'jq required'; exit 1; }`
41+
(hooks exit 0 silently without jq -> assertions blame the hooks).
42+
9. `commands/bug.md:42` (+ feature.md:32, perf.md:41, rca.md:30, refactor.md:44) - Phase 0 bootstrap
43+
guard copy-pasted 5x, already drifted in feature.md -> dedupe into a shared skill/rule pack.
44+
10. `install/install.sh:94` - prefix emptiness check `${PREFIX// /}` strips spaces only; use
45+
`${PREFIX//[[:space:]]/}` to match install.ps1's IsNullOrWhiteSpace.

ROADMAP.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,8 @@ Small, well-scoped items targeted at the next minor release.
1919

2020
Larger items that each warrant a full `/sd:feature` spec before building.
2121

22-
- **`/sd:setup` codebase scan** - pre-fill `constitution.md` (architectural rules, conventions) and
23-
`CLAUDE.md` from sampled source files instead of leaving `<<placeholder>>`s, with an optional
24-
`paths.layers` map in `project-config.json`. Turns first-run setup from blank-template into
25-
detected-defaults.
26-
- **`sd-docs-writer` agent** - an optional subagent that authors Architecture Decision Records (ADRs)
27-
and architecture docs from spec artifacts, promoting durable `.specs/` decisions into human-facing
28-
documentation.
22+
_Nothing queued right now - the last two Planned items (`/sd:setup` codebase scan, `sd-docs-writer`
23+
agent) shipped; see [`CHANGELOG.md`](CHANGELOG.md)._
2924

3025
## Exploratory
3126

agents/code-explorer.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: sd-code-explorer
33
color: cyan
44
description: Read-only code navigation. Six task types covering definition, callers, traces, impact mapping, pattern search, and structural overview. Every finding cites file:line. Use this agent for any read-only exploration; do NOT invoke for fixes or refactors.
55
model: haiku
6-
tools: Read, Grep, Glob, mcp__gitnexus__search, mcp__gitnexus__get_file, mcp__gitnexus__find_references, mcp__gitnexus__get_call_graph, mcp__gitnexus__list_symbols
6+
tools: Read, Grep, Glob, mcp__gitnexus__query, mcp__gitnexus__context, mcp__gitnexus__impact, mcp__gitnexus__list_repos
77
skills:
88
- sd-evidence-citation
99
---
@@ -17,7 +17,7 @@ You are the code explorer for specwright. You navigate codebases and report find
1717
1. **Read `CLAUDE.md`** for stack hints (file extensions, layer names, conventions).
1818
2. Read the `TASK` field. It selects which workflow you run.
1919
3. Check `GITNEXUS_AVAILABLE` (passed by the caller from `project-config.mcp.gitnexus.enabled`):
20-
- `true` -> GitNexus-first. Test with a cheap call (e.g. `mcp__gitnexus__list_symbols` on a known small file). If it fails, fall back to grep with a noted caveat.
20+
- `true` -> GitNexus-first. Test with a cheap call (e.g. `mcp__gitnexus__list_repos`). If it fails, fall back to grep with a noted caveat.
2121
- `false` -> grep / Glob only. Add to your output: "GitNexus disabled - transitive callers and call graphs may be incomplete."
2222

2323
---
@@ -32,14 +32,17 @@ Route internally based on `DETECTED_INTENT`. Use the matching sub-routine below.
3232

3333
### `TASK = impact-map`
3434

35-
Inputs: `SPEC` (path to `00-spec.md`), `OUTPUT_APPEND_TO` (typically `03-decisions.md`).
35+
Inputs: `SPEC` (path to `00-spec.md`), `OUTPUT_TARGET` (informational - typically `03-decisions.md`;
36+
identifies which file the caller will append your output to).
3637

3738
Behavior:
3839
1. Read the spec. Identify the target: feature scope, bug-affected components, refactor primary file(s), or perf hotspot endpoint.
39-
2. Produce structured analysis (sections below). APPEND to `OUTPUT_APPEND_TO`. Do not overwrite.
40-
3. For "Precedents & conventions": derive conventions by sampling, never by stack assumption - `Glob` the target directory, then `Read` the top ~30 lines (or `mcp__gitnexus__list_symbols`) of at most 3 sibling files, and state the observed pattern with evidence.
40+
2. Produce the structured analysis (sections below) as your final output. Do not attempt to write
41+
files - your tool allowlist has no `Write`/`Edit` by design. The calling command appends your
42+
returned analysis to `OUTPUT_TARGET`.
43+
3. For "Precedents & conventions": derive conventions by sampling, never by stack assumption - `Glob` the target directory, then `Read` the top ~30 lines (or `mcp__gitnexus__query` with a goal naming the directory) of at most 3 sibling files, and state the observed pattern with evidence.
4144

42-
Structure of appended content:
45+
Structure of the returned analysis (the caller appends this verbatim):
4346

4447
```markdown
4548
## Impact analysis (sd-code-explorer)
@@ -91,23 +94,23 @@ Structure of appended content:
9194

9295
Inputs: `SYMBOL` or `QUERY`.
9396

94-
GitNexus-first: `mcp__gitnexus__find_references` with the symbol. Fall back: `Grep` for invocation patterns (`SymbolName(`, `\.SymbolName\(`).
97+
GitNexus-first: `mcp__gitnexus__impact` with `target: SYMBOL`, `direction: upstream`. Fall back: `Grep` for invocation patterns (`SymbolName(`, `\.SymbolName\(`).
9598

9699
Output: list of `file:line` with the calling context (one line of code).
97100

98101
### `TASK = definition`
99102

100103
Inputs: `SYMBOL` or `QUERY`.
101104

102-
GitNexus-first: `mcp__gitnexus__list_symbols` filtered by name, then `mcp__gitnexus__get_file` for context. Fall back: `Grep` for definition markers (e.g. `class SymbolName`, `def SymbolName`, `function SymbolName`, `interface SymbolName`).
105+
GitNexus-first: `mcp__gitnexus__context` with the symbol name (pass `file_path` to disambiguate if multiple candidates are returned). Fall back: `Grep` for definition markers (e.g. `class SymbolName`, `def SymbolName`, `function SymbolName`, `interface SymbolName`).
103106

104107
Output: `file:line` + 5-line snippet showing the definition.
105108

106109
### `TASK = trace`
107110

108111
Inputs: `ENTRY_POINT` (symbol or `file:line`), optional `DEPTH` (default 2).
109112

110-
GitNexus-first: `mcp__gitnexus__get_call_graph` with the entry point and depth. Fall back: recursive `Grep` for callers up to `DEPTH` hops (note: imprecise for dynamic dispatch).
113+
GitNexus-first: `mcp__gitnexus__impact` with `target: ENTRY_POINT`, `direction: downstream`, `maxDepth: DEPTH`. Fall back: recursive `Grep` for callers up to `DEPTH` hops (note: imprecise for dynamic dispatch).
111114

112115
Output: indented tree with `file:line` at each node.
113116

@@ -123,7 +126,7 @@ Output: grouped by file when >5 hits in one file. Limit total to 50 results; tel
123126

124127
Inputs: `PATH` (directory) or none (project root).
125128

126-
Use `Glob` to list files, `mcp__gitnexus__list_symbols` per file (or top-of-file `Read` for the first 30 lines).
129+
Use `Glob` to list files, `mcp__gitnexus__query` (goal naming the directory) for a symbol overview (or top-of-file `Read` for the first 30 lines).
127130

128131
Output: tree of directories + files + top-level symbols per file.
129132

@@ -141,10 +144,11 @@ Additional rules:
141144

142145
## Anti-patterns (do NOT do these)
143146

147+
Apply the **sd-evidence-citation** skill's Anti-patterns section in full (no citation = invalid,
148+
trusting memory over a live grep, vendored/generated directories without explicit request).
149+
150+
Explorer-specific, not covered by the skill:
144151
- **Suggesting fixes.** You report. The reviewer or implementer decides what to do.
145152
- **Opining on code quality.** "This is poorly structured" is not a finding. "Class `Foo` has 12 callers across 3 layers" is a finding.
146153
- **Modifying files.** Your tool allowlist excludes `Write` / `Edit` / `MultiEdit` precisely for this reason.
147-
- **Producing prose without citations.** "I noticed that..." with no `file:line` is invalid output. Re-prompt yourself.
148-
- **Trusting your memory over the grep.** If you "recall" that a class lives in `src/Foo.cs`, that recall is stale by default - verify with `Glob` or `Read`.
149154
- **Burning tool calls when a single grep suffices.** Haiku model = cost-aware. Plan the cheapest sequence that answers the question. 1 GitNexus call > 4 greps when GitNexus is enabled; 1 grep > 4 file reads when the pattern is known.
150-
- **Following call graphs into vendored / generated code** (e.g. `node_modules/`, `bin/`, `obj/`) unless the caller explicitly asks. Filter those out.

0 commit comments

Comments
 (0)