claude-dev-env 1.67.2 → 1.69.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 (124) hide show
  1. package/_shared/CLAUDE.md +13 -0
  2. package/_shared/pr-loop/CLAUDE.md +24 -0
  3. package/_shared/pr-loop/scripts/CLAUDE.md +30 -0
  4. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +21 -0
  5. package/_shared/pr-loop/scripts/tests/CLAUDE.md +32 -0
  6. package/agents/CLAUDE.md +29 -0
  7. package/audit-rubrics/CLAUDE.md +41 -0
  8. package/audit-rubrics/category_rubrics/CLAUDE.md +36 -0
  9. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  10. package/audit-rubrics/prompts/CLAUDE.md +36 -0
  11. package/bin/CLAUDE.md +28 -0
  12. package/commands/CLAUDE.md +25 -0
  13. package/docs/CLAUDE.md +28 -0
  14. package/docs/references/CLAUDE.md +13 -0
  15. package/hooks/CLAUDE.md +31 -0
  16. package/hooks/advisory/CLAUDE.md +16 -0
  17. package/hooks/blocking/CLAUDE.md +107 -0
  18. package/hooks/blocking/code_rules_constants_config.py +7 -4
  19. package/hooks/blocking/code_rules_docstrings.py +253 -0
  20. package/hooks/blocking/code_rules_enforcer.py +6 -0
  21. package/hooks/blocking/config/CLAUDE.md +22 -0
  22. package/hooks/blocking/test_code_rules_enforcer_class_docstring_methods.py +262 -0
  23. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +36 -0
  24. package/hooks/blocking/test_code_rules_enforcer_docstring_fallback_branch.py +398 -0
  25. package/hooks/blocking/test_code_rules_enforcer_file_global_constants.py +9 -0
  26. package/hooks/diagnostic/CLAUDE.md +43 -0
  27. package/hooks/diagnostic/migrations/CLAUDE.md +16 -0
  28. package/hooks/diagnostic/queries/CLAUDE.md +19 -0
  29. package/hooks/git-hooks/CLAUDE.md +28 -0
  30. package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +21 -0
  31. package/hooks/hooks_constants/CLAUDE.md +60 -0
  32. package/hooks/hooks_constants/blocking_check_limits.py +18 -0
  33. package/hooks/lifecycle/CLAUDE.md +18 -0
  34. package/hooks/observability/CLAUDE.md +16 -0
  35. package/hooks/session/CLAUDE.md +21 -0
  36. package/hooks/validation/CLAUDE.md +19 -0
  37. package/hooks/validators/CLAUDE.md +49 -0
  38. package/hooks/workflow/CLAUDE.md +22 -0
  39. package/package.json +1 -1
  40. package/rules/CLAUDE.md +46 -0
  41. package/rules/docstring-prose-matches-implementation.md +3 -2
  42. package/scripts/CLAUDE.md +34 -0
  43. package/scripts/dev_env_scripts_constants/CLAUDE.md +14 -0
  44. package/scripts/sync_to_cursor/CLAUDE.md +23 -0
  45. package/scripts/tests/CLAUDE.md +18 -0
  46. package/skills/CLAUDE.md +66 -0
  47. package/skills/_shared/CLAUDE.md +11 -0
  48. package/skills/_shared/pr-loop/CLAUDE.md +27 -0
  49. package/skills/_shared/pr-loop/prompts/CLAUDE.md +9 -0
  50. package/skills/_shared/pr-loop/scripts/CLAUDE.md +23 -0
  51. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +19 -0
  52. package/skills/anthropic-plan/CLAUDE.md +34 -0
  53. package/skills/anthropic-plan/SKILL.md +1 -1
  54. package/skills/anthropic-plan/scripts/CLAUDE.md +11 -0
  55. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +16 -0
  56. package/skills/anthropic-plan/templates/CLAUDE.md +13 -0
  57. package/skills/anthropic-plan/workflow/CLAUDE.md +14 -0
  58. package/skills/auditing-claude-config/CLAUDE.md +20 -0
  59. package/skills/autoconverge/CLAUDE.md +30 -0
  60. package/skills/autoconverge/reference/CLAUDE.md +12 -0
  61. package/skills/autoconverge/workflow/CLAUDE.md +23 -0
  62. package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +16 -0
  63. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +135 -0
  64. package/skills/autoconverge/workflow/converge.mjs +119 -2
  65. package/skills/bdd-protocol/CLAUDE.md +26 -0
  66. package/skills/bdd-protocol/references/CLAUDE.md +10 -0
  67. package/skills/bg-agent/CLAUDE.md +17 -0
  68. package/skills/bugteam/CLAUDE.md +30 -0
  69. package/skills/bugteam/reference/CLAUDE.md +22 -0
  70. package/skills/bugteam/reference/obstacles/CLAUDE.md +24 -0
  71. package/skills/bugteam/scripts/CLAUDE.md +36 -0
  72. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +20 -0
  73. package/skills/caveman/CLAUDE.md +15 -0
  74. package/skills/code/CLAUDE.md +17 -0
  75. package/skills/copilot-review/CLAUDE.md +17 -0
  76. package/skills/deep-research/CLAUDE.md +17 -0
  77. package/skills/doc-gist/CLAUDE.md +25 -0
  78. package/skills/doc-gist/references/CLAUDE.md +9 -0
  79. package/skills/doc-gist/references/examples/CLAUDE.md +25 -0
  80. package/skills/doc-gist/scripts/CLAUDE.md +27 -0
  81. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +10 -0
  82. package/skills/everything-search/CLAUDE.md +17 -0
  83. package/skills/findbugs/CLAUDE.md +20 -0
  84. package/skills/fixbugs/CLAUDE.md +19 -0
  85. package/skills/fresh-branch/CLAUDE.md +15 -0
  86. package/skills/gh-paginate/CLAUDE.md +18 -0
  87. package/skills/gotcha/CLAUDE.md +33 -0
  88. package/skills/implement/CLAUDE.md +27 -0
  89. package/skills/implement/scripts/CLAUDE.md +22 -0
  90. package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +22 -0
  91. package/skills/logifix/CLAUDE.md +36 -0
  92. package/skills/logifix/scripts/CLAUDE.md +16 -0
  93. package/skills/monitor-open-prs/CLAUDE.md +34 -0
  94. package/skills/monitor-open-prs/scripts/CLAUDE.md +17 -0
  95. package/skills/pr-consistency-audit/CLAUDE.md +34 -0
  96. package/skills/pr-consistency-audit/reference/CLAUDE.md +16 -0
  97. package/skills/pr-converge/CLAUDE.md +29 -0
  98. package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +26 -0
  99. package/skills/pr-converge/reference/CLAUDE.md +27 -0
  100. package/skills/pr-converge/reference/obstacles/CLAUDE.md +23 -0
  101. package/skills/pr-converge/scripts/CLAUDE.md +36 -0
  102. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +17 -0
  103. package/skills/pr-converge/workflows/CLAUDE.md +16 -0
  104. package/skills/pr-review-responder/CLAUDE.md +35 -0
  105. package/skills/pre-compact/CLAUDE.md +24 -0
  106. package/skills/qbug/CLAUDE.md +40 -0
  107. package/skills/rebase/CLAUDE.md +32 -0
  108. package/skills/recall/CLAUDE.md +30 -0
  109. package/skills/refine/CLAUDE.md +44 -0
  110. package/skills/refine/templates/CLAUDE.md +17 -0
  111. package/skills/remember/CLAUDE.md +31 -0
  112. package/skills/research-mode/CLAUDE.md +35 -0
  113. package/skills/session-log/CLAUDE.md +31 -0
  114. package/skills/session-tidy/CLAUDE.md +36 -0
  115. package/skills/skill-builder/CLAUDE.md +45 -0
  116. package/skills/skill-builder/references/CLAUDE.md +19 -0
  117. package/skills/skill-builder/templates/CLAUDE.md +14 -0
  118. package/skills/skill-builder/workflows/CLAUDE.md +17 -0
  119. package/skills/structure-prompt/CLAUDE.md +42 -0
  120. package/skills/structure-prompt/reference/CLAUDE.md +28 -0
  121. package/skills/task-build/CLAUDE.md +28 -0
  122. package/skills/update/CLAUDE.md +38 -0
  123. package/skills/verified-build/CLAUDE.md +33 -0
  124. package/system-prompts/CLAUDE.md +17 -0
@@ -0,0 +1,30 @@
1
+ # autoconverge
2
+
3
+ **Trigger:** `/autoconverge`, "autoconverge this PR", "converge this PR in one run", "run the converge workflow", "drive the PR to ready autonomously".
4
+
5
+ Drives one draft PR to convergence in a single autonomous workflow run. Each round runs Cursor Bugbot, a code-review pass, and a bug-audit in parallel on the same HEAD, deduplicates findings, applies every fix in one commit, re-verifies, clears a Copilot wait-gate, and marks the PR ready on convergence. State lives in the workflow journal; no `ScheduleWakeup` ticks.
6
+
7
+ ## Subdirectories
8
+
9
+ | Directory | Role |
10
+ |---|---|
11
+ | `reference/` | Markdown docs the skill and workflow cite: round shape, stop conditions, gotchas, and closing report format. |
12
+ | `workflow/` | The `.mjs` convergence workflow, Python report scripts, test files, and the `autoconverge_report_constants/` package. |
13
+
14
+ ## Key files
15
+
16
+ | File | Role |
17
+ |---|---|
18
+ | `SKILL.md` | Full entry-point protocol: pre-flight steps, worktree setup, `Workflow` call, budget-aware round boundaries, teardown, and the per-round convergence loop summary. |
19
+ | `workflow/converge.mjs` | Main convergence workflow. Runs rounds, gates on Copilot, checks convergence, and marks the PR ready. |
20
+ | `workflow/aggregate_runs.py` | Merges every autoconverge journal for a PR into one deduped journal. |
21
+ | `workflow/convergence_summary.py` | Builds the convergence-summary agent prompt over the merged findings. |
22
+ | `workflow/render_report.py` | Builds the closing HTML report from the merged journal and summary. |
23
+ | `reference/convergence.md` | Round shape: the three parallel lenses, deduplication, fix commit, and the ready definition. |
24
+ | `reference/stop-conditions.md` | Every way the run ends short of ready. |
25
+ | `reference/gotchas.md` | Hard-won failure lessons. |
26
+ | `reference/closing-report.md` | Specification for the closing HTML report format. |
27
+
28
+ ## Entry point
29
+
30
+ Requires the `Workflow` tool. The `SKILL.md` body specifies the exact pre-flight sequence and `Workflow` call.
@@ -0,0 +1,12 @@
1
+ # reference
2
+
3
+ Reference documentation for the `autoconverge` skill. The `converge.mjs` workflow and the `SKILL.md` cite these files to define behavior precisely.
4
+
5
+ ## Key files
6
+
7
+ | File | Role |
8
+ |---|---|
9
+ | `convergence.md` | Round shape: the three parallel lenses (Bugbot, code-review, bug-audit), deduplication, the fix commit step, and the definition of a clean convergence. |
10
+ | `stop-conditions.md` | Every condition that ends the run short of ready: budget cap, iteration cap, blocker exit, Copilot bypass. |
11
+ | `gotchas.md` | Hard-won lessons from failed runs: PR title validation, conflicting PRs, worktree branch lock, resumed sessions rerooting, and minter issues. |
12
+ | `closing-report.md` | Specification for the closing HTML convergence report the teardown step builds and publishes. |
@@ -0,0 +1,23 @@
1
+ # workflow
2
+
3
+ Workflow scripts and report utilities for the `autoconverge` skill.
4
+
5
+ ## Key files
6
+
7
+ | File | Role |
8
+ |---|---|
9
+ | `converge.mjs` | Main convergence workflow script. Each round runs Bugbot, code-review, and bug-audit lenses in parallel, deduplicates findings, applies fixes, pushes, gates on Copilot, checks convergence, and marks the PR ready. Runs via the `Workflow` tool — not directly with Node. |
10
+ | `aggregate_runs.py` | Merges every autoconverge journal for a given PR (matched by run id) into one merged journal. Prints a JSON line with `mergedJournal`, `roundCount`, `finalSha`, and `findingCount`. |
11
+ | `convergence_summary.py` | Builds the convergence-summary agent prompt over the merged journal's findings. The teardown step spawns a `general-purpose` subagent on this prompt. |
12
+ | `render_report.py` | Builds the closing HTML insights report. Takes `--journal`, `--summary-file`, `--out`, `--pr`, `--final-sha`, and `--rounds`. Writes the HTML to `--out` and prints the output path on stdout. |
13
+ | `autoconverge_report_constants/` | Named constants package for `render_report.py` and `convergence_summary.py`. |
14
+ | `converge.contract.test.mjs` | Contract tests for `converge.mjs` — verify the workflow interface and step ordering. |
15
+ | `converge.clean-audit.test.mjs` | Tests the clean-audit path (all lenses clean on first round). |
16
+ | `converge.copilot-gate.test.mjs` | Tests Copilot gate behavior (bypass on quota exhaustion). |
17
+ | `converge.fix-progress.test.mjs` | Tests fix-progress tracking across rounds. |
18
+ | `converge.fix-recovery.test.mjs` | Tests recovery when a fix commit fails. |
19
+ | `converge.run-input.test.mjs` | Tests workflow input validation. |
20
+ | `test_aggregate_runs.py` | Tests for `aggregate_runs.py`. |
21
+ | `test_convergence_summary.py` | Tests for `convergence_summary.py`. |
22
+ | `test_render_report.py` | Tests for `render_report.py`. |
23
+ | `fixtures/` | Test fixture data for the workflow tests. |
@@ -0,0 +1,16 @@
1
+ # autoconverge_report_constants
2
+
3
+ Python package of named constants for `render_report.py` and `convergence_summary.py` in the `autoconverge/workflow/` directory.
4
+
5
+ ## Key files
6
+
7
+ | File | Role |
8
+ |---|---|
9
+ | `__init__.py` | Package marker. |
10
+ | `render_report_constants.py` | Named constants for the report renderer: structured output tool name, journal label prefixes (`resolve-head`, `lens:`, `fix:`, `copilot-gate`, `convergence-summary`), journal sibling directory names, default finding category and severity, date and SHA length constants, workflow name, projects directory name, merged run id prefix, summary detail character limit, and `onexc` Python version threshold. |
11
+
12
+ ## Usage
13
+
14
+ ```python
15
+ from autoconverge_report_constants.render_report_constants import LABEL_PREFIX_LENS
16
+ ```
@@ -183,3 +183,138 @@ test('the round-loop fix-stalled blockers survive the recovery wiring', () => {
183
183
  assert.match(convergeSource, /fix lens landed no push for/);
184
184
  assert.match(convergeSource, /copilot fix lens landed no push for/);
185
185
  });
186
+
187
+ const verifyObjectionModule = new Function(
188
+ `${constantLine('VERIFY_OBJECTION_FALLBACK')}\n` +
189
+ `${functionSource('renderVerifyObjectionLine')}\n` +
190
+ `${functionSource('extractVerifyObjection')}\n` +
191
+ 'return { extractVerifyObjection, VERIFY_OBJECTION_FALLBACK };',
192
+ )();
193
+
194
+ const { extractVerifyObjection, VERIFY_OBJECTION_FALLBACK } = verifyObjectionModule;
195
+
196
+ test('extractVerifyObjection falls back for a non-string transcript', () => {
197
+ assert.equal(extractVerifyObjection(null), VERIFY_OBJECTION_FALLBACK);
198
+ });
199
+
200
+ test('extractVerifyObjection falls back when no verdict fence is present', () => {
201
+ assert.equal(
202
+ extractVerifyObjection('the verifier wrote prose with no verdict fence'),
203
+ VERIFY_OBJECTION_FALLBACK,
204
+ );
205
+ });
206
+
207
+ test('extractVerifyObjection falls back when the verdict fence carries no findings', () => {
208
+ const transcript = '```verdict\n{"all_pass": false, "findings": []}\n```';
209
+ assert.equal(extractVerifyObjection(transcript), VERIFY_OBJECTION_FALLBACK);
210
+ });
211
+
212
+ test('extractVerifyObjection renders each verdict finding as check then detail', () => {
213
+ const transcript =
214
+ '```verdict\n{"all_pass": false, "findings": [{"check": "Finding 1", "detail": "still over-blocks"}, {"check": "Finding 2", "detail": "boundary unchecked"}]}\n```';
215
+ const objection = extractVerifyObjection(transcript);
216
+ assert.match(objection, /1\. Finding 1 — still over-blocks/);
217
+ assert.match(objection, /2\. Finding 2 — boundary unchecked/);
218
+ });
219
+
220
+ test('extractVerifyObjection reads the LAST verdict fence', () => {
221
+ const transcript =
222
+ '```verdict\n{"all_pass": false, "findings": [{"check": "stale", "detail": "old"}]}\n```\nretry\n```verdict\n{"all_pass": false, "findings": [{"check": "fresh", "detail": "new"}]}\n```';
223
+ const objection = extractVerifyObjection(transcript);
224
+ assert.match(objection, /fresh — new/);
225
+ assert.doesNotMatch(objection, /stale/);
226
+ });
227
+
228
+ test('extractVerifyObjection renders bare string findings as their text', () => {
229
+ const transcript =
230
+ '```verdict\n{"all_pass": false, "findings": ["boundary still over-blocks", "missing test for empty input"]}\n```';
231
+ const objection = extractVerifyObjection(transcript);
232
+ assert.match(objection, /1\. boundary still over-blocks/);
233
+ assert.match(objection, /2\. missing test for empty input/);
234
+ assert.doesNotMatch(objection, /unnamed check/);
235
+ });
236
+
237
+ test('extractVerifyObjection renders alternate-keyed objects (title, message, description, issue)', () => {
238
+ const transcript =
239
+ '```verdict\n{"all_pass": false, "findings": [{"title": "over-blocks", "detail": "boundary unchecked"}, {"message": "regex too broad"}, {"description": "no fallback path"}, {"issue": "stale fixture"}]}\n```';
240
+ const objection = extractVerifyObjection(transcript);
241
+ assert.match(objection, /over-blocks — boundary unchecked/);
242
+ assert.match(objection, /regex too broad/);
243
+ assert.match(objection, /no fallback path/);
244
+ assert.match(objection, /stale fixture/);
245
+ assert.doesNotMatch(objection, /unnamed check/);
246
+ assert.doesNotMatch(objection, /no detail/);
247
+ });
248
+
249
+ test('extractVerifyObjection renders mixed string and object findings', () => {
250
+ const transcript =
251
+ '```verdict\n{"all_pass": false, "findings": ["plain concern", {"check": "named", "detail": "explained"}]}\n```';
252
+ const objection = extractVerifyObjection(transcript);
253
+ assert.match(objection, /1\. plain concern/);
254
+ assert.match(objection, /2\. named — explained/);
255
+ });
256
+
257
+ test('extractVerifyObjection stringifies an object whose keys it does not recognize', () => {
258
+ const transcript = '```verdict\n{"all_pass": false, "findings": [{"severity": "P1", "line": 42}]}\n```';
259
+ const objection = extractVerifyObjection(transcript);
260
+ assert.match(objection, /severity/);
261
+ assert.match(objection, /42/);
262
+ assert.doesNotMatch(objection, /unnamed check/);
263
+ });
264
+
265
+ test('extractVerifyObjection falls back when no finding yields usable text', () => {
266
+ const transcript = '```verdict\n{"all_pass": false, "findings": [null, {}, ""]}\n```';
267
+ assert.equal(extractVerifyObjection(transcript), VERIFY_OBJECTION_FALLBACK);
268
+ });
269
+
270
+ test('recoverVerifyFailEdit is a clean-coder edit step bound to the verifier objection and leaves changes uncommitted', () => {
271
+ const recoverBody = functionSource('recoverVerifyFailEdit');
272
+ assert.match(recoverBody, /agentType:\s*'clean-coder'/, 'expected the fixer to use clean-coder');
273
+ assert.match(recoverBody, /schema:\s*EDIT_SCHEMA/, 'expected the fixer to reuse EDIT_SCHEMA');
274
+ assert.match(recoverBody, /label:\s*`fix-verify-recover:/, 'expected the fix-verify-recover label');
275
+ assert.match(recoverBody, /objection/, 'expected the fixer prompt to consume the verifier objection');
276
+ assert.match(
277
+ recoverBody,
278
+ /do not commit and do not push|Do NOT commit|leave .*uncommitted|uncommitted/i,
279
+ 'expected the fixer to leave its fix uncommitted for the re-verify and retry commit',
280
+ );
281
+ });
282
+
283
+ test('verifyWithRecovery bounds the loop, re-fixes on a failed verdict, and re-verifies', () => {
284
+ const recoveryBody = functionSource('verifyWithRecovery');
285
+ assert.match(recoveryBody, /verdictPassed\(/, 'expected the loop guard to call verdictPassed');
286
+ assert.match(
287
+ recoveryBody,
288
+ /attempt\s*<\s*FIX_RECOVERY_MAX_ATTEMPTS/,
289
+ 'expected the loop to be bounded by FIX_RECOVERY_MAX_ATTEMPTS',
290
+ );
291
+ assert.match(recoveryBody, /runRecoverEdit\(/, 'expected the loop to spawn the verify-recovery fixer');
292
+ assert.match(recoveryBody, /runVerify\(/, 'expected the loop to re-verify after the fixer edit');
293
+ assert.match(
294
+ recoveryBody,
295
+ /extractVerifyObjection\(/,
296
+ 'expected the loop to feed the fixer the verifier objection',
297
+ );
298
+ const editGuardIndex = recoveryBody.search(/edited\s*!==\s*true/);
299
+ assert.notEqual(editGuardIndex, -1, 'expected an early break when the fixer made no edit');
300
+ const recoverEditIndex = recoveryBody.search(/runRecoverEdit\(/);
301
+ const reverifyIndex = recoveryBody.lastIndexOf('runVerify(');
302
+ assert.ok(recoverEditIndex < reverifyIndex, 'expected order recover-edit -> re-verify, so a swap fails');
303
+ });
304
+
305
+ test('applyFixes routes its verify through verifyWithRecovery before commitWithRecovery', () => {
306
+ const applyFixesBody = functionSource('applyFixes');
307
+ assert.match(applyFixesBody, /verifyWithRecovery\(/, 'expected applyFixes to call verifyWithRecovery');
308
+ assert.match(applyFixesBody, /runVerify:\s*\(\)\s*=>\s*verifyFixesInWorkingTree\(/);
309
+ assert.match(applyFixesBody, /runRecoverEdit:[\s\S]*?recoverVerifyFailEdit\(/);
310
+ const verifyIndex = applyFixesBody.search(/verifyWithRecovery\(/);
311
+ const commitIndex = applyFixesBody.search(/commitWithRecovery\(/);
312
+ assert.ok(verifyIndex < commitIndex, 'expected verify-recovery to precede commit-recovery');
313
+ });
314
+
315
+ test('repairConvergence routes its verify through verifyWithRecovery wired to the repair verify step', () => {
316
+ const repairBody = functionSource('repairConvergence');
317
+ assert.match(repairBody, /verifyWithRecovery\(/, 'expected repairConvergence to call verifyWithRecovery');
318
+ assert.match(repairBody, /runVerify:\s*\(\)\s*=>\s*verifyRepairChanges\(/);
319
+ assert.match(repairBody, /runRecoverEdit:[\s\S]*?recoverVerifyFailEdit\(/);
320
+ });
@@ -406,6 +406,68 @@ function verdictPassed(verifyTranscript) {
406
406
  }
407
407
  }
408
408
 
409
+ const VERIFY_OBJECTION_FALLBACK = 'The verify step rejected the working-tree fixes without a parseable verdict; re-read the fix-verify transcript above and address every concern it raised.'
410
+
411
+ /**
412
+ * Render one verdict finding as a single objection line, tolerant of the shapes a
413
+ * verifier realistically emits: a bare string, an object keyed by any of
414
+ * check/title/message/description/issue for the headline and detail/description
415
+ * for the body, or any other object (stringified so its content survives). A
416
+ * headline and a detail render as "headline — detail"; a headline alone renders
417
+ * as the headline; an entry that yields no usable text returns null so the caller
418
+ * can fall back rather than emit a content-free placeholder.
419
+ * @param {unknown} eachFinding one entry from the verdict findings array
420
+ * @returns {string|null} the rendered objection line, or null when unusable
421
+ */
422
+ function renderVerifyObjectionLine(eachFinding) {
423
+ if (typeof eachFinding === 'string') {
424
+ const trimmedFinding = eachFinding.trim()
425
+ return trimmedFinding.length > 0 ? trimmedFinding : null
426
+ }
427
+ if (eachFinding === null || typeof eachFinding !== 'object') return null
428
+ const headline =
429
+ eachFinding.check || eachFinding.title || eachFinding.message || eachFinding.description || eachFinding.issue
430
+ const detail = eachFinding.detail || (headline === eachFinding.description ? '' : eachFinding.description)
431
+ if (typeof headline === 'string' && headline.length > 0) {
432
+ return typeof detail === 'string' && detail.length > 0 ? `${headline} — ${detail}` : headline
433
+ }
434
+ const stringifiedFinding = JSON.stringify(eachFinding)
435
+ return stringifiedFinding === '{}' ? null : stringifiedFinding
436
+ }
437
+
438
+ /**
439
+ * Pull the verifier's stated objections out of a failed verify transcript so the
440
+ * re-fix step knows what the verdict rejected. Reads the last fenced verdict JSON
441
+ * (the same block verdictPassed reads) and renders each finding through
442
+ * renderVerifyObjectionLine into a numbered list. A missing fence, a parse
443
+ * failure, an empty findings list, or a findings list where no entry yields
444
+ * usable text falls back to a generic re-read instruction, so the re-fix step
445
+ * always receives actionable text.
446
+ * @param {string|null|undefined} verifyTranscript the failed verifier transcript text
447
+ * @returns {string} a human-readable block of the verifier's objections
448
+ */
449
+ function extractVerifyObjection(verifyTranscript) {
450
+ if (typeof verifyTranscript !== 'string') return VERIFY_OBJECTION_FALLBACK
451
+ const fencePattern = /```verdict\s*\n([\s\S]*?)```/g
452
+ let lastFenceBody = null
453
+ let eachMatch
454
+ while ((eachMatch = fencePattern.exec(verifyTranscript)) !== null) {
455
+ lastFenceBody = eachMatch[1]
456
+ }
457
+ if (lastFenceBody === null) return VERIFY_OBJECTION_FALLBACK
458
+ try {
459
+ const verdictRecord = JSON.parse(lastFenceBody)
460
+ const allObjections = Array.isArray(verdictRecord?.findings) ? verdictRecord.findings : []
461
+ const renderedObjections = allObjections
462
+ .map((eachFinding) => renderVerifyObjectionLine(eachFinding))
463
+ .filter((eachLine) => eachLine !== null)
464
+ if (renderedObjections.length === 0) return VERIFY_OBJECTION_FALLBACK
465
+ return renderedObjections.map((eachLine, position) => `${position + 1}. ${eachLine}`).join('\n')
466
+ } catch {
467
+ return VERIFY_OBJECTION_FALLBACK
468
+ }
469
+ }
470
+
409
471
  /**
410
472
  * Decide whether a fix lens actually advanced the round: a pushed fix that moved
411
473
  * HEAD progressed, and so did an all-stale round whose findings were every one
@@ -808,6 +870,32 @@ function recoverCommitBlockEdit(head, blockerDetail, sourceLabel, attempt) {
808
870
  )
809
871
  }
810
872
 
873
+ /**
874
+ * Verify-recovery fixer: when the verify step rejects the working-tree fixes, one
875
+ * clean-coder re-fixes against the verdict's stated objections, test-first, and
876
+ * leaves the work uncommitted so the re-verify step can bind a fresh verdict. The
877
+ * objection text names which findings the verifier judged unresolved and why, so
878
+ * the fixer addresses those concerns; it does not touch GitHub review threads —
879
+ * the edit step already replied to and resolved those.
880
+ * @param {string} head PR HEAD SHA the fixes were raised against
881
+ * @param {string} objection the verifier's rendered objections from the failed verdict
882
+ * @param {string} sourceLabel short description of where the findings came from
883
+ * @param {number} attempt the 1-based recovery attempt number
884
+ * @returns {Promise<object>} EDIT_SCHEMA result
885
+ */
886
+ function recoverVerifyFailEdit(head, objection, sourceLabel, attempt) {
887
+ return convergeAgent(
888
+ `You are the VERIFY-RECOVERY fixer (attempt ${attempt}) for fixes (${sourceLabel}) on ${prCoordinates}, HEAD ${head}. The verify step rejected the working-tree fixes; its verdict named what is still unresolved. A separate verify step then a separate commit step run after you.\n\n` +
889
+ `The verify step's objections:\n${objection}\n\n` +
890
+ `Rules:\n` +
891
+ `- Confirm the working tree is on the PR branch at HEAD ${head} with the prior fixes still present.\n` +
892
+ `- Address every objection above test-first (failing test, then minimum code to pass) per CODE_RULES, so each named concern is genuinely resolved the way the verdict requires. Do not touch GitHub review threads — the edit step already handled those.\n` +
893
+ `- Leave the corrected fixes in the working tree. Do NOT commit and do NOT push — the verify step re-binds a verdict and the commit step pushes after you.\n\n` +
894
+ `Return values: edited=true with a one-line summary when you changed code to address the objections; edited=false, resolvedWithoutCommit=false when the objections cannot be cleared with a code change.`,
895
+ { label: `fix-verify-recover:${sourceLabel}`, phase: 'Converge', schema: EDIT_SCHEMA, agentType: 'clean-coder' },
896
+ )
897
+ }
898
+
811
899
  const FIX_RECOVERY_MAX_ATTEMPTS = 2
812
900
 
813
901
  /**
@@ -836,6 +924,29 @@ async function commitWithRecovery({ runCommit, runVerify, runRecoverEdit }) {
836
924
  return commitResult
837
925
  }
838
926
 
927
+ /**
928
+ * Run the verify step and, when its verdict fails, route back to a fixer: re-fix
929
+ * against the verifier's objection, then re-verify — bounded by
930
+ * FIX_RECOVERY_MAX_ATTEMPTS. The loop breaks early when the fixer makes no edit,
931
+ * returning the last failed verify transcript so the caller's verdict-failed
932
+ * handling still applies; a verify that passes on any attempt returns its passing
933
+ * transcript so the caller proceeds to commit.
934
+ * @param {{runVerify: function, runRecoverEdit: function}} steps the verify and verify-recovery-edit thunks
935
+ * @returns {Promise<string>} the final verify transcript — passing, or the last failed one
936
+ */
937
+ async function verifyWithRecovery({ runVerify, runRecoverEdit }) {
938
+ let verifyTranscript = await runVerify()
939
+ let attempt = 0
940
+ while (!verdictPassed(verifyTranscript) && attempt < FIX_RECOVERY_MAX_ATTEMPTS) {
941
+ attempt += 1
942
+ const objection = extractVerifyObjection(verifyTranscript)
943
+ const recoverEdit = await runRecoverEdit(objection, attempt)
944
+ if (recoverEdit?.edited !== true) break
945
+ verifyTranscript = await runVerify()
946
+ }
947
+ return verifyTranscript
948
+ }
949
+
839
950
  /**
840
951
  * Fix lens: edit (clean-coder, no commit) -> verify (code-verifier emits a
841
952
  * verdict fence binding the working tree) -> commit (clean-coder, one commit +
@@ -862,7 +973,10 @@ async function applyFixes(head, findings, sourceLabel) {
862
973
  blockerDetail: '',
863
974
  }
864
975
  }
865
- const verifyTranscript = await verifyFixesInWorkingTree(head, findings, sourceLabel)
976
+ const verifyTranscript = await verifyWithRecovery({
977
+ runVerify: () => verifyFixesInWorkingTree(head, findings, sourceLabel),
978
+ runRecoverEdit: (objection, attempt) => recoverVerifyFailEdit(head, objection, sourceLabel, attempt),
979
+ })
866
980
  if (!verdictPassed(verifyTranscript)) {
867
981
  return {
868
982
  newSha: head,
@@ -1099,7 +1213,10 @@ async function repairConvergence(head, failures) {
1099
1213
  blockerDetail: '',
1100
1214
  }
1101
1215
  }
1102
- const verifyTranscript = await verifyRepairChanges(head, failures)
1216
+ const verifyTranscript = await verifyWithRecovery({
1217
+ runVerify: () => verifyRepairChanges(head, failures),
1218
+ runRecoverEdit: (objection, attempt) => recoverVerifyFailEdit(head, objection, 'repair', attempt),
1219
+ })
1103
1220
  if (!verdictPassed(verifyTranscript)) {
1104
1221
  return {
1105
1222
  newSha: head,
@@ -0,0 +1,26 @@
1
+ # bdd-protocol
2
+
3
+ **Trigger:** `/bdd-protocol`, "Example Mapping", "BDD anti-patterns", "§7.6", writing executable specifications, BDD scenario quality, "the one where" discovery examples.
4
+
5
+ On-demand BDD depth layered on top of the always-on `<behavior_protocol>` in the system prompt. The skill adds the Example Mapping algorithm (Smart & Molak §6.4), the scenario quality catalog (§7.6), outside-in test layout, and solo BDD patterns.
6
+
7
+ ## Subdirectories
8
+
9
+ | Directory | Role |
10
+ |---|---|
11
+ | `references/` | Loaded reference docs: Example Mapping algorithm and the anti-patterns catalog. |
12
+
13
+ ## Key files
14
+
15
+ | File | Role |
16
+ |---|---|
17
+ | `SKILL.md` | Entry point. `@`-imports both reference files so they load with the skill. Lists authorities and scope boundaries. |
18
+ | `references/example-mapping.md` | Example Mapping algorithm: core moves ("The one where …"), the chat algorithm for solo use, time-boxing guidance. Source: Smart & Molak §6.4. |
19
+ | `references/anti-patterns.md` | §7.6 scenario quality catalog: anti-patterns to avoid and the criteria for a good scenario. |
20
+
21
+ ## What the skill adds
22
+
23
+ The base `<behavior_protocol>` (Deliberate Discovery → Illustrate → Formulate → Automate) is always active. This skill adds depth only when:
24
+ - The task needs Example Mapping steps or parking-lot question management.
25
+ - Scenarios need the §7.6 quality bar applied.
26
+ - Tests need outside-in layout using describe / when / should.
@@ -0,0 +1,10 @@
1
+ # references
2
+
3
+ Reference documentation loaded by the `bdd-protocol` skill. Both files are `@`-imported in `SKILL.md` and load when the skill activates.
4
+
5
+ ## Key files
6
+
7
+ | File | Role |
8
+ |---|---|
9
+ | `example-mapping.md` | Example Mapping algorithm (Smart & Molak §6.4). Covers core moves, the "The one where …" phrasing, probes, parking-lot questions, the solo chat algorithm, and time-boxing guidance. |
10
+ | `anti-patterns.md` | §7.6 scenario quality catalog. Lists anti-patterns to avoid and the criteria for a well-formed BDD scenario. |
@@ -0,0 +1,17 @@
1
+ # bg-agent
2
+
3
+ Delegates a task to a background agent so the main session stays free. Triggered by `/bg-agent`, `bg-agent`, or `background agent for this`.
4
+
5
+ ## Purpose
6
+
7
+ This skill picks a suitable agent type for the task, spawns it via the `Agent` tool with `run_in_background: true`, and returns control at once. The spawned agent notifies on completion. Other skills (such as `gotcha`) invoke this skill to offload their own PR-creation steps.
8
+
9
+ ## Key file
10
+
11
+ | File | Purpose |
12
+ |---|---|
13
+ | `SKILL.md` | Full instructions: how to parse the task argument, how to pick an agent type, how to write a self-contained spawn prompt, and how to report spawn to the user. |
14
+
15
+ ## How this skill is invoked
16
+
17
+ The user types `/bg-agent <task description>` or a calling skill invokes it by name. The skill always spawns with `run_in_background: true` — it never runs the task inline in the main session.
@@ -0,0 +1,30 @@
1
+ # bugteam
2
+
3
+ Runs an audit-fix loop on an open pull request until all findings are resolved or the 20-loop cap is reached. Triggered by `/bugteam`, `run the bug team`, `auto-fix the PR until clean`, or `loop audit and fix`.
4
+
5
+ ## Purpose
6
+
7
+ Each loop: a `code-quality-agent` (fresh context, all A–P audit categories) produces an outcome XML; a `clean-coder` agent applies every fix; the lead commits, pushes, and posts a GitHub PR review (APPROVE on clean, REQUEST_CHANGES with inline anchored comments on dirty). Grants `.claude/**` write permissions at the start and revokes them at the end.
8
+
9
+ ## Key files
10
+
11
+ | File | Purpose |
12
+ |---|---|
13
+ | `SKILL.md` | Hub — pre-flight call, refusals, audit-posting protocol, progress checklist, and situation-to-reference table. Read this first. |
14
+ | `PROMPTS.md` | Spawn XML, A–P category bindings, outcome XML schemas. |
15
+ | `CONSTRAINTS.md` | Invariants — what the loop must never violate. |
16
+ | `EXAMPLES.md` | Exit scenarios: converged, cap-reached, stuck, refusal, mixed-outcome. |
17
+ | `sources.md` | Doc URLs and verbatim quotes cited in the skill body. |
18
+
19
+ ## Subdirectories
20
+
21
+ | Directory | Role |
22
+ |---|---|
23
+ | `reference/` | Expanded workflow detail loaded on demand (team setup, audit contract, GitHub PR review shape, teardown). |
24
+ | `scripts/` | Python scripts executed by the lead or teammates at runtime. |
25
+
26
+ ## Environment controls
27
+
28
+ - `CLAUDE_REVIEWS_DISABLED=bugteam` — disables the skill entirely (pre-flight exits 7).
29
+ - `BUGTEAM_PREFLIGHT_SKIP=1` — skips pytest in pre-flight.
30
+ - `BUGTEAM_REVIEWER_ACCOUNT=<login>` — names the alternate `gh` account for posting reviews when the PR author and reviewer identity match.
@@ -0,0 +1,22 @@
1
+ # bugteam/reference
2
+
3
+ Expanded workflow detail for the `bugteam` skill. Load a file from this directory when the orchestration stub in `SKILL.md` is not enough — for example, when debugging GitHub review shape, understanding gate semantics, or working through teardown edge cases.
4
+
5
+ ## Key files
6
+
7
+ | File | Purpose |
8
+ |---|---|
9
+ | `README.md` | Index of all files in this directory with one-line domain summaries. |
10
+ | `team-setup.md` | Permissions grant, PR scope resolution, run name, temp dir, and loop state. |
11
+ | `audit-and-teammates.md` | Pre-audit CODE_RULES gate, full cycle numbering, AUDIT and FIX action detail. |
12
+ | `audit-contract.md` | Finding shape (Shape A / B), Haiku secondary merge rules, post-fix self-audit. |
13
+ | `github-pr-reviews.md` | Per-loop review posting, `jq`+`gh api` payloads, inline anchors, fallbacks, REST endpoints. |
14
+ | `teardown-publish-permissions.md` | Teardown steps, PR description rewrite via `pr-description-writer`, permission revoke, final report. |
15
+ | `design-rationale.md` | Why clean-room subagents, when `/bugteam` applies, refusal reasons. |
16
+ | `copilot-gap-analysis.md` | Historical gap analysis (reference only). |
17
+
18
+ ## Subdirectories
19
+
20
+ | Directory | Role |
21
+ |---|---|
22
+ | `obstacles/` | Per-step obstacle guides — one file per common failure point (e.g., write XML, resolve thread, push, test suite). |
@@ -0,0 +1,24 @@
1
+ # bugteam/reference/obstacles
2
+
3
+ Per-step obstacle guides for the `bugteam` skill. Each file addresses a specific failure point that can occur during an audit-fix loop. Load the matching file when a step fails rather than improvising a fix.
4
+
5
+ ## Files
6
+
7
+ | File | Obstacle it addresses |
8
+ |---|---|
9
+ | `audit-assign-ids.md` | Assigning stable finding IDs in the audit output. |
10
+ | `audit-capture-excerpts.md` | Capturing code excerpts for each finding. |
11
+ | `audit-walk-categories.md` | Walking all A–P categories without skipping. |
12
+ | `audit-write-xml.md` | Writing the outcome XML from an audit pass. |
13
+ | `fix-append-summary.md` | Appending the fix summary to the outcome XML. |
14
+ | `fix-apply-fixes.md` | Applying code fixes from the finding list. |
15
+ | `fix-git-add-commit.md` | Staging and committing the fixed files. |
16
+ | `fix-git-push.md` | Pushing the fix commit to the remote branch. |
17
+ | `fix-post-reply.md` | Posting inline replies to finding threads on the PR. |
18
+ | `fix-publish-summary.md` | Publishing the loop summary to the PR. |
19
+ | `fix-py-compile.md` | Verifying Python syntax after fixes. |
20
+ | `fix-read-files.md` | Reading the files referenced in a finding. |
21
+ | `fix-resolve-thread.md` | Resolving a finding's review thread on GitHub. |
22
+ | `fix-test-suite.md` | Running the test suite and interpreting failures. |
23
+ | `fix-violation-count.md` | Counting open violations after a fix pass. |
24
+ | `fix-write-xml.md` | Writing the per-fix XML record. |
@@ -0,0 +1,36 @@
1
+ # bugteam/scripts
2
+
3
+ Python scripts executed by the bugteam lead or teammates at runtime. These are not loaded into context as instructions — they run as subprocess calls from within the skill workflow.
4
+
5
+ ## Scripts
6
+
7
+ | File | Purpose |
8
+ |---|---|
9
+ | `bugteam_preflight.py` | Run pytest and optional `pre-commit` before the first loop. Skips pytest when `BUGTEAM_PREFLIGHT_SKIP=1` or no test files exist. |
10
+ | `bugteam_fix_hookspath.py` | Auto-remediate a stale `core.hooksPath` override, set the canonical global value, re-run preflight. |
11
+ | `bugteam_code_rules_gate.py` | Run `validate_content` from `code_rules_enforcer.py` on PR-scoped files. Exit 1 on mandatory rule failures. |
12
+ | `grant_project_claude_permissions.py` | Grant Edit/Write/Read on `cwd/.claude/**` in `~/.claude/settings.json`. |
13
+ | `revoke_project_claude_permissions.py` | Remove the matching grant entries from `~/.claude/settings.json`. |
14
+ | `_bugteam_permissions_common.py` | Shared helpers for grant/revoke (atomic JSON writes, settings sections). |
15
+ | `windows_safe_rmtree.py` | Remove a directory tree on Windows by stripping ReadOnly attributes and retrying on failure. |
16
+ | `probe_code_rules_enforcer_check.py` | Load `code_rules_enforcer.py` and invoke a named check function against a fixture file. |
17
+ | `reflow_skill_md.py` | Reflow the bugteam SKILL.md body to fit line-length limits. |
18
+
19
+ ## Test files
20
+
21
+ | File | Tests |
22
+ |---|---|
23
+ | `test_bugteam_preflight.py` | `bugteam_preflight.py` |
24
+ | `test_bugteam_code_rules_gate.py` | `bugteam_code_rules_gate.py` |
25
+ | `test_bugteam_fix_hookspath.py` | `bugteam_fix_hookspath.py` |
26
+ | `test_bugteam_permissions_common.py` | `_bugteam_permissions_common.py` |
27
+ | `test__bugteam_permissions_common.py` | Internal helpers in `_bugteam_permissions_common.py` |
28
+ | `test_agent_config_carveout.py` | `.claude/**` grant/revoke carveout logic |
29
+ | `test_probe_code_rules_enforcer_check.py` | `probe_code_rules_enforcer_check.py` |
30
+ | `test_windows_safe_rmtree.py` | `windows_safe_rmtree.py` |
31
+
32
+ ## Subdirectories
33
+
34
+ | Directory | Role |
35
+ |---|---|
36
+ | `bugteam_scripts_constants/` | Named constants imported by the scripts above. |
@@ -0,0 +1,20 @@
1
+ # bugteam/scripts/bugteam_scripts_constants
2
+
3
+ Python package of named constants imported by the bugteam scripts. Each module holds the constants for one script; importing from this package keeps magic values out of the script bodies.
4
+
5
+ ## Modules
6
+
7
+ | File | Constants for |
8
+ |---|---|
9
+ | `bugteam_preflight_constants.py` | `bugteam_preflight.py` — env var name, hooks path suffix, exit codes, ignore dirs, argument tuples, config filenames. |
10
+ | `bugteam_code_rules_gate_constants.py` | `bugteam_code_rules_gate.py` — gate-related path and exit-code constants. |
11
+ | `bugteam_fix_hookspath_constants.py` | `bugteam_fix_hookspath.py` — canonical hooks path, remediation message strings. |
12
+ | `claude_permissions_common_constants.py` | `_bugteam_permissions_common.py` — settings JSON keys, glob patterns for the grant/revoke scripts. |
13
+ | `probe_code_rules_enforcer_check_constants.py` | `probe_code_rules_enforcer_check.py` — enforcer module path and function name constants. |
14
+ | `reflow_skill_md_constants.py` | `reflow_skill_md.py` — line-length and formatting constants. |
15
+ | `windows_safe_rmtree_constants.py` | `windows_safe_rmtree.py` — retry count and wait constants. |
16
+ | `__init__.py` | Empty package marker. |
17
+
18
+ ## Convention
19
+
20
+ Scripts import from this package at module scope. No constant is defined inline in a script body — the hook enforces this at write time.
@@ -0,0 +1,15 @@
1
+ # caveman
2
+
3
+ Trims noise from conversational text in the current turn. Triggered by `/caveman`, `caveman this`, `trim this`, `make it terse`, or `caveman voice`.
4
+
5
+ ## Purpose
6
+
7
+ The inline counterpart to the `caveman` agent. When the user wants preamble, hedging, filler transitions, restatements, empty future-proofing, dead examples, or pleasantries stripped from the last assistant message or from text passed as an argument, this skill performs the trim directly in the main session — no `Agent` spawn. The entire reply is the trimmed text; no report, no commentary about what was cut.
8
+
9
+ Use the `caveman` agent (`subagent_type: caveman`) when the input is a file path, a multi-section artifact that needs a structured report, or a delegated workflow.
10
+
11
+ ## Key file
12
+
13
+ | File | Purpose |
14
+ |---|---|
15
+ | `SKILL.md` | Instructions: resolve the source (argument or prior message), noise categories to cut, what to preserve verbatim, and the escape hatch for load-bearing spans. |
@@ -0,0 +1,17 @@
1
+ # code
2
+
3
+ Activates strict code standards for the entire implementation session. Triggered by `/code`, `code standards`, `strict code`, `enforce standards`, or `implement with standards`.
4
+
5
+ ## Purpose
6
+
7
+ Prepends a set of binary completion criteria to every implementation task: no `Any`, no `cast()`, no `# type: ignore`, treated-as-immutable TypedDicts with explicit `_encode_*`/`_decode_*` functions, 100% statement and branch coverage, zero mocks, zero stubs, zero fallbacks, and proper module structure. Every criterion is pass-or-fail; partial credit does not exist.
8
+
9
+ ## Key file
10
+
11
+ | File | Purpose |
12
+ |---|---|
13
+ | `SKILL.md` | Sixteen numbered criteria (typing strictness, error handling, test coverage, DI hooks, DRY, TypedDict protocol, Redis boundary, TOML boundary, JSON recursive types, ASGI boundaries, dynamic import pattern, documentation, build infrastructure, lint gates, Protocol signature match, auth/credentials), plus gotchas for Windows PowerShell invocation and per-module `_test_hooks.py` placement. |
14
+
15
+ ## Invocation note
16
+
17
+ Invoke at the start of an implementation task. The standards persist for the full session. The skill refuses research or planning tasks and redirects them to `/anthropic-plan`.
@@ -0,0 +1,17 @@
1
+ # copilot-review
2
+
3
+ Spawns a background subagent that polls the GitHub Copilot reviewer on the current PR, fixes unaddressed findings, and re-requests review each tick until the PR is clean. Triggered by `/copilot-review`, `watch copilot`, `babysit copilot review`, or `keep re-requesting copilot`.
4
+
5
+ ## Purpose
6
+
7
+ The main session gathers PR context (number, HEAD SHA, owner/repo, branch), spawns a self-terminating background subagent with a fully filled-in prompt, and returns control at once. The subagent loops on a 5-minute `ScheduleWakeup` cadence: fetch Copilot's latest review, TDD-fix any inline findings, push a commit, reply inline, re-request review. It stops on convergence, a persistent blocker, `TaskStop`, or after 20 ticks.
8
+
9
+ ## Key file
10
+
11
+ | File | Purpose |
12
+ |---|---|
13
+ | `SKILL.md` | Four-step orchestration (opt-out check, gather PR context, spawn subagent, report to user), the verbatim subagent prompt template with all placeholders, fix protocol, stop conditions, and ground rules (one commit per tick, honor hooks, preserve draft state, use `copilot-pull-request-reviewer[bot]` with the `[bot]` suffix). |
14
+
15
+ ## Environment opt-out
16
+
17
+ Set `CLAUDE_REVIEWS_DISABLED=copilot` to disable. The skill checks this before spawning anything.