claude-dev-env 2.5.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.
- package/CLAUDE.md +20 -57
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
- package/agents/CLAUDE.md +1 -1
- package/agents/code-verifier.md +36 -7
- package/bin/codex-compat.mjs +104 -0
- package/bin/codex-compat.test.mjs +51 -0
- package/codex-capability-map.json +13 -0
- package/docs/CODE_RULES.md +2 -0
- package/docs/codex-compatibility.md +25 -0
- package/docs/nas-ssh-invocation.md +96 -12
- package/docs/references/code-review-enforcement.md +31 -6
- package/hooks/blocking/CLAUDE.md +3 -0
- package/hooks/blocking/config/code_review_enforcement_constants.py +40 -10
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +56 -3
- package/hooks/blocking/eli11_reply_enforcer.py +479 -0
- package/hooks/blocking/gh_body_arg_blocker.py +1 -1
- package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
- package/hooks/blocking/shell_substitution_blocker.py +129 -0
- package/hooks/blocking/state_description_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +1 -1
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
- package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
- package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
- package/hooks/blocking/test_stop_dispatcher.py +23 -0
- package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +4 -8
- package/hooks/blocking/unscoped_search_blocker.py +391 -0
- package/hooks/git-hooks/CLAUDE.md +3 -0
- package/hooks/git-hooks/conftest.py +30 -0
- package/hooks/git-hooks/gate_utils.py +2 -2
- package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
- package/hooks/git-hooks/pre_push.py +75 -4
- package/hooks/git-hooks/pre_push_base_reference.py +166 -0
- package/hooks/git-hooks/test_config.py +0 -15
- package/hooks/git-hooks/test_gate_utils.py +3 -15
- package/hooks/git-hooks/test_pre_commit.py +1 -15
- package/hooks/git-hooks/test_pre_push.py +236 -27
- package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
- package/hooks/hooks.json +0 -12
- package/hooks/hooks_constants/CLAUDE.md +5 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
- package/hooks/hooks_constants/shell_command_segments.py +82 -0
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
- package/package.json +4 -2
- package/rules/CLAUDE.md +17 -23
- package/rules/agent-spawn-protocol.md +6 -6
- package/rules/anti-corollary-tests.md +1 -1
- package/rules/bdd.md +1 -1
- package/rules/cleanup-temp-files.md +10 -4
- package/rules/code-standards.md +7 -0
- package/rules/conservative-action.md +1 -5
- package/rules/context7.md +0 -4
- package/rules/destructive-commands.md +47 -0
- package/rules/doc-inventory-integrity.md +48 -0
- package/rules/doc-prose-cuts.md +58 -0
- package/rules/docstring-prose-matches-implementation.md +10 -2
- package/rules/durable-post-artifacts.md +0 -4
- package/rules/eli11-replies.md +31 -0
- package/rules/explore-thoroughly.md +4 -4
- package/rules/falsify-before-green.md +68 -0
- package/rules/file-global-constants.md +1 -1
- package/rules/filesystem-search.md +51 -0
- package/rules/gh-cli-conventions.md +27 -0
- package/rules/git-workflow.md +26 -0
- package/rules/hedging-claims.md +9 -0
- package/rules/long-horizon-autonomy.md +0 -4
- package/rules/measurement-denominators.md +48 -0
- package/rules/nas-ssh-invocation.md +23 -5
- package/rules/parallel-tools.md +2 -2
- package/rules/plain-illustrative-docstrings.md +3 -7
- package/rules/plain-language.md +2 -0
- package/rules/proof-of-work-pr-comments.md +0 -4
- package/rules/re-stage-before-commit.md +2 -0
- package/rules/research-mode.md +10 -0
- package/rules/shell-invocation.md +21 -0
- package/rules/testing.md +4 -0
- package/rules/verified-commit-gate-skip.md +3 -27
- package/rules/verify-before-asking.md +5 -0
- package/rules/windows-filesystem-safe.md +1 -1
- package/rules/workers-done-before-complete.md +4 -0
- package/scripts/Migrate-ShellPolicy.ps1 +1 -1
- package/scripts/codex_capability_bridge.py +171 -0
- package/scripts/codex_compat_materializer.py +1087 -0
- package/scripts/codex_compat_watcher.py +502 -0
- package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
- package/scripts/invoke_code_review.py +11 -4
- package/scripts/sync_to_cursor/rules.py +0 -10
- package/scripts/test_invoke_code_review.py +143 -0
- package/scripts/test_invoke_code_review_chain.py +1 -1
- package/scripts/test_invoke_code_review_contract.py +1 -1
- package/scripts/tests/test_code_review_constants.py +80 -0
- package/scripts/tests/test_codex_capability_bridge.py +91 -0
- package/scripts/tests/test_codex_compat_materializer.py +632 -0
- package/scripts/tests/test_codex_compat_watcher.py +599 -0
- package/scripts/tests/test_sync_to_cursor.py +0 -1
- package/skills/autoconverge/workflow/converge.mjs +1 -1
- package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
- package/skills/condensing-instructions/SKILL.md +42 -51
- package/skills/fresh-branch/CLAUDE.md +1 -1
- package/skills/fresh-branch/SKILL.md +5 -6
- package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
- package/skills/orchestrator/SKILL.md +23 -9
- package/skills/orchestrator-refresh/SKILL.md +20 -1
- package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
- package/skills/session-log/SKILL.md +1 -1
- package/rules/claude-md-orphan-file.md +0 -28
- package/rules/cleanup-command-forms.md +0 -23
- package/rules/code-reviews.md +0 -11
- package/rules/env-var-table-code-drift.md +0 -10
- package/rules/gh-body-file.md +0 -5
- package/rules/gh-paginate.md +0 -3
- package/rules/hook-prose-matches-detector.md +0 -15
- package/rules/no-historical-clutter.md +0 -26
- package/rules/no-inline-destructive-literals.md +0 -9
- package/rules/no-justification-noise.md +0 -61
- package/rules/package-inventory-stale-entry.md +0 -25
- package/rules/right-sized-engineering.md +0 -28
- package/rules/self-contained-docs.md +0 -17
- package/rules/shell-invocation-policy.md +0 -5
- package/rules/state-what-is.md +0 -25
- package/rules/tdd.md +0 -7
package/rules/CLAUDE.md
CHANGED
|
@@ -11,35 +11,33 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. A rule withou
|
|
|
11
11
|
|
|
12
12
|
| File | Rule |
|
|
13
13
|
|---|---|
|
|
14
|
-
| `agent-spawn-protocol.md` |
|
|
14
|
+
| `agent-spawn-protocol.md` | Check context sufficiency before a spawn and ask subagents for file-and-line answers; `/prompt-generator` is recommended for a complex or user-facing spawn |
|
|
15
15
|
| `anti-corollary-tests.md` | Tests must carry information: no corollary matrices over canonical reductions, no suite that only matches a dead-implementation default, stated mutation in the audit lane |
|
|
16
16
|
| `ask-user-question-required.md` | Every user-directed question goes through the `AskUserQuestion` tool — no plain-text questions |
|
|
17
17
|
| `bdd.md` | BDD discovery-driven development workflow and Example Mapping reference |
|
|
18
|
-
| `claude-md-orphan-file.md` | Every backticked bare filename in a per-directory `CLAUDE.md` table's first column names a file in that directory's subtree |
|
|
19
|
-
| `cleanup-command-forms.md` | Never use bash `rm` to clean up; use the PowerShell `Remove-Item` and `git worktree remove --force` forms the `destructive_command_blocker` hook never prompts on, and carry the rule into every subagent prompt |
|
|
20
18
|
| `cleanup-temp-files.md` | Remove temporary files created during a task when the task is complete |
|
|
21
|
-
| `code-
|
|
22
|
-
| `code-standards.md` | Pointer to `CODE_RULES.md` as the single source of truth |
|
|
19
|
+
| `code-standards.md` | Pointer to `CODE_RULES.md` as the single source of truth, including §8 (TDD) and §7 (right-sizing); BDD is the outer process and TDD the inner loop |
|
|
23
20
|
| `confirm-implementation-forks.md` | Stop and ask when two or more workable implementation paths change the deliverable |
|
|
24
21
|
| `conservative-action.md` | Research and recommend when intent is ambiguous; act only on explicit request |
|
|
25
22
|
| `context7.md` | Use Context7 MCP to fetch current library docs; always prefer live docs over built-in knowledge |
|
|
23
|
+
| `destructive-commands.md` | Allowed removal forms and the ephemeral namespace the `destructive_command_blocker` auto-allows; keep destructive literals out of a Bash command string even as data |
|
|
24
|
+
| `doc-inventory-integrity.md` | Three inventory shapes stay in step with the code: a per-directory `CLAUDE.md` file list, a package `README`/`SKILL.md` inventory, and an env-var summary table |
|
|
25
|
+
| `doc-prose-cuts.md` | Four sentence shapes to cut from prose: exclusion claims, justification sentences, conversation references, and time references |
|
|
26
26
|
| `docstring-prose-matches-implementation.md` | Prose enumerations in docstrings cover every behavior the body applies |
|
|
27
27
|
| `durable-post-artifacts.md` | GitHub post bodies never reference volatile scratch paths; text embeds inline and binary artifacts upload to the `artifacts` release with the permanent URL linked |
|
|
28
|
+
| `eli11-replies.md` | Every chat reply the user reads follows one shape: action first, detail last, few words; `plain-language.md` governs word choice, this rule governs reply length and shape |
|
|
28
29
|
| `explore-thoroughly.md` | Read relevant files and map existing patterns before proposing a change |
|
|
30
|
+
| `falsify-before-green.md` | A check's green counts as evidence only after that same check ran red on a named break, with a passing control beside it |
|
|
29
31
|
| `file-global-constants.md` | File-global constants need at least two same-file references; otherwise move value to `config/` |
|
|
30
|
-
| `
|
|
31
|
-
| `gh-
|
|
32
|
-
| `git-workflow.md` | PR workflow: always create as draft, one commit per review stage, never commit working docs or images |
|
|
33
|
-
| `
|
|
32
|
+
| `filesystem-search.md` | Every filesystem search names a scope; `es.exe`, `Glob`, `Grep`, and `Read` are equally sanctioned, and the `unscoped_search_blocker` denies a walk from a root |
|
|
33
|
+
| `gh-cli-conventions.md` | `--body-file` for every `gh` body; `--paginate --slurp` piped to external `jq` for every paginated list read |
|
|
34
|
+
| `git-workflow.md` | PR workflow: always create as draft, one commit per review stage, never commit working docs or images; carries the review-response protocol and a See-also block for its seven siblings |
|
|
35
|
+
| `hedging-claims.md` | State the evidence or name the claim unverified; the `hedging_language_blocker` Stop hook sends a hedged response back for a re-check |
|
|
34
36
|
| `long-horizon-autonomy.md` | Autonomous-run behaviors: act on what you have, do not end on a promise, delegate and keep working |
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `no-
|
|
38
|
-
| `no-inline-destructive-literals.md` | No destructive-command literals in Bash tool command strings, even as data |
|
|
39
|
-
| `no-justification-noise.md` | Markdown states facts a reader can act on; cut a present-tense sentence that only justifies a stated choice or restates a gain the reader already works out from the behavior or from a rule enforced elsewhere |
|
|
40
|
-
| `env-var-table-code-drift.md` | Every env-var summary table row in a `.md` file names a code file whose source references the variable |
|
|
37
|
+
| `measurement-denominators.md` | Every reported count names what it scanned and carries its denominator; a rate needs two runs; the consumer cross-checks the count against the scope its denominator names |
|
|
38
|
+
| `nas-ssh-invocation.md` | Reach the NAS through the paramiko-backed `nas_ssh_key.py` runner, which signs in-process; every ssh-family client reads the key through file permissions, refuses it, and stalls an unattended run on a password prompt |
|
|
39
|
+
| `no-cross-skill-duplicate-helpers.md` | Within one skill a duplicated helper is blocked; across two skill folders a small self-contained copy is a sanctioned isolation tradeoff that draws a non-blocking advisory naming the source skill |
|
|
41
40
|
| `orphan-css-class.md` | Every `class="..."` attribute in Python-generated markup has a matching selector in the `<style>` block |
|
|
42
|
-
| `package-inventory-stale-entry.md` | A new production code file added to a directory carries an entry in that directory's `README.md`/`CLAUDE.md` file inventory |
|
|
43
41
|
| `paired-test-coverage.md` | A public function omitted by a module's established paired test suite must get a behavioral test |
|
|
44
42
|
| `parallel-tools.md` | Make all independent tool calls in a single response |
|
|
45
43
|
| `plain-illustrative-docstrings.md` | Public docstring narrative reads plainly and shows behavior with a diagram block (a `::` example or a doctest), painting a concrete scene a general developer follows on first read; a run-on backstop hook, a prose-wall backstop hook, and Category O9 audit enforce it |
|
|
@@ -48,14 +46,10 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. A rule withou
|
|
|
48
46
|
| `proof-of-work-pr-comments.md` | Every PR carries one five-part proof-of-work comment before it leaves draft; the `pr_description_enforcer` hook audits proof-shaped comments and gates `gh pr ready` |
|
|
49
47
|
| `re-stage-before-commit.md` | Stage the files edited this session before `git commit`; the session edit stage gate denies a commit that leaves a tracked session edit unstaged, with `-a`, a pathspec, a preceding `git add`, and `# partial-commit` as escapes |
|
|
50
48
|
| `research-mode.md` | Three anti-hallucination constraints: say "I don't know", verify with citations, quote for factual grounding |
|
|
51
|
-
| `
|
|
52
|
-
| `self-contained-docs.md` | Every document is fully self-contained; no references to the conversation that produced it |
|
|
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 |
|
|
55
|
-
| `tdd.md` | Test-driven development: red → green → refactor, no production code before a failing test |
|
|
49
|
+
| `shell-invocation.md` | Windows shell commands run through `pwsh`; no `$(...)`, backtick, or process substitution in a Bash tool command |
|
|
56
50
|
| `testing.md` | Test quality and infrastructure standards |
|
|
57
51
|
| `vault-context.md` | Search Obsidian vault for prior sessions and decisions before substantive project work |
|
|
58
|
-
| `verified-commit-gate-skip.md` |
|
|
52
|
+
| `verified-commit-gate-skip.md` | Code-verifier review is optional; commits and pushes use the checks selected for the task |
|
|
59
53
|
| `verify-before-asking.md` | Answer questions by inspecting files or running tools before asking; recalled facts expire until re-checked this session |
|
|
60
54
|
| `verify-runtime-state.md` | A "component is fine / not at fault" verdict rests on a live probe this session, never code reading or prior-session memory |
|
|
61
55
|
| `windows-filesystem-safe.md` | Use safe `rmtree` patterns on Windows; `mkdirSync` with `recursive: true` on possibly-existing paths |
|
|
@@ -64,4 +58,4 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. A rule withou
|
|
|
64
58
|
|
|
65
59
|
## Hook enforcement
|
|
66
60
|
|
|
67
|
-
Rules marked with ⚡ in
|
|
61
|
+
Rules marked with ⚡ in `~/.claude/docs/CODE_RULES.md` are backed by a blocking hook in `hooks/blocking/`. Rules without a hook are judgment-based and enforced via audit rubrics (`audit-rubrics/`).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# Agent Spawn
|
|
1
|
+
# Agent Spawn Guidance
|
|
2
2
|
|
|
3
|
-
Before any Agent or Task tool spawn
|
|
3
|
+
Before any Agent or Task tool spawn, check context sufficiency: you can name the files involved, the constraints, and what success looks like, and the task is unambiguous. When you cannot, investigate or ask the user first — a spawn with incomplete context returns work you throw away.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
2. **Craft the prompt with `/prompt-generator`** — feed it the goal, the target files from step 1, the constraints, the output format, and the acceptance criteria; use its output as the agent's `prompt`.
|
|
7
|
-
3. **Spawn** with that structured prompt.
|
|
5
|
+
Ask each research subagent for precise file-and-line answers. A finding that names a path and a line number is one a reader can check.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
`/prompt-generator` is recommended for a complex spawn, or one whose output the user reads directly: feed it the goal, the target files, the constraints, the output format, and the acceptance criteria, then use its output as the agent's `prompt`. Inside a scoped autonomous run, an inline structured prompt you write yourself is fine.
|
|
8
|
+
|
|
9
|
+
Full step detail and the relationship to other rules: `@~/.claude/docs/agent-spawn-protocol.md`.
|
|
@@ -59,7 +59,7 @@ A structural hook is the wrong tool here. "Is this a corollary?" and "would this
|
|
|
59
59
|
|
|
60
60
|
| Rule | Role |
|
|
61
61
|
|---|---|
|
|
62
|
-
| `
|
|
62
|
+
| `code-standards.md` | Points at CODE_RULES §8: write a failing test before production code |
|
|
63
63
|
| `testing.md` | Mocks and test infrastructure standards |
|
|
64
64
|
| `paired-test-coverage.md` | Every public function in an established suite gets a behavioral test |
|
|
65
65
|
| `anti-corollary-tests.md` | Each test carries information; no corollary matrices; no suite that only matches the dead default |
|
package/rules/bdd.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
1. **Deliberate Discovery** — Reduce uncertainty before code; surface what you do not know (Smart & Molak §5.4).
|
|
14
14
|
2. **Illustrate** — Explore goals, constraints, and concrete examples in chat; "given … when … then …" style outcomes.
|
|
15
15
|
3. **Formulate** — Express behavior as narrow **"should …"** specifications the user can approve.
|
|
16
|
-
4. **Automate** —
|
|
16
|
+
4. **Automate** — Build each formulated behavior through the TDD inner loop: CODE_RULES §8, red-green-refactor, canonical as stated in [`code-standards.md`](code-standards.md).
|
|
17
17
|
|
|
18
18
|
Conversation is the essential practice: if discovery is skipped, structured formats do not rescue the workflow (Minimal BDD).
|
|
19
19
|
|
|
@@ -15,13 +15,19 @@ Source: [Anthropic — Reduce file creation in agentic coding](https://platform.
|
|
|
15
15
|
- Leave the working directory cleaner than you found it.
|
|
16
16
|
- If a file was created at the user's explicit request (not as a byproduct of your process), leave it in place.
|
|
17
17
|
|
|
18
|
+
## Exceptions to the removal duty
|
|
19
|
+
|
|
20
|
+
Three kinds of file are already ephemeral and need no explicit removal:
|
|
21
|
+
|
|
22
|
+
- A file under the OS temporary root.
|
|
23
|
+
- A file under `$CLAUDE_JOB_DIR`, which the harness clears with the job.
|
|
24
|
+
- A child agent's scratch file, which the parent removes at teardown.
|
|
25
|
+
|
|
26
|
+
Use an allowed removal form for everything else: [`destructive-commands.md`](destructive-commands.md) names them.
|
|
27
|
+
|
|
18
28
|
## What counts as temporary
|
|
19
29
|
|
|
20
30
|
- Scripts written to test a hypothesis or run a one-off check
|
|
21
31
|
- Debug output files, log dumps, or intermediate data exports
|
|
22
32
|
- Helper files created to work around tool limitations
|
|
23
33
|
- Any file the user did not ask for and would not expect to find after the task
|
|
24
|
-
|
|
25
|
-
## Why
|
|
26
|
-
|
|
27
|
-
Temporary files accumulate across sessions and clutter the project root. Latest models sometimes use files as scratchpads during iteration, and these leftovers confuse both the user and future sessions if not cleaned up.
|
package/rules/code-standards.md
CHANGED
|
@@ -4,3 +4,10 @@
|
|
|
4
4
|
> This is the single source of truth for code standards. Non-negotiable.
|
|
5
5
|
|
|
6
6
|
`CODE_RULES.md` (`~/.claude/docs/CODE_RULES.md`) is the compact reference for every standard: self-documenting names, centralized configuration, constant reuse, no magic literals, full words, complete type hints, required-vs-optional parameters, construction logic in the model, temporary-code `TODO:` markers, behavior-first component names, and TDD.
|
|
7
|
+
|
|
8
|
+
Two standards live there in full and nowhere else:
|
|
9
|
+
|
|
10
|
+
- **TDD** — CODE_RULES §8 is canonical: red, green, refactor, with no production code before a failing test.
|
|
11
|
+
- **Right-sized engineering** — CODE_RULES §7 is canonical: functions over classes, concrete over abstract, an abstraction added at the commit that introduces its second concrete implementation.
|
|
12
|
+
|
|
13
|
+
BDD is the outer process and TDD is the inner loop: [`bdd.md`](bdd.md) discovers and formulates the behavior a feature needs, then each formulated behavior is built through the CODE_RULES §8 red-green-refactor cycle.
|
|
@@ -14,8 +14,4 @@ Proceed with edits, file modifications, or implementations only when the user ex
|
|
|
14
14
|
- If the user describes a problem, investigate and recommend. Do not jump to implementation.
|
|
15
15
|
- If the user says "do it", "go ahead", "make the change", or similarly explicit language, proceed with action.
|
|
16
16
|
- Once the user has explicitly asked and you have what you need, act — do not re-open settled facts or decisions, and do not re-survey options you will not pursue. This rule governs the ambiguous case; the clear case belongs to `long-horizon-autonomy`.
|
|
17
|
-
- When in doubt,
|
|
18
|
-
|
|
19
|
-
## Why
|
|
20
|
-
|
|
21
|
-
Acting prematurely wastes effort and round-trips when the user wanted a different approach. Exploring first produces better outcomes than committing early. This is especially important with models that have a strong action bias.
|
|
17
|
+
- When in doubt, put the decision to the user through `AskUserQuestion` with two options: show the approach first, or make the change now.
|
package/rules/context7.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
alwaysApply: true
|
|
3
|
-
---
|
|
4
|
-
|
|
5
1
|
When working with libraries, frameworks, or APIs — use Context7 MCP to fetch current documentation instead of relying on training data. This includes setup questions, code generation, API references, and anything involving specific packages.
|
|
6
2
|
|
|
7
3
|
## Steps
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Destructive Commands in Bash
|
|
2
|
+
|
|
3
|
+
The `destructive_command_blocker` PreToolUse hook watches every Bash-tool command and matches destructive patterns (`rm -rf`, `git reset --hard`, `dd`, `mkfs`, `chmod -R`, fork bombs) as raw text, with no quote-awareness. Anything it cannot prove safe falls through to a confirmation prompt. In a background or auto-mode run no human can answer that prompt, so the call stalls.
|
|
4
|
+
|
|
5
|
+
Two consequences follow: use an allowed removal form, and keep a destructive literal out of the command string even when it rides only as data.
|
|
6
|
+
|
|
7
|
+
## Removal forms that never prompt
|
|
8
|
+
|
|
9
|
+
- **Scratch and probe files** — the PowerShell tool: `Remove-Item -Recurse -Force -Confirm:$false <absolute path>`. The hook watches only the Bash tool, so a PowerShell removal never reaches it.
|
|
10
|
+
- **Worktrees** — `git worktree remove --force <path>`. This matches no destructive pattern.
|
|
11
|
+
- **Tracked files** — `git rm <path>`, which records the deletion in the index.
|
|
12
|
+
- **Bash `rm` when unavoidable** — one standalone `rm`, absolute literal paths, no chaining, no globs, every target inside the ephemeral namespace below.
|
|
13
|
+
|
|
14
|
+
## The ephemeral namespace the hook auto-allows
|
|
15
|
+
|
|
16
|
+
An `rm` is auto-allowed when it is a single invocation and every target resolves inside one of:
|
|
17
|
+
|
|
18
|
+
- The OS temporary root (`tempfile.gettempdir()`).
|
|
19
|
+
- A path rooted at `/tmp` or `/temp`, drive-letter tolerant.
|
|
20
|
+
- A path holding a `/worktrees/` or `/worktree/` segment, or a directory git reports inside a worktree admin directory.
|
|
21
|
+
- `~/.claude`.
|
|
22
|
+
|
|
23
|
+
A bare ephemeral root (`/tmp`, the OS temp root itself, a bare directory named `worktrees` or `worktree`) is refused, so a single stray argument cannot wipe the whole namespace.
|
|
24
|
+
|
|
25
|
+
Four environment variables resolve inside a target token: `TEMP`, `TMP`, `TMPDIR`, and `CLAUDE_JOB_DIR`. Any other variable, a `$(...)` or backtick expansion, or a brace glob makes the target unresolvable and the command prompts. A `$CLAUDE_JOB_DIR` path is auto-allowed only when it resolves into the namespace above — the variable is readable, not a blanket pass. Set `CLAUDE_DESTRUCTIVE_DISABLE_EPHEMERAL_AUTO_ALLOW` to a truthy value to turn the whole auto-allow off.
|
|
26
|
+
|
|
27
|
+
A file left in the OS temp directory or under `$CLAUDE_JOB_DIR` is cleaned by the harness and needs no explicit removal — see the exception clause in [`cleanup-temp-files.md`](cleanup-temp-files.md).
|
|
28
|
+
|
|
29
|
+
## Keep destructive literals out of the command string
|
|
30
|
+
|
|
31
|
+
A destructive literal carried only as data — a commit message, a PR or issue body, an echoed string, a `python -c` / `node -e` / `awk` argument, a heredoc — trips the same raw-text match even though the shell never executes it.
|
|
32
|
+
|
|
33
|
+
- Bodies that describe destructive-command behavior go in a file passed by path: `git commit -F <file>`, `gh … --body-file <file>` (see [`gh-cli-conventions.md`](gh-cli-conventions.md)). Never `git commit -m` or `gh … -b`.
|
|
34
|
+
- To exercise or verify the blocker, or any hook, run the committed test suite (`python -m pytest <test_file>`), which passes the command strings as in-language data. Never an inline `python -c` harness.
|
|
35
|
+
|
|
36
|
+
## Every subagent prompt carries the rule
|
|
37
|
+
|
|
38
|
+
A prompt-delivered directive reaches only the agent that gets it. An agent that spawns its own workers — review lenses, fix agents, verifiers — copies this line into every subagent prompt it issues, so a grandchild cleaning up its own probe file uses an allowed form:
|
|
39
|
+
|
|
40
|
+
> Never use bash rm in any form. Delete scratch/probe files with the PowerShell tool (Remove-Item -Recurse -Force -Confirm:$false <absolute path>), or leave them in the OS temp dir; remove worktrees only via git worktree remove --force.
|
|
41
|
+
|
|
42
|
+
Prefer that a child leaves its scratch files for the parent to remove at teardown.
|
|
43
|
+
|
|
44
|
+
## Sibling rules
|
|
45
|
+
|
|
46
|
+
- [`cleanup-temp-files.md`](cleanup-temp-files.md) — which scratch files a task removes, and which it leaves.
|
|
47
|
+
- [`windows-filesystem-safe.md`](windows-filesystem-safe.md) — the safe `rmtree` / `force_rmtree` patterns for read-only Windows files.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.md"
|
|
4
|
+
- "**/*.py"
|
|
5
|
+
- "**/*.mjs"
|
|
6
|
+
- "**/*.js"
|
|
7
|
+
- "**/*.ts"
|
|
8
|
+
- "**/*.ps1"
|
|
9
|
+
- "**/*.sh"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Documentation Inventory Integrity
|
|
13
|
+
|
|
14
|
+
A doc that inventories code is a contract: a reader trusts the listing to map the directory, trusts a shown command to run, and trusts a table row to name the file that reads the variable. Three hooks hold the three inventory shapes in step with the code.
|
|
15
|
+
|
|
16
|
+
## 1. A per-directory `CLAUDE.md` names files that exist
|
|
17
|
+
|
|
18
|
+
Every bare filename a per-directory `CLAUDE.md` names points at a file in the subtree that `CLAUDE.md` describes — both the filenames its table cells list and the scripts its fenced run commands invoke (`python script.py`). Add the row and the run command in the change that adds the file; drop both in the change that removes it.
|
|
19
|
+
|
|
20
|
+
`claude_md_orphan_file_blocker.py` (PreToolUse on Write|Edit|MultiEdit of any `CLAUDE.md`) reads the content the tool would leave on disk. For an Edit or MultiEdit it reconstructs the post-edit file and notes which orphans the file already held, so a pre-existing orphan on an untouched line is excluded and only an orphan the edit introduces is reported; when the existing file cannot be read it scans the raw `new_string` fragments instead.
|
|
21
|
+
|
|
22
|
+
It collects two kinds of reference:
|
|
23
|
+
|
|
24
|
+
- **Table cells** — the first column of each markdown table row **outside** a fenced code block, keeping cells that name a bare filename in backticks, with no path separator, not a slash-command, ending in a known extension (`.py`, `.md`, `.json`, `.mjs`, `.js`, `.ts`, `.ps1`, `.cmd`, `.ahk`, `.yml`, `.yaml`, `.sh`, `.txt`, `.cfg`, `.toml`, `.ini`).
|
|
25
|
+
- **Run commands** — each line **inside** a fenced code block that invokes an interpreter (`python`, `python.exe`, `python3`, `node`, `pwsh`, `powershell`, `bash`, `sh`, `ruby`, `perl`) on a script, taking that script's basename when it ends in `.py`, `.mjs`, `.js`, `.ts`, `.ps1`, `.sh`, `.rb`, or `.pl`.
|
|
26
|
+
|
|
27
|
+
A fenced *table row* is an example and contributes nothing; a fenced *run command* is a contract the reader runs and is checked. The write is blocked when a collected filename exists nowhere under the scan root — the `CLAUDE.md` directory's parent, covering the directory, its subdirectories, and its siblings. A filesystem error that halts the subtree walk fails open.
|
|
28
|
+
|
|
29
|
+
The check stays quiet for a target that is not a `CLAUDE.md`, for a cell holding a path, a subdirectory ending in `/`, or a slash-command, for a table row inside a fence, for an inline `python x.py` mention outside a fence, and for a table naming an explicit relative-path source (a `../` token), which documents files outside the subtree by design.
|
|
30
|
+
|
|
31
|
+
## 2. A package inventory names each new production file
|
|
32
|
+
|
|
33
|
+
A package directory that documents its own files in a `README.md` Layout table, a `CLAUDE.md` "Key files" list, or a skill `SKILL.md` Layout table keeps that inventory in step with the directory. A new production file in such a directory gets its entry — a table row or a list bullet naming the file in backticks and saying what it does — in the same change.
|
|
34
|
+
|
|
35
|
+
`package_inventory_stale_blocker.py` (PreToolUse on Write) blocks a new production file whose basename appears in no present inventory and names the fix. A skill `SKILL.md` Layout table that maps `scripts/` counts as the inventory for files in that subdirectory.
|
|
36
|
+
|
|
37
|
+
Two free-prose slices stay with judgment and belong in the same change:
|
|
38
|
+
|
|
39
|
+
1. **Purpose / scope sentence.** When the new module adds a responsibility the package `## Purpose` (or the parent inventory's one-line summary of the subdirectory) omits, broaden that sentence to name it. A hook cannot derive a module's responsibility from its filename.
|
|
40
|
+
2. **Per-file description clause.** When a file gains a responsibility the inventory's em-dash description omits — a new public function, a new module-level constant — broaden the clause to name it. The gate checks only that the basename appears once and never reads the description. Constants modules (`*_constants.py`, or any `.py` directly inside `config/`) are the common shape: the clause that lands in the module docstring lands in the inventory description in the same change. The gate fires on Write of a new file and skips files directly inside `config/`, so an Edit adding a constant to an existing config module matches neither path.
|
|
41
|
+
|
|
42
|
+
This is the `category-o-docstring-vs-impl-drift` (O8) orphaned-doc-claim shape applied to a package inventory.
|
|
43
|
+
|
|
44
|
+
## 3. An env-var table row names a file that reads the variable
|
|
45
|
+
|
|
46
|
+
Every row in an env-var summary table pairs an UPPER_SNAKE variable with a code-file path that reads it — written as `` | `GOOGLE_APPLICATION_CREDENTIALS` | `auth/google_auth.py` | … | ``. When a code change removes the last read of a variable from a file, the same change drops or corrects the row naming that file.
|
|
47
|
+
|
|
48
|
+
`env_var_table_code_drift_blocker.py` (PreToolUse on Write|Edit|MultiEdit of `.md`) blocks a row whose named code file exists yet never references the variable, and names the fix. For an Edit, drift a file already held on an untouched row is excluded; a row whose code file resolves nowhere stays quiet, since the hook cannot prove the drift.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Documentation Prose Cuts
|
|
2
|
+
|
|
3
|
+
Prose a reader acts on states settled facts, decisions, and behavior directly. Four sentence shapes carry no fact the reader can act on. Cut each on sight, in `.md` files, in code comments, and in docstrings alike.
|
|
4
|
+
|
|
5
|
+
A detail earns its place by mattering now, or by being timeless enough to matter for future work. Everything else is noise.
|
|
6
|
+
|
|
7
|
+
## The four cut shapes
|
|
8
|
+
|
|
9
|
+
### 1. Exclusion claims — state the claim itself
|
|
10
|
+
|
|
11
|
+
Establishing a claim by naming what it is not, or by walking rejected candidates to reach the answer. Replace with the claim and the evidence behind it.
|
|
12
|
+
|
|
13
|
+
> This is not Option A from the original framing.
|
|
14
|
+
|
|
15
|
+
Cut it. Write what the approach is.
|
|
16
|
+
|
|
17
|
+
### 2. Justification sentences — state the fact, drop the payoff
|
|
18
|
+
|
|
19
|
+
A sentence whose only job is to say why a stated choice is good, or to restate a gain the reader already works out from the behavior around it or from a rule enforced elsewhere.
|
|
20
|
+
|
|
21
|
+
> The lenses point at this file and read it when they run; they do not carry its text in their spawn prompts, so the checklist stays out of the per-round token budget.
|
|
22
|
+
|
|
23
|
+
Keep the first clause. Cut the tail — the reader reaches it alone.
|
|
24
|
+
|
|
25
|
+
For each sentence, ask: **does it state a fact the reader can act on that they could not already work out from the behavior around it?** If no, cut it.
|
|
26
|
+
|
|
27
|
+
A rule's one-line reason stated in present behavior stays — `--jq` runs per page, so cross-page sorts give wrong results — because that reason names a fact the reader needs to pick the right call. A tradeoff or constraint the reader weighs before choosing a path stays too.
|
|
28
|
+
|
|
29
|
+
### 3. Conversation references — write for a reader who saw nothing
|
|
30
|
+
|
|
31
|
+
Every document stands alone. A reader with zero prior context understands every statement without the conversation that produced it.
|
|
32
|
+
|
|
33
|
+
| Shape | Example | Fix |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Options discussed in chat | "This is not Option A from the original framing" | State the decision on its own terms |
|
|
36
|
+
| "As discussed" / "as we decided" | "As discussed, we'll use embeddings" | "Sref matching uses sentence-transformer embeddings" |
|
|
37
|
+
| Pronouns pointing at chat | "This addresses the concerns raised earlier" | Name the concerns inline, or cut |
|
|
38
|
+
| Relative framing on unseen alternatives | "Instead of the three options considered" | State the chosen approach directly |
|
|
39
|
+
| Session sequencing | "After Round 3 we decided…" | State the decision as a fact |
|
|
40
|
+
|
|
41
|
+
Obsidian session logs are the exception — they are conversation-scoped on purpose.
|
|
42
|
+
|
|
43
|
+
### 4. Time references — describe current state only
|
|
44
|
+
|
|
45
|
+
Never reference removed implementations, old defaults, prior behaviors, or earlier contracts. A module or function docstring carries the same current-state-only contract as a `.md` file.
|
|
46
|
+
|
|
47
|
+
Comparisons to alternatives that still exist stay allowed ("use `--paginate --slurp | jq`, not `--jq` alone"), as do references to external defects that still exist (gh CLI #10459).
|
|
48
|
+
|
|
49
|
+
After writing, ask: read a year from now by someone who knew no earlier state, does every sentence still make sense? If a sentence only helps someone who knew an earlier state, cut it.
|
|
50
|
+
|
|
51
|
+
## Enforcement
|
|
52
|
+
|
|
53
|
+
- **Write-time.** `state_description_blocker` (PreToolUse on Write|Edit) blocks historical and comparative phrases in `.md` prose, code comments, and Python docstrings. A phrase wrapped in double quotes or backticks inside a docstring counts as a mention and is skipped. The denial names the matched phrases and shows a rewrite.
|
|
54
|
+
- **AI review.** The claude-dev-env repository's root `AGENTS.md`, the AI-review fan-out source, names the other three shapes as findings an agent applies to the `.md` lines a PR changes. No hook backs them: telling a justification sentence from a load-bearing one needs meaning a regex cannot read.
|
|
55
|
+
|
|
56
|
+
## Sibling rule
|
|
57
|
+
|
|
58
|
+
[`plain-language.md`](plain-language.md) governs word choice — heavy words swapped for everyday ones. This rule governs which sentences survive at all.
|
|
@@ -28,13 +28,21 @@ Read the body and the docstring side by side. Apply each check that matches the
|
|
|
28
28
|
- **Gate-outcome status flags** — an outcome routed to a blocker (`blocker = ...; break`) reads as blocked everywhere, never as a bypass.
|
|
29
29
|
- **Returns / Raises / Note claims** — each free-form claim matches the body.
|
|
30
30
|
|
|
31
|
-
Many deterministic shapes of this drift have Write/Edit gates in
|
|
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.
|
|
32
40
|
|
|
33
41
|
## Full standard
|
|
34
42
|
|
|
35
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:
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
`~/.claude/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md`
|
|
38
46
|
|
|
39
47
|
## Division of labor
|
|
40
48
|
|
|
@@ -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
|
|
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.
|