claude-dev-env 2.4.0 → 2.7.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 (309) hide show
  1. package/CLAUDE.md +26 -59
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +6 -3
  4. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
  5. package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
  6. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
  7. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
  8. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
  9. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
  10. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
  11. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
  13. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
  14. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
  15. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
  16. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
  17. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
  18. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
  19. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
  20. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
  21. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
  22. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
  23. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
  24. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
  25. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
  26. package/_shared/pr-loop/worker-spawn.md +1 -1
  27. package/agents/CLAUDE.md +3 -2
  28. package/agents/caveman.md +0 -1
  29. package/agents/clasp-deployment-orchestrator.md +0 -1
  30. package/agents/clean-coder.md +0 -1
  31. package/agents/code-advisor.md +0 -1
  32. package/agents/code-quality-agent.md +1 -2
  33. package/agents/code-verifier.md +36 -8
  34. package/agents/deep-research.md +0 -1
  35. package/agents/docs-agent.md +0 -1
  36. package/agents/git-commit-crafter.md +0 -1
  37. package/agents/issue-tracker.md +42 -0
  38. package/agents/plan-packet-validator.md +0 -1
  39. package/agents/pr-description-writer.md +0 -1
  40. package/agents/test_agent_frontmatter.py +67 -18
  41. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
  42. package/bin/CLAUDE.md +68 -5
  43. package/bin/codex-compat.mjs +104 -0
  44. package/bin/codex-compat.test.mjs +51 -0
  45. package/bin/ever-shipped-skills.mjs +1 -0
  46. package/bin/install-constants.mjs +88 -0
  47. package/bin/install.mjs +1138 -114
  48. package/bin/install.prune.test.mjs +869 -19
  49. package/bin/install.test.mjs +906 -2
  50. package/codex-capability-map.json +13 -0
  51. package/commands/implement.md +1 -1
  52. package/commands/right-size.md +1 -1
  53. package/docs/CLAUDE.md +1 -0
  54. package/docs/CODE_RULES.md +2 -0
  55. package/docs/codex-compatibility.md +25 -0
  56. package/docs/host-pool-health-monitor.md +102 -0
  57. package/docs/nas-ssh-invocation.md +96 -12
  58. package/docs/references/CLAUDE.md +4 -2
  59. package/docs/references/advisor-tool.md +13 -0
  60. package/docs/references/code-review-enforcement.md +35 -0
  61. package/docs/references/team-advisor-skill.md +14 -0
  62. package/hooks/blocking/CLAUDE.md +4 -0
  63. package/hooks/blocking/code_review_pr_create_gate.py +7 -3
  64. package/hooks/blocking/code_review_push_gate.py +9 -4
  65. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
  66. package/hooks/blocking/config/__init__.py +5 -5
  67. package/hooks/blocking/config/code_review_enforcement_constants.py +40 -7
  68. package/hooks/blocking/config/test_code_review_enforcement_constants.py +58 -0
  69. package/hooks/blocking/config/verified_commit_constants.py +160 -159
  70. package/hooks/blocking/eli11_reply_enforcer.py +479 -0
  71. package/hooks/blocking/gh_body_arg_blocker.py +1 -1
  72. package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
  73. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
  74. package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
  75. package/hooks/blocking/shell_substitution_blocker.py +129 -0
  76. package/hooks/blocking/state_description_blocker.py +1 -1
  77. package/hooks/blocking/stop_dispatcher.py +1 -1
  78. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
  79. package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
  80. package/hooks/blocking/test_code_review_push_gate.py +16 -0
  81. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
  82. package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
  83. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
  84. package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
  85. package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
  86. package/hooks/blocking/test_stop_dispatcher.py +23 -0
  87. package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
  88. package/hooks/blocking/test_verdict_directory_write_blocker.py +804 -808
  89. package/hooks/blocking/test_verification_verdict_store.py +54 -0
  90. package/hooks/blocking/test_verified_commit_gate.py +581 -581
  91. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
  92. package/hooks/blocking/unscoped_search_blocker.py +391 -0
  93. package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
  94. package/hooks/blocking/verification_verdict_store.py +1039 -1036
  95. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
  96. package/hooks/blocking/verifier_verdict_minter.py +280 -280
  97. package/hooks/git-hooks/CLAUDE.md +3 -0
  98. package/hooks/git-hooks/conftest.py +30 -0
  99. package/hooks/git-hooks/gate_utils.py +2 -2
  100. package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
  101. package/hooks/git-hooks/pre_push.py +75 -4
  102. package/hooks/git-hooks/pre_push_base_reference.py +166 -0
  103. package/hooks/git-hooks/test_config.py +0 -15
  104. package/hooks/git-hooks/test_gate_utils.py +3 -15
  105. package/hooks/git-hooks/test_pre_commit.py +1 -15
  106. package/hooks/git-hooks/test_pre_push.py +257 -23
  107. package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
  108. package/hooks/hooks.json +10 -12
  109. package/hooks/hooks_constants/CLAUDE.md +7 -2
  110. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
  111. package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
  112. package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
  113. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
  114. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
  115. package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
  116. package/hooks/hooks_constants/shell_command_segments.py +82 -0
  117. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
  118. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
  119. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
  120. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
  121. package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
  122. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
  123. package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
  124. package/hooks/pyproject.toml +1 -0
  125. package/hooks/validators/CLAUDE.md +1 -0
  126. package/hooks/validators/config/__init__.py +0 -0
  127. package/hooks/validators/config/directory_exemption_constants.py +183 -0
  128. package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
  129. package/hooks/validators/conftest.py +4 -0
  130. package/hooks/validators/ruff_integration.py +49 -5
  131. package/hooks/validators/run_all_validators.py +206 -9
  132. package/hooks/validators/test_directory_exemption_constants.py +185 -0
  133. package/hooks/validators/test_python_antipattern_checks.py +110 -5
  134. package/hooks/validators/test_ruff_integration.py +92 -1
  135. package/hooks/validators/test_run_all_validators.py +115 -68
  136. package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
  137. package/package.json +13 -3
  138. package/rules/CLAUDE.md +17 -22
  139. package/rules/agent-spawn-protocol.md +6 -6
  140. package/rules/anti-corollary-tests.md +1 -1
  141. package/rules/bdd.md +1 -1
  142. package/rules/cleanup-temp-files.md +10 -4
  143. package/rules/code-standards.md +7 -0
  144. package/rules/conservative-action.md +1 -5
  145. package/rules/context7.md +0 -4
  146. package/rules/destructive-commands.md +47 -0
  147. package/rules/doc-inventory-integrity.md +48 -0
  148. package/rules/doc-prose-cuts.md +58 -0
  149. package/rules/docstring-prose-matches-implementation.md +53 -44
  150. package/rules/durable-post-artifacts.md +0 -4
  151. package/rules/eli11-replies.md +31 -0
  152. package/rules/explore-thoroughly.md +4 -4
  153. package/rules/falsify-before-green.md +68 -0
  154. package/rules/file-global-constants.md +1 -1
  155. package/rules/filesystem-search.md +51 -0
  156. package/rules/gh-cli-conventions.md +27 -0
  157. package/rules/git-workflow.md +26 -0
  158. package/rules/hedging-claims.md +9 -0
  159. package/rules/long-horizon-autonomy.md +0 -4
  160. package/rules/measurement-denominators.md +48 -0
  161. package/rules/nas-ssh-invocation.md +23 -5
  162. package/rules/parallel-tools.md +2 -2
  163. package/rules/plain-illustrative-docstrings.md +3 -7
  164. package/rules/plain-language.md +2 -0
  165. package/rules/proof-of-work-pr-comments.md +0 -4
  166. package/rules/re-stage-before-commit.md +2 -0
  167. package/rules/research-mode.md +10 -0
  168. package/rules/shell-invocation.md +21 -0
  169. package/rules/testing.md +4 -0
  170. package/rules/verified-commit-gate-skip.md +3 -27
  171. package/rules/verify-before-asking.md +5 -0
  172. package/rules/windows-filesystem-safe.md +1 -1
  173. package/rules/workers-done-before-complete.md +4 -0
  174. package/scripts/CLAUDE.md +1 -0
  175. package/scripts/Capture-PoolHealth.ps1 +410 -0
  176. package/scripts/Migrate-ShellPolicy.ps1 +1 -1
  177. package/scripts/_code_review_test_support.py +404 -0
  178. package/scripts/claude_chain_runner.py +141 -1
  179. package/scripts/codex_capability_bridge.py +171 -0
  180. package/scripts/codex_compat_materializer.py +1087 -0
  181. package/scripts/codex_compat_watcher.py +502 -0
  182. package/scripts/conftest.py +16 -1
  183. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
  184. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
  185. package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
  186. package/scripts/invoke_code_review.py +11 -4
  187. package/scripts/resolve_worker_spawn.py +626 -626
  188. package/scripts/spawn_grok_batch.py +672 -672
  189. package/scripts/sync_to_cursor/rules.py +0 -10
  190. package/scripts/test_claude_chain_runner.py +131 -0
  191. package/scripts/test_invoke_code_review.py +85 -908
  192. package/scripts/test_invoke_code_review_chain.py +70 -0
  193. package/scripts/test_invoke_code_review_cli.py +192 -0
  194. package/scripts/test_invoke_code_review_contract.py +256 -0
  195. package/scripts/test_invoke_code_review_git.py +123 -0
  196. package/scripts/test_invoke_code_review_mode.py +99 -0
  197. package/scripts/test_resolve_worker_spawn.py +1014 -1014
  198. package/scripts/tests/test_code_review_constants.py +80 -0
  199. package/scripts/tests/test_codex_capability_bridge.py +91 -0
  200. package/scripts/tests/test_codex_compat_materializer.py +632 -0
  201. package/scripts/tests/test_codex_compat_watcher.py +599 -0
  202. package/scripts/tests/test_sync_to_cursor.py +0 -1
  203. package/skills/CLAUDE.md +2 -0
  204. package/skills/auditing-claude-config/SKILL.md +114 -114
  205. package/skills/autoconverge/SKILL.md +427 -427
  206. package/skills/autoconverge/reference/convergence.md +24 -3
  207. package/skills/autoconverge/workflow/CLAUDE.md +1 -0
  208. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
  209. package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
  210. package/skills/autoconverge/workflow/converge.mjs +168 -1
  211. package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
  212. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
  213. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
  214. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
  215. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
  216. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
  217. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
  218. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
  219. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
  220. package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
  221. package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
  222. package/skills/closeout/SKILL.md +33 -50
  223. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
  224. package/skills/codex-review/scripts/run_codex_review.py +233 -1
  225. package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
  226. package/skills/condensing-instructions/SKILL.md +72 -0
  227. package/skills/copilot-review/SKILL.md +119 -119
  228. package/skills/e-code-review/SKILL.md +52 -0
  229. package/skills/e-code-review/reference/fix.md +54 -0
  230. package/skills/e-code-review/reference/loop.md +43 -0
  231. package/skills/e-code-review/reference/low.md +57 -0
  232. package/skills/e-code-review/reference/medium.md +153 -0
  233. package/skills/e-code-review/reference/xhigh.md +182 -0
  234. package/skills/e-simplify/SKILL.md +97 -0
  235. package/skills/fresh-branch/CLAUDE.md +1 -1
  236. package/skills/fresh-branch/SKILL.md +5 -6
  237. package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
  238. package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
  239. package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
  240. package/skills/issue-tracker/SKILL.md +92 -0
  241. package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
  242. package/skills/issue-tracker/reference/handoff-schema.md +64 -0
  243. package/skills/issue-tracker/reference/operation-matrix.md +41 -0
  244. package/skills/orchestrator/SKILL.md +177 -22
  245. package/skills/orchestrator/scripts/status_gate.py +625 -0
  246. package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
  247. package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
  248. package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
  249. package/skills/orchestrator/scripts/test_status_gate.py +439 -0
  250. package/skills/orchestrator-refresh/SKILL.md +129 -35
  251. package/skills/plan-to-pr/SKILL.md +155 -0
  252. package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
  253. package/skills/plan-to-pr/reference/model-routing.md +36 -0
  254. package/skills/plan-to-pr/reference/packet-contract.md +43 -0
  255. package/skills/plan-to-pr/reference/packet-schema.json +57 -0
  256. package/skills/plan-to-pr/reference/process-inventory.md +22 -0
  257. package/skills/plan-to-pr/reference/review-loop.md +33 -0
  258. package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
  259. package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
  260. package/skills/plan-to-pr/reference/task-seeds.md +14 -0
  261. package/skills/plan-to-pr/reference/task-ticket.md +38 -0
  262. package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
  263. package/skills/plan-to-pr/scripts/config/constants.py +193 -0
  264. package/skills/plan-to-pr/scripts/create_packet.py +173 -0
  265. package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
  266. package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
  267. package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
  268. package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
  269. package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
  270. package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
  271. package/skills/plan-to-pr/scripts/validate_run.py +173 -0
  272. package/skills/plan-to-pr/test_skill_contract.py +207 -0
  273. package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
  274. package/skills/pr-converge/SKILL.md +472 -469
  275. package/skills/pr-converge/reference/examples.md +3 -3
  276. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  277. package/skills/pr-converge/reference/ground-rules.md +7 -4
  278. package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
  279. package/skills/pr-converge/reference/per-tick.md +5 -5
  280. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  281. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
  282. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
  283. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
  284. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  285. package/skills/pr-fix-protocol/SKILL.md +1 -1
  286. package/skills/privacy-hygiene/SKILL.md +68 -68
  287. package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
  288. package/skills/prototype/workflows/promotion.md +1 -1
  289. package/skills/release-notes-html/SKILL.md +164 -0
  290. package/skills/session-log/SKILL.md +1 -1
  291. package/skills/task-build/CLAUDE.md +8 -7
  292. package/skills/task-build/SKILL.md +16 -8
  293. package/skills/task-build/reference/tool-routing.md +19 -0
  294. package/rules/claude-md-orphan-file.md +0 -28
  295. package/rules/cleanup-command-forms.md +0 -23
  296. package/rules/code-reviews.md +0 -11
  297. package/rules/env-var-table-code-drift.md +0 -10
  298. package/rules/gh-body-file.md +0 -5
  299. package/rules/gh-paginate.md +0 -3
  300. package/rules/hook-prose-matches-detector.md +0 -15
  301. package/rules/no-historical-clutter.md +0 -26
  302. package/rules/no-inline-destructive-literals.md +0 -9
  303. package/rules/no-justification-noise.md +0 -61
  304. package/rules/package-inventory-stale-entry.md +0 -25
  305. package/rules/right-sized-engineering.md +0 -28
  306. package/rules/self-contained-docs.md +0 -17
  307. package/rules/shell-invocation-policy.md +0 -5
  308. package/rules/tdd.md +0 -7
  309. package/skills/closeout/reference/issue-body-templates.md +0 -108
@@ -1,44 +1,53 @@
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 `~/.claude/hooks/blocking/code_rules_docstrings.py` (and the JS/`.mjs` slices in `code_rules_imports_logging.py`). Free-form rest is judgment.
32
+
33
+ ## Hook prose matches its detector
34
+
35
+ A hook module is the sharpest case of the same rule: its docstring lead narrative and its `CORRECTIVE_MESSAGE` describe exactly the shapes the detector flags, and claim no broader trigger surface than the regex enforces.
36
+
37
+ `hook_prose_detector_consistency` (PreToolUse on Write|Edit of hook modules and their `*_constants.py` companions) blocks prose that claims a trigger the detector never fires on, and names the fix.
38
+
39
+ After writing a hook, ask: would a token matching every word of this message actually trip the detector? When the message names a shape the regex skips, rewrite the message to name only what the regex catches. The path-shape case is the common overstatement — a detector that keys off a path separator must not claim it blocks an "output-key segment". The corrective message spells the rewrite.
40
+
41
+ ## Full standard
42
+
43
+ The full Category O judgment standard sub-buckets O1–O9, the complete write-time gate inventory, free-form checklists, and worked examples — lives in:
44
+
45
+ `~/.claude/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md`
46
+
47
+ ## Division of labor
48
+
49
+ | Surface | Role |
50
+ |---|---|
51
+ | **This rule** | Always-on write-time policy and the compact checklist above. |
52
+ | Category O rubric | Single thick source for the full standard (on demand). |
53
+ | Category O prompt | Audit template; points at the rubric for judgment. |
@@ -36,7 +36,3 @@ With neither anchor the text names the directory rather than something inside it
36
36
  ## Enforcement
37
37
 
38
38
  The `volatile_path_in_post_blocker` PreToolUse hook reads the body of each `gh` post command and each GitHub MCP post call, scans it for these markers, and blocks the post when it finds one. For a `--body-file`, the hook reads the file and scans its contents, so writing the body to a temp file and passing it with `--body-file` stays allowed — what the hook rejects is a volatile path inside the text that gets posted.
39
-
40
- ## Why
41
-
42
- A comment that cites an artifact under a job's tmp directory reads fine the moment it is posted and breaks a few minutes later, once the job is cleaned. Embedding text inline and linking binary artifacts to a durable release keeps every post readable for as long as it exists.
@@ -0,0 +1,31 @@
1
+ # ELI11 Replies
2
+
3
+ **Users read about 20% of your words, and 79% of them scan.** Write every reply so the bold words alone tell the whole story.
4
+
5
+ ## Four skim mechanics
6
+
7
+ 1. **Bold keyword first** — open every line and bullet with its load-bearing words in bold. Eyes land on the first words of a line, then fall down the left edge — the [F-pattern](https://www.nngroup.com/articles/f-shaped-pattern-reading-web-content-discovered/).
8
+ 2. **One idea per line** — a second idea in the same line is invisible to a skimmer.
9
+ 3. **Conclusion first** — the outcome goes in sentence one. Detail sits below it, or gets cut.
10
+ 4. **Half the words** — write it, halve it, halve it again. Cap a reply at about 120 words.
11
+
12
+ **Measured gains** ([NN/g eyetracking](https://www.nngroup.com/articles/how-users-read-on-the-web/)): concise +58%, scannable layout +47%, both together +124%.
13
+
14
+ ## Reply shape
15
+
16
+ 1. **Action first** — when the user must act, open with "Do N things" and numbered click-by-click steps, one short line each.
17
+ 2. **Outcome first** — when nothing is needed, open with the outcome in one sentence.
18
+ 3. **Findings** — at most 3 short bullets.
19
+ 4. **Detail** — only when the user asks.
20
+
21
+ ## Rules
22
+
23
+ - **One command per block** — a command the user runs goes in its own `bash`-tagged fenced block, so the Run button appears. That tag gives the user a Run button; [`shell-invocation-policy`](shell-invocation-policy.md) stays in charge of the agent's own Bash-tool calls, which run pwsh-only.
24
+ - **One line per status** — each background-work update gets a single line.
25
+ - **Cut findings first** — when a reply runs long, drop findings and keep the action steps.
26
+ - **Skim test** — reading only the bold words tells the whole story.
27
+
28
+ ## Relationship to other rules
29
+
30
+ - **[`plain-language`](plain-language.md)** owns word choice; this rule owns reply length and shape.
31
+ - **`AskUserQuestion`** carries every question to the user, in the same short style.
@@ -17,11 +17,11 @@ Note: This deliberately chooses exploration depth over the "commit and execute q
17
17
  - New feature or cross-cutting change: read broadly across the codebase to understand how similar things are done.
18
18
  - Architectural decision: explore the full landscape before recommending a direction.
19
19
 
20
+ ## Inside an autonomous run
21
+
22
+ The depth budget shrinks once the evidence is in hand. When you can already name the files, the constraints, and what success looks like, further reading buys nothing — act. Re-reading a file to re-derive a fact the run already settled is the shape to cut. See [`long-horizon-autonomy.md`](long-horizon-autonomy.md).
23
+
20
24
  ## Relationship to other rules
21
25
 
22
26
  - **conservative-action.md** gates *whether* to act. This rule governs *how deeply* to investigate.
23
27
  - **research-mode.md** ensures factual claims are grounded. This rule ensures implementation plans are grounded in the actual codebase.
24
-
25
- ## Why
26
-
27
- Premature commitment leads to wasted effort when the chosen approach conflicts with existing patterns or misses important context. Thorough exploration surfaces constraints early and produces better-informed solutions.
@@ -0,0 +1,68 @@
1
+ ---
2
+ paths:
3
+ - "**/test_*.py"
4
+ - "**/*_test.py"
5
+ - "**/*.test.*"
6
+ - "**/*.spec.*"
7
+ - "**/conftest.py"
8
+ - "**/tests/**"
9
+ - "**/scripts/**"
10
+ ---
11
+
12
+ # Falsify Before Green
13
+
14
+ **When this applies:** Any new test, probe, concurrency harness, sweep, mutation check, or measurement script, before its green counts as evidence.
15
+
16
+ ## Rule
17
+
18
+ A check's green counts as evidence only after that same check ran red on a deliberate break, with a paired control that passes beside it. The break is named: a mutation applied to the code, a stubbed-out target, or a trip input built to fire the check.
19
+
20
+ A green with no shown red is an unmeasured result, not a pass. Apply the break, watch the check fail, then trust the green. A check that stays green under its own break reads nothing about the code, and its number carries no weight.
21
+
22
+ ## The four shapes this stops
23
+
24
+ ### 1. A probe whose trigger condition never fires
25
+
26
+ The probe reports zero because it measured zero events, not because the code is clean. Its counter sits at its start value for the whole run.
27
+
28
+ **Break to apply:** feed it one input that must trip it. A probe still at zero on that input measures nothing.
29
+
30
+ ### 2. A sweep that reads a subset of the files it claims to cover
31
+
32
+ The sweep compares against the wrong base, walks a slice of the tree, and reports its finding count over the full set.
33
+
34
+ **Break to apply:** plant one violation in a file the sweep's coverage claim names. A sweep that misses the plant walks a smaller file set than the one it reports.
35
+
36
+ ### 3. A mutation that survives
37
+
38
+ The test meant to kill the mutation never reaches the mutated code — a mock stands in for the call, a guard returns early, or the test drives a neighboring branch.
39
+
40
+ **Break to apply:** hold the mutation in place and run the test. A green test names a line nothing covers.
41
+
42
+ ### 4. An assertion that counts an artifact the harness seeded
43
+
44
+ The harness writes the row, file, or event the assertion counts, so the assertion tracks the harness rather than the code under test.
45
+
46
+ **Break to apply:** stub the production writer to a no-op. A green assertion counts the seed.
47
+
48
+ ## What a shown-red record holds
49
+
50
+ | Part | What it names |
51
+ |---|---|
52
+ | The break | The mutation, stub, or trip input applied, named by file and line or by the exact input text |
53
+ | The red | The failing output the check printed under that break |
54
+ | The control | The case that passes beside the red, run on the same command |
55
+
56
+ All three land together. A record carrying the red alone shows a check that fails on everything; a record carrying the control alone shows a check that passes on everything.
57
+
58
+ ## Sibling rules
59
+
60
+ | Rule | Role |
61
+ |---|---|
62
+ | `anti-corollary-tests.md` | Each test carries information; the stated mutation names one code change and how many tests it kills |
63
+ | `verify-runtime-state.md` | A runtime verdict rests on a live probe from this session |
64
+ | `measurement-denominators.md` | Every count names what it scanned; a rate needs two runs |
65
+
66
+ ## Enforcement
67
+
68
+ This rule binds as prose discipline: a reviewer reads the shown-red record beside each new check a PR adds. No hook backs it, because a green that measured the code and a green that measured nothing look the same to a regex — the difference sits in what the check reached at run time.
@@ -4,7 +4,7 @@ paths: **/*.py
4
4
 
5
5
  # File-Global Constants
6
6
 
7
- This rule extends the `constants-location` rule defined in `~/.claude/docs/CODE_RULES.md` — see the ⚡ HOOK-ENFORCED RULES table, Constants location row.
7
+ This rule extends the `constants-location` rule defined in `~/.claude/docs/CODE_RULES.md` — see the ⚡ HOOK-ENFORCED RULES section, the "UPPER_SNAKE constants only in `config/`" clause.
8
8
 
9
9
  **file_global_constants_use_count:** A file-global constant is a module-level named constant declared at the top of a file (for example, an `UPPER_SNAKE_CASE` value assigned at module scope). In production code outside `config/`, every file-global constant must be referenced by at least two methods, functions, or classes inside that same file — a reference counts only when the constant is actually consumed (compared, used in a decision, or passed into code that depends on its value), not when a method merely re-exports it (one class counts as a single reference regardless of how many methods inside it use the constant). Module-level usages outside any function, method, or class body also count as a reference. A default parameter value counts as one reference from the enclosing function. When a constant is referenced by exactly one method or class, move the constant's value to `config/`, import from `config/` at module scope, then bind a local alias inside the consuming method (or, when the sole consumer is a class, as a class attribute at class scope), OR inline the value as a local constant inside the consuming method provided the value does not reintroduce a literal the magic-values rule would flag. When the sole reference is a module-level expression (for example, `ALL_ITEMS = build_registry(BATCH_SIZE)` at module scope), move the value to `config/` and reference the imported name directly at module scope; no local alias is needed.
10
10
 
@@ -0,0 +1,51 @@
1
+ # Filesystem Search
2
+
3
+ **When this applies:** Any search for files by name, path, extension, size, or date — through `es.exe`, a shell `find`, a recursive `Get-ChildItem` / `gci` / `dir` / `ls -R`, or the harness Grep and Glob tools.
4
+
5
+ ## The scope invariant
6
+
7
+ Every filesystem search names a scope. A scope is a project, worktree, or package directory under the work in progress, or a filter that narrows the walk: an `ext:` filter, a `dm:` date filter, a `size:` filter, or a name pattern.
8
+
9
+ A search that starts at the filesystem root, a drive root, bare home, or a network share is out of bounds. Narrow it to what you need.
10
+
11
+ ## Choosing a tool
12
+
13
+ Three tools are equally sanctioned; pick by what you know:
14
+
15
+ | You know | Use |
16
+ |---|---|
17
+ | The exact path | `Read` — no search at all |
18
+ | A name, extension, or date, on Windows | `es.exe` with a path scope |
19
+ | A name or path pattern | The harness `Glob` tool |
20
+ | Text inside files | The harness `Grep` tool |
21
+
22
+ When `es.exe` fails or returns nothing, fall back to `Glob` or `Grep` without pausing, and report the outage so the reader knows the index was unavailable. Ask the user only after all three tools fail.
23
+
24
+ `skills/everything-search/SKILL.md` holds the full `es.exe` operator reference: `ext:`, `dm:`, `size:`, wildcards, OR/AND/NOT, output flags, and the junction and drive-mapping note.
25
+
26
+ ## Allowed and denied shapes
27
+
28
+ | Allowed | Example |
29
+ |---|---|
30
+ | Cwd-relative | `find . -iname '*.py'` |
31
+ | Project path | `find packages/claude-dev-env -name code_rules_gate.py` |
32
+ | Git Bash scoped path | `find /c/Users/<you>/repo -iname SKILL.md` |
33
+ | Recursive listing under a project | `Get-ChildItem -Path .\src -Recurse` |
34
+ | Scoped Windows index search | `es.exe path:C:\dev\repo ext:py gate` |
35
+
36
+ | Denied | Example |
37
+ |---|---|
38
+ | Filesystem root | `find / -iname code_rules_gate.py` |
39
+ | Git Bash drive root | `find /c -name '*.py'` |
40
+ | Windows drive root | `find C:\ -name foo` / `Get-ChildItem C:\ -Recurse` |
41
+ | Bare home | `find ~ -name README.md` / `find $HOME -type f` |
42
+ | Network share root | `find //server/share -name x` — a path under the share (`//server/share/project/src`) is allowed |
43
+
44
+ ## Shell batching
45
+
46
+ Issue one shell search at a time when the walk is large. Parallel full-tree searches contend for the shell and can lock the host. Harness `Grep` and `Glob` calls carry no such cost and run in parallel freely — see [`parallel-tools.md`](parallel-tools.md).
47
+
48
+ ## Enforcement
49
+
50
+ - `unscoped_search_blocker` (PreToolUse on Bash and PowerShell, hosted by `bash_pre_tool_use_dispatcher`) denies a walk from an unscoped root and returns the scoped alternative.
51
+ - `es_exe_path_rewriter` (PreToolUse on Bash) substitutes `{project-name}` placeholders and bare registry keys in an `es.exe` command with their quoted absolute paths, read from `~/.claude/project-paths.json`. It allows and rewrites; it never blocks, and a machine with no registry file passes the command through unchanged. `scripts/setup_project_paths.py` writes the registry.
@@ -0,0 +1,27 @@
1
+ # gh CLI Conventions
2
+
3
+ Two call shapes the `gh` CLI gets wrong by default.
4
+
5
+ ## Body content goes in a file
6
+
7
+ Every `gh` command carrying markdown body content (`gh pr create/edit/comment/review`, `gh issue create/edit/comment`) uses `--body-file <path>` with a temp file — never a `--body` / `-b` string, where backticks land on GitHub as a literal `` \` ``. Write the temp file BOM-free:
8
+
9
+ ```powershell
10
+ [IO.File]::WriteAllText($bodyPath, $body, [Text.UTF8Encoding]::new($false))
11
+ ```
12
+
13
+ MCP GitHub tools take `body` as a structured parameter and are unaffected.
14
+
15
+ `gh_body_arg_blocker.py` (PreToolUse on Bash, hosted by `bash_pre_tool_use_dispatcher`) blocks `--body <arg>` and returns the corrective message.
16
+
17
+ ## Paginated reads slurp before they filter
18
+
19
+ Every `gh api` read of a paginated GitHub list endpoint (PR `reviews` / `comments` / `files`, issue `comments`, `pulls`, `issues`) uses `--paginate --slurp` piped to **external** `jq`. The built-in `--jq` runs per page, so a cross-page operation like `sort_by | last` gives a wrong-but-confident result.
20
+
21
+ Single-object endpoints (`pulls/<n>`, `issues/<n>`) skip pagination and may use `--jq` directly. For a newest-first walk, sort the slurped array and take the last element; for single-page bounds, cap with a `per_page` query parameter.
22
+
23
+ ## Sibling rules
24
+
25
+ - [`destructive-commands.md`](destructive-commands.md) — why a body describing `rm -rf` must travel by file path.
26
+ - [`durable-post-artifacts.md`](durable-post-artifacts.md) — what a post body may reference.
27
+ - [`proof-of-work-pr-comments.md`](proof-of-work-pr-comments.md) — what the proof comment must contain.
@@ -40,3 +40,29 @@ User-level rule: applies to **every** git repo that uses GitHub with `gh` (no ex
40
40
  | `*.plan.md` | Temporary planning files |
41
41
  | `SESSION_STATE.md` | Local session state |
42
42
  | `*.png *.jpg *.jpeg *.gif *.webp *.avif *.svg *.ico` | Images go to external storage, not GitHub |
43
+
44
+ An image a PR needs as visual evidence is not an exception to that row. Upload it to the repository's durable `artifacts` release with `python3 ~/.claude/scripts/gh_artifact_upload.py <file> <owner/repo>` and embed the permanent URL in the proof comment. The image lives on GitHub without entering the repository tree.
45
+
46
+ ## Responding to review feedback
47
+
48
+ **When this applies:** GitHub PR review feedback on a branch you are fixing.
49
+
50
+ 1. Fetch every reviewer comment before making any fix.
51
+ 2. Create a TodoWrite checklist with one item per comment.
52
+ 3. Fix systematically, marking each todo complete.
53
+ 4. Reply to each comment inline.
54
+ 5. Create one review-fix commit. Do not squash it with the original.
55
+
56
+ Repair only reported findings, then re-verify after every repair.
57
+
58
+ ## See also
59
+
60
+ | Rule | Covers |
61
+ |---|---|
62
+ | [`gh-cli-conventions.md`](gh-cli-conventions.md) | `--body-file` for post bodies; `--paginate --slurp` for list reads |
63
+ | [`proof-of-work-pr-comments.md`](proof-of-work-pr-comments.md) | The five-part proof comment every PR carries before leaving draft |
64
+ | [`re-stage-before-commit.md`](re-stage-before-commit.md) | Staging session edits so a commit does not drop them |
65
+ | [`verified-commit-gate-skip.md`](verified-commit-gate-skip.md) | Optional code-verifier review guidance |
66
+ | [`durable-post-artifacts.md`](durable-post-artifacts.md) | Keeping volatile scratch paths out of a post body |
67
+ | [`destructive-commands.md`](destructive-commands.md) | Allowed removal forms; destructive literals in commit and post bodies |
68
+ | [`code-standards.md`](code-standards.md) | The code standards a PR's diff is reviewed against |
@@ -0,0 +1,9 @@
1
+ # Hedging Claims
2
+
3
+ State a claim with the evidence that backs it, or name the claim unverified. A hedge word stands in for evidence you did not gather.
4
+
5
+ `hedging_language_blocker` (Stop hook, hosted by `stop_dispatcher`) blocks a response carrying one — `likely`, `probably`, `presumably`, `perhaps`, `possibly`, `seemingly`, `apparently`, `arguably`, `supposedly`, `ostensibly`, `conceivably`, `plausibly`, `unlikely`, `probable`, and the phrases `might be`, `could be`, `seems to be`, `appears to be`, `in all likelihood`, `more likely than not`, `it's possible that`.
6
+
7
+ Deleting the hedge word and keeping the claim does not clear the block. Gather the source, run the probe, or ask the user through `AskUserQuestion` — then re-output the whole revised response.
8
+
9
+ Sibling rules: [`research-mode.md`](research-mode.md) names what counts as a citation; [`verify-runtime-state.md`](verify-runtime-state.md) names the live probe a runtime verdict rests on.
@@ -37,7 +37,3 @@ Terse shorthand between tool calls is fine — that is you thinking. The final m
37
37
  ## Keep going on context
38
38
 
39
39
  A remaining-context or token count is not a reason to stop. Do not pause, summarize, or float a fresh session on account of context limits; keep working. When the user must see content word-for-word (a partial deliverable, a direct answer to a mid-run question), surface it through the channel the harness gives for that, not by ending the turn.
40
-
41
- ## Why
42
-
43
- A capable model under-delivers on long runs for predictable reasons: it overplans when it could act, stops on a promise, blocks on subagents, skips its own verification, fabricates progress, buries the result in working shorthand, or quits early over a context count. Each section above removes one of those failure modes so the run finishes.
@@ -0,0 +1,48 @@
1
+ ---
2
+ paths:
3
+ - "**/*.md"
4
+ - "**/*.py"
5
+ ---
6
+
7
+ # Measurement Denominators
8
+
9
+ **When this applies:** Any Write or Edit that states a count, rate, or coverage figure in a docstring or a `.md` file.
10
+
11
+ ## Rule
12
+
13
+ Every count names what it scanned. "Read 10 of 10 changed files" states the scan and the whole set it was drawn from. "Swept the files" states neither, and a reader takes it as full coverage of a scan that touched a fraction.
14
+
15
+ Three parts travel with each figure. The report author writes part 1 for every figure and part 2 when the figure is a rate; the consumer runs part 3:
16
+
17
+ 1. **A count carries its denominator.** Name both numbers: files read of files changed, rounds fired of rounds available, tests reached of tests collected, entries compared of entries present.
18
+ 2. **A rate needs two runs and a stated denominator.** One run yields a count. Written down as a rate — "fires 40% of the time" — it claims a spread across runs that one run cannot back. Report the count and the run that produced it until a second run exists; once it does, the rate stays counts across runs — "failed twice across 5 runs on this branch" — never a percentage.
19
+ 3. **The consumer cross-checks the count against the scope its denominator names.** A sweep reporting 3 files read of 10 changed fails coverage: its verdict reaches 3 of the 10 files its own denominator names. A sweep reporting 3 of 3 security-sensitive files states its own scope and covers all of it, so it passes. That comparison settles the sweep before anyone reads its result.
20
+
21
+ A number written into a docstring or a doc carries its denominator beside it. A number written there as a rate carries its run count too.
22
+
23
+ ## Shapes
24
+
25
+ | Bare figure | With its denominator |
26
+ |---|---|
27
+ | swept the files | read 10 of 10 changed files |
28
+ | all tests pass | 412 of 412 collected tests pass, 0 skipped |
29
+ | the hook catches this | the hook denies 6 of 6 recorded shapes |
30
+ | fails about 40% of the time | failed twice across 5 runs on this branch |
31
+ | most entries match | 88 of 90 entries match |
32
+
33
+ ## Cross-check at the consumer
34
+
35
+ A sweep reports "read 3 files". The change under review touches 10 files. The arithmetic reads: the sweep covered 3 of 10, so its clean verdict covers 3 of 10. The gap is the finding — send the sweep back for the other 7, and hold the verdict until the two numbers meet.
36
+
37
+ ## Sibling rules
38
+
39
+ | Rule | Role |
40
+ |---|---|
41
+ | `falsify-before-green.md` | A check's green counts once the check was shown red |
42
+ | `anti-corollary-tests.md` | Each test carries information; no corollary matrices; no suite that only matches the dead default |
43
+ | `docstring-prose-matches-implementation.md` | A docstring enumeration covers every behavior the body applies |
44
+ | `measurement-denominators.md` | Every count names what it scanned; a rate needs two runs |
45
+
46
+ ## Enforcement
47
+
48
+ This rule binds as prose discipline: a reviewer applies it to the counts a PR's prose and docstrings state, and to the counts a report claims. No hook backs it, because weighing a figure's denominator against the scope it covers needs meaning a regex cannot read.
@@ -1,11 +1,29 @@
1
- # NAS SSH Invocation Policy
1
+ # Running Commands on the NAS
2
2
 
3
- Reach the NAS through the Windows `System32/OpenSSH` binary with `-o BatchMode=yes` on every `ssh`, `scp`, or `sftp` command:
3
+ Reach the NAS through the `nas_ssh_key.py` runner, never through `ssh`, `scp` or `sftp`:
4
4
 
5
5
  ```
6
- "/c/Windows/System32/OpenSSH/ssh.exe" -o BatchMode=yes -o ConnectTimeout=10 -p 22 operator@nas.example.local "<cmd>"
6
+ python <runner-path> <command-script.sh> <private-key-path>
7
7
  ```
8
8
 
9
- Git Bash's MSYS `ssh` falls back to an interactive password prompt that hangs an unattended session; the `System32/OpenSSH` binary authenticates the key without a prompt, and `-o BatchMode=yes` turns an auth failure into a loud non-zero exit. `nas_ssh_binary_enforcer.py` (PreToolUse on Bash) enforces this: it denies a bare ssh-family word aimed at the NAS, and denies the full binary when `-o BatchMode=yes` is absent.
9
+ The first argument is a **path to a file** holding a bash script, not a command string. Write that
10
+ file with the Write tool. The whole script runs in one shell, so variables, `cd` and `source` carry
11
+ from line to line.
10
12
 
11
- Host, user, and port config, the `scp`/`sftp` forms, and the full rationale: `@~/.claude/docs/nas-ssh-invocation.md`.
13
+ The runner ships with the automation project it serves; read its path from that project's own
14
+ reference. Use the ops key under `~/.claude/keys` — keys under `~/.ssh` either carry a passphrase,
15
+ which cannot be answered unattended, or belong to other hosts.
16
+
17
+ The runner loads the key with paramiko and signs in the same process. The command-line clients check
18
+ the key file's permissions first and refuse it, and Git Bash's `ssh` then falls back to a password
19
+ prompt that hangs an unattended run. `nas_ssh_binary_enforcer.py` (PreToolUse on Bash) denies a bare
20
+ ssh-family word aimed at the NAS, and denies the full `System32/OpenSSH` binary when
21
+ `-o BatchMode=yes` is missing.
22
+
23
+ Host, ssh port and ssh user are constants inside the runner and are also under the `nas` key in
24
+ `~/.claude/local-identity.json`. Keep all three out of anything committed or posted.
25
+
26
+ To copy a file, write it inside the script with a quoted heredoc rather than reaching for `scp`.
27
+
28
+ The `/tmp` size limit, how to tell a real break from a platform-only one, and a failure-to-cause
29
+ table: `@~/.claude/docs/nas-ssh-invocation.md`.
@@ -18,6 +18,6 @@ When multiple tool calls have no dependencies between them, make all independent
18
18
  - Use real parameter values only. Do not guess or use placeholders to force parallelism.
19
19
  - If you are unsure whether calls are independent, run them sequentially.
20
20
 
21
- ## Why
21
+ ## The one surface that serializes
22
22
 
23
- Explicit reinforcement of parallel calling boosts compliance to near 100%. Sequential calls for independent operations waste time and round-trips for the user.
23
+ Harness tool calls Read, Grep, Glob, and the rest carry no shared cost and parallelize freely. A large shell filesystem walk does not: parallel full-tree searches contend for the shell and can lock the host, so issue those one at a time. See [`filesystem-search.md`](filesystem-search.md).
@@ -48,7 +48,7 @@ cannot tell which name states the truth. Rename the callee to a neutral form
48
48
  the two names agree on at every call site.
49
49
  ```
50
50
 
51
- The live version of this docstring sits on `check_polarity_name_contradiction` in `packages/claude-dev-env/hooks/blocking/code_rules_naming_collection.py`.
51
+ The live version of this docstring sits on `check_polarity_name_contradiction` in `~/.claude/hooks/blocking/code_rules_naming_collection.py`.
52
52
 
53
53
  A short narrative with no diagram is fine when a couple of plain sentences carry the whole picture. The diagram earns its place once the explanation grows past what two or three lines hold — the moment a wall of prose starts to form.
54
54
 
@@ -86,10 +86,6 @@ one — and you're debugging blind.
86
86
 
87
87
  Two surfaces carry this standard:
88
88
 
89
- - **Hook (the run-on backstop).** `check_docstring_runon_sentence` in `packages/claude-dev-env/hooks/blocking/code_rules_docstrings.py` flags the one mechanical mark of a wall: a single narrative sentence that is both over the word limit and joined by an em-dash or a semicolon. A hook cannot judge whether prose paints a picture, so it catches only this structural mark. It reads the narrative through a shared partition that sets aside any `::` literal block and any doctest, so a diagram's own arrows and dashes never count against the sentence.
89
+ - **Hook (the run-on backstop).** `check_docstring_runon_sentence` in `~/.claude/hooks/blocking/code_rules_docstrings.py` flags the one mechanical mark of a wall: a single narrative sentence that is both over the word limit and joined by an em-dash or a semicolon. A hook cannot judge whether prose paints a picture, so it catches only this structural mark. It reads the narrative through a shared partition that sets aside any `::` literal block and any doctest, so a diagram's own arrows and dashes never count against the sentence.
90
90
  - **Hook (the prose-wall backstop).** `check_docstring_prose_wall_without_illustration` in the same module flags a narrative that runs more than six prose lines with no diagram block. It marks the wall so the writer shows the behavior with a `::` example or a doctest and trims the prose to a few short lines. It cannot judge whether the diagram illustrates well; that stays with the audit lane.
91
- - **Audit (the judgment lane).** Category O sub-bucket O9 in `packages/claude-dev-env/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md` carries the illustrative-and-brief judgment the hook cannot. The audit teammate reads each changed docstring's narrative and asks whether a general developer follows it on the first read.
92
-
93
- ## Why
94
-
95
- A docstring earns its place by saving the reader a trip into the body. A wall of stacked machinery nouns costs more to read than the code it describes, so the reader skips it and the docstring becomes dead weight. Prose that paints a concrete scene — the moment, the input, the outcome — lets a reader reason about the code without reading it. Naming this standard makes the wall a finding at write time and at audit, rather than a slow defect a reader meets months later.
91
+ - **Audit (the judgment lane).** Category O sub-bucket O9 in `~/.claude/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md` carries the illustrative-and-brief judgment the hook cannot. The audit teammate reads each changed docstring's narrative and asks whether a general developer follows it on the first read.
@@ -4,4 +4,6 @@ All prose a person reads (chat, `AskUserQuestion`, docs, PR/issue bodies, commit
4
4
 
5
5
  The `plain_language_blocker` PreToolUse hook (AskUserQuestion + `.md` Write/Edit/MultiEdit) blocks a heavy word and names the everyday swap; code fences, inline code, blockquotes, URLs, and file paths are skipped.
6
6
 
7
+ [`eli11-replies`](eli11-replies.md) governs reply length and shape; this rule governs word choice.
8
+
7
9
  A project can keep its own domain words out of the check with a `.claude/plain-language-allow.json` file: a JSON array of terms. An exact, case-insensitive, whole-word match on any term passes. The hook reads this file only from inside the project tree, up to the repository root, so each project's allowlist stays with its own code.
@@ -20,7 +20,3 @@ The `pr_description_enforcer` hook enforces the standard at two points:
20
20
  - **On `gh pr ready`:** the hook reads the PR's comments and blocks readying while no comment passes the audit. `gh pr ready --undo` returns a PR to draft and is never blocked.
21
21
 
22
22
  A `gh` failure (network, auth, missing executable) never blocks — the gate fails open on tooling problems, and the comment audit skips bodies it cannot read.
23
-
24
- ## Why
25
-
26
- A PR body says what changed; the proof comment shows that it worked. Real command output, measured numbers, and a rendered image let a reviewer check the claim in seconds, with no need to re-run the work. Stating the gaps keeps the proof honest: the reviewer knows exactly what still rests on trust and where that is covered. Gating draft-to-ready makes the comment land before review starts, on every machine, whatever the session's habits.
@@ -4,6 +4,8 @@ Stage the files you edited this session right before you commit them. A plain `g
4
4
 
5
5
  `session_edit_stage_gate` (PreToolUse on Bash `git commit`) denies a commit that would drop tracked session edits and names the fix: `git add <paths>`, `git commit -a`, or a `# partial-commit` marker.
6
6
 
7
+ Staging covers tracked files you edited. Do not commit untracked files unless the user explicitly instructs it — an untracked file in the working tree is outside the change until they say otherwise.
8
+
7
9
  ## Escapes the denial does not restate
8
10
 
9
11
  - **A pathspec** — `git commit -- <paths>` or `git commit <paths>` commits only the named paths on purpose and steps the gate aside.
@@ -19,5 +19,15 @@ If you generate a claim and cannot find a supporting source, retract it. Do not
19
19
  ## 3. Direct quotes for factual grounding
20
20
  When working from documents, extract the actual text first before analyzing. Ground your response in word-for-word quotes, not paraphrased summaries. Reference the quote when making your point.
21
21
 
22
+ ## How citations appear in a chat reply
23
+
24
+ The grounding requirement above never relaxes: state no claim you cannot source. What changes with the channel is how much of the source you print. A chat reply carries the source in compact form — a linked source name, or a `file:line` reference. Word-for-word quotes and full citation lists belong in artifacts, PR bodies, and issue bodies, or in a reply when the user asks for them.
25
+
22
26
  ## Exceptions
23
27
  Creative thinking, brainstorming, and novel ideas don't require citation. You can synthesize across sources to reach new conclusions, but the inputs must be grounded.
28
+
29
+ ## Sibling rules
30
+
31
+ - [`explore-thoroughly.md`](explore-thoroughly.md) — grounds an implementation plan in the codebase, as this rule grounds a factual claim in a source.
32
+ - [`verify-runtime-state.md`](verify-runtime-state.md) — a runtime verdict needs a live probe from this session, not a citation.
33
+ - [`hedging-claims.md`](hedging-claims.md) — the Stop hook that catches an unverified claim wearing a hedge word.
@@ -0,0 +1,21 @@
1
+ # Shell Invocation
2
+
3
+ Two constraints govern every shell command an agent issues: which shell runs it, and what the command string may contain.
4
+
5
+ ## Use pwsh
6
+
7
+ Every Bash-tool shell command on Windows uses `pwsh`: `pwsh -NoProfile -File '<script>.ps1' <args>` for scripts, `pwsh -NoProfile -Command "..."` (or a literal `@'...'@` here-string) for inline work, or the built-in `PowerShell` tool for pure-PowerShell workflows (it supports `run_in_background`). Never wrap a script path in `-Command "& '...'"` — `-File` keeps `permissions.allow` matching. The `&` call operator is fine for invoking an executable at a path (`& '<venv>\Scripts\python.exe' script.py`).
8
+
9
+ The mandate covers the shell a command runs through, not every executable a command names. A direct interpreter invocation another rule documents — the paramiko NAS helper in [`nas-ssh-invocation.md`](nas-ssh-invocation.md), a `python` call on a repo script — conforms as written.
10
+
11
+ Keep `powershell`, `powershell.exe`, `cmd /c`, and `bash -c` out of the `settings.json` permission rules. `Audit-ShellPolicy.ps1` reports those forms and `Migrate-ShellPolicy.ps1` rewrites them to `pwsh`. Both ship in the claude-dev-env repo at `packages/claude-dev-env/scripts/` and run on demand, not as a live gate.
12
+
13
+ ## No shell substitution
14
+
15
+ No `$(...)`, unescaped backticks, or `<(...)` / `>(...)` process substitution in Bash tool commands. The allowlist matcher reads the raw command string, so a substitution wrapper forces a permission prompt even when every inner segment is auto-allowed. Split into separate tool calls, or use flag forms like `git -C "<path>" rev-parse HEAD`. Arithmetic `$((...))` passes: it spawns no subshell.
16
+
17
+ When a script file's literal body needs `$(...)`, author it with the Write tool, not a Bash heredoc.
18
+
19
+ ## Enforcement
20
+
21
+ `shell_substitution_blocker.py` (PreToolUse on Bash, hosted by `bash_pre_tool_use_dispatcher`) denies a command carrying a live substitution and returns the split-into-two-calls rewrite. Single-quoted runs are stripped before the scan, and a backtick preceded by an odd number of backslashes is escaped, so an inert mention passes.
package/rules/testing.md CHANGED
@@ -18,3 +18,7 @@ paths:
18
18
 
19
19
  If a component renders field X, the mock must have field X with a valid value.
20
20
  Incomplete mocks make it impossible to distinguish "broken code" from "missing data".
21
+
22
+ ## Tests Exercise Real Behavior
23
+
24
+ Tests exercise real behavior, real data, and production code paths. A test that asserts on a stand-in for the production path proves the stand-in works.
@@ -1,28 +1,4 @@
1
- # Verified-Commit-Gate Skip Marker
1
+ # Optional Verifier Review
2
2
 
3
- **When this applies:** A `git commit` or `git push` through the Bash tool is blocked by the `verified_commit_gate` hook.
4
-
5
- ## The marker
6
-
7
- Appending the comment `# verify-skip` as a trailing shell comment to the Bash command exempts that single commit or push from the gate. The hook (`hooks/blocking/verified_commit_gate.py`, marker constant `VERIFICATION_BYPASS_MARKER`) recognizes the marker only when its leading `#` sits at a word boundary and outside every quoted region — a genuine comment, not a data-only mention inside a quoted commit message or `gh` body — and lets the command run without a minted verdict.
8
-
9
- ## When the marker is allowed
10
-
11
- Use it only when both hold:
12
-
13
- 1. The gate is blocking the command, and
14
- 2. The branch surface content is the same code a `code-verifier` already passed clean — nothing effectively changed since that clean verdict.
15
-
16
- That situation arises when the verdict fails to cover the current surface even though the code is the same: a clean verdict that never minted (the verifier's fenced block ran in a resumed turn, so the SubagentStop minter never fired), a surface hash perturbed by index-only staging churn, or a concurrent worktree write that was fully reverted back to the verified content. Before using the marker, confirm the match yourself: the test suite the verifier ran still passes, and the diff holds no content beyond what the clean verdict covered.
17
-
18
- ## When the marker is not allowed
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:
21
-
22
- - Skip a branch's first verification.
23
- - Commit or push after any real code change since the last clean verdict — one changed line means a fresh verification.
24
- - Work around a verifier that reported findings; findings get repaired and re-verified.
25
-
26
- ## One command, one exemption
27
-
28
- The marker exempts only the command that carries it. The next commit or push on the branch faces the gate again, so a follow-up change still verifies before it lands.
3
+ Code-verifier review is an optional workflow selected by the task owner.
4
+ Commit and push operations use the checks selected for the task.
@@ -47,3 +47,8 @@ Reserve user questions for:
47
47
 
48
48
  **Wrong:** "Is there a Prisma schema in this project?"
49
49
  **Right:** Glob for `schema.prisma` and check.
50
+
51
+ ## Parent rules
52
+
53
+ - [`ask-user-question-required.md`](ask-user-question-required.md) — once a question genuinely belongs to the user, this rule routes it through `AskUserQuestion`.
54
+ - [`verify-runtime-state.md`](verify-runtime-state.md) — the same duty applied to a verdict: gather the live probe before you conclude, not just before you ask.