claude-dev-env 2.4.0 → 2.5.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 (195) hide show
  1. package/CLAUDE.md +53 -49
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +4 -2
  4. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
  8. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
  9. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
  10. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
  12. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
  13. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
  14. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
  15. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
  16. package/_shared/pr-loop/worker-spawn.md +1 -1
  17. package/agents/CLAUDE.md +2 -1
  18. package/agents/caveman.md +0 -1
  19. package/agents/clasp-deployment-orchestrator.md +0 -1
  20. package/agents/clean-coder.md +0 -1
  21. package/agents/code-advisor.md +0 -1
  22. package/agents/code-quality-agent.md +1 -2
  23. package/agents/code-verifier.md +0 -1
  24. package/agents/deep-research.md +0 -1
  25. package/agents/docs-agent.md +0 -1
  26. package/agents/git-commit-crafter.md +0 -1
  27. package/agents/issue-tracker.md +42 -0
  28. package/agents/plan-packet-validator.md +0 -1
  29. package/agents/pr-description-writer.md +0 -1
  30. package/agents/test_agent_frontmatter.py +67 -18
  31. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
  32. package/bin/CLAUDE.md +68 -5
  33. package/bin/ever-shipped-skills.mjs +1 -0
  34. package/bin/install-constants.mjs +88 -0
  35. package/bin/install.mjs +1138 -114
  36. package/bin/install.prune.test.mjs +869 -19
  37. package/bin/install.test.mjs +906 -2
  38. package/commands/implement.md +1 -1
  39. package/commands/right-size.md +1 -1
  40. package/docs/CLAUDE.md +1 -0
  41. package/docs/host-pool-health-monitor.md +102 -0
  42. package/docs/references/CLAUDE.md +4 -2
  43. package/docs/references/advisor-tool.md +13 -0
  44. package/docs/references/code-review-enforcement.md +10 -0
  45. package/docs/references/team-advisor-skill.md +14 -0
  46. package/hooks/blocking/CLAUDE.md +1 -0
  47. package/hooks/blocking/code_review_pr_create_gate.py +7 -3
  48. package/hooks/blocking/code_review_push_gate.py +9 -4
  49. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
  50. package/hooks/blocking/config/__init__.py +5 -5
  51. package/hooks/blocking/config/code_review_enforcement_constants.py +4 -1
  52. package/hooks/blocking/config/test_code_review_enforcement_constants.py +5 -0
  53. package/hooks/blocking/config/verified_commit_constants.py +160 -159
  54. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
  55. package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
  56. package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
  57. package/hooks/blocking/test_code_review_push_gate.py +16 -0
  58. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
  59. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
  60. package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
  61. package/hooks/blocking/test_verdict_directory_write_blocker.py +808 -808
  62. package/hooks/blocking/test_verification_verdict_store.py +54 -0
  63. package/hooks/blocking/test_verified_commit_gate.py +581 -581
  64. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
  65. package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
  66. package/hooks/blocking/verification_verdict_store.py +1039 -1036
  67. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
  68. package/hooks/blocking/verifier_verdict_minter.py +280 -280
  69. package/hooks/git-hooks/test_pre_push.py +25 -0
  70. package/hooks/hooks.json +10 -0
  71. package/hooks/hooks_constants/CLAUDE.md +2 -1
  72. package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
  73. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
  74. package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
  75. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
  76. package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
  77. package/hooks/pyproject.toml +1 -0
  78. package/hooks/validators/CLAUDE.md +1 -0
  79. package/hooks/validators/config/__init__.py +0 -0
  80. package/hooks/validators/config/directory_exemption_constants.py +183 -0
  81. package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
  82. package/hooks/validators/conftest.py +4 -0
  83. package/hooks/validators/ruff_integration.py +49 -5
  84. package/hooks/validators/run_all_validators.py +206 -9
  85. package/hooks/validators/test_directory_exemption_constants.py +185 -0
  86. package/hooks/validators/test_python_antipattern_checks.py +110 -5
  87. package/hooks/validators/test_ruff_integration.py +92 -1
  88. package/hooks/validators/test_run_all_validators.py +115 -68
  89. package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
  90. package/package.json +10 -2
  91. package/rules/CLAUDE.md +1 -0
  92. package/rules/docstring-prose-matches-implementation.md +45 -44
  93. package/rules/state-what-is.md +25 -0
  94. package/rules/verified-commit-gate-skip.md +1 -1
  95. package/scripts/CLAUDE.md +1 -0
  96. package/scripts/Capture-PoolHealth.ps1 +410 -0
  97. package/scripts/_code_review_test_support.py +404 -0
  98. package/scripts/claude_chain_runner.py +141 -1
  99. package/scripts/conftest.py +16 -1
  100. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
  101. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
  102. package/scripts/resolve_worker_spawn.py +626 -626
  103. package/scripts/spawn_grok_batch.py +672 -672
  104. package/scripts/test_claude_chain_runner.py +131 -0
  105. package/scripts/test_invoke_code_review_chain.py +70 -0
  106. package/scripts/test_invoke_code_review_cli.py +192 -0
  107. package/scripts/test_invoke_code_review_contract.py +256 -0
  108. package/scripts/test_invoke_code_review_git.py +123 -0
  109. package/scripts/test_invoke_code_review_mode.py +99 -0
  110. package/scripts/test_resolve_worker_spawn.py +1014 -1014
  111. package/skills/CLAUDE.md +2 -0
  112. package/skills/auditing-claude-config/SKILL.md +114 -114
  113. package/skills/autoconverge/SKILL.md +427 -427
  114. package/skills/autoconverge/reference/convergence.md +24 -3
  115. package/skills/autoconverge/workflow/CLAUDE.md +1 -0
  116. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
  117. package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
  118. package/skills/autoconverge/workflow/converge.mjs +167 -0
  119. package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
  120. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
  121. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
  122. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
  123. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
  124. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
  125. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
  126. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
  127. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
  128. package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
  129. package/skills/closeout/SKILL.md +33 -50
  130. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
  131. package/skills/codex-review/scripts/run_codex_review.py +233 -1
  132. package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
  133. package/skills/condensing-instructions/SKILL.md +81 -0
  134. package/skills/copilot-review/SKILL.md +119 -119
  135. package/skills/e-code-review/SKILL.md +52 -0
  136. package/skills/e-code-review/reference/fix.md +54 -0
  137. package/skills/e-code-review/reference/loop.md +43 -0
  138. package/skills/e-code-review/reference/low.md +57 -0
  139. package/skills/e-code-review/reference/medium.md +153 -0
  140. package/skills/e-code-review/reference/xhigh.md +182 -0
  141. package/skills/e-simplify/SKILL.md +97 -0
  142. package/skills/issue-tracker/SKILL.md +92 -0
  143. package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
  144. package/skills/issue-tracker/reference/handoff-schema.md +64 -0
  145. package/skills/issue-tracker/reference/operation-matrix.md +41 -0
  146. package/skills/orchestrator/SKILL.md +162 -21
  147. package/skills/orchestrator/scripts/status_gate.py +625 -0
  148. package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
  149. package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
  150. package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
  151. package/skills/orchestrator/scripts/test_status_gate.py +439 -0
  152. package/skills/orchestrator-refresh/SKILL.md +110 -35
  153. package/skills/plan-to-pr/SKILL.md +155 -0
  154. package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
  155. package/skills/plan-to-pr/reference/model-routing.md +36 -0
  156. package/skills/plan-to-pr/reference/packet-contract.md +43 -0
  157. package/skills/plan-to-pr/reference/packet-schema.json +57 -0
  158. package/skills/plan-to-pr/reference/process-inventory.md +22 -0
  159. package/skills/plan-to-pr/reference/review-loop.md +33 -0
  160. package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
  161. package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
  162. package/skills/plan-to-pr/reference/task-seeds.md +14 -0
  163. package/skills/plan-to-pr/reference/task-ticket.md +38 -0
  164. package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
  165. package/skills/plan-to-pr/scripts/config/constants.py +193 -0
  166. package/skills/plan-to-pr/scripts/create_packet.py +173 -0
  167. package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
  168. package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
  169. package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
  170. package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
  171. package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
  172. package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
  173. package/skills/plan-to-pr/scripts/validate_run.py +173 -0
  174. package/skills/plan-to-pr/test_skill_contract.py +207 -0
  175. package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
  176. package/skills/pr-converge/SKILL.md +472 -469
  177. package/skills/pr-converge/reference/examples.md +3 -3
  178. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  179. package/skills/pr-converge/reference/ground-rules.md +7 -4
  180. package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
  181. package/skills/pr-converge/reference/per-tick.md +5 -5
  182. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  183. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
  184. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
  185. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
  186. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  187. package/skills/pr-fix-protocol/SKILL.md +1 -1
  188. package/skills/privacy-hygiene/SKILL.md +68 -68
  189. package/skills/prototype/workflows/promotion.md +1 -1
  190. package/skills/release-notes-html/SKILL.md +164 -0
  191. package/skills/task-build/CLAUDE.md +8 -7
  192. package/skills/task-build/SKILL.md +16 -8
  193. package/skills/task-build/reference/tool-routing.md +19 -0
  194. package/scripts/test_invoke_code_review.py +0 -966
  195. package/skills/closeout/reference/issue-body-templates.md +0 -108
@@ -8,6 +8,7 @@ when that content violates a validator, rather than grading the whole branch.
8
8
  import json
9
9
  import subprocess
10
10
  import sys
11
+ import tempfile
11
12
  from collections import Counter
12
13
  from pathlib import Path
13
14
  from unittest.mock import patch
@@ -16,12 +17,21 @@ import pytest
16
17
 
17
18
  from .run_all_validators import (
18
19
  ValidatorResult,
20
+ _escapes_temporary_root,
21
+ _hooks_subprocess_working_directory_and_environment,
19
22
  _scope_new_and_preexisting,
23
+ _temporary_path_preserving_directory_signal,
20
24
  _violation_line_number,
21
25
  main,
22
26
  run_validators_entrypoint_subprocess,
23
27
  )
24
28
 
29
+ CONFIG_DIR_TARGET_PATH = (
30
+ "CDP Automations/os_update_workflow/config/submission_constants.py"
31
+ )
32
+ PARENT_TRAVERSAL_TARGET_PATH = "../../escape_target.py"
33
+ RELATIVE_CONFIG_TARGET_PATH = "config/x.py"
34
+
25
35
  CLEAN_PYTHON_SOURCE = (
26
36
  "def add_two_numbers(first_number: int, second_number: int) -> int:\n"
27
37
  " return first_number + second_number\n"
@@ -85,7 +95,9 @@ class TestPreToolUseGate:
85
95
  def test_edit_validates_reconstructed_post_edit_content(
86
96
  self, tmp_path: Path
87
97
  ) -> None:
88
- target_file = tmp_path / "calculate.py"
98
+ target_directory = tmp_path / "neutral_edit_target"
99
+ target_directory.mkdir(exist_ok=True)
100
+ target_file = target_directory / "calculate.py"
89
101
  target_file.write_text(CLEAN_PYTHON_SOURCE, encoding="utf-8")
90
102
  completed = run_gate(
91
103
  {
@@ -107,6 +119,152 @@ class TestPreToolUseGate:
107
119
  assert completed.returncode == 0, completed.stderr
108
120
  assert "deny" not in completed.stdout
109
121
 
122
+ def test_write_to_config_dir_path_is_not_denied(self) -> None:
123
+ completed = run_gate(
124
+ {
125
+ "tool_name": "Write",
126
+ "tool_input": {
127
+ "file_path": CONFIG_DIR_TARGET_PATH,
128
+ "content": VIOLATING_PYTHON_SOURCE,
129
+ },
130
+ }
131
+ )
132
+ assert completed.returncode == 0, completed.stderr
133
+ assert "deny" not in completed.stdout
134
+
135
+ def test_write_relative_config_path_not_denied_when_cwd_under_system_temp(
136
+ self, monkeypatch: pytest.MonkeyPatch
137
+ ) -> None:
138
+ system_temp_root = Path(tempfile.gettempdir()).resolve()
139
+ monkeypatch.setenv("TEMP", str(system_temp_root))
140
+ monkeypatch.setenv("TMP", str(system_temp_root))
141
+ monkeypatch.setenv("TMPDIR", str(system_temp_root))
142
+ with tempfile.TemporaryDirectory(
143
+ dir=str(system_temp_root), prefix="gate_cwd_"
144
+ ) as temporary_root_string:
145
+ temporary_cwd = Path(temporary_root_string) / "gate_cwd"
146
+ temporary_cwd.mkdir()
147
+
148
+ def working_directory_under_system_temp() -> tuple[str, dict[str, str]]:
149
+ _working_directory, environment = (
150
+ _hooks_subprocess_working_directory_and_environment()
151
+ )
152
+ return str(temporary_cwd), environment
153
+
154
+ with patch(
155
+ "validators.run_all_validators._hooks_subprocess_working_directory_and_environment",
156
+ side_effect=working_directory_under_system_temp,
157
+ ):
158
+ completed = run_gate(
159
+ {
160
+ "tool_name": "Write",
161
+ "tool_input": {
162
+ "file_path": RELATIVE_CONFIG_TARGET_PATH,
163
+ "content": VIOLATING_PYTHON_SOURCE,
164
+ },
165
+ }
166
+ )
167
+ assert completed.returncode == 0, completed.stderr
168
+ assert "deny" not in completed.stdout
169
+
170
+ def test_write_to_parent_traversal_path_still_validates(self) -> None:
171
+ completed = run_gate(
172
+ {
173
+ "tool_name": "Write",
174
+ "tool_input": {
175
+ "file_path": PARENT_TRAVERSAL_TARGET_PATH,
176
+ "content": VIOLATING_PYTHON_SOURCE,
177
+ },
178
+ }
179
+ )
180
+ assert completed.returncode == 0, completed.stderr
181
+ assert '"permissionDecision": "deny"' in completed.stdout
182
+ assert "Magic Values" in completed.stdout
183
+
184
+
185
+ class TestTemporaryPathPreservingDirectorySignal:
186
+ def test_strips_parent_traversal_segments(self, tmp_path: Path) -> None:
187
+ assert _escapes_temporary_root("..") is True
188
+ staged_path = _temporary_path_preserving_directory_signal(
189
+ tmp_path, PARENT_TRAVERSAL_TARGET_PATH
190
+ )
191
+ assert staged_path == tmp_path / "escape_target.py"
192
+ assert staged_path.resolve().is_relative_to(tmp_path.resolve())
193
+
194
+ def test_keeps_config_directory_segment(self, tmp_path: Path) -> None:
195
+ staged_path = _temporary_path_preserving_directory_signal(
196
+ tmp_path, CONFIG_DIR_TARGET_PATH
197
+ )
198
+ assert staged_path.name == "submission_constants.py"
199
+ assert "config" in staged_path.parts
200
+ assert staged_path == tmp_path / "config" / "submission_constants.py"
201
+
202
+ def test_drops_leading_anchor(self, tmp_path: Path) -> None:
203
+ absolute_target = tmp_path / "config" / "submission_constants.py"
204
+ staging_root = tmp_path / "staging_root"
205
+ staging_root.mkdir()
206
+ staged_path = _temporary_path_preserving_directory_signal(
207
+ staging_root, str(absolute_target)
208
+ )
209
+ relative_parts = staged_path.relative_to(staging_root).parts
210
+ assert relative_parts == ("config", "submission_constants.py")
211
+ assert absolute_target.anchor not in relative_parts
212
+ assert staged_path.resolve().is_relative_to(staging_root.resolve())
213
+
214
+ def test_path_without_exemption_directory_stages_flat_basename(
215
+ self, tmp_path: Path
216
+ ) -> None:
217
+ pytest_shaped_target = (
218
+ tmp_path / "test_edit_introducing_new_viol0" / "legacy_module.py"
219
+ )
220
+ pytest_shaped_target.parent.mkdir(parents=True, exist_ok=True)
221
+ pytest_shaped_target.write_text(CLEAN_MARKER_FUNCTION, encoding="utf-8")
222
+ staging_root = tmp_path / "staging_root"
223
+ staging_root.mkdir()
224
+ staged_path = _temporary_path_preserving_directory_signal(
225
+ staging_root, str(pytest_shaped_target)
226
+ )
227
+ assert staged_path == staging_root / "legacy_module.py"
228
+
229
+ def test_relative_config_path_preserves_config_under_system_temp_cwd(
230
+ self, monkeypatch: pytest.MonkeyPatch
231
+ ) -> None:
232
+ system_temp_root = Path(tempfile.gettempdir()).resolve()
233
+ monkeypatch.setenv("TEMP", str(system_temp_root))
234
+ monkeypatch.setenv("TMP", str(system_temp_root))
235
+ monkeypatch.setenv("TMPDIR", str(system_temp_root))
236
+ with tempfile.TemporaryDirectory(
237
+ dir=str(system_temp_root), prefix="staging_cwd_"
238
+ ) as temporary_root_string:
239
+ temporary_root = Path(temporary_root_string)
240
+ previous_cwd = Path.cwd()
241
+ try:
242
+ monkeypatch.chdir(temporary_root)
243
+ staging_root = temporary_root / "staging_root"
244
+ staging_root.mkdir()
245
+ staged_path = _temporary_path_preserving_directory_signal(
246
+ staging_root, RELATIVE_CONFIG_TARGET_PATH
247
+ )
248
+ assert staged_path == staging_root / "config" / "x.py"
249
+ assert "config" in staged_path.parts
250
+ assert staged_path.name == "x.py"
251
+ finally:
252
+ monkeypatch.chdir(previous_cwd)
253
+
254
+ def test_escapes_temporary_root_rejects_absolute_and_parent_parts(
255
+ self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
256
+ ) -> None:
257
+ sandbox_temp_root = tmp_path / "system_temp"
258
+ sandbox_temp_root.mkdir()
259
+ monkeypatch.setenv("TEMP", str(sandbox_temp_root))
260
+ monkeypatch.setenv("TMP", str(sandbox_temp_root))
261
+ monkeypatch.setenv("TMPDIR", str(sandbox_temp_root))
262
+ assert _escapes_temporary_root("..") is True
263
+ assert _escapes_temporary_root("scripts") is False
264
+ assert _escapes_temporary_root("config") is False
265
+ absolute_part = str(Path(tempfile.gettempdir()).resolve().anchor) or "/"
266
+ assert _escapes_temporary_root(absolute_part) is True
267
+
110
268
 
111
269
  class TestCliModeRegression:
112
270
  def test_cli_mode_reports_violations_and_exits_one(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,15 @@
21
21
  "scripts/",
22
22
  "_shared/",
23
23
  "audit-rubrics/",
24
- "CLAUDE.md"
24
+ "CLAUDE.md",
25
+ "!**/__pycache__/**",
26
+ "!**/*.py[cod]",
27
+ "!**/.pytest_cache/**",
28
+ "!**/.mypy_cache/**",
29
+ "!**/.ruff_cache/**",
30
+ "!**/*.log",
31
+ "!**/debug-*.log",
32
+ "!**/*.egg-info/**"
25
33
  ],
26
34
  "keywords": [
27
35
  "claude-code",
package/rules/CLAUDE.md CHANGED
@@ -51,6 +51,7 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. A rule withou
51
51
  | `right-sized-engineering.md` | Simple over clever; functions over classes; concrete over abstract |
52
52
  | `self-contained-docs.md` | Every document is fully self-contained; no references to the conversation that produced it |
53
53
  | `shell-invocation-policy.md` | All Windows shell commands use `pwsh`; `Audit-ShellPolicy.ps1` reports the non-`pwsh` forms in the `settings.json` permission rules and `Migrate-ShellPolicy.ps1` rewrites them to `pwsh`, both run on demand, not as a live gate |
54
+ | `state-what-is.md` | Assert claims, decisions, and actions directly; replace exclusion (naming what a claim is not) and elimination (walking rejected candidates) with the claim or answer itself |
54
55
  | `tdd.md` | Test-driven development: red → green → refactor, no production code before a failing test |
55
56
  | `testing.md` | Test quality and infrastructure standards |
56
57
  | `vault-context.md` | Search Obsidian vault for prior sessions and decisions before substantive project work |
@@ -1,44 +1,45 @@
1
- ---
2
- paths:
3
- - "**/*.py"
4
- - "**/*.md"
5
- ---
6
-
7
- # Docstring Prose Matches Implementation
8
-
9
- **When this applies:** Any Write or Edit to a public function, method, class, or module whose docstring prose makes an enumerable claim about behavior — a list of inputs the code handles, the conditions it treats as a match, the cases it skips, or the order of its steps. It applies equally to a skill's companion `SKILL.md` (or any sibling `.md`) that describes a producer the skill's `scripts/` carry out: a doc sentence that claims a produced artifact's ordering or content is the prose this rule governs, and it tracks the producer function's own docstring and body.
10
-
11
- ## Rule
12
-
13
- When a docstring enumerates the behaviors a body applies, the enumeration covers every behavior the body applies. A reader trusts the list to be complete: an item the code applies but the prose omits is a silent gap that misleads every future reader and reviewer.
14
-
15
- When the body changes the set of behaviors it applies, the same edit updates the prose enumeration. The two move together in one commit.
16
-
17
- ## Write-time checks
18
-
19
- Read the body and the docstring side by side. Apply each check that matches the prose:
20
-
21
- - **Unions / match sources** — every member of a "what counts" union appears in the prose.
22
- - **Suppressors / skip lists** — every early-return suppressor appears in the prose.
23
- - **Step order** — named order matches call order; branch-guarded corrective steps are named too.
24
- - **Shared fallbacks** — every condition that reaches a fallback call is named.
25
- - **Predicate breadth** — the body accepts only the inputs the prose names.
26
- - **Exclusion axis** — an exclusion clause keys on the same axis the body classifies on.
27
- - **Companion docs** — a `SKILL.md` (or sibling) order/content claim matches the producer body.
28
- - **Returns / Raises / Note claims** each free-form claim matches the body.
29
-
30
- Many deterministic shapes of this drift have Write/Edit gates in `packages/claude-dev-env/hooks/blocking/code_rules_docstrings.py` (and the JS/`.mjs` slices in `code_rules_imports_logging.py`). Free-form rest is judgment.
31
-
32
- ## Full standard
33
-
34
- The full Category O judgment standard — sub-buckets O1–O9, the complete write-time gate inventory, free-form checklists, and worked examples — lives in:
35
-
36
- `packages/claude-dev-env/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md`
37
-
38
- ## Division of labor
39
-
40
- | Surface | Role |
41
- |---|---|
42
- | **This rule** | Always-on write-time policy and the compact checklist above. |
43
- | Category O rubric | Single thick source for the full standard (on demand). |
44
- | Category O prompt | Audit template; points at the rubric for judgment. |
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ - "**/*.md"
5
+ ---
6
+
7
+ # Docstring Prose Matches Implementation
8
+
9
+ **When this applies:** Any Write or Edit to a public function, method, class, or module whose docstring prose makes an enumerable claim about behavior — a list of inputs the code handles, the conditions it treats as a match, the cases it skips, or the order of its steps. It applies equally to a skill's companion `SKILL.md` (or any sibling `.md`) that describes a producer the skill's `scripts/` carry out: a doc sentence that claims a produced artifact's ordering or content is the prose this rule governs, and it tracks the producer function's own docstring and body.
10
+
11
+ ## Rule
12
+
13
+ When a docstring enumerates the behaviors a body applies, the enumeration covers every behavior the body applies. A reader trusts the list to be complete: an item the code applies but the prose omits is a silent gap that misleads every future reader and reviewer.
14
+
15
+ When the body changes the set of behaviors it applies, the same edit updates the prose enumeration. The two move together in one commit.
16
+
17
+ ## Write-time checks
18
+
19
+ Read the body and the docstring side by side. Apply each check that matches the prose:
20
+
21
+ - **Unions / match sources** — every member of a "what counts" union appears in the prose.
22
+ - **Suppressors / skip lists** — every early-return suppressor appears in the prose.
23
+ - **Step order** — named order matches call order; branch-guarded corrective steps are named too.
24
+ - **Shared fallbacks** — every condition that reaches a fallback call is named.
25
+ - **Predicate breadth** — the body accepts only the inputs the prose names.
26
+ - **Exclusion axis** — an exclusion clause keys on the same axis the body classifies on.
27
+ - **Companion docs** — a `SKILL.md` (or sibling) order/content claim matches the producer body.
28
+ - **Gate-outcome status flags** an outcome routed to a blocker (`blocker = ...; break`) reads as blocked everywhere, never as a bypass.
29
+ - **Returns / Raises / Note claims** — each free-form claim matches the body.
30
+
31
+ Many deterministic shapes of this drift have Write/Edit gates in `packages/claude-dev-env/hooks/blocking/code_rules_docstrings.py` (and the JS/`.mjs` slices in `code_rules_imports_logging.py`). Free-form rest is judgment.
32
+
33
+ ## Full standard
34
+
35
+ The full Category O judgment standard — sub-buckets O1–O9, the complete write-time gate inventory, free-form checklists, and worked examples — lives in:
36
+
37
+ `packages/claude-dev-env/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md`
38
+
39
+ ## Division of labor
40
+
41
+ | Surface | Role |
42
+ |---|---|
43
+ | **This rule** | Always-on write-time policy and the compact checklist above. |
44
+ | Category O rubric | Single thick source for the full standard (on demand). |
45
+ | Category O prompt | Audit template; points at the rubric for judgment. |
@@ -0,0 +1,25 @@
1
+ ---
2
+ paths:
3
+ - "**/*.md"
4
+ - "**/*.py"
5
+ - "**/*.mjs"
6
+ - "**/*.js"
7
+ - "**/*.ts"
8
+ - "**/*.ps1"
9
+ - "**/*.sh"
10
+ ---
11
+
12
+ # State What Is
13
+
14
+ Write settled facts, decisions, and actions that are load-bearing for the reader now. Assert each claim, decision, or action directly, and let it stand on its own evidence.
15
+
16
+ A detail earns its place by mattering now, or by being timeless enough to matter for future work or plans. Omit everything else as noise.
17
+
18
+ ## Two patterns to replace on sight
19
+
20
+ - **Exclusion** — establishing a claim by naming what it is not, or by listing what is out of bounds. Replace it with the claim itself.
21
+ - **Elimination** — walking rejected candidates (causes, options, paths, explanations) to reach the answer. Replace it with the answer and the evidence that supports it.
22
+
23
+ ## Sibling rules
24
+
25
+ This rule sits beside the other prose-quality rules in this directory: [`no-historical-clutter.md`](no-historical-clutter.md) cuts references to old state, [`self-contained-docs.md`](self-contained-docs.md) cuts references to the conversation that produced a doc, [`no-justification-noise.md`](no-justification-noise.md) cuts sentences that only justify a stated choice, and [`plain-language.md`](plain-language.md) swaps heavy words for everyday ones. This rule governs how a claim gets established — directly, not by elimination or exclusion.
@@ -17,7 +17,7 @@ That situation arises when the verdict fails to cover the current surface even t
17
17
 
18
18
  ## When the marker is not allowed
19
19
 
20
- Every other case runs the verification: spawn the `code-verifier` agent and let the SubagentStop hook mint the verdict. In particular, never use the marker to:
20
+ Every other case runs the verification: spawn the `code-verifier` agent — `model: sonnet`, worker-model routing per [`skills/orchestrator/SKILL.md`](../skills/orchestrator/SKILL.md#workflow-agent-routing); resolver-supplied sonnet-equivalent on third-party hosts — and let the SubagentStop hook mint the verdict. In particular, never use the marker to:
21
21
 
22
22
  - Skip a branch's first verification.
23
23
  - Commit or push after any real code change since the last clean verdict — one changed line means a fresh verification.
package/scripts/CLAUDE.md CHANGED
@@ -27,6 +27,7 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
27
27
  | `check.ps1` | Runs the full code-quality check suite |
28
28
  | `Show-Asset.ps1` | Opens files on screen, sizing each image window to the image's pixel dimensions (scaled to fit the screen); non-image files open in their default application |
29
29
  | `Get-SessionAccount.ps1` | Reports which Claude account the current session is actually logged into by comparing `~/.claude.json`'s CLI login against a `CLAUDE_USER_DATA_DIR` desktop profile's `lastKnownAccountUuid`, recovering the desktop account's email from profile storage when the two accounts differ |
30
+ | `Capture-PoolHealth.ps1` | Captures Windows memory pool counters, high-handle processes, and kernel pool tags (via `NtQuerySystemInformation` class 22), prints a threshold verdict with a remediation map, and exits non-zero when any alert threshold fires |
30
31
 
31
32
  ## Subdirectories
32
33