claude-dev-env 1.36.0 → 1.36.1

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.
@@ -3,50 +3,111 @@ name: bugteam
3
3
  description: >-
4
4
  Open pull request audit–fix until convergence: CODE_RULES gate, clean-room
5
5
  audit (`code-quality-agent`, opus) and fix (`clean-coder`, opus), per-loop
6
- GitHub reviews, 10-audit cap; grant then revoke `.claude/**`. **Path A**
7
- when `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (orchestrated teams, `TeamCreate`).
8
- **Path B** otherwise (Task harness — workflow in `reference/workflow-path-b-task-harness.md`).
9
- **This `SKILL.md` holds only shared steps**; per-path harness lives in `reference/workflow-path-*.md`.
10
- Triggers: '/bugteam', 'run the bug team', 'auto-fix the PR until clean', 'loop audit and fix'.
6
+ GitHub reviews, 10-audit cap; grant then revoke `.claude/**`. **Path A** when
7
+ `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (orchestrated teams, `TeamCreate`).
8
+ **Path B** otherwise (Task harness — workflow in
9
+ `reference/workflow-path-b-task-harness.md`). **This `SKILL.md` holds only
10
+ shared steps**; per-path harness lives in `reference/workflow-path-*.md`.
11
+ Triggers: '/bugteam', 'run the bug team', 'auto-fix the PR until clean', 'loop
12
+ audit and fix'.
11
13
  ---
12
14
 
13
15
  # Bugteam
14
16
 
15
- **Core principle:** Audit–fix until convergence. **Bugfind:** `code-quality-agent`, fresh context each loop. **Bugfix:** `clean-coder`. Hard cap: 10 audit loops. Grant `.claude/**` at start, revoke always at end.
17
+ **Core principle:** Audit–fix until convergence. **Bugfind:**
18
+ `code-quality-agent`, fresh context each loop. **Bugfix:** `clean-coder`. Hard
19
+ cap: 10 audit loops. Grant `.claude/**` at start, revoke always at end.
16
20
 
17
- **Path routing** picks **Path A** (orchestrated teams) vs **Path B** (Task harness). Harness execution — `TeamCreate`, `Agent`/`Task` spawns, `SendMessage`, `TeamDelete`, who runs Step 2.5 `gh api` — lives only in [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) and [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md). Verbatim doc quotes and URLs: [`sources.md`](sources.md).
21
+ **Path routing** picks **Path A** (orchestrated teams) vs **Path B** (Task
22
+ harness). Harness execution — `TeamCreate`, `Agent`/`Task` spawns,
23
+ `SendMessage`, `TeamDelete`, who runs Step 2.5 `gh api` — lives only in
24
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] and
25
+ [`reference/workflow-path-b-task-harness.md`][path-b]. Verbatim doc quotes and
26
+ URLs: [`sources.md`](sources.md).
18
27
 
19
28
  ## Path routing (mandatory first branch)
20
29
 
21
- At `/bugteam` entry, evaluate **once** (same rule as pr-converge §Team infrastructure detection):
30
+ At `/bugteam` entry, evaluate **once** (same rule as pr-converge §Team
31
+ infrastructure detection):
22
32
 
23
- - **Path A** — `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` set and equals **`1`** after trim → load and follow [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) for every harness step (with this `SKILL.md` for shared material).
24
- - **Path B** — otherwise → load and follow [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) for every harness step (with this `SKILL.md` for shared material).
33
+ - **Path A** — `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` set and equals **`1`**
34
+ after trim → load and follow
35
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] for every harness
36
+ step (with this `SKILL.md` for shared material).
37
+ - **Path B** — otherwise → load and follow
38
+ [`reference/workflow-path-b-task-harness.md`][path-b] for every harness step
39
+ (with this `SKILL.md` for shared material).
25
40
 
26
- Shared material is **everything else in this file** plus [`PROMPTS.md`](PROMPTS.md), [`EXAMPLES.md`](EXAMPLES.md), [`CONSTRAINTS.md`](CONSTRAINTS.md) — agent types, models, XML, gates, cycle state machine, Step 2.5 payload shapes, shared teardown `rmtree`, revoke, final report.
41
+ Shared material is **everything else in this file** plus
42
+ [`PROMPTS.md`](PROMPTS.md), [`EXAMPLES.md`](EXAMPLES.md),
43
+ [`CONSTRAINTS.md`](CONSTRAINTS.md) — agent types, models, XML, gates, cycle
44
+ state machine, Step 2.5 payload shapes, shared teardown `rmtree`, revoke, final
45
+ report.
27
46
 
28
47
  ## Team lifecycle (Path A only)
29
48
 
30
- The `TeamCreate` / `TeamDelete` pair has historically been bound to a single `/bugteam` invocation. That coupling fails when an orchestrator (`pr-converge` multi-PR mode, `monitor-open-prs`) needs to call `/bugteam` repeatedly inside one parent session: only one team can be led at a time, and a missed Step 4 leaks the team. To decouple, every Path A invocation reads `BUGTEAM_TEAM_LIFECYCLE` (defaults to `auto`) and may also read `BUGTEAM_TEAM_NAME`.
31
-
32
- | Mode | Step 2 behavior | Step 4 behavior | Use case |
33
- | --- | --- | --- | --- |
34
- | `owned` | `TeamCreate(<computed_team_name>)`. If the runtime returns `Already leading team "<existing>". A leader can only manage one team at a time.` → **error**: `Already leading team <existing>; rerun with BUGTEAM_TEAM_LIFECYCLE=attach BUGTEAM_TEAM_NAME=<existing>`. | `TeamDelete()` (lead-owned). | Pre-decoupling behavior. Use only when you know the session leads no other team. |
35
- | `attach` | Require `BUGTEAM_TEAM_NAME`. Treat that team as already-led; do **not** call `TeamCreate`. | **Skip** `TeamDelete` — the orchestrator owns teardown. | Orchestrators (pr-converge multi-PR, monitor-open-prs) that explicitly created a team and will tear it down themselves. |
36
- | `auto` (**default: `auto`**) | Try `TeamCreate(<computed_team_name>)`. On `Already leading team "<existing>"` → parse `<existing>`, attach (do **not** call `TeamCreate` again), set `team_owned=false`. On success → set `team_owned=true`. | If `team_owned=true` → `TeamDelete()`. Else → **skip** `TeamDelete`. | All callers when in doubt. Solo invocations behave like `owned`; nested or repeated invocations attach safely. |
37
-
38
- **`team_owned` flag** — set in Step 2 by all three modes (`owned` always `true`; `attach` always `false`; `auto` reflects the `TeamCreate` outcome). Read in Step 4 to decide whether to call `TeamDelete`. The same flag also gates `<team_temp_dir>` `rmtree`: when `team_owned=false`, only the per-PR subfolders this invocation created (`<team_temp_dir>/pr-<N>/`) are removed; the orchestrator's parent directory survives.
39
-
40
- **Path B note:** Path B does not use `TeamCreate` / `TeamDelete`, so `BUGTEAM_TEAM_LIFECYCLE` is read but only its `team_temp_dir` cleanup behavior applies. `team_owned` is treated as `true` by default in Path B; orchestrators driving Path B that share a temp directory should set `BUGTEAM_TEAM_LIFECYCLE=attach` so the per-PR subfolder cleanup rule applies.
49
+ The `TeamCreate` / `TeamDelete` pair has historically been bound to a single
50
+ `/bugteam` invocation. That coupling fails when an orchestrator (`pr-converge`
51
+ multi-PR mode, `monitor-open-prs`) needs to call `/bugteam` repeatedly inside
52
+ one parent session: only one team can be led at a time, and a missed Step 4
53
+ leaks the team. To decouple, every Path A invocation reads
54
+ `BUGTEAM_TEAM_LIFECYCLE` (defaults to `auto`) and may also read
55
+ `BUGTEAM_TEAM_NAME`.
56
+
57
+ **`owned`**
58
+
59
+ - **Step 2:** `TeamCreate(<computed_team_name>)`. If the runtime returns
60
+ `Already leading team "<existing>". A leader can only manage one team at a
61
+ time.` → **error**: `Already leading team <existing>; rerun with
62
+ BUGTEAM_TEAM_LIFECYCLE=attach BUGTEAM_TEAM_NAME=<existing>`.
63
+ - **Step 4:** `TeamDelete()` (lead-owned).
64
+ - **Use case:** Pre-decoupling behavior. Use only when you know the session
65
+ leads no other team.
66
+
67
+ **`attach`**
68
+
69
+ - **Step 2:** Require `BUGTEAM_TEAM_NAME`. Treat that team as already-led; do
70
+ **not** call `TeamCreate`.
71
+ - **Step 4:** **Skip** `TeamDelete` — the orchestrator owns teardown.
72
+ - **Use case:** Orchestrators (pr-converge multi-PR, monitor-open-prs) that
73
+ explicitly created a team and will tear it down themselves.
74
+
75
+ ### `auto` (**default: `auto`**)
76
+
77
+ - **Step 2:** Try `TeamCreate(<computed_team_name>)`. On `Already leading team
78
+ "<existing>"` → parse `<existing>`, attach (do **not** call `TeamCreate`
79
+ again), set `team_owned=false`. On success → set `team_owned=true`.
80
+ - **Step 4:** If `team_owned=true` → `TeamDelete()`. Else → **skip**
81
+ `TeamDelete`.
82
+ - **Use case:** All callers when in doubt. Solo invocations behave like `owned`;
83
+ nested or repeated invocations attach safely.
84
+
85
+ **`team_owned` flag** — set in Step 2 by all three modes
86
+ (`owned` always `true`; `attach` always `false`; `auto` reflects the
87
+ `TeamCreate` outcome). Read in Step
88
+ 4 to decide whether to call `TeamDelete`. The same flag also gates
89
+ `<team_temp_dir>` `rmtree`: when `team_owned=false`, only the per-PR subfolders
90
+ this invocation created (`<team_temp_dir>/pr-<N>/`) are removed; the
91
+ orchestrator's parent directory survives.
92
+
93
+ **Path B note:** Path B does not use `TeamCreate` / `TeamDelete`, so
94
+ `BUGTEAM_TEAM_LIFECYCLE` is read but only its `team_temp_dir` cleanup behavior
95
+ applies. `team_owned` is treated as `true` by default in Path B; orchestrators
96
+ driving Path B that share a temp directory should set
97
+ `BUGTEAM_TEAM_LIFECYCLE=attach` so the per-PR subfolder cleanup rule applies.
41
98
 
42
99
  ## Contents
43
100
 
44
- Orchestration lives here; companion files hold prompts, invariants, examples, citations, and domain reference notes. Scan this list before a partial read.
101
+ Orchestration lives here; companion files hold prompts, invariants, examples,
102
+ citations, and domain reference notes. Scan this list before a partial read.
45
103
 
46
104
  - [Path routing](#path-routing-mandatory-first-branch) — Path A vs Path B
47
- - [Team lifecycle](#team-lifecycle-path-a-only) — `owned` / `attach` / `auto` modes; orchestrator-owned teams
48
- - [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) — Path A harness (orchestrated teams)
49
- - [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) — Path B harness (Task harness)
105
+ - [Team lifecycle](#team-lifecycle-path-a-only) — `owned` / `attach` / `auto`
106
+ modes; orchestrator-owned teams
107
+ - [`reference/workflow-path-a-orchestrated-teams.md`][path-a] — Path A harness
108
+ (orchestrated teams)
109
+ - [`reference/workflow-path-b-task-harness.md`][path-b] — Path B harness (Task
110
+ harness)
50
111
  - When this skill applies — refusal cases and trigger conditions
51
112
  - Utility scripts — pre-flight (`scripts/`, executed not inlined)
52
113
  - Pre-audit gate — `validate_content` before each AUDIT
@@ -64,7 +125,8 @@ Orchestration lives here; companion files hold prompts, invariants, examples, ci
64
125
  - [`EXAMPLES.md`](EXAMPLES.md) — exit scenarios
65
126
  - [`CONSTRAINTS.md`](CONSTRAINTS.md) — invariants and design rationale
66
127
  - [`sources.md`](sources.md) — doc URLs and verbatim quotes
67
- - [`reference/README.md`](reference/README.md) — expanded prose by topic (design, team setup, GitHub reviews, cycle, teardown)
128
+ - [`reference/README.md`](reference/README.md) — expanded prose by topic
129
+ (design, team setup, GitHub reviews, cycle, teardown)
68
130
 
69
131
  ## When this skill applies
70
132
 
@@ -73,13 +135,24 @@ Orchestration lives here; companion files hold prompts, invariants, examples, ci
73
135
  Refusals — first match wins; respond with the quoted line exactly and stop:
74
136
 
75
137
  - **No PR or upstream diff.** `No PR or upstream diff. /bugteam needs a target.`
76
- - **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before /bugteam.`
77
- - **Missing subagents.** Before Step 0, confirm `code-quality-agent` and `clean-coder` exist. Else: `Required subagent type <name> not installed. /bugteam needs both code-quality-agent and clean-coder available.`
78
- - **Lead role must be held by the orchestrator.** Run /bugteam in the session that received the user's command. **Path A:** lead calls `TeamCreate` per [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md); runtime may return `Already leading team "<name>". A leader can only manage one team at a time.` **Path B:** lead runs the Task harness per [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md); no `TeamCreate`.
138
+ - **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before
139
+ /bugteam.`
140
+ - **Missing subagents.** Before Step 0, confirm `code-quality-agent` and
141
+ `clean-coder` exist. Else: `Required subagent type <name> not installed.
142
+ /bugteam needs both code-quality-agent and clean-coder available.`
143
+ - **Lead role must be held by the orchestrator.** Run /bugteam in the session
144
+ that received the user's command. **Path A:** lead calls `TeamCreate` per
145
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a]; runtime may
146
+ return `Already leading team "<name>". A leader can only manage one team at a
147
+ time.` **Path B:** lead runs the Task harness per
148
+ [`reference/workflow-path-b-task-harness.md`][path-b]; no `TeamCreate`.
79
149
 
80
150
  ## Utility scripts
81
151
 
82
- Shell-heavy steps live under [`_shared/pr-loop/scripts/`](../../_shared/pr-loop/scripts/) (run, do not paste into context). Utility scripts are **executed**, not loaded as primary context ([`sources.md`](sources.md) § Progressive disclosure and utility scripts).
152
+ Shell-heavy steps live under
153
+ [`_shared/pr-loop/scripts/`](../../_shared/pr-loop/scripts/) (run, do not paste
154
+ into context). Utility scripts are **executed**, not loaded as primary context
155
+ ([`sources.md`](sources.md) § Progressive disclosure and utility scripts).
83
156
 
84
157
  ### Pre-flight (before Step 0)
85
158
 
@@ -87,15 +160,27 @@ Shell-heavy steps live under [`_shared/pr-loop/scripts/`](../../_shared/pr-loop/
87
160
  python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/preflight.py"
88
161
  ```
89
162
 
90
- Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only. `--pre-commit` if `.pre-commit-config.yaml` exists.
163
+ Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only.
164
+ `--pre-commit` if `.pre-commit-config.yaml` exists.
91
165
 
92
- **Auto-remediation for `core.hooksPath`:** when preflight fails with stderr containing `core.hooksPath` (the message starts with `bugteam_preflight: core.hooksPath is`, or `Git-side CODE_RULES enforcement is not active`), Claude must auto-invoke the fix script — do not fall through to `AskUserQuestion`, do not punt to the user, do not ask for confirmation:
166
+ **Auto-remediation for `core.hooksPath`:** when preflight fails with stderr
167
+ containing `core.hooksPath` (the message starts with `bugteam_preflight:
168
+ core.hooksPath is`, or `Git-side CODE_RULES enforcement is not active`), Claude
169
+ must auto-invoke the fix script — do not fall through to `AskUserQuestion`, do
170
+ not punt to the user, do not ask for confirmation:
93
171
 
94
172
  ```bash
95
173
  python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/fix_hookspath.py"
96
174
  ```
97
175
 
98
- The fix script removes any non-canonical local-scope override on the active repository, sets the global `core.hooksPath` to `~/.claude/hooks/git-hooks` if missing or wrong, and re-runs `preflight.py`. Its exit code becomes the preflight outcome. Exit 0 → continue to Step 0. Non-zero only when the canonical hooks directory is missing (run `npx claude-dev-env .` first) or `git config --global` writes are blocked. Other preflight failures (pytest, pre-commit) still require manual fixes — the auto-remediation only applies to the `core.hooksPath` failure mode.
176
+ The fix script removes any non-canonical local-scope override on the active
177
+ repository, sets the global `core.hooksPath` to `~/.claude/hooks/git-hooks` if
178
+ missing or wrong, and re-runs `preflight.py`. Its exit code becomes the
179
+ preflight outcome. Exit 0 → continue to Step 0. Non-zero only when the
180
+ canonical hooks directory is missing (run `npx claude-dev-env .` first) or
181
+ `git config --global` writes are blocked. Other preflight failures (pytest,
182
+ pre-commit) still require manual fixes —
183
+ the auto-remediation only applies to the `core.hooksPath` failure mode.
99
184
 
100
185
  ## The Process
101
186
 
@@ -115,14 +200,22 @@ The fix script removes any non-canonical local-scope override on the active repo
115
200
  ### Step 0: Grant project permissions (once, first)
116
201
 
117
202
  ```bash
118
- python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/grant_project_claude_permissions.py"
203
+ python
204
+ "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/grant_project_claude_permis \
205
+ sions.py"
119
206
  ```
120
207
 
121
- `${CLAUDE_SKILL_DIR}` is host-substituted before the shell runs (unlike normal env expansion). Idempotent writes to `~/.claude/settings.json` from repo root. Non-zero → stop. Revoke in Step 5 on every exit path.
208
+ `${CLAUDE_SKILL_DIR}` is host-substituted before the shell runs (unlike normal
209
+ env expansion). Idempotent writes to `~/.claude/settings.json` from repo root.
210
+ Non-zero → stop. Revoke in Step 5 on every exit path.
122
211
 
123
212
  ### Step 1: Resolve PR scope (once)
124
213
 
125
- Accept one or more PR numbers from the invocation. For each PR, run `gh pr view --json number,baseRefName,headRefName,url` (falling back to the merge-base diff path when no PR exists). Capture `all_prs = [{number, owner, repo, baseRef, headRef, url}, ...]`. A single-PR invocation produces a one-element list and follows the same downstream rules.
214
+ Accept one or more PR numbers from the invocation. For each PR, run `gh pr view
215
+ --json number,baseRefName,headRefName,url` (falling back to the merge-base diff
216
+ path when no PR exists). Capture `all_prs = [{number, owner, repo, baseRef,
217
+ headRef, url}, ...]`. A single-PR invocation produces a one-element list and
218
+ follows the same downstream rules.
126
219
 
127
220
  Keep: owner/repo, branches, PR number, URL — for all loops.
128
221
 
@@ -134,13 +227,29 @@ For each PR in all_prs:
134
227
  2. Run `git worktree add "<team_temp_dir>/pr-<N>/worktree" origin/<headRef>`.
135
228
  3. Record the absolute worktree path alongside the PR's other fields.
136
229
 
137
- Teammates or Task workers for a PR operate inside that PR's worktree. Step 4 teardown runs `git worktree remove "<team_temp_dir>/pr-<N>/worktree"` for each PR, then path-specific harness teardown per [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) or [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § Step 4.
230
+ Teammates or Task workers for a PR operate inside that PR's worktree. Step 4
231
+ teardown runs `git worktree remove "<team_temp_dir>/pr-<N>/worktree"` for each
232
+ PR, then path-specific harness teardown per
233
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] or
234
+ [`reference/workflow-path-b-task-harness.md`][path-b] § Step 4.
138
235
 
139
236
  ### Step 2: Path harness + loop state
140
237
 
141
- Apply the path you chose in [Path routing](#path-routing-mandatory-first-branch): **Path A** — [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) § Step 2 (`TeamCreate`, team name, `team_temp_dir`, roles, optional Groq FIX, `--bugbot-retrigger`). **Path B** — [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § Step 2 (no `TeamCreate` / `TeamDelete`; same worktrees and variables).
142
-
143
- Path A also resolves the team lifecycle here per [Team lifecycle](#team-lifecycle-path-a-only): pick the mode (`owned` / `attach` / `auto`) from `BUGTEAM_TEAM_LIFECYCLE`, set `team_name` (computed for `owned`/`auto` create paths; required `BUGTEAM_TEAM_NAME` for `attach` and `auto`'s attach branch), and set `team_owned` (`true` when `TeamCreate` succeeded in this invocation; `false` when attaching to an existing team). Step 4 reads `team_owned` to decide whether to call `TeamDelete`.
238
+ Apply the path you chose in [Path
239
+ routing](#path-routing-mandatory-first-branch): **Path A** —
240
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 2
241
+ (`TeamCreate`, team name, `team_temp_dir`, roles, optional Groq FIX,
242
+ `--bugbot-retrigger`). **Path B** —
243
+ [`reference/workflow-path-b-task-harness.md`][path-b] § Step 2 (no `TeamCreate`
244
+ / `TeamDelete`; same worktrees and variables).
245
+
246
+ Path A also resolves the team lifecycle here per [Team
247
+ lifecycle](#team-lifecycle-path-a-only): pick the mode (`owned` / `attach` /
248
+ `auto`) from `BUGTEAM_TEAM_LIFECYCLE`, set `team_name` (computed for
249
+ `owned`/`auto` create paths; required `BUGTEAM_TEAM_NAME` for `attach` and
250
+ `auto`'s attach branch), and set `team_owned` (`true` when `TeamCreate`
251
+ succeeded in this invocation; `false` when attaching to an existing team). Step
252
+ 4 reads `team_owned` to decide whether to call `TeamDelete`.
144
253
 
145
254
  **Loop state (lead; not a single script):**
146
255
 
@@ -152,47 +261,63 @@ audit_log=""
152
261
  starting_sha="$(git rev-parse HEAD)"
153
262
  team_name="bugteam-pr-<number>-<YYYYMMDDHHMMSS>"
154
263
  team_temp_dir="<absolute-path>/<team_name>"
155
- team_owned="true" # set by Step 2 lifecycle resolution; see Team lifecycle table
264
+ team_owned="true" # set by Step 2 lifecycle resolution; see Team lifecycle table
156
265
  loop_comment_index=""
157
266
  ```
158
267
 
159
- **`loop_comment_index`:** reset each AUDIT start; filled during AUDIT; FIX consumes for replies; cleared after FIX. Entries: `{loop, finding_id, finding_comment_id, finding_comment_url, used_fallback, fix_status}`.
268
+ **`loop_comment_index`:** reset each AUDIT start; filled during AUDIT; FIX
269
+ consumes for replies; cleared after FIX. Entries: `{loop, finding_id,
270
+ finding_comment_id, finding_comment_url, used_fallback, fix_status}`.
160
271
 
161
272
  ### Step 2.5: PR comments (one review per loop)
162
273
 
163
- **Who posts:** Path A vs Path B — [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) § Step 2.5 and [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § Step 2.5. Payloads and endpoints below are identical for both paths.
274
+ **Who posts:** Path A vs Path B —
275
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 2.5 and
276
+ [`reference/workflow-path-b-task-harness.md`][path-b] § Step 2.5. Payloads and
277
+ endpoints below are identical for both paths.
164
278
 
165
- Order: audit → buffer → validate anchors vs diff → single review POST. Review body states counts; zero findings → still one review, `comments: []`, body `## /bugteam loop <N> audit: 0P0 / 0P1 / 0P2 → clean`.
279
+ Order: audit → buffer → validate anchors vs diff → single review POST.
280
+ Review body states counts; zero findings → still one review, `comments: []`,
281
+ body `## /bugteam loop <N> audit: 0P0 / 0P1 / 0P2 → clean`.
166
282
 
167
- **Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ... --input -` (avoids shell-quoting; satisfies `gh-body-backtick-guard`). Write each markdown body to a temp file first.
283
+ **Payloads:** build JSON with `jq --rawfile` / `-Rs`, pipe to `gh api ...
284
+ --input -` (avoids shell-quoting; satisfies `gh-body-backtick-guard`). Write
285
+ each markdown body to a temp file first.
168
286
 
169
- **Review POST** (one `comments[]` object per anchored finding; single-line `{path, line, side: "RIGHT", body}`; multi-line add `start_line`, `start_side: "RIGHT"`):
287
+ **Review POST** (one `comments[]` object per anchored finding; single-line
288
+ `{path, line, side: "RIGHT", body}`; multi-line add `start_line`, `start_side:
289
+ "RIGHT"`):
170
290
 
171
291
  ```
172
292
  jq -n \
173
- --rawfile review_body <tmp_review_body.md> \
174
- --arg commit_id "$(git rev-parse HEAD)" \
175
- --rawfile finding_body_1 <tmp_finding_1.md> \
176
- --arg path_1 "<file_1>" \
177
- --argjson line_1 <line_1> \
178
- [... one finding_body_K / path_K / line_K triple per finding ...] \
179
- '{
180
- commit_id: $commit_id,
181
- event: "COMMENT",
182
- body: $review_body,
183
- comments: [
184
- {path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
185
- [, ... ]
186
- ]
187
- }' \
293
+ --rawfile review_body <tmp_review_body.md> \
294
+ --arg commit_id "$(git rev-parse HEAD)" \
295
+ --rawfile finding_body_1 <tmp_finding_1.md> \
296
+ --arg path_1 "<file_1>" \
297
+ --argjson line_1 <line_1> \
298
+ [... one finding_body_K / path_K / line_K triple per finding ...] \
299
+ '{
300
+ commit_id: $commit_id,
301
+ event: "COMMENT",
302
+ body: $review_body,
303
+ comments: [
304
+ {path: $path_1, line: $line_1, side: "RIGHT", body: $finding_body_1}
305
+ [, ... ]
306
+ ]
307
+ }' \
188
308
  | gh api repos/<owner>/<repo>/pulls/<number>/reviews -X POST --input -
189
309
  ```
190
310
 
191
- **Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X POST --input -`
311
+ **Fix reply:** `jq -Rs '{body: .}' <tmp_reply.md | gh api
312
+ repos/<owner>/<repo>/pulls/<number>/comments/<finding_comment_id>/replies -X
313
+ POST --input -`
192
314
 
193
- **Review POST fails:** issue comment fallback: `jq -Rs '{body: .}' <tmp_fallback.md | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST --input -`
315
+ **Review POST fails:** issue comment fallback: `jq -Rs '{body: .}'
316
+ <tmp_fallback.md | gh api repos/<owner>/<repo>/issues/<number>/comments -X POST
317
+ --input -`
194
318
 
195
- `<head_sha_at_post_time>`: `git rev-parse HEAD` in teammate cwd immediately before POST.
319
+ `<head_sha_at_post_time>`: `git rev-parse HEAD` in teammate cwd immediately
320
+ before POST.
196
321
 
197
322
  **Review body template (`<tmp_review_body.md>`):**
198
323
 
@@ -204,55 +329,105 @@ jq -n \
204
329
  - **[severity] title** — <file>:<line> — <one-line description>
205
330
  ```
206
331
 
207
- **Anchor fallback:** lines not in diff → omit from `comments[]`, list under `### Findings without a diff anchor`; outcome `used_fallback="true"`, empty `finding_comment_id`, `finding_comment_url` = parent review URL.
332
+ **Anchor fallback:** lines not in diff → omit from `comments[]`, list under
333
+ `### Findings without a diff anchor`; outcome `used_fallback="true"`, empty
334
+ `finding_comment_id`, `finding_comment_url` = parent review URL.
208
335
 
209
- **POST failure fallback:** one issue comment with full text; all findings `used_fallback="true"`, URLs = issue comment.
336
+ **POST failure fallback:** one issue comment with full text; all findings
337
+ `used_fallback="true"`, URLs = issue comment.
210
338
 
211
- **Endpoints:** `POST .../pulls/{pull}/reviews`; `POST .../pulls/{pull}/comments/{id}/replies`; fallback `POST .../issues/{issue}/comments` (`issue` = PR number).
339
+ **Endpoints:** `POST .../pulls/{pull}/reviews`; `POST
340
+ .../pulls/{pull}/comments/{id}/replies`; fallback `POST
341
+ .../issues/{issue}/comments` (`issue` = PR number).
212
342
 
213
343
  ### Step 3: The cycle
214
344
 
215
- Run the AUDIT-FIX cycle for each PR in all_prs, reusing the same team across PRs. The 10-loop cap applies per PR. Exit reasons (converged, cap reached, stuck, error) are tracked per PR; the final report lists one outcome line per PR.
345
+ Run the AUDIT-FIX cycle for each PR in all_prs, reusing the same team across
346
+ PRs. The 10-loop cap applies per PR. Exit reasons (converged, cap reached,
347
+ stuck, error) are tracked per PR; the final report lists one outcome line per
348
+ PR.
216
349
 
217
- **Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on PR-scoped files before every AUDIT (`_shared/pr-loop/scripts/code_rules_gate.py`). Lead runs gate; clean-coder clears failures; then bugfind audits.
350
+ **Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on
351
+ PR-scoped files before every AUDIT
352
+ (`_shared/pr-loop/scripts/code_rules_gate.py`). Lead runs gate; clean-coder
353
+ clears failures; then bugfind audits.
218
354
 
219
- **Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2 and before iteration begins, when `last_action == "fresh"`). A re-invocation of `/bugteam` on a PR with prior loops detects whether the most recent loop already cleaned this HEAD (short-circuit) and otherwise records that prior loops were dirty so the AUDIT runs against the latest diff with that signal in mind:
355
+ **Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2
356
+ and before iteration begins, when `last_action == "fresh"`). A re-invocation of
357
+ `/bugteam` on a PR with prior loops detects whether the most recent loop already
358
+ cleaned this HEAD (short-circuit) and otherwise records that prior loops were
359
+ dirty so the AUDIT runs against the latest diff with that signal in mind:
220
360
 
221
361
  ```bash
222
362
  dirty_review_count=0
223
363
  gh api "repos/<owner>/<repo>/pulls/<number>/reviews" \
224
- --jq '[.[] | select(.body | startswith("## /bugteam loop "))] | sort_by(.submitted_at) | reverse'
364
+ --jq '[.[] | select(.body | startswith("## /bugteam loop "))] |
365
+ sort_by(.submitted_at) | reverse'
225
366
  ```
226
367
 
227
368
  Iterate from index 0 (most recent) toward older entries:
228
369
 
229
- - A bugteam review body that ends with `→ clean` is **clean**; any other `## /bugteam loop ...` body is **dirty**.
230
- - For a dirty review, increment `dirty_review_count` by one. The review's specific finding bodies are not carried forward — bugteam's AUDIT regenerates findings against the current HEAD's diff each loop, so prior bodies are stale by definition. The count alone is the carried signal.
231
- - Stop at the first clean review. Older reviews are presumed addressed at that clean checkpoint and are not re-read.
232
- - When index 0 is itself clean AND its `commit_id` matches `git rev-parse HEAD`, the PR is already converged on this HEAD set `last_action="audited"`, `last_findings='{"total": 0}'`, fall through to step 1's `converged` exit, skip Step 3 iteration entirely.
233
- - When `dirty_review_count > 0`, log the count and proceed into the normal iteration; the next AUDIT regenerates anchored findings against the current HEAD so `loop_comment_index` stays correct. Unlike `pr-converge` — where Cursor Bugbot's prior dirty-review *bodies* are read back by the Fix protocol because each dirty body lists specific findings the loop must still address — bugteam's per-loop bodies are anchored to the diff at *that loop's* HEAD, so re-applying them against a newer diff would be incorrect. The count is sufficient signal that "prior loops did not converge here."
370
+ - A bugteam review body that ends with `→ clean` is **clean**; any other `##
371
+ /bugteam loop ...` body is **dirty**.
372
+ - For a dirty review, increment `dirty_review_count` by one. The review's
373
+ specific finding bodies are not carried forward
374
+ bugteam's AUDIT regenerates
375
+ findings against the current HEAD's diff each loop, so prior bodies are stale
376
+ by definition. The count alone is the carried signal.
377
+ - Stop at the first clean review. Older reviews are presumed addressed at that
378
+ clean checkpoint and are not re-read.
379
+ - When index 0 is itself clean AND its `commit_id` matches `git rev-parse HEAD`,
380
+ the PR is already converged on this HEAD — set `last_action="audited"`,
381
+ `last_findings='{"total": 0}'`, fall through to step 1's `converged` exit,
382
+ skip Step 3 iteration entirely.
383
+ - When `dirty_review_count > 0`, log the count and proceed into the normal
384
+ iteration; the next AUDIT regenerates anchored findings against the current
385
+ HEAD so `loop_comment_index` stays correct. Unlike `pr-converge` — where
386
+ Cursor Bugbot's prior dirty-review *bodies* are read back by the Fix protocol
387
+ because each dirty body lists specific findings the loop must still address
388
+
389
+ bugteam's per-loop bodies are anchored to the diff at *that loop's* HEAD, so
390
+ re-applying them against a newer diff would be incorrect. The count is
391
+ sufficient signal that "prior loops did not converge here."
234
392
 
235
393
  1. From `last_action` / `last_findings`:
236
- - `last_action == "audited"` and `last_findings.total == 0` → exit `converged`
237
- - `last_action == "fixed"` and `git rev-parse HEAD` unchanged since pre-FIX → exit `stuck`
394
+ - `last_action == "audited"` and `last_findings.total == 0` → exit
395
+ `converged`
396
+ - `last_action == "fixed"` and `git rev-parse HEAD` unchanged since
397
+ pre-FIX → exit `stuck`
238
398
  - `last_action in {"fresh", "fixed"}` → **pre-audit** then **AUDIT**
239
399
  - `last_action == "audited"` and `last_findings.total > 0` → **FIX**
240
400
 
241
401
  2. **Pre-audit** (only when the next step is AUDIT):
242
402
 
243
403
  ```bash
244
- python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py" --base origin/<baseRefName>
404
+ python \
405
+ "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py" \
406
+ --base origin/<baseRefName>
245
407
  ```
246
408
 
247
- Lead only; merge-base / diff semantics: [`../../_shared/pr-loop/code-rules-gate.md`](../../_shared/pr-loop/code-rules-gate.md); shared script inventory: [`../../_shared/pr-loop/scripts/README.md`](../../_shared/pr-loop/scripts/README.md). Non-zero → spawn **clean-coder** standards-fix (read stderr, edit, re-run **this same** command, one commit, `git push`, shutdown) until exit **0** or **5** failed gate rounds → `error: code rules gate failed pre-audit`. After **0**: `loop_count += 1`; if `loop_count > 10` → `cap reached`. Then **AUDIT** (bugfind); print `Loop <N> audit: ...`.
409
+ Lead only; merge-base / diff semantics:
410
+ [`../../_shared/pr-loop/code-rules-gate.md`][path-code-rules]; shared script
411
+ inventory: [`../../_shared/pr-loop/scripts/README.md`][path-scripts-readme].
412
+ Non-zero → spawn **clean-coder** standards-fix (read stderr, edit, re-run
413
+ **this same** command, one commit, `git push`, shutdown) until exit **0** or
414
+ **5**
415
+ failed gate rounds → `error: code rules gate failed pre-audit`. After **0**:
416
+ `loop_count += 1`; if `loop_count > 10` → `cap reached`. Then **AUDIT**
417
+ (bugfind); print `Loop <N> audit: ...`.
248
418
 
249
- 3. **FIX** (`last_action == "audited"` and `last_findings.total > 0`): `loop_count += 1`; if `loop_count > 10` → `cap reached`; **FIX** (bugfix); print `Loop <N> fix: ...`; `last_action = "fixed"`, update `audit_log`; loop to step 1.
419
+ 3. **FIX** (`last_action == "audited"` and `last_findings.total > 0`):
420
+ `loop_count += 1`; if `loop_count > 10` → `cap reached`; **FIX** (bugfix);
421
+ print `Loop <N> fix: ...`; `last_action = "fixed"`, update `audit_log`; loop
422
+ to step 1.
250
423
 
251
- 4. After **AUDIT**: update `last_action`, `last_findings`, `audit_log`; print audit line if not already printed.
424
+ 4. After **AUDIT**: update `last_action`, `last_findings`, `audit_log`; print
425
+ audit line if not already printed.
252
426
 
253
427
  5. Loop.
254
428
 
255
- First pass: pre-audit → AUDIT. After a FIX, the next pass runs pre-audit again before the next AUDIT.
429
+ First pass: pre-audit → AUDIT. After a FIX, the next pass runs pre-audit again
430
+ before the next AUDIT.
256
431
 
257
432
  ### AUDIT action
258
433
 
@@ -261,54 +436,95 @@ mkdir -p "<team_temp_dir>/pr-<N>"
261
436
  gh pr diff <N> -R <owner>/<repo> > "<team_temp_dir>/pr-<N>/loop-<L>.patch"
262
437
  ```
263
438
 
264
- **Spawn and shutdown:** Path A — [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) § AUDIT. Path B — [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § AUDIT. Same `prompt="<audit XML; see PROMPTS.md>"` and outcome files.
439
+ **Spawn and shutdown:** Path A —
440
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] § AUDIT. Path B —
441
+ [`reference/workflow-path-b-task-harness.md`][path-b] § AUDIT. Same
442
+ `prompt="<audit XML; see PROMPTS.md>"` and outcome files.
265
443
 
266
- Fresh spawn each loop; Path A teammate context excludes lead history ([`sources.md`](sources.md) § Teammate context isolation). Path B: fresh Task per loop for the same clean-room intent. [`PROMPTS.md`](PROMPTS.md): XML + outcome schema. Lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml`, fills `loop_comment_index`.
444
+ Fresh spawn each loop; Path A teammate context excludes lead history
445
+ ([`sources.md`](sources.md) § Teammate context isolation). Path B: fresh Task
446
+ per loop for the same clean-room intent. [`PROMPTS.md`](PROMPTS.md): XML +
447
+ outcome schema. Lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml`, fills
448
+ `loop_comment_index`.
267
449
 
268
450
  `last_action = "audited"`; append audit line to `audit_log`.
269
451
 
270
- **Parallel auditors (`loop_count >= 4`):** gate passes immediately before; after three full audit/fix rounds without convergence, issue three spawns in one assistant message (parallel): Path A — three `Agent` calls; Path B — three `Task` calls — full rules in the workflow files § parallel auditors. `-a` posts the review and merges outcomes from `-b`/`-c` (read `.bugteam-pr<N>-loop<L>.outcomes.xml` plus `<team_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml` and `...-c...`); merge key `(file, line, category_letter)`; re-id `loopN-K`. `-b`/`-c` write sibling XML only; prompts must pass literal absolute sibling paths. Shutdown order: Path A workflow § parallel auditors; Path B: await all three Tasks.
452
+ **Parallel auditors (`loop_count >= 4`):** gate passes immediately before;
453
+ after three full audit/fix rounds without convergence, issue three spawns in
454
+ one assistant message (parallel): Path A — three `Agent` calls; Path B —
455
+ three `Task` calls — full rules in the workflow files § parallel auditors.
456
+ `-a` posts
457
+ the review and merges outcomes from `-b`/`-c` (read
458
+ `.bugteam-pr<N>-loop<L>.outcomes.xml` plus
459
+ `<team_temp_dir>/pr-<N>/loop-<L>-b.outcomes.xml` and `...-c...`); merge key
460
+ `(file, line, category_letter)`; re-id `loopN-K`. `-b`/`-c` write sibling XML
461
+ only; prompts must pass literal absolute sibling paths. Shutdown order: Path A
462
+ workflow § parallel auditors; Path B: await all three Tasks.
271
463
 
272
464
  ### FIX action
273
465
 
274
- **Spawn and shutdown:** Path A — [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) § FIX. Path B — [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § FIX.
466
+ **Spawn and shutdown:** Path A —
467
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] § FIX. Path B —
468
+ [`reference/workflow-path-b-task-harness.md`][path-b] § FIX.
275
469
 
276
- Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed in <sha>` or `Could not address this loop: <reason>`.
470
+ Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed
471
+ in <sha>` or `Could not address this loop: <reason>`.
277
472
 
278
- [`PROMPTS.md`](PROMPTS.md): fix XML + schema. Verify: `git rev-parse HEAD` advanced; `git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`. Unchanged HEAD → `stuck — bugfix teammate could not address findings`.
473
+ [`PROMPTS.md`](PROMPTS.md): fix XML + schema. Verify: `git rev-parse HEAD`
474
+ advanced; `git fetch origin <branch> && git rev-parse origin/<branch>` matches
475
+ `HEAD`. Unchanged HEAD →
476
+ `stuck — bugfix teammate could not address findings`.
279
477
 
280
478
  ### Step 4: Teardown
281
479
 
282
- 1. For each PR in `all_prs`: `git worktree remove "<team_temp_dir>/pr-<N>/worktree"` (from Step 1) before tearing down the team harness — tolerate already-removed worktrees.
480
+ 1. For each PR in `all_prs`: `git worktree remove
481
+ "<team_temp_dir>/pr-<N>/worktree"` (from Step 1) before tearing down the team
482
+ harness — tolerate already-removed worktrees.
283
483
 
284
- 2. Path-specific harness — [`reference/workflow-path-a-orchestrated-teams.md`](reference/workflow-path-a-orchestrated-teams.md) § Step 4 (teammate `SendMessage`, `TeamDelete` **only when `team_owned=true`**) or [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md) § Step 4 (omit those).
484
+ 2. Path-specific harness —
485
+ [`reference/workflow-path-a-orchestrated-teams.md`][path-a] § Step 4
486
+ (teammate `SendMessage`, `TeamDelete` **only when `team_owned=true`**) or
487
+ [`reference/workflow-path-b-task-harness.md`][path-b] § Step 4 (omit those).
285
488
 
286
- 3. **Windows-safe `rmtree` — gated by `team_owned` from [Team lifecycle](#team-lifecycle-path-a-only).** The Windows-safe handler strips the Windows ReadOnly attribute and retries the failing syscall (see `~/.claude/rules/windows-filesystem-safe.md`).
489
+ 3. **Windows-safe `rmtree` — gated by `team_owned` from [Team
490
+ lifecycle](#team-lifecycle-path-a-only).** The Windows-safe handler strips
491
+ the Windows ReadOnly attribute and retries the failing syscall (see
492
+ `~/.claude/rules/windows-filesystem-safe.md`).
287
493
 
288
494
  - `team_owned=true` → remove the full `<team_temp_dir>`:
289
495
 
290
496
  ```bash
291
- python -c "import os, shutil, stat, sys; \
292
- h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
293
- shutil.rmtree(r'<team_temp_dir>', **({'onexc': h} if sys.version_info >= (3, 12) else {'onerror': h}))"
497
+ python -c "import os, shutil, stat, sys; \
498
+ h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
499
+ shutil.rmtree(r'<team_temp_dir>', **({'onexc': h} if sys.version_info >= (3, 12)
500
+ else {'onerror': h}))"
294
501
  ```
295
502
 
296
- - `team_owned=false` (attach mode) → for each PR in `all_prs`, remove only that PR's `<team_temp_dir>/pr-<N>/` subfolder. The orchestrator-owned parent `<team_temp_dir>` survives so the next attached invocation can write its own per-PR subfolders without colliding.
503
+ - `team_owned=false` (attach mode) → for each PR in `all_prs`, remove only
504
+ that PR's `<team_temp_dir>/pr-<N>/` subfolder. The orchestrator-owned
505
+ parent `<team_temp_dir>` survives so the next attached invocation can write
506
+ its own per-PR subfolders without colliding.
297
507
 
298
508
  ```bash
299
- python -c "import os, shutil, stat, sys; \
300
- h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
301
- shutil.rmtree(r'<team_temp_dir>/pr-<N>', **({'onexc': h} if sys.version_info >= (3, 12) else {'onerror': h}))"
509
+ python -c "import os, shutil, stat, sys; \
510
+ h = lambda f, p, *_: (os.chmod(p, stat.S_IWRITE), f(p)); \
511
+ shutil.rmtree(r'<team_temp_dir>/pr-<N>', **({'onexc': h} if sys.version_info >=
512
+ (3, 12) else {'onerror': h}))"
302
513
  ```
303
514
 
304
515
  ### Step 4.5: PR description
305
516
 
306
- Lead only; cumulative product narrative (not process). Delegate body to `pr-description-writer` via `Agent` (else `general-purpose`) so the mandatory-pr-description hook accepts `gh pr edit`.
517
+ Lead only; cumulative product narrative (not process). Delegate body to
518
+ `pr-description-writer` via `Agent` (else `general-purpose`) so the
519
+ mandatory-pr-description hook accepts `gh pr edit`.
307
520
 
308
521
  1. `gh pr diff <number> -R <owner>/<repo> > .bugteam-final.diff`
309
- 2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body > .bugteam-original-body.md`
310
- 3. Agent brief: paths + branch names; describe merge-ready change from diff; keep curated original sections intact; return markdown body.
311
- 4. Write `.bugteam-final-body.md`; `gh pr edit <number> -R <owner>/<repo> --body-file .bugteam-final-body.md`
522
+ 2. `gh pr view <number> -R <owner>/<repo> --json body --jq .body >
523
+ .bugteam-original-body.md`
524
+ 3. Agent brief: paths + branch names; describe merge-ready change from diff;
525
+ keep curated original sections intact; return markdown body.
526
+ 4. Write `.bugteam-final-body.md`; `gh pr edit <number> -R <owner>/<repo>
527
+ --body-file .bugteam-final-body.md`
312
528
  5. Delete the three temp files.
313
529
 
314
530
  On failure: log in final report; continue to Step 5.
@@ -316,7 +532,9 @@ On failure: log in final report; continue to Step 5.
316
532
  ### Step 5: Revoke permissions (always)
317
533
 
318
534
  ```bash
319
- python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/revoke_project_claude_permissions.py"
535
+ python
536
+ "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/revoke_project_claude_permi \
537
+ ssions.py"
320
538
  ```
321
539
 
322
540
  Removes Step 0 grant — run even if Step 4 partially failed (log separately).
@@ -331,11 +549,12 @@ Final commit: <current_HEAD_sha7>
331
549
  Net change: <total_files> files, +<total_add>/-<total_del>
332
550
 
333
551
  Loop log:
334
- 1 audit: 3P0 2P1 0P2
335
- ...
552
+ 1 audit: 3P0 2P1 0P2
553
+ ...
336
554
  ```
337
555
 
338
- `cap reached` → suggest `/findbugs`. `stuck` → which findings. `error` → detail + loop.
556
+ `cap reached` → suggest `/findbugs`. `stuck` → which findings. `error` →
557
+ detail + loop.
339
558
 
340
559
  ## Constraints
341
560
 
@@ -352,3 +571,8 @@ See [`reference/README.md`](reference/README.md).
352
571
  ## Sources
353
572
 
354
573
  See [`sources.md`](sources.md).
574
+
575
+ [path-a]: reference/workflow-path-a-orchestrated-teams.md
576
+ [path-b]: reference/workflow-path-b-task-harness.md
577
+ [path-code-rules]: ../../_shared/pr-loop/code-rules-gate.md
578
+ [path-scripts-readme]: ../../_shared/pr-loop/scripts/README.md