claude-dev-env 1.35.0 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/clean-coder.md +109 -1
- package/bin/install.mjs +28 -8
- package/bin/install.test.mjs +9 -1
- package/docs/CODE_RULES.md +3 -0
- package/docs/agents-md-alignment-plan.md +123 -0
- package/hooks/blocking/code_rules_enforcer.py +451 -39
- package/hooks/blocking/es_exe_path_rewriter.py +10 -4
- package/hooks/blocking/test_code_rules_enforcer.py +182 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_identifier.py +106 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +173 -0
- package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +191 -0
- package/hooks/blocking/test_code_rules_enforcer_constant_equality.py +40 -0
- package/hooks/blocking/test_code_rules_enforcer_hardcoded_user_path.py +291 -0
- package/hooks/blocking/test_code_rules_enforcer_loop_variable_naming.py +87 -3
- package/hooks/blocking/test_code_rules_enforcer_naming_pattern.py +49 -0
- package/hooks/blocking/test_code_rules_enforcer_sys_path_insert.py +157 -0
- package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +244 -0
- package/hooks/blocking/test_es_exe_path_rewriter.py +81 -3
- package/hooks/blocking/test_windows_rmtree_blocker.py +120 -8
- package/hooks/blocking/windows_rmtree_blocker.py +23 -6
- package/hooks/config/banned_identifiers_constants.py +24 -0
- package/hooks/config/hardcoded_user_path_constants.py +12 -0
- package/hooks/config/hook_log_extractor_constants.py +1 -1
- package/hooks/config/pre_tool_use_stdin.py +48 -0
- package/hooks/config/setup_project_paths_constants.py +4 -0
- package/hooks/config/stuttering_check_config.py +14 -0
- package/hooks/config/stuttering_import_binding_constants.py +11 -0
- package/hooks/config/sys_path_insert_constants.py +4 -0
- package/hooks/config/test_banned_identifiers_constants.py +48 -0
- package/hooks/config/test_hardcoded_user_path_constants.py +78 -0
- package/hooks/config/test_hook_log_extractor_constants.py +3 -3
- package/hooks/config/test_pre_tool_use_stdin.py +80 -0
- package/hooks/config/unused_module_import_constants.py +7 -0
- package/hooks/config/windows_rmtree_blocker_constants.py +3 -0
- package/hooks/diagnostic/hook_log_stop_wrapper.py +7 -4
- package/hooks/git-hooks/config.py +3 -3
- package/hooks/git-hooks/test_gate_utils.py +10 -10
- package/hooks/mypy.ini +2 -0
- package/package.json +1 -1
- package/rules/gh-paginate.md +125 -0
- package/skills/bugteam/CONSTRAINTS.md +12 -6
- package/skills/bugteam/SKILL.md +77 -91
- package/skills/bugteam/SKILL_EVALS.md +25 -23
- package/skills/bugteam/reference/README.md +2 -0
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/teardown-publish-permissions.md +1 -1
- package/skills/bugteam/reference/workflow-path-a-orchestrated-teams.md +113 -0
- package/skills/bugteam/reference/workflow-path-b-task-harness.md +48 -0
- package/skills/bugteam/test_skill_additions.py +13 -4
- package/skills/bugteam/test_team_lifecycle.py +94 -0
- package/skills/findbugs/SKILL.md +3 -3
- package/skills/fixbugs/SKILL.md +4 -4
- package/skills/monitor-open-prs/SKILL.md +32 -2
- package/skills/monitor-open-prs/test_team_lifecycle.py +46 -0
- package/skills/pr-converge/SKILL.md +562 -97
- package/skills/pr-converge/scripts/README.md +145 -0
- package/skills/pr-converge/scripts/caller-window-pid.ps1 +86 -0
- package/skills/pr-converge/scripts/check_pr_mergeability.py +79 -0
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +65 -0
- package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +176 -0
- package/skills/pr-converge/scripts/cursor-agents-continue-caller.cmd +9 -0
- package/skills/pr-converge/scripts/cursor-agents-continue-stop-others.ps1 +16 -0
- package/skills/pr-converge/scripts/cursor-agents-continue.ahk +172 -0
- package/skills/pr-converge/scripts/cursor-agents-continue.cmd +2 -0
- package/skills/pr-converge/scripts/evict_cached_config_modules.py +20 -0
- package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +110 -0
- package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +103 -0
- package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +112 -0
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +121 -0
- package/skills/pr-converge/scripts/mark_pr_ready.py +54 -0
- package/skills/pr-converge/scripts/open_followup_copilot_pr.py +136 -0
- package/skills/pr-converge/scripts/post-bugbot-run.helpers.ps1 +49 -0
- package/skills/pr-converge/scripts/post-bugbot-run.ps1 +33 -0
- package/skills/pr-converge/scripts/reply_to_inline_comment.py +84 -0
- package/skills/pr-converge/scripts/request_copilot_review.py +71 -0
- package/skills/pr-converge/scripts/resolve_pr_head.py +58 -0
- package/skills/pr-converge/scripts/review_field_helpers.py +43 -0
- package/skills/pr-converge/scripts/test_check_pr_mergeability.py +126 -0
- package/skills/pr-converge/scripts/test_evict_cached_config_modules.py +22 -0
- package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +342 -0
- package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +220 -0
- package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +372 -0
- package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +280 -0
- package/skills/pr-converge/scripts/test_mark_pr_ready.py +69 -0
- package/skills/pr-converge/scripts/test_open_followup_copilot_pr.py +236 -0
- package/skills/pr-converge/scripts/test_post_bugbot_run.py +195 -0
- package/skills/pr-converge/scripts/test_reply_to_inline_comment.py +159 -0
- package/skills/pr-converge/scripts/test_request_copilot_review.py +101 -0
- package/skills/pr-converge/scripts/test_resolve_pr_head.py +79 -0
- package/skills/pr-converge/scripts/test_review_field_helpers.py +80 -0
- package/skills/pr-converge/scripts/test_trigger_bugbot.py +139 -0
- package/skills/pr-converge/scripts/test_view_pr_context.py +111 -0
- package/skills/pr-converge/scripts/trigger_bugbot.py +77 -0
- package/skills/pr-converge/scripts/view_pr_context.py +47 -0
- package/skills/pr-converge/test_team_lifecycle.py +47 -0
- package/skills/pr-converge/workflows/ahk-auto-continue-loop.md +108 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +37 -0
- package/skills/qbug/SKILL.md +4 -4
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +2 -2
- package/skills/resume-review/SKILL.md +261 -0
- package/skills/bugteam/scripts/README.md +0 -58
- package/skills/bugteam/scripts/_claude_permissions_common.py +0 -219
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +0 -633
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +0 -260
- package/skills/bugteam/scripts/bugteam_preflight.py +0 -201
- package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +0 -17
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -109
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -135
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +0 -271
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +0 -267
- package/skills/bugteam/scripts/test_bugteam_preflight.py +0 -189
- package/skills/bugteam/scripts/test_claude_permissions_common.py +0 -44
- /package/skills/{bugteam → pr-converge}/scripts/config/__init__.py +0 -0
package/skills/bugteam/SKILL.md
CHANGED
|
@@ -1,34 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bugteam
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. Triggers: '/bugteam',
|
|
12
|
-
'run the bug team', 'auto-fix the PR until clean', 'loop audit and fix'.
|
|
4
|
+
Open pull request audit–fix until convergence: CODE_RULES gate, clean-room
|
|
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'.
|
|
13
11
|
---
|
|
14
12
|
|
|
15
13
|
# Bugteam
|
|
16
14
|
|
|
17
|
-
**Core principle:**
|
|
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.
|
|
18
16
|
|
|
19
|
-
|
|
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).
|
|
18
|
+
|
|
19
|
+
## Path routing (mandatory first branch)
|
|
20
|
+
|
|
21
|
+
At `/bugteam` entry, evaluate **once** (same rule as pr-converge §Team infrastructure detection):
|
|
22
|
+
|
|
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).
|
|
25
|
+
|
|
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.
|
|
27
|
+
|
|
28
|
+
## Team lifecycle (Path A only)
|
|
29
|
+
|
|
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.
|
|
20
41
|
|
|
21
42
|
## Contents
|
|
22
43
|
|
|
23
44
|
Orchestration lives here; companion files hold prompts, invariants, examples, citations, and domain reference notes. Scan this list before a partial read.
|
|
24
45
|
|
|
25
|
-
-
|
|
46
|
+
- [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)
|
|
50
|
+
- When this skill applies — refusal cases and trigger conditions
|
|
26
51
|
- Utility scripts — pre-flight (`scripts/`, executed not inlined)
|
|
27
52
|
- Pre-audit gate — `validate_content` before each AUDIT
|
|
28
53
|
- The Process — checklist + Steps 0–6
|
|
29
54
|
- Step 0 — Grant project permissions
|
|
30
55
|
- Step 1 — Resolve PR scope
|
|
31
|
-
- Step 2 —
|
|
56
|
+
- Step 2 — Path harness + loop state
|
|
32
57
|
- Step 2.5 — PR comment lifecycle (per-loop review + fix replies)
|
|
33
58
|
- Step 3 — Cycle (AUDIT ↔ FIX, exits)
|
|
34
59
|
- Step 4 — Teardown + clean tree
|
|
@@ -47,20 +72,19 @@ Orchestration lives here; companion files hold prompts, invariants, examples, ci
|
|
|
47
72
|
|
|
48
73
|
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
49
74
|
|
|
50
|
-
- **Agent teams not enabled.** Check `claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and `~/.claude/settings.json`. If neither is `"1"`: `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.`
|
|
51
75
|
- **No PR or upstream diff.** `No PR or upstream diff. /bugteam needs a target.`
|
|
52
76
|
- **Dirty tree.** `Uncommitted changes detected. Stash, commit, or revert before /bugteam.`
|
|
53
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.`
|
|
54
|
-
- **Lead role must be held by the orchestrator.** Run /bugteam in the session that received the user's command.
|
|
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`.
|
|
55
79
|
|
|
56
80
|
## Utility scripts
|
|
57
81
|
|
|
58
|
-
Shell-heavy steps live under `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).
|
|
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).
|
|
59
83
|
|
|
60
84
|
### Pre-flight (before Step 0)
|
|
61
85
|
|
|
62
86
|
```bash
|
|
63
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
87
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/preflight.py"
|
|
64
88
|
```
|
|
65
89
|
|
|
66
90
|
Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only. `--pre-commit` if `.pre-commit-config.yaml` exists.
|
|
@@ -68,10 +92,10 @@ Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only. `--pre
|
|
|
68
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:
|
|
69
93
|
|
|
70
94
|
```bash
|
|
71
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
95
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/fix_hookspath.py"
|
|
72
96
|
```
|
|
73
97
|
|
|
74
|
-
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 `
|
|
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.
|
|
75
99
|
|
|
76
100
|
## The Process
|
|
77
101
|
|
|
@@ -80,7 +104,7 @@ The fix script removes any non-canonical local-scope override on the active repo
|
|
|
80
104
|
```
|
|
81
105
|
[ ] Step 0: project permissions granted
|
|
82
106
|
[ ] Step 1: PR scope resolved
|
|
83
|
-
[ ] Step 2:
|
|
107
|
+
[ ] Step 2: loop state set + path harness applied
|
|
84
108
|
[ ] Step 3: cycle complete (converged | cap reached | stuck | error)
|
|
85
109
|
[ ] Step 4: team torn down + working tree clean
|
|
86
110
|
[ ] Step 4.5: PR description rewritten (or skip warning logged)
|
|
@@ -91,7 +115,7 @@ The fix script removes any non-canonical local-scope override on the active repo
|
|
|
91
115
|
### Step 0: Grant project permissions (once, first)
|
|
92
116
|
|
|
93
117
|
```bash
|
|
94
|
-
python "${CLAUDE_SKILL_DIR}/scripts/grant_project_claude_permissions.py"
|
|
118
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/grant_project_claude_permissions.py"
|
|
95
119
|
```
|
|
96
120
|
|
|
97
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.
|
|
@@ -110,31 +134,13 @@ For each PR in all_prs:
|
|
|
110
134
|
2. Run `git worktree add "<team_temp_dir>/pr-<N>/worktree" origin/<headRef>`.
|
|
111
135
|
3. Record the absolute worktree path alongside the PR's other fields.
|
|
112
136
|
|
|
113
|
-
Teammates
|
|
114
|
-
|
|
115
|
-
### Step 2: Create the agent team
|
|
116
|
-
|
|
117
|
-
**This session is the lead.** The orchestrator calls `TeamCreate` directly:
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
TeamCreate(
|
|
121
|
-
team_name="<team_name>",
|
|
122
|
-
description="Bugteam audit/fix loop for PR <number> (<owner>/<repo>)",
|
|
123
|
-
agent_type="team-lead"
|
|
124
|
-
)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
**Team name:** For a single-PR invocation use `bugteam-pr-<number>-<YYYYMMDDHHMMSS>`. For a multi-PR invocation use `bugteam-<YYYYMMDDHHMMSS>`. The timestamp is captured once at team-creation time. Apply the no-PR fallback (`bugteam-<sanitized-head>-<YYYYMMDDHHMMSS>`) only when no PR resolves at all. `TeamCreate` implements natural-language team creation ([`sources.md`](sources.md) § Team creation in natural language).
|
|
128
|
-
|
|
129
|
-
**Sanitize head branch (no-PR only):** replace characters outside `[A-Za-z0-9._-]` with `-` (e.g. `feat/foo*bar` → `feat-foo-bar`). Apply once; reuse everywhere below.
|
|
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.
|
|
130
138
|
|
|
131
|
-
|
|
139
|
+
### Step 2: Path harness + loop state
|
|
132
140
|
|
|
133
|
-
|
|
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).
|
|
134
142
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
**`--bugbot-retrigger` flag:** when present on the `/bugteam` invocation, after every successful FIX push in Step 3, post an additional `bugbot run` issue comment via the Step 2.5 issue-comments fallback endpoint (`POST .../issues/{issue}/comments`) to re-trigger Cursor's bugbot on the new commit. Omit when the flag is absent.
|
|
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`.
|
|
138
144
|
|
|
139
145
|
**Loop state (lead; not a single script):**
|
|
140
146
|
|
|
@@ -146,6 +152,7 @@ audit_log=""
|
|
|
146
152
|
starting_sha="$(git rev-parse HEAD)"
|
|
147
153
|
team_name="bugteam-pr-<number>-<YYYYMMDDHHMMSS>"
|
|
148
154
|
team_temp_dir="<absolute-path>/<team_name>"
|
|
155
|
+
team_owned="true" # set by Step 2 lifecycle resolution; see Team lifecycle table
|
|
149
156
|
loop_comment_index=""
|
|
150
157
|
```
|
|
151
158
|
|
|
@@ -153,7 +160,7 @@ loop_comment_index=""
|
|
|
153
160
|
|
|
154
161
|
### Step 2.5: PR comments (one review per loop)
|
|
155
162
|
|
|
156
|
-
|
|
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.
|
|
157
164
|
|
|
158
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`.
|
|
159
166
|
|
|
@@ -207,7 +214,7 @@ jq -n \
|
|
|
207
214
|
|
|
208
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.
|
|
209
216
|
|
|
210
|
-
**Gate:** `validate_content` / `hooks/blocking/code_rules_enforcer.py` on PR-scoped files before every AUDIT (`
|
|
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.
|
|
211
218
|
|
|
212
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:
|
|
213
220
|
|
|
@@ -234,10 +241,10 @@ Iterate from index 0 (most recent) toward older entries:
|
|
|
234
241
|
2. **Pre-audit** (only when the next step is AUDIT):
|
|
235
242
|
|
|
236
243
|
```bash
|
|
237
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
244
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py" --base origin/<baseRefName>
|
|
238
245
|
```
|
|
239
246
|
|
|
240
|
-
Lead only; merge-base / diff
|
|
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: ...`.
|
|
241
248
|
|
|
242
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.
|
|
243
250
|
|
|
@@ -254,66 +261,45 @@ mkdir -p "<team_temp_dir>/pr-<N>"
|
|
|
254
261
|
gh pr diff <N> -R <owner>/<repo> > "<team_temp_dir>/pr-<N>/loop-<L>.patch"
|
|
255
262
|
```
|
|
256
263
|
|
|
257
|
-
|
|
258
|
-
Agent(
|
|
259
|
-
subagent_type="code-quality-agent",
|
|
260
|
-
name="bugfind-pr<N>-loop<L>",
|
|
261
|
-
team_name="<team_name>",
|
|
262
|
-
model="opus",
|
|
263
|
-
description="Bugfind audit PR <N> loop <L>",
|
|
264
|
-
prompt="<audit XML; see PROMPTS.md>"
|
|
265
|
-
)
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
Fresh `Agent` each loop; teammate context excludes lead history ([`sources.md`](sources.md) § Teammate context isolation). [`PROMPTS.md`](PROMPTS.md): XML + outcome schema. Lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml`, fills `loop_comment_index`.
|
|
269
|
-
|
|
270
|
-
**Shutdown:** If `Agent` returned and the teammate already ended, skip. Otherwise:
|
|
271
|
-
|
|
272
|
-
```
|
|
273
|
-
SendMessage(
|
|
274
|
-
to="bugfind-pr<N>-loop<L>",
|
|
275
|
-
message={"type": "shutdown_request", "reason": "audit PR <N> loop <L> complete; outcome XML captured"}
|
|
276
|
-
)
|
|
277
|
-
```
|
|
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.
|
|
278
265
|
|
|
279
|
-
`
|
|
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`.
|
|
280
267
|
|
|
281
268
|
`last_action = "audited"`; append audit line to `audit_log`.
|
|
282
269
|
|
|
283
|
-
**Parallel auditors (`loop_count >= 4`):** gate passes immediately before; after three full audit/fix rounds without convergence, issue three `Agent` calls in
|
|
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.
|
|
284
271
|
|
|
285
272
|
### FIX action
|
|
286
273
|
|
|
287
|
-
|
|
288
|
-
Agent(
|
|
289
|
-
subagent_type="clean-coder",
|
|
290
|
-
name="bugfix-pr<N>-loop<L>",
|
|
291
|
-
team_name="<team_name>",
|
|
292
|
-
model="opus",
|
|
293
|
-
description="Bugfix PR <N> loop <L>",
|
|
294
|
-
prompt="<fix XML; see PROMPTS.md>"
|
|
295
|
-
)
|
|
296
|
-
```
|
|
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.
|
|
297
275
|
|
|
298
276
|
Pass finding comment URLs/ids from `loop_comment_index` in XML. Replies: `Fixed in <sha>` or `Could not address this loop: <reason>`.
|
|
299
277
|
|
|
300
|
-
**Shutdown:** same as bugfind; else `SendMessage(to="bugfix-pr<N>-loop<L>", message={"type": "shutdown_request", "reason": "fix PR <N> loop <L> complete; commit <sha7> pushed"})`. `approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
|
|
301
|
-
|
|
302
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`.
|
|
303
279
|
|
|
304
280
|
### Step 4: Teardown
|
|
305
281
|
|
|
306
|
-
1. For each
|
|
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.
|
|
307
283
|
|
|
308
|
-
2. `TeamDelete()
|
|
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).
|
|
309
285
|
|
|
310
|
-
3. Windows-safe
|
|
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`).
|
|
311
287
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
288
|
+
- `team_owned=true` → remove the full `<team_temp_dir>`:
|
|
289
|
+
|
|
290
|
+
```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}))"
|
|
294
|
+
```
|
|
295
|
+
|
|
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.
|
|
297
|
+
|
|
298
|
+
```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}))"
|
|
302
|
+
```
|
|
317
303
|
|
|
318
304
|
### Step 4.5: PR description
|
|
319
305
|
|
|
@@ -330,7 +316,7 @@ On failure: log in final report; continue to Step 5.
|
|
|
330
316
|
### Step 5: Revoke permissions (always)
|
|
331
317
|
|
|
332
318
|
```bash
|
|
333
|
-
python "${CLAUDE_SKILL_DIR}/scripts/revoke_project_claude_permissions.py"
|
|
319
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/revoke_project_claude_permissions.py"
|
|
334
320
|
```
|
|
335
321
|
|
|
336
322
|
Removes Step 0 grant — run even if Step 4 partially failed (log separately).
|
|
@@ -14,23 +14,23 @@ Evals are split into two layers. Both layers run against the same trace but carr
|
|
|
14
14
|
|
|
15
15
|
## Ironclad invariants (Layer A, apply to every eval)
|
|
16
16
|
|
|
17
|
-
Each invariant cites the normative section or companion file it derives from.
|
|
17
|
+
Each invariant cites the normative section or companion file it derives from. **Path A vs Path B:** `SKILL.md` **Path routing** splits harnesses. Invariants **I-1, I-3, I-4, I-7, I-9, I-11 (teammate shutdown → `TeamDelete` prefix), I-13** apply to **Path A only**. **Path B** substitutes per [`reference/workflow-path-b-task-harness.md`](reference/workflow-path-b-task-harness.md): no `TeamCreate` / `TeamDelete`; parallel auditors use parallel **`Task`** calls; **I-12 Path B** — the **lead** runs Step 2.5 `gh api` posts. **I-2, I-5, I-6, I-8, I-10** apply to **both** paths (revoke once; fresh spawn per loop; `model="opus"` on audit/fix workers; cap; read outcome XML).
|
|
18
18
|
|
|
19
19
|
| # | Invariant | Citation |
|
|
20
20
|
|---|---|---|
|
|
21
|
-
| I-1 | `Bash` invoking `scripts/grant_project_claude_permissions.py` precedes every `TeamCreate`. | `SKILL.md` § Step 0 |
|
|
22
|
-
| I-2 | `Bash` invoking `scripts/revoke_project_claude_permissions.py` runs exactly once per invocation, after
|
|
23
|
-
| I-3 | Exactly one `TeamCreate` and exactly one `TeamDelete` per invocation. | `SKILL.md` § Step 2; § Step 4 |
|
|
24
|
-
| I-4 | Before `TeamDelete`, no teammate remains active without cleanup
|
|
25
|
-
| I-5 | `Agent` calls are fresh per loop
|
|
26
|
-
| I-6 | Both audit and fix
|
|
27
|
-
| I-7 | `TeamDelete()` is called with no arguments.
|
|
21
|
+
| I-1 | **Path A:** `Bash` invoking `scripts/grant_project_claude_permissions.py` precedes every `TeamCreate`. **Path B:** grant precedes first audit **`Task`**. | `SKILL.md` § Step 0; § Path routing |
|
|
22
|
+
| I-2 | `Bash` invoking `scripts/revoke_project_claude_permissions.py` runs exactly once per invocation on every exit path, **after** teardown that applies to that path (`TeamDelete` only on Path A). | `SKILL.md` § Step 5 |
|
|
23
|
+
| I-3 | **Path A:** Exactly one `TeamCreate` and exactly one `TeamDelete` per invocation. **Path B:** zero `TeamCreate` / `TeamDelete`. | `SKILL.md` § Step 2; § Step 4 |
|
|
24
|
+
| I-4 | **Path A:** Before `TeamDelete`, no teammate remains active without cleanup (self-terminated `Agent` or `SendMessage` shutdown). | `SKILL.md` § AUDIT/FIX shutdown; § Step 4 |
|
|
25
|
+
| I-5 | **Path A:** `Agent` calls are fresh per loop. **Path B:** `Task` calls for audit/fix are fresh per loop (same `name` discipline where the host exposes naming). | `CONSTRAINTS.md` — **Fresh teammate per loop**; deltas **Clean-room note** |
|
|
26
|
+
| I-6 | Both paths: audit and fix worker spawns pass `model="opus"` on `Agent` **or** `Task` as documented in `SKILL.md` § AUDIT/FIX. | `SKILL.md` § Step 2 (**Roles**); `CONSTRAINTS.md` — **Opus 4.7 at xhigh effort for both teammates** |
|
|
27
|
+
| I-7 | **Path A:** `TeamDelete()` is called with no arguments. **Path B:** omit. | `SKILL.md` § Step 4 |
|
|
28
28
|
| I-8 | Loop count ≤ 10 audits. 11th audit never fires. | `SKILL.md` YAML `description` (10-loop cap); § Step 3 (**Pre-audit** / **FIX** increment rules) |
|
|
29
|
-
| I-9 | From loop 4 onward without convergence,
|
|
29
|
+
| I-9 | **Path A:** From loop 4 onward without convergence, three parallel `Agent` calls in one message. **Path B:** three parallel **`Task`** calls. | `SKILL.md` § AUDIT action (**Parallel auditors**); `reference/workflow-path-b-task-harness.md` |
|
|
30
30
|
| I-10 | Lead reads `.bugteam-loop-<N>.outcomes.xml` with the `Read` tool after each audit, before the next action. | `SKILL.md` § AUDIT action |
|
|
31
|
-
| I-11 |
|
|
32
|
-
| I-12 | Lead never posts PR review
|
|
33
|
-
| I-13 | Only the
|
|
31
|
+
| I-11 | **Path A:** `git worktree remove` each PR → teammate shutdowns → `TeamDelete` → `rmtree` `<team_temp_dir>` → Step 4.5 → revoke. **Path B:** `git worktree remove` each PR → (omit shutdown / `TeamDelete`) → `rmtree` → Step 4.5 → revoke. | `SKILL.md` § Step 4; § Step 4.5; § Step 5; `reference/workflow-path-a-orchestrated-teams.md` § Step 4; `reference/workflow-path-b-task-harness.md` § Step 4 |
|
|
32
|
+
| I-12 | **Path A:** Lead never posts PR review / finding / fix replies except Step 4.5 body. **Path B:** Lead performs Step 2.5 posts per deltas; Step 4.5 unchanged. | `CONSTRAINTS.md` — **Audit/fix comment posting** |
|
|
33
|
+
| I-13 | **Path A:** Only the lead invokes `TeamCreate`; every teammate `Agent(..., team_name=...)`. **Path B:** no `TeamCreate`; `Task` spawns omit `team_name`. | `CONSTRAINTS.md` — **Path A — orchestrator-only `TeamCreate`**; `reference/workflow-path-b-task-harness.md` |
|
|
34
34
|
|
|
35
35
|
Any eval failing one or more Layer A invariants fails the run.
|
|
36
36
|
|
|
@@ -46,23 +46,25 @@ The harness does not yet exist; this document defines its contract.
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
## Eval 1 —
|
|
49
|
+
## Eval 1 — Path B: agent teams env unset (Task harness, not a refusal)
|
|
50
50
|
|
|
51
51
|
**Scenario.** `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is unset in both `claude config` and `~/.claude/settings.json`.
|
|
52
52
|
|
|
53
53
|
**Trigger.** `/bugteam`
|
|
54
54
|
|
|
55
|
-
**Layer A invariants.**
|
|
55
|
+
**Layer A invariants.** Path B subset (I-2, I-5, I-6, I-8, I-10; I-1/I-3/I-4/I-7/I-9/I-11/I-13 N/A or Path-B-shaped).
|
|
56
56
|
|
|
57
|
-
**Layer B predicted trace.**
|
|
57
|
+
**Layer B predicted trace (Path B smoke).**
|
|
58
58
|
1. `Bash("claude config get env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS")` → empty.
|
|
59
|
-
2. `
|
|
60
|
-
3. No
|
|
59
|
+
2. `Bash("python .../grant_project_claude_permissions.py")` runs (Step 0).
|
|
60
|
+
3. **No** `TeamCreate`.
|
|
61
|
+
4. At least one `Task(subagent_type="code-quality-agent", ...)` or host-equivalent for AUDIT; FIX rounds use the host-appropriate FIX `Task` from `workflow-path-b-task-harness.md` § **FIX spawn** (`clean-coder` subtype on Claude Code when accepted; `generalPurpose` + clean-coder **Read** preamble on Cursor when the enum rejects `clean-coder`).
|
|
62
|
+
5. `Bash("python .../revoke_project_claude_permissions.py")` on exit.
|
|
61
63
|
|
|
62
64
|
**Pass criteria.**
|
|
63
|
-
-
|
|
64
|
-
- Zero `TeamCreate`, `
|
|
65
|
-
-
|
|
65
|
+
- **No** refusal string about missing agent teams.
|
|
66
|
+
- Zero `TeamCreate`, zero `TeamDelete`, zero teammate `SendMessage` shutdowns.
|
|
67
|
+
- Non-zero `Task` (or `Agent` without `team_name` only if the host maps Path B that way) carrying **`code-quality-agent`** / **fix worker under the clean-coder contract** (subtype `clean-coder` where accepted, else `generalPurpose` + `clean-coder.md` Read per `workflow-path-b-task-harness.md`).
|
|
66
68
|
|
|
67
69
|
---
|
|
68
70
|
|
|
@@ -95,11 +97,11 @@ The harness does not yet exist; this document defines its contract.
|
|
|
95
97
|
|
|
96
98
|
---
|
|
97
99
|
|
|
98
|
-
## Eval 5 — Happy path: converges in 2 loops
|
|
100
|
+
## Eval 5 — Happy path: converges in 2 loops (Path A fixture)
|
|
99
101
|
|
|
100
|
-
**Scenario.** PR #42 contains three P1 bugs all addressable by the mock fix teammate. Loop 1 audit returns 3 findings; loop 1 fix commits cleanly; loop 2 audit returns zero findings.
|
|
102
|
+
**Scenario.** PR #42 contains three P1 bugs all addressable by the mock fix teammate. Loop 1 audit returns 3 findings; loop 1 fix commits cleanly; loop 2 audit returns zero findings. **`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`** (Path A — `TeamCreate` + teammate `Agent`).
|
|
101
103
|
|
|
102
|
-
**Layer A invariants.** I-1, I-2, I-3, I-4, I-5, I-6, I-7, I-10, I-11, I-12.
|
|
104
|
+
**Layer A invariants.** Path A: I-1, I-2, I-3, I-4, I-5, I-6, I-7, I-10, I-11, I-12, I-13.
|
|
103
105
|
|
|
104
106
|
**Layer B predicted trace.**
|
|
105
107
|
|
|
@@ -4,6 +4,8 @@ Expanded material that used to live inline in `SKILL.md`. Load a file when the o
|
|
|
4
4
|
|
|
5
5
|
| File | Domain |
|
|
6
6
|
|------|--------|
|
|
7
|
+
| [`workflow-path-a-orchestrated-teams.md`](workflow-path-a-orchestrated-teams.md) | **Path A only** — `TeamCreate`, `Agent` + `team_name`, `SendMessage`, `TeamDelete`, who posts Step 2.5 |
|
|
8
|
+
| [`workflow-path-b-task-harness.md`](workflow-path-b-task-harness.md) | **Path B only** — `Task` harness (no `TeamCreate` / `TeamDelete`, lead Step 2.5 `gh api`, Step 4 omissions) |
|
|
7
9
|
| [`design-rationale.md`](design-rationale.md) | Why agent teams (clean-room), table-of-contents habit, when `/bugteam` applies, refusal reasons |
|
|
8
10
|
| [`team-setup.md`](team-setup.md) | Permissions grant (`CLAUDE_SKILL_DIR`), PR scope, `TeamCreate`, team name / sanitization / temp dir / roles / loop state |
|
|
9
11
|
| [`github-pr-reviews.md`](github-pr-reviews.md) | Per-loop reviews, `jq` + `gh api` payloads, anchors, fallbacks, REST endpoints |
|
|
@@ -16,10 +16,10 @@ Repeat until an exit condition fires.
|
|
|
16
16
|
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`):
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
python "${CLAUDE_SKILL_DIR}/scripts/
|
|
19
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py" --base origin/<baseRefName>
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
`git merge-base` + `git diff --name-only` live inside the script; see [
|
|
22
|
+
`git merge-base` + `git diff --name-only` live inside the script; see [`../../../_shared/pr-loop/scripts/README.md`](../../../_shared/pr-loop/scripts/README.md) for what lives under this directory, and [`../../../_shared/pr-loop/code-rules-gate.md`](../../../_shared/pr-loop/code-rules-gate.md) for gate-only merge-base / invocation semantics. The lead runs this (not a teammate).
|
|
23
23
|
|
|
24
24
|
2. If exit code **0** → continue to step 2.5 (AUDIT spawn) below.
|
|
25
25
|
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`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Utility scripts (progressive disclosure)
|
|
4
4
|
|
|
5
|
-
Fragile or repeatable shell sequences belong in `scripts/`. Anthropic: [Progressive disclosure patterns](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#progressive-disclosure-patterns) — utility scripts are **executed**, not loaded into context as primary reading.
|
|
5
|
+
Fragile or repeatable shell sequences belong in `_shared/pr-loop/scripts/`. Anthropic: [Progressive disclosure patterns](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#progressive-disclosure-patterns) — utility scripts are **executed**, not loaded into context as primary reading. Script inventory and entry points: [`../../../_shared/pr-loop/scripts/README.md`](../../../_shared/pr-loop/scripts/README.md). Gate-only merge-base / diff semantics: [`../../../_shared/pr-loop/code-rules-gate.md`](../../../_shared/pr-loop/code-rules-gate.md).
|
|
6
6
|
|
|
7
7
|
### Pre-flight (recommended before Step 0)
|
|
8
8
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Bugteam — Path A workflow (orchestrated teams)
|
|
2
|
+
|
|
3
|
+
Load when bugteam `SKILL.md` **Path routing** selects **Path A** (`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` equals **`1`** after trim). Execute **after** shared `SKILL.md` steps through **Step 2 loop state**; then use this file for **harness-only** steps. Shared gate scripts, Step 3 cycle numbering, Step 2.5 `jq`/`gh` payload shapes, `PROMPTS.md`, and outcome XML rules remain in **`SKILL.md`**.
|
|
4
|
+
|
|
5
|
+
## Step 2 harness — lifecycle, `TeamCreate`, and team metadata
|
|
6
|
+
|
|
7
|
+
**This session is the lead.** Step 2 first resolves the team lifecycle from the [Team lifecycle](../SKILL.md#team-lifecycle-path-a-only) table in `SKILL.md`, then either creates or attaches to a team.
|
|
8
|
+
|
|
9
|
+
**Lifecycle resolution (read once, then apply):**
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
mode = os.environ.get("BUGTEAM_TEAM_LIFECYCLE", "auto").strip().lower() or "auto"
|
|
16
|
+
attached_team_name = os.environ.get("BUGTEAM_TEAM_NAME", "").strip()
|
|
17
|
+
|
|
18
|
+
if mode == "attach" and not attached_team_name:
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
"BUGTEAM_TEAM_LIFECYCLE=attach requires BUGTEAM_TEAM_NAME to name an existing team."
|
|
21
|
+
)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The mode then drives Step 2's `TeamCreate` decision:
|
|
25
|
+
|
|
26
|
+
- **`mode == "attach"`** — skip `TeamCreate` entirely. Set `team_name = attached_team_name`, `team_owned = false`. Continue to teammate spawns using that `team_name`.
|
|
27
|
+
|
|
28
|
+
- **`mode == "owned"`** — call `TeamCreate(team_name=<computed_team_name>, ...)` (form below). On the runtime error matching `Already leading team "(.+)"\.` → **fail** with `Already leading team <existing>; rerun with BUGTEAM_TEAM_LIFECYCLE=attach BUGTEAM_TEAM_NAME=<existing>`. On success, set `team_owned = true`.
|
|
29
|
+
|
|
30
|
+
- **`mode == "auto"`** (default) — call `TeamCreate(team_name=<computed_team_name>, ...)`. On the same runtime error, parse the existing team name with the regex `r'Already leading team "([^"]+)"'`, set `team_name = <existing>`, `team_owned = false`, and continue without retrying `TeamCreate`. On success, set `team_owned = true`. Both branches honor §Team name below.
|
|
31
|
+
|
|
32
|
+
**`TeamCreate` call shape (only when `mode != "attach"` and the auto branch did not already attach):**
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
TeamCreate(
|
|
36
|
+
team_name="<computed_team_name>",
|
|
37
|
+
description="Bugteam audit/fix loop for PR <number> (<owner>/<repo>)",
|
|
38
|
+
agent_type="team-lead"
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Team name:** For a single-PR invocation use `bugteam-pr-<number>-<YYYYMMDDHHMMSS>`. For a multi-PR invocation use `bugteam-<YYYYMMDDHHMMSS>`. The timestamp is captured once at team-creation time. Apply the no-PR fallback (`bugteam-<sanitized-head>-<YYYYMMDDHHMMSS>`) only when no PR resolves at all. `TeamCreate` implements natural-language team creation ([`sources.md`](../sources.md) § Team creation in natural language).
|
|
43
|
+
|
|
44
|
+
**Sanitize head branch (no-PR only):** replace characters outside `[A-Za-z0-9._-]` with `-` (e.g. `feat/foo*bar` → `feat-foo-bar`). Apply once; reuse everywhere below.
|
|
45
|
+
|
|
46
|
+
**`<team_temp_dir>`:** `Path(tempfile.gettempdir()) / team_name` (lead resolves once to an absolute path; every shell gets that literal string).
|
|
47
|
+
|
|
48
|
+
**Roles (spawned per loop, not here):** bugfind → `code-quality-agent` opus (4.7) at xhigh effort; bugfix → `clean-coder` opus (4.7) at xhigh effort. `model="opus"` resolves to Opus 4.7 on the Anthropic API and runs at the model's default `xhigh` effort level — see [`CONSTRAINTS.md`](../CONSTRAINTS.md) § **Opus 4.7 at xhigh effort for both teammates** for rationale. **Display:** inherit `teammateMode` from `~/.claude.json`. Reference subagent types by name when spawning teammates ([`sources.md`](../sources.md) § Referencing subagent types when spawning teammates).
|
|
49
|
+
|
|
50
|
+
**Optional Groq-backed FIX path (explicit opt-in only):** when the user explicitly sets `BUGTEAM_FIX_IMPLEMENTER=groq-coder` before invocation, spawn the FIX teammate with `subagent_type="groq-coder"`. Before Step 3, `groq_bugteam.py` loads `packages/claude-dev-env/.env` when that file exists (gitignored; start from `packages/claude-dev-env/.env.example`). If `GROQ_API_KEY` is still unset after that load, stop and prompt the user to create `packages/claude-dev-env/.env` from the example path above—do not continue the Groq path without a key. Any other `BUGTEAM_FIX_IMPLEMENTER` value (or unset) keeps `clean-coder` on Opus. The FIX spawn XML in [`PROMPTS.md`](../PROMPTS.md) is identical for both implementers.
|
|
51
|
+
|
|
52
|
+
**`--bugbot-retrigger` flag:** when present on the `/bugteam` invocation, after every successful FIX push in Step 3, post an additional `bugbot run` issue comment via the Step 2.5 issue-comments fallback endpoint (`POST .../issues/{issue}/comments`) to re-trigger Cursor's bugbot on the new commit. Omit when the flag is absent.
|
|
53
|
+
|
|
54
|
+
## Step 2.5 — who posts (Path A)
|
|
55
|
+
|
|
56
|
+
**Bugfind** posts one `POST .../pulls/<n>/reviews` per loop after audit. **Bugfix** posts `.../comments/<id>/replies` after push. The **lead’s** only PR write before Step 4.5 is unchanged from `SKILL.md` (Step 4.5 body edit).
|
|
57
|
+
|
|
58
|
+
## AUDIT spawn (Path A)
|
|
59
|
+
|
|
60
|
+
After shared setup in `SKILL.md` (`mkdir`, `gh pr diff`):
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Agent(
|
|
64
|
+
subagent_type="code-quality-agent",
|
|
65
|
+
name="bugfind-pr<N>-loop<L>",
|
|
66
|
+
team_name="<team_name>",
|
|
67
|
+
model="opus",
|
|
68
|
+
description="Bugfind audit PR <N> loop <L>",
|
|
69
|
+
prompt="<audit XML; see PROMPTS.md>"
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Fresh `Agent` each loop; teammate context excludes lead history ([`sources.md`](../sources.md) § Teammate context isolation). [`PROMPTS.md`](../PROMPTS.md): XML + outcome schema. Lead reads `.bugteam-pr<N>-loop<L>.outcomes.xml`, fills `loop_comment_index` per `SKILL.md`.
|
|
74
|
+
|
|
75
|
+
**Shutdown:** If `Agent` returned and the teammate already ended, skip. Otherwise:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
SendMessage(
|
|
79
|
+
to="bugfind-pr<N>-loop<L>",
|
|
80
|
+
message={"type": "shutdown_request", "reason": "audit PR <N> loop <L> complete; outcome XML captured"}
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`approve: false` → `error: bugfind teammate refused shutdown` → Step 4 then 5 per `SKILL.md`.
|
|
85
|
+
|
|
86
|
+
**Parallel auditors (`loop_count >= 4`):** after three full audit/fix rounds without convergence, issue three `Agent` calls in one assistant message with `team_name="<team_name>"` per `SKILL.md` § parallel variant naming (`-a` / `-b` / `-c`). Shutdown: parallel `SendMessage` to `b` and `c`, then `a`.
|
|
87
|
+
|
|
88
|
+
## FIX spawn (Path A)
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Agent(
|
|
92
|
+
subagent_type="clean-coder",
|
|
93
|
+
name="bugfix-pr<N>-loop<L>",
|
|
94
|
+
team_name="<team_name>",
|
|
95
|
+
model="opus",
|
|
96
|
+
description="Bugfix PR <N> loop <L>",
|
|
97
|
+
prompt="<fix XML; see PROMPTS.md>"
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Shutdown:** same pattern as AUDIT; `SendMessage(to="bugfix-pr<N>-loop<L>", message={"type": "shutdown_request", "reason": "fix PR <N> loop <L> complete; commit <sha7> pushed"})`. `approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
|
|
102
|
+
|
|
103
|
+
Verify and outcome handling: unchanged from `SKILL.md` § FIX action (**Verify**, stuck message, [`PROMPTS.md`](../PROMPTS.md)).
|
|
104
|
+
|
|
105
|
+
## Step 4 harness — after worktree remove, before shared `rmtree`
|
|
106
|
+
|
|
107
|
+
Run **after** `SKILL.md` § Step 4 step 1 (`git worktree remove` for each PR).
|
|
108
|
+
|
|
109
|
+
1. For each live teammate **spawned by this invocation**: `SendMessage(to="<name>", message={"type": "shutdown_request", "reason": "bugteam cycle ending"})`. `approve: false` on cleanup → log and continue. Teammates that pre-existed an attached team (mode `attach` or `auto` after the attach branch) are owned by the orchestrator, not this invocation — leave them alone.
|
|
110
|
+
|
|
111
|
+
2. `TeamDelete()` — **only when `team_owned=true`** (set in Step 2 lifecycle resolution). When `team_owned=false`, **skip `TeamDelete`** and log `cleanup: skipped TeamDelete (team not owned by this invocation; lifecycle=<mode>)`. The orchestrator that originally created the team owns teardown — see [Team lifecycle](../SKILL.md#team-lifecycle-path-a-only).
|
|
112
|
+
|
|
113
|
+
Then continue with `SKILL.md` § Step 4 step 3 (`<team_temp_dir>` cleanup, also gated on `team_owned`).
|