claude-dev-env 2.13.0 → 2.14.1
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/AGENTS.md +135 -0
- package/CLAUDE.md +1 -57
- package/_shared/AGENTS.md +15 -0
- package/_shared/CLAUDE.md +1 -15
- package/_shared/advisor/AGENTS.md +22 -0
- package/_shared/advisor/CLAUDE.md +1 -22
- package/_shared/pr-loop/AGENTS.md +27 -0
- package/_shared/pr-loop/CLAUDE.md +1 -27
- package/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
- package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
- package/_shared/process-tree/AGENTS.md +41 -0
- package/_shared/process-tree/CLAUDE.md +1 -41
- package/agents/AGENTS.md +26 -0
- package/agents/CLAUDE.md +1 -31
- package/agents/clean-coder.md +6 -6
- package/agents/test_agent_frontmatter.py +11 -11
- package/audit-rubrics/AGENTS.md +43 -0
- package/audit-rubrics/CLAUDE.md +1 -43
- package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
- package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
- package/audit-rubrics/prompts/AGENTS.md +37 -0
- package/audit-rubrics/prompts/CLAUDE.md +1 -37
- package/bin/AGENTS.md +112 -0
- package/bin/CLAUDE.md +1 -112
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +6 -7
- package/bin/install.mjs +24 -5
- package/bin/install.test.mjs +34 -0
- package/commands/AGENTS.md +13 -0
- package/commands/CLAUDE.md +1 -23
- package/docs/AGENTS.md +32 -0
- package/docs/CLAUDE.md +1 -32
- package/docs/CODE_RULES.md +1 -1
- package/docs/imagegen.md +22 -0
- package/docs/references/AGENTS.md +17 -0
- package/docs/references/CLAUDE.md +1 -17
- package/hooks/AGENTS.md +31 -0
- package/hooks/CLAUDE.md +1 -31
- package/hooks/_gh_pr_author_swap_utils.py +14 -0
- package/hooks/advisory/AGENTS.md +16 -0
- package/hooks/advisory/CLAUDE.md +1 -16
- package/hooks/blocking/AGENTS.md +123 -0
- package/hooks/blocking/CLAUDE.md +1 -123
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
- package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
- package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
- package/hooks/blocking/code_rules_probe_chains.py +6 -2
- package/hooks/blocking/config/AGENTS.md +10 -0
- package/hooks/blocking/config/CLAUDE.md +1 -10
- package/hooks/blocking/gh_pr_author_restore.py +7 -2
- package/hooks/blocking/intent_only_ending_blocker.py +11 -16
- package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
- package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
- package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
- package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
- package/hooks/blocking/test_claude_md_orphan_file_blocker.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
- package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
- package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
- package/hooks/diagnostic/AGENTS.md +75 -0
- package/hooks/diagnostic/CLAUDE.md +1 -43
- package/hooks/diagnostic/hook_log_extractor.py +2 -2
- package/hooks/diagnostic/hook_log_init.py +2 -2
- package/hooks/diagnostic/migrations/AGENTS.md +16 -0
- package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
- package/hooks/diagnostic/queries/AGENTS.md +19 -0
- package/hooks/diagnostic/queries/CLAUDE.md +1 -19
- package/hooks/diagnostic/test_hook_log_extractor.py +2 -2
- package/hooks/git-hooks/AGENTS.md +31 -0
- package/hooks/git-hooks/CLAUDE.md +1 -31
- package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
- package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
- package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -6
- package/hooks/git-hooks/pre_push.py +47 -34
- package/hooks/git-hooks/test_pre_push.py +111 -7
- package/hooks/hooks_constants/AGENTS.md +104 -0
- package/hooks/hooks_constants/CLAUDE.md +1 -104
- package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
- package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
- package/hooks/lifecycle/AGENTS.md +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -18
- package/hooks/observability/AGENTS.md +20 -0
- package/hooks/observability/CLAUDE.md +1 -20
- package/hooks/session/AGENTS.md +33 -0
- package/hooks/session/CLAUDE.md +1 -33
- package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
- package/hooks/session/task_list_loop_starter.py +3 -3
- package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
- package/hooks/session/test_task_list_loop_starter.py +10 -2
- package/hooks/session/test_working_style_prompt.py +9 -4
- package/hooks/validation/AGENTS.md +20 -0
- package/hooks/validation/CLAUDE.md +1 -20
- package/hooks/validators/AGENTS.md +51 -0
- package/hooks/validators/CLAUDE.md +1 -51
- package/hooks/validators/health_check.py +52 -19
- package/hooks/validators/python_style_checks.py +1 -1
- package/hooks/validators/test_health_check.py +112 -27
- package/hooks/workflow/AGENTS.md +16 -0
- package/hooks/workflow/CLAUDE.md +1 -16
- package/installable-surfaces.manifest.json +1 -0
- package/output-styles/AGENTS.md +15 -0
- package/output-styles/CLAUDE.md +1 -15
- package/package.json +2 -1
- package/rules/AGENTS.md +61 -0
- package/rules/CLAUDE.md +1 -61
- package/rules/code-standards.md +5 -9
- package/rules/doc-prose-cuts.md +1 -1
- package/scripts/AGENTS.md +62 -0
- package/scripts/CLAUDE.md +1 -62
- package/scripts/codex_compat_materializer.py +4 -0
- package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
- package/scripts/sync_to_cursor/AGENTS.md +23 -0
- package/scripts/sync_to_cursor/CLAUDE.md +1 -23
- package/scripts/test_active_capability_references.py +2 -2
- package/scripts/test_validate_instruction_pairs.py +90 -0
- package/scripts/test_verify_installable_package.py +5 -1
- package/scripts/tests/AGENTS.md +33 -0
- package/scripts/tests/CLAUDE.md +1 -33
- package/scripts/tests/test_codex_compat_materializer.py +36 -1
- package/scripts/validate_instruction_pairs.py +183 -0
- package/skills/AGENTS.md +72 -0
- package/skills/CLAUDE.md +1 -72
- package/skills/_shared/AGENTS.md +44 -0
- package/skills/_shared/CLAUDE.md +1 -44
- package/skills/_shared/advisor/AGENTS.md +9 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/AGENTS.md +50 -0
- package/skills/_shared/pr-loop/CLAUDE.md +1 -50
- package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
- package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
- package/skills/anthropic-plan/AGENTS.md +34 -0
- package/skills/anthropic-plan/CLAUDE.md +1 -34
- package/skills/anthropic-plan/SKILL.md +1 -1
- package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
- package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
- package/skills/anthropic-plan/templates/AGENTS.md +13 -0
- package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
- package/skills/anthropic-plan/test_skill_contract.py +8 -6
- package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
- package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
- package/skills/auditing-claude-config/AGENTS.md +21 -0
- package/skills/auditing-claude-config/CLAUDE.md +1 -21
- package/skills/autoconverge/AGENTS.md +36 -0
- package/skills/autoconverge/CLAUDE.md +1 -36
- package/skills/autoconverge/reference/AGENTS.md +16 -0
- package/skills/autoconverge/reference/CLAUDE.md +1 -16
- package/skills/autoconverge/workflow/AGENTS.md +26 -0
- package/skills/autoconverge/workflow/CLAUDE.md +1 -26
- package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
- package/skills/bugteam/AGENTS.md +30 -0
- package/skills/bugteam/CLAUDE.md +1 -30
- package/skills/bugteam/reference/AGENTS.md +20 -0
- package/skills/bugteam/reference/CLAUDE.md +1 -20
- package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
- package/skills/bugteam/scripts/AGENTS.md +30 -0
- package/skills/bugteam/scripts/CLAUDE.md +1 -30
- package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
- package/skills/closeout/reference/handoff-prompt-template.md +1 -1
- package/skills/codex-review/AGENTS.md +46 -0
- package/skills/codex-review/CLAUDE.md +1 -46
- package/skills/codex-review/reference/AGENTS.md +15 -0
- package/skills/codex-review/reference/CLAUDE.md +1 -15
- package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
- package/skills/codex-review/test_skill_scaffold.py +3 -3
- package/skills/copilot-review/AGENTS.md +18 -0
- package/skills/copilot-review/CLAUDE.md +1 -18
- package/skills/everything-search/AGENTS.md +17 -0
- package/skills/everything-search/CLAUDE.md +1 -17
- package/skills/fresh-branch/AGENTS.md +14 -0
- package/skills/fresh-branch/CLAUDE.md +1 -14
- package/skills/grok-spawn/AGENTS.md +28 -0
- package/skills/grok-spawn/CLAUDE.md +1 -28
- package/skills/pr-converge/AGENTS.md +32 -0
- package/skills/pr-converge/CLAUDE.md +1 -32
- package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
- package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
- package/skills/pr-converge/reference/AGENTS.md +28 -0
- package/skills/pr-converge/reference/CLAUDE.md +1 -28
- package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
- package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
- package/skills/pr-converge/scripts/AGENTS.md +46 -0
- package/skills/pr-converge/scripts/CLAUDE.md +1 -46
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
- package/skills/pr-converge/workflows/AGENTS.md +16 -0
- package/skills/pr-converge/workflows/CLAUDE.md +1 -16
- package/skills/prototype/SKILL.md +1 -2
- package/skills/prototype/reference/honest-limitations.md +1 -1
- package/skills/prototype/reference/promotion-tasks.md +1 -1
- package/skills/prototype/workflows/promotion.md +1 -1
- package/skills/rebase/AGENTS.md +32 -0
- package/skills/rebase/CLAUDE.md +1 -32
- package/skills/recall/AGENTS.md +30 -0
- package/skills/recall/CLAUDE.md +1 -30
- package/skills/remember/AGENTS.md +31 -0
- package/skills/remember/CLAUDE.md +1 -31
- package/skills/reviews/SKILL.md +1 -1
- package/skills/session-log/AGENTS.md +32 -0
- package/skills/session-log/CLAUDE.md +1 -32
- package/skills/session-tidy/AGENTS.md +36 -0
- package/skills/session-tidy/CLAUDE.md +1 -36
- package/skills/skill-builder/AGENTS.md +49 -0
- package/skills/skill-builder/CLAUDE.md +1 -49
- package/skills/skill-builder/references/AGENTS.md +25 -0
- package/skills/skill-builder/references/CLAUDE.md +1 -25
- package/skills/skill-builder/references/deterministic-elements.md +1 -1
- package/skills/skill-builder/templates/AGENTS.md +14 -0
- package/skills/skill-builder/templates/CLAUDE.md +1 -14
- package/skills/skill-builder/workflows/AGENTS.md +19 -0
- package/skills/skill-builder/workflows/CLAUDE.md +1 -19
- package/skills/task-build/AGENTS.md +29 -0
- package/skills/task-build/CLAUDE.md +1 -29
- package/skills/update/AGENTS.md +38 -0
- package/skills/update/CLAUDE.md +1 -38
- package/system-prompts/AGENTS.md +17 -0
- package/system-prompts/CLAUDE.md +1 -17
- package/system-prompts/software-engineer.xml +3 -3
- package/agents/caveman.md +0 -73
- package/agents/clasp-deployment-orchestrator.md +0 -608
- package/agents/code-advisor.md +0 -23
- package/agents/deep-research.md +0 -152
- package/agents/docs-agent.md +0 -85
- package/commands/commit.md +0 -28
- package/commands/docupdate.md +0 -322
- package/commands/hook-log-extract.md +0 -70
- package/commands/hook-log-init.md +0 -76
- package/commands/implement.md +0 -102
- package/commands/plan.md +0 -14
- package/commands/pr-comments.md +0 -47
- package/commands/review-plan.md +0 -5
- package/commands/right-size.md +0 -15
- package/commands/sum.md +0 -30
- package/skills/imagegen/SKILL.md +0 -21
- package/skills/imagegen/scripts/config/__init__.py +0 -1
- package/skills/imagegen/scripts/config/constants.py +0 -28
- package/skills/imagegen/scripts/imagegen.py +0 -45
- package/skills/imagegen/scripts/imagegen_core.py +0 -528
- package/skills/imagegen/scripts/test_imagegen.py +0 -204
package/hooks/AGENTS.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# hooks
|
|
2
|
+
|
|
3
|
+
Python hook scripts wired into Claude Code's lifecycle via `settings.json`. Each hook answers one or more lifecycle events (`PreToolUse`, `PostToolUse`, `Stop`, `SubagentStop`, `SessionStart`, `SessionEnd`) and either blocks a tool call, annotates it, or performs a side-effect.
|
|
4
|
+
|
|
5
|
+
## Subdirectories
|
|
6
|
+
|
|
7
|
+
| Directory | Role |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `advisory/` | Hooks that warn but do not block (`permissionDecision: "ask"`) |
|
|
10
|
+
| `blocking/` | Hooks that deny tool calls when a rule is violated |
|
|
11
|
+
| `blocking/config/` | Shared constants for blocking hooks |
|
|
12
|
+
| `diagnostic/` | Hooks that record and extract hook-firing records into Neon |
|
|
13
|
+
| `diagnostic/migrations/` | SQL migrations for the `hook_events` Neon schema |
|
|
14
|
+
| `diagnostic/queries/` | Parameterized SQL queries for inspecting blocked commands |
|
|
15
|
+
| `git-hooks/` | Native git hooks (`pre-commit`, `pre-push`, `post-commit`) installed via the git-hooks path |
|
|
16
|
+
| `git-hooks/git_hooks_constants/` | Shared constants for the git-hook scripts |
|
|
17
|
+
| `hooks_constants/` | Shared constant modules imported by multiple hooks across this tree (includes `pii_prevention_constants.py` for personal-data and secret scan patterns) |
|
|
18
|
+
| `lifecycle/` | Hooks that run at session or config-change boundaries |
|
|
19
|
+
| `observability/` | PostToolUse hooks that record agent behavior for diagnostics |
|
|
20
|
+
| `session/` | SessionStart and SessionEnd hooks for per-session cleanup |
|
|
21
|
+
| `validation/` | PostToolUse hooks that validate code quality after a write (mypy, auto-format) |
|
|
22
|
+
| `validators/` | Library modules used by the validation hooks — checks split by concern |
|
|
23
|
+
| `workflow/` | PostToolUse hooks that trigger doc publishing and companion-file generation |
|
|
24
|
+
|
|
25
|
+
## Conventions
|
|
26
|
+
|
|
27
|
+
- **Event mapping:** Every hook reads JSON from stdin and exits 0 (allow) or prints a `hookSpecificOutput` block (block/ask). Blocking hooks set `permissionDecision: "block"`.
|
|
28
|
+
- **Constants companion:** Each hook with more than a handful of tunable strings keeps them in a `hooks_constants/<hook_name>_constants.py` sibling. Import from there; do not repeat literals.
|
|
29
|
+
- **Tests:** Each hook has one or more `test_<hookname>*.py` files beside it. Run with `python -m pytest <test_file>`.
|
|
30
|
+
- **Registration:** Hooks are declared in `settings.json` under the right lifecycle event. The installer (`packages/claude-dev-env/bin/install.mjs`) merges the hook entries during `npx claude-dev-env`.
|
|
31
|
+
- **Top-level utilities:** `_gh_pr_author_swap_utils.py` and `rewrite_plugin_paths.py` are shared helpers imported by multiple blocking hooks. `hooks.json` records the canonical hook-to-event mapping for auditing.
|
package/hooks/CLAUDE.md
CHANGED
|
@@ -1,31 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Python hook scripts wired into Claude Code's lifecycle via `settings.json`. Each hook answers one or more lifecycle events (`PreToolUse`, `PostToolUse`, `Stop`, `SubagentStop`, `SessionStart`, `SessionEnd`) and either blocks a tool call, annotates it, or performs a side-effect.
|
|
4
|
-
|
|
5
|
-
## Subdirectories
|
|
6
|
-
|
|
7
|
-
| Directory | Role |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `advisory/` | Hooks that warn but do not block (`permissionDecision: "ask"`) |
|
|
10
|
-
| `blocking/` | Hooks that deny tool calls when a rule is violated |
|
|
11
|
-
| `blocking/config/` | Shared constants for blocking hooks |
|
|
12
|
-
| `diagnostic/` | Hooks that record and extract hook-firing records into Neon |
|
|
13
|
-
| `diagnostic/migrations/` | SQL migrations for the `hook_events` Neon schema |
|
|
14
|
-
| `diagnostic/queries/` | Parameterized SQL queries for inspecting blocked commands |
|
|
15
|
-
| `git-hooks/` | Native git hooks (`pre-commit`, `pre-push`, `post-commit`) installed via the git-hooks path |
|
|
16
|
-
| `git-hooks/git_hooks_constants/` | Shared constants for the git-hook scripts |
|
|
17
|
-
| `hooks_constants/` | Shared constant modules imported by multiple hooks across this tree (includes `pii_prevention_constants.py` for personal-data and secret scan patterns) |
|
|
18
|
-
| `lifecycle/` | Hooks that run at session or config-change boundaries |
|
|
19
|
-
| `observability/` | PostToolUse hooks that record agent behavior for diagnostics |
|
|
20
|
-
| `session/` | SessionStart and SessionEnd hooks for per-session cleanup |
|
|
21
|
-
| `validation/` | PostToolUse hooks that validate code quality after a write (mypy, auto-format) |
|
|
22
|
-
| `validators/` | Library modules used by the validation hooks — checks split by concern |
|
|
23
|
-
| `workflow/` | PostToolUse hooks that trigger doc publishing and companion-file generation |
|
|
24
|
-
|
|
25
|
-
## Conventions
|
|
26
|
-
|
|
27
|
-
- **Event mapping:** Every hook reads JSON from stdin and exits 0 (allow) or prints a `hookSpecificOutput` block (block/ask). Blocking hooks set `permissionDecision: "block"`.
|
|
28
|
-
- **Constants companion:** Each hook with more than a handful of tunable strings keeps them in a `hooks_constants/<hook_name>_constants.py` sibling. Import from there; do not repeat literals.
|
|
29
|
-
- **Tests:** Each hook has one or more `test_<hookname>*.py` files beside it. Run with `python -m pytest <test_file>`.
|
|
30
|
-
- **Registration:** Hooks are declared in `settings.json` under the right lifecycle event. The installer (`packages/claude-dev-env/bin/install.mjs`) merges the hook entries during `npx claude-dev-env`.
|
|
31
|
-
- **Top-level utilities:** `_gh_pr_author_swap_utils.py` and `rewrite_plugin_paths.py` are shared helpers imported by multiple blocking hooks. `hooks.json` records the canonical hook-to-event mapping for auditing.
|
|
1
|
+
@AGENTS.md
|
|
@@ -155,6 +155,20 @@ def _switch_gh_account(to_account: str) -> bool:
|
|
|
155
155
|
return completed_process.returncode == 0
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
def _build_restore_failure_message(
|
|
159
|
+
hook_label: str,
|
|
160
|
+
original_account: str,
|
|
161
|
+
state_file: Path,
|
|
162
|
+
state_file_context: str,
|
|
163
|
+
) -> str:
|
|
164
|
+
"""Build the shared diagnostic for a failed account restoration."""
|
|
165
|
+
return (
|
|
166
|
+
f"[{hook_label}] Restore the gh account to {original_account!r}; "
|
|
167
|
+
f"gh account switch requires attention for {state_file_context} {state_file}. "
|
|
168
|
+
"The file remains for the next session."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
158
172
|
def _read_original_account(state_file: Path) -> str | None:
|
|
159
173
|
"""Read the original-account login from a swap-state file.
|
|
160
174
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# hooks/advisory
|
|
2
|
+
|
|
3
|
+
Hooks that produce a warning prompt (`permissionDecision: "ask"`) rather than an outright block. The user sees the warning and can continue or cancel.
|
|
4
|
+
|
|
5
|
+
## Key files
|
|
6
|
+
|
|
7
|
+
| File | Event | What it guards |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `migration_safety_advisor.py` | PreToolUse (Write/Edit) | Django migration files containing `RemoveField`, `RenameField`, `DeleteModel`, or `RenameModel` — warns that these operations must be backwards-compatible during deployment |
|
|
10
|
+
| `refactor_guard.py` | PreToolUse (Edit) | Edits that rename or restructure existing code not present in the current git diff — warns that the change may be out of scope |
|
|
11
|
+
|
|
12
|
+
## Conventions
|
|
13
|
+
|
|
14
|
+
- Both hooks exit 0 (silent) when their trigger condition is not met.
|
|
15
|
+
- `refactor_guard.py` respects a bypass token at `~/.claude/.refactor-bypass-token`; when that file exists the hook stays silent.
|
|
16
|
+
- Tests live beside each hook following the `test_<name>.py` pattern used in `blocking/`. Run with `python -m pytest <test_file>`.
|
package/hooks/advisory/CLAUDE.md
CHANGED
|
@@ -1,16 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Hooks that produce a warning prompt (`permissionDecision: "ask"`) rather than an outright block. The user sees the warning and can continue or cancel.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Event | What it guards |
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| `migration_safety_advisor.py` | PreToolUse (Write/Edit) | Django migration files containing `RemoveField`, `RenameField`, `DeleteModel`, or `RenameModel` — warns that these operations must be backwards-compatible during deployment |
|
|
10
|
-
| `refactor_guard.py` | PreToolUse (Edit) | Edits that rename or restructure existing code not present in the current git diff — warns that the change may be out of scope |
|
|
11
|
-
|
|
12
|
-
## Conventions
|
|
13
|
-
|
|
14
|
-
- Both hooks exit 0 (silent) when their trigger condition is not met.
|
|
15
|
-
- `refactor_guard.py` respects a bypass token at `~/.claude/.refactor-bypass-token`; when that file exists the hook stays silent.
|
|
16
|
-
- Tests live beside each hook following the `test_<name>.py` pattern used in `blocking/`. Run with `python -m pytest <test_file>`.
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# hooks/blocking
|
|
2
|
+
|
|
3
|
+
PreToolUse hooks that deny (block) tool calls when a rule is violated. The main enforcer is `code_rules_enforcer.py`, which routes each Write/Edit through a suite of focused check modules. Every other file in this directory is either a standalone blocker, a check module, or a test.
|
|
4
|
+
|
|
5
|
+
## Subdirectory
|
|
6
|
+
|
|
7
|
+
| Directory | Role |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `tdd_enforcer_parts/` | Concern modules the `tdd_enforcer.py` entry hook wires together: path classification, content analysis, candidate-path resolution, freshness, git-tracking restore detection, decisions, and constants |
|
|
10
|
+
| `claude_md_orphan_file_blocker_parts/` | Concern modules the `claude_md_orphan_file_blocker.py` entry hook wires together: reference extraction, subtree scan, scan plan, decision, and constants |
|
|
11
|
+
| `package_inventory_stale_blocker_parts/` | Concern modules the `package_inventory_stale_blocker.py` entry hook wires together: inventory detection, decision, and constants |
|
|
12
|
+
| `inventory_intent_records/` | The shared per-session pending-intent store both inventory blockers read to break the file/row add-order deadlock |
|
|
13
|
+
| `pii_prevention_blocker_parts/` | Concern modules the `pii_prevention_blocker.py` entry hook wires together: per-repository scan exemption, the per-repository allowlist of exact values a commit may carry, and resolving the repository a commit command targets (with `config/` for the resolution deny-message constants) |
|
|
14
|
+
| `tests/` | pytest suite for `pii_prevention_blocker.py` repository resolution and the `pii_prevention_blocker_parts` modules |
|
|
15
|
+
|
|
16
|
+
## Core enforcer
|
|
17
|
+
|
|
18
|
+
| File | What it does |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `code_rules_enforcer.py` | Entry point — reads PreToolUse stdin, reconstructs post-edit content, dispatches all check modules, and returns a block with a per-issue list when any check fails |
|
|
21
|
+
|
|
22
|
+
The check modules it calls are the `code_rules_<concern>.py` files below.
|
|
23
|
+
|
|
24
|
+
## Check modules (imported by `code_rules_enforcer.py`)
|
|
25
|
+
|
|
26
|
+
| Module | Concern |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `code_rules_annotations_length.py` | Parameter/return annotations, function length, pytest fixture annotation requirements |
|
|
29
|
+
| `code_rules_banned_identifiers.py` | Banned short names (`ctx`, `cfg`, `msg`, etc.), banned prefixes (`handle_`, `process_`, etc.) |
|
|
30
|
+
| `code_rules_boolean_mustcheck.py` | Boolean naming (`is_`/`has_`/… prefixes) and must-check return values |
|
|
31
|
+
| `code_rules_command_dispatch.py` | A `hooks/blocking/` command classifier matching a multi-word command regex without a start anchor or first-word tokenization |
|
|
32
|
+
| `code_rules_comments.py` | No new inline comments; advisory on deletion of existing ones |
|
|
33
|
+
| `code_rules_constants_config.py` | Constants must live in `config/`; file-global constant use-count |
|
|
34
|
+
| `code_rules_dead_argparse_argument.py` | Argparse arguments with no references in the same file |
|
|
35
|
+
| `code_rules_dead_config_field.py` | `*Config` / `*Selectors` dataclass fields with no live references |
|
|
36
|
+
| `code_rules_dead_dataclass_field.py` | Dataclass fields with no consuming references |
|
|
37
|
+
| `code_rules_dead_module_constant.py` | `UPPER_SNAKE` constants in `*_constants.py` modules with no importers |
|
|
38
|
+
| `code_rules_dead_split_branch.py` | A conditional whose falsy branch is unreachable because the tested value comes from a separator `str.split()`, which never returns an empty list |
|
|
39
|
+
| `code_rules_docstrings.py` | Google-style docstrings; `Args:` section matches signature; fallback-branch coverage |
|
|
40
|
+
| `code_rules_duplicate_body.py` | A function body copied from a sibling module, or a helper body inlined as a block inside a larger function in the same file |
|
|
41
|
+
| `code_rules_imports_logging.py` | Imports at top of file; logging format-arg style; printf tokens in `str.format`-logger messages |
|
|
42
|
+
| `code_rules_js_conventions.py` | Boolean-prefix naming and banned identifiers for JavaScript/TypeScript declarations and `@param {boolean}` JSDoc, scoped to changed lines |
|
|
43
|
+
| `code_rules_magic_values.py` | No magic numbers or strings in production code bodies |
|
|
44
|
+
| `code_rules_mock_completeness.py` | Mock calls that skip required arguments |
|
|
45
|
+
| `code_rules_naming_collection.py` | Collection names must use `all_*` prefix |
|
|
46
|
+
| `code_rules_optional_params.py` | No optional parameters where a required one would do |
|
|
47
|
+
| `code_rules_orphan_css_class.py` | CSS class attributes in Python markup with no matching `.<class>` selector |
|
|
48
|
+
| `code_rules_paired_test.py` | A public function omitted by a module's established paired test suite must get a behavioral test — checked on both the production-module write and the stem-matched test-file write |
|
|
49
|
+
| `code_rules_path_utils.py` | Path utility helpers shared across check modules |
|
|
50
|
+
| `code_rules_paths_syspath.py` | `sys.path.insert` must be guarded |
|
|
51
|
+
| `code_rules_probe_chains.py` | Probe-chain detection logic |
|
|
52
|
+
| `code_rules_probe_detection.py` | Probe pattern detection helpers |
|
|
53
|
+
| `code_rules_probe_recording.py` | Probe recording utilities |
|
|
54
|
+
| `code_rules_scope_binding.py` | Scope/binding analysis utilities |
|
|
55
|
+
| `code_rules_shared.py` | Shared dataclasses and helpers used by multiple check modules |
|
|
56
|
+
| `code_rules_string_magic.py` | Magic string detection with masking and f-string support; whitespace-only indentation literals in function bodies |
|
|
57
|
+
| `code_rules_test_assertions.py` | Test assertion style rules |
|
|
58
|
+
| `code_rules_test_layout.py` | Dead scaffolding in a test module: a private module constant read by no other line, and an unused parameter on a private test helper |
|
|
59
|
+
| `code_rules_test_branching_except.py` | No bare or broad `except` in test branches |
|
|
60
|
+
| `code_rules_test_isolation.py` | Tests must not rely on home-dir or temp-dir side effects |
|
|
61
|
+
| `code_rules_type_escape.py` | No `Any` imports, `cast()`, or `# type: ignore` outside boundary files |
|
|
62
|
+
| `code_rules_typeddict_stub.py` | TypedDict pairs (`_encode_*`/`_decode_*`) must both exist in the same module |
|
|
63
|
+
| `code_rules_unused_imports.py` | Unused module-level imports |
|
|
64
|
+
|
|
65
|
+
## Other standalone blockers
|
|
66
|
+
|
|
67
|
+
| File | Event | What it blocks |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `orchestrator_refresh_reschedule_gate.py` | PreToolUse (ScheduleWakeup/CronCreate) | `/orchestrator-refresh` re-arm when run status is not `active` |
|
|
70
|
+
| `block_main_commit.py` | PreToolUse (Bash) | `git commit`/`git push` directly to `main` |
|
|
71
|
+
| `bot_mention_comment_blocker.py` | PreToolUse (Write/Edit) | PR review comments that @-mention a bot |
|
|
72
|
+
| `claude_md_orphan_file_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | Per-directory `CLAUDE.md` table cells naming a bare filename absent from the directory subtree |
|
|
73
|
+
| `conventional_pr_title_gate.py` | PreToolUse (Bash) | `gh pr create`/`gh pr edit` with a `--title` that is not a Conventional Commit, in a repo whose CI runs a semantic-pull-request title check |
|
|
74
|
+
| `destructive_command_blocker.py` | PreToolUse (Bash/PowerShell) | Shell commands with destructive literals (`rm -rf`, `git reset --hard`, etc.) |
|
|
75
|
+
| `docstring_rule_gate_count_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | A stale spelled-out gate-validator count in `docstring-prose-matches-implementation.md` — the "N more gate validators" / "M gated slices" count drifting from the `check_docstring_*` validators the prose names |
|
|
76
|
+
| `duplicate_rmtree_helper_blocker.py` | PreToolUse (Write/Edit) | A local re-definition of the Windows-safe rmtree helper trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`) in place of importing a shared helper |
|
|
77
|
+
| `eli11_reply_enforcer.py` | Stop | Final replies breaking the `eli11-replies` shape — more than 6 bullet lines, more than 2 list lines over 20 words each, or multi-line instructions with no numbered step among the lead lines. Code fences, inline code, blockquotes, table rows, and link targets come off before the reply is judged. |
|
|
78
|
+
| `env_var_table_code_drift_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | A markdown env-var summary table row attributing an environment variable to a code file whose source never references that variable name |
|
|
79
|
+
| `es_exe_path_rewriter.py` | PreToolUse | Rewrites paths referencing `.exe` under the Everything search path |
|
|
80
|
+
| `fable_spawn_gate.py` | PreToolUse (Agent/Task) | An `Agent` or `Task` spawn whose prompt carries no `FABLE-SPAWN-AUTHORIZED` token and whose model field reads `fable` in any letter case — the bare alias, or a delimiter segment of a full model id, so `claude-fable-5` is denied too |
|
|
81
|
+
| `gh_body_arg_blocker.py` | PreToolUse (Bash) | `gh` commands passing `--body`/`-b` directly (requires `--body-file` instead) |
|
|
82
|
+
| `gh_pr_author_enforcer.py` | PreToolUse | Enforces PR author identity rules |
|
|
83
|
+
| `gh_pr_author_restore.py` | PostToolUse | Restores PR author after a tool call |
|
|
84
|
+
| `hedging_language_blocker.py` | Stop | Responses with hedging words (`likely`, `probably`, `appears to`); armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
85
|
+
| `hook_prose_detector_consistency.py` | PreToolUse (Write/Edit) | Hook docstrings/messages that claim a trigger the detector cannot fire on; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
86
|
+
| `intent_only_ending_blocker.py` | Stop | Responses that end on a plan or intent without doing the work; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
87
|
+
| `open_questions_in_plans_blocker.py` | PreToolUse (Write/Edit) | Plan documents with unresolved open questions |
|
|
88
|
+
| `nas_ssh_binary_enforcer.py` | PreToolUse (Bash) | A bare `ssh`/`scp`/`sftp` command word targeting the NAS (Git Bash's MSYS ssh stalls on an interactive password prompt), or the full `System32/OpenSSH` binary to that host without `-o BatchMode=yes` |
|
|
89
|
+
| `package_inventory_stale_blocker.py` | PreToolUse (Write) | A new production code file created in a directory whose `README.md`/`CLAUDE.md` inventory (or a parent skill's `SKILL.md` Layout table mapping the `scripts/` subdirectory) names two or more sibling files but no entry for the new file |
|
|
90
|
+
| `pii_commit_command.py` | library | Token-aware git-commit detection reused by `pii_prevention_blocker.py` |
|
|
91
|
+
| `pii_payload_scan.py` | library | Write/Edit and durable post-body PII evaluation reused by `pii_prevention_blocker.py` |
|
|
92
|
+
| `pii_prevention_blocker.py` | PreToolUse (Write/Edit/MultiEdit/Bash/PowerShell/MCP GitHub) | Entry hook — content that carries high-confidence personal data or secrets (real emails, home-dir paths, private IPs, credential material) on write, durable GitHub posts, or staged commit paths; resolves the staged-commit repository from the command it gates (via `pii_prevention_blocker_parts`), not the session working directory |
|
|
93
|
+
| `pii_scanner.py` | library | Pure text scanners shared by `pii_prevention_blocker.py` |
|
|
94
|
+
| `piped_pytest_blocker.py` | PreToolUse (Bash) | A pytest run whose output feeds a pipe, where the pipeline reports the exit code of the command on the right |
|
|
95
|
+
| `plain_language_blocker.py` | PreToolUse (Write/Edit/AskUserQuestion) | Heavy or jargon words in user-facing prose when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off); AskUserQuestion lean-block structure stays always on |
|
|
96
|
+
| `precommit_code_rules_gate.py` | PreToolUse (Bash) | Staged changes that fail the CODE_RULES gate at commit time |
|
|
97
|
+
| `pytest_testpaths_orphan_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | New `test_*.py` files created under a directory absent from a package's explicit pytest `testpaths` allowlist |
|
|
98
|
+
| `question_to_user_enforcer.py` | Stop | User-directed questions not routed through `AskUserQuestion` |
|
|
99
|
+
| `send_user_file_open_locally_blocker.py` | PreToolUse (SendUserFile) | A desk-side file attach (`SendUserFile` with `status` not `proactive`); points to opening the file with its native Windows app |
|
|
100
|
+
| `sensitive_file_protector.py` | PreToolUse (Write/Edit) | Writes to sensitive credential or config files |
|
|
101
|
+
| `session_edit_stage_gate.py` | PreToolUse (Bash) | A `git commit` that would drop files edited this session because they are tracked but left unstaged |
|
|
102
|
+
| `session_handoff_blocker.py` | Stop | Responses suggesting a new session mid-task |
|
|
103
|
+
| `shell_substitution_blocker.py` | PreToolUse (Bash) | A command carrying `$(...)`, a live backtick, or `<(...)`/`>(...)` process substitution, which the allowlist matcher cannot descend into |
|
|
104
|
+
| `stale_comment_reference_blocker.py` | PreToolUse (Edit) | An Edit that rewrites a Python code line while keeping the standalone comment directly above it, when that comment names an identifier the rewrite removes from the line |
|
|
105
|
+
| `state_description_blocker.py` | PreToolUse (Write/Edit) | Historical/comparative language in documentation; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
106
|
+
| `subprocess_budget_completeness.py` | PreToolUse | Subprocess calls missing required budget arguments |
|
|
107
|
+
| `tdd_enforcer.py` | PreToolUse (Write/Edit) | Production code written without a matching failing test |
|
|
108
|
+
| `unscoped_search_blocker.py` | PreToolUse (Bash/PowerShell) | A `find` or recursive listing that walks from the filesystem root, a drive root, bare home, or a network share root |
|
|
109
|
+
| `volatile_path_in_post_blocker.py` | PreToolUse (Bash/MCP GitHub) | `gh` post commands and GitHub MCP post tools whose body references a volatile path (job scratch dir, worktree, or system temp) that outlives the durable post |
|
|
110
|
+
| `windows_rmtree_blocker.py` | PreToolUse (Write/Edit) | `shutil.rmtree` with `ignore_errors=True` on Windows |
|
|
111
|
+
| `workflow_substitution_slot_blocker.py` | PreToolUse (Write/Edit) | Workflow templates with bare per-iteration tokens missing angle-bracket slots |
|
|
112
|
+
| `write_existing_file_blocker.py` | PreToolUse (Write) | Write to a path where a file already exists |
|
|
113
|
+
|
|
114
|
+
## Supporting modules
|
|
115
|
+
|
|
116
|
+
| File | Role |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `_gh_body_arg_utils.py` | Parsing helpers for `gh_body_arg_blocker.py` |
|
|
119
|
+
|
|
120
|
+
## Conventions
|
|
121
|
+
|
|
122
|
+
- Tests live beside each hook as `test_<hookname>.py` or `test_<hookname>_<suffix>.py`. Run with `python -m pytest <test_file>`.
|
|
123
|
+
- Tunable constants live in `hooks_constants/<hook_name>_constants.py`.
|
package/hooks/blocking/CLAUDE.md
CHANGED
|
@@ -1,123 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
PreToolUse hooks that deny (block) tool calls when a rule is violated. The main enforcer is `code_rules_enforcer.py`, which routes each Write/Edit through a suite of focused check modules. Every other file in this directory is either a standalone blocker, a check module, or a test.
|
|
4
|
-
|
|
5
|
-
## Subdirectory
|
|
6
|
-
|
|
7
|
-
| Directory | Role |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `tdd_enforcer_parts/` | Concern modules the `tdd_enforcer.py` entry hook wires together: path classification, content analysis, candidate-path resolution, freshness, git-tracking restore detection, decisions, and constants |
|
|
10
|
-
| `claude_md_orphan_file_blocker_parts/` | Concern modules the `claude_md_orphan_file_blocker.py` entry hook wires together: reference extraction, subtree scan, scan plan, decision, and constants |
|
|
11
|
-
| `package_inventory_stale_blocker_parts/` | Concern modules the `package_inventory_stale_blocker.py` entry hook wires together: inventory detection, decision, and constants |
|
|
12
|
-
| `inventory_intent_records/` | The shared per-session pending-intent store both inventory blockers read to break the file/row add-order deadlock |
|
|
13
|
-
| `pii_prevention_blocker_parts/` | Concern modules the `pii_prevention_blocker.py` entry hook wires together: per-repository scan exemption, the per-repository allowlist of exact values a commit may carry, and resolving the repository a commit command targets (with `config/` for the resolution deny-message constants) |
|
|
14
|
-
| `tests/` | pytest suite for `pii_prevention_blocker.py` repository resolution and the `pii_prevention_blocker_parts` modules |
|
|
15
|
-
|
|
16
|
-
## Core enforcer
|
|
17
|
-
|
|
18
|
-
| File | What it does |
|
|
19
|
-
|---|---|
|
|
20
|
-
| `code_rules_enforcer.py` | Entry point — reads PreToolUse stdin, reconstructs post-edit content, dispatches all check modules, and returns a block with a per-issue list when any check fails |
|
|
21
|
-
|
|
22
|
-
The check modules it calls are the `code_rules_<concern>.py` files below.
|
|
23
|
-
|
|
24
|
-
## Check modules (imported by `code_rules_enforcer.py`)
|
|
25
|
-
|
|
26
|
-
| Module | Concern |
|
|
27
|
-
|---|---|
|
|
28
|
-
| `code_rules_annotations_length.py` | Parameter/return annotations, function length, pytest fixture annotation requirements |
|
|
29
|
-
| `code_rules_banned_identifiers.py` | Banned short names (`ctx`, `cfg`, `msg`, etc.), banned prefixes (`handle_`, `process_`, etc.) |
|
|
30
|
-
| `code_rules_boolean_mustcheck.py` | Boolean naming (`is_`/`has_`/… prefixes) and must-check return values |
|
|
31
|
-
| `code_rules_command_dispatch.py` | A `hooks/blocking/` command classifier matching a multi-word command regex without a start anchor or first-word tokenization |
|
|
32
|
-
| `code_rules_comments.py` | No new inline comments; advisory on deletion of existing ones |
|
|
33
|
-
| `code_rules_constants_config.py` | Constants must live in `config/`; file-global constant use-count |
|
|
34
|
-
| `code_rules_dead_argparse_argument.py` | Argparse arguments with no references in the same file |
|
|
35
|
-
| `code_rules_dead_config_field.py` | `*Config` / `*Selectors` dataclass fields with no live references |
|
|
36
|
-
| `code_rules_dead_dataclass_field.py` | Dataclass fields with no consuming references |
|
|
37
|
-
| `code_rules_dead_module_constant.py` | `UPPER_SNAKE` constants in `*_constants.py` modules with no importers |
|
|
38
|
-
| `code_rules_dead_split_branch.py` | A conditional whose falsy branch is unreachable because the tested value comes from a separator `str.split()`, which never returns an empty list |
|
|
39
|
-
| `code_rules_docstrings.py` | Google-style docstrings; `Args:` section matches signature; fallback-branch coverage |
|
|
40
|
-
| `code_rules_duplicate_body.py` | A function body copied from a sibling module, or a helper body inlined as a block inside a larger function in the same file |
|
|
41
|
-
| `code_rules_imports_logging.py` | Imports at top of file; logging format-arg style; printf tokens in `str.format`-logger messages |
|
|
42
|
-
| `code_rules_js_conventions.py` | Boolean-prefix naming and banned identifiers for JavaScript/TypeScript declarations and `@param {boolean}` JSDoc, scoped to changed lines |
|
|
43
|
-
| `code_rules_magic_values.py` | No magic numbers or strings in production code bodies |
|
|
44
|
-
| `code_rules_mock_completeness.py` | Mock calls that skip required arguments |
|
|
45
|
-
| `code_rules_naming_collection.py` | Collection names must use `all_*` prefix |
|
|
46
|
-
| `code_rules_optional_params.py` | No optional parameters where a required one would do |
|
|
47
|
-
| `code_rules_orphan_css_class.py` | CSS class attributes in Python markup with no matching `.<class>` selector |
|
|
48
|
-
| `code_rules_paired_test.py` | A public function omitted by a module's established paired test suite must get a behavioral test — checked on both the production-module write and the stem-matched test-file write |
|
|
49
|
-
| `code_rules_path_utils.py` | Path utility helpers shared across check modules |
|
|
50
|
-
| `code_rules_paths_syspath.py` | `sys.path.insert` must be guarded |
|
|
51
|
-
| `code_rules_probe_chains.py` | Probe-chain detection logic |
|
|
52
|
-
| `code_rules_probe_detection.py` | Probe pattern detection helpers |
|
|
53
|
-
| `code_rules_probe_recording.py` | Probe recording utilities |
|
|
54
|
-
| `code_rules_scope_binding.py` | Scope/binding analysis utilities |
|
|
55
|
-
| `code_rules_shared.py` | Shared dataclasses and helpers used by multiple check modules |
|
|
56
|
-
| `code_rules_string_magic.py` | Magic string detection with masking and f-string support; whitespace-only indentation literals in function bodies |
|
|
57
|
-
| `code_rules_test_assertions.py` | Test assertion style rules |
|
|
58
|
-
| `code_rules_test_layout.py` | Dead scaffolding in a test module: a private module constant read by no other line, and an unused parameter on a private test helper |
|
|
59
|
-
| `code_rules_test_branching_except.py` | No bare or broad `except` in test branches |
|
|
60
|
-
| `code_rules_test_isolation.py` | Tests must not rely on home-dir or temp-dir side effects |
|
|
61
|
-
| `code_rules_type_escape.py` | No `Any` imports, `cast()`, or `# type: ignore` outside boundary files |
|
|
62
|
-
| `code_rules_typeddict_stub.py` | TypedDict pairs (`_encode_*`/`_decode_*`) must both exist in the same module |
|
|
63
|
-
| `code_rules_unused_imports.py` | Unused module-level imports |
|
|
64
|
-
|
|
65
|
-
## Other standalone blockers
|
|
66
|
-
|
|
67
|
-
| File | Event | What it blocks |
|
|
68
|
-
|---|---|---|
|
|
69
|
-
| `orchestrator_refresh_reschedule_gate.py` | PreToolUse (ScheduleWakeup/CronCreate) | `/orchestrator-refresh` re-arm when run status is not `active` |
|
|
70
|
-
| `block_main_commit.py` | PreToolUse (Bash) | `git commit`/`git push` directly to `main` |
|
|
71
|
-
| `bot_mention_comment_blocker.py` | PreToolUse (Write/Edit) | PR review comments that @-mention a bot |
|
|
72
|
-
| `claude_md_orphan_file_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | Per-directory `CLAUDE.md` table cells naming a bare filename absent from the directory subtree |
|
|
73
|
-
| `conventional_pr_title_gate.py` | PreToolUse (Bash) | `gh pr create`/`gh pr edit` with a `--title` that is not a Conventional Commit, in a repo whose CI runs a semantic-pull-request title check |
|
|
74
|
-
| `destructive_command_blocker.py` | PreToolUse (Bash/PowerShell) | Shell commands with destructive literals (`rm -rf`, `git reset --hard`, etc.) |
|
|
75
|
-
| `docstring_rule_gate_count_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | A stale spelled-out gate-validator count in `docstring-prose-matches-implementation.md` — the "N more gate validators" / "M gated slices" count drifting from the `check_docstring_*` validators the prose names |
|
|
76
|
-
| `duplicate_rmtree_helper_blocker.py` | PreToolUse (Write/Edit) | A local re-definition of the Windows-safe rmtree helper trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`) in place of importing a shared helper |
|
|
77
|
-
| `eli11_reply_enforcer.py` | Stop | Final replies breaking the `eli11-replies` shape — more than 6 bullet lines, more than 2 list lines over 20 words each, or multi-line instructions with no numbered step among the lead lines. Code fences, inline code, blockquotes, table rows, and link targets come off before the reply is judged. |
|
|
78
|
-
| `env_var_table_code_drift_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | A markdown env-var summary table row attributing an environment variable to a code file whose source never references that variable name |
|
|
79
|
-
| `es_exe_path_rewriter.py` | PreToolUse | Rewrites paths referencing `.exe` under the Everything search path |
|
|
80
|
-
| `fable_spawn_gate.py` | PreToolUse (Agent/Task) | An `Agent` or `Task` spawn whose prompt carries no `FABLE-SPAWN-AUTHORIZED` token and whose model field reads `fable` in any letter case — the bare alias, or a delimiter segment of a full model id, so `claude-fable-5` is denied too |
|
|
81
|
-
| `gh_body_arg_blocker.py` | PreToolUse (Bash) | `gh` commands passing `--body`/`-b` directly (requires `--body-file` instead) |
|
|
82
|
-
| `gh_pr_author_enforcer.py` | PreToolUse | Enforces PR author identity rules |
|
|
83
|
-
| `gh_pr_author_restore.py` | PostToolUse | Restores PR author after a tool call |
|
|
84
|
-
| `hedging_language_blocker.py` | Stop | Responses with hedging words (`likely`, `probably`, `appears to`); armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
85
|
-
| `hook_prose_detector_consistency.py` | PreToolUse (Write/Edit) | Hook docstrings/messages that claim a trigger the detector cannot fire on; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
86
|
-
| `intent_only_ending_blocker.py` | Stop | Responses that end on a plan or intent without doing the work; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
87
|
-
| `open_questions_in_plans_blocker.py` | PreToolUse (Write/Edit) | Plan documents with unresolved open questions |
|
|
88
|
-
| `nas_ssh_binary_enforcer.py` | PreToolUse (Bash) | A bare `ssh`/`scp`/`sftp` command word targeting the NAS (Git Bash's MSYS ssh stalls on an interactive password prompt), or the full `System32/OpenSSH` binary to that host without `-o BatchMode=yes` |
|
|
89
|
-
| `package_inventory_stale_blocker.py` | PreToolUse (Write) | A new production code file created in a directory whose `README.md`/`CLAUDE.md` inventory (or a parent skill's `SKILL.md` Layout table mapping the `scripts/` subdirectory) names two or more sibling files but no entry for the new file |
|
|
90
|
-
| `pii_commit_command.py` | library | Token-aware git-commit detection reused by `pii_prevention_blocker.py` |
|
|
91
|
-
| `pii_payload_scan.py` | library | Write/Edit and durable post-body PII evaluation reused by `pii_prevention_blocker.py` |
|
|
92
|
-
| `pii_prevention_blocker.py` | PreToolUse (Write/Edit/MultiEdit/Bash/PowerShell/MCP GitHub) | Entry hook — content that carries high-confidence personal data or secrets (real emails, home-dir paths, private IPs, credential material) on write, durable GitHub posts, or staged commit paths; resolves the staged-commit repository from the command it gates (via `pii_prevention_blocker_parts`), not the session working directory |
|
|
93
|
-
| `pii_scanner.py` | library | Pure text scanners shared by `pii_prevention_blocker.py` |
|
|
94
|
-
| `piped_pytest_blocker.py` | PreToolUse (Bash) | A pytest run whose output feeds a pipe, where the pipeline reports the exit code of the command on the right |
|
|
95
|
-
| `plain_language_blocker.py` | PreToolUse (Write/Edit/AskUserQuestion) | Heavy or jargon words in user-facing prose when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off); AskUserQuestion lean-block structure stays always on |
|
|
96
|
-
| `precommit_code_rules_gate.py` | PreToolUse (Bash) | Staged changes that fail the CODE_RULES gate at commit time |
|
|
97
|
-
| `pytest_testpaths_orphan_blocker.py` | PreToolUse (Write/Edit/MultiEdit) | New `test_*.py` files created under a directory absent from a package's explicit pytest `testpaths` allowlist |
|
|
98
|
-
| `question_to_user_enforcer.py` | Stop | User-directed questions not routed through `AskUserQuestion` |
|
|
99
|
-
| `send_user_file_open_locally_blocker.py` | PreToolUse (SendUserFile) | A desk-side file attach (`SendUserFile` with `status` not `proactive`); points to opening the file with its native Windows app |
|
|
100
|
-
| `sensitive_file_protector.py` | PreToolUse (Write/Edit) | Writes to sensitive credential or config files |
|
|
101
|
-
| `session_edit_stage_gate.py` | PreToolUse (Bash) | A `git commit` that would drop files edited this session because they are tracked but left unstaged |
|
|
102
|
-
| `session_handoff_blocker.py` | Stop | Responses suggesting a new session mid-task |
|
|
103
|
-
| `shell_substitution_blocker.py` | PreToolUse (Bash) | A command carrying `$(...)`, a live backtick, or `<(...)`/`>(...)` process substitution, which the allowlist matcher cannot descend into |
|
|
104
|
-
| `stale_comment_reference_blocker.py` | PreToolUse (Edit) | An Edit that rewrites a Python code line while keeping the standalone comment directly above it, when that comment names an identifier the rewrite removes from the line |
|
|
105
|
-
| `state_description_blocker.py` | PreToolUse (Write/Edit) | Historical/comparative language in documentation; armed only when `CLAUDE_PROSE_STYLE_ENFORCEMENT` is on (default off) |
|
|
106
|
-
| `subprocess_budget_completeness.py` | PreToolUse | Subprocess calls missing required budget arguments |
|
|
107
|
-
| `tdd_enforcer.py` | PreToolUse (Write/Edit) | Production code written without a matching failing test |
|
|
108
|
-
| `unscoped_search_blocker.py` | PreToolUse (Bash/PowerShell) | A `find` or recursive listing that walks from the filesystem root, a drive root, bare home, or a network share root |
|
|
109
|
-
| `volatile_path_in_post_blocker.py` | PreToolUse (Bash/MCP GitHub) | `gh` post commands and GitHub MCP post tools whose body references a volatile path (job scratch dir, worktree, or system temp) that outlives the durable post |
|
|
110
|
-
| `windows_rmtree_blocker.py` | PreToolUse (Write/Edit) | `shutil.rmtree` with `ignore_errors=True` on Windows |
|
|
111
|
-
| `workflow_substitution_slot_blocker.py` | PreToolUse (Write/Edit) | Workflow templates with bare per-iteration tokens missing angle-bracket slots |
|
|
112
|
-
| `write_existing_file_blocker.py` | PreToolUse (Write) | Write to a path where a file already exists |
|
|
113
|
-
|
|
114
|
-
## Supporting modules
|
|
115
|
-
|
|
116
|
-
| File | Role |
|
|
117
|
-
|---|---|
|
|
118
|
-
| `_gh_body_arg_utils.py` | Parsing helpers for `gh_body_arg_blocker.py` |
|
|
119
|
-
|
|
120
|
-
## Conventions
|
|
121
|
-
|
|
122
|
-
- Tests live beside each hook as `test_<hookname>.py` or `test_<hookname>_<suffix>.py`. Run with `python -m pytest <test_file>`.
|
|
123
|
-
- Tunable constants live in `hooks_constants/<hook_name>_constants.py`.
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# claude_md_orphan_file_blocker_parts
|
|
2
|
+
|
|
3
|
+
The concern modules `claude_md_orphan_file_blocker.py` wires together to block a
|
|
4
|
+
per-directory `CLAUDE.md` that names a file absent from its subtree. The entry
|
|
5
|
+
hook imports them and re-exports their surface for the test suite.
|
|
6
|
+
|
|
7
|
+
## Modules
|
|
8
|
+
|
|
9
|
+
| File | Purpose |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `references.py` | Extracts the bare filenames a table cell names and the scripts a fenced run command invokes, honoring the `../` relative-path exemptions |
|
|
12
|
+
| `subtree_scan.py` | Resolves the scan root and reports which referenced filenames are absent from it, with a bounded walk plus a direct probe fallback |
|
|
13
|
+
| `scan_plan.py` | Builds the Write/Edit/MultiEdit scan plan and collects the orphan filenames the change introduces, excluding pre-existing orphans |
|
|
14
|
+
| `decision.py` | Builds the deny payload listing the missing files and closing with the retry hint, and emits the decision JSON |
|
|
15
|
+
| `__init__.py` | Package marker |
|
|
16
|
+
|
|
17
|
+
## Subdirectories
|
|
18
|
+
|
|
19
|
+
| Entry | Description |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `config/` | The region-join newline, the retry hint the deny reason closes with, and the missing-name join separator (`orphan_blocker_constants.py`) |
|
|
22
|
+
| `tests/` | pytest suite with one test module per module above |
|
|
23
|
+
|
|
24
|
+
## Running tests
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python -m pytest packages/claude-dev-env/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/
|
|
28
|
+
```
|
|
@@ -1,28 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
The concern modules `claude_md_orphan_file_blocker.py` wires together to block a
|
|
4
|
-
per-directory `CLAUDE.md` that names a file absent from its subtree. The entry
|
|
5
|
-
hook imports them and re-exports their surface for the test suite.
|
|
6
|
-
|
|
7
|
-
## Modules
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|---|---|
|
|
11
|
-
| `references.py` | Extracts the bare filenames a table cell names and the scripts a fenced run command invokes, honoring the `../` relative-path exemptions |
|
|
12
|
-
| `subtree_scan.py` | Resolves the scan root and reports which referenced filenames are absent from it, with a bounded walk plus a direct probe fallback |
|
|
13
|
-
| `scan_plan.py` | Builds the Write/Edit/MultiEdit scan plan and collects the orphan filenames the change introduces, excluding pre-existing orphans |
|
|
14
|
-
| `decision.py` | Builds the deny payload listing the missing files and closing with the retry hint, and emits the decision JSON |
|
|
15
|
-
| `__init__.py` | Package marker |
|
|
16
|
-
|
|
17
|
-
## Subdirectories
|
|
18
|
-
|
|
19
|
-
| Entry | Description |
|
|
20
|
-
|---|---|
|
|
21
|
-
| `config/` | The region-join newline, the retry hint the deny reason closes with, and the missing-name join separator (`orphan_blocker_constants.py`) |
|
|
22
|
-
| `tests/` | pytest suite with one test module per module above |
|
|
23
|
-
|
|
24
|
-
## Running tests
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
python -m pytest packages/claude-dev-env/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/
|
|
28
|
-
```
|
|
1
|
+
@AGENTS.md
|
|
@@ -390,7 +390,7 @@ def check_banned_noun_word_boundary(
|
|
|
390
390
|
def check_banned_prefixes(content: str, file_path: str) -> list[str]:
|
|
391
391
|
"""Flag function and method names using generic banned prefixes.
|
|
392
392
|
|
|
393
|
-
Per CODE_RULES.md
|
|
393
|
+
Per CODE_RULES.md Naming, function names use specific verbs.
|
|
394
394
|
Generic prefixes ``handle_``, ``process_``, ``manage_``, ``do_`` are
|
|
395
395
|
placeholders that hide the actual responsibility and are flagged so the
|
|
396
396
|
author renames the function to a specific verb.
|