claude-dev-env 1.50.4 → 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CLAUDE.md +0 -8
  2. package/_shared/pr-loop/audit-contract.md +3 -3
  3. package/_shared/pr-loop/scripts/pr_loop_shared_constants/preflight_self_heal_constants.py +28 -0
  4. package/_shared/pr-loop/scripts/preflight.py +18 -6
  5. package/_shared/pr-loop/scripts/preflight_self_heal.py +164 -0
  6. package/_shared/pr-loop/scripts/tests/test_preflight.py +39 -0
  7. package/_shared/pr-loop/scripts/tests/test_preflight_self_heal.py +273 -0
  8. package/agents/clean-coder.md +1 -1
  9. package/agents/code-quality-agent.md +7 -5
  10. package/audit-rubrics/category_rubrics/category-a-api-contracts.md +3 -0
  11. package/audit-rubrics/category_rubrics/category-f-silent-failures.md +3 -0
  12. package/audit-rubrics/category_rubrics/category-k-codebase-conflicts.md +8 -2
  13. package/audit-rubrics/category_rubrics/category-n-test-name-scenario-verifier.md +3 -0
  14. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +39 -0
  15. package/audit-rubrics/category_rubrics/category-p-name-vs-behavior-contract.md +40 -0
  16. package/audit-rubrics/prompts/category-a-api-contracts.md +11 -4
  17. package/audit-rubrics/prompts/category-b-selector-engine-compat.md +2 -2
  18. package/audit-rubrics/prompts/category-c-resource-cleanup.md +1 -1
  19. package/audit-rubrics/prompts/category-d-scoping-and-ordering.md +1 -1
  20. package/audit-rubrics/prompts/category-e-dead-code.md +1 -1
  21. package/audit-rubrics/prompts/category-f-silent-failures.md +13 -2
  22. package/audit-rubrics/prompts/category-g-bounds-and-overflow.md +1 -1
  23. package/audit-rubrics/prompts/category-h-security-boundaries.md +1 -1
  24. package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
  25. package/audit-rubrics/prompts/category-j-code-rules-compliance.md +1 -1
  26. package/audit-rubrics/prompts/category-k-codebase-conflicts.md +15 -5
  27. package/audit-rubrics/prompts/category-l-behavior-equivalence.md +1 -1
  28. package/audit-rubrics/prompts/category-m-producer-consumer-cardinality.md +1 -1
  29. package/audit-rubrics/prompts/category-n-test-name-scenario-verifier.md +10 -3
  30. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +74 -0
  31. package/audit-rubrics/prompts/category-p-name-vs-behavior-contract.md +75 -0
  32. package/docs/CODE_RULES.md +24 -346
  33. package/package.json +1 -1
  34. package/rules/ask-user-question-required.md +2 -41
  35. package/rules/confirm-implementation-forks.md +3 -44
  36. package/rules/gh-body-file.md +2 -78
  37. package/rules/gh-paginate.md +2 -78
  38. package/rules/plain-language.md +2 -41
  39. package/rules/prompt-workflow-context-controls.md +9 -38
  40. package/rules/shell-invocation-policy.md +2 -141
  41. package/rules/testing.md +10 -0
  42. package/rules/vault-context.md +3 -32
  43. package/rules/windows-filesystem-safe.md +3 -87
  44. package/scripts/sync_to_cursor/rules.py +201 -79
  45. package/scripts/tests/test_sync_to_cursor.py +122 -26
  46. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +2 -0
  47. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +51 -4
  48. package/skills/auditing-claude-config/SKILL.md +6 -1
  49. package/skills/bugteam/CONSTRAINTS.md +1 -1
  50. package/skills/bugteam/PROMPTS.md +8 -6
  51. package/skills/bugteam/SKILL.md +5 -5
  52. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  53. package/skills/bugteam/reference/audit-contract.md +4 -4
  54. package/skills/bugteam/reference/design-rationale.md +1 -1
  55. package/skills/bugteam/reference/obstacles/audit-walk-categories.md +1 -1
  56. package/skills/bugteam/reference/team-setup.md +17 -5
  57. package/skills/bugteam/scripts/bugteam_preflight.py +22 -10
  58. package/skills/bugteam/scripts/test_bugteam_preflight.py +32 -0
  59. package/skills/copilot-review/SKILL.md +5 -8
  60. package/skills/doc-gist/SKILL.md +5 -8
  61. package/skills/fixbugs/SKILL.md +1 -1
  62. package/skills/gh-paginate/SKILL.md +84 -0
  63. package/skills/pre-compact/SKILL.md +4 -9
  64. package/skills/refine/SKILL.md +8 -2
  65. package/skills/structure-prompt/SKILL.md +5 -10
@@ -1,6 +1,11 @@
1
1
  ---
2
2
  name: auditing-claude-config
3
- description: Audits a Claude Code setup (user CLAUDE.md, ~/.claude/rules/, project .claude/) for context-budget waste — duplicate @-imports, eagerly-loaded rules that should be path-scoped or converted to skills, oversized always-on files, and rules duplicating existing skills. Produces a migration table with line-count savings. Use when reviewing the always-on instruction load, when sessions feel sluggish, when /memory shows surprising loads, when adding new rules, or for periodic config hygiene. Optionally verifies findings empirically via an InstructionsLoaded probe hook that logs every load event with its load_reason and parent_file_path.
3
+ description: >-
4
+ Audits a Claude Code setup (user CLAUDE.md, ~/.claude/rules/, project .claude/) for
5
+ context-budget waste — duplicate @-imports, always-on rules to path-scope or convert
6
+ to skills, oversized files — and produces a migration table with savings. Use when
7
+ reviewing the startup/instruction load, when /memory shows surprising loads, when
8
+ adding new rules, or for periodic config hygiene.
4
9
  ---
5
10
 
6
11
  # Auditing Claude Config
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Constraints
4
4
 
5
- - **Full A–N audit every loop, no exceptions.** PR size, "focused audit," "team overhead," "CODE_RULES already passed" — not valid reasons. Empty `<findings/>` for any category is a valid result. The audit agent walks all A–N rubrics each loop.
5
+ - **Full A–P audit every loop, no exceptions.** PR size, "focused audit," "team overhead," "CODE_RULES already passed" — not valid reasons. Empty `<findings/>` for any category is a valid result. The audit agent walks all A–P rubrics each loop.
6
6
  - **One run per invocation, multi-PR supported.** All PRs in a single /bugteam invocation share one `run_temp_dir`. Per-PR identity lives in the subagent name prefix (`bugfind-pr<N>-loop<L>` / `bugfix-pr<N>-loop<L>`) and the `<run_temp_dir>/pr-<N>/` subfolder containing that PR's git worktree, diff patches, and outcome XML files.
7
7
  - **Grant before any spawn, revoke before any return.** Step 0 grants project `.claude/**` permissions; Step 5 revokes. Both are mandatory. Revoke runs on every exit path including error, cap-reached, and stuck.
8
8
  - **Fresh subagent per loop.** Both bugfind and bugfix are spawned new each loop. Reusing a subagent across loops accumulates context inside that subagent's window — defeats clean-room.
@@ -24,7 +24,7 @@ cd into `<worktree_path>` before any git or file operation.
24
24
  </scope>
25
25
 
26
26
  <bug_categories>
27
- Investigate each of the fourteen categories (A–N) explicitly. For each,
27
+ Investigate each of the sixteen categories (A–P) explicitly. For each,
28
28
  return either at least one finding OR a verified-clean entry with the
29
29
  evidence backing the verdict. A category is verified-clean only when one
30
30
  complete execution path through the changed code has been traced from
@@ -37,7 +37,7 @@ cd into `<worktree_path>` before any git or file operation.
37
37
  When evidence contains any of these phrases, the category is not
38
38
  verified-clean -- re-audit with a concrete trace.
39
39
 
40
- Categories A–N (one-line summary; full rubric and sub-bucket
40
+ Categories A–P (one-line summary; full rubric and sub-bucket
41
41
  decomposition for each is in
42
42
  `$HOME/.claude/audit-rubrics/category_rubrics/`; ready-to-send Variant
43
43
  C prompts — each with a PR/repo-independent generalized skeleton above
@@ -58,6 +58,8 @@ cd into `<worktree_path>` before any git or file operation.
58
58
  L. Behavior-equivalence for refactors
59
59
  M. Producer/consumer cardinality vs collection-type contract
60
60
  N. Test-name scenario verifier
61
+ O. Docstring / fixture-prose vs implementation drift
62
+ P. Name / regex / word-list vs behavior-contract precision
61
63
  </bug_categories>
62
64
 
63
65
  <rubric_reference>
@@ -77,7 +79,7 @@ cd into `<worktree_path>` before any git or file operation.
77
79
  </constraints>
78
80
 
79
81
  <comment_posting>
80
- Load all A–N rubrics from
82
+ Load all A–P rubrics from
81
83
  `$HOME/.claude/audit-rubrics/{category_rubrics,prompts}/`. The prompt file
82
84
  is a template for output shape, not a straitjacket — reorganize when the
83
85
  diff demands it. The diff supplies the findings; the rubric supplies the
@@ -88,7 +90,7 @@ cd into `<worktree_path>` before any git or file operation.
88
90
  done.
89
91
 
90
92
  <self_audit_checklist>
91
- [ ] Walk all 14 categories (A–N), each with Shape A or Shape B
93
+ [ ] Walk all 16 categories (A–P), each with Shape A or Shape B
92
94
  [ ] Assign finding IDs (loop<L>-<K>)
93
95
  [ ] Capture excerpts, validate anchors, format finding bodies
94
96
  [ ] Build findings JSON, invoke post_audit_thread.py, capture html_url
@@ -96,7 +98,7 @@ cd into `<worktree_path>` before any git or file operation.
96
98
  [ ] Write outcome XML
97
99
  </self_audit_checklist>
98
100
 
99
- 1. Audit the diff against the 14 categories above. Buffer the findings
101
+ 1. Audit the diff against the 16 categories above. Buffer the findings
100
102
  in memory; all posting happens at step 4 once anchors are validated.
101
103
  2. Assign each finding a stable finding_id of exactly the form `loop<L>-<K>`
102
104
  where <K> is 1-based within this loop.
@@ -227,7 +229,7 @@ attributes.
227
229
  </bugteam_audit>
228
230
  ```
229
231
 
230
- Verified-clean evidence per A–N category is surfaced in the agent's text-mode
232
+ Verified-clean evidence per A–P category is surfaced in the agent's text-mode
231
233
  final report, not in this outcome XML (the writer accepts a flat findings list
232
234
  only).
233
235
 
@@ -11,10 +11,10 @@ description: >-
11
11
  # Bugteam
12
12
 
13
13
  Audit–fix until convergence. Bugfind: `code-quality-agent`, fresh context each
14
- loop, auditing all A–N categories. Bugfix: `clean-coder`. Hard cap: 20 audit
14
+ loop, auditing all A–P categories. Bugfix: `clean-coder`. Hard cap: 20 audit
15
15
  loops. Grant `.claude/**` at start, revoke always at end.
16
16
 
17
- The audit agent loads the A–N category rubrics from
17
+ The audit agent loads the A–P category rubrics from
18
18
  `$HOME/.claude/audit-rubrics/{category_rubrics,prompts}/` alongside
19
19
  [`PROMPTS.md`](PROMPTS.md) and produces a single outcome XML per loop.
20
20
 
@@ -146,7 +146,7 @@ end-to-end mental model before starting Step 0.
146
146
  | Posting the end-of-pass audit review via `post_audit_thread.py` (APPROVE on CLEAN — the request event; GitHub stores it as `state=APPROVED` — REQUEST_CHANGES with inline anchored comments on DIRTY) | [§ Audit posting](#audit-posting) |
147
147
  | Posting per-finding fix replies via GitHub MCP `add_reply_to_pull_request_comment` (rendered with the unified template at [`_shared/pr-loop/audit-reply-template.md`](../../_shared/pr-loop/audit-reply-template.md)) | [reference/github-pr-reviews.md](reference/github-pr-reviews.md) |
148
148
  | Teardown, PR description rewrite via `pr-description-writer`, permission revoke, final report | [reference/teardown-publish-permissions.md](reference/teardown-publish-permissions.md) |
149
- | Spawn-prompt XML, A–N category bindings, outcome XML schemas | [PROMPTS.md](PROMPTS.md) |
149
+ | Spawn-prompt XML, A–P category bindings, outcome XML schemas | [PROMPTS.md](PROMPTS.md) |
150
150
  | Per-category audit content (sub-buckets, decision criteria, ready-to-send Variant C templates) | `$HOME/.claude/audit-rubrics/{category_rubrics,prompts}/` |
151
151
  | Invariants and design rationale | [CONSTRAINTS.md](CONSTRAINTS.md), [reference/design-rationale.md](reference/design-rationale.md) |
152
152
  | Audit-contract finding shape (Shape A / B), Haiku secondary, post-fix self-audit | [reference/audit-contract.md](reference/audit-contract.md) |
@@ -159,11 +159,11 @@ end-to-end mental model before starting Step 0.
159
159
  - `SKILL.md` — this hub.
160
160
  - `reference/` — workflow detail per situation.
161
161
  - `scripts/` — utility scripts executed, not loaded as primary context.
162
- - `PROMPTS.md` — spawn XML, A–N category bindings, outcome schemas.
162
+ - `PROMPTS.md` — spawn XML, A–P category bindings, outcome schemas.
163
163
  - `CONSTRAINTS.md` — invariants.
164
164
  - `EXAMPLES.md` — exit scenarios.
165
165
  - `sources.md` — doc URLs and verbatim quotes.
166
166
  - `~/.claude/audit-rubrics/` — installed by `npx claude-dev-env` from
167
- `packages/claude-dev-env/audit-rubrics/`; the audit agent reads all A–N
167
+ `packages/claude-dev-env/audit-rubrics/`; the audit agent reads all A–P
168
168
  rubrics under `category_rubrics/` and prompts under `prompts/`. Required
169
169
  at audit time alongside `PROMPTS.md`.
@@ -116,7 +116,7 @@ Repeat until an exit condition fires.
116
116
 
117
117
  ## AUDIT action
118
118
 
119
- Spawn one audit agent that walks all A–N categories:
119
+ Spawn one audit agent that walks all A–P categories:
120
120
 
121
121
  ```
122
122
  Agent(
@@ -21,7 +21,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
21
21
  "id": "loop<L>-<K>",
22
22
  "file": "path/relative/to/repo/root.py",
23
23
  "line": 123,
24
- "category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N",
24
+ "category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P",
25
25
  "severity": "P0 | P1 | P2",
26
26
  "excerpt": "verbatim code snippet from the offending line(s)",
27
27
  "failure_mode": "one sentence describing what goes wrong and when",
@@ -37,7 +37,7 @@ Used when an audit investigates a category and does NOT find a bug. Bare "verifi
37
37
 
38
38
  ```json
39
39
  {
40
- "category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N",
40
+ "category": "A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P",
41
41
  "files_opened": ["file1.py", "file2.py"],
42
42
  "lines_quoted": [
43
43
  {"file": "file1.py", "line": 88, "text": "verbatim line content"}
@@ -89,7 +89,7 @@ After the primary finding list is complete, every audit runs a second pass again
89
89
 
90
90
  The audit must either produce new Shape A findings citing new file:line references not present in the first pass, or cite explicit Shape B adversarial-probe entries for each category it re-examined. An adversarial pass that returns "nothing new, confident first pass was complete" is REJECTED — produce evidence or findings, not confidence.
91
91
 
92
- For `/bugteam`, the single audit agent provides per-category coverage by walking all A–N rubrics in one invocation.
92
+ For `/bugteam`, the single audit agent provides per-category coverage by walking all A–P rubrics in one invocation.
93
93
 
94
94
  ## Merge rules
95
95
 
@@ -113,7 +113,7 @@ Sequence:
113
113
  3. Run `py_compile` (or language-equivalent) on each modified file.
114
114
  4. Compute `fix_diff` against pre-fix contents for the modified set.
115
115
  5. Run `bugteam_code_rules_gate.py` with explicit paths for every modified file.
116
- 6. Spawn a scoped audit of `fix_diff` with full A–N rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
116
+ 6. Spawn a scoped audit of `fix_diff` with full A–P rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
117
117
  7. Any new findings become same-loop fix-targets. Internal iteration count increments by one.
118
118
  8. After 3 internal iterations with fresh findings each time, exit `stuck: post-fix audit not converging`.
119
119
  9. Only when `gate_findings` empty AND `post_fix_findings` empty: `git add`, commit, push.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Core principle (expanded)
4
4
 
5
- One audit agent (`code-quality-agent`, opus) walks all A–N categories per loop. One fix agent (`clean-coder`, opus) addresses the audit's findings.
5
+ One audit agent (`code-quality-agent`, opus) walks all A–P categories per loop. One fix agent (`clean-coder`, opus) addresses the audit's findings.
6
6
 
7
7
  Fresh-spawn clean-room isolation: each `Agent` call creates a new subagent with its own context window and no access to prior conversation. After the subagent writes its outcome XML and self-terminates, the lead reads the file. Results never accumulate in the lead’s context beyond the XML artifact. Verbatim Anthropic quotes and URLs: [`../sources.md`](../sources.md).
8
8
 
@@ -1,6 +1,6 @@
1
1
  # Walk categories
2
2
 
3
- Audit every category A through K. Each returns Shape A finding or Shape B verified-clean. No skipped categories.
3
+ Audit every category A through P. Each returns Shape A finding or Shape B verified-clean. No skipped categories.
4
4
 
5
5
  ## Self-population
6
6
 
@@ -17,11 +17,23 @@ python "${CLAUDE_SKILL_DIR}/scripts/bugteam_preflight.py"
17
17
  Non-zero → fix before grant. `BUGTEAM_PREFLIGHT_SKIP=1` emergency only.
18
18
  `--pre-commit` if `.pre-commit-config.yaml` exists.
19
19
 
20
- **Auto-remediation for `core.hooksPath`:** when preflight fails with stderr
21
- containing `core.hooksPath` (the message starts with `bugteam_preflight:
22
- core.hooksPath is`, or `Git-side CODE_RULES enforcement is not active`), Claude
23
- must auto-invoke the fix script do not fall through to `AskUserQuestion`, do
24
- not punt to the user, do not ask for confirmation:
20
+ **Self-heal for stale local-scope `core.hooksPath`:** preflight silently
21
+ unsets ALL local-scope `core.hooksPath` entries on the active repository when
22
+ two conditions both hold: at least one entry does not end in the canonical
23
+ `hooks/git-hooks` suffix, AND a canonical global `core.hooksPath` is already
24
+ configured. The check clears the `<repo>/.git/hooks` entry git can seed into a
25
+ worktree's local config when `extensions.worktreeConfig` is set or seeding
26
+ tooling is in use, so the canonical global setting takes effect without Claude
27
+ needing to surface a failure or invoke the fix script. When the global is
28
+ unset or non-canonical, the self-heal stands down so the downstream
29
+ `core.hooksPath is '<path>'` diagnostic stays informative.
30
+
31
+ **Auto-remediation for `core.hooksPath`:** when preflight reports stderr
32
+ containing `core.hooksPath` (the message starts with
33
+ `bugteam_preflight: core.hooksPath is`, or `Git-side CODE_RULES enforcement is
34
+ not active`) — which surfaces when the global setting is missing or points
35
+ elsewhere — Claude must auto-invoke the fix script. Do not fall through to
36
+ `AskUserQuestion`, do not punt to the user, do not ask for confirmation:
25
37
 
26
38
  ```bash
27
39
  python "${CLAUDE_SKILL_DIR}/scripts/bugteam_fix_hookspath.py"
@@ -36,7 +36,8 @@ _shared_pr_loop_scripts_directory = (
36
36
  if str(_shared_pr_loop_scripts_directory) not in sys.path:
37
37
  sys.path.insert(0, str(_shared_pr_loop_scripts_directory))
38
38
 
39
- from reviews_disabled import (
39
+ from preflight_self_heal import silently_clear_stale_local_hooks_path_override # noqa: E402
40
+ from reviews_disabled import ( # noqa: E402
40
41
  CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
41
42
  CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
42
43
  EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV,
@@ -47,9 +48,17 @@ from reviews_disabled import (
47
48
  def verify_git_hooks_path(repository_root: Path | None) -> int:
48
49
  """Check that core.hooksPath resolves to the claude-dev-env git-hooks directory.
49
50
 
50
- When *repository_root* is provided, queries the effective config for that
51
- repository (``git -C <root> config --get``), which detects repo-level
52
- overrides such as Husky or lefthook. Falls back to the current working
51
+ Silently clears any stale, non-canonical local-scope core.hooksPath
52
+ override before querying the effective config, so a worktree-seeded local
53
+ entry cannot shadow a correctly configured global setting. When
54
+ *repository_root* is provided, queries the effective config for that
55
+ repository (``git -C <root> config --get``). When a canonical global
56
+ ``core.hooksPath`` is already configured, the preceding self-heal step
57
+ clears non-canonical local-scope entries, so repo-level overrides such
58
+ as Husky or lefthook at local scope are silently removed in favor of
59
+ the canonical global; when the global is unset or non-canonical, the
60
+ self-heal stands down and the ``--get`` query still surfaces those
61
+ overrides through the failure path. Falls back to the current working
53
62
  directory's effective config when *repository_root* is None.
54
63
 
55
64
  Args:
@@ -60,12 +69,15 @@ def verify_git_hooks_path(repository_root: Path | None) -> int:
60
69
  Zero when the configured path ends with the expected hooks suffix.
61
70
  Non-zero and prints a correction message when unset or pointing elsewhere.
62
71
  """
72
+ silently_clear_stale_local_hooks_path_override(
73
+ repository_root, EXPECTED_HOOKS_PATH_SUFFIX
74
+ )
63
75
  git_command: list[str] = ["git"]
64
76
  if repository_root is not None:
65
77
  git_command.extend(["-C", str(repository_root)])
66
78
  git_command.extend(list(ALL_GIT_CONFIG_HOOKS_PATH_ARGUMENTS))
67
79
  try:
68
- query_result = subprocess.run(
80
+ query_completed_process = subprocess.run(
69
81
  git_command,
70
82
  capture_output=True,
71
83
  text=True,
@@ -87,13 +99,13 @@ def verify_git_hooks_path(repository_root: Path | None) -> int:
87
99
  file=sys.stderr,
88
100
  )
89
101
  return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
90
- if query_result.returncode != 0:
102
+ if query_completed_process.returncode != 0:
91
103
  print(
92
104
  f"{BUGTEAM_PREFLIGHT_PREFIX}{ENFORCEMENT_ABSENT_MESSAGE}",
93
105
  file=sys.stderr,
94
106
  )
95
107
  return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
96
- configured_path = query_result.stdout.strip().replace("\\", "/").rstrip("/")
108
+ configured_path = query_completed_process.stdout.strip().replace("\\", "/").rstrip("/")
97
109
  if not configured_path.endswith(EXPECTED_HOOKS_PATH_SUFFIX):
98
110
  print(
99
111
  f"{BUGTEAM_PREFLIGHT_PREFIX}core.hooksPath is '{configured_path}' — "
@@ -178,20 +190,20 @@ def _pytest_exit_code_no_tests_collected() -> int:
178
190
  return PYTEST_EXIT_CODE_NO_TESTS_COLLECTED
179
191
 
180
192
 
181
- def run_pytest(repository_root: Path, verbose: bool) -> int:
193
+ def run_pytest(repository_root: Path, is_verbose: bool) -> int:
182
194
  """Run pytest in the repository root and return the exit code.
183
195
 
184
196
  Treats the "no tests collected" exit code as a pass (exit 0).
185
197
 
186
198
  Args:
187
199
  repository_root: The repository root for running pytest.
188
- verbose: When True, pass no -q flag (shows individual test names).
200
+ is_verbose: When True, pass no -q flag (shows individual test names).
189
201
 
190
202
  Returns:
191
203
  The pytest exit code, or 0 when no tests were collected.
192
204
  """
193
205
  command = [sys.executable, "-m", "pytest"]
194
- if not verbose:
206
+ if not is_verbose:
195
207
  command.append("-q")
196
208
  completed = subprocess.run(
197
209
  command,
@@ -282,3 +282,35 @@ def test_main_should_halt_when_env_var_contains_uppercase_or_whitespace_bugteam_
282
282
  monkeypatch.delenv("BUGTEAM_PREFLIGHT_SKIP", raising=False)
283
283
  exit_code = bugteam_preflight.main(["--no-pytest"])
284
284
  assert exit_code == bugteam_preflight.EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
285
+
286
+
287
+ def _was_called_with_argument(
288
+ mock_subprocess_run: MagicMock, argument_token: str
289
+ ) -> bool:
290
+ return any(
291
+ argument_token in each_call_args[0][0]
292
+ for each_call_args in mock_subprocess_run.call_args_list
293
+ )
294
+
295
+
296
+ def test_verify_git_hooks_path_invokes_self_heal_before_effective_query(
297
+ tmp_path: Path,
298
+ ) -> None:
299
+ """verify_git_hooks_path must delegate to the shared self-heal helper before --get."""
300
+ canonical_hooks_path = tmp_path / ".claude" / "hooks" / "git-hooks"
301
+ canonical_hooks_path.mkdir(parents=True)
302
+ with patch("subprocess.run") as mock_run:
303
+ mock_run.return_value = _make_completed_process(
304
+ str(canonical_hooks_path) + "\n", returncode=0
305
+ )
306
+ bugteam_preflight.verify_git_hooks_path(tmp_path)
307
+ assert _was_called_with_argument(mock_run, "--get-all"), (
308
+ "verify_git_hooks_path must run the --local --get-all read for self-heal"
309
+ )
310
+ assert _was_called_with_argument(mock_run, "--get"), (
311
+ "verify_git_hooks_path must still run the effective --get verification"
312
+ )
313
+ first_called_command = mock_run.call_args_list[0][0][0]
314
+ assert "--get-all" in first_called_command, (
315
+ "Self-heal must run BEFORE the effective config query, not after"
316
+ )
@@ -1,14 +1,11 @@
1
1
  ---
2
2
  name: copilot-review
3
3
  description: >-
4
- Spawns a background subagent that babysits the GitHub Copilot reviewer on the
5
- current PR. The subagent self-paces at ~5 minutes per tick, fetches the
6
- latest copilot-pull-request-reviewer[bot] review, fixes unaddressed inline
7
- findings against current HEAD (new commit, push, inline replies), and
8
- re-requests review via the documented requested_reviewers API. The subagent
9
- terminates on convergence (clean review against HEAD) and reports back.
10
- Triggers: '/copilot-review', 'watch copilot', 'babysit copilot review',
11
- 'loop copilot reviews', 're-request copilot', 'keep re-requesting copilot'.
4
+ Spawns a background subagent that babysits the GitHub Copilot reviewer on the current
5
+ PR: each ~5-min tick it fetches the latest copilot-pull-request-reviewer[bot] review,
6
+ fixes unaddressed findings against HEAD (commit, push, inline replies), re-requests
7
+ review, and exits on convergence. Triggers: '/copilot-review', 'watch copilot',
8
+ 'babysit copilot review', 'keep re-requesting copilot'.
12
9
  ---
13
10
 
14
11
  # Copilot Review
@@ -1,14 +1,11 @@
1
1
  ---
2
2
  name: doc-gist
3
3
  description: >-
4
- Use when the user asks to share, publish, preview, or open as a webpage any
5
- HTML doc, writeup, report, plan, decision record, runbook, explainer, status
6
- update, or interactive artifact. Triggers on `/doc-gist`, "publish this",
7
- "share as a gist", "open this as a webpage", "make me a writeup", "publish my
8
- report", or any request that ends in a shareable HTML preview URL. Provides
9
- the `gist_upload` transport script, an auto-publish hook keyed off the
10
- `<!-- @publish-as-gist -->` HTML comment, and a 20-file gallery of HTML
11
- artifact patterns to draw from when designing fresh.
4
+ Use when the user asks to share, publish, preview, or open as a webpage any HTML doc,
5
+ writeup, report, plan, runbook, or interactive artifact. Triggers on /doc-gist,
6
+ "publish this", "share as a gist", "open this as a webpage", "make me a writeup", or
7
+ any request ending in a shareable HTML preview URL. Provides the gist_upload transport
8
+ script, the <!-- @publish-as-gist --> auto-publish hook, and an HTML pattern gallery.
12
9
  ---
13
10
 
14
11
  # doc-gist
@@ -33,7 +33,7 @@ Locate the most recent `/findbugs` output in the current conversation. For each
33
33
 
34
34
  - Severity (`P0` / `P1` / `P2`)
35
35
  - `file:line`
36
- - Category (the A–N letter or category name `/findbugs` reported)
36
+ - Category (the A–P letter or category name `/findbugs` reported)
37
37
  - One-sentence description as `/findbugs` wrote it
38
38
 
39
39
  Apply the severity filter from `$ARGUMENTS` if present:
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: gh-paginate
3
+ description: Safe pagination for gh api reads of paginated GitHub list endpoints (PR reviews/comments/files, issue comments, pulls, issues) — --paginate --slurp piped to external jq, single-page bounds, newest-first walks. Use before composing any gh api list-endpoint call or any cross-page jq operation (sort_by | last, reverse).
4
+ ---
5
+
6
+ # gh API Pagination Rule
7
+
8
+ **Root cause:** GitHub REST API list endpoints paginate by default. Without `--paginate --slurp`, callers see only the oldest page, and cross-page jq operations (e.g., `sort_by | last`) operate within a single page — producing wrong-but-confident results.
9
+
10
+ **Rule:** All `gh api` calls that read `pulls/<number>/reviews`, `pulls/<number>/comments`, `issues/<number>/comments`, or any other paginated GitHub list endpoint **must** request the full set of pages AND apply any cross-page jq operation through external `jq`, not through `gh`'s built-in `--jq`. Use `--paginate --slurp | jq` (preferred — see [Safe patterns](#safe-patterns)). Never call these endpoints with their default pagination, and never use `gh`'s `--jq` for cross-page operations like `sort_by | last` or `| reverse | .[0]`.
11
+
12
+ ## Two defects, one rule
13
+
14
+ This rule guards against two distinct silent-truncation defects that compound:
15
+
16
+ 1. **Default page truncation.** Without `--paginate`, only the first page is fetched.
17
+ 2. **`--jq` runs per-page, not on the concatenated result.** Per [GitHub CLI #10459](https://github.com/cli/cli/issues/10459), `gh api --paginate --jq '<filter>'` applies `<filter>` to each page **separately** and emits one output per page. Cross-page operations like `sort_by(.submitted_at) | last` therefore operate within each page independently, not across the merged result set.
18
+
19
+ The safe patterns below fix both defects together: `--paginate --slurp` walks every page AND emits a single merged structure, and an **external** `jq` then runs cross-page operations on that merged structure.
20
+
21
+ ## Affected endpoints
22
+
23
+ The rule applies to every paginated read from the GitHub REST API. Common offenders in PR-loop skills:
24
+
25
+ - `gh api repos/<owner>/<repo>/pulls/<number>/reviews`
26
+ - `gh api repos/<owner>/<repo>/pulls/<number>/comments`
27
+ - `gh api repos/<owner>/<repo>/pulls/<number>/files`
28
+ - `gh api repos/<owner>/<repo>/issues/<number>/comments`
29
+ - `gh api repos/<owner>/<repo>/pulls`
30
+ - `gh api repos/<owner>/<repo>/issues`
31
+
32
+ The same rule applies to any other endpoint documented as paginated by GitHub (see [GitHub REST API pagination](https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api)).
33
+
34
+ Single-object endpoints (e.g., `repos/<owner>/<repo>/pulls/<number>` returning one PR object) are not paginated — `?per_page=...` is silently ignored, and neither `--paginate` nor external `jq` is required. Use `gh`'s `--jq` directly on those endpoints.
35
+
36
+ ## Safe patterns
37
+
38
+ ### Preferred — `--paginate --slurp` piped to external `jq`
39
+
40
+ `gh api ... --paginate --slurp` walks every page and emits a single merged JSON array of page-arrays (`[[page1_items...], [page2_items...], ...]`). Pipe to external `jq` to flatten and filter across the full result set:
41
+
42
+ ```bash
43
+ gh api 'repos/<owner>/<repo>/pulls/<number>/reviews?per_page=100' --paginate --slurp \
44
+ | jq '[.[][] | select(.user.login=="cursor[bot]")] | sort_by(.submitted_at) | last'
45
+ ```
46
+
47
+ The `.[][]` flattens the array-of-pages into one stream of items before the cross-page operators (`sort_by`, `last`, `reverse`) run. Combine with `?per_page=100` to reduce round-trips on long PRs.
48
+
49
+ `gh`'s `--jq` flag and `--slurp` flag are mutually exclusive (gh CLI rejects `--paginate --slurp --jq` with `the --slurp option is not supported with --jq or --template`), which is why the filter must run in an external `jq` invocation.
50
+
51
+ ### Acceptable — single-page bound on a paginated list endpoint when result fits
52
+
53
+ When you have an explicit reason to read at most one page from a **paginated** list endpoint (e.g., a known-small list), document the bound in a comment and use `?per_page=100` without `--paginate`. Cross-page operators are not in play here, so `gh`'s `--jq` is safe:
54
+
55
+ ```bash
56
+ # Bound: a freshly created issue is expected to have <= 100 comments.
57
+ gh api 'repos/<owner>/<repo>/issues/<number>/comments?per_page=100' \
58
+ --jq '[.[] | select(.user.login=="cursor[bot]")] | length'
59
+ ```
60
+
61
+ This pattern is only safe when the endpoint is confirmed to return a list smaller than 100 entries. Lists that grow over the PR's lifetime (reviews, comments) must use `--paginate --slurp` plus external `jq`.
62
+
63
+ ### Single-object endpoints — no pagination needed
64
+
65
+ Endpoints that return a single object (e.g., `pulls/<number>`, `issues/<number>`) are not paginated. `?per_page=...`, `--paginate`, and `--slurp` are all unnecessary. Use `gh`'s built-in `--jq` directly:
66
+
67
+ ```bash
68
+ gh api 'repos/<owner>/<repo>/pulls/<number>' --jq '.head.sha'
69
+ ```
70
+
71
+ ### Newest-first walk
72
+
73
+ Pair pagination with explicit reverse-sort so the consumer reads newest-first regardless of the API's internal order:
74
+
75
+ ```bash
76
+ gh api 'repos/<owner>/<repo>/pulls/<number>/reviews?per_page=100' --paginate --slurp \
77
+ | jq '[.[][] | select(.user.login=="cursor[bot]")] | sort_by(.submitted_at) | reverse'
78
+ ```
79
+
80
+ This is the canonical pattern for the bugbot <-> bugteam convergence loop: walk newest-first, stop at the first clean review.
81
+
82
+ ## Enforcement
83
+
84
+ This rule is documentation-only at present. A future PreToolUse hook may pattern-match `Bash` invocations of `gh api repos/.../pulls/<n>/(reviews|comments)` without `--paginate --slurp` (or with `--paginate --jq` doing cross-page operations) and return a corrective message. Until that hook lands, treat this rule as binding by review and rely on it during skill authoring.
@@ -1,15 +1,10 @@
1
1
  ---
2
2
  name: pre-compact
3
3
  description: >-
4
- Composes a focus directive for `/compact [instructions]` and copies the full
5
- `/compact <directive>` string to the operator's clipboard so the next prompt
6
- is a single paste. The directive pins the session's load-bearing identifiers
7
- (branch, PR, HEAD, worktree, in-flight work, decisions, blockers, files in
8
- play, follow-ups) the next steps depend on, so the summarizer keeps them with
9
- high fidelity. It confirms the operator's intent for the next chat through a
10
- structured question first, then validates each identifier against its live
11
- source before stating it. Use when the user says `/pre-compact`, asks to prep for compaction, or
12
- asks to compose a focus directive for `/compact`.
4
+ Composes a focus directive for /compact and copies the full "/compact <directive>"
5
+ string to the clipboard, pinning the session's load-bearing identifiers (branch, PR,
6
+ HEAD, worktree, in-flight work, decisions, blockers, files in play) after validating
7
+ each against its live source. Use on /pre-compact or any ask to prep for compaction.
13
8
  disable-model-invocation: true
14
9
  ---
15
10
 
@@ -1,6 +1,12 @@
1
1
  ---
2
2
  name: refine
3
- description: Interview-driven plan refiner with built-in audit loop. Takes a draft, a topic, or the active conversation; fans out research agents; interviews via AskUserQuestion until further questions would be impractical hypotheticals; writes the plan to the Obsidian vault under Research/<topic>/<slug>.md; then loops a general-purpose audit and fix pass (both with plan-quality rubrics) until the plan is clean, with a sibling <slug>-implementation-notes.html capturing design decisions, deviations, tradeoffs, and open questions across iterations. The interview is mandatory and the vault is the only output target — these survive any session-level "no clarifying questions" or local plans/ shortcuts. Use when the user says /refine, "refine this", "turn this into a plan", "flesh this out", "make a spec for this", "let's plan this out", or asks for a vague idea to be matured into a plan. Always operates on plans — skill plans, new-code implementation plans, or code-refinement plans.
3
+ description: >-
4
+ Interview-driven plan refiner with built-in audit loop: fans out research agents,
5
+ interviews via AskUserQuestion (mandatory — survives no-question directives), writes
6
+ the plan to the Obsidian vault under Research/<topic>/<slug>.md, then loops audit and
7
+ fix until clean. Triggers: /refine, "refine this", "turn this into a plan", "flesh
8
+ this out", "make a spec for this", "let's plan this out", or any vague idea to mature
9
+ into a plan.
4
10
  ---
5
11
 
6
12
  # refine
@@ -164,7 +170,7 @@ Spawn `general-purpose` (`subagent_type: general-purpose`, foreground) with:
164
170
  - **Ambiguity** — no parked open questions where a decision is required for implementation to begin
165
171
  - **Implementer-readiness** — a downstream implementer can act on each step without back-and-forth (file paths named, agents named, change concrete)
166
172
  - A required return shape: structured findings as `severity (P0/P1/P2) | location | violation`, plus an explicit `CLEAN` verdict when no findings remain
167
- - An explicit instruction NOT to apply code-review rubrics (CODE_RULES categories A–N, API contracts, resource cleanup, etc.) — the audit target is a markdown plan, not source code
173
+ - An explicit instruction NOT to apply code-review rubrics (CODE_RULES categories A–P, API contracts, resource cleanup, etc.) — the audit target is a markdown plan, not source code
168
174
 
169
175
  If the verdict is `CLEAN`: skip step 8 and proceed to step 10.
170
176
 
@@ -1,16 +1,11 @@
1
1
  ---
2
2
  name: structure-prompt
3
3
  description: >-
4
- Restructure any user-provided prompt order blocks correctly, replace persona
5
- framing with task constraints, enforce per-category dispositions, replace
6
- ceremony directives with measurable constraints, expand placeholder tokens
7
- into real values via the sibling rubric or AskUserQuestion, add file:line
8
- citations for identifiers that appear in the data body, mark the canonical
9
- sub-bucket with ⭐, and sharpen generic adversarial-pass phrasing into a
10
- category-specific failure-mode noun. Trigger when the user invokes
11
- /structure-prompt, pastes a prompt and asks to optimize it, asks for a
12
- "minimally invasive edit" to a prompt artifact, or asks to "tighten this
13
- prompt."
4
+ Restructure a user-provided prompt: order blocks, replace persona framing with task
5
+ constraints, enforce per-category dispositions, expand placeholder tokens via the
6
+ sibling rubric or AskUserQuestion, add file:line citations, mark the canonical
7
+ sub-bucket, sharpen adversarial-pass phrasing. Triggers: /structure-prompt, "optimize
8
+ this prompt", "minimally invasive edit" to a prompt artifact, "tighten this prompt".
14
9
  ---
15
10
 
16
11
  # structure-prompt