claude-dev-env 1.37.0 → 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 (95) 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/gh-paginate.md +4 -50
  24. package/rules/no-historical-clutter.md +57 -0
  25. package/scripts/config/groq_bugteam_config.py +13 -5
  26. package/skills/bugteam/CONSTRAINTS.md +20 -27
  27. package/skills/bugteam/EXAMPLES.md +1 -1
  28. package/skills/bugteam/PROMPTS.md +78 -42
  29. package/skills/bugteam/SKILL.md +76 -63
  30. package/skills/bugteam/SKILL_EVALS.md +12 -12
  31. package/skills/bugteam/reference/audit-and-teammates.md +21 -48
  32. package/skills/bugteam/reference/audit-contract.md +7 -7
  33. package/skills/bugteam/reference/github-pr-reviews.md +31 -31
  34. package/skills/bugteam/reference/team-setup.md +1 -1
  35. package/skills/bugteam/reference/teardown-publish-permissions.md +4 -4
  36. package/skills/copilot-review/SKILL.md +7 -14
  37. package/skills/findbugs/SKILL.md +2 -2
  38. package/skills/fixbugs/SKILL.md +1 -1
  39. package/skills/monitor-open-prs/SKILL.md +6 -6
  40. package/skills/pr-converge/SKILL.md +7 -6
  41. package/skills/pr-converge/reference/convergence-gates.md +46 -44
  42. package/skills/pr-converge/reference/examples.md +4 -4
  43. package/skills/pr-converge/reference/fix-protocol.md +8 -8
  44. package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -10
  45. package/skills/pr-converge/reference/per-tick.md +24 -36
  46. package/skills/pr-converge/reference/stop-conditions.md +7 -7
  47. package/skills/pr-converge/scripts/README.md +65 -117
  48. package/skills/pr-review-responder/EXAMPLES.md +2 -2
  49. package/skills/pr-review-responder/PRINCIPLES.md +2 -8
  50. package/skills/pr-review-responder/README.md +7 -48
  51. package/skills/pr-review-responder/SKILL.md +2 -3
  52. package/skills/pr-review-responder/TESTING.md +8 -65
  53. package/skills/qbug/SKILL.md +10 -16
  54. package/_shared/pr-loop/scripts/config/gh_util_constants.py +0 -31
  55. package/_shared/pr-loop/scripts/gh_util.py +0 -193
  56. package/_shared/pr-loop/scripts/tests/test_gh_util.py +0 -257
  57. package/_shared/pr-loop/scripts/tests/test_gh_util_constants.py +0 -61
  58. package/skills/pr-converge/scripts/check_pr_mergeability.py +0 -78
  59. package/skills/pr-converge/scripts/config/pr_converge_constants.py +0 -118
  60. package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +0 -152
  61. package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +0 -70
  62. package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +0 -57
  63. package/skills/pr-converge/scripts/fetch_claude_inline_comments.py +0 -70
  64. package/skills/pr-converge/scripts/fetch_claude_reviews.py +0 -61
  65. package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +0 -70
  66. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +0 -61
  67. package/skills/pr-converge/scripts/mark_pr_ready.py +0 -54
  68. package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +0 -49
  69. package/skills/pr-converge/scripts/post-bugbot-run.ps1 +0 -33
  70. package/skills/pr-converge/scripts/reply_to_inline_comment.py +0 -84
  71. package/skills/pr-converge/scripts/request_copilot_review.py +0 -71
  72. package/skills/pr-converge/scripts/resolve_pr_head.py +0 -58
  73. package/skills/pr-converge/scripts/review_field_helpers.py +0 -43
  74. package/skills/pr-converge/scripts/reviewer_fetch_core.py +0 -153
  75. package/skills/pr-converge/scripts/reviewer_specs.py +0 -98
  76. package/skills/pr-converge/scripts/test_check_pr_mergeability.py +0 -126
  77. package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +0 -443
  78. package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +0 -299
  79. package/skills/pr-converge/scripts/test_fetch_claude_inline_comments.py +0 -485
  80. package/skills/pr-converge/scripts/test_fetch_claude_reviews.py +0 -368
  81. package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +0 -440
  82. package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +0 -366
  83. package/skills/pr-converge/scripts/test_mark_pr_ready.py +0 -69
  84. package/skills/pr-converge/scripts/test_post_bugbot_run.py +0 -195
  85. package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +0 -159
  86. package/skills/pr-converge/scripts/test_request_copilot_review.py +0 -101
  87. package/skills/pr-converge/scripts/test_resolve_pr_head.py +0 -79
  88. package/skills/pr-converge/scripts/test_review_field_helpers.py +0 -80
  89. package/skills/pr-converge/scripts/test_reviewer_fetch_core.py +0 -448
  90. package/skills/pr-converge/scripts/test_reviewer_specs.py +0 -107
  91. package/skills/pr-converge/scripts/test_trigger_bugbot.py +0 -139
  92. package/skills/pr-converge/scripts/test_view_pr_context.py +0 -111
  93. package/skills/pr-converge/scripts/trigger_bugbot.py +0 -77
  94. package/skills/pr-converge/scripts/view_pr_context.py +0 -47
  95. package/skills/pr-review-responder/scripts/respond_to_reviews.py +0 -376
@@ -11,32 +11,36 @@ Fetch latest Copilot reviewer (`copilot-pull-request-reviewer[bot]`) review
11
11
  plus inline comments anchored to most recent Copilot review on
12
12
  `current_head`:
13
13
 
14
- ```bash
15
- python "${CLAUDE_SKILL_DIR}/scripts/fetch_copilot_reviews.py" \
16
- --owner <OWNER> --repo <REPO> --number <NUMBER>
14
+ ```
15
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_reviews")
16
+ filter `.user.login` for copilot (case-insensitive substring "copilot")
17
+ → sort by `.submitted_at` descending
17
18
 
18
- python "${CLAUDE_SKILL_DIR}/scripts/fetch_copilot_inline_comments.py" \
19
- --owner <OWNER> --repo <REPO> --number <NUMBER> --commit "$current_head"
19
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_comments")
20
+ filter threads where `is_outdated == false` AND any comment has `.author` matching Copilot (case-insensitive substring "copilot")
20
21
  ```
21
22
 
22
23
  Decide (four branches; match first whose predicate holds):
23
24
 
24
25
  - **`classification == "dirty"` with non-empty inline comments matching
25
26
  `pull_request_review_id`:** Fix protocol input (same shape as bugbot
26
- dirty). Apply Fix protocol on every inline finding (TDD test
27
- production fixpush reply inline on each thread), reset
28
- `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase = BUGBOT`,
29
- Step 3 on new HEAD, schedule next wakeup, return. Full
30
- back-to-back-clean cycle plus all four gates must hold again on new HEAD.
27
+ dirty). Spawn Agent (subagent_type: clean-coder) to implement → push → reply inline on each thread via
28
+ `add_reply_to_pull_request_comment` MCPStep 3 in same tick (see
29
+ [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
30
+ full contract).
31
+ Reset `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase =
32
+ BUGBOT`, schedule next wakeup, return. Full back-to-back-clean cycle
33
+ plus all four gates must hold again on new HEAD.
31
34
  - **`classification == "dirty"` with empty inline comments matching
32
35
  `pull_request_review_id`:** Copilot posted findings only in review body
33
36
  (`CHANGES_REQUESTED` or `COMMENTED` with non-empty body, no inline
34
- threads). Parse body for actionable findings, apply Fix protocol using
35
- body excerpts (TDD test production fixpush). Post top-level review
36
- reply acknowledging fixes and citing new HEAD SHA. Reset
37
- `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase =
38
- BUGBOT`, Step 3 on new HEAD, schedule next wakeup, return. Convergence
39
- requires full back-to-back-clean on new HEAD.
37
+ threads). Parse body for actionable findings. Spawn Agent (subagent_type: clean-coder) to implement → push → post
38
+ top-level review reply using `pull_request_review_write(method="create", event="COMMENT", body)` citing new HEAD SHA Step 3 in same tick.
39
+ Reset
40
+ `bugbot_clean_at = null` AND
41
+ `copilot_clean_at = null`, `phase = BUGBOT`, Step 3 on new HEAD,
42
+ schedule next wakeup, return. Convergence requires full
43
+ back-to-back-clean on new HEAD.
40
44
  - **`classification == "clean"` (state `APPROVED`):** Set
41
45
  `copilot_clean_at = current_head`. Continue to gate (b).
42
46
  - **No Copilot review on `current_head` yet:** Skip — gate (c) issues
@@ -46,16 +50,16 @@ Decide (four branches; match first whose predicate holds):
46
50
 
47
51
  Resolve PR's mergeability state:
48
52
 
49
- ```bash
50
- python "${CLAUDE_SKILL_DIR}/scripts/check_pr_mergeability.py" \
51
- --owner <OWNER> --repo <REPO> --number <NUMBER>
53
+ ```
54
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get")
55
+ `.mergeable_state`, `.mergeable`
52
56
  ```
53
57
 
54
- Persist `mergeStateStatus` into `merge_state_status`. Decide:
58
+ Persist `mergeable_state` into `merge_state_status`. Decide:
55
59
 
56
- - **`mergeStateStatus == "CLEAN"` AND `mergeable == "MERGEABLE"`:**
60
+ - **`mergeable_state == "clean"` AND `mergeable == true`:**
57
61
  Continue to gate (c).
58
- - **`mergeStateStatus == "DIRTY"` (or `mergeable == "CONFLICTING"`):** Do
62
+ - **`mergeable_state == "dirty"` (or `mergeable == false`):** Do
59
63
  **not** mark ready. Invoke **`rebase`** skill
60
64
  ([`../../rebase/SKILL.md`](../../rebase/SKILL.md)) Phase 1–4 against PR's
61
65
  base ref. After rebase + force-with-lease push, new HEAD invalidates
@@ -63,39 +67,39 @@ Persist `mergeStateStatus` into `merge_state_status`. Decide:
63
67
  `copilot_clean_at = null`, `merge_state_status = null`, `phase = BUGBOT`,
64
68
  Step 3 on new HEAD, schedule next wakeup, return. Loop re-runs from
65
69
  scratch on new HEAD.
66
- - **`mergeStateStatus` is `BLOCKED`, `BEHIND`, or `UNKNOWN` for
70
+ - **`mergeable_state` is `"blocked"`, `"behind"`, or `"unknown"` for
67
71
  non-conflict reasons** (required checks pending, branch behind base
68
72
  without conflicts GitHub cannot auto-resolve): **hard blocker** per
69
73
  [stop-conditions.md](stop-conditions.md) — do not invent a fix. Report specific
70
- `mergeStateStatus`, omit loop pacing.
74
+ `mergeable_state`, omit loop pacing.
71
75
 
72
76
  ## (c) Post-convergence Copilot review request
73
77
 
74
78
  Once gates (a) and (b) both pass (Copilot clean at `current_head` *or* no
75
- Copilot review yet, AND `mergeStateStatus == "CLEAN"`), request Copilot
79
+ Copilot review yet, AND `mergeable_state == "clean"`), request Copilot
76
80
  review:
77
81
 
78
- ```bash
79
- python "${CLAUDE_SKILL_DIR}/scripts/request_copilot_review.py" \
80
- --owner <OWNER> --repo <REPO> --number <NUMBER>
82
+ ```
83
+ request_copilot_review(owner=OWNER, repo=REPO, pullNumber=NUMBER)
81
84
  ```
82
85
 
86
+ When the `request_copilot_review` MCP tool is unavailable, use `add_issue_comment` as fallback: `add_issue_comment(owner=OWNER, repo=REPO, issueNumber=NUMBER, body="@copilot review")`.
87
+
83
88
  After request, schedule next wakeup and return — next tick checks response.
84
89
 
85
90
  Next tick with `phase == BUGTEAM` and prior state preserved → re-run gate
86
91
  (a) first. Decide:
87
92
 
88
93
  - **Copilot review `clean` (state `APPROVED`):** Set `copilot_clean_at =
89
- current_head`. Mark PR ready (`mark_pr_ready.py`), report convergence
94
+ current_head`. Mark PR ready (`update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`), report convergence
90
95
  per §(d), terminate per [stop-conditions.md](stop-conditions.md) / Convergence.
91
96
  - **Copilot review `dirty`:** Treat identically to gate (a) dirty path —
92
- fix in same PR, restart convergence from BUGBOT. Apply Fix protocol on
93
- every confirmed Copilot finding (TDD test production fix push
94
- reply inline on each thread; for body-only findings with empty inline,
95
- parse body excerpts and post top-level review reply citing new HEAD).
96
- Reset `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase =
97
- BUGBOT`, Step 3 on new HEAD, schedule next wakeup, return. Full
98
- back-to-back-clean cycle plus all four gates must hold again on new HEAD.
97
+ spawn Agent (subagent_type: clean-coder) to fix in same PR, restart convergence from BUGBOT. Follow [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow).
98
+ For body-only findings with empty inline, spawn Agent (subagent_type: clean-coder) to implement, then post top-level review reply
99
+ citing new HEAD SHA. Reset `bugbot_clean_at = null` AND
100
+ `copilot_clean_at = null`, `phase = BUGBOT`, schedule next wakeup,
101
+ return. Full back-to-back-clean cycle plus all four gates must hold
102
+ again on new HEAD.
99
103
  - **No Copilot review at `current_head` yet (still propagating):**
100
104
  Schedule one more wakeup (270s), re-check next tick. After three consecutive empty waits,
101
105
  escalate as hard blocker per [stop-conditions.md](stop-conditions.md).
@@ -103,16 +107,14 @@ Next tick with `phase == BUGTEAM` and prior state preserved → re-run gate
103
107
  ## (d) Mark ready and report
104
108
 
105
109
  Only when all four gates pass — bugbot CLEAN ∧ bugteam CLEAN ∧
106
- `mergeStateStatus == "CLEAN"` ∧ Copilot CLEAN at HEAD — run:
110
+ `mergeable_state == "clean"` ∧ Copilot CLEAN at HEAD — run:
107
111
 
108
- ```bash
109
- python "${CLAUDE_SKILL_DIR}/scripts/mark_pr_ready.py" \
110
- --owner <OWNER> --repo <REPO> --number <NUMBER>
111
- ```
112
+ Use the `update_pull_request` MCP tool:
113
+
114
+ update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)
112
115
 
113
- When scripts unavailable, `gh pr ready <NUMBER> --repo <OWNER>/<REPO>` is
114
- equivalent. With `state.json`, append convergence row to
116
+ With `state.json`, append convergence row to
115
117
  `<TMPDIR>/pr-converge-<session_id>/converged.log` per `multi-pr-orchestration.md` §Memory; else skip.
116
118
  Report: `PR #<NUMBER> converged: bugbot CLEAN at <SHA>, bugteam CLEAN at
117
- <SHA>, mergeStateStatus CLEAN, copilot CLEAN at <SHA>; marked ready for
119
+ <SHA>, mergeable_state CLEAN, copilot CLEAN at <SHA>; marked ready for
118
120
  review`. **Omit loop pacing** per **Convergence** of active pacing workflow.
@@ -25,7 +25,7 @@ convergence or stop]
25
25
  </example>
26
26
 
27
27
  <example> BUGTEAM phase, bugteam reports convergence and `bugbot_clean_at
28
- == current_head`. Claude: [runs `gh pr ready <NUMBER>`, reports "PR
28
+ == current_head`. Claude: [runs `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`, reports "PR
29
29
  converged: bugbot CLEAN at <SHA>, bugteam CLEAN at <SHA>; marked ready for
30
30
  review", applies **Convergence** from `workflows/schedule-wakeup-loop.md`]
31
31
  </example>
@@ -58,11 +58,11 @@ HEAD, schedules next wakeup]
58
58
  </example>
59
59
 
60
60
  <example> Back-to-back clean, mergeability CLEAN, no Copilot review on
61
- `current_head`. Claude requests Copilot via `request_copilot_review.py`,
61
+ `current_head`. Claude requests Copilot via `add_issue_comment(owner=OWNER, repo=REPO, issueNumber=NUMBER, body="@copilot review")`,
62
62
  waits one tick. Next tick: Copilot review `state: APPROVED`. Claude: [sets
63
- `copilot_clean_at = current_head`; runs `mark_pr_ready.py`; reports "PR
63
+ `copilot_clean_at = current_head`; runs `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`; reports "PR
64
64
  #N converged: bugbot CLEAN at <SHA>, bugteam CLEAN at <SHA>,
65
- mergeStateStatus CLEAN, copilot CLEAN; marked ready for review"]
65
+ mergeable_state clean, copilot CLEAN; marked ready for review"]
66
66
  </example>
67
67
 
68
68
  <example> Back-to-back clean, mergeability CLEAN, post-convergence Copilot
@@ -8,8 +8,8 @@ per [ground-rules.md](ground-rules.md).
8
8
  **Multi-PR (`state.json`) teammate obligations** (plus TDD, commit, push):
9
9
 
10
10
  - Replies inline on each addressed finding via
11
- `reply_to_inline_comment.py` (what changed + commit identifier),
12
- matching §Audit result → fix worker step 4 — **before** writing
11
+ `add_reply_to_pull_request_comment(owner, repo, pullNumber, commentId, body)`
12
+ (what changed + commit identifier), matching §Audit result → fix worker step 4 — **before** writing
13
13
  `state.json` and going idle.
14
14
  - Writes `last_action: "fix_pushed"`, `current_head: <new SHA>`,
15
15
  `bugbot_clean_at: null`, `phase: "BUGBOT"`, `status: "awaiting_bugbot"`,
@@ -20,6 +20,8 @@ per [ground-rules.md](ground-rules.md).
20
20
  Orchestrator does not reply inline, trigger bugbot, or read repo source
21
21
  files during fix phase in multi-PR mode.
22
22
 
23
+ ### Single-PR fix workflow
24
+
23
25
  **Single-PR (no `state.json`) — same gates, main session executor:**
24
26
 
25
27
  - Read each referenced file:line.
@@ -38,12 +40,10 @@ git push origin <BRANCH>
38
40
  ```
39
41
  **Pre-push gate:** honor hooks; full-stop on bypass. Capture new HEAD
40
42
  only after both gates pass; set `current_head`, `bugbot_clean_at = null`.
41
- - Reply inline on each addressed comment thread using `--body-file` (per
42
- gh-body-file rule):
43
- ```bash
44
- python "${CLAUDE_SKILL_DIR}/scripts/reply_to_inline_comment.py" \
45
- --owner <OWNER> --repo <REPO> --number <NUMBER> \
46
- --comment-id <COMMENT_ID> --body-file <path/to/reply.md>
43
+ - Reply inline on each addressed comment thread using the `add_reply_to_pull_request_comment` MCP tool:
44
+
45
+ ```
46
+ add_reply_to_pull_request_comment(owner=OWNER, repo=REPO, pullNumber=NUMBER, commentId=COMMENT_ID, body="Fixed in <SHA> — <what changed>")
47
47
  ```
48
48
  - **After pushing a fix, always run Step 3 (`bugbot run`) in the same
49
49
  tick** regardless of phase. New commit **resets full convergence cycle**:
@@ -25,7 +25,7 @@ Create once at session start. Each teammate writes result before going idle.
25
25
 
26
26
  **Directory lifecycle:** Keep `<TMPDIR>/pr-converge-<session_id>/` until every
27
27
  `prs[...]` is `converged` or `blocked`, or user stops. Then delete folder.
28
- `mark_pr_ready.py` / `gh pr ready` on GitHub is canonical record. See
28
+ `update_pull_request(draft=false)` on GitHub is canonical record. See
29
29
  [Memory](#memory) for optional append-only log.
30
30
 
31
31
  **Barebones schema:**
@@ -107,7 +107,7 @@ Bugfind subagent completes (findings or clean):
107
107
  2. Applies TDD fixes (test first, then production).
108
108
  3. Commits, pushes one fix commit.
109
109
  4. Replies inline on each addressed finding via
110
- `reply_to_inline_comment.py`.
110
+ `add_reply_to_pull_request_comment(owner, repo, pullNumber, commentId, body)`.
111
111
  5. Writes `state.json` (per §Concurrency): `last_action: "fix_pushed"`,
112
112
  `current_head: <new SHA>`, `bugbot_clean_at: null`, `phase:
113
113
  "BUGBOT"`, `status: "awaiting_bugbot"`, `last_updated` ISO-8601 UTC.
@@ -116,7 +116,7 @@ Bugfind subagent completes (findings or clean):
116
116
  - **PRs with zero findings:** spawn one `general-purpose` subagent per PR via
117
117
  `Agent(subagent_type="general-purpose", run_in_background=true)`. Subagent:
118
118
  1. `bugbot_clean_at == current_head` (back-to-back clean): run
119
- `mark_pr_ready.py`, append convergence row to
119
+ `update_pull_request(pullNumber=PR_NUMBER, owner=OWNER, repo=REPO, draft=false)`, append convergence row to
120
120
  `<TMPDIR>/pr-converge-<session_id>/converged.log` per §Memory, then
121
121
  write `state.json` (per §Concurrency) with `status: "converged"`,
122
122
  `last_action: "converged"` (or `marked_ready`), `phase: "BUGBOT"`,
@@ -125,7 +125,7 @@ Bugfind subagent completes (findings or clean):
125
125
  duplicate work.
126
126
  2. Else: update `state.json` (per §Concurrency) with `last_action:
127
127
  "audit_clean"`, `status: "awaiting_bugbot"`, `phase: "BUGBOT"`, then
128
- trigger bugbot via `trigger_bugbot.py`.
128
+ trigger bugbot via `add_issue_comment(owner, repo, issueNumber, body="bugbot run")`.
129
129
  3. Goes idle.
130
130
 
131
131
  ### Fix result → general-purpose per PR
@@ -135,11 +135,11 @@ When bugfix (clean-coder) subagent completes after push:
135
135
  - Spawn one `general-purpose` subagent per PR via
136
136
  `Agent(subagent_type="general-purpose", run_in_background=true)`. Subagent:
137
137
  1. Reads `state.json` for its PR.
138
- 2. Triggers bugbot via `trigger_bugbot.py`.
139
- 3. Polls `fetch_bugbot_reviews.py` every 60s (up to 10 polls) until review
140
- anchored to `current_head` appears.
138
+ 2. Triggers bugbot via `add_issue_comment(owner, repo, issueNumber, body="bugbot run")`.
139
+ 3. Polls `pull_request_read(method="get_reviews")` every 60s (up to 10 polls) until review
140
+ anchored to `current_head` appears with `commit_id == current_head`.
141
141
  4. **Poll / classify loop** (repeat from 4a whenever 4c retries):
142
- - **4a.** Fetch inline comments via `fetch_bugbot_inline_comments.py`.
142
+ - **4a.** Fetch inline comments via `pull_request_read(method="get_review_comments")` filtered by review ID and `commit_id == current_head`.
143
143
  - **4b.** Classify — three outcomes (same as `SKILL.md` Step 2 BUGBOT):
144
144
  - **`clean`:** review body clean, zero unaddressed inline findings.
145
145
  - **`dirty`:** ≥1 unaddressed inline finding for `current_head`
@@ -186,7 +186,7 @@ When bugfix (clean-coder) subagent completes after push:
186
186
  Run directory `<TMPDIR>/pr-converge-<session_id>/` holds `state.json` and
187
187
  optional `converged.log`. Keep from first create until every PR under `prs`
188
188
  is `converged` or `blocked`, or **Stop conditions** ends loop. Safe to
189
- delete folder after — `mark_pr_ready.py` / `gh pr ready` on GitHub is
189
+ delete folder after — `update_pull_request(draft=false)` on GitHub is
190
190
  canonical record. Folder skill, not a plugin package; do **not** rely
191
191
  on `${CLAUDE_PLUGIN_DATA}`. OS/disk cleanup of `<TMPDIR>` (reboot, policy)
192
192
  can remove files mid-run — environmental risk.
@@ -196,7 +196,7 @@ can remove files mid-run — environmental risk.
196
196
  - **Path:** sibling of `state.json`.
197
197
  - **Format:** one tab-separated row per converged PR: ISO8601 UTC,
198
198
  owner/repo#number, bugbot SHA, bugteam SHA.
199
- - **Append site:** agent running `mark_pr_ready.py`. Append **before**
199
+ - **Append site:** agent running `update_pull_request(pullNumber=PR_NUMBER, owner=OWNER, repo=REPO, draft=false)`. Append **before**
200
200
  locked `state.json` publish so log row survives failed merge.
201
201
  - **Never read inside loop.** User / follow-up tooling only.
202
202
 
@@ -37,10 +37,12 @@ state line when **no** `state.json` (single-PR only). With `state.json`, do
37
37
  **not** increment here — orchestrator's per-tick bump is sole increment.
38
38
 
39
39
  ```bash
40
- python "${CLAUDE_SKILL_DIR}/scripts/view_pr_context.py"
40
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get") → `.head.sha`
41
41
  ```
42
42
 
43
- Capture `number`, `headRefOid` (= `current_head`), owner/repo, branch.
43
+ If owner/repo/number are not yet known, extract them from the PR URL.
44
+
45
+ Capture `number`, `head.sha` (= `current_head`), owner/repo, branch.
44
46
 
45
47
  ## Step 2: Branch on `phase`
46
48
 
@@ -48,15 +50,14 @@ Capture `number`, `headRefOid` (= `current_head`), owner/repo, branch.
48
50
 
49
51
  a. Fetch Cursor Bugbot reviews newest-first, walk back until first clean:
50
52
 
51
- ```bash
52
- python "${CLAUDE_SKILL_DIR}/scripts/fetch_bugbot_reviews.py" \
53
- --owner <OWNER> --repo <REPO> --number <NUMBER>
53
+ ```
54
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_reviews")
55
+ filter `.user.login` for cursor/bugbot, sort by `.submitted_at` descending
54
56
  ```
55
57
 
56
- Track dirty entries in a temp file; Fix protocol reads it back later
57
- this tick.
58
+ Track dirty entries (review body contains `BUGBOT_REVIEW` markers with finding content); Fix protocol reads them back later this tick.
58
59
 
59
- Iterate from index 0 (most recent) toward older:
60
+ Iterate from index 0 (most recent) toward older:
60
61
 
61
62
  - Dirty review → append JSON line with `{review_id, commit_id,
62
63
  submitted_at, body}`.
@@ -69,14 +70,12 @@ review for decisions below. When branch routes to **Fix protocol**, address
69
70
  **every** entry in `$dirty_reviews_path` — not just index 0.
70
71
 
71
72
  b. Fetch unaddressed inline comments from `cursor[bot]` for newest Bugbot
72
- review on `current_head`. Script uses same `--paginate --slurp` pattern,
73
- resolves review via reviews list, returns only inline rows whose
74
- `pull_request_review_id` matches that review (excludes stale threads from
75
- older reviews on same SHA).
73
+ review on `current_head`:
76
74
 
77
- ```bash
78
- python "${CLAUDE_SKILL_DIR}/scripts/fetch_bugbot_inline_comments.py" \
79
- --owner <OWNER> --repo <REPO> --number <NUMBER> --commit "$current_head"
75
+ ```
76
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_comments")
77
+ filter threads where `is_outdated == false` AND `is_resolved == false`
78
+ AND any comment has `.author` matching cursor/bugbot (case-insensitive substring)
80
79
  ```
81
80
 
82
81
  c. Decide (four branches; match first whose predicate holds):
@@ -93,9 +92,11 @@ c. Decide (four branches; match first whose predicate holds):
93
92
  `state.json`: clean-coder teammate pushes, replies inline, writes
94
93
  `state.json`, goes idle; Step 3 on new HEAD runs after via
95
94
  orchestrator-spawned follow-up agent (§Fix result → general-purpose).
96
- No `state.json` (single-PR): implement → push → inline replies
97
- → Step 3 in same tick per loaded pacing workflow. Schedule next
98
- wakeup, return.
95
+ No `state.json` (single-PR): spawn Agent (subagent_type: clean-coder) to implement → push → reply inline on each thread
96
+ via `add_reply_to_pull_request_comment` MCP → Step 3 in same tick (see
97
+ [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
98
+ full contract).
99
+ Schedule next wakeup, return.
99
100
  - **`commit_id == current_head` AND review body findings AND inline
100
101
  API zero matching for `current_head`:** Transient API lag. Increment
101
102
  `inline_lag_streak`. `>= 3` → hard blocker; report and terminate with
@@ -121,8 +122,7 @@ Skill({skill: "bugteam", args:
121
122
  b. **Re-resolve current HEAD** — bugteam may have pushed commits during
122
123
  its run. `current_head` from Step 1 is potentially stale:
123
124
  ```bash
124
- new_head=$(python "${CLAUDE_SKILL_DIR}/scripts/resolve_pr_head.py" \
125
- --owner <OWNER> --repo <REPO> --number <NUMBER>)
125
+ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get") → `.head.sha`
126
126
  ```
127
127
  If `new_head != current_head`, set `current_head = new_head` AND
128
128
  `bugbot_clean_at = null`. New commits invalidate bugbot's prior clean.
@@ -142,26 +142,14 @@ never falsely terminates:
142
142
  **omit loop pacing** per **Convergence** of active pacing workflow.
143
143
  - **Convergence BUT `bugbot_clean_at != current_head` (no push):**
144
144
  `phase = BUGBOT`, schedule next wakeup, return.
145
- - **Findings without committed fixes:** apply **[fix-protocol.md](fix-protocol.md)**; Step 3
146
- on new HEAD runs after fix handoff per `multi-pr-orchestration.md` or in-tick for
147
- single-PR. `phase = BUGBOT`, schedule next wakeup, return.
145
+ - **Findings without committed fixes:** spawn Agent (subagent_type: clean-coder) to implement fixes and push, then reply inline via `add_reply_to_pull_request_comment` MCP, following [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow).
146
+ `phase = BUGBOT`, schedule next wakeup, return.
148
147
 
149
148
  ## Step 3: Re-trigger bugbot
150
149
 
151
- Prefer portable script (temp body file, `gh pr comment --body-file`):
150
+ Use the `add_issue_comment` MCP tool:
152
151
 
153
- ```bash
154
- python "${CLAUDE_SKILL_DIR}/scripts/trigger_bugbot.py" \
155
- --owner <OWNER> --repo <REPO> --number <NUMBER>
156
- ```
157
-
158
- **Bundled PowerShell alternative** (same gh-body-file contract):
159
-
160
- ```bash
161
- POST_BUGBOT_RUN="$HOME/.claude/skills/pr-converge/scripts/post-bugbot-run.ps1"
162
- pwsh -NoProfile -ExecutionPolicy Bypass -File "$POST_BUGBOT_RUN" \
163
- "https://github.com/<OWNER>/<REPO>/pull/<NUMBER>"
164
- ```
152
+ add_issue_comment(owner="OWNER", repo="REPO", issueNumber=NUMBER, body="bugbot run")
165
153
 
166
154
  `bugbot run` is empirically the only re-trigger Cursor Bugbot recognizes;
167
155
  alternative phrasings (`re-review`, `bugbot please`, etc.) silently no-op.
@@ -1,9 +1,9 @@
1
1
  # Stop conditions
2
2
 
3
3
  - **Convergence** (back-to-back clean ∧ no outstanding Copilot findings
4
- on `current_head` ∧ `mergeStateStatus == "CLEAN"` with `mergeable ==
5
- "MERGEABLE"` ∧ post-convergence Copilot request returned `clean` at
6
- `current_head`): prefer `mark_pr_ready.py`; else `gh pr ready`. With
4
+ on `current_head` ∧ `mergeable_state == "clean"` with `mergeable ==
5
+ true` ∧ post-convergence Copilot request returned `clean` at
6
+ `current_head`): use `update_pull_request(pullNumber=NUMBER, owner=OWNER, repo=REPO, draft=false)`. With
7
7
  `state.json`, append convergence row to
8
8
  `<TMPDIR>/pr-converge-<session_id>/converged.log` per `multi-pr-orchestration.md` §Memory; else
9
9
  skip. Report [convergence-gates.md](convergence-gates.md) (d) summary, then **omit loop pacing**
@@ -16,11 +16,11 @@
16
16
  `current_head` after three consecutive wakeups. Report specific
17
17
  blocker and diagnosis, **omit loop pacing** per
18
18
  `../workflows/schedule-wakeup-loop.md`.
19
- - **Hard blocker (`mergeStateStatus` non-CLEAN non-DIRTY):**
20
- `mergeStateStatus` is `BLOCKED`, `UNKNOWN`, or `BEHIND` (required
19
+ - **Hard blocker (`mergeable_state` non-clean non-dirty):**
20
+ `mergeable_state` is `"blocked"`, `"unknown"`, or `"behind"` (required
21
21
  checks pending, branch behind base without textual conflicts, or
22
22
  GitHub indeterminate). Investigate before retrying; `rebase` skill
23
- handles `DIRTY` (textual conflicts) only. Report specific
24
- `mergeStateStatus`, **omit loop pacing**.
23
+ handles `"dirty"` (textual conflicts) only. Report specific
24
+ `mergeable_state`, **omit loop pacing**.
25
25
  - **User stops loop:** "stop the converge loop" → **omit loop pacing**
26
26
  per `../workflows/schedule-wakeup-loop.md`.