claude-dev-env 1.37.1 → 1.38.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.
Files changed (92) hide show
  1. package/CLAUDE.md +3 -0
  2. package/_shared/pr-loop/audit-contract.md +4 -3
  3. package/_shared/pr-loop/fix-protocol.md +2 -0
  4. package/_shared/pr-loop/gh-payloads.md +38 -37
  5. package/_shared/pr-loop/scripts/README.md +0 -1
  6. package/_shared/pr-loop/scripts/preflight.py +2 -1
  7. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +2 -2
  8. package/_shared/pr-loop/scripts/tests/test_preflight.py +22 -0
  9. package/_shared/pr-loop/state-schema.md +10 -10
  10. package/agents/clean-coder.md +4 -0
  11. package/agents/code-quality-agent.md +23 -85
  12. package/agents/groq-coder.md +8 -6
  13. package/hooks/blocking/__init__.py +0 -0
  14. package/hooks/blocking/hedging_language_blocker.py +2 -2
  15. package/hooks/blocking/state_description_blocker.py +243 -0
  16. package/hooks/blocking/tdd_enforcer.py +94 -0
  17. package/hooks/blocking/test_hedging_language_blocker.py +1 -1
  18. package/hooks/blocking/test_state_description_blocker.py +618 -0
  19. package/hooks/blocking/test_tdd_enforcer.py +152 -0
  20. package/hooks/config/state_description_blocker_constants.py +130 -0
  21. package/hooks/hooks.json +10 -0
  22. package/package.json +1 -1
  23. package/rules/no-historical-clutter.md +31 -10
  24. package/scripts/config/groq_bugteam_config.py +13 -5
  25. package/skills/bugteam/CONSTRAINTS.md +20 -27
  26. package/skills/bugteam/EXAMPLES.md +1 -1
  27. package/skills/bugteam/PROMPTS.md +60 -31
  28. package/skills/bugteam/SKILL.md +47 -47
  29. package/skills/bugteam/SKILL_EVALS.md +8 -8
  30. package/skills/bugteam/reference/github-pr-reviews.md +31 -31
  31. package/skills/bugteam/reference/team-setup.md +1 -1
  32. package/skills/bugteam/reference/teardown-publish-permissions.md +4 -4
  33. package/skills/copilot-review/SKILL.md +7 -14
  34. package/skills/findbugs/SKILL.md +2 -2
  35. package/skills/fixbugs/SKILL.md +1 -1
  36. package/skills/monitor-open-prs/SKILL.md +6 -6
  37. package/skills/pr-converge/SKILL.md +7 -6
  38. package/skills/pr-converge/reference/convergence-gates.md +28 -30
  39. package/skills/pr-converge/reference/examples.md +4 -4
  40. package/skills/pr-converge/reference/fix-protocol.md +6 -8
  41. package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -10
  42. package/skills/pr-converge/reference/per-tick.md +18 -33
  43. package/skills/pr-converge/reference/stop-conditions.md +7 -7
  44. package/skills/pr-converge/scripts/README.md +65 -117
  45. package/skills/pr-review-responder/EXAMPLES.md +2 -2
  46. package/skills/pr-review-responder/PRINCIPLES.md +2 -8
  47. package/skills/pr-review-responder/README.md +7 -48
  48. package/skills/pr-review-responder/SKILL.md +2 -3
  49. package/skills/pr-review-responder/TESTING.md +8 -65
  50. package/skills/qbug/SKILL.md +10 -16
  51. package/_shared/pr-loop/scripts/config/gh_util_constants.py +0 -31
  52. package/_shared/pr-loop/scripts/gh_util.py +0 -193
  53. package/_shared/pr-loop/scripts/tests/test_gh_util.py +0 -257
  54. package/_shared/pr-loop/scripts/tests/test_gh_util_constants.py +0 -61
  55. package/skills/pr-converge/scripts/check_pr_mergeability.py +0 -78
  56. package/skills/pr-converge/scripts/config/pr_converge_constants.py +0 -134
  57. package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +0 -152
  58. package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +0 -70
  59. package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +0 -57
  60. package/skills/pr-converge/scripts/fetch_claude_inline_comments.py +0 -70
  61. package/skills/pr-converge/scripts/fetch_claude_reviews.py +0 -61
  62. package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +0 -70
  63. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +0 -61
  64. package/skills/pr-converge/scripts/mark_pr_ready.py +0 -54
  65. package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +0 -49
  66. package/skills/pr-converge/scripts/post-bugbot-run.ps1 +0 -33
  67. package/skills/pr-converge/scripts/reply_to_inline_comment.py +0 -84
  68. package/skills/pr-converge/scripts/request_copilot_review.py +0 -71
  69. package/skills/pr-converge/scripts/resolve_pr_head.py +0 -58
  70. package/skills/pr-converge/scripts/review_field_helpers.py +0 -43
  71. package/skills/pr-converge/scripts/reviewer_fetch_core.py +0 -153
  72. package/skills/pr-converge/scripts/reviewer_specs.py +0 -98
  73. package/skills/pr-converge/scripts/test_check_pr_mergeability.py +0 -126
  74. package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +0 -443
  75. package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +0 -299
  76. package/skills/pr-converge/scripts/test_fetch_claude_inline_comments.py +0 -485
  77. package/skills/pr-converge/scripts/test_fetch_claude_reviews.py +0 -368
  78. package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +0 -440
  79. package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +0 -366
  80. package/skills/pr-converge/scripts/test_mark_pr_ready.py +0 -69
  81. package/skills/pr-converge/scripts/test_post_bugbot_run.py +0 -195
  82. package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +0 -159
  83. package/skills/pr-converge/scripts/test_request_copilot_review.py +0 -101
  84. package/skills/pr-converge/scripts/test_resolve_pr_head.py +0 -79
  85. package/skills/pr-converge/scripts/test_review_field_helpers.py +0 -80
  86. package/skills/pr-converge/scripts/test_reviewer_fetch_core.py +0 -448
  87. package/skills/pr-converge/scripts/test_reviewer_specs.py +0 -107
  88. package/skills/pr-converge/scripts/test_trigger_bugbot.py +0 -139
  89. package/skills/pr-converge/scripts/test_view_pr_context.py +0 -155
  90. package/skills/pr-converge/scripts/trigger_bugbot.py +0 -77
  91. package/skills/pr-converge/scripts/view_pr_context.py +0 -78
  92. package/skills/pr-review-responder/scripts/respond_to_reviews.py +0 -376
@@ -15,16 +15,35 @@ Keep the spawn prompt self-contained: reference only the PR scope, audit rubric,
15
15
  <worktree_path>absolute path from Step 1 per-PR workspace</worktree_path>
16
16
  </context>
17
17
 
18
- cd into `<worktree_path>` before any git, gh, or file operation.
18
+ cd into `<worktree_path>` before any git or file operation.
19
19
 
20
20
  <scope>
21
21
  <diff_path>Absolute path to the per-PR patch file: <run_temp_dir>/pr-<N>/loop-<L>.patch (same path as gh pr diff redirect in AUDIT)</diff_path>
22
22
  <scope_rule>Audit only lines added or modified in the diff. Pre-existing code on untouched lines is out of scope.</scope_rule>
23
+ <changed_files_rule>Build the list of changed file paths from the diff. Open each one with Read and audit cross-file consistency. Read every changed test file and cross-reference test assertions, expected values, and mock setup against the production code's config constants and function signatures. When a test file asserts a value that diverges from config, file a finding under category J.</changed_files_rule>
23
24
  </scope>
24
25
 
25
26
  <bug_categories>
26
- Investigate each category explicitly. For each, return either at least
27
- one finding OR a verified-clean entry with the evidence used to clear it:
27
+ Investigate each of the eleven categories (A–K) explicitly. For each,
28
+ return either at least one finding OR a verified-clean entry with the
29
+ evidence used to clear it. A category is verified-clean only when one
30
+ complete execution path through the changed code has been traced from
31
+ entry to exit. Surface-level scanning is insufficient evidence. The
32
+ evidence field must name (1) the specific function examined, (2) the
33
+ code path traced from entry to exit, and (3) the specific check performed.
34
+ Generic phrases such as "verified clean", "no issues found",
35
+ "pattern appears correct", "looks good", "seems fine", and
36
+ "no problems detected" do not satisfy the verified-clean requirement.
37
+ When evidence contains any of these phrases, the category is not
38
+ verified-clean -- re-audit with a concrete trace.
39
+
40
+ Categories A–K (one-line summary; full rubric and sub-bucket decomposition
41
+ for each is in `packages/claude-dev-env/audit-rubrics/category_rubrics/`;
42
+ ready-to-send Variant C prompts — each with a PR/repo-independent
43
+ generalized skeleton above a `---` separator and a worked example against
44
+ an authentic PR below — are in
45
+ `packages/claude-dev-env/audit-rubrics/prompts/`):
46
+
28
47
  A. API contract verification (signatures, return types, async/await correctness)
29
48
  B. Selector / query / engine compatibility
30
49
  C. Resource cleanup and lifecycle (file handles, connections, processes, locks)
@@ -35,6 +54,10 @@ cd into `<worktree_path>` before any git, gh, or file operation.
35
54
  H. Security boundaries (injection, path traversal, auth bypass, secret leakage)
36
55
  I. Concurrency hazards (race conditions, missing awaits, shared mutable state)
37
56
  J. Magic values and configuration drift
57
+ K. Codebase conflicts — a change updates one site of a pattern but a parallel
58
+ site in unchanged code stays stale, producing contradictory behavior;
59
+ the diff is internally consistent, the bug emerges only against unchanged
60
+ code (canonical example: jl-cmd/claude-code-config PR #397 r3210166636)
38
61
  </bug_categories>
39
62
 
40
63
  <constraints>
@@ -42,26 +65,26 @@ cd into `<worktree_path>` before any git, gh, or file operation.
42
65
  - Cite file:line for every finding.
43
66
  - When the diff alone does not provide enough context to confirm a bug,
44
67
  list it under "Open questions" rather than assert it.
68
+ - For every finding, search `git grep` for all callers of the targeted function. When the obvious fix would silently change behavior for other call paths, include a fix constraint that preserves them.
45
69
  </constraints>
46
70
 
47
71
  <comment_posting>
48
- Sibling auditors (-b through -k): run only steps 1–3 (audit, assign IDs,
72
+ Sibling auditors (-b through -k): run only steps 1–2 (audit, assign IDs,
49
73
  capture excerpt, validate anchors), then write outcome XML per <output_format> and return.
50
- Skip steps 48 — sibling auditors do not post PR reviews.
74
+ Skip steps 35 — sibling auditors do not post PR reviews.
51
75
 
52
76
  Validator (-a) and single-opus auditors: run all steps below.
53
77
 
54
- 1. Audit the diff against the 10 categories above. Buffer the findings
55
- in memory; all posting happens at step 6 once anchors are validated.
78
+ 1. Audit the diff against the 11 categories above. Buffer the findings
79
+ in memory; all posting happens at step 4 once anchors are validated.
56
80
  2. Assign each finding a stable finding_id of exactly the form `loop<L>-<K>`
57
81
  where <K> is 1-based within this loop.
58
- 3. For each finding, capture a verbatim excerpt from the target file at the cited line. Populate the `<excerpt>` element in the outcome XML with it. Validate every finding's (file, line) against the captured diff. Split
59
- findings into two buckets: anchored (line is in the diff) and
60
- unanchored (line is not in the diff goes into the review body's
61
- "Findings without a diff anchor" section per Step 2.5).
62
- 4. Build the review body per Step 2.5's review-body shape, filling in the
63
- P0/P1/P2 counts and the unanchored-findings list (if any).
64
- 5. For each anchored finding, write its body to its own temp file:
82
+ 3. For each finding, capture a verbatim excerpt from the target file at the cited
83
+ line. Populate the `<excerpt>` element in the outcome XML with it. Validate
84
+ every finding's (file, line) against the captured diff. Split findings into two
85
+ buckets: anchored (line is in the diff) and unanchored (line is not in the diff
86
+ goes into the review body's "Findings without a diff anchor" section per
87
+ Step 2.5). Format each finding body as:
65
88
 
66
89
  **[severity] one-line title**
67
90
  Category: <letter> (<category name>)
@@ -69,16 +92,16 @@ cd into `<worktree_path>` before any git, gh, or file operation.
69
92
 
70
93
  _From /bugteam audit loop <L>._
71
94
 
72
- 6. Post ONE review via Step 2.5's per-loop review CLI shape. Harvest the
73
- parent review `html_url` from the response JSON and the `comments[]`
74
- child entries (each with its own `id` and `html_url`). Match child
75
- entries to anchored findings in index order.
76
- 7. If the review POST itself fails, use Step 2.5's Review POST failure
77
- fallback (single issue comment with full body and all findings inline).
78
- 8. Write every body (review body, each finding body, any fallback body)
79
- to its own temp file. Load each file into the JSON payload via jq's
80
- `--rawfile` or `-Rs`, then pipe the jq output to `gh api ... --input -`
81
- so every body reaches GitHub as file contents inside the JSON payload.
95
+ 4. Post ONE review via `pull_request_review_write(method="create",
96
+ event="COMMENT", body=<review_body>, owner=<O>, repo=<R>,
97
+ pullNumber=<N>, comments=[...])`. See Step 2.5 in SKILL.md for the full
98
+ parameter shape. Harvest the parent review `html_url` from the response
99
+ and the `comments[]` child entries (each with its own `id` and `html_url`).
100
+ Match child entries to anchored findings in index order.
101
+ 5. If the review POST fails, use `add_issue_comment(owner=<O>, repo=<R>,
102
+ issueNumber=<N>, body=<full_text>)` as fallback.
103
+ Body text is passed directly as string parameters to the MCP tool calls
104
+ no temp files, no jq, no shell pipes.
82
105
  </comment_posting>
83
106
 
84
107
  <output_format>
@@ -126,7 +149,7 @@ After the teammate writes the XML and returns, the lead reads `.bugteam-pr<N>-lo
126
149
  <worktree_path>absolute path from Step 1 per-PR workspace</worktree_path>
127
150
  </context>
128
151
 
129
- cd into `<worktree_path>` before any git, gh, or file operation.
152
+ cd into `<worktree_path>` before any git or file operation.
130
153
 
131
154
  <bugs_to_fix>
132
155
  [for each P0/P1/P2 finding from last_findings:]
@@ -147,19 +170,22 @@ cd into `<worktree_path>` before any git, gh, or file operation.
147
170
  1. Read each referenced file before editing.
148
171
  2. Apply each fix you can address.
149
172
  3. Run `python -m py_compile` (or language-equivalent) on every modified file.
150
- 4. git add by explicit path, then git commit with a message summarizing the bugs fixed.
173
+ 4. Run the project's test suite and confirm all existing tests pass. If a test fails, diagnose the regression and fix it before committing.
174
+ 5. Read the previous loop's outcome XML (`<worktree_path>/.bugteam-pr<N>-loop<L-1>.outcomes.xml`) and obtain its total finding count. If this is the first loop (L <= 1) or the file does not exist, skip this comparison. Otherwise, re-read each changed file and count any new violations. Compute the post-fix total: previous total minus bugs fixed in this round plus new violations. If the post-fix total exceeds the previous total, flag all new findings as same-loop fix-targets and revise before committing.
175
+ 6. git add by explicit path, then git commit with a message summarizing the bugs fixed.
151
176
  - If the commit fails because a git hook (pre-commit, commit-msg, etc.) blocked it,
152
177
  capture the hook's stderr, write status=hook_blocked for every finding in this loop
153
178
  (the commit was atomic; if it failed, no finding was applied), populate hook_output
154
179
  on each outcome, and return WITHOUT retrying. The lead will treat this loop as no-progress.
155
- 5. git push with a plain fast-forward push (the default, no flag overrides).
156
- 6. For each bug, post a fix reply to its finding_comment_id via the
157
- Step 2.5 reply CLI shape:
180
+ 7. git push with a plain fast-forward push (the default, no flag overrides).
181
+ 8. For each bug, post a fix reply to its finding_comment_id via
182
+ `add_reply_to_pull_request_comment(commentId=<id>, body=<reply_text>,
183
+ owner=<O>, repo=<R>, pullNumber=<N>)`:
158
184
  - "Fixed in <commit_sha>" if the bug was addressed by your commit
159
185
  - "Could not address this loop: <one-line reason>" if you skipped or failed it
160
186
  - "Hook blocked the fix commit: <one-line summary>" if the commit was hook-blocked
161
- Use the Fix reply CLI shape from Step 2.5 (`jq -Rs | gh api .../comments/<id>/replies --input -`). Write every reply body to a temp file first.
162
- 7. Write `.bugteam-pr<N>-loop<L>.outcomes.xml` inside `<worktree_path>` (schema below) and return its path.
187
+ Body text is passed directly as string parameters -- no temp files, no jq, no shell pipes.
188
+ 9. Write `.bugteam-pr<N>-loop<L>.fix-outcomes.xml` inside `<worktree_path>` (schema below) and return its path.
163
189
  </execution>
164
190
 
165
191
  <outcome_xml_schema>
@@ -186,5 +212,8 @@ cd into `<worktree_path>` before any git, gh, or file operation.
186
212
  - git add by explicit path — name each file being staged.
187
213
  - Preserve existing comments on lines you do not modify.
188
214
  - Type hints on every signature you touch.
215
+ - **Narrow scope.** Fix only the exact defect at the specified file:line. No restructuring, no inlining helpers, no renames, no "while I'm here" cleanup.
216
+ - **Preserve helpers.** Do not remove or inline existing helper functions unless the finding explicitly names the helper as the problem.
217
+ - **No regression.** Before committing, re-read each changed file and count any new violations. Compare the post-fix total (previous total minus bugs fixed plus new violations) against the previous loop's total finding count (from `<worktree_path>/.bugteam-pr<N>-loop<L-1>.outcomes.xml`). On the first loop (L <= 1) or when the file does not exist, skip this guard. The post-fix total must be flat or decreased relative to the previous loop. An increase means the fix introduced new bugs — revise before committing. Do not commit a regression.
189
218
  </constraints>
190
219
  ```
@@ -120,9 +120,9 @@ Non-zero → stop. Revoke in Step 5 on every exit path.
120
120
 
121
121
  ### Step 1: Resolve PR scope (once)
122
122
 
123
- Accept one or more PR numbers from the invocation. For each PR, run `gh pr view
124
- --json number,baseRefName,headRefName,url` (falling back to the merge-base diff
125
- path when no PR exists). Capture `all_prs = [{number, owner, repo, baseRef,
123
+ Accept one or more PR numbers from the invocation. For each PR, call
124
+ `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` (falling back
125
+ to the merge-base diff path when no PR exists). Capture `all_prs = [{number, owner, repo, baseRef,
126
126
  headRef, url}, ...]`. A single-PR invocation produces a one-element list and
127
127
  follows the same downstream rules.
128
128
 
@@ -186,41 +186,34 @@ Order: audit → buffer → validate anchors vs diff → single review POST.
186
186
  Review body states counts; zero findings → still one review, `comments: []`,
187
187
  body `## /bugteam loop <L> audit: 0P0 / 0P1 / 0P2 → clean`.
188
188
 
189
- **Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ...
190
- --input -` (avoids shell-quoting; satisfies `gh-body-backtick-guard`). Write
191
- each markdown body to a temp file first.
189
+ **Payloads:** Use MCP tool calls (see below). Body text with markdown (backticks,
190
+ newlines, quotes) passes through safely as string parameters — no temp files, no
191
+ jq, no shell pipes.
192
192
 
193
193
  **Review POST** (one `comments[]` object per anchored finding; single-line
194
194
  `{path, line, side: "RIGHT", body}`; multi-line add `start_line`, `start_side:
195
195
  "RIGHT"`):
196
196
 
197
197
  ```
198
- jq -n \
199
- --rawfile review_body <tmp_review_body.md> \
200
- --arg commit_id "$(git rev-parse HEAD)" \
201
- --rawfile finding_body_1 <tmp_finding_1.md> \
202
- --arg path_1 "<file_1>" \
203
- --argjson line_1 <line_1> \
204
- [... one finding_body_K / path_K / line_K triple per finding ...] \
205
- '{
206
- commit_id: $commit_id,
207
- event: "COMMENT",
208
- body: $review_body,
209
- comments: [
210
- {path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
211
- [, ... ]
212
- ]
213
- }' \
214
- | gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
198
+ pull_request_review_write(
199
+ method="create",
200
+ event="COMMENT",
201
+ body=<review_body_text>,
202
+ commitID=<head_sha_at_post_time>,
203
+ owner=<owner>, repo=<repo>, pullNumber=<number>,
204
+ comments=[
205
+ {path: <path_1>, line: <line_1>, side: "RIGHT", body: <finding_body_1>}
206
+ [, ... ]
207
+ ]
208
+ )
215
209
  ```
216
210
 
217
- **Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api
218
- repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X
219
- POST --input -`
211
+ **Fix reply:** `add_reply_to_pull_request_comment(commentId=<finding_comment_id>,
212
+ body=<reply_text>, owner=<owner>, repo=<repo>, pullNumber=<number>)`
220
213
 
221
- **Review POST fails:** issue comment fallback: `jq -Rs '{body: .}'
222
- <tmp_fallback.md | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST
223
- --input -`
214
+ **Review POST fails:** issue comment fallback:
215
+ `add_issue_comment(owner=<owner>, repo=<repo>, issueNumber=<number>,
216
+ body=<fallback_text>)`
224
217
 
225
218
  `<head_sha_at_post_time>`: `git rev-parse HEAD` in subagent cwd immediately
226
219
  before POST.
@@ -263,10 +256,16 @@ and before iteration begins, when `last_action == "fresh"`). A re-invocation of
263
256
  cleaned this HEAD (short-circuit) and otherwise records that prior loops were
264
257
  dirty so the AUDIT runs against the latest diff with that signal in mind:
265
258
 
266
- ```bash
267
- dirty_review_count=0
268
- gh api "repos/<owner>/<repo>/pulls/<number>/reviews?per_page=100" --paginate --slurp \
269
- | jq '[.[][] | select((.body // "") | startswith("## /bugteam loop "))] | sort_by(.submitted_at) | reverse'
259
+ ```python
260
+ dirty_review_count = 0
261
+ all_reviews = pull_request_read(
262
+ method="get_reviews", pullNumber=N, owner=O, repo=R
263
+ )
264
+ prior_reviews = [
265
+ rev for rev in all_reviews
266
+ if rev.get("body", "").startswith("## /bugteam loop ")
267
+ ]
268
+ prior_reviews.sort(key=lambda rev: rev["submitted_at"], reverse=True)
270
269
  ```
271
270
 
272
271
  Iterate from index 0 (most recent) toward older entries:
@@ -313,7 +312,7 @@ Iterate from index 0 (most recent) toward older entries:
313
312
  Lead only; merge-base / diff semantics:
314
313
  [`../../_shared/pr-loop/code-rules-gate.md`][path-code-rules]; shared script
315
314
  inventory: [`../../_shared/pr-loop/scripts/README.md`][path-scripts-readme].
316
- Non-zero → spawn **clean-coder** standards-fix (read stderr, edit, re-run
315
+ Non-zero → spawn **clean-coder** standards-fix (`mode="bypassPermissions"`) (read stderr, edit, re-run
317
316
  **this same** command, one commit, `git push`, shutdown) until exit **0** or
318
317
  **5**
319
318
  failed gate rounds → `error: code rules gate failed pre-audit`. After **0**:
@@ -335,12 +334,10 @@ before the next AUDIT.
335
334
 
336
335
  ### AUDIT action
337
336
 
338
- ```bash
339
- mkdir -p "<run_temp_dir>/pr-<N>"
340
- gh pr diff <N> -R <owner>/<repo> > "<run_temp_dir>/pr-<N>/loop-<L>.patch"
341
- ```
342
-
343
- **Spawn:**
337
+ 1. Create the directory: `mkdir -p "<run_temp_dir>/pr-<N>"`.
338
+ 2. Call `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)`
339
+ to capture the diff text, then write it to
340
+ `"<run_temp_dir>/pr-<N>/loop-<L>.patch"` using the `Write` tool.
344
341
 
345
342
  ```
346
343
  Agent(
@@ -411,6 +408,8 @@ advanced; `git -C "<run_temp_dir>/pr-<N>/worktree" fetch origin <branch> && git
411
408
  `HEAD`. Unchanged HEAD →
412
409
  `stuck — bugfix subagent could not address findings`.
413
410
 
411
+ **Scope verification.** Run `git diff HEAD~1 --name-only` and compare against the set of files referenced in bugs_to_fix. When the commit touches any file NOT in the bugs_to_fix list, downgrade the outcome to `unverified_fixed` with reason "commit touched unexpected files: <list>".
412
+
414
413
  ### Step 4: Teardown
415
414
 
416
415
  1. For each PR in `all_prs`: `git worktree remove
@@ -431,16 +430,17 @@ else {'onerror': h}))"
431
430
  ### Step 4.5: PR description
432
431
 
433
432
  Lead only; cumulative product narrative (not process). Delegate body to
434
- `pr-description-writer` via `Agent` (else `general-purpose`) so the
435
- mandatory-pr-description hook accepts `gh pr edit`.
433
+ `pr-description-writer` via `Agent` (`mode="bypassPermissions"`) (else `general-purpose`) so the
434
+ mandatory-pr-description hook accepts `update_pull_request`.
436
435
 
437
- 1. `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`
438
- 2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body >
439
- .bugteam-original-body.md`
436
+ 1. `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` write
437
+ output to `.bugteam-final.diff` with `Write` tool.
438
+ 2. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` → extract
439
+ `.body` from response, write to `.bugteam-original-body.md` with `Write` tool.
440
440
  3. Agent brief: paths + branch names; describe merge-ready change from diff;
441
441
  keep curated original sections intact; return markdown body.
442
- 4. Write `.bugteam-final-body.md`; `gh pr edit <number> -R <owner>/<repo>
443
- --body-file .bugteam-final-body.md`
442
+ 4. Write `.bugteam-final-body.md`; `update_pull_request(pullNumber=N, owner=O,
443
+ repo=R, body=<body_text>)`.
444
444
  5. Delete the three temp files.
445
445
 
446
446
  On failure: log in final report; continue to Step 5.
@@ -68,7 +68,7 @@ The harness does not yet exist; this document defines its contract.
68
68
  **Scenario.** Current branch is `main` with no PR and no upstream difference.
69
69
 
70
70
  **Layer B predicted trace.**
71
- 1. `Bash("gh pr view --json ...")` → non-zero exit.
71
+ 1. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` → fails / no matching PR.
72
72
  2. `Bash("git merge-base HEAD origin/main")` → empty.
73
73
  3. No grant script.
74
74
 
@@ -103,10 +103,10 @@ The harness does not yet exist; this document defines its contract.
103
103
  | # | Tool call | Source |
104
104
  |---|---|---|
105
105
  | 1 | `Bash("python .../scripts/grant_project_claude_permissions.py")` | `SKILL.md` § Step 0 |
106
- | 2 | `Bash("gh pr view --json number,baseRefName,headRefName,url")` | `SKILL.md` § Step 1 |
106
+ | 2 | `pull_request_read(method="get", pullNumber=42, owner=..., repo=...)` | `SKILL.md` § Step 1 |
107
107
  | 3 | `Bash("git -C \"<run_temp_dir>/pr-42/worktree\" rev-parse HEAD")` → captures `starting_sha` | `SKILL.md` § Step 2 — **Loop state** block |
108
108
  | 4 | `Bash("mkdir -p <run_temp_dir>/pr-42")` | `SKILL.md` § AUDIT action |
109
- | 5 | `Bash("gh pr diff 42 -R ... > <run_temp_dir>/pr-42/loop-1.patch")` | `SKILL.md` § AUDIT action |
109
+ | 5 | `pull_request_read(method="get_diff", pullNumber=42, owner=..., repo=...)` write to `<run_temp_dir>/pr-42/loop-1.patch` | `SKILL.md` § AUDIT action |
110
110
  | 6 | `Agent(subagent_type="code-quality-agent", name="bugfind-pr42-loop1", run_in_background=true, model="opus", description=..., prompt=<audit XML loop 1>)` | `SKILL.md` § AUDIT action |
111
111
  | 7 | Lead awaits background-completion notification | `SKILL.md` § AUDIT action |
112
112
  | 8 | `Read(".bugteam-pr42-loop1.outcomes.xml")` | `SKILL.md` § AUDIT action |
@@ -116,17 +116,17 @@ The harness does not yet exist; this document defines its contract.
116
116
  | 12 | `Bash("git -C \"<run_temp_dir>/pr-42/worktree\" rev-parse HEAD")` → verify HEAD advanced | `SKILL.md` § FIX action (**Verify**) |
117
117
  | 13 | `Bash("git -C \"<run_temp_dir>/pr-42/worktree\" fetch origin <branch>")` → fetch remote state | `SKILL.md` § FIX action (**Verify**) |
118
118
  | 14 | `Bash("git -C \"<run_temp_dir>/pr-42/worktree\" rev-parse origin/<branch>")` → confirm matches HEAD | `SKILL.md` § FIX action (**Verify**) |
119
- | 15 | `Bash("gh pr diff 42 -R ... > <run_temp_dir>/pr-42/loop-2.patch")` | `SKILL.md` § AUDIT action |
119
+ | 15 | `pull_request_read(method="get_diff", pullNumber=42, owner=..., repo=...)` write to `<run_temp_dir>/pr-42/loop-2.patch` | `SKILL.md` § AUDIT action |
120
120
  | 16 | `Agent(subagent_type="code-quality-agent", name="bugfind-pr42-loop2", run_in_background=true, ...)` (loop 2) | `SKILL.md` § AUDIT action |
121
121
  | 17 | Lead awaits background-completion notification | `SKILL.md` § AUDIT action |
122
122
  | 18 | `Read(".bugteam-pr42-loop2.outcomes.xml")` — zero findings | `SKILL.md` § AUDIT action |
123
123
  | 19 | `Bash("git worktree remove \"<run_temp_dir>/pr-42/worktree\"")` | `SKILL.md` § Step 4 step 1 |
124
124
  | 20 | `Bash("python -c \"...shutil.rmtree(r'<run_temp_dir>', ...)\"")` | `SKILL.md` § Step 4 step 2 (Windows-safe teardown) |
125
- | 21 | `Bash("gh pr diff 42 -R ... > .bugteam-final.diff")` | `SKILL.md` § Step 4.5 step 1 |
126
- | 22 | `Bash("gh pr view 42 -R ... --json body --jq .body > .bugteam-original-body.md")` | `SKILL.md` § Step 4.5 step 2 |
125
+ | 21 | `pull_request_read(method="get_diff", pullNumber=42, owner=..., repo=...)` write to `.bugteam-final.diff` | `SKILL.md` § Step 4.5 step 1 |
126
+ | 22 | `pull_request_read(method="get", pullNumber=42, owner=..., repo=...)` extract `.body`, write to `.bugteam-original-body.md` | `SKILL.md` § Step 4.5 step 2 |
127
127
  | 23 | `Agent(subagent_type="pr-description-writer", description=..., prompt=<brief>)` | `SKILL.md` § Step 4.5 |
128
128
  | 24 | `Write(".bugteam-final-body.md", <returned body>)` | `SKILL.md` § Step 4.5 step 4 |
129
- | 25 | `Bash("gh pr edit 42 -R ... --body-file .bugteam-final-body.md")` | `SKILL.md` § Step 4.5 step 4 |
129
+ | 25 | `update_pull_request(pullNumber=42, owner=..., repo=..., body=...)` | `SKILL.md` § Step 4.5 step 4 |
130
130
  | 26 | `Bash("rm .bugteam-final.diff .bugteam-original-body.md .bugteam-final-body.md")` | `SKILL.md` § Step 4.5 step 5 |
131
131
  | 27 | `Bash("python .../scripts/revoke_project_claude_permissions.py")` | `SKILL.md` § Step 5 |
132
132
 
@@ -224,7 +224,7 @@ Patch this table to match observation and annotate each correction.
224
224
  - Every finding's outcome XML carries `used_fallback="true"` and the issue-comment URL as `finding_comment_url`.
225
225
  - Cycle continues to the FIX action without aborting.
226
226
 
227
- **Open item for the real run.** The issue-comments fallback shape is `jq -Rs | gh api .../issues/<number>/comments --input -` (`SKILL.md` § Step 2.5 **Review POST fails**; full narrative in `reference/github-pr-reviews.md` § **Review POST failure fallback**). Before running Eval 10 for real, confirm the teammate obeys this shape — the fixture must assert the endpoint path and the `--input -` pattern.
227
+ **Open item for the real run.** The issue-comments fallback uses `add_issue_comment(owner=..., repo=..., issueNumber=42, body=...)` (`SKILL.md` § Step 2.5 **Review POST fails**; full narrative in `reference/github-pr-reviews.md` § **Review POST failure fallback**). Before running Eval 10 for real, confirm the teammate obeys this shape — the fixture must assert the `add_issue_comment` tool call.
228
228
 
229
229
  ---
230
230
 
@@ -8,55 +8,55 @@ Per-loop pull-request reviews: findings render as a tree under one parent review
8
8
 
9
9
  **Ordering:** Bugfind audits first, buffers findings, validates anchors against the captured diff, then posts the review **once** at the end. The review body states the finding count authoritatively. Keep all posting in that single end-of-loop review POST.
10
10
 
11
- ## CLI shapes (teammate)
11
+ ## MCP tool shapes (teammate)
12
12
 
13
- All three POSTs use the same pattern: build JSON with `jq` (`--rawfile` or `-Rs` so markdown with backticks, newlines, and quotes survives intact), then pipe to `gh api ... --input -` on stdin. This avoids shell-quoting edge cases.
13
+ All three POSTs use MCP tool calls. Body text with markdown (backticks, newlines, quotes) passes through safely as string parameters no temp files, no jq, no shell pipes.
14
14
 
15
15
  ### Per-loop review (one POST creates parent + children)
16
16
 
17
17
  Build `comments[]` programmatically from buffered, diff-anchored findings. Single-line shape: `{path, line, side: "RIGHT", body: <finding markdown>}`. Multi-line: `{path, start_line, start_side: "RIGHT", line, side: "RIGHT", body: ...}` (all four anchor fields required).
18
18
 
19
19
  ```
20
- jq -n \
21
- --rawfile review_body <tmp_review_body.md> \
22
- --arg commit_id "$(git rev-parse HEAD)" \
23
- --rawfile finding_body_1 <tmp_finding_1.md> \
24
- --arg path_1 "<file_1>" \
25
- --argjson line_1 <line_1> \
26
- [... one finding_body_K / path_K / line_K triple per anchored finding ...] \
27
- '{
28
- commit_id: $commit_id,
29
- event: "COMMENT",
30
- body: $review_body,
31
- comments: [
32
- {path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
33
- [, ... one object per anchored finding ...]
34
- ]
35
- }' \
36
- | gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
20
+ pull_request_review_write(
21
+ method="create",
22
+ event="COMMENT",
23
+ body=<review_body_markdown>,
24
+ commitID=<head_sha_at_post_time>,
25
+ owner=<owner>, repo=<repo>, pullNumber=<pull_number>,
26
+ comments=[
27
+ {path: <file_1>, line: <line_1>, side: "RIGHT", body: <finding_1_markdown>}
28
+ [, ... one object per anchored finding ...]
29
+ ]
30
+ )
37
31
  ```
38
32
 
39
- Response JSON includes the parent review `id` / `html_url` and a `comments` array of child comments (`id`, `html_url`). Harvest children in index order and align with the finding list.
33
+ Response includes the parent review `html_url` and a `comments` array of child comments (`id`, `html_url`). Harvest children in index order and align with the finding list.
40
34
 
41
35
  ### Fix reply
42
36
 
43
37
  ```
44
- jq -Rs '{body: .}' < <tmp_reply.md> \
45
- | gh api repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X POST --input -
38
+ add_reply_to_pull_request_comment(
39
+ commentId=<finding_comment_id>,
40
+ body=<reply_markdown>,
41
+ owner=<owner>, repo=<repo>, pullNumber=<pull_number>
42
+ )
46
43
  ```
47
44
 
48
45
  ### Review POST failure fallback
49
46
 
50
- Top-level PR comment via issue-comments (`{issue_number}` is the PR number):
47
+ Top-level PR comment via issue-comments (`issue_number` is the PR number):
51
48
 
52
49
  ```
53
- jq -Rs '{body: .}' < <tmp_fallback.md> \
54
- | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST --input -
50
+ add_issue_comment(
51
+ owner=<owner>, repo=<repo>,
52
+ issueNumber=<pull_number>,
53
+ body=<full_fallback_markdown>
54
+ )
55
55
  ```
56
56
 
57
57
  `<head_sha_at_post_time>` is the SHA at post time (`git rev-parse HEAD` in the teammate’s working directory immediately before the POST). The review anchors finding comments to the head SHA at audit time (before this loop’s fix lands).
58
58
 
59
- Write each body (review body and every per-finding body) to its own temp file before the `jq` pipeline. Bodies stay inside files the pipeline reads they reach GitHub inside the JSON payload — which keeps them compatible with the `gh-body-backtick-guard` hook that scans command-line `--body` arguments.
59
+ Body text is passed directly as string parameters to the MCP tool callsno temp files, no jq, no shell pipes.
60
60
 
61
61
  ## Review body template (`<tmp_review_body.md>`)
62
62
 
@@ -77,10 +77,10 @@ GitHub rejects the entire review POST if any `comments[]` entry targets a line n
77
77
 
78
78
  ## Review POST failure fallback
79
79
 
80
- If the review POST fails (rate limit, network, malformed payload), fall back to one top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run: `used_fallback="true"`, `finding_comment_url` = issue-comment URL. Use the issue-comment CLI shape above.
80
+ If the review POST fails (rate limit, network, malformed payload), fall back to one top-level issue comment containing the review body plus every finding inline (severity, file:line, description). Every finding in that run: `used_fallback="true"`, `finding_comment_url` = issue-comment URL. Use `add_issue_comment` (see MCP tool reference below).
81
81
 
82
- ## GitHub REST endpoints
82
+ ## MCP tool reference
83
83
 
84
- - Per-loop batched review: `POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews` (required: `body`, `event=COMMENT`, `commit_id`; optional `comments[]` — each entry needs `path`, `body`, `line`, `side`)
85
- - Fix reply: `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies` (required: `body`)
86
- - Review-POST failure fallback: `POST /repos/{owner}/{repo}/issues/{issue_number}/comments` (required: `body`; `{issue_number}` is the PR number)
84
+ - Per-loop batched review: `pull_request_review_write(method="create", event="COMMENT", body=..., commitID=..., owner=..., repo=..., pullNumber=..., comments=[...])` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
85
+ - Fix reply: `add_reply_to_pull_request_comment(commentId=..., body=..., owner=..., repo=..., pullNumber=...)` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies`
86
+ - Review-POST failure fallback: `add_issue_comment(owner=..., repo=..., issueNumber=..., body=...)` — wraps `POST /repos/{owner}/{repo}/issues/{issue_number}/comments`
@@ -14,7 +14,7 @@ This is the **first** action of every `/bugteam` invocation, before any subagent
14
14
 
15
15
  Same resolution path as `/findbugs`:
16
16
 
17
- 1. `gh pr view --json number,baseRefName,headRefName,url` from the working directory.
17
+ 1. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` — extracts `number`, `baseRefName`, `headRefName`, `url` from response (`N` comes from the parent skill's PR context, or fall back to `pull_request_read` with the default branch lookup to recover the PR number).
18
18
  2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
19
19
  3. Neither → refuse per refusal cases in `SKILL.md`.
20
20
 
@@ -34,15 +34,15 @@ If that subagent is missing, fall back to `general-purpose` with the same brief
34
34
 
35
35
  **Steps:**
36
36
 
37
- 1. Capture cumulative diff: `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`.
38
- 2. Capture original body: `gh pr view <number> -R <owner>/<repo> --json body --jq .body > .bugteam-original-body.md`.
37
+ 1. Capture cumulative diff: `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` write output to `.bugteam-final.diff` with `Write` tool.
38
+ 2. Capture original body: `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` extract `.body` from response, write to `.bugteam-original-body.md` with `Write` tool.
39
39
  3. Agent brief:
40
40
  - **Inputs:** diff path, original body path, head branch, base branch.
41
41
  - **Constraint:** describe what the PR delivers from the cumulative diff — behavior, user-visible effect, merge rationale. Process metadata (loops, fix counts, findings) stays in review comments.
42
- - **Preservation rule:** if the original body has manually curated sections (linked issues, screenshots, test plan, Risk Assessment”, etc.), preserve them verbatim and only rewrite narrative around them.
42
+ - **Preservation rule:** if the original body has manually curated sections (linked issues, screenshots, test plan, "Risk Assessment", etc.), preserve them verbatim and only rewrite narrative around them.
43
43
  - **Output:** new body markdown.
44
44
  4. Write `.bugteam-final-body.md`.
45
- 5. `gh pr edit <number> -R <owner>/<repo> --body-file .bugteam-final-body.md`.
45
+ 5. `update_pull_request(pullNumber=N, owner=O, repo=R, body=<body_text>)`.
46
46
  6. Delete `.bugteam-final.diff`, `.bugteam-original-body.md`, `.bugteam-final-body.md`.
47
47
 
48
48
  If Step 4.5 fails (agent error, hook block, network), report in the final report and continue to Step 5. The original PR body remains; commits and comments are unaffected.
@@ -26,10 +26,10 @@ The user is on a PR branch, wants Copilot (the GitHub Copilot reviewer bot) to k
26
26
  From the current repo:
27
27
 
28
28
  ```bash
29
- gh pr view --json number,url,headRefOid,baseRefName,headRefName,isDraft
29
+ # MCP: pull_request_read(method="get") returns {number, url, head.sha, base.ref, head.ref, isDraft}
30
30
  ```
31
31
 
32
- Capture `number`, `headRefOid`, owner/repo (from `url`), and branch name. Pass these to the subagent so it does not rediscover them.
32
+ Capture `number`, `head.sha`, owner/repo (from `url`), and branch name. Pass these to the subagent so it does not rediscover them.
33
33
 
34
34
  ### Step 2: Spawn the background subagent
35
35
 
@@ -57,23 +57,16 @@ Pass this verbatim to the subagent (substituting the bracketed values):
57
57
  >
58
58
  > **Per-tick work** (do this now, then on each wakeup):
59
59
  >
60
- > 1. Resolve current HEAD: `gh api repos/[OWNER]/[REPO]/pulls/[NUMBER] --jq '.head.sha'`.
61
- > 2. Fetch latest Copilot review:
62
- > ```bash
63
- > gh api repos/[OWNER]/[REPO]/pulls/[NUMBER]/reviews \
64
- > --jq '[.[] | select(.user.login=="copilot-pull-request-reviewer[bot]")] | sort_by(.submitted_at) | last'
65
- > ```
60
+ > 1. Resolve current HEAD: `pull_request_read(method="get", pullNumber=[NUMBER], owner="[OWNER]", repo="[REPO]")` and extract `.head.sha`.
61
+ > 2. Fetch latest Copilot review via `pull_request_read(method="get_reviews", pullNumber=[NUMBER], owner="[OWNER]", repo="[REPO]")`.
66
62
  > Capture `commit_id`, `state`, `submitted_at`, `id`.
67
63
  > 3. Decide the branch:
68
64
  > - **No review exists:** re-request (step 4), schedule next wakeup, return.
69
65
  > - **Latest review's `commit_id` != current HEAD:** re-request (step 4), schedule next wakeup, return.
70
66
  > - **Latest review's `commit_id` == current HEAD with unresolved inline findings:** TDD-fix them, push, reply inline on each thread, re-request (step 4), schedule next wakeup, return.
71
67
  > - **Latest review's `commit_id` == current HEAD and clean:** report convergence to the parent with a one-sentence summary and terminate. The loop is done; skip the ScheduleWakeup call.
72
- > 4. Re-request Copilot. The reviewer ID **must** be `copilot-pull-request-reviewer[bot]` with the `[bot]` suffix — empirically verified: `Copilot`, `copilot`, and `github-copilot` all return `requested_reviewers: []` with no error, silently no-op.
73
- > ```bash
74
- > gh api -X POST repos/[OWNER]/[REPO]/pulls/[NUMBER]/requested_reviewers \
75
- > -f 'reviewers[]=copilot-pull-request-reviewer[bot]'
76
- > ```
68
+ > 4. Re-request Copilot via `request_copilot_review(owner="[OWNER]", repo="[REPO]", pullNumber=[NUMBER])`.
69
+ > The reviewer ID **must** be `copilot-pull-request-reviewer[bot]` with the `[bot]` suffix — empirically verified: `Copilot`, `copilot`, and `github-copilot` all return `requested_reviewers: []` with no error, silently no-op.
77
70
  > 5. Schedule the next wakeup with `ScheduleWakeup`:
78
71
  > - `delaySeconds: 300`
79
72
  > - `reason`: one short sentence on what you are waiting for.
@@ -86,7 +79,7 @@ Pass this verbatim to the subagent (substituting the bracketed values):
86
79
  > - Implement the fix.
87
80
  > - Stage the fix and create one new commit on the existing branch: `git add <files> && git commit -m "fix(review): ..."`.
88
81
  > - Push the new commit: `git push origin [BRANCH]`.
89
- > - Reply inline on each comment thread with `gh api -X POST repos/[OWNER]/[REPO]/pulls/[NUMBER]/comments` using `in_reply_to` set to the comment id, referencing the new commit SHA.
82
+ > - Reply inline on each comment thread with `add_reply_to_pull_request_comment(owner="[OWNER]", repo="[REPO]", pullNumber=[NUMBER], body="...", commentId=<comment_id>)`, referencing the new commit SHA.
90
83
  >
91
84
  > When a pre-push, pre-commit, or other hook rejects the change, solve it. Read the hook's error message, diagnose the root cause in the code or test, and fix that. Then rerun the commit or push. Hooks exist to catch real problems; treat each rejection as new evidence to act on.
92
85
  >
@@ -24,7 +24,7 @@ If the current branch has no associated PR and no diff against the default branc
24
24
 
25
25
  Determine the audit target in this order:
26
26
 
27
- 1. **Open PR for current branch.** Run `gh pr view --json number,baseRefName,headRefName,url` from the working directory. If a PR exists, capture its number, base ref, head ref, and URL.
27
+ 1. **Open PR for current branch.** Call `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` for the current branch (`N` comes from the parent skill's context, or fall back to `search_issues` MCP with the current branch name to recover the PR number). If a PR exists, capture its number, base ref, head ref, and URL.
28
28
  2. **No PR but a remote default branch exists.** Diff against the default branch's merge-base: `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`. Treat this as the audit scope.
29
29
  3. **Neither.** Respond exactly: `No PR or upstream diff found. Push the branch or open a PR first.` and stop.
30
30
 
@@ -39,7 +39,7 @@ diff_temp_path = Path(tempfile.gettempdir()) / f"findbugs-pr-{os.getpid()}.patch
39
39
 
40
40
  `os.getpid()` supplies the per-invocation suffix that prevents collisions with parallel `/findbugs` runs (a UUID or timestamp is equally acceptable). Capture the resolved absolute path as `<diff_temp_path>` and pass that **literal** path to every shell command that follows. Shell-side parameter expansion (`${TMPDIR:-/tmp}`, `$$`, `%TEMP%`) is forbidden because cmd.exe and PowerShell do not honor it.
41
41
 
42
- When a PR exists: `gh pr diff <number> -R <owner>/<repo> > "<diff_temp_path>"`.
42
+ When a PR exists: call `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` and save the returned diff content to `"<diff_temp_path>"`.
43
43
 
44
44
  When falling back to merge-base diff: `git diff <merge-base>...HEAD > "<diff_temp_path>"`.
45
45
 
@@ -49,7 +49,7 @@ If the filtered set is empty, refuse per the refusal cases above.
49
49
 
50
50
  Re-establish the same PR target `/findbugs` used:
51
51
 
52
- 1. `gh pr view --json number,baseRefName,headRefName,url` from the working directory.
52
+ 1. `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` for the current branch (`N` comes from the parent skill's PR context, or fall back to `search_issues` MCP with the current branch name to recover the PR number).
53
53
  2. Fall back to `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`.
54
54
  3. Neither → respond `No PR or upstream diff. Cannot scope fixes.` and stop.
55
55