claude-dev-env 1.82.0 → 1.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +16 -13
- package/_shared/pr-loop/audit-contract.md +24 -12
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -0
- package/_shared/pr-loop/scripts/README.md +1 -0
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +16 -5
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviewer_availability_constants.py +12 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +0 -2
- package/_shared/pr-loop/scripts/reviewer_availability.py +182 -0
- package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +9 -33
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +2 -0
- package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
- package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
- package/_shared/pr-loop/scripts/tests/test_reviewer_availability.py +159 -0
- package/_shared/pr-loop/scripts/tests/test_reviewer_availability_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +14 -4
- package/agents/clean-coder.md +3 -0
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
- package/bin/install.mjs +16 -8
- package/bin/install.test.mjs +17 -6
- package/commands/CLAUDE.md +0 -1
- package/docs/CODE_RULES.md +1 -1
- package/hooks/blocking/CLAUDE.md +2 -4
- package/hooks/blocking/code_rules_constants_config.py +164 -1
- package/hooks/blocking/code_rules_docstrings.py +428 -15
- package/hooks/blocking/code_rules_enforcer.py +33 -0
- package/hooks/blocking/code_rules_imports_logging.py +867 -1
- package/hooks/blocking/code_rules_magic_values.py +5 -0
- package/hooks/blocking/code_rules_naming_collection.py +152 -6
- package/hooks/blocking/code_rules_shared.py +34 -0
- package/hooks/blocking/code_rules_string_magic.py +68 -0
- package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
- package/hooks/blocking/pre_tool_use_dispatcher.py +3 -3
- package/hooks/blocking/reviewer_spawn_gate.py +182 -0
- package/hooks/blocking/stale_comment_reference_blocker.py +267 -0
- package/hooks/blocking/state_description_blocker.py +96 -5
- package/hooks/blocking/test_code_rules_config_duplicate_path_anchor.py +132 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +2 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_delegation_summary.py +385 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +67 -0
- package/hooks/blocking/test_code_rules_enforcer_module_docstring_roster.py +40 -0
- package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +213 -0
- package/hooks/blocking/test_code_rules_enforcer_referenced_underscore_loop.py +169 -0
- package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
- package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
- package/hooks/blocking/test_code_rules_js_bare_flag_return_directive.py +266 -0
- package/hooks/blocking/test_code_rules_js_sibling_return_object_key_drift.py +490 -0
- package/hooks/blocking/test_code_rules_logging_adjacent_literals.py +171 -0
- package/hooks/blocking/test_code_rules_magic_values.py +54 -0
- package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
- package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +9 -3
- package/hooks/blocking/test_reviewer_spawn_gate.py +230 -0
- package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
- package/hooks/blocking/test_stale_comment_reference_blocker.py +236 -0
- package/hooks/blocking/test_state_description_blocker.py +135 -0
- package/hooks/hooks.json +5 -0
- package/hooks/hooks_constants/CLAUDE.md +3 -4
- package/hooks/hooks_constants/blocking_check_limits.py +46 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +41 -0
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
- package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
- package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
- package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +41 -0
- package/hooks/hooks_constants/stale_comment_reference_blocker_constants.py +76 -0
- package/hooks/hooks_constants/state_description_blocker_constants.py +8 -0
- package/hooks/validation/post_tool_use_dispatcher.py +1 -1
- package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
- package/hooks/workflow/CLAUDE.md +2 -8
- package/package.json +1 -1
- package/rules/CLAUDE.md +5 -2
- package/rules/claude-md-orphan-file.md +5 -0
- package/rules/docstring-prose-matches-implementation.md +10 -1
- package/rules/env-var-table-code-drift.md +5 -0
- package/rules/es-exe-file-search.md +17 -0
- package/rules/no-historical-clutter.md +12 -1
- package/rules/orphan-css-class.md +5 -0
- package/rules/package-inventory-stale-entry.md +10 -0
- package/rules/paired-test-coverage.md +5 -0
- package/rules/plain-illustrative-docstrings.md +40 -1
- package/rules/verify-before-asking.md +7 -0
- package/rules/verify-runtime-state.md +40 -0
- package/rules/windows-filesystem-safe.md +8 -0
- package/rules/workers-done-before-complete.md +33 -0
- package/rules/workflow-substitution-slots.md +5 -0
- package/skills/CLAUDE.md +7 -2
- package/skills/autoconverge/SKILL.md +48 -61
- package/skills/autoconverge/reference/closing-report.md +6 -6
- package/skills/autoconverge/reference/convergence.md +17 -15
- package/skills/autoconverge/reference/gotchas.md +6 -3
- package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
- package/skills/autoconverge/workflow/converge.contract.test.mjs +153 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +55 -19
- package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
- package/skills/autoconverge/workflow/converge.mjs +167 -106
- package/skills/autoconverge/workflow/render_report.py +7 -11
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/PROMPTS.md +7 -6
- package/skills/bugteam/SKILL.md +25 -72
- package/skills/bugteam/reference/CLAUDE.md +1 -3
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +1 -1
- package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
- package/skills/bugteam/reference/team-setup.md +8 -7
- package/skills/bugteam/scripts/CLAUDE.md +0 -6
- package/skills/bugteam/scripts/README.md +0 -4
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
- package/skills/code/SKILL.md +2 -0
- package/skills/copilot-review/CLAUDE.md +1 -1
- package/skills/copilot-review/SKILL.md +25 -23
- package/skills/everything-search/SKILL.md +5 -0
- package/skills/findbugs/CLAUDE.md +2 -2
- package/skills/findbugs/SKILL.md +22 -83
- package/skills/fixbugs/SKILL.md +2 -4
- package/skills/log-audit/CLAUDE.md +20 -0
- package/skills/log-audit/SKILL.md +68 -0
- package/skills/log-audit/reference/CLAUDE.md +9 -0
- package/skills/log-audit/reference/charter.md +52 -0
- package/skills/log-audit/scripts/CLAUDE.md +27 -0
- package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
- package/skills/log-audit/scripts/collect_log_window.py +199 -0
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
- package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
- package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
- package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
- package/skills/monitor-open-prs/SKILL.md +2 -2
- package/skills/post-audit-findings/SKILL.md +84 -0
- package/skills/pr-converge/CLAUDE.md +2 -0
- package/skills/pr-converge/SKILL.md +72 -59
- package/skills/pr-converge/reference/CLAUDE.md +1 -1
- package/skills/pr-converge/reference/convergence-gates.md +16 -19
- package/skills/pr-converge/reference/examples.md +5 -5
- package/skills/pr-converge/reference/fix-protocol.md +16 -43
- package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
- package/skills/pr-converge/reference/per-tick.md +24 -45
- package/skills/pr-converge/reference/state-schema.md +15 -0
- package/skills/pr-converge/scripts/README.md +3 -5
- package/skills/pr-fix-protocol/SKILL.md +70 -0
- package/skills/pr-loop-lifecycle/SKILL.md +73 -0
- package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
- package/skills/pr-scope-resolve/SKILL.md +48 -0
- package/skills/qbug/CLAUDE.md +4 -4
- package/skills/qbug/SKILL.md +46 -144
- package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
- package/skills/reviewer-gates/SKILL.md +96 -0
- package/skills/session-log/CLAUDE.md +7 -7
- package/skills/session-log/SKILL.md +27 -44
- package/skills/test_markdown_link_integrity.py +103 -0
- package/commands/doc-gist.md +0 -16
- package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
- package/hooks/blocking/conftest.py +0 -30
- package/hooks/blocking/md_path_exemptions.py +0 -224
- package/hooks/blocking/md_to_html_blocker.py +0 -155
- package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
- package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
- package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
- package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
- package/hooks/hooks_constants/html_companion_constants.py +0 -20
- package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
- package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
- package/hooks/workflow/doc_gist_auto_publish.py +0 -144
- package/hooks/workflow/md_to_html_companion.py +0 -358
- package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
- package/hooks/workflow/test_md_to_html_companion.py +0 -613
- package/skills/bugteam/reference/audit-contract.md +0 -163
- package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
- package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
- package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
- package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
- package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
- package/skills/doc-gist/CLAUDE.md +0 -25
- package/skills/doc-gist/SKILL.md +0 -97
- package/skills/doc-gist/references/CLAUDE.md +0 -9
- package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
- package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
- package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
- package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
- package/skills/doc-gist/references/examples/05-design-system.html +0 -629
- package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
- package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
- package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
- package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
- package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
- package/skills/doc-gist/references/examples/11-status-report.html +0 -528
- package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
- package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
- package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
- package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
- package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
- package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
- package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
- package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
- package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
- package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
- package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
- package/skills/doc-gist/references/examples/README.md +0 -5
- package/skills/doc-gist/scripts/CLAUDE.md +0 -27
- package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
- package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
- package/skills/doc-gist/scripts/gist_upload.py +0 -177
- package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
- /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Fix protocol
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The full fix protocol — executor choice, the shared 13-step sequence,
|
|
4
|
+
reply transport, thread resolution, the unresolved-thread sweep, and
|
|
5
|
+
post-push resets — lives in the `pr-fix-protocol` skill
|
|
6
|
+
(`../../pr-fix-protocol/SKILL.md`), which follows the shared step
|
|
7
|
+
sequence in `../../../_shared/pr-loop/fix-protocol.md`. Hook handling
|
|
6
8
|
per [ground-rules.md](ground-rules.md).
|
|
7
9
|
|
|
10
|
+
This file holds only the pr-converge deltas: the multi-PR teammate
|
|
11
|
+
obligations and the same-tick re-trigger rule.
|
|
12
|
+
|
|
8
13
|
**Multi-PR (`state.json`) teammate obligations** (plus TDD, commit, push):
|
|
9
14
|
|
|
10
15
|
- Replies inline on each addressed finding via
|
|
@@ -21,44 +26,12 @@ per [ground-rules.md](ground-rules.md).
|
|
|
21
26
|
Orchestrator does not reply inline, trigger bugbot, or read repo source
|
|
22
27
|
files during fix phase in multi-PR mode.
|
|
23
28
|
|
|
24
|
-
###
|
|
25
|
-
|
|
26
|
-
**Single-PR (no `state.json`) — same gates, main session executor:**
|
|
27
|
-
|
|
28
|
-
Run every command below in the PR worktree (the working directory routed in
|
|
29
|
-
[per-tick.md § Step 1.5](per-tick.md)). The `git add`, `git commit`, and
|
|
30
|
-
`git push` act on the repo of the current working directory, so a cross-repo
|
|
31
|
-
PR's fix lands in the PR's repo only when the cwd is its worktree. A spawned
|
|
32
|
-
`clean-coder` does not inherit the lead's working directory — name the PR
|
|
33
|
-
worktree path in its prompt and direct it to edit, stage, and commit there,
|
|
34
|
-
matching the worktree-path handoff bugteam embeds in its fix worker's spawn
|
|
35
|
-
prompt.
|
|
36
|
-
|
|
37
|
-
- Read each referenced file:line.
|
|
38
|
-
- Write failing test first when finding has behavior to test. Pure doc /
|
|
39
|
-
comment / naming nits with no behavior → straight to fix.
|
|
40
|
-
- **Implement** via `Agent` (`subagent_type: "clean-coder"`).
|
|
41
|
-
Full-stop if `Agent` is unavailable.
|
|
42
|
-
- Stage affected files and create one new commit on existing branch:
|
|
43
|
-
```bash
|
|
44
|
-
git add <files> && git commit -m "fix(review): <brief summary>"
|
|
45
|
-
```
|
|
46
|
-
**Pre-commit gate:** honor hooks; full-stop on bypass.
|
|
47
|
-
- Push the new commit:
|
|
48
|
-
```bash
|
|
49
|
-
git push origin <BRANCH>
|
|
50
|
-
```
|
|
51
|
-
**Pre-push gate:** honor hooks; full-stop on bypass. Capture new HEAD
|
|
52
|
-
only after both gates pass; set `current_head`, `bugbot_clean_at = null`.
|
|
53
|
-
- Reply inline on each addressed comment thread using `python scripts/post_fix_reply.py`:
|
|
29
|
+
### Same-tick re-trigger rule
|
|
54
30
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`current_head`, then bugteam CLEAN on same `HEAD` with no
|
|
63
|
-
intervening push. Re-triggering in same tick saves a wakeup cycle vs
|
|
64
|
-
deferring Step 3.
|
|
31
|
+
**After pushing a fix, always run Step 3 (`bugbot run`) in the same
|
|
32
|
+
tick** regardless of phase. A new commit **resets the full convergence
|
|
33
|
+
cycle**: a bugbot clean and a bugteam clean on an older SHA do **not**
|
|
34
|
+
count toward convergence on the new `HEAD`. Re-obtain bugbot CLEAN on
|
|
35
|
+
`current_head`, then bugteam CLEAN on the same `HEAD` with no
|
|
36
|
+
intervening push. Re-triggering in the same tick saves a wakeup cycle
|
|
37
|
+
vs deferring Step 3.
|
|
@@ -190,11 +190,8 @@ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_
|
|
|
190
190
|
→ filter threads where `is_resolved == false`
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
— but the gate itself doesn't filter on those fields. Verify each
|
|
196
|
-
thread's concern against current HEAD; either fix-and-resolve or
|
|
197
|
-
reply-with-note-and-resolve.
|
|
193
|
+
Per-thread handling lives in the `pr-fix-protocol` skill's
|
|
194
|
+
unresolved-thread sweep (`../../pr-fix-protocol/SKILL.md`).
|
|
198
195
|
|
|
199
196
|
c. Decide (four branches; match first whose predicate holds):
|
|
200
197
|
- **No bugbot review yet, OR latest review's `commit_id` ≠
|
|
@@ -206,15 +203,12 @@ c. Decide (four branches; match first whose predicate holds):
|
|
|
206
203
|
in same tick — back-to-back convergence requires code-review then
|
|
207
204
|
bugteam on same HEAD before next wakeup.
|
|
208
205
|
- **`commit_id == current_head` with unaddressed inline findings:**
|
|
209
|
-
Apply
|
|
210
|
-
`state.json`: clean-coder
|
|
211
|
-
`state.json`, goes idle; Step 3 on new
|
|
212
|
-
orchestrator-spawned follow-up agent (§Fix result
|
|
213
|
-
No `state.json` (single-PR):
|
|
214
|
-
|
|
215
|
-
[Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
|
|
216
|
-
full contract).
|
|
217
|
-
Schedule next wakeup, return.
|
|
206
|
+
Apply the `pr-fix-protocol` skill (`../../pr-fix-protocol/SKILL.md`).
|
|
207
|
+
Reset `inline_lag_streak = 0`. With `state.json`: the clean-coder
|
|
208
|
+
teammate executes it, writes `state.json`, goes idle; Step 3 on new
|
|
209
|
+
HEAD runs after via orchestrator-spawned follow-up agent (§Fix result
|
|
210
|
+
→ general-purpose). No `state.json` (single-PR): the lead executes it
|
|
211
|
+
→ Step 3 in same tick. Schedule next wakeup, return.
|
|
218
212
|
|
|
219
213
|
### `phase == CODE_REVIEW`
|
|
220
214
|
|
|
@@ -245,8 +239,8 @@ a. Run Claude Code's built-in `/code-review --fix` on the FULL
|
|
|
245
239
|
b. Decide (two branches; match first whose predicate holds):
|
|
246
240
|
|
|
247
241
|
- **`/code-review` applied fixes (working tree changed):** Commit the
|
|
248
|
-
applied fixes in one commit → push, following
|
|
249
|
-
|
|
242
|
+
applied fixes in one commit → push, following the `pr-fix-protocol`
|
|
243
|
+
skill's commit and push steps (`../../pr-fix-protocol/SKILL.md`). Reset
|
|
250
244
|
`bugbot_clean_at = null` AND `code_review_clean_at = null`. Re-trigger
|
|
251
245
|
bugbot (Step 3) so the new HEAD enters the queue. Set `phase = BUGBOT`,
|
|
252
246
|
schedule next wakeup, return. A code-review fix push requires a full
|
|
@@ -318,7 +312,8 @@ never falsely terminates:
|
|
|
318
312
|
**omit loop pacing** per **Convergence** of active pacing workflow.
|
|
319
313
|
- **Convergence BUT `bugbot_clean_at != current_head` (no push):**
|
|
320
314
|
`phase = BUGBOT`, schedule next wakeup, return.
|
|
321
|
-
- **Findings without committed fixes:**
|
|
315
|
+
- **Findings without committed fixes:** apply the `pr-fix-protocol`
|
|
316
|
+
skill (`../../pr-fix-protocol/SKILL.md`).
|
|
322
317
|
`phase = BUGBOT`, schedule next wakeup, return.
|
|
323
318
|
|
|
324
319
|
### `phase == COPILOT_WAIT`
|
|
@@ -345,11 +340,9 @@ b. Decide (three branches; match first whose predicate holds):
|
|
|
345
340
|
`phase = BUGTEAM`. Continue to convergence-gates.md gate (b) in same
|
|
346
341
|
tick — back-to-back convergence requires all gates on same HEAD.
|
|
347
342
|
- **Copilot review dirty (CHANGES_REQUESTED or COMMENTED with findings)
|
|
348
|
-
at `current_head`:** Apply
|
|
349
|
-
(
|
|
350
|
-
|
|
351
|
-
findings (no inline threads), post top-level review reply citing new
|
|
352
|
-
HEAD SHA. Reset
|
|
343
|
+
at `current_head`:** Apply the `pr-fix-protocol` skill
|
|
344
|
+
(`../../pr-fix-protocol/SKILL.md`) — it covers body-only findings with
|
|
345
|
+
no inline threads. Reset
|
|
353
346
|
`bugbot_clean_at = null` AND `copilot_clean_at = null`. **Set
|
|
354
347
|
`phase = BUGBOT`** (NOT COPILOT_WAIT) — every fix push requires a full
|
|
355
348
|
back-to-back-clean cycle on the new HEAD. Schedule next wakeup, return.
|
|
@@ -370,29 +363,15 @@ BUGBOT.
|
|
|
370
363
|
- [ ] **Opt-out gate.** Enforced at BUGBOT entry (see `### phase == BUGBOT`).
|
|
371
364
|
When `CLAUDE_REVIEWS_DISABLED` lists `bugbot`, the entry gate sets
|
|
372
365
|
`bugbot_down = true` and routes to BUGTEAM before any trigger flow runs,
|
|
373
|
-
so the
|
|
374
|
-
- [ ]
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
|
|
378
|
-
- [ ]
|
|
379
|
-
- [ ]
|
|
380
|
-
- [ ]
|
|
381
|
-
- [ ]
|
|
382
|
-
- [ ] Exit non-zero → bugbot is down; set `bugbot_down = true`, `phase = CODE_REVIEW`, continue CODE_REVIEW same tick
|
|
383
|
-
- [ ] Exit 0 (check run present) → record `bugbot_acknowledged_at = <now ISO 8601>`, proceed to Step 4
|
|
384
|
-
|
|
385
|
-
The silent-pass pre-check fires FIRST so we never re-trigger a bot that
|
|
386
|
-
already finished cleanly. Cursor Bugbot communicates "no findings" by
|
|
387
|
-
completing the CI check with `conclusion: success` (or `neutral`) and
|
|
388
|
-
posting no review. The pre-check treats that outcome as
|
|
389
|
-
`bugbot_clean_at = current_head`, equivalent to an explicit clean
|
|
390
|
-
review. Without it, the trigger flow would re-prompt a bot that has
|
|
391
|
-
already evaluated this commit and refuses to re-run, and the bypass
|
|
392
|
-
branch would falsely mark `bugbot_down = true`.
|
|
393
|
-
|
|
394
|
-
`bugbot run` is empirically the only re-trigger Cursor Bugbot recognizes;
|
|
395
|
-
alternative phrasings silently no-op.
|
|
366
|
+
so the flow below is skipped.
|
|
367
|
+
- [ ] Apply the `reviewer-gates` skill's Bugbot flow
|
|
368
|
+
(`../../reviewer-gates/SKILL.md` § Gate 3) against `current_head` — the
|
|
369
|
+
silent-pass pre-check, the already-queued check, the trigger comment, and
|
|
370
|
+
the acknowledge check, with their rationale. Map its outcomes:
|
|
371
|
+
- [ ] Silent pass → set `bugbot_clean_at = current_head`, `phase = CODE_REVIEW`, continue CODE_REVIEW same tick
|
|
372
|
+
- [ ] Already queued → skip posting, wait for completion, advance to Step 4
|
|
373
|
+
- [ ] Trigger acknowledged (`bugbot_acknowledged_at` recorded) → advance to Step 4
|
|
374
|
+
- [ ] Bugbot down → set `bugbot_down = true`, `phase = CODE_REVIEW`, continue CODE_REVIEW same tick
|
|
396
375
|
|
|
397
376
|
## Step 4: Loop pacing
|
|
398
377
|
|
|
@@ -79,6 +79,21 @@ live ONLY in the single-PR `$CLAUDE_JOB_DIR/pr-converge-state.json` file
|
|
|
79
79
|
The enforcer requires this value to equal the current `tick_count` so a
|
|
80
80
|
Skill invocation from a prior tick cannot wave through clean-coder
|
|
81
81
|
audit-shaped Agent spawns on a later tick at the same HEAD.
|
|
82
|
+
- `agents_session_id`: string or `null`, init `null`. The session id that
|
|
83
|
+
spawned the persistent per-step agents recorded in `persistent_agents`.
|
|
84
|
+
On tick entry, compare it to the current session id: when they differ,
|
|
85
|
+
clear `persistent_agents` to `{}` and stamp this field with the current
|
|
86
|
+
session id. `ScheduleWakeup` re-enters the same session, so a mismatch
|
|
87
|
+
means a fresh-session manual resume — the stored agent ids point at dead
|
|
88
|
+
agents and must not be reused.
|
|
89
|
+
- `persistent_agents`: object, init `{}`. Map of step-key →
|
|
90
|
+
`{agent_id, created_tick, last_used_tick}` for the persistent per-step
|
|
91
|
+
agents the loop resumes across ticks. Exactly three step keys:
|
|
92
|
+
`fix_executor` (the clean-coder that applies findings in Step 4 dirty,
|
|
93
|
+
Step 6 findings, gates (a)/(d), and Step 7a), `thread_sweep`, and
|
|
94
|
+
`copilot_watch`. `agent_id` is the id the `Agent` tool returned at spawn;
|
|
95
|
+
`created_tick` is the `tick_count` at spawn; `last_used_tick` is bumped
|
|
96
|
+
on every `SendMessage` resume.
|
|
82
97
|
|
|
83
98
|
Single-PR tick begins by reading `$CLAUDE_JOB_DIR/pr-converge-state.json`
|
|
84
99
|
if it exists and ends by writing the updated state back to that same file
|
|
@@ -79,15 +79,13 @@ non-empty body → dirty.
|
|
|
79
79
|
|
|
80
80
|
### Inline comment threads: `pull_request_read(method="get_review_comments")`
|
|
81
81
|
|
|
82
|
-
Fetch via MCP
|
|
82
|
+
Fetch via MCP:
|
|
83
83
|
|
|
84
84
|
pull_request_read(method="get_review_comments", pullNumber=NUMBER, owner=OWNER, repo=REPO)
|
|
85
85
|
→ filter threads where `is_resolved == false`
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
(re-fix? reply-with-note?), but they do not exclude a thread from the
|
|
90
|
-
count.
|
|
87
|
+
Sweep semantics and per-thread handling live in the `pr-fix-protocol`
|
|
88
|
+
skill's unresolved-thread sweep (`../../pr-fix-protocol/SKILL.md`).
|
|
91
89
|
|
|
92
90
|
### Request Copilot review: `gh api` REST endpoint
|
|
93
91
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-fix-protocol
|
|
3
|
+
description: >-
|
|
4
|
+
Applies reviewer findings to a PR as verified fixes and drives unresolved
|
|
5
|
+
review threads to zero: executor choice (clean-coder spawn or multi-PR
|
|
6
|
+
teammate with a worktree-path handoff), the shared 13-step fix sequence
|
|
7
|
+
(TDD, one commit, fast-forward push), an atomic reply-and-resolve per
|
|
8
|
+
thread, the unresolved-thread sweep hard gate (is_resolved == false is the
|
|
9
|
+
only filter), and post-push state resets. Invoked by PR-loop orchestrators
|
|
10
|
+
(pr-converge, autoconverge, bugteam, qbug, copilot-review) whenever a
|
|
11
|
+
reviewer reports findings or unresolved threads exist; not for ad-hoc "fix
|
|
12
|
+
this bug" requests outside a PR review loop.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# PR Fix Protocol
|
|
16
|
+
|
|
17
|
+
**Core principle:** a finding is addressed only when the fix is pushed, the thread carries a reply, and the thread is resolved — as one unit of work. Anything less leaves a convergence gate stalled.
|
|
18
|
+
|
|
19
|
+
## How callers invoke this
|
|
20
|
+
|
|
21
|
+
- **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "pr-fix-protocol", args: "--skill <caller> --pr <URL> --worktree <path> [findings payload or 'sweep']"})`.
|
|
22
|
+
- **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/pr-fix-protocol/SKILL.md` and apply it with the parameters below."
|
|
23
|
+
|
|
24
|
+
The caller passes: its identity, the PR scope, the PR worktree path, this round's findings (or `sweep` for a thread sweep with no fresh findings), and its post-push obligations (which clean-SHA state fields to reset, which reviewers to re-trigger).
|
|
25
|
+
|
|
26
|
+
## Executor choice
|
|
27
|
+
|
|
28
|
+
- **Single-PR loops** (no shared `state.json`): the lead spawns `Agent(subagent_type: "clean-coder")` to write the fix. Full-stop if `Agent` is unavailable. A spawned clean-coder does not inherit the lead's working directory — name the PR worktree path in its prompt and direct it to edit, stage, and commit there.
|
|
29
|
+
- **Multi-PR orchestration** (shared `state.json`): a per-PR clean-coder teammate owns edits, replies, and state writes; the orchestrator never edits inline. The teammate obligations (reply before writing state, state fields, idle handoff) live in the calling skill's multi-PR reference.
|
|
30
|
+
|
|
31
|
+
Run every git command in the PR worktree — `git add`, `git commit`, and `git push` act on the repo of the current working directory, so a cross-repo PR's fix lands in the PR's repo only when the cwd is its worktree.
|
|
32
|
+
|
|
33
|
+
## The fix sequence
|
|
34
|
+
|
|
35
|
+
Follow the shared 13-step sequence in [`_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md) exactly: read each file:line, capture the pre-fix SHA and contents, TDD where the finding has behavior, apply narrowly, `py_compile`, post-fix self-audit, stage by explicit path, one commit, fast-forward push, then reply + resolve atomically per thread. Its Constraints section (narrow scope, no `--no-verify`, preserve helpers) binds every executor.
|
|
36
|
+
|
|
37
|
+
**Reply transport:** the GitHub MCP `add_reply_to_pull_request_comment` is primary. `python "$HOME/.claude/skills/pr-converge/scripts/post_fix_reply.py" --owner <O> --repo <R> --pr-number <N> --in-reply-to <COMMENT_ID> --body "Fixed in <SHA> — <what changed>"` is the fallback for script-only contexts and multi-PR teammates. Both carry the body shape from [`_shared/pr-loop/audit-reply-template.md`](../../_shared/pr-loop/audit-reply-template.md). For body-only findings with no inline thread, post a top-level review reply citing the new HEAD SHA.
|
|
38
|
+
|
|
39
|
+
**Thread resolution:** `pull_request_review_write(method="resolve_thread", threadId=<PRRT node id>)` right after each reply. Harvest thread node ids (`PRRT_…`) from `get_review_comments` at fetch time.
|
|
40
|
+
|
|
41
|
+
## The unresolved-thread sweep (hard gate)
|
|
42
|
+
|
|
43
|
+
No caller advances a phase, records a clean SHA, or marks a PR ready while ANY unresolved review thread exists on the PR.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
pull_request_read(method="get_review_comments") → filter threads where is_resolved == false
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- The filter is purely `is_resolved == false`. Author, anchor commit, and `is_outdated` are all irrelevant to the count.
|
|
50
|
+
- `is_outdated` is informational, not a skip flag: GitHub marks a thread outdated when its anchor line changed, but the concern can still apply to current HEAD (the fix may have moved, not landed). Verify each outdated thread against current HEAD like any other.
|
|
51
|
+
- Per unresolved thread: verify the concern against current HEAD. The concern holds → fix (this protocol) → reply → resolve. The concern does not hold on current HEAD → reply-with-note explaining why → resolve.
|
|
52
|
+
- Code changed during the sweep → push and hand control back to the caller's re-entry phase. Only resolutions, no code → re-run the sweep without resetting caller state.
|
|
53
|
+
|
|
54
|
+
## Post-push obligations
|
|
55
|
+
|
|
56
|
+
Every push through this protocol:
|
|
57
|
+
|
|
58
|
+
1. Re-resolve `current_head` (`git rev-parse HEAD` locally; the PR `get` call for API-visible state).
|
|
59
|
+
2. Reset the caller-named clean-SHA fields to null (`bugbot_clean_at`, `code_review_clean_at`, `copilot_clean_at` — whichever the caller tracks). A new HEAD invalidates every prior clean.
|
|
60
|
+
3. Re-trigger reviewers per the caller's parameter (for Cursor Bugbot, the `reviewer-gates` Bugbot flow; for Copilot, the caller's request step). Audit-family callers (`bugteam`, `qbug`) skip re-triggering — their next loop iteration is the reviewer.
|
|
61
|
+
|
|
62
|
+
## Gotchas
|
|
63
|
+
|
|
64
|
+
- **Reply-then-resolve, atomic per thread.** Batching all replies before any resolves, or yielding to the orchestrator between the two, leaves threads half-addressed when a run dies mid-loop.
|
|
65
|
+
- **An unchanged HEAD after step 11 means no commit landed** — exit `stuck — could not address findings` rather than reporting the findings as fixed.
|
|
66
|
+
- **A resolved thread with no reply reads as dismissed.** Reviewers (and the humans reading the PR) need the one-paragraph explanation the template carries.
|
|
67
|
+
|
|
68
|
+
## Folder map
|
|
69
|
+
|
|
70
|
+
- `SKILL.md` — this file. The step sequence, reply template, and payload shapes live in `_shared/pr-loop/` (`fix-protocol.md`, `audit-reply-template.md`, `gh-payloads.md`); the reply fallback script lives in `pr-converge/scripts/`.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-loop-lifecycle
|
|
3
|
+
description: >-
|
|
4
|
+
Opens and closes a PR-loop run: the .claude/** permission grant (with the
|
|
5
|
+
auto-mode AskUserQuestion escalation when the classifier blocks it),
|
|
6
|
+
worktree preflight and cwd routing, then the ordered close — conditional
|
|
7
|
+
TeamDelete for team callers, worktree teardown, working-tree clean, PR
|
|
8
|
+
description rewrite via pr-description-writer, the always-run permission
|
|
9
|
+
revoke, and the caller-parameterized final report. Invoked by PR-loop
|
|
10
|
+
orchestrators (bugteam, pr-converge, autoconverge, qbug) at run start and
|
|
11
|
+
run end, including error exits; not for general git cleanup or permission
|
|
12
|
+
management outside a PR loop.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# PR Loop Lifecycle
|
|
16
|
+
|
|
17
|
+
**Core principle:** a PR-loop run opens with an explicit, revocable permission grant and closes the same way every time — teardown, description rewrite, revoke, report — no matter how the run ended.
|
|
18
|
+
|
|
19
|
+
## How callers invoke this
|
|
20
|
+
|
|
21
|
+
- **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "pr-loop-lifecycle", args: "--skill <caller> <open|close> [parameters]"})`.
|
|
22
|
+
- **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/pr-loop-lifecycle/SKILL.md` and apply the `<open|close>` section with the parameters below."
|
|
23
|
+
|
|
24
|
+
The caller passes its identity (fills the final-report header and scratch-file prefix), whether it runs an agent team (gates the TeamDelete step), and at close time the run's exit reason, loop count, and SHAs.
|
|
25
|
+
|
|
26
|
+
## Open
|
|
27
|
+
|
|
28
|
+
1. **Grant project permissions:**
|
|
29
|
+
`python "$HOME/.claude/_shared/pr-loop/scripts/grant_project_claude_permissions.py"`
|
|
30
|
+
The script writes idempotent allow-rules and `additionalDirectories` entries into `~/.claude/settings.json` so subagents can edit the project's `.claude/` tree without prompting.
|
|
31
|
+
|
|
32
|
+
**Auto-mode escalation:** in an unattended run the permission classifier can block this grant as an unrequested allowlist change. Keep the run alive — surface the exact command to the user through `AskUserQuestion` and ask them to approve it or run it themselves with the `!` prefix. Continue once the grant lands. A user who wants future runs to skip the prompt can add a standing Bash allow-rule for the script in their settings.
|
|
33
|
+
|
|
34
|
+
2. **Worktree preflight:** confirm the session is isolated (the working directory path includes `.claude/worktrees/`) before the first tick or round. Classify the working tree against the PR's repo with
|
|
35
|
+
`python "$HOME/.claude/skills/_shared/pr-loop/scripts/preflight_worktree.py" --owner <O> --repo <R> --mode <classify|strict>`
|
|
36
|
+
and route per the caller's cwd-routing reference (pr-converge Step 1.5 for the classify route; autoconverge pre-flight for the strict route). Capture the session worktree path before routing away — close-time steps target the session repo.
|
|
37
|
+
|
|
38
|
+
## Close
|
|
39
|
+
|
|
40
|
+
Run these in order from the lead session on EVERY exit — converged, cap reached, stuck, or error.
|
|
41
|
+
|
|
42
|
+
1. **TeamDelete (team callers only).** Callers that created an agent team remove it with `TeamDelete`; single-agent and workflow callers skip this step.
|
|
43
|
+
2. **Worktree teardown:**
|
|
44
|
+
```bash
|
|
45
|
+
python "$HOME/.claude/skills/_shared/pr-loop/scripts/teardown_worktrees.py" \
|
|
46
|
+
--run-temp-dir "<run_temp_dir>" \
|
|
47
|
+
--all-pr-jsons '<json array of {number, owner, repo}>'
|
|
48
|
+
```
|
|
49
|
+
Tolerates already-removed worktrees and missing directories; removal is Windows-safe per `~/.claude/rules/windows-filesystem-safe.md`.
|
|
50
|
+
3. **Clean the working tree.** Return to the session worktree, remove run-scoped scratch files, and leave `git status` clean of run artifacts.
|
|
51
|
+
4. **Rewrite the PR description.** Follow [`reference/teardown-publish-permissions.md` § Publish the final PR description](reference/teardown-publish-permissions.md): capture the cumulative diff and original body, brief the `pr-description-writer` agent, publish via `update_pull_request`, remove the scratch files. On failure, report it and continue — the revoke still runs.
|
|
52
|
+
5. **Revoke project permissions (always):**
|
|
53
|
+
`python "$HOME/.claude/_shared/pr-loop/scripts/revoke_project_claude_permissions.py"`
|
|
54
|
+
Non-negotiable, including on error exits: leaving the grant in place lets future sessions inherit elevated `.claude/**` access without an explicit opt-in. Run revoke even when earlier close steps partially failed; log cleanup errors separately.
|
|
55
|
+
6. **Final report.** Print the caller's report block verbatim — no paraphrase, no extra commentary:
|
|
56
|
+
```
|
|
57
|
+
/<caller> exit: <converged | cap reached | stuck | error>
|
|
58
|
+
Loops: <loop_count>
|
|
59
|
+
Starting commit: <starting_sha7>
|
|
60
|
+
Final commit: <current_HEAD_sha7>
|
|
61
|
+
```
|
|
62
|
+
Callers append their own lines (net change, loop log, converged SHAs) per their SKILL.md.
|
|
63
|
+
|
|
64
|
+
## Gotchas
|
|
65
|
+
|
|
66
|
+
- **Revoke runs on the error path too.** The single most common lifecycle defect is a run that dies mid-loop and leaves the `.claude/**` grant in settings.
|
|
67
|
+
- **Close targets the session repo.** A cross-repo run that routed its cwd into the PR's worktree returns to the session worktree before steps 3–5; grant and revoke read the current working directory.
|
|
68
|
+
- **TeamDelete fires once, at run end.** Removing the team between audit-fix iterations is a bug.
|
|
69
|
+
|
|
70
|
+
## Folder map
|
|
71
|
+
|
|
72
|
+
- `SKILL.md` — this file.
|
|
73
|
+
- `reference/teardown-publish-permissions.md` — the full close sequence: utility-script homes, teardown, PR-description rewrite brief, revoke, report shape.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Utility scripts, teardown, PR body, permissions, report
|
|
2
2
|
|
|
3
|
+
The ordered close sequence for a PR-loop run. `<caller>` is the invoking skill's name (`bugteam`, `pr-converge`, `autoconverge`, `qbug`); it prefixes scratch files and the final-report header.
|
|
4
|
+
|
|
3
5
|
## Utility scripts (progressive disclosure)
|
|
4
6
|
|
|
5
7
|
Fragile or repeatable shell sequences live in one of two shared script directories. Match the reference depth to the directory:
|
|
@@ -7,17 +9,13 @@ Fragile or repeatable shell sequences live in one of two shared script directori
|
|
|
7
9
|
- **Package-root** [`_shared/pr-loop/scripts/`](../../../_shared/pr-loop/scripts/) holds `code_rules_gate.py`, `preflight.py`, `post_audit_thread.py`, and the permission helpers. Reference it as `../../../_shared/…` in markdown and `${CLAUDE_SKILL_DIR}/../../_shared/…` at runtime (resolves to `~/.claude/_shared/`). Inventory: [`../../../_shared/pr-loop/scripts/README.md`](../../../_shared/pr-loop/scripts/README.md).
|
|
8
10
|
- **Skill-tree** [`skills/_shared/pr-loop/scripts/`](../../_shared/pr-loop/scripts/) holds `teardown_worktrees.py`, `build_audit_prompt.py`, `build_fix_prompt.py`, `init_loop_state.py`, `write_audit_outcomes.py`, `write_fix_outcomes.py`, and `_path_resolver.py`. Reference it as `../../_shared/…` in markdown and `${CLAUDE_SKILL_DIR}/../_shared/…` at runtime (resolves to `~/.claude/skills/_shared/`).
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
### Pre-flight (recommended before Step 0)
|
|
13
|
-
|
|
14
|
-
From the repository root, run the command in `SKILL.md`. If the exit code is non-zero, stop and fix failing checks before granting permissions. Optional: `BUGTEAM_PREFLIGHT_SKIP=1` skips pre-flight (emergency only). Optional: `--pre-commit` when `.pre-commit-config.yaml` exists.
|
|
12
|
+
Caller-specific scripts live in the calling skill's own `scripts/` directory with their own README inventory. Anthropic: [Progressive disclosure patterns](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#progressive-disclosure-patterns) — utility scripts are **executed**, not loaded into context as primary reading. Gate-only merge-base / diff semantics: [`../../../_shared/pr-loop/code-rules-gate.md`](../../../_shared/pr-loop/code-rules-gate.md).
|
|
15
13
|
|
|
16
|
-
##
|
|
14
|
+
## Clean working tree
|
|
17
15
|
|
|
18
|
-
When the
|
|
16
|
+
When the run exits (any reason), run these steps in order from **this** session (the lead).
|
|
19
17
|
|
|
20
|
-
1. **
|
|
18
|
+
1. **TeamDelete (team callers only):** a caller that created an agent team removes `~/.claude/teams/<caller>/` and `~/.claude/tasks/<caller>/` with `TeamDelete`. Only at convergence/cap/stuck — not between loops. Single-agent and workflow callers skip this step.
|
|
21
19
|
|
|
22
20
|
2. Run [`teardown_worktrees.py`](../../_shared/pr-loop/scripts/teardown_worktrees.py)
|
|
23
21
|
to remove each PR's worktree (`git worktree remove`) and the run temp
|
|
@@ -33,11 +31,11 @@ When the cycle exits (any reason), run these steps in order from **this** sessio
|
|
|
33
31
|
`onexc`/`onerror` handler for Windows ReadOnly attribute safety
|
|
34
32
|
(see `~/.claude/rules/windows-filesystem-safe.md`).
|
|
35
33
|
|
|
36
|
-
##
|
|
34
|
+
## Publish the final PR description (mandatory)
|
|
37
35
|
|
|
38
|
-
After teardown and before permission revoke, the lead rewrites the PR body to the PR
|
|
36
|
+
After teardown and before permission revoke, the lead rewrites the PR body to the PR's **final cumulative state** — what the change delivers, not the loop's process. This is the **only** PR-write the lead performs (audit and fix comments stay with the agents that produced them).
|
|
39
37
|
|
|
40
|
-
The lead delegates body text to the `pr-description-writer` agent so the global mandatory-pr-description-writer hook accepts the
|
|
38
|
+
The lead delegates body text to the `pr-description-writer` agent so the global mandatory-pr-description-writer hook accepts the `gh pr edit` that follows. The lead does **not** compose the body inline.
|
|
41
39
|
|
|
42
40
|
`pr-description-writer` comes from the global git-workflow rule in `claude-code-config`. Invoke with `Agent`:
|
|
43
41
|
|
|
@@ -50,37 +48,37 @@ Agent(
|
|
|
50
48
|
)
|
|
51
49
|
```
|
|
52
50
|
|
|
53
|
-
If that subagent is missing, fall back to `general-purpose` with the same brief — the hook treats agent-authored bodies the same. If neither exists, log a warning and skip
|
|
51
|
+
If that subagent is missing, fall back to `general-purpose` with the same brief — the hook treats agent-authored bodies the same. If neither exists, log a warning and skip this step.
|
|
54
52
|
|
|
55
53
|
**Steps:**
|
|
56
54
|
|
|
57
|
-
1. Capture cumulative diff: `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` → write the response text to
|
|
58
|
-
2. Capture original body: `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` → extract `.body` from the response, write it to
|
|
55
|
+
1. Capture cumulative diff: `pull_request_read(method="get_diff", pullNumber=N, owner=O, repo=R)` → write the response text to `.<caller>-final.diff` using the `Write` tool.
|
|
56
|
+
2. Capture original body: `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` → extract `.body` from the response, write it to `.<caller>-original-body.md` using the `Write` tool.
|
|
59
57
|
3. Agent brief:
|
|
60
58
|
- **Inputs:** diff path, original body path, head branch, base branch.
|
|
61
59
|
- **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.
|
|
62
|
-
- **Preservation rule:** if the original body has manually curated sections (linked issues, screenshots, test plan,
|
|
60
|
+
- **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.
|
|
63
61
|
- **Output:** new body markdown.
|
|
64
|
-
4. Write
|
|
65
|
-
5. Publish the new body: `update_pull_request(pullNumber=N, owner=O, repo=R, body=<contents of
|
|
66
|
-
6.
|
|
62
|
+
4. Write `.<caller>-final-body.md`.
|
|
63
|
+
5. Publish the new body: `update_pull_request(pullNumber=N, owner=O, repo=R, body=<contents of .<caller>-final-body.md>)`.
|
|
64
|
+
6. Remove `.<caller>-final.diff`, `.<caller>-original-body.md`, `.<caller>-final-body.md`.
|
|
67
65
|
|
|
68
|
-
If
|
|
66
|
+
If this step fails (agent error, hook block, network), report in the final report and continue to the revoke. The original PR body remains; commits and comments are unaffected.
|
|
69
67
|
|
|
70
|
-
##
|
|
68
|
+
## Revoke project permissions (mandatory, always)
|
|
71
69
|
|
|
72
70
|
After team cleanup — including on error, cap-reached, or stuck exits — run:
|
|
73
71
|
|
|
74
72
|
```bash
|
|
75
|
-
python "${CLAUDE_SKILL_DIR}/scripts/revoke_project_claude_permissions.py"
|
|
73
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/revoke_project_claude_permissions.py"
|
|
76
74
|
```
|
|
77
75
|
|
|
78
|
-
This removes allow rules and `additionalDirectories` added
|
|
76
|
+
This removes allow rules and `additionalDirectories` added at open. Revoke is non-negotiable: leaving the grant in place would let future sessions inherit elevated `.claude/**` access without an explicit opt-in. Run revoke even if teardown partially failed; log cleanup errors separately.
|
|
79
77
|
|
|
80
|
-
##
|
|
78
|
+
## Final report
|
|
81
79
|
|
|
82
80
|
```
|
|
83
|
-
|
|
81
|
+
/<caller> exit: <converged | cap reached | stuck | error>
|
|
84
82
|
Loops: <loop_count>
|
|
85
83
|
Starting commit: <starting_sha7>
|
|
86
84
|
Final commit: <current_HEAD_sha7>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-scope-resolve
|
|
3
|
+
description: >-
|
|
4
|
+
Resolves the audit/fix target for a PR-loop skill: owner, repo, PR number,
|
|
5
|
+
head ref, base ref, PR URL, and starting head SHA — via
|
|
6
|
+
pull_request_read(method="get"), a search_pull_requests branch fallback, then a
|
|
7
|
+
git merge-base upstream-diff fallback, ending in the canonical refusal line
|
|
8
|
+
when no target exists. Invoked by PR-loop orchestrators (pr-converge,
|
|
9
|
+
bugteam, qbug, findbugs, fixbugs) as their first step; not for general git
|
|
10
|
+
questions or branch management.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PR Scope Resolve
|
|
14
|
+
|
|
15
|
+
**Core principle:** every PR-loop skill agrees on what it is auditing before any other work. One resolution ladder, one refusal line.
|
|
16
|
+
|
|
17
|
+
## How callers invoke this
|
|
18
|
+
|
|
19
|
+
- **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "pr-scope-resolve", args: "--skill <caller> [PR URL if the user gave one]"})`.
|
|
20
|
+
- **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/pr-scope-resolve/SKILL.md` and apply the resolution ladder with the parameters below."
|
|
21
|
+
|
|
22
|
+
The caller identity fills the refusal template. The resolved scope hands back: `owner`, `repo`, `number`, `head_ref`, `base_ref`, `url`, and `head_sha` (the starting `current_head`).
|
|
23
|
+
|
|
24
|
+
## The resolution ladder
|
|
25
|
+
|
|
26
|
+
Match the first rung that holds:
|
|
27
|
+
|
|
28
|
+
1. **A PR URL was given.** Extract `owner`, `repo`, and `number` from the URL, then `pull_request_read(method="get", pullNumber=N, owner=O, repo=R)` for `head.sha`, `head.ref`, `base.ref`, and draft state.
|
|
29
|
+
2. **Open PR for the current branch.** Call `pull_request_read(method="get")` with the PR number from the caller's context. When the number is unknown, recover it with the `search_pull_requests` MCP tool using the current branch name, then fetch as in rung 1.
|
|
30
|
+
3. **No PR, but a remote default branch exists.** The scope is the upstream diff: `git merge-base HEAD origin/<default>` then `git diff <merge-base>...HEAD`. `head_sha` is `git rev-parse HEAD`; there is no PR number or URL, and steps that post to a PR are skipped by the caller.
|
|
31
|
+
4. **Neither.** Respond exactly with the refusal template and stop:
|
|
32
|
+
|
|
33
|
+
`No PR or upstream diff. /<caller> needs a target.`
|
|
34
|
+
|
|
35
|
+
## Ground rules
|
|
36
|
+
|
|
37
|
+
- **The GitHub MCP is the primary transport** (`pull_request_read`, `search_pull_requests`); raw `gh api` is the fallback. MCP calls behave the same from any worktree, so scope resolution never depends on the working directory.
|
|
38
|
+
- **Re-resolve `head_sha` after any push or external wait.** The scope tuple (`owner`, `repo`, `number`) is stable for a run; the head SHA is not.
|
|
39
|
+
- **Full-diff scope.** The resolved scope always means the full `origin/<base>...HEAD` diff — every file the PR touches. A caller that narrows to a file list, commit range, or flagged-path subset is out of contract with every convergence gate downstream.
|
|
40
|
+
|
|
41
|
+
## Gotchas
|
|
42
|
+
|
|
43
|
+
- **`search_pull_requests` recovers PR numbers from branch names**, but a branch reused across repos returns several hits — filter by repo before trusting the number.
|
|
44
|
+
- **A draft-state read belongs to this step.** Callers that need a draft PR (convergence loops that mark ready at the end) check `isDraft` here, on the same `get` call, rather than paying a second fetch later.
|
|
45
|
+
|
|
46
|
+
## Folder map
|
|
47
|
+
|
|
48
|
+
- `SKILL.md` — this file; the ladder is MCP- and git-native, so the skill ships no scripts.
|
package/skills/qbug/CLAUDE.md
CHANGED
|
@@ -6,13 +6,13 @@ Quick baseline PR audit: one clean-coder subagent loops audit → fix → commit
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
`/qbug` is the required baseline review for every new PR. It runs the same A–
|
|
9
|
+
`/qbug` is the required baseline review for every new PR. It runs the same A–P bug category rubric and CODE_RULES gate as `/bugteam` but with a single persistent subagent (no TeamCreate, no per-loop clean-room, no loop cap). Escalate to `/bugteam` when bias isolation across loops matters.
|
|
10
10
|
|
|
11
11
|
## Key files
|
|
12
12
|
|
|
13
13
|
| File | Purpose |
|
|
14
14
|
|---|---|
|
|
15
|
-
| `SKILL.md` | The complete skill — four steps (pre-flight, resolve PR scope, spawn subagent cycle, final report).
|
|
15
|
+
| `SKILL.md` | The complete skill — four steps (pre-flight, resolve PR scope via the `pr-scope-resolve` skill, spawn subagent cycle, final report). The subagent XML prompt is inline and points the embedded agent at the `post-audit-findings` and `pr-fix-protocol` skills for review posting and reply/resolve mechanics. |
|
|
16
16
|
|
|
17
17
|
## Shared artifacts (referenced by path, not copied)
|
|
18
18
|
|
|
@@ -25,7 +25,7 @@ The skill references shared scripts from `../_shared/pr-loop/scripts/`:
|
|
|
25
25
|
| `post_audit_thread.py` | Posts one GitHub review per loop (APPROVE or REQUEST_CHANGES) |
|
|
26
26
|
| `audit-reply-template.md` | Unified reply body shape for resolved threads |
|
|
27
27
|
|
|
28
|
-
Bug category rubric A–
|
|
28
|
+
Bug category rubric A–P lives at `../bugteam/PROMPTS.md`. Audit contract (finding schema, proof-of-absence, Haiku secondary, self-audit) lives at `../../_shared/pr-loop/audit-contract.md`.
|
|
29
29
|
|
|
30
30
|
## Subagent structure
|
|
31
31
|
|
|
@@ -37,4 +37,4 @@ Bug category rubric A–N lives at `../bugteam/PROMPTS.md`. Audit contract (find
|
|
|
37
37
|
|
|
38
38
|
- The lead resolves the temp directory via Python's `tempfile.gettempdir()` and passes the absolute path to the subagent.
|
|
39
39
|
- Each loop: one `code_rules_gate.py` pre-audit, one GitHub review posted, one commit on fix.
|
|
40
|
-
- Self-PR toggle
|
|
40
|
+
- Self-PR toggle, findings-JSON mapping, and anchored-only serialization live in the `post-audit-findings` skill; reply-and-resolve mechanics live in the `pr-fix-protocol` skill.
|