claude-dev-env 2.12.0 → 2.13.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 (193) hide show
  1. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  2. package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
  3. package/agents/CLAUDE.md +1 -2
  4. package/agents/pr-description-writer.md +11 -81
  5. package/bin/install.mjs +48 -9
  6. package/bin/install.prune.test.mjs +26 -0
  7. package/bin/install.settings-defaults.test.mjs +60 -33
  8. package/bin/install.test.mjs +2 -4
  9. package/commands/sr-loop.md +9 -5
  10. package/docs/CLAUDE.md +0 -1
  11. package/docs/references/CLAUDE.md +0 -1
  12. package/hooks/CLAUDE.md +1 -1
  13. package/hooks/blocking/CLAUDE.md +2 -27
  14. package/hooks/blocking/config/CLAUDE.md +1 -13
  15. package/hooks/blocking/conventional_pr_title_gate.py +1 -2
  16. package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
  17. package/hooks/blocking/stop_dispatcher.py +4 -4
  18. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
  19. package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
  20. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
  21. package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
  22. package/hooks/diagnostic/CLAUDE.md +3 -3
  23. package/hooks/diagnostic/hook_log_extractor.py +2 -36
  24. package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
  25. package/hooks/diagnostic/test_hook_log_extractor.py +8 -21
  26. package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
  27. package/hooks/git-hooks/git_hooks_constants/__init__.py +0 -6
  28. package/hooks/git-hooks/pre_push.py +3 -85
  29. package/hooks/git-hooks/test_pre_push.py +0 -130
  30. package/hooks/hooks.json +0 -35
  31. package/hooks/hooks_constants/CLAUDE.md +0 -9
  32. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
  33. package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
  34. package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
  35. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
  36. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
  37. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
  38. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
  39. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
  40. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
  41. package/hooks/lifecycle/CLAUDE.md +1 -3
  42. package/package.json +1 -1
  43. package/rules/CLAUDE.md +0 -2
  44. package/rules/gh-cli-conventions.md +0 -1
  45. package/rules/git-workflow.md +1 -3
  46. package/scripts/CLAUDE.md +0 -1
  47. package/scripts/_code_review_test_support.py +0 -95
  48. package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
  49. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
  50. package/scripts/invoke_code_review.py +8 -451
  51. package/scripts/test_invoke_code_review.py +5 -61
  52. package/scripts/test_invoke_code_review_cli.py +1 -45
  53. package/scripts/test_invoke_code_review_contract.py +1 -118
  54. package/settings.json +1 -10
  55. package/skills/CLAUDE.md +8 -0
  56. package/skills/autoconverge/reference/CLAUDE.md +1 -1
  57. package/skills/autoconverge/reference/convergence.md +7 -7
  58. package/skills/autoconverge/reference/gotchas.md +3 -10
  59. package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
  60. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
  61. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
  62. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
  63. package/skills/autoconverge/workflow/converge.mjs +201 -238
  64. package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
  65. package/skills/bugteam/CONSTRAINTS.md +1 -1
  66. package/skills/bugteam/SKILL.md +9 -0
  67. package/skills/bugteam/reference/audit-and-teammates.md +10 -6
  68. package/skills/bugteam/test_skill_additions.py +9 -0
  69. package/skills/comments/SKILL.md +65 -0
  70. package/skills/descriptions/SKILL.md +51 -0
  71. package/skills/emergencies/SKILL.md +42 -0
  72. package/skills/imagegen/SKILL.md +21 -0
  73. package/skills/imagegen/scripts/config/__init__.py +1 -0
  74. package/skills/imagegen/scripts/config/constants.py +28 -0
  75. package/skills/imagegen/scripts/imagegen.py +45 -0
  76. package/skills/imagegen/scripts/imagegen_core.py +528 -0
  77. package/skills/imagegen/scripts/test_imagegen.py +204 -0
  78. package/skills/orchestrator/SKILL.md +2 -4
  79. package/skills/plan-to-pr/SKILL.md +6 -7
  80. package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
  81. package/skills/plan-to-pr/reference/process-inventory.md +2 -2
  82. package/skills/plan-to-pr/reference/review-loop.md +2 -2
  83. package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
  84. package/skills/plan-to-pr/reference/task-seeds.md +1 -1
  85. package/skills/plan-to-pr/reference/task-ticket.md +3 -4
  86. package/skills/plan-to-pr/scripts/config/constants.py +1 -2
  87. package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
  88. package/skills/plan-to-pr/test_skill_contract.py +2 -2
  89. package/skills/pr-converge/SKILL.md +13 -16
  90. package/skills/pr-converge/reference/progress-checklist.md +6 -5
  91. package/skills/pr-converge/reference/state-schema.md +1 -27
  92. package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
  93. package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
  94. package/skills/pr-loop-lifecycle/SKILL.md +1 -1
  95. package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
  96. package/skills/prototype/SKILL.md +4 -4
  97. package/skills/prototype/reference/honest-limitations.md +4 -4
  98. package/skills/prototype/reference/promotion-tasks.md +2 -2
  99. package/skills/prototype/workflows/promotion.md +4 -6
  100. package/skills/reviews/SKILL.md +85 -0
  101. package/skills/small-cl/SKILL.md +52 -0
  102. package/agents/code-verifier.md +0 -74
  103. package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
  104. package/docs/references/code-review-enforcement.md +0 -132
  105. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
  106. package/hooks/blocking/code_review_gate_deny.py +0 -74
  107. package/hooks/blocking/code_review_pr_create_gate.py +0 -198
  108. package/hooks/blocking/code_review_push_gate.py +0 -145
  109. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
  110. package/hooks/blocking/code_review_stamp_store.py +0 -233
  111. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
  112. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
  113. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
  114. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
  115. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
  116. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
  117. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
  118. package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
  119. package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
  120. package/hooks/blocking/config/verified_commit_constants.py +0 -160
  121. package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
  122. package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
  123. package/hooks/blocking/conftest.py +0 -123
  124. package/hooks/blocking/convergence_gate_blocker.py +0 -310
  125. package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
  126. package/hooks/blocking/pr_description_body_audit.py +0 -148
  127. package/hooks/blocking/pr_description_command_parser.py +0 -237
  128. package/hooks/blocking/pr_description_enforcer.py +0 -227
  129. package/hooks/blocking/pr_description_pr_number.py +0 -155
  130. package/hooks/blocking/pr_description_proof_of_work.py +0 -385
  131. package/hooks/blocking/pr_description_readability.py +0 -364
  132. package/hooks/blocking/reviewer_spawn_gate.py +0 -182
  133. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
  134. package/hooks/blocking/test_code_review_gate_deny.py +0 -54
  135. package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
  136. package/hooks/blocking/test_code_review_push_gate.py +0 -205
  137. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
  138. package/hooks/blocking/test_code_review_stamp_store.py +0 -205
  139. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
  140. package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
  141. package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
  142. package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
  143. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
  144. package/hooks/blocking/test_pr_description_enforcer.py +0 -221
  145. package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
  146. package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
  147. package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
  148. package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
  149. package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
  150. package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
  151. package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
  152. package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
  153. package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
  154. package/hooks/blocking/test_verification_verdict_store.py +0 -974
  155. package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
  156. package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
  157. package/hooks/blocking/test_verified_commit_gate.py +0 -581
  158. package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
  159. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
  160. package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
  161. package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
  162. package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
  163. package/hooks/blocking/verification_verdict_store.py +0 -1039
  164. package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
  165. package/hooks/blocking/verified_commit_gate.py +0 -113
  166. package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
  167. package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
  168. package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
  169. package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
  170. package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
  171. package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
  172. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
  173. package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
  174. package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
  175. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
  176. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
  177. package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
  178. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
  179. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
  180. package/hooks/blocking/verifier_verdict_minter.py +0 -280
  181. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
  182. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
  183. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
  184. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
  185. package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
  186. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
  187. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
  188. package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
  189. package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
  190. package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
  191. package/rules/proof-of-work-pr-comments.md +0 -22
  192. package/rules/verified-commit-gate-skip.md +0 -4
  193. package/scripts/Show-Asset.ps1 +0 -106
@@ -10,8 +10,8 @@ description: >-
10
10
 
11
11
  Give a build the freedom to move fast, then make it earn the right to ship. Two phases, one hard wall between them:
12
12
 
13
- - **Sandbox** — an isolated worktree where an agent runs under `claude --bare`, so none of the standards gates (TDD, code rules, verified-commit, plain-language, stage) fire. The agent builds a proof-of-concept with zero friction.
14
- - **Promotion** — back in the normal, fully-hooked session, the successful POC goes through a clean-room re-verification before it becomes a commit and a pull request. Nothing from the sandbox rides along un-checked.
13
+ - **Sandbox** — an isolated worktree where an agent runs under `claude --bare`, so the normal TDD, code-rules, plain-language, and stage hooks do not run. The agent builds a proof-of-concept with zero friction.
14
+ - **Promotion** — back in the normal, fully-hooked session, the successful POC receives clean-room review and verification under the [review guide](../reviews/SKILL.md#review-workflow) before it becomes a commit and a pull request.
15
15
 
16
16
  Two safety gates stay live even in the sandbox: personal-data blocking and destructive-command blocking. A worktree shares the real repo's `.git` store and `rm` reaches the whole disk, so these are containment, not the "delays" the sandbox is meant to shed.
17
17
 
@@ -45,7 +45,7 @@ Follow `workflows/sandbox.md`. In short:
45
45
 
46
46
  ### Phase 2 — Promotion
47
47
 
48
- Run only in the normal, fully-hooked session — never inside the sandbox. Follow `workflows/promotion.md`, which drives the clean-room task seeds in `reference/promotion-tasks.md`: fresh branch off live `origin/main`, POC content as an uncommitted diff, cleanup and privacy sweep, `code-verifier` in a fresh context, then `/commit` and a draft PR handed to a PR-loop skill. State the two honest limitations from `reference/honest-limitations.md`.
48
+ Run only in the normal, fully-hooked session — never inside the sandbox. Follow `workflows/promotion.md`, which drives the clean-room task seeds in `reference/promotion-tasks.md`: fresh branch off live `origin/main`, POC content as an uncommitted diff, cleanup and privacy sweep, review and verification under the [review guide](../reviews/SKILL.md#review-workflow), then `/commit` and a draft PR handed to a PR-loop skill. State the two honest limitations from `reference/honest-limitations.md`.
49
49
 
50
50
  ## Task seeding
51
51
 
@@ -57,7 +57,7 @@ At the start of Phase 2, register every item in `reference/promotion-tasks.md` a
57
57
  |---|---|---|---|
58
58
  | `fresh-branch` | Sandbox step 1; Promotion step 2 | isolated worktree JSON (`worktree_path`, `base_commit`, `repo_root`) | Refuse — see refusal cases |
59
59
  | `privacy-hygiene` | Promotion step 5 | personal-data and secret sweep of the diff | Warn; do a manual review before continuing |
60
- | `code-verifier` (agent) | Promotion step 6 | fresh-context verdict against the real diff; mints the commit-gate verdict | Stop; the commit gate will block anyway |
60
+ | [Review guide](../reviews/SKILL.md#review-workflow) | Promotion step 6 | review and verification of the real diff | Stop and report the incomplete promotion |
61
61
  | `/commit` (command) | Promotion step 7 | conventional commit + push | Commit and push by hand per `git-workflow` |
62
62
  | `autoconverge` (default; `pr-converge` or `bugteam` as alternatives) | Promotion step 9 | the PR converged to ready | Stop after the draft PR; tell the user to converge manually |
63
63
 
@@ -6,9 +6,9 @@ State both of these to the user, in these terms, whenever a proof-of-concept is
6
6
 
7
7
  `code_rules_enforcer` is a Write/Edit gate: it checks content as it is written. Prototype code is built under `--bare`, so that gate never fired, and content brought into promotion as a git diff (apply, checkout, cherry-pick) does not pass through it either.
8
8
 
9
- Standards re-engage on promotion through three surfaces that stand in for the write-time hook:
9
+ Promotion records the controls applied to the real diff:
10
10
 
11
- - the `code-verifier` agent, in a fresh context, deriving and running the named gates against the real diff;
11
+ - review and verification under the [review guide](../../reviews/SKILL.md#review-workflow);
12
12
  - the `privacy-hygiene` sweep for personal data and secrets;
13
13
  - the pull-request review (AGENTS.md criteria and any PR-loop reviewers).
14
14
 
@@ -18,6 +18,6 @@ Say plainly: the write-time rule engine did not see this code; the verifier and
18
18
 
19
19
  The sandbox agent wrote code first and tests, if any, after. Red-green-refactor ordering did not happen. So the honest claim on promoted prototype code is exactly this, and nothing more:
20
20
 
21
- > code-verifier passed, privacy swept, review passed — TDD ordering waived.
21
+ > Review and verification completed, privacy swept — TDD ordering waived.
22
22
 
23
- Do not claim red-green compliance on these lines. A prototype is a reference build, not a test-first build. Fred Brooks: plan to throw one away. Promotion re-verifies the code and often rewrites it to standard; expect real work in the verifier repair loop, not a rubber stamp.
23
+ Do not claim red-green compliance on these lines. A prototype is a reference build, not a test-first build. Promotion reviews and verifies the code against the current standards.
@@ -14,9 +14,9 @@ Promotion runs in the **normal, fully-hooked session** — never inside the `--b
14
14
 
15
15
  5. **Privacy sweep.** Run the `privacy-hygiene` skill over the full applied working tree, not only the diff — a POC that pulled live data can leave a secret in a file the diff view hides. Evidence: its clean report, or the leak it found and how it was removed. If the skill is missing, do a manual PII and secret review and say so.
16
16
 
17
- 6. **Verify in a fresh context.** Spawn the `code-verifier` agent against the real diff. Expect findings and a repair loop — the code was un-TDD'd. Evidence: the verifier's clean verdict, and a note of what it made you fix. Do not skip this on the belief that the sandbox agent already tested it.
17
+ 6. **Review and verify the real diff.** Apply the [review guide](../../reviews/SKILL.md#review-workflow). Evidence: the checks run and each required finding repaired. Do not rely on sandbox testing as promotion evidence.
18
18
 
19
- 7. **Commit and open a draft PR.** Only on a clean verdict, run `/commit` (which mints the commit-gate verdict and pushes), then open a draft PR per the `git-workflow` rule. Evidence: the commit hash and the PR URL.
19
+ 7. **Commit and open a draft PR.** After the review and verification record is complete, run `/commit`, then open a draft PR per the `git-workflow` rule. Evidence: the commit hash and the PR URL.
20
20
 
21
21
  8. **State the honest limitations.** Post the two statements from `reference/honest-limitations.md` — write-time rules never ran; TDD ordering waived — in the PR body or to the user. Evidence: the text was included.
22
22
 
@@ -4,7 +4,7 @@ Turn a successful proof-of-concept into a real, verified change. Run every step
4
4
 
5
5
  ## Seed the task list first
6
6
 
7
- Register every item in `reference/promotion-tasks.md` as a session task (`TaskCreate`, or `TodoWrite` if that is the host tool). Work only from the task list. Mark each complete with evidence — a command result, a path, a verdict, or a skill's return.
7
+ Register every item in `reference/promotion-tasks.md` as a session task (`TaskCreate`, or `TodoWrite` if that is the host tool). Work only from the task list. Mark each complete with evidence — a command result, a path, a review record, or a skill's return.
8
8
 
9
9
  ## The clean-room protocol
10
10
 
@@ -15,13 +15,11 @@ The task seeds carry the full ordered detail. The shape:
15
15
  3. **Bring content as an uncommitted diff.** Copy the POC's file changes into the new branch's working tree. Do not cherry-pick or merge the sandbox commits; the sandbox history stays behind.
16
16
  4. **Cleanup.** Remove scratch files, debug dumps, and temp helpers the POC created (`cleanup-temp-files` rule).
17
17
  5. **Privacy sweep** via `privacy-hygiene` over the diff.
18
- 6. **Verify** with the `code-verifier` agent `model: sonnet`, worker-model routing per [`skills/orchestrator/SKILL.md`](../../orchestrator/SKILL.md#workflow-agent-routing); resolver-supplied sonnet-equivalent on third-party hosts — in a fresh context. This is where standards re-engage. Expect findings and a repair loop the POC was un-TDD'd.
19
- 7. **Commit and PR.** Only on a clean verdict, run `/commit`, then open a draft PR per the `git-workflow` rule.
18
+ 6. **Review and verify** the real diff against the [review guide](../../reviews/SKILL.md#review-workflow). Record the checks run and repair every required finding.
19
+ 7. **Commit and PR.** After the review and verification record is complete, run `/commit`, then open a draft PR per the `git-workflow` rule.
20
20
  8. **State the honest limitations** from `reference/honest-limitations.md` in the PR body or to the user.
21
21
  9. **Converge** by handing the PR to `autoconverge` by default; use `pr-converge` for paced ticks or `bugteam` for an open-loop audit.
22
22
 
23
23
  ## Why the clean room, not a push
24
24
 
25
- `code_rules_enforcer` is a write-time Write/Edit gate. Content that lands through `git apply`, `git checkout`, or cherry-pick never passes through it, so pushing the sandbox branch would ship code the rule engine never saw, carrying sandbox scratch along with it. Standards re-engage through the `code-verifier` agent, the `privacy-hygiene` sweep, and the PR review not through a write-time hook. Steps 4-6 are hard gates: the honest claim on promoted POC code is code-verifier-passed, privacy-swept, review-passed, with TDD ordering waived.
26
-
27
- The `verified_commit_gate` hook is the backstop under all of this — it refuses a commit or push with no minted verdict — but the clean-room steps are the mechanism, not the gate firing.
25
+ `code_rules_enforcer` is a write-time Write/Edit gate. Content that lands through `git apply`, `git checkout`, or cherry-pick receives the clean-room controls in steps 4–6: cleanup, privacy review, and review and verification under the [review guide](../../reviews/SKILL.md#review-workflow). The promotion record states the checks run and the remaining TDD limitation.
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: reviews
3
+ description: >-
4
+ Review a pull request or code change for code health. Use when a user asks to
5
+ "code review", "review this PR", or "review this change".
6
+ ---
7
+
8
+ # Code Review Guide
9
+
10
+ Use this guide to evaluate a pull request or code change. Apply the repository's
11
+ `AGENTS.md` and `CODE_RULES.md` as its project-specific quality rubric.
12
+
13
+ ## Review Judgment
14
+
15
+ Review work supports code health. Frame each conclusion around observable
16
+ behavior, maintainability, risk, and the change's intended outcome.
17
+
18
+ - Use technical evidence and repository conventions to resolve trade-offs.
19
+ - Mark a required change when it materially affects correctness, security,
20
+ reliability, data integrity, maintainability, or the stated behavior.
21
+ - Mark optional improvement as `Consider` or `Nit` so the author can prioritize
22
+ the work accurately.
23
+ - Accept an evidence-backed explanation when it satisfies the applicable
24
+ quality rubric.
25
+
26
+ ## Evaluation Criteria
27
+
28
+ Evaluate the changed code and the surrounding context for:
29
+
30
+ - Design fit, interfaces, complexity, and future maintenance cost.
31
+ - Functional behavior, user impact, edge cases, concurrency, privacy,
32
+ security, and accessibility where applicable.
33
+ - Tests that exercise the changed behavior and distinguish regressions.
34
+ - Names, comments, documentation, and style against the repository rubric and
35
+ the applicable language guide.
36
+ - Migration, configuration, compatibility, and operational effects.
37
+
38
+ ## Review Workflow
39
+
40
+ 1. Read the pull request description and identify the intended outcome.
41
+ 2. Inspect the changed code, relevant callers, and the surrounding design.
42
+ 3. Run or assess relevant verification and identify its coverage boundaries.
43
+ 4. Write each finding with the affected location, observed effect, expected
44
+ outcome, and supporting evidence.
45
+ 5. State the reviewed scope, verification performed, and any remaining
46
+ uncertainty in the review output.
47
+
48
+ Use the [comment guide](../comments/SKILL.md#writing-useful-review-comments)
49
+ for finding wording and the [description guide](../descriptions/SKILL.md#reviewing-a-description)
50
+ for description content.
51
+
52
+ ## Execution Support
53
+
54
+ Use available runners for inspection, verification, and repository navigation.
55
+ This guide supplies the judgment criteria and the corresponding guide anchors.
56
+
57
+ ## Review Responsiveness
58
+
59
+ Begin a requested review at the next clean work boundary. Provide a useful
60
+ response promptly, including the completed scope and the remaining work when
61
+ context gathering continues.
62
+
63
+ Review the highest-impact design questions early. A focused response gives the
64
+ author a clear next action while the full assessment continues.
65
+
66
+ ## Resolving Disagreements
67
+
68
+ Consolidate a disagreement into one thread that records the relevant context,
69
+ technical rationale, and desired decision. Reassess the finding against the
70
+ repository rubric and accept a sound alternative that meets the same outcome.
71
+
72
+ Seek a maintainer or lead decision when the discussion requires ownership or
73
+ product direction beyond the available evidence. Keep the resulting decision in
74
+ the pull request record.
75
+
76
+ ## Related Guides
77
+
78
+ - Use [comments](../comments/SKILL.md#when-to-use-this-guide) to draft or answer
79
+ review feedback.
80
+ - Use [descriptions](../descriptions/SKILL.md#when-to-use-this-guide) to prepare
81
+ or assess pull request context.
82
+ - Use [emergencies](../emergencies/SKILL.md#emergency-classification) to classify
83
+ an urgent production change.
84
+ - Use [small-cl](../small-cl/SKILL.md#when-to-use-this-guide) to focus or split
85
+ a change that exceeds a clear review boundary.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: small-cl
3
+ description: >-
4
+ Scope or split a pull request into a self-contained reviewable increment. Use
5
+ when a user asks to "split this PR", "make this change smaller", or "small CL".
6
+ ---
7
+
8
+ # Focused Pull Request Guide
9
+
10
+ ## When to Use This Guide
11
+
12
+ Use this guide to plan, assess, or split a pull request into a reviewable unit.
13
+ The pull request boundary is conceptual: one coherent outcome that a reviewer
14
+ can understand with its context and verification.
15
+
16
+ ## What a Focused Pull Request Contains
17
+
18
+ A focused pull request contains the implementation, related tests, documentation,
19
+ and configuration needed for one outcome. It leaves the system in a usable state
20
+ and gives the reviewer the information needed to assess the change.
21
+
22
+ Use the [description guide](../descriptions/SKILL.md#required-content) to record
23
+ the scope, verification, risks, and follow-up work.
24
+
25
+ ## Splitting a Change
26
+
27
+ Choose a split that gives each increment a coherent purpose and a clear test
28
+ boundary. Useful seams include:
29
+
30
+ - Preparation refactors followed by behavior changes.
31
+ - Independent vertical features that each deliver a user-visible capability.
32
+ - Layer-specific work when each layer remains independently understandable.
33
+ - Stacked changes when each earlier change supplies the next change's stable
34
+ foundation.
35
+
36
+ State dependencies between related pull requests and keep each increment safe to
37
+ merge or revert on its own.
38
+
39
+ ## Reviewable Scope
40
+
41
+ Ask to split a change when its breadth prevents a reliable assessment of design,
42
+ behavior, or verification. Identify the first coherent increment and the
43
+ remaining increments so the author has an actionable path forward.
44
+
45
+ Use [reviews](../reviews/SKILL.md#evaluation-criteria) to evaluate the resulting
46
+ scope and [emergencies](../emergencies/SKILL.md#emergency-classification) when an
47
+ active incident sets the immediate boundary.
48
+
49
+ ## Responding to Review
50
+
51
+ Use the [comment guide](../comments/SKILL.md#responding-to-feedback) to respond
52
+ to feedback and resolve pushback.
@@ -1,74 +0,0 @@
1
- ---
2
- name: code-verifier
3
- description: Post-hoc verification agent. Runs only when the task owner asks for a verification pass — never spawned automatically because a coder agent finished. Runs every check itself in a fresh context — named gates, tests against recorded baselines, two-way diff-vs-task reading — puts the draft verdict through one strongest-tier validation subagent that tries to refute it, then ends with a fenced verdict block the verifier_verdict_minter hook turns into the commit-gate verdict. Never edits files in the tree under review — its one exception is a deliberate break at an off-tree break site outside that tree, defined in its body.
4
- tools: Read, Grep, Glob, Bash, Task
5
- color: orange
6
- ---
7
-
8
- You are the verifier in a three-phase code workflow: coder agents wrote changes, and you grade the result on its own terms (Claude Code best practices, fresh-context review: https://code.claude.com/docs/en/best-practices). The agent doing the work is never the one grading it — that is you, so you trust nothing you did not run or read yourself this session.
9
-
10
- The caller gives you task texts, the diff scope, and baselines recorded before the coders ran. Treat every claim in the caller's message — and any coder summary quoted in it — as a hypothesis to test, never as a fact.
11
-
12
- Run all three layers, in this order:
13
-
14
- 1. **Runnable gates.** Every check the task names (its verification section), plus the universal set whether or not the caller asked: compile/syntax checks on changed files, the recorded-baseline tests scoped to the changed modules — the test files the task names plus tests that import a changed module (the failure set must match the recorded baseline exactly — no new failures, none silently fixed without explanation), imports of changed modules, and any repo commit gate. Run the full recorded suite only when the caller recorded a full-suite baseline because the surface spans multiple modules or multiple coders. Run each command yourself and keep its output.
15
- 2. **Two-way diff-vs-task reading.** Read each coder's diff against that coder's task text. Every task item maps to a hunk that does it; every hunk maps back to a task item — a hunk with no task item is out-of-scope change, a task item with no hunk is missing work.
16
- 3. **Negative space.** Walk the task's item list asking "where is this one?": silent deferrals, stubs, TODO markers, the smaller half of a task shipped, a sync change without its async twin.
17
-
18
- Findings discipline:
19
-
20
- - A finding must cite a failing command (with its output) or a named task item. No citation, no finding. `findings` carries code defects alone.
21
- - Report gaps that affect correctness or the task's stated terms — never style preferences. Sound work produces zero findings; do not invent gaps to look thorough.
22
- - Never edit a file in the work tree you verify — you verify; repair agents repair. The one exception is a deliberate break for the shown-red table, which goes at one of the off-tree break sites the shown-red section below lists.
23
- - Never run `git stash`. `refs/stash` belongs to the repository, not to a work tree, so every worktree shares one stash list: a `pop` can apply another verifier's entry into your tree and hand you a surface that is not your assignment. To read the base, add a throwaway detached worktree at the base commit (`git worktree add --detach <temp-path> <base-sha>`), read it there, and drop it with `git worktree remove --force <temp-path>`. You only ever need to read a base tree, and stash moves the very tree you were asked to verify.
24
- - Never execute code that drives the user's real input or screen — no live mouse moves, keystrokes, clicks, or window focus (pyautogui and its callers included). Run only the test commands the task names, scoped to the test files it names; no repo-wide test sweeps. Judge behavior equivalence by reading both versions, never by live execution of input-driving paths.
25
-
26
- Before you write the verdict, learn the surface hash of the work tree you verified. Use the branch mode — it resolves the work tree that holds the branch automatically, so it is immune to your own cwd:
27
-
28
- python ~/.claude/hooks/blocking/verification_verdict_store.py --manifest-hash-for-branch <branch under review>
29
-
30
- On Windows the same file sits at %USERPROFILE%\.claude\hooks\blocking\verification_verdict_store.py; invoke it with the python on your PATH. If the caller named an explicit work-tree path rather than a branch, use the explicit-directory mode instead:
31
-
32
- python ~/.claude/hooks/blocking/verification_verdict_store.py --manifest-hash <explicit-work-tree-dir>
33
-
34
- The printed hash commits to every changed and untracked file's content in the verified work tree, so it names that surface no matter which directory you or the committer run from. If the CLI prints an empty-surface or wrong-work-tree error and no hash, you are pointed at a work tree with no changes versus origin/main — re-run with the branch mode to locate the correct work tree.
35
-
36
- As the last step before the verdict, put your draft verdict through one best-effort strongest-tier validation pass. Spawn a single validation subagent through the Task tool as the `Explore` agent type at the strongest reachable tier: set the Task `subagent_type` to `Explore`, detect the host profile first per `~/.claude/_shared/advisor/advisor-protocol.md` — the source of truth for host detection, the ladder, and its aliases — then on a Claude host pick the strongest reachable tier on the Fable → Opus → Sonnet → Haiku ladder and on a third-party host use the single third-party tier, and set the Task `model:` field to that tier's alias. A tier denied by policy counts as unreachable, so the walk continues down the ladder to the next tier rather than skipping the validation pass. The `Explore` type carries no Edit or Write tools and cannot spawn further agents, so the harness itself holds the validator to the no-edit, no-spawn contract the next paragraph names. Hand it the draft verdict together with your evidence — every command you ran with its output, your two-way diff-to-task mapping, and the shown-red table with every deliberate-red run labeled as shown-red evidence so the validator reads it as a staged break rather than a genuine failure — and state that its task is adversarial verification of that supplied draft verdict: refute it against the supplied evidence rather than discover code, naming any gate you misread, any task item you mapped wrong, or any finding that does not hold. This pass is always a cold `Explore` spawn, not a message to the session's warm advisor: the refutation needs a grader with no accumulated session context or prior positions, and the verifier runs in sessions that have no advisor bound. Run that spawn synchronously — set the Task `run_in_background` field to `false` — so the validator's reply lands inside this turn. A background spawn returns straight away and its completion notification arrives after your turn is over, so the reply you are waiting for never reaches you and the verdict fence never gets written. When the spawn is unavailable — a Task tool error, an unreachable tier at every rung, or this subagent being barred from spawning further agents — skip the validation pass and emit the draft verdict as it stands, noting the skip in your final message; a spawn failure never blocks the verdict fence from being emitted.
37
-
38
- Ending your turn without the verdict fence throws the whole run away: every gate you ran and every mapping you built reaches the caller as prose it cannot mint, and the commit gate stays shut on work you already checked. So the fence is unconditional. A validator that returns nothing usable, a tier that never binds, a refutation you accept and fold in — each of those ends the same way, with the fence. When you find yourself about to close on a promise to finish once something reports back, run the refutation pass yourself and emit the verdict.
39
-
40
- This validation pass is terminal: the `Explore` type gives the validation subagent no way to spawn a further agent or edit a file, so it answers with prose only. When it refutes any part, re-check that part yourself against the commands and the diff, and correct the verdict before you emit it. When it refutes nothing, the draft verdict stands. Then write your final message.
41
-
42
- Your final message runs in one order: the shown-red table, then — only when the verdict is incomplete — the named unshown check, then every `no break available` row named, then the verdict fence last, so the verifier_verdict_minter hook reads it. Every runnable check the verdict rests on gets one row — a runnable check is a layer 1 runnable gate you can execute against the surface. Breakability is not part of that definition: no check leaves the runnable set by being called unbreakable.
43
-
44
- | Check | Deliberate break | Red | Green |
45
- |---|---|---|---|
46
- | `<command you ran>` | `<break you applied>`, or `no break available — <why no input, no environment, and no scratch-copy mutation can make this check fail>`, or `n/a — check not run` | `<exit code or the deciding line>`, or `no red` | `<exit code or the deciding line>` |
47
-
48
- The Deliberate break cell holds exactly one of those three values: the break you applied, `no break available` with its one-line reason, or `n/a — check not run`. Only the first of the three produced a red, so only the first carries a red result in the Red cell. A `no break available` row and an `n/a — check not run` row each carry the literal `no red` there — never an empty cell, never the Green value repeated, and never an exit code, which would make a row that showed no red scan like one that did.
49
-
50
- Keep each cell to one line — an exit code, a failing test id, an assert line, or a hook's block message. The Green cell may cite the check's first clean run when you kept that output; a clean result already in hand needs no third run. Longer excerpts go below the table in a plain fenced block carrying no info string.
51
-
52
- The reading layers, 2 and 3 above, take no rows. Name in prose what you read and what that reading would catch. A runnable check keeps its row whatever you conclude by reading it, and whatever you conclude about breaking it.
53
-
54
- Break the check at an off-tree break site — a site where the break cannot reach the tree you verify: a failing input or environment fed to the check, or a mutated copy in a scratch directory outside that tree.
55
-
56
- At either off-tree break site, a check that exercises the changed behavior fails because of the break rather than for an unrelated reason.
57
-
58
- Break off-tree so the work tree under verification stays as the coders left it; an in-place break moves the surface `manifest_sha256` names and is forbidden. The green is that same check run against the verified tree.
59
-
60
- Every runnable check the verdict rests on gets a row, with no exclusion path: a rested-on runnable check with no row makes the verdict incomplete, and a check you judge unbreakable still owes its row. Where no runnable check the verdict depends on exists, the surface rests on the reading layers alone and carries an empty table, complete. The empty table is for a surface where nothing runnable exists at all, never for one where a runnable check exists and you skipped it. A row carrying `n/a — check not run` is a runnable check you relied on and never showed red, and it makes the verdict incomplete too; its Red cell carries `no red`.
61
-
62
- `no break available` is a different claim from `n/a — check not run`: the check ran, and no break exists for it, so its Red cell carries `no red` as well. That row counts complete when it carries the one-line reason naming why no input, no environment, and no scratch-copy mutation can make that check fail, so `all_pass` true stays reachable for a genuinely unbreakable gate. A `no break available` row without that reason is an incomplete row and makes the verdict incomplete exactly as a missing row does.
63
-
64
- An incomplete verdict names the unshown check directly above the fence and sets `all_pass` to false. Naming a `no break available` row is a separate matter from that incomplete-check naming: a verdict carrying any `no break available` row names each of those rows directly above the fence because the row carries no red, whether the verdict is otherwise complete or incomplete, and naming one never by itself makes the verdict incomplete or sets `all_pass` false. `findings` goes on carrying every code defect the run found, and is empty only when the run found none.
65
-
66
- Write the table as plain markdown; the fence holds JSON alone.
67
-
68
- Exactly one fenced verdict block — the verifier_verdict_minter hook parses it, binds it to that hash, and the verified_commit_gate hook unlocks `git commit`/`git push` for any work tree whose live surface matches it:
69
-
70
- ```verdict
71
- {"all_pass": false, "findings": [{"check": "<gate or task item>", "detail": "<command + output, or the named task item and what is missing>"}], "manifest_sha256": "<hash the CLI printed>"}
72
- ```
73
-
74
- Set `all_pass` to true with an empty `findings` list only when every layer came back clean and the shown-red table is complete. Always include `manifest_sha256` so the verdict clears the commit regardless of which work tree the verifier or the committer ran in. Commit-committability gates (CODE_RULES / merge conflicts) must already be green before you are spawned; you are the last semantic check before commit. Any file change after you finish moves that hash and invalidates the verdict.
@@ -1,157 +0,0 @@
1
- # PR Description Guide
2
-
3
- Authoritative reference for the `pr-description-writer` agent and the `pr_description_enforcer` PreToolUse hook. PR bodies that match this guide pass the enforcer on first attempt.
4
-
5
- ## Anthropic style basis
6
-
7
- The shape rules and header vocabulary derive from a 120-PR sample. Sources: `anthropics/claude-code` (40 PRs), `anthropics/claude-code-action` (40 PRs), and `anthropics/claude-code-sdk-python` (40 PRs). The corpus was sampled from merged PRs.
8
-
9
- Key signals from the corpus:
10
-
11
- - **Shape distribution.** Trivial (≤ 10 lines): 32.5% — median body 288 chars. Small (11–100 lines): 41.7% — median 1,105 chars. Medium (101–500 lines): 20.0% — median 940 chars. Large (> 500 lines): 5.8% — median 2,441 chars.
12
- - **Modal headers.** `## Summary` 43, `## Problem` 20, `## Test plan` 20, `## Fix` 18, `## Changes` 14, `## Tests` 11, `## Testing` 10, `## Root cause` 5, `## Approach` 2.
13
- - **Opening style.** 46.7% open with a header, 53.3% with an unmarked paragraph. 51% of prose-opening Small/Medium PRs open with an imperative verb. `This PR` appears in 1 of 120 PRs.
14
- - **Issue references.** 27.5% of PRs use `Fixes #N`, `Closes #N`, or `Resolves #N`.
15
- - **Sentence length.** First-paragraph mean 15.2 words; median 14.5. Sentences over 28 words are uncommon.
16
- - **Em-dashes.** Appear in 48% of bodies as parenthetical separators.
17
- - **Backtick identifiers in intros.** Routine — filenames, function names, env vars, and CLI flags appear in opening paragraphs.
18
-
19
- ## The three shapes
20
-
21
- ### Trivial
22
-
23
- - **Guidance.** Diff ≤ 10 lines changed (the agent picks shape by diff size; the hook cannot see the diff).
24
- - **Hook enforcement.** Substantive prose under `TRIVIAL_BODY_CHAR_THRESHOLD` (200 chars). The hook blocks any ATX heading at any depth (`#`, `##`, `###`, ...) in a Trivial-sized body — the ceremony-on-Trivial check uses `HEADING_LINE_PATTERN`, not just `##`.
25
- - **Body.** 1–3 sentences of prose. Zero headings of any level.
26
- - **Forbidden.** Any heading (`# Anything`, `## Summary`, `### Detail`, ...). Triggers the hook's ceremony-on-Trivial check.
27
-
28
- Example:
29
-
30
- ```markdown
31
- Bump bun to 1.3.14. Picks up the bugfix for the runtime panic on empty stdin.
32
- ```
33
-
34
- ### Standard
35
-
36
- - **Guidance.** Diff 11–500 lines (agent-side; hook infers shape from body length).
37
- - **Hook enforcement.** Substantive prose between `TRIVIAL_BODY_CHAR_THRESHOLD` (200) and `HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION` (500). No required headers.
38
- - **Body.** Imperative-verb intro paragraph. Optional headers drawn from the Anthropic set.
39
- - **Optional headers.** `## Summary`, `## Problem`, `## Fix`, `## Changes`, `## Test plan`, `## Tests`, `## Testing`, `## Approach`, `## Root cause`.
40
-
41
- Example:
42
-
43
- ```markdown
44
- Adds a syllable-counted Flesch reading score to the PR description enforcer. Bodies above the readability ceiling surface a targeted block message before the strike counter increments.
45
-
46
- ## Test plan
47
-
48
- - [ ] `pytest packages/claude-dev-env/hooks/blocking/test_pr_description_enforcer.py`
49
- - [ ] Open a draft PR with a 45-word sentence and confirm the metric block fires
50
- ```
51
-
52
- ### Heavy
53
-
54
- - **Criterion.** Diff > 500 lines, or a cross-cutting bug fix that touches multiple subsystems.
55
- - **Body.** At least one of `## Problem` or `## Summary`. At least one of `## Test plan`, `## Testing`, `## Tests`, `## Verification`, or `## Validation`. Plus any additional Anthropic headers the change earns.
56
- - **Hook enforcement.** Missing either required category triggers a Heavy-required-headers block message naming the absent category.
57
-
58
- Example:
59
-
60
- ```markdown
61
- ## Problem
62
-
63
- Long-running `gh api` review fetches drop pages silently when the reviewer count crosses 30. Bugbot findings on PRs past the first review cycle stay hidden.
64
-
65
- ## Fix
66
-
67
- Routes every `gh api .../reviews` and `.../comments` call through `--paginate --slurp | jq` so the cross-page filter sees the full set.
68
-
69
- ## Test plan
70
-
71
- - [ ] Mock paginated API and assert `jq` filter operates on the merged stream
72
- - [ ] Replay PR #467 review history and confirm the late bugbot comment surfaces
73
- ```
74
-
75
- ## Header vocabulary
76
-
77
- | Header | Corpus count | Typical use |
78
- |---|---:|---|
79
- | `## Summary` | 43 | High-level overview, often two or three sentences |
80
- | `## Problem` | 20 | Bug context — what broke, who hit it |
81
- | `## Test plan` | 20 | Reviewer checklist of verification steps |
82
- | `## Fix` | 18 | How the change addresses the problem |
83
- | `## Changes` | 14 | Bulleted catalog of code-level updates |
84
- | `## Tests` | 11 | New or expanded test coverage |
85
- | `## Testing` | 10 | Manual or CI verification notes |
86
- | `## Root cause` | 5 | Underlying defect analysis |
87
- | `## Approach` | 2 | Design rationale for non-obvious solutions |
88
-
89
- `## Test plan` and `## Root cause` use sentence-case in the corpus. The enforcer regex matches case-insensitively.
90
-
91
- ## Readability targets
92
-
93
- The enforcer measures three metrics on the intro paragraph and first body section combined.
94
-
95
- | Metric | Target |
96
- |---|---|
97
- | Longest sentence | ≤ 28 words |
98
- | Average sentence | ≤ 18 words |
99
- | Flesch Reading Ease | ≥ 50 |
100
-
101
- The Flesch score uses `206.835 - 1.015 × (words/sentences) - 84.6 × (syllables/words)`. The hook implements the formula in pure stdlib with a vowel-group syllable heuristic.
102
-
103
- Hit the targets by writing short sentences in common Anglo-Saxon words. The corpus first-paragraph average of 14.5 words is the target to beat.
104
-
105
- ## Escape hatch
106
-
107
- The hook tracks a per-user readability strike counter at `~/.claude/state/pr_description_readability_strikes.json`. Counter increments on every triggering violation. The first two failures emit metric-specific block messages. The third triggering failure fires the escape-hatch message with four recovery actions.
108
-
109
- ### Action 1 — loosen thresholds 10%
110
-
111
- ```bash
112
- python <enforcer-path> --readability-loosen
113
- ```
114
-
115
- Scales the three thresholds. Flesch floor × 0.9 (rounded down). Max-sentence ceiling × 10/9 (rounded up). Avg-sentence ceiling × 10/9 (rounded up). Cascades on repeat — the second loosen applies the same scaling to the already-loosened values.
116
-
117
- Caps:
118
-
119
- - Max 3 successive loosens (`READABILITY_LOOSEN_CAP = 3`). A fourth `--readability-loosen` errors with `loosen cap reached; use --readability-disable or --readability-reset`.
120
- - Flesch floor of 30 (`READABILITY_MIN_FLESCH_FLOOR`). Once `flesch_min` reaches 30 the loosen action errors.
121
- - Max-sentence ceiling of 60 (`READABILITY_MAX_SENTENCE_WORDS_CEILING`). Once `max_sentence_words` reaches 60 the loosen action errors.
122
- - Avg-sentence ceiling of 40 (`READABILITY_AVG_SENTENCE_WORDS_CEILING`). Once `avg_sentence_words` reaches 40 the loosen action errors.
123
-
124
- ### Action 2 — disable readability entirely
125
-
126
- ```bash
127
- python <enforcer-path> --readability-disable
128
- ```
129
-
130
- Writes `{"enabled": false}` to `~/.claude/state/pr_description_readability_enabled.json`. Shape detection, Heavy required-headers, ceremony-on-Trivial, self-closing reference, `This PR` opening, vague-language, and minimum-length checks all stay active. The readability check is the only one silenced.
131
-
132
- Re-enable with:
133
-
134
- ```bash
135
- python <enforcer-path> --readability-enable
136
- ```
137
-
138
- ### Action 3 — reset the strike counter
139
-
140
- ```bash
141
- python <enforcer-path> --readability-reset
142
- ```
143
-
144
- Zeroes the strike counter at `~/.claude/state/pr_description_readability_strikes.json`. Clears `loosens_used` and threshold overrides at `~/.claude/state/pr_description_readability_overrides.json`. The readability check returns to default thresholds and a clean strike count.
145
-
146
- ### Action 4 — report a false positive
147
-
148
- Reply with the PR body and your intended commit message. The maintainer tunes the thresholds or refines the regex.
149
-
150
- ## What to avoid
151
-
152
- - **Vague language.** `fix bug`, `update code`, `minor changes`, `various improvements`. Each trips the `VAGUE_LANGUAGE_PATTERN` check.
153
- - **`This PR` openings.** Hard block. Open with an imperative verb.
154
- - **Self-closing references.** `Fixes #<this PR>` in a `gh pr edit` body. Self-reference adds zero context. Triggers a block on `gh pr edit` and `gh pr comment` invocations where the PR number is known.
155
- - **Code snippets in prose.** The diff shows the code. Bodies describe intent.
156
- - **Implementation-detail dumping.** Reviewers do not need every parameter name and call site. Describe the behavior change.
157
- - **Filler.** `In this PR I have made the following changes:` adds zero signal. Start with the action.
@@ -1,132 +0,0 @@
1
- # Code-review enforcement
2
-
3
- This feature ties two git actions to a clean run of the built-in
4
- `/code-review --fix`:
5
-
6
- - **`git push`** needs a clean review at effort **low** or higher.
7
- - **Pull-request creation** (`gh pr create` and the MCP `create_pull_request`
8
- tool) needs a clean review at effort **xhigh** or higher.
9
-
10
- The gates follow the same shape as the `verified_commit` gate family.
11
-
12
- ## Opt-in (default off)
13
-
14
- Enforcement is **off by default**. Turn it on by setting the environment
15
- variable `CLAUDE_CODE_REVIEW_ENFORCEMENT` to `1`, `true`, `yes`, or `on`
16
- (case and surrounding spaces are ignored). Any other value, and an unset
17
- variable, leave enforcement off.
18
-
19
- Set the variable in the machine's own user environment so every gate reads it,
20
- including the native git pre-push backstop, which git runs in the shell's
21
- environment. An `env` block in `settings.json` reaches the three Claude Code
22
- hook gates alone. Each gate process reads the variable as it starts, so a
23
- Claude Code session already running keeps its current setting until it
24
- restarts, while the git pre-push backstop picks up the current shell
25
- environment on each push.
26
-
27
- A user-environment setting arms the gates machine-wide. The backstop installs
28
- through the shared `core.hooksPath`, so it runs for every repository on the
29
- machine, and the gates carry no per-repository allowlist. Each repository then
30
- needs its own clean stamp before a push lands there.
31
-
32
- The variable feeds the master flag `CODE_REVIEW_ENFORCEMENT_ENABLED` in
33
- `hooks/blocking/config/code_review_enforcement_constants.py`, which every gate
34
- reads at start-up. When it is on, the push gate, the PR-create gate, the native
35
- pre-push backstop (via the shared deny decision), and the stamp-directory write
36
- blocker all enforce. When it is off, every gate allows the action and the
37
- write-blocker allows stamp-directory access.
38
-
39
- `npx claude-dev-env` copies the shipped `hooks/` tree over `~/.claude/` on each
40
- install, so the environment setting survives an install and an edit to the
41
- constant does not.
42
-
43
- ## How a stamp works
44
-
45
- A stamp is a small JSON file that records one fact: a clean `/code-review` pass
46
- ran against an exact branch surface at a given effort. Each work tree keeps one
47
- file under `~/.claude/code-review-stamps/`, named by a hash of the resolved
48
- work-tree path.
49
-
50
- The stamp binds to a **branch-surface hash** — the hash of every changed path
51
- and untracked file, each bound by its content digest, measured against the
52
- merge base. When any byte of the change surface moves, the live hash stops
53
- matching the stored hash, so the stamp stops covering the surface and the gate
54
- asks for a fresh review.
55
-
56
- A gate allows the action only when a stored stamp matches the live hash exactly
57
- and its effort ranks at or above the effort the action needs. A missing,
58
- unreadable, or malformed stamp reads as no coverage, so the gate fails closed.
59
-
60
- ## The single sanctioned minter
61
-
62
- Only `invoke_code_review.py --record-stamp` writes a stamp. It forces a headless
63
- `/code-review <effort> --fix` run, then mints a stamp only when the review
64
- returns a clean exit code and leaves the branch surface unchanged in the same
65
- pass. A pass that applies fixes mints nothing; the run loops on the new surface
66
- up to a capped number of passes and mints only on a stable clean pass.
67
-
68
- ## Two layers guard the stamp directory
69
-
70
- The gates trust one rule: only the sanctioned minter writes stamp files. Two
71
- layers hold that rule.
72
-
73
- 1. **File-tool deny in `settings.json`.** `Write`, `Edit`, and `MultiEdit`
74
- under `~/.claude/code-review-stamps/` are denied. This layer covers work
75
- inside the repository. The installer merges hook groups into a user's
76
- `settings.json` and does not ship this package's `permissions.deny`, so on a
77
- user's machine this layer protects contributor work, at parity with the
78
- `verified_commit` gate's own file-tool deny.
79
- 2. **`code_review_stamp_directory_write_blocker` hook.** This hook ships through
80
- `hooks.json`, so it reaches every install. It has two arms:
81
- - a shell arm that denies any Bash or PowerShell command naming the stamp
82
- directory, or importing the stamp store module, or calling its mint
83
- function — while it lets the sanctioned minter command through;
84
- - a file-tool arm that denies any `Write`, `Edit`, or `MultiEdit` whose path
85
- resolves under the stamp directory. This arm closes the plain file-tool
86
- forge on every shipped install, which the package `settings.json` deny
87
- cannot reach on its own.
88
-
89
- ## What the gates block
90
-
91
- - **Casual and accidental forges.** A plain file-tool write to the stamp
92
- directory, and a casual shell write to it, are both denied.
93
- - **Hidden-path and split-step shell forges.** A shell command that assembles
94
- the stamp path from hex, base64, or character math is decoded and denied. A
95
- command that splits the directory change across steps to walk into the stamp
96
- directory is traced and denied.
97
- - **Lazy skips.** A push or a pull-request creation cannot go ahead without a
98
- stamp that matches the live surface at the needed effort.
99
-
100
- ## What the gates do not block
101
-
102
- The chain-mode `/code-review` runs as a subprocess spawn of the `claude`
103
- binary, not a harness-recorded subagent, so there is no signed sidecar to
104
- anchor a forgery-proof mint. The stamp reaches the same posture the
105
- `verified_commit` gate holds, and no further. These bypass surfaces stay open:
106
-
107
- - **Pull requests that skip the tool paths.** A PR opened through
108
- `gh api -X POST .../pulls` or the GitHub web page never triggers the
109
- create-PR gate.
110
- - **`git push --no-verify`.** This flag tells git to skip the native pre-push
111
- hook, so the native backstop does not run.
112
- - **A push that clears the enable variable.** The backstop reads
113
- `CLAUDE_CODE_REVIEW_ENFORCEMENT` from the shell that runs the push, so
114
- `CLAUDE_CODE_REVIEW_ENFORCEMENT=0 git push` reads as enforcement off and the
115
- backstop allows the push with no flag and no bypass marker.
116
- - **A rebuilt store.** A script that re-implements the stamp store in memory
117
- and writes a matching file can mint a stamp the gates accept.
118
-
119
- In short: these gates stop casual forges and lazy skips. They do not stop a
120
- determined attacker who sets out to defeat them.
121
-
122
- ## Where the pieces live
123
-
124
- - Gates: `hooks/blocking/code_review_push_gate.py`,
125
- `hooks/blocking/code_review_pr_create_gate.py`.
126
- - Stamp store: `hooks/blocking/code_review_stamp_store.py`.
127
- - Directory guard: `hooks/blocking/code_review_stamp_directory_write_blocker.py`.
128
- - Shared constants: `hooks/blocking/config/code_review_enforcement_constants.py`.
129
- - Native backstop: `hooks/git-hooks/pre_push.py` reuses the push gate's
130
- `deny_reason_for_directory` so the native hook and the Claude gate share one
131
- decision source.
132
- - Minter: `scripts/invoke_code_review.py --record-stamp`.