claude-dev-env 1.25.2 → 1.26.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 (105) hide show
  1. package/CLAUDE.md +6 -0
  2. package/agents/clean-coder.md +1 -1
  3. package/docs/CODE_RULES.md +3 -1
  4. package/hooks/HOOK_SPECS_PROMPT_WORKFLOW.md +54 -0
  5. package/hooks/blocking/{code-rules-enforcer.py → code_rules_enforcer.py} +150 -5
  6. package/hooks/blocking/test_code_rules_enforcer_any_type_ignore.py +2 -2
  7. package/hooks/blocking/test_code_rules_enforcer_banned_identifier.py +2 -2
  8. package/hooks/blocking/test_code_rules_enforcer_conftest_anchor.py +1 -1
  9. package/hooks/blocking/test_code_rules_enforcer_dot_test_pattern.py +2 -2
  10. package/hooks/blocking/test_code_rules_enforcer_file_global_constants.py +181 -0
  11. package/hooks/blocking/test_code_rules_enforcer_fstring_scan.py +4 -4
  12. package/hooks/blocking/test_code_rules_enforcer_logger_fstring.py +1 -1
  13. package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
  14. package/hooks/blocking/test_code_rules_enforcer_magic_string_masking.py +104 -0
  15. package/hooks/blocking/test_code_rules_enforcer_naming_pattern.py +2 -2
  16. package/hooks/blocking/test_code_rules_enforcer_type_checking_scope.py +2 -2
  17. package/hooks/blocking/test_content_search_to_zoekt_redirector_integration.py +1 -1
  18. package/hooks/blocking/test_destructive_command_blocker.py +1 -1
  19. package/hooks/blocking/test_gh_body_arg_blocker.py +1 -1
  20. package/hooks/blocking/test_pr_description_enforcer.py +8 -8
  21. package/hooks/blocking/test_tdd_enforcer.py +1 -1
  22. package/hooks/github-action/pre-push-review.yml +27 -0
  23. package/hooks/hooks.json +28 -28
  24. package/hooks/lifecycle/{config-change-guard.py → config_change_guard.py} +27 -12
  25. package/hooks/lifecycle/test_config_change_guard.py +3 -3
  26. package/hooks/notification/{attention-needed-notify.py → attention_needed_notify.py} +7 -0
  27. package/hooks/notification/{claude-notification-handler.py → claude_notification_handler.py} +8 -0
  28. package/hooks/notification/notification_utils.py +56 -0
  29. package/hooks/notification/subagent_complete_notify.py +381 -0
  30. package/hooks/notification/test_attention_needed_notify.py +47 -0
  31. package/hooks/notification/test_claude_notification_handler.py +54 -0
  32. package/hooks/notification/test_notification_utils.py +45 -0
  33. package/hooks/notification/test_subagent_complete_notify.py +72 -0
  34. package/hooks/validators/README.md +5 -1
  35. package/hooks/validators/abbreviation_checks.py +1 -1
  36. package/hooks/validators/code_quality_checks.py +1 -1
  37. package/hooks/validators/config.py +5 -0
  38. package/hooks/validators/conftest.py +10 -0
  39. package/hooks/validators/exempt_paths.py +1 -1
  40. package/hooks/validators/git_checks.py +80 -0
  41. package/hooks/validators/magic_value_checks.py +2 -2
  42. package/hooks/validators/pr_reference_checks.py +1 -1
  43. package/hooks/validators/python_antipattern_checks.py +1 -1
  44. package/hooks/validators/run_all_validators.py +53 -105
  45. package/hooks/validators/security_checks.py +1 -1
  46. package/hooks/validators/test_abbreviation_checks.py +2 -2
  47. package/hooks/validators/test_code_quality_checks.py +2 -2
  48. package/hooks/validators/test_file_structure_checks.py +1 -1
  49. package/hooks/validators/test_git_checks.py +79 -13
  50. package/hooks/validators/test_health_check.py +1 -1
  51. package/hooks/validators/test_magic_value_checks.py +2 -2
  52. package/hooks/validators/test_mypy_integration.py +1 -1
  53. package/hooks/validators/test_output_formatter.py +3 -1
  54. package/hooks/validators/test_pr_reference_checks.py +2 -2
  55. package/hooks/validators/test_python_antipattern_checks.py +2 -2
  56. package/hooks/validators/test_python_style_checks.py +2 -4
  57. package/hooks/validators/test_react_checks.py +1 -1
  58. package/hooks/validators/test_ruff_integration.py +1 -1
  59. package/hooks/validators/test_run_all_validators.py +75 -43
  60. package/hooks/validators/test_run_all_validators_integration.py +14 -37
  61. package/hooks/validators/test_security_checks.py +2 -2
  62. package/hooks/validators/test_test_safety_checks.py +1 -1
  63. package/hooks/validators/test_todo_checks.py +2 -2
  64. package/hooks/validators/test_type_safety_checks.py +2 -2
  65. package/hooks/validators/test_useless_test_checks.py +2 -2
  66. package/hooks/validators/test_validator_base.py +1 -1
  67. package/hooks/validators/test_verify_paths.py +2 -4
  68. package/hooks/validators/todo_checks.py +1 -1
  69. package/hooks/validators/type_safety_checks.py +1 -1
  70. package/hooks/validators/useless_test_checks.py +1 -1
  71. package/package.json +1 -1
  72. package/rules/file-global-constants.md +71 -0
  73. package/rules/gh-body-file.md +1 -1
  74. package/rules/prompt-workflow-context-controls.md +48 -0
  75. package/scripts/sync_to_cursor/rules.py +2 -2
  76. package/scripts/tests/test_sync_to_cursor.py +2 -2
  77. package/skills/bugteam/CONSTRAINTS.md +37 -0
  78. package/skills/bugteam/EXAMPLES.md +64 -0
  79. package/skills/bugteam/PROMPTS.md +175 -0
  80. package/skills/bugteam/SKILL.md +204 -295
  81. package/skills/bugteam/SKILL_EVALS.md +346 -0
  82. package/skills/bugteam/scripts/README.md +37 -0
  83. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +334 -0
  84. package/skills/bugteam/scripts/bugteam_preflight.py +135 -0
  85. package/skills/rule-audit/SKILL.md +4 -4
  86. /package/hooks/advisory/{migration-safety-advisor.py → migration_safety_advisor.py} +0 -0
  87. /package/hooks/advisory/{refactor-guard.py → refactor_guard.py} +0 -0
  88. /package/hooks/blocking/{block-main-commit.py → block_main_commit.py} +0 -0
  89. /package/hooks/blocking/{content-search-to-zoekt-redirector.py → content_search_to_zoekt_redirector.py} +0 -0
  90. /package/hooks/blocking/{destructive-command-blocker.py → destructive_command_blocker.py} +0 -0
  91. /package/hooks/blocking/{gh-body-arg-blocker.py → gh_body_arg_blocker.py} +0 -0
  92. /package/hooks/blocking/{hedging-language-blocker.py → hedging_language_blocker.py} +0 -0
  93. /package/hooks/blocking/{pr-description-enforcer.py → pr_description_enforcer.py} +0 -0
  94. /package/hooks/blocking/{sensitive-file-protector.py → sensitive_file_protector.py} +0 -0
  95. /package/hooks/blocking/{tdd-enforcer.py → tdd_enforcer.py} +0 -0
  96. /package/hooks/blocking/{test-preflight-check.py → test_preflight_check.py} +0 -0
  97. /package/hooks/blocking/{write-existing-file-blocker.py → write_existing_file_blocker.py} +0 -0
  98. /package/hooks/git-hooks/{post-commit.py → post_commit.py} +0 -0
  99. /package/hooks/lifecycle/{session-end-cleanup.py → session_end_cleanup.py} +0 -0
  100. /package/hooks/{rewrite-plugin-paths.py → rewrite_plugin_paths.py} +0 -0
  101. /package/hooks/session/{plugin-data-dir-cleanup.py → plugin_data_dir_cleanup.py} +0 -0
  102. /package/hooks/validation/{hook-format-validator.py → hook_format_validator.py} +0 -0
  103. /package/hooks/workflow/{auto-formatter.py → auto_formatter.py} +0 -0
  104. /package/hooks/workflow/{investigation-tracker-reset.py → investigation_tracker_reset.py} +0 -0
  105. /package/scripts/{sync-to-cursor.py → sync_to_cursor.py} +0 -0
@@ -7,8 +7,8 @@ description: >-
7
7
  returns zero bugs or a 10-loop safety cap is reached. One up-front
8
8
  confirmation authorizes the entire cycle. Each audit teammate is spawned
9
9
  fresh per loop to prevent anchoring bias. Wraps the cycle with project
10
- permission grant/revoke. Requires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
11
- and Claude Code v2.1.32+. Triggers: '/bugteam', 'run the bug team',
10
+ permission grant/revoke. Requires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.
11
+ Triggers: '/bugteam', 'run the bug team',
12
12
  'auto-fix the PR until clean', 'loop audit and fix'.
13
13
  ---
14
14
 
@@ -22,9 +22,11 @@ description: >-
22
22
 
23
23
  ## Contents
24
24
 
25
- This file is 400+ lines. The list below is for the LLM reading this skill — partial reads (e.g., `head -100`) miss what comes later, so this section ensures the full scope is visible from the top. (Per Anthropic's [Skill authoring best practices — Structure longer reference files with table of contents](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#structure-longer-reference-files-with-table-of-contents).)
25
+ This file is the orchestration core. The list below is for the LLM reading this skill — partial reads (e.g., `head -100`) miss what comes later, so this section ensures the full scope is visible from the top. (Per Anthropic's [Skill authoring best practices — Structure longer reference files with table of contents](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#structure-longer-reference-files-with-table-of-contents).)
26
26
 
27
27
  - When this skill applies — refusal cases (4) and trigger conditions
28
+ - Utility scripts — pre-flight checks (`scripts/`, executed not loaded as context)
29
+ - Pre-audit code rules gate — `validate_content` / hook parity before each AUDIT
28
30
  - The Process — Progress checklist + Steps 0–6
29
31
  - Step 0 — Grant project permissions
30
32
  - Step 1 — Resolve PR scope
@@ -35,9 +37,9 @@ This file is 400+ lines. The list below is for the LLM reading this skill — pa
35
37
  - Step 4.5 — Finalize the PR description (via pr-description-writer)
36
38
  - Step 5 — Revoke project permissions
37
39
  - Step 6 — Print the final report
38
- - Constraintsinvariants the implementer must preserve
39
- - Examplesfive end-to-end scenarios
40
- - Why this design rationale for agent-teams + clean-room + grant/revoke
40
+ - [`PROMPTS.md`](PROMPTS.md)AUDIT spawn-prompt XML, FIX spawn-prompt XML, the 10 audit categories (A–J), and both outcome XML schemas. Load before spawning bugfind or bugfix, or when parsing teammate outcome XML.
41
+ - [`EXAMPLES.md`](EXAMPLES.md)six end-to-end scenarios (converged, cap reached, stuck, partial-fix, no-PR, dirty-tree). Load when an unfamiliar exit condition appears.
42
+ - [`CONSTRAINTS.md`](CONSTRAINTS.md) — invariants plus "Why this design" rationale. Load when a constraint question arises.
41
43
 
42
44
  ## When this skill applies
43
45
 
@@ -46,11 +48,24 @@ User wants automated convergence on a clean PR without babysitting each step. Ty
46
48
  Refusal cases — check in order; first match short-circuits and stops:
47
49
 
48
50
  - **Agent teams not enabled.** Check `claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and `~/.claude/settings.json`. If neither sets it to `"1"`, respond: `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 not set. /bugteam requires the agent teams feature. See https://code.claude.com/docs/en/agent-teams#enable-agent-teams.` and stop.
49
- - **Claude Code version too old.** Run `claude --version`. If older than v2.1.32, respond: `Claude Code v<version> is older than the v2.1.32 minimum for agent teams. Upgrade first.` and stop.
50
51
  - **Missing PR or upstream diff.** Respond exactly: `No PR or upstream diff. /bugteam needs a target.` and stop.
51
52
  - **Working tree dirty with uncommitted changes the user did not stage.** Respond: `Uncommitted changes detected. Stash, commit, or revert before /bugteam.` and stop. Reason: the fix teammate will commit the working tree, mixing user-uncommitted work into automated fixes.
52
53
  - **Required subagents not installed.** Before Step 0, verify `code-quality-agent` and `clean-coder` subagent types exist in the available agents list. If either is missing, respond: `Required subagent type <name> not installed. /bugteam needs both code-quality-agent and clean-coder available.` and stop.
53
54
 
55
+ ## Utility scripts
56
+
57
+ Fragile or repeatable shell sequences belong in `scripts/` (see Anthropic [Skill authoring best practices — Progressive disclosure](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#progressive-disclosure-patterns): utility scripts are **executed**, not loaded into context). Details: [`scripts/README.md`](scripts/README.md).
58
+
59
+ ### Pre-flight (recommended before Step 0)
60
+
61
+ From the repository root, run:
62
+
63
+ ```bash
64
+ python "${CLAUDE_SKILL_DIR}/scripts/bugteam_preflight.py"
65
+ ```
66
+
67
+ 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.
68
+
54
69
  ## The Process
55
70
 
56
71
  ### Progress checklist (copy at start, tick as you go)
@@ -92,7 +107,17 @@ Capture: `<owner>/<repo>`, head branch, base branch, PR number, PR URL. This sco
92
107
 
93
108
  ### Step 2: Create the agent team
94
109
 
95
- This session is the **team lead**. Create a team using the agent teams feature. Per the docs: *"After enabling agent teams, tell Claude to create an agent team and describe the task and the team structure you want in natural language. Claude creates the team, spawns teammates, and coordinates work based on your prompt."*
110
+ This session is the **team lead**. Create the team by calling the `TeamCreate` tool with these exact arguments:
111
+
112
+ ```
113
+ TeamCreate(
114
+ team_name="<team_name>",
115
+ description="Bugteam audit/fix loop for PR <number> (<owner>/<repo>)",
116
+ agent_type="team-lead"
117
+ )
118
+ ```
119
+
120
+ `<team_name>` is the value built below under **Team name** (sanitization + timestamp already applied). `TeamCreate` is the tool that resolves the docs' phrasing: *"tell Claude to create an agent team and describe the task and the team structure you want in natural language. Claude creates the team, spawns teammates, and coordinates work based on your prompt."*
96
121
 
97
122
  Team specification:
98
123
 
@@ -202,20 +227,39 @@ If the audit returns zero findings, the teammate still posts ONE review with `ev
202
227
 
203
228
  ### Step 3: The cycle
204
229
 
205
- Repeat until an exit condition fires:
230
+ Repeat until an exit condition fires.
206
231
 
207
- 1. Increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached`.
208
- 2. Decide the next action:
209
- - `last_action in {"fresh", "fixed"}` run **AUDIT**
210
- - `last_action == "audited"` and `last_findings.total > 0` → run **FIX**
232
+ **Ordering principle:** Mandatory **CODE_RULES** checks (`validate_content` from `hooks/blocking/code_rules_enforcer.py`) must pass on the PR-scoped file set **before** any **AUDIT** (bugfind) teammate runs. The **clean-coder** teammate clears gate failures; then the **code-quality-agent** teammate audits. This mirrors “CI green, then review,” without relying on GitHub Actions — the script is the gate.
233
+
234
+ 1. Decide the next action from `last_action` and `last_findings`:
211
235
  - `last_action == "audited"` and `last_findings.total == 0` → exit reason = `converged`
212
- - `last_action == "fixed"` and `git rev-parse HEAD` did not change since pre-FIX → exit reason = `stuck` (see FIX action for detection)
213
- 3. Execute the chosen action (see action specs below).
214
- 4. Update `last_action`, `last_findings`, and append to `audit_log`.
215
- 5. Print a one-line progress marker so the user can watch convergence:
216
- - After audit: `Loop <N> audit: <P0>P0 / <P1>P1 / <P2>P2`
217
- - After fix: `Loop <N> fix: commit <sha7> (<files_changed> files, +<add>/-<del>)`
218
- 6. Loop.
236
+ - `last_action == "fixed"` and `git rev-parse HEAD` did not change since pre-FIX → exit reason = `stuck` (see FIX action)
237
+ - `last_action in {"fresh", "fixed"}` go to **pre-audit path** (below), then **AUDIT**
238
+ - `last_action == "audited"` and `last_findings.total > 0` → go to **FIX** (below)
239
+
240
+ 2. **Pre-audit path** (only when the next step is **AUDIT**):
241
+ 1. From the repository root, run the gate script (align `--base` with the PR base branch from Step 1, e.g. `origin/main` or `origin/develop`):
242
+
243
+ ```bash
244
+ python "${CLAUDE_SKILL_DIR}/scripts/bugteam_code_rules_gate.py" --base origin/<baseRefName>
245
+ ```
246
+
247
+ Use `git merge-base` + `git diff --name-only` inside the script; see [`scripts/README.md`](scripts/README.md). The lead runs this (not a teammate).
248
+ 2. If exit code **0** → continue to step 3 (AUDIT spawn) below.
249
+ 3. If exit code **non-zero** → spawn a NEW **clean-coder** teammate — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
250
+ 4. After gate exit **0**, increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
251
+ 5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <N> audit: ...`
252
+
253
+ 3. **FIX path** (when `last_action == "audited"` and `last_findings.total > 0`):
254
+ 1. Increment `loop_count`. If `loop_count > 10`, exit reason = `cap reached`.
255
+ 2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <N> fix: commit ...`
256
+ 3. Set `last_action = "fixed"`, update `audit_log`, loop to step 1 (next iteration will hit **pre-audit path** before the next AUDIT).
257
+
258
+ 4. After **AUDIT**, update `last_action`, `last_findings`, `audit_log`; print the audit progress line if not already printed.
259
+
260
+ 5. Loop.
261
+
262
+ **Note:** The first iteration uses **pre-audit path** then **AUDIT**. After a **FIX** for audit findings, the next iteration runs **pre-audit path** again (gate → then AUDIT), so `validate_content` stays green before semantic audit.
219
263
 
220
264
  ### AUDIT action (clean-room teammate, fresh per loop)
221
265
 
@@ -228,192 +272,105 @@ gh pr diff <number> -R <owner>/<repo> > "<team_temp_dir>/loop-<N>.patch"
228
272
 
229
273
  `<team_temp_dir>` is the absolute path captured in Step 2 (already includes the sanitized team_name and timestamp suffix, and `team_name` itself is already prefixed with `bugteam-`). Claude resolves the portable temp root once via `Path(tempfile.gettempdir()) / team_name` (requires `import tempfile`) and passes the literal absolute path to every shell command. `tempfile.gettempdir()` honors `TMPDIR`, `TEMP`, and `TMP` in the platform-correct order and falls back to `C:\Users\<user>\AppData\Local\Temp` on Windows or `/tmp` on Unix, so this works identically on macOS, Linux, Windows cmd.exe, and PowerShell: Claude resolves the literal path once and every shell receives the same absolute value.
230
274
 
231
- Spawn a NEW `bugfind` teammate for this loop using the `code-quality-agent` subagent type. The teammate is fresh: no prior loop's findings, no chat history, no inherited audit context. Per the docs: *"The lead's conversation history does not carry over."* — and we further guarantee independence by spawning a new teammate per loop rather than reusing one.
232
-
233
- The teammate's spawn prompt is the full XML below — copy it verbatim with the placeholders substituted. **Keep the spawn prompt context-free.** Reference only the PR scope, audit rubric, and this loop number. Write each instruction as a standalone statement so the teammate treats the prompt as a fresh brief — every audit starts from first principles.
234
-
235
- ```xml
236
- <context>
237
- <repo>owner/repo</repo>
238
- <branch>head ref</branch>
239
- <base_branch>base ref</base_branch>
240
- <pr_url>full URL</pr_url>
241
- <loop>N</loop>
242
- </context>
243
-
244
- <scope>
245
- <diff_path>Absolute path to the loop-N patch file under team_temp_dir from Step 2 (same path as gh pr diff redirect in AUDIT)</diff_path>
246
- <scope_rule>Audit only lines added or modified in the diff. Pre-existing code on untouched lines is out of scope.</scope_rule>
247
- </scope>
248
-
249
- <bug_categories>
250
- Investigate each category explicitly. For each, return either at least
251
- one finding OR a verified-clean entry with the evidence used to clear it:
252
- A. API contract verification (signatures, return types, async/await correctness)
253
- B. Selector / query / engine compatibility
254
- C. Resource cleanup and lifecycle (file handles, connections, processes, locks)
255
- D. Variable scoping, ordering, and unbound references
256
- E. Dead code and unused imports
257
- F. Silent failures (catch-all excepts, unconditional success returns, missing error propagation)
258
- G. Off-by-one, bounds, and integer overflow
259
- H. Security boundaries (injection, path traversal, auth bypass, secret leakage)
260
- I. Concurrency hazards (race conditions, missing awaits, shared mutable state)
261
- J. Magic values and configuration drift
262
- </bug_categories>
263
-
264
- <constraints>
265
- - Read-only on source code: the audit does not modify any source file.
266
- - Cite file:line for every finding.
267
- - When the diff alone does not provide enough context to confirm a bug,
268
- list it under "Open questions" rather than assert it.
269
- </constraints>
270
-
271
- <comment_posting>
272
- 1. Audit the diff against the 10 categories above. Buffer the findings
273
- in memory; all posting happens at step 6 once anchors are validated.
274
- 2. Assign each finding a stable finding_id of exactly the form `loopN-K`
275
- where K is 1-based within this loop.
276
- 3. Validate every finding's (file, line) against the captured diff. Split
277
- findings into two buckets: anchored (line is in the diff) and
278
- unanchored (line is not in the diff — goes into the review body's
279
- "Findings without a diff anchor" section per Step 2.5).
280
- 4. Build the review body per Step 2.5's review-body shape, filling in the
281
- P0/P1/P2 counts and the unanchored-findings list (if any).
282
- 5. For each anchored finding, write its body to its own temp file:
283
-
284
- **[severity] one-line title**
285
- Category: <letter> (<category name>)
286
- <2-3 sentence description with concrete trace>
287
-
288
- _From /bugteam audit loop N._
289
-
290
- 6. Post ONE review via Step 2.5's per-loop review CLI shape. Harvest the
291
- parent review `html_url` from the response JSON and the `comments[]`
292
- child entries (each with its own `id` and `html_url`). Match child
293
- entries to anchored findings in index order.
294
- 7. If the review POST itself fails, use Step 2.5's Review POST failure
295
- fallback (single issue comment with full body and all findings inline).
296
- 8. Write every body (review body, each finding body, any fallback body)
297
- to its own temp file. Load each file into the JSON payload via jq's
298
- `--rawfile` or `-Rs`, then pipe the jq output to `gh api ... --input -`
299
- so every body reaches GitHub as file contents inside the JSON payload.
300
- </comment_posting>
301
-
302
- <output_format>
303
- Write the outcome XML below to .bugteam-loop-N.outcomes.xml in the
304
- working directory. Return only that path on stdout. The schema:
305
- </output_format>
306
- ```
307
-
308
- Outcome XML schema (bugfind writes this):
309
-
310
- ```xml
311
- <bugteam_audit loop="<N>" review_url="<url>">
312
- <finding
313
- finding_id="loop<N>-<index>"
314
- severity="P0|P1|P2"
315
- category="<letter>"
316
- file="<path>"
317
- line="<int>"
318
- finding_comment_id="<gh child comment id, or empty if unanchored/review-fallback>"
319
- finding_comment_url="<url of child comment, OR review_url if unanchored, OR fallback issue comment URL>"
320
- used_fallback="true|false"
321
- >
322
- <title>one-line title</title>
323
- <description>2-3 sentence description with concrete trace</description>
324
- </finding>
325
- <verified_clean>
326
- <category letter="<letter>" name="<name>" evidence="brief evidence + cleared conclusion"/>
327
- </verified_clean>
328
- </bugteam_audit>
329
- ```
330
-
331
- After the teammate writes the XML and returns, the lead reads `.bugteam-loop-<N>.outcomes.xml`, parses it, and populates `loop_comment_index` from `<finding>` elements. Then **shut down the bugfind teammate**: `Ask the bugfind teammate to shut down`. Per the docs: *"The lead sends a shutdown request. The teammate can approve, exiting gracefully, or reject with an explanation."* If the teammate rejects shutdown, force-shut by failing the team and starting Step 5 cleanup with exit reason = `error: bugfind teammate refused shutdown`.
275
+ Spawn a fresh `bugfind` teammate for this loop by calling the `Agent` tool with these exact arguments:
276
+
277
+ ```
278
+ Agent(
279
+ subagent_type="code-quality-agent",
280
+ name="bugfind",
281
+ team_name="<team_name>",
282
+ model="sonnet",
283
+ description="Bugfind audit loop <N>",
284
+ prompt="<audit XML from the block below, with placeholders substituted>"
285
+ )
286
+ ```
287
+
288
+ Each loop calls `Agent` again with a fresh `Agent` invocation so the teammate starts with its own context window. The docs guarantee this: *"The lead's conversation history does not carry over."* Spawning per loop keeps every audit independent.
289
+
290
+ See [`PROMPTS.md`](PROMPTS.md) for the AUDIT spawn-prompt XML and bugfind outcome schema. Substitute placeholders (repo, branch, base_branch, pr_url, loop, diff_path) and pass the result as the `prompt` argument.
291
+
292
+ After the teammate writes the XML and returns, the lead reads `.bugteam-loop-<N>.outcomes.xml` with the `Read` tool, parses it, and populates `loop_comment_index` from `<finding>` elements.
293
+
294
+ **Expected path: self-termination.** In practice, teammates self-terminate when their task is complete — the `Agent` call returns and the teammate's session ends automatically. When that happens, no `SendMessage` shutdown is needed and the cycle proceeds directly to the next action.
295
+
296
+ **Fallback path: lead-initiated shutdown.** If the teammate has not self-terminated after the `Agent` call returns (observable as the teammate still appearing in the active-teammates list), send a shutdown message:
297
+
298
+ ```
299
+ SendMessage(
300
+ to="bugfind",
301
+ message={
302
+ "type": "shutdown_request",
303
+ "reason": "audit loop <N> complete; outcome XML captured"
304
+ }
305
+ )
306
+ ```
307
+
308
+ The teammate replies with `{type: "shutdown_response", approve: true}` and exits. If `approve` comes back `false`, treat this as a fatal error: set exit reason = `error: bugfind teammate refused shutdown` and jump to Step 4 teardown followed by Step 5 revoke.
332
309
 
333
310
  `last_action = "audited"`. `last_findings = parsed`. Append `(loop=N, action="audit", counts={P0,P1,P2}, sha=current_HEAD, review_url=<url>, finding_count=<n>, fallback_count=<n>)` to `audit_log`.
334
311
 
335
- **Parallel auditors from loop 4 onward (`loop_count >= 4`).** Once the cycle has made it through three full audit/fix rounds without converging, the next audit spawns THREE bugfind teammates in parallel — named `bugfind-loop-<N>-a`, `bugfind-loop-<N>-b`, `bugfind-loop-<N>-c` — each with an identical spawn prompt (same diff path, same rubric, same loop number). `a` is the post-owner; `b` and `c` write their outcome XML to `<team_temp_dir>/loop-<N>-b.outcomes.xml` and `...-c.outcomes.xml` respectively, then shut down. `a` reads all three outcome XML files, merges findings by `(file, line, category_letter)` (same tuple collapses to one finding, keeping the longest description and the highest severity of the group), re-assigns merged-finding IDs as `loopN-K`, and posts the single per-loop review per the standard posting protocol above. The lead shuts down `b` and `c` first, then `a` after its post completes.
312
+ **Parallel auditors from loop 4 onward (`loop_count >= 4`).** The pre-audit code rules gate must still pass immediately before this step (Step 3). After three full audit/fix rounds without convergence, spawn three bugfind teammates concurrently by issuing three `Agent` calls in a single assistant message so they run in parallel:
313
+
314
+ ```
315
+ Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-a", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant a", prompt="<audit XML; write outcome to .bugteam-loop-<N>.outcomes.xml; post the per-loop review; read and merge b/c outcomes from <team_temp_dir>/loop-<N>-b.outcomes.xml and <team_temp_dir>/loop-<N>-c.outcomes.xml>")
316
+ Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-b", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant b", prompt="<audit XML; write outcome to <team_temp_dir>/loop-<N>-b.outcomes.xml; skip PR posting>")
317
+ Agent(subagent_type="code-quality-agent", name="bugfind-loop-<N>-c", team_name="<team_name>", model="sonnet", description="Bugfind audit loop <N> variant c", prompt="<audit XML; write outcome to <team_temp_dir>/loop-<N>-c.outcomes.xml; skip PR posting>")
318
+ ```
319
+
320
+ Teammate `-a` is the post-owner: it reads all three outcome XML files using their explicit absolute paths — its own outcome at `.bugteam-loop-<N>.outcomes.xml` (working directory), and the sibling outcomes at `<team_temp_dir>/loop-<N>-b.outcomes.xml` and `<team_temp_dir>/loop-<N>-c.outcomes.xml` — then merges findings by `(file, line, category_letter)` (same tuple collapses to one finding, keeping the longest description and the highest severity of the group), re-assigns merged-finding IDs as `loopN-K`, and posts the single per-loop review per the standard posting protocol above. The `-a` spawn prompt must include both sibling paths as literal absolute values so `-a` can read them with the `Read` tool by path without any discovery step.
321
+
322
+ Shut down `-b` and `-c` first with two parallel `SendMessage` calls, then shut down `-a` after its post completes:
323
+
324
+ ```
325
+ SendMessage(to="bugfind-loop-<N>-b", message={"type": "shutdown_request", "reason": "variant XML captured"})
326
+ SendMessage(to="bugfind-loop-<N>-c", message={"type": "shutdown_request", "reason": "variant XML captured"})
327
+ ```
328
+
329
+ then
330
+
331
+ ```
332
+ SendMessage(to="bugfind-loop-<N>-a", message={"type": "shutdown_request", "reason": "merged review posted"})
333
+ ```
336
334
 
337
335
  ### FIX action (fresh teammate, only sees latest audit)
338
336
 
339
- Spawn a NEW `bugfix` teammate for this loop using the `clean-coder` teammate role, model sonnet. The teammate sees ONLY the most recent audit's findings — no prior-loop findings, no prior-loop fix history, no chat history.
340
-
341
- The teammate receives the **finding comment URL and id for each finding** (from `loop_comment_index`) and **owns the reply posting**. After committing fixes, the teammate posts one reply per finding: `Fixed in <commit_sha>` for addressed findings, `Could not address this loop: <one-line reason>` for skipped or failed findings. Same one-identity model as bugfind: teammate posts, lead does not.
342
-
343
- After all replies are posted, the teammate writes its own outcome XML (see schema below), returns, and the lead **shuts down the bugfix teammate** the same way as the bugfind shutdown.
344
-
345
- Prompt skeleton:
346
-
347
- ```xml
348
- <context>
349
- <repo>owner/repo</repo>
350
- <branch>head</branch>
351
- <base_branch>base</base_branch>
352
- <pr_url>url</pr_url>
353
- <loop>N</loop>
354
- </context>
355
-
356
- <bugs_to_fix>
357
- [for each P0/P1/P2 finding from last_findings:]
358
- <bug
359
- finding_id="loop<N>-<index>"
360
- severity="P0|P1|P2"
361
- file="<path>"
362
- line="<int>"
363
- category="<letter>"
364
- finding_comment_id="<id>"
365
- finding_comment_url="<url>"
366
- >
367
- <description>...</description>
368
- </bug>
369
- </bugs_to_fix>
370
-
371
- <execution>
372
- 1. Read each referenced file before editing.
373
- 2. Apply each fix you can address.
374
- 3. Run `python -m py_compile` (or language-equivalent) on every modified file.
375
- 4. git add by explicit path, then git commit with a message summarizing the bugs fixed.
376
- - If the commit fails because a git hook (pre-commit, commit-msg, etc.) blocked it,
377
- capture the hook's stderr, write status=hook_blocked for every finding in this loop
378
- (the commit was atomic; if it failed, no finding was applied), populate hook_output
379
- on each outcome, and return WITHOUT retrying. The lead will treat this loop as no-progress.
380
- 5. git push with a plain fast-forward push (the default, no flag overrides).
381
- 6. For each bug, post a fix reply to its finding_comment_id via the
382
- Step 2.5 reply CLI shape:
383
- - "Fixed in <commit_sha>" if the bug was addressed by your commit
384
- - "Could not address this loop: <one-line reason>" if you skipped or failed it
385
- - "Hook blocked the fix commit: <one-line summary>" if the commit was hook-blocked
386
- Use the Fix reply CLI shape from Step 2.5 (`jq -Rs | gh api .../comments/<id>/replies --input -`). Write every reply body to a temp file first.
387
- 7. Write `.bugteam-loop-<N>.outcomes.xml` (schema below) and return its path.
388
- </execution>
389
-
390
- <outcome_xml_schema>
391
- <bugteam_fix loop="<N>" commit_sha="<sha or empty if no commit>">
392
- <outcome
393
- finding_id="loop<N>-<index>"
394
- status="fixed|could_not_address|hook_blocked"
395
- commit_sha="<sha if fixed, empty otherwise>"
396
- reply_comment_id="<id of the reply posted>"
397
- reply_comment_url="<url of the reply posted>"
398
- >
399
- <reason>only present when status=could_not_address; one-line reason text</reason>
400
- <hook_output>only present when status=hook_blocked; verbatim stderr from the blocked hook</hook_output>
401
- </outcome>
402
- </bugteam_fix>
403
- </outcome_xml_schema>
404
-
405
- <constraints>
406
- - Modify only files referenced in bugs_to_fix.
407
- - One commit on the existing branch, then push.
408
- - Keep the branch linear and the PR base fixed; append one new commit per
409
- loop and fast-forward push only.
410
- - Let every git hook run on every commit.
411
- - git add by explicit path — name each file being staged.
412
- - Preserve existing comments on lines you do not modify.
413
- - Type hints on every signature you touch.
414
- </constraints>
337
+ Spawn a fresh `bugfix` teammate for this loop by calling the `Agent` tool with these exact arguments:
338
+
339
+ ```
340
+ Agent(
341
+ subagent_type="clean-coder",
342
+ name="bugfix",
343
+ team_name="<team_name>",
344
+ model="sonnet",
345
+ description="Bugfix loop <N>",
346
+ prompt="<fix XML from the block below, with placeholders substituted>"
347
+ )
415
348
  ```
416
349
 
350
+ The teammate sees only the most recent audit's findings — each `Agent` call starts with a fresh context window, so prior-loop findings, prior-loop fix history, and prior chat history stay inside the lead.
351
+
352
+ Pass the **finding comment URL and id for each finding** (from `loop_comment_index`) inside the XML prompt so the teammate owns reply posting. After committing fixes, the teammate posts one reply per finding: `Fixed in <commit_sha>` for addressed findings, `Could not address this loop: <one-line reason>` for skipped or failed findings. Same one-identity model as bugfind: teammate posts, lead waits.
353
+
354
+ After all replies are posted, the teammate writes its own outcome XML (see schema below) and returns.
355
+
356
+ **Expected path: self-termination.** In practice, teammates self-terminate when their task is complete — the `Agent` call returns and the teammate's session ends automatically. When that happens, no `SendMessage` shutdown is needed and the cycle proceeds directly to the next action.
357
+
358
+ **Fallback path: lead-initiated shutdown.** If the teammate has not self-terminated after the `Agent` call returns, send a shutdown message:
359
+
360
+ ```
361
+ SendMessage(
362
+ to="bugfix",
363
+ message={
364
+ "type": "shutdown_request",
365
+ "reason": "fix loop <N> complete; commit <sha7> pushed"
366
+ }
367
+ )
368
+ ```
369
+
370
+ If the shutdown response returns `approve: false`, treat it the same as the bugfind refusal case above: exit reason = `error: bugfix teammate refused shutdown`, jump to Step 4 teardown then Step 5 revoke.
371
+
372
+ See [`PROMPTS.md`](PROMPTS.md) for the FIX spawn-prompt XML and bugfix outcome schema. Substitute placeholders (repo, branch, base_branch, pr_url, loop, and the per-finding bug entries built from `last_findings`) and pass the result as the `prompt` argument.
373
+
417
374
  Verify the fix actually committed and pushed:
418
375
 
419
376
  - `git rev-parse HEAD` after fix should differ from before
@@ -425,10 +382,33 @@ If `git rev-parse HEAD` did not change, exit reason = `stuck — bugfix teammate
425
382
 
426
383
  ### Step 4: Tear down the team and clean working tree
427
384
 
428
- When the cycle exits (any reason):
385
+ When the cycle exits (any reason), run these steps in order from THIS session (the lead):
386
+
387
+ 1. **Confirm every teammate has shut down.** Any teammate still alive (for example, from an aborted shutdown mid-loop) must receive a shutdown message first. For each remaining teammate name:
388
+
389
+ ```
390
+ SendMessage(to="<teammate_name>", message={"type": "shutdown_request", "reason": "bugteam cycle ending"})
391
+ ```
429
392
 
430
- 1. **Clean up the team as the lead.** Per the docs: *"When you're done, ask the lead to clean up: 'Clean up the team'. This removes the shared team resources. When the lead runs cleanup, it checks for active teammates and fails if any are still running, so shut them down first."* The lead is THIS session — call cleanup directly. If any teammate is still alive (e.g., from an aborted shutdown), shut it down first.
431
- 2. Delete the per-team scoped temp directory using Python: `shutil.rmtree(team_temp_dir, ignore_errors=True)` (requires `import shutil`). This works on every platform without OS-detection branching. Pass the literal absolute path Claude resolved at Step 2; Claude performs the path resolution so every shell receives the same literal value at cleanup time.
393
+ The docs state: *"When the lead runs cleanup, it checks for active teammates and fails if any are still running, so shut them down first."*
394
+
395
+ If any teammate returns `approve: false` during this cleanup shutdown, log the refusing teammate name (e.g., `cleanup warning: <teammate_name> refused shutdown_request`) and force-proceed to step 2 (`TeamDelete`) anyway. `TeamDelete` may fail if active teammates remain; if it does, surface the error in the final report with the refusing teammate name so the user can manually clean up. Do not abort the cleanup sequence — continue through temp-dir deletion, Step 4.5, and Step 5 regardless.
396
+
397
+ 2. **Clean up the team** by calling `TeamDelete` with no arguments — it reads `<team_name>` from the current session's team context:
398
+
399
+ ```
400
+ TeamDelete()
401
+ ```
402
+
403
+ The docs state: *"When you're done, ask the lead to clean up: 'Clean up the team'."* `TeamDelete` is the tool that resolves that sentence.
404
+
405
+ 3. **Delete the per-team scoped temp directory** by running this Python one-liner through the `Bash` tool (same literal `<team_temp_dir>` path resolved at Step 2):
406
+
407
+ ```
408
+ python -c "import shutil; shutil.rmtree(r'<team_temp_dir>', ignore_errors=True)"
409
+ ```
410
+
411
+ `shutil.rmtree(..., ignore_errors=True)` works identically on Windows and Unix, so the lead uses one command regardless of platform.
432
412
 
433
413
  ### Step 4.5: Finalize the PR description (mandatory)
434
414
 
@@ -436,7 +416,27 @@ After teardown and before permission revoke, the lead rewrites the PR body to re
436
416
 
437
417
  The lead delegates the body authoring to the `pr-description-writer` agent so the global mandatory-pr-description-writer hook accepts the subsequent `gh pr edit`. The lead does NOT compose the body inline.
438
418
 
439
- `pr-description-writer` is provided by the global git-workflow rule in `claude-code-config` (as the `pr-description-writer` agent type). If that agent is not available in the current environment, fall back to spawning a `general-purpose` agent with the same brief — the global hook treats agent-authored bodies the same regardless of the specific agent type. If neither agent is available, log a warning in the final report and skip Step 4.5; the original PR body remains.
419
+ `pr-description-writer` is provided by the global git-workflow rule in `claude-code-config`. Invoke it with the `Agent` tool:
420
+
421
+ ```
422
+ Agent(
423
+ subagent_type="pr-description-writer",
424
+ description="Rewrite PR <number> body from cumulative diff",
425
+ prompt="<brief from step 3 below>"
426
+ )
427
+ ```
428
+
429
+ If `pr-description-writer` is not in the available agents list for the current environment, fall back to `general-purpose` with the same brief — the global hook treats agent-authored bodies the same regardless of the specific agent type:
430
+
431
+ ```
432
+ Agent(
433
+ subagent_type="general-purpose",
434
+ description="Rewrite PR <number> body from cumulative diff",
435
+ prompt="<brief from step 3 below>"
436
+ )
437
+ ```
438
+
439
+ When neither agent is available, log a warning in the final report and skip Step 4.5 so the original PR body stays in place.
440
440
 
441
441
  Steps:
442
442
 
@@ -484,99 +484,8 @@ If exit = `cap reached`, name the remaining bug count and recommend `/findbugs`
484
484
 
485
485
  ## Constraints
486
486
 
487
- - **Agent teams required, not parallel subagents.** The skill MUST use Claude Code's agent teams feature (`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`). Spawning `code-quality-agent` and `clean-coder` as parallel subagents from the lead's context = fail; the clean-room property requires independent teammate sessions.
488
- - **Grant before any spawn, revoke before any return.** Step 0 grants project `.claude/**` permissions; Step 5 revokes. Both are mandatory. Revoke runs on every exit path including error, cap-reached, and stuck.
489
- - **Fresh teammate per loop.** Both bugfind and bugfix are spawned new each loop and shut down after their action. Reusing a teammate across loops accumulates context inside that teammate's window — defeats clean-room.
490
- - **One up-front confirmation = whole cycle.** The `/bugteam` invocation authorizes the entire cycle; every subsequent decision runs on that single authorization.
491
- - **10-loop hard cap.** Counted as audits performed. Worst case = 10 audits + 10 fixes = 20 teammate spawns + 20 shutdowns.
492
- - **Clean-room audits, every loop.** Each bugfind teammate's spawn prompt contains only the PR scope, audit rubric, and the current loop number. Prior loop history stays in the lead.
493
- - **Targeted fixes.** Each fix teammate sees ONLY the most recent audit's findings. Prior loops are invisible to the fix teammate.
494
- - **Sonnet for both teammates.** Predictable cost, fits-purpose for code work.
495
- - **Fix teammate receives the latest audit as its input contract.** Passing the audit's findings to the fix teammate is the input contract — each loop's fix run operates on the current audit's output and only that.
496
- - **One commit per fix action.** Loops produce one commit per loop, not one per bug.
497
- - **Linear branch, fixed PR base.** Every loop appends one forward-only commit; existing commits and the PR base stay intact throughout the cycle.
498
- - **Lead-only cleanup.** Per the docs: *"Always use the lead to clean up. Teammates should not run cleanup because their team context may not resolve correctly, potentially leaving resources in an inconsistent state."* This session is the lead, and cleanup runs here only.
499
- - **Cleanup the per-team scoped temp directory on exit.** The resolved `<team_temp_dir>` (absolute literal captured in Step 2) is deleted entirely so no loop patches leak between runs.
500
- - **Cleanup all `.bugteam-*` files on exit.** `.bugteam-loop-*.patch`, `.bugteam-loop-*.outcomes.xml`, `.bugteam-final.diff`, `.bugteam-original-body.md`, `.bugteam-final-body.md`. Working directory ends clean.
501
- - **Teammates own audit/fix comment posting.** Bugfind posts ONE per-loop review (parent body + child finding comments in a single batched POST, with review-fallback to a top-level issue comment). Bugfix posts the fix replies after committing. All comment, review, and reply POSTs belong to the teammates; the lead's single PR-write action is the final description rewrite at Step 4.5.
502
- - **Lead owns the final PR description rewrite only** (Step 4.5), and only via the `pr-description-writer` agent. The lead does not compose the description inline.
503
- - **One review per loop, findings as child comments of that review.** Each loop posts a single pull-request review whose body is the loop header and whose `comments[]` are the anchored findings. Each loop's review stands alone — one review created per loop, fully self-contained on the PR conversation.
504
- - **PR description rewrite on every exit.** Step 4.5 runs on `converged`, `cap reached`, and `stuck`. On `error`, the rewrite is best-effort; if it fails, surface the error in the final report and continue to revoke.
505
- - **Outcome XML, not JSON.** Both teammates write structured outcome data (findings or fix outcomes) to `.bugteam-loop-<N>.outcomes.xml`. The lead reads these files between actions. XML chosen for parser robustness against multi-line, special-character, and quoted reason fields.
487
+ See [`CONSTRAINTS.md`](CONSTRAINTS.md).
506
488
 
507
489
  ## Examples
508
490
 
509
- <example>
510
- User: `/bugteam`
511
- Claude: [resolves PR #42, runs loop]
512
-
513
- `Loop 1 audit: 1P0 / 2P1 / 0P2`
514
- `Loop 1 fix: commit a1b2c3d (3 files, +18/-7)`
515
- `Loop 2 audit: 0P0 / 1P1 / 0P2`
516
- `Loop 2 fix: commit e4f5g6h (1 file, +5/-2)`
517
- `Loop 3 audit: 0P0 / 0P1 / 0P2 → converged`
518
-
519
- `/bugteam exit: converged`
520
- `Loops: 3`
521
- `Starting commit: 9d8c7b6`
522
- `Final commit: e4f5g6h`
523
- `Net change: 4 files, +23/-9`
524
- </example>
525
-
526
- <example>
527
- User: `/bugteam`
528
- Claude: [runs 10 loops without convergence]
529
-
530
- `Loop 10 audit: 0P0 / 1P1 / 2P2`
531
-
532
- `/bugteam exit: cap reached`
533
- `Loops: 10`
534
- `Remaining: 0P0 / 1P1 / 2P2 — run /findbugs for human triage`
535
- </example>
536
-
537
- <example>
538
- User: `/bugteam`
539
- Claude: [loop 4 fix produces no commit]
540
-
541
- `Loop 4 fix: clean-coder reported no changes (could not address remaining bugs)`
542
- `/bugteam exit: stuck`
543
- `Unresolved findings (3): src/cache.py:88 (P0 race condition); ...`
544
- </example>
545
-
546
- <example>
547
- User: `/bugteam` (mixed-outcome path: some findings fixed, others skipped)
548
- Claude: [resolves PR #99, runs loop with partial-fix outcomes]
549
-
550
- `Loop 1 audit: 1P0 / 3P1 / 0P2`
551
- `Loop 1 fix: commit a1b2c3d (2 files, +8/-3) — 2 fixed, 2 could_not_address`
552
- `Loop 2 audit: 0P0 / 2P1 / 0P2`
553
- `Loop 2 fix: 0 fixed, 2 could_not_address (no commit)`
554
-
555
- `/bugteam exit: stuck`
556
- `Loops: 2`
557
- `Unresolved findings (2): src/auth.py:45 (P1: file is generated, cannot edit); src/legacy.py:200 (P1: rewrite scope exceeds the bug)`
558
-
559
- The bugfix teammate writes one outcome per finding to `.bugteam-loop-2.outcomes.xml`. Findings with `status=could_not_address` carry their `<reason>` text, and the teammate posts a matching reply to each finding comment so the reviewer sees why each bug stayed open.
560
- </example>
561
-
562
- <example>
563
- User: `/bugteam` (no PR or upstream diff)
564
- Claude: `No PR or upstream diff. /bugteam needs a target.`
565
- </example>
566
-
567
- <example>
568
- User: `/bugteam` (uncommitted changes in working tree)
569
- Claude: `Uncommitted changes detected. Stash, commit, or revert before /bugteam.`
570
- </example>
571
-
572
- ## Why this design
573
-
574
- The three sibling skills compose, but `/bugteam` solves a problem they cannot solve in sequence:
575
-
576
- - `/findbugs` audits once and stops.
577
- - `/fixbugs` fixes the findings of one audit and stops.
578
- - A human-driven `/findbugs` → `/fixbugs` → `/findbugs` → `/fixbugs` cycle works but requires the user to drive it.
579
-
580
- `/bugteam` automates that cycle. The clean-room property is preserved by spawning a fresh audit agent each loop with no inherited context — every audit is independent of the prior loop's verdict. The 10-loop cap is the safety: pathological cases (audit agent oscillating, fix agent regressing) cannot run away.
581
-
582
- The single up-front confirmation is the explicit trade — `/bugteam` is more autonomous than `/findbugs`+`/fixbugs` chained manually. The user accepts that autonomy by typing the command. Stop conditions and the loop log give the user full visibility on exit.
491
+ See [`EXAMPLES.md`](EXAMPLES.md).