claude-dev-env 1.36.1 → 1.37.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/_shared/pr-loop/audit-contract.md +159 -0
- package/_shared/pr-loop/code-rules-gate.md +64 -0
- package/_shared/pr-loop/fix-protocol.md +37 -0
- package/_shared/pr-loop/gh-payloads.md +85 -0
- package/_shared/pr-loop/scripts/README.md +20 -0
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +234 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +975 -0
- package/_shared/pr-loop/scripts/config/__init__.py +0 -0
- package/_shared/pr-loop/scripts/config/claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/config/claude_settings_keys_constants.py +11 -0
- package/_shared/pr-loop/scripts/config/code_rules_gate_constants.py +56 -0
- package/_shared/pr-loop/scripts/config/fix_hookspath_constants.py +25 -0
- package/_shared/pr-loop/scripts/config/gh_util_constants.py +31 -0
- package/_shared/pr-loop/scripts/config/preflight_constants.py +68 -0
- package/_shared/pr-loop/scripts/fix_hookspath.py +260 -0
- package/_shared/pr-loop/scripts/gh_util.py +193 -0
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +130 -0
- package/_shared/pr-loop/scripts/preflight.py +449 -0
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +156 -0
- package/_shared/pr-loop/scripts/tests/conftest.py +51 -0
- package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +135 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +169 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +58 -0
- package/_shared/pr-loop/scripts/tests/test_claude_settings_keys_constants.py +50 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +917 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +102 -0
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +374 -0
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath_constants.py +47 -0
- package/_shared/pr-loop/scripts/tests/test_gh_util.py +257 -0
- package/_shared/pr-loop/scripts/tests/test_gh_util_constants.py +61 -0
- package/_shared/pr-loop/scripts/tests/test_grant_project_claude_permissions.py +49 -0
- package/_shared/pr-loop/scripts/tests/test_preflight.py +670 -0
- package/_shared/pr-loop/scripts/tests/test_preflight_constants.py +77 -0
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +49 -0
- package/_shared/pr-loop/state-schema.md +81 -0
- package/hooks/blocking/code_rules_enforcer.py +269 -23
- package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +157 -1
- package/hooks/config/test_unused_module_import_constants.py +48 -0
- package/hooks/config/unused_module_import_constants.py +41 -0
- package/package.json +2 -1
- package/skills/bg-agent/SKILL.md +69 -0
- package/skills/bugteam/CONSTRAINTS.md +10 -19
- package/skills/bugteam/PROMPTS.md +3 -3
- package/skills/bugteam/SKILL.md +103 -202
- package/skills/bugteam/SKILL_EVALS.md +75 -114
- package/skills/bugteam/reference/README.md +2 -4
- package/skills/bugteam/reference/design-rationale.md +3 -8
- package/skills/bugteam/reference/team-setup.md +11 -19
- package/skills/bugteam/reference/teardown-publish-permissions.md +2 -14
- package/skills/bugteam/scripts/config/__init__.py +0 -0
- package/skills/bugteam/scripts/config/reflow_skill_md_constants.py +12 -0
- package/skills/bugteam/scripts/reflow_skill_md.py +51 -47
- package/skills/bugteam/sources.md +1 -25
- package/skills/bugteam/test_skill_additions.py +4 -13
- package/skills/fresh-branch/SKILL.md +71 -0
- package/skills/gotcha/SKILL.md +73 -0
- package/skills/monitor-open-prs/SKILL.md +4 -37
- package/skills/monitor-open-prs/test_skill_contract.py +0 -5
- package/skills/pr-converge/SKILL.md +60 -1298
- package/skills/pr-converge/reference/convergence-gates.md +118 -0
- package/skills/pr-converge/reference/examples.md +76 -0
- package/skills/pr-converge/reference/fix-protocol.md +54 -0
- package/skills/pr-converge/reference/ground-rules.md +13 -0
- package/skills/pr-converge/reference/multi-pr-orchestration.md +204 -0
- package/skills/pr-converge/reference/per-tick.md +201 -0
- package/skills/pr-converge/reference/state-schema.md +19 -0
- package/skills/pr-converge/reference/stop-conditions.md +26 -0
- package/skills/pr-converge/scripts/README.md +36 -9
- package/skills/pr-converge/scripts/check_pr_mergeability.py +1 -2
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +58 -5
- package/skills/pr-converge/scripts/config/reflow_skill_md_constants.py +13 -0
- package/skills/pr-converge/scripts/config/test_pr_converge_constants.py +0 -24
- package/skills/pr-converge/scripts/cursor-agents-continue.ahk +22 -2
- package/skills/pr-converge/scripts/fetch_bugbot_inline_comments.py +19 -59
- package/skills/pr-converge/scripts/fetch_bugbot_reviews.py +15 -61
- package/skills/pr-converge/scripts/fetch_claude_inline_comments.py +70 -0
- package/skills/pr-converge/scripts/fetch_claude_reviews.py +61 -0
- package/skills/pr-converge/scripts/fetch_copilot_inline_comments.py +19 -61
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +14 -74
- package/skills/pr-converge/scripts/reflow_skill_md.py +71 -50
- package/skills/pr-converge/scripts/reviewer_fetch_core.py +153 -0
- package/skills/pr-converge/scripts/reviewer_specs.py +98 -0
- package/skills/pr-converge/scripts/test_cursor_agents_continue.py +65 -0
- package/skills/pr-converge/scripts/test_fetch_bugbot_inline_comments.py +107 -6
- package/skills/pr-converge/scripts/test_fetch_bugbot_reviews.py +85 -6
- package/skills/pr-converge/scripts/test_fetch_claude_inline_comments.py +485 -0
- package/skills/pr-converge/scripts/test_fetch_claude_reviews.py +368 -0
- package/skills/pr-converge/scripts/test_fetch_copilot_inline_comments.py +74 -6
- package/skills/pr-converge/scripts/test_fetch_copilot_reviews.py +94 -8
- package/skills/pr-converge/scripts/test_reflow_skill_md.py +162 -0
- package/skills/pr-converge/scripts/test_reviewer_fetch_core.py +448 -0
- package/skills/pr-converge/scripts/test_reviewer_specs.py +107 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +24 -22
- package/skills/bugteam/reference/workflow-path-a-orchestrated-teams.md +0 -113
- package/skills/bugteam/reference/workflow-path-b-task-harness.md +0 -48
- package/skills/bugteam/test_team_lifecycle.py +0 -103
- package/skills/monitor-open-prs/test_team_lifecycle.py +0 -46
- package/skills/pr-converge/scripts/open_followup_copilot_pr.py +0 -136
- package/skills/pr-converge/scripts/test_open_followup_copilot_pr.py +0 -236
- package/skills/pr-converge/test_team_lifecycle.py +0 -56
- package/skills/pr-converge/workflows/ahk-auto-continue-loop.md +0 -108
|
@@ -17,14 +17,15 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import re
|
|
19
19
|
import textwrap
|
|
20
|
-
from pathlib import Path
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
from config.reflow_skill_md_constants import (
|
|
22
|
+
BASH_CONTINUATION_MARKER_WIDTH,
|
|
23
|
+
BULLET_LIST_ITEM_PATTERN as BULLET_RE,
|
|
24
|
+
MAXIMUM_LINE_WIDTH as MAX_WIDTH,
|
|
25
|
+
ORDERED_LIST_ITEM_PATTERN as ORDERED_RE,
|
|
26
|
+
TARGET_SKILL_PATH as SKILL_PATH,
|
|
27
|
+
UNFINISHED_MARKDOWN_LINK_TARGET_PATTERN as UNFINISHED_MD_LINK_TARGET,
|
|
28
|
+
)
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
def wrap_paragraph_plain(text: str) -> list[str]:
|
|
@@ -55,11 +56,14 @@ def wrap_list_item(lead_ws: str, marker: str, body: str) -> list[str]:
|
|
|
55
56
|
).splitlines()
|
|
56
57
|
|
|
57
58
|
|
|
58
|
-
def reflow_yaml_description_block(
|
|
59
|
+
def reflow_yaml_description_block(
|
|
60
|
+
all_lines: list[str],
|
|
61
|
+
body_start: int,
|
|
62
|
+
) -> tuple[list[str], int]:
|
|
59
63
|
body_parts: list[str] = []
|
|
60
64
|
index = body_start
|
|
61
|
-
while index < len(
|
|
62
|
-
line =
|
|
65
|
+
while index < len(all_lines):
|
|
66
|
+
line = all_lines[index]
|
|
63
67
|
if line.strip() == "---":
|
|
64
68
|
index += 1
|
|
65
69
|
break
|
|
@@ -118,30 +122,30 @@ def merge_without_space(buffer: str, continuation: str) -> bool:
|
|
|
118
122
|
return False
|
|
119
123
|
|
|
120
124
|
|
|
121
|
-
def merge_soft_breaks(
|
|
122
|
-
|
|
125
|
+
def merge_soft_breaks(all_lines: list[str]) -> list[str]:
|
|
126
|
+
reflowed_lines: list[str] = []
|
|
123
127
|
index = 0
|
|
124
|
-
|
|
125
|
-
while index < len(
|
|
126
|
-
raw =
|
|
128
|
+
is_inside_fence = False
|
|
129
|
+
while index < len(all_lines):
|
|
130
|
+
raw = all_lines[index]
|
|
127
131
|
line = raw.rstrip("\n")
|
|
128
132
|
if line.lstrip().startswith("```"):
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
is_inside_fence = not is_inside_fence
|
|
134
|
+
reflowed_lines.append(line)
|
|
131
135
|
index += 1
|
|
132
136
|
continue
|
|
133
|
-
if
|
|
134
|
-
|
|
137
|
+
if is_inside_fence:
|
|
138
|
+
reflowed_lines.append(line)
|
|
135
139
|
index += 1
|
|
136
140
|
continue
|
|
137
141
|
if line.strip() == "":
|
|
138
|
-
|
|
142
|
+
reflowed_lines.append(line)
|
|
139
143
|
index += 1
|
|
140
144
|
continue
|
|
141
145
|
buffer_line = line
|
|
142
146
|
index += 1
|
|
143
|
-
while index < len(
|
|
144
|
-
next_raw =
|
|
147
|
+
while index < len(all_lines):
|
|
148
|
+
next_raw = all_lines[index].rstrip("\n")
|
|
145
149
|
if next_raw.strip() == "":
|
|
146
150
|
break
|
|
147
151
|
if next_raw.lstrip().startswith("```"):
|
|
@@ -154,8 +158,8 @@ def merge_soft_breaks(lines: list[str]) -> list[str]:
|
|
|
154
158
|
else:
|
|
155
159
|
buffer_line = f"{buffer_line.rstrip()} {stripped_next}"
|
|
156
160
|
index += 1
|
|
157
|
-
|
|
158
|
-
return
|
|
161
|
+
reflowed_lines.append(buffer_line)
|
|
162
|
+
return reflowed_lines
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
def reflow_merged_line(line: str) -> list[str]:
|
|
@@ -212,39 +216,39 @@ def reflow_merged_line(line: str) -> list[str]:
|
|
|
212
216
|
return wrap_paragraph_plain(stripped)
|
|
213
217
|
|
|
214
218
|
|
|
215
|
-
def reflow_markdown_body(
|
|
216
|
-
merged = merge_soft_breaks(
|
|
217
|
-
|
|
219
|
+
def reflow_markdown_body(all_lines: list[str]) -> list[str]:
|
|
220
|
+
merged = merge_soft_breaks(all_lines)
|
|
221
|
+
reflowed_lines: list[str] = []
|
|
218
222
|
for each_line in merged:
|
|
219
223
|
if each_line.strip() == "":
|
|
220
|
-
|
|
224
|
+
reflowed_lines.append("")
|
|
221
225
|
continue
|
|
222
|
-
|
|
223
|
-
return
|
|
226
|
+
reflowed_lines.extend(reflow_merged_line(each_line))
|
|
227
|
+
return reflowed_lines
|
|
224
228
|
|
|
225
229
|
|
|
226
|
-
def wrap_long_bash_fence_lines(
|
|
230
|
+
def wrap_long_bash_fence_lines(all_lines: list[str]) -> list[str]:
|
|
227
231
|
"""Hard-wrap only ```bash fence bodies that still exceed MAX_WIDTH."""
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
for
|
|
231
|
-
stripped =
|
|
232
|
+
wrapped_lines: list[str] = []
|
|
233
|
+
is_inside_bash_fence = False
|
|
234
|
+
for each_line in all_lines:
|
|
235
|
+
stripped = each_line.lstrip()
|
|
232
236
|
if stripped.startswith("```"):
|
|
233
|
-
if not
|
|
237
|
+
if not is_inside_bash_fence:
|
|
234
238
|
lang = stripped[3:].strip().lower()
|
|
235
|
-
|
|
239
|
+
is_inside_bash_fence = lang == "bash"
|
|
236
240
|
else:
|
|
237
|
-
|
|
238
|
-
|
|
241
|
+
is_inside_bash_fence = False
|
|
242
|
+
wrapped_lines.append(each_line)
|
|
239
243
|
continue
|
|
240
|
-
if
|
|
241
|
-
indent_len = len(
|
|
242
|
-
indent =
|
|
243
|
-
content =
|
|
244
|
+
if is_inside_bash_fence and len(each_line) > MAX_WIDTH:
|
|
245
|
+
indent_len = len(each_line) - len(each_line.lstrip())
|
|
246
|
+
indent = each_line[:indent_len]
|
|
247
|
+
content = each_line.lstrip()
|
|
244
248
|
wrapped_segments: list[str] = []
|
|
245
249
|
rest = content
|
|
246
250
|
while len(rest) > MAX_WIDTH - len(indent):
|
|
247
|
-
room = MAX_WIDTH - len(indent) -
|
|
251
|
+
room = MAX_WIDTH - len(indent) - BASH_CONTINUATION_MARKER_WIDTH
|
|
248
252
|
window = rest[:room]
|
|
249
253
|
break_at = window.rfind(" ")
|
|
250
254
|
if break_at <= 0:
|
|
@@ -254,10 +258,10 @@ def wrap_long_bash_fence_lines(lines: list[str]) -> list[str]:
|
|
|
254
258
|
wrapped_segments.append(indent + piece + " \\")
|
|
255
259
|
if rest:
|
|
256
260
|
wrapped_segments.append(indent + (" " if wrapped_segments else "") + rest)
|
|
257
|
-
|
|
261
|
+
wrapped_lines.extend(wrapped_segments)
|
|
258
262
|
else:
|
|
259
|
-
|
|
260
|
-
return
|
|
263
|
+
wrapped_lines.append(each_line)
|
|
264
|
+
return wrapped_lines
|
|
261
265
|
|
|
262
266
|
|
|
263
267
|
def main() -> None:
|
|
@@ -26,15 +26,7 @@ Direct quote:
|
|
|
26
26
|
|
|
27
27
|
**Skill use:** Subagents return into the lead context (accumulates across loops); agent-team teammates do not pollute the lead. This skill needs the independent-context property.
|
|
28
28
|
|
|
29
|
-
###
|
|
30
|
-
|
|
31
|
-
Direct quote:
|
|
32
|
-
|
|
33
|
-
> "tell Claude to create an agent team and describe the task and the team structure you want in natural language. Claude creates the team, spawns teammates, and coordinates work based on your prompt."
|
|
34
|
-
|
|
35
|
-
**Skill use:** Maps to the `TeamCreate` tool step in the process section.
|
|
36
|
-
|
|
37
|
-
### Referencing subagent types when spawning teammates
|
|
29
|
+
### Referencing subagent types when spawning subagents
|
|
38
30
|
|
|
39
31
|
Direct quote:
|
|
40
32
|
|
|
@@ -42,22 +34,6 @@ Direct quote:
|
|
|
42
34
|
|
|
43
35
|
**Skill use:** Bugfind / bugfix roles reference `code-quality-agent` and `clean-coder` by subagent type name.
|
|
44
36
|
|
|
45
|
-
### Lead cleanup and active teammates
|
|
46
|
-
|
|
47
|
-
Direct quote:
|
|
48
|
-
|
|
49
|
-
> "When the lead runs cleanup, it checks for active teammates and fails if any are still running, so shut them down first."
|
|
50
|
-
|
|
51
|
-
**Skill use:** Step 4 shutdown sequence before `TeamDelete`.
|
|
52
|
-
|
|
53
|
-
### Ending the team
|
|
54
|
-
|
|
55
|
-
Direct quote:
|
|
56
|
-
|
|
57
|
-
> "When you're done, ask the lead to clean up: 'Clean up the team'."
|
|
58
|
-
|
|
59
|
-
**Skill use:** Maps to calling `TeamDelete()` after shutdown messages.
|
|
60
|
-
|
|
61
37
|
---
|
|
62
38
|
|
|
63
39
|
## Claude — Agent skills best practices
|
|
@@ -10,16 +10,9 @@ def _read_skill_text() -> str:
|
|
|
10
10
|
return skill_path.read_text(encoding="utf-8")
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def _read_path_a_workflow_text() -> str:
|
|
14
|
-
workflow_path = (
|
|
15
|
-
pathlib.Path(__file__).parent / "reference" / "workflow-path-a-orchestrated-teams.md"
|
|
16
|
-
)
|
|
17
|
-
return workflow_path.read_text(encoding="utf-8")
|
|
18
|
-
|
|
19
|
-
|
|
20
13
|
def test_skill_references_fix_implementer_env_var():
|
|
21
|
-
|
|
22
|
-
assert "BUGTEAM_FIX_IMPLEMENTER" in
|
|
14
|
+
skill_text = _read_skill_text()
|
|
15
|
+
assert "BUGTEAM_FIX_IMPLEMENTER" in skill_text
|
|
23
16
|
|
|
24
17
|
|
|
25
18
|
def test_skill_names_default_implementer_subagent_type():
|
|
@@ -28,12 +21,10 @@ def test_skill_names_default_implementer_subagent_type():
|
|
|
28
21
|
|
|
29
22
|
|
|
30
23
|
def test_skill_names_optional_groq_implementer_subagent_type():
|
|
31
|
-
|
|
32
|
-
assert "groq-coder" in
|
|
24
|
+
skill_text = _read_skill_text()
|
|
25
|
+
assert "groq-coder" in skill_text
|
|
33
26
|
|
|
34
27
|
|
|
35
28
|
def test_skill_documents_bugbot_retrigger_flag():
|
|
36
29
|
skill_text = _read_skill_text()
|
|
37
|
-
workflow_text = _read_path_a_workflow_text()
|
|
38
30
|
assert "--bugbot-retrigger" in skill_text
|
|
39
|
-
assert "--bugbot-retrigger" in workflow_text
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fresh-branch
|
|
3
|
+
description: Creates a fresh branch for the current repo based on origin main. Always fetches actual origin main rather than relying on local main. Suggests possible branch names via AskUserQuestion when context is available, or prompts the user to provide a name directly. Triggers on "fresh branch", "new branch from main", "/fresh-branch", "start fresh".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# fresh-branch
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Creates a new branch from `origin/main` (always fresh-fetched, never stale local main). Designed as a shared primitive: other skills (e.g. gotcha) invoke `/fresh-branch` to create a clean branch for their own PR workflows.
|
|
11
|
+
|
|
12
|
+
**Announce at start:** "Creating a fresh branch from origin/main."
|
|
13
|
+
|
|
14
|
+
## Instructions
|
|
15
|
+
|
|
16
|
+
### Phase 1 — Fetch origin main
|
|
17
|
+
|
|
18
|
+
Always fetch `origin/main` directly. Do not rely on the local `main` branch, which may be stale.
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
git fetch origin main
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Confirm the fetch succeeded. If it fails (no network, no remote), report the error and stop.
|
|
25
|
+
|
|
26
|
+
### Phase 2 — Determine branch name
|
|
27
|
+
|
|
28
|
+
Branch names follow the repo's convention: lowercase, hyphen-separated, descriptive prefix.
|
|
29
|
+
|
|
30
|
+
**When context is available (the caller or prior conversation provides a topic):**
|
|
31
|
+
|
|
32
|
+
Suggest 2–4 branch names via `AskUserQuestion`. The suggestions should be short, descriptive, and follow the `prefix/description` or `description` convention visible in recent `git log` output.
|
|
33
|
+
|
|
34
|
+
Poll recent branch naming patterns to inform suggestions:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
git branch -r --sort=-committerdate | head -20
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**When no context is available:**
|
|
41
|
+
|
|
42
|
+
Ask the user to provide a branch name directly via `AskUserQuestion` with `multiSelect: false` and a free-text option.
|
|
43
|
+
|
|
44
|
+
### Phase 3 — Create the branch
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
git checkout -b <branch-name> origin/main
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `-b` flag creates the branch and checks it out. Basing on `origin/main` (not local `main`) guarantees the branch starts from the true latest state.
|
|
51
|
+
|
|
52
|
+
Confirm success:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
git rev-parse --abbrev-ref HEAD
|
|
56
|
+
git log --oneline -1
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Phase 4 — Report
|
|
60
|
+
|
|
61
|
+
State the new branch name and its base commit. If invoked as a subroutine by another skill, return the branch name so the caller can proceed (e.g., creating a PR from it).
|
|
62
|
+
|
|
63
|
+
## What this skill does NOT do
|
|
64
|
+
|
|
65
|
+
- Does not push the branch. The caller decides when and whether to push.
|
|
66
|
+
- Does not create a PR. Use `gh pr create` separately.
|
|
67
|
+
- Does not switch an existing branch. It always creates a new one.
|
|
68
|
+
|
|
69
|
+
## Gotchas
|
|
70
|
+
|
|
71
|
+
See the gotcha reference at the bottom of this file. When a new gotcha is discovered during use, invoke `/gotcha` to add it here.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gotcha
|
|
3
|
+
description: When a skill encounters an obstacle requiring user intervention, this skill invokes bg-agent to add the gotcha to the skill file's gotcha section and creates a PR via fresh-branch. Triggers on "/gotcha", "add a gotcha", "document this gotcha", "record this obstacle".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# gotcha
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
When a skill is executed and hits an obstacle that requires user intervention to resolve, `/gotcha` captures that knowledge so future invocations avoid the same trap. It delegates the mechanical work to `bg-agent`, which writes the gotcha entry and opens a PR using `fresh-branch`.
|
|
11
|
+
|
|
12
|
+
**Announce at start:** "Recording this gotcha and opening a PR."
|
|
13
|
+
|
|
14
|
+
## Instructions
|
|
15
|
+
|
|
16
|
+
### Step 1 — Collect the gotcha
|
|
17
|
+
|
|
18
|
+
The caller provides the obstacle context. Distill it into:
|
|
19
|
+
|
|
20
|
+
- **Which skill file** hit the obstacle (full path, e.g. `packages/claude-dev-env/skills/rebase/SKILL.md`).
|
|
21
|
+
- **What happened** — the specific failure or blocker, in one or two sentences.
|
|
22
|
+
- **What the user had to do** to resolve it.
|
|
23
|
+
- **What to do differently next time** (the actionable gotcha).
|
|
24
|
+
|
|
25
|
+
Determine which repo the skill lives in. Usually this is `claude-code-config`, but if the skill is in another repo (e.g. a project-specific `.claude/skills/` directory), use that repo instead.
|
|
26
|
+
|
|
27
|
+
### Step 2 — Delegate to bg-agent
|
|
28
|
+
|
|
29
|
+
Invoke `/bg-agent` with a task like:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
bg-agent add a gotcha to <skill-file-path> in repo <repo-name>. The gotcha is: "<one-line summary>". Details: "<what happened, what the user did, and what to do next time>."
|
|
33
|
+
|
|
34
|
+
Steps:
|
|
35
|
+
1. Use /fresh-branch to create a branch named gotcha/<short-slug>.
|
|
36
|
+
2. In <skill-file-path>, add the gotcha entry under a ## Gotchas section (create the section at the bottom of the file if it does not exist).
|
|
37
|
+
3. Format each gotcha as a bullet: "- **<title>:** <description>."
|
|
38
|
+
4. Commit with message "fix(<skill-name>): add gotcha — <title>".
|
|
39
|
+
5. Push and create a draft PR.
|
|
40
|
+
6. Report the PR URL.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The bg-agent will pick a suitable agent type and run the full workflow in the background.
|
|
44
|
+
|
|
45
|
+
### Step 3 — Confirm
|
|
46
|
+
|
|
47
|
+
Tell the user: "Recording gotcha in the background. You will be notified when the PR is ready."
|
|
48
|
+
|
|
49
|
+
## Gotcha entry format
|
|
50
|
+
|
|
51
|
+
Every gotcha entry follows this format:
|
|
52
|
+
|
|
53
|
+
```markdown
|
|
54
|
+
## Gotchas
|
|
55
|
+
|
|
56
|
+
- **<title>:** <what happens>. <what to do instead>.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If a `## Gotchas` section already exists, append to it. If not, create it at the bottom of the skill file.
|
|
60
|
+
|
|
61
|
+
## Which repo
|
|
62
|
+
|
|
63
|
+
| Skill location | Repo |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `packages/claude-dev-env/skills/<name>/` | `jl-cmd/claude-code-config` |
|
|
66
|
+
| `~/.claude/skills/<name>/` | `jl-cmd/claude-code-config` (user skills) |
|
|
67
|
+
| Project `.claude/skills/<name>/` | That project's repo |
|
|
68
|
+
|
|
69
|
+
When unsure, ask the user which repo. Otherwise, default to `claude-code-config`.
|
|
70
|
+
|
|
71
|
+
## Gotchas
|
|
72
|
+
|
|
73
|
+
- **The bg-agent prompt must be self-contained.** The background agent has no access to this conversation. Include the skill file path, the gotcha text, the repo, and the exact workflow steps in the prompt.
|
|
@@ -7,8 +7,7 @@ description: >-
|
|
|
7
7
|
re-trigger flag (--bugbot-retrigger), wrap the session in `bws run`
|
|
8
8
|
to inject GROQ_API_KEY, and poll Cursor's bugbot replies after
|
|
9
9
|
convergence so any post-Groq findings loop back through /bugteam.
|
|
10
|
-
|
|
11
|
-
'/monitor-open-prs', 'sweep the open PRs', 'groq-bugteam the backlog'.
|
|
10
|
+
Triggers: '/monitor-open-prs', 'sweep the open PRs', 'groq-bugteam the backlog'.
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
# Monitor Open PRs
|
|
@@ -19,9 +18,8 @@ description: >-
|
|
|
19
18
|
|
|
20
19
|
- When this skill applies — refusal cases and trigger conditions
|
|
21
20
|
- Discovery — live `gh search prs` across both owner scopes
|
|
22
|
-
- Team lifecycle — single long-lived team for the whole sweep
|
|
23
21
|
- Wrapping — `bws run` for GROQ_API_KEY injection
|
|
24
|
-
- Dispatch — `/bugteam <
|
|
22
|
+
- Dispatch — `/bugteam --bugbot-retrigger <pr_numbers...>` with groq-coder + retrigger
|
|
25
23
|
- Post-convergence polling — bugbot replies and re-invocation
|
|
26
24
|
- `scripts/discover_open_prs.py` — the discovery helper
|
|
27
25
|
|
|
@@ -31,7 +29,6 @@ description: >-
|
|
|
31
29
|
|
|
32
30
|
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
33
31
|
|
|
34
|
-
- **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. /monitor-open-prs requires the agent teams feature.`
|
|
35
32
|
- **bws not on PATH.** `bws not installed. /monitor-open-prs injects GROQ_API_KEY via Bitwarden Secrets Manager.`
|
|
36
33
|
- **gh not authenticated.** `gh auth status failed. /monitor-open-prs relies on existing gh credentials.`
|
|
37
34
|
- **Dirty tree on the caller's repo.** `Uncommitted changes detected. Stash, commit, or revert before /monitor-open-prs.`
|
|
@@ -41,35 +38,6 @@ Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
|
41
38
|
|
|
42
39
|
Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to merge the live open-PR list across both scopes. The helper runs `gh search prs --owner <owner> --state open --json number,repository,url,headRefName,baseRefName` once per owner and flattens the result to a uniform dict shape with keys `number`, `owner`, `repo`, `head_ref`, `base_ref`, `url`. Empty scopes contribute empty lists; an entirely empty sweep returns `[]` and exits cleanly.
|
|
43
40
|
|
|
44
|
-
## Team Lifecycle
|
|
45
|
-
|
|
46
|
-
`/monitor-open-prs` dispatches one `/bugteam` per discovered PR — often more than ten in a sweep. Per-invocation `TeamCreate` / `TeamDelete` from each `/bugteam` would either collide on the runtime's `Already leading team` rule or tear down the wrong team mid-sweep, depending on dispatch order. The sweep instead owns a **single long-lived team for the whole sweep** and passes that team to every `/bugteam` invocation in attach mode. See [bugteam Team lifecycle](../bugteam/SKILL.md#team-lifecycle-path-a-only).
|
|
47
|
-
|
|
48
|
-
**Before the first dispatch:**
|
|
49
|
-
|
|
50
|
-
1. Capture `sweep_id = <YYYYMMDDHHMMSS>` once at sweep start. This is the same convention as bugteam's team-name timestamp.
|
|
51
|
-
2. Compute `team_name = "bugteam-monitor-<sweep_id>"`.
|
|
52
|
-
3. `TeamCreate(team_name=<team_name>, description="monitor-open-prs sweep <sweep_id>", agent_type="team-lead")`. The orchestrator (this session) becomes the lead.
|
|
53
|
-
|
|
54
|
-
**For every `/bugteam` dispatch** (parallel fan-out or serial), prepend the two attach-mode env vars to the wrapped command so bugteam reuses the orchestrator's team and skips its own `TeamCreate` / `TeamDelete`:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
bws run \
|
|
58
|
-
--project-id c69cedc5-aea1-4aa8-b350-b4300145d978 \
|
|
59
|
-
-- \
|
|
60
|
-
env BUGTEAM_TEAM_LIFECYCLE=attach \
|
|
61
|
-
BUGTEAM_TEAM_NAME=<team_name> \
|
|
62
|
-
BUGTEAM_FIX_IMPLEMENTER=groq-coder \
|
|
63
|
-
/bugteam --bugbot-retrigger <pr_numbers...>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Teardown — only after every PR has exited polling** (see §Post-Convergence Polling): the sweep is done; no further `/bugteam` invocation will run. At that point, and only at that point:
|
|
67
|
-
|
|
68
|
-
1. `TeamDelete()` (orchestrator is the lead; no arguments).
|
|
69
|
-
2. Print one cleanup line into the §Final Report: `team teardown: TeamDelete <team_name>` (success) or the error message on failure.
|
|
70
|
-
|
|
71
|
-
If a hard blocker or user stop ends the sweep early, the orchestrator is shutting down: still call `TeamDelete()` once after polling stops for the in-flight PRs.
|
|
72
|
-
|
|
73
41
|
## Secret Wrapping
|
|
74
42
|
|
|
75
43
|
Every `/bugteam` dispatch runs inside `bws run` so `GROQ_API_KEY` is injected from Bitwarden Secrets Manager without touching the filesystem. The project and secret UUIDs are fixed for this skill:
|
|
@@ -89,9 +57,9 @@ The `bws run` subshell resolves the project's secrets and exports them for the w
|
|
|
89
57
|
For each discovered PR:
|
|
90
58
|
|
|
91
59
|
1. Resolve the PR's repo checkout (existing worktree or fresh `git clone`).
|
|
92
|
-
2. From that checkout, invoke `/bugteam <pr_number>` under the `bws run` wrapper from §
|
|
60
|
+
2. From that checkout, invoke `/bugteam --bugbot-retrigger <pr_number>` under the `bws run` wrapper from §Secret Wrapping.
|
|
93
61
|
3. The `BUGTEAM_FIX_IMPLEMENTER=groq-coder` env var routes the FIX role to the `groq-coder` subagent. The `--bugbot-retrigger` flag tells bugteam to post `bugbot run` as an issue comment after every successful FIX push so Cursor's bugbot re-evaluates the new commit.
|
|
94
|
-
4. Bugteam runs its own 10-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
|
|
62
|
+
4. Bugteam runs its own 10-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
|
|
95
63
|
|
|
96
64
|
**Fan-out (optional):** when the discovered list has more than one PR, the skill may spawn `/bugteam` dispatches in parallel by issuing multiple `Agent` calls in a single assistant message. Each dispatch operates in its own per-PR worktree (bugteam Step 1.1). Serialize when the caller sets an explicit `--serial` flag.
|
|
97
65
|
|
|
@@ -127,7 +95,6 @@ Total Groq tokens consumed: <approx from /bugteam outcome summaries>
|
|
|
127
95
|
|
|
128
96
|
## Non-Negotiable Guardrails
|
|
129
97
|
|
|
130
|
-
- Never run `/bugteam` without `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` active.
|
|
131
98
|
- Never source secrets outside `bws run` — no `.env` files, no shell history, no logs.
|
|
132
99
|
- Never pass `--no-verify` or `--no-gpg-sign` to git in any dispatched bugteam run.
|
|
133
100
|
- Never open a PR from this skill; only comment on existing ones.
|
|
@@ -16,11 +16,6 @@ def test_skill_has_frontmatter_name():
|
|
|
16
16
|
assert "name: monitor-open-prs" in skill_text
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def test_skill_requires_agent_teams_env_var():
|
|
20
|
-
skill_text = _read_skill_text()
|
|
21
|
-
assert "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS" in skill_text
|
|
22
|
-
|
|
23
|
-
|
|
24
19
|
def test_skill_invokes_bugteam_with_groq_implementer():
|
|
25
20
|
skill_text = _read_skill_text()
|
|
26
21
|
assert "BUGTEAM_FIX_IMPLEMENTER" in skill_text
|