claude-dev-env 1.38.1 → 1.40.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 +10 -36
- package/_shared/pr-loop/audit-reply-template.md +147 -0
- package/_shared/pr-loop/fix-protocol.md +25 -4
- package/_shared/pr-loop/gh-payloads.md +37 -50
- package/_shared/pr-loop/scripts/code_rules_gate.py +0 -60
- package/_shared/pr-loop/scripts/config/post_audit_thread_constants.py +199 -0
- package/_shared/pr-loop/scripts/config/reviews_disabled_constants.py +8 -0
- package/_shared/pr-loop/scripts/post_audit_thread.py +1242 -0
- package/_shared/pr-loop/scripts/preflight.py +129 -2
- package/_shared/pr-loop/scripts/reviews_disabled.py +59 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -19
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +1116 -0
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
- package/_shared/pr-loop/scripts/tests/test_preflight.py +41 -0
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +36 -0
- package/_shared/pr-loop/state-schema.md +1 -1
- package/agents/clean-coder.md +2 -2
- package/agents/pr-description-writer.md +150 -52
- package/bin/install.mjs +6 -7
- package/bin/install.test.mjs +8 -0
- package/commands/doc-gist.md +16 -0
- package/commands/plan.md +0 -2
- package/commands/review-plan.md +1 -1
- package/docs/CODE_RULES.md +122 -2
- package/docs/PR_DESCRIPTION_GUIDE.md +127 -64
- package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
- package/hooks/blocking/code_rules_enforcer.py +1143 -129
- package/hooks/blocking/convergence_gate_blocker.py +130 -0
- package/hooks/blocking/destructive_command_blocker.py +74 -0
- package/hooks/blocking/gh_body_arg_blocker.py +30 -0
- package/hooks/blocking/md_to_html_blocker.py +119 -0
- package/hooks/blocking/pr_description_enforcer.py +57 -22
- package/hooks/blocking/test_bot_mention_comment_blocker.py +131 -0
- package/hooks/blocking/test_code_rules_enforcer.py +21 -0
- package/hooks/blocking/test_code_rules_enforcer_any_exempt_files.py +70 -0
- package/hooks/blocking/test_code_rules_enforcer_any_imports_and_cast.py +92 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +152 -0
- package/hooks/blocking/test_code_rules_enforcer_bare_except.py +120 -0
- package/hooks/blocking/test_code_rules_enforcer_boundary_types.py +175 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
- package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +50 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_format.py +255 -0
- package/hooks/blocking/test_code_rules_enforcer_inline_tuple_string_magic.py +130 -0
- package/hooks/blocking/test_code_rules_enforcer_stub_implementations.py +141 -0
- package/hooks/blocking/test_code_rules_enforcer_test_branching.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_thin_wrapper_files.py +169 -0
- package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_typed_dict_pairs.py +141 -0
- package/hooks/blocking/test_convergence_gate_blocker.py +63 -0
- package/hooks/blocking/test_destructive_command_blocker.py +146 -0
- package/hooks/blocking/test_destructive_command_blocker_no_verify.py +102 -0
- package/hooks/blocking/test_gh_body_arg_blocker.py +45 -0
- package/hooks/blocking/test_md_to_html_blocker.py +317 -0
- package/hooks/blocking/test_pr_description_enforcer.py +69 -8
- package/hooks/config/any_type_config.py +7 -0
- package/hooks/config/banned_identifiers_constants.py +11 -0
- package/hooks/config/blocking_check_limits.py +38 -0
- package/hooks/config/bot_mention_comment_blocker_constants.py +20 -0
- package/hooks/config/code_rules_enforcer_constants.py +53 -0
- package/hooks/config/convergence_branch_constants.py +9 -0
- package/hooks/config/doc_gist_auto_publish_constants.py +18 -0
- package/hooks/config/html_companion_constants.py +20 -0
- package/hooks/config/inline_tuple_string_magic_constants.py +22 -0
- package/hooks/config/pr_description_enforcer_constants.py +14 -0
- package/hooks/config/test_banned_identifiers_constants.py +17 -0
- package/hooks/hooks.json +28 -20
- package/hooks/pyproject.toml +69 -0
- package/hooks/validators/mypy_integration.py +47 -1
- package/hooks/validators/run_all_validators.py +3 -3
- package/hooks/validators/test_mypy_integration.py +50 -1
- package/hooks/workflow/doc_gist_auto_publish.py +144 -0
- package/hooks/workflow/md_to_html_companion.py +365 -0
- package/hooks/workflow/test_doc_gist_auto_publish.py +117 -0
- package/hooks/workflow/test_md_to_html_companion.py +452 -0
- package/package.json +1 -1
- package/rules/gh-body-file.md +2 -0
- package/scripts/Install-SweepEmptyDirs.ps1 +111 -0
- package/scripts/check.ps1 +106 -0
- package/scripts/config/timing.py +11 -0
- package/scripts/sweep_empty_dirs.py +138 -0
- package/scripts/sync_to_cursor/rules.py +1 -1
- package/scripts/test_sweep_empty_dirs.py +183 -0
- package/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +323 -0
- package/skills/_shared/pr-loop/scripts/_cli_utils.py +22 -0
- package/skills/_shared/pr-loop/scripts/_path_resolver.py +165 -0
- package/skills/_shared/pr-loop/scripts/_xml_utils.py +20 -0
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +182 -0
- package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +185 -0
- package/skills/_shared/pr-loop/scripts/config/__init__.py +0 -0
- package/skills/_shared/pr-loop/scripts/config/path_resolver_constants.py +78 -0
- package/skills/_shared/pr-loop/scripts/init_loop_state.py +135 -0
- package/skills/_shared/pr-loop/scripts/teardown_worktrees.py +175 -0
- package/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +182 -0
- package/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +206 -0
- package/skills/bugteam/CONSTRAINTS.md +21 -22
- package/skills/bugteam/EXAMPLES.md +3 -3
- package/skills/bugteam/PROMPTS.md +227 -67
- package/skills/bugteam/SKILL.md +132 -455
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +112 -39
- package/skills/bugteam/reference/audit-contract.md +4 -22
- package/skills/bugteam/reference/copilot-gap-analysis.md +8 -5
- package/skills/bugteam/reference/design-rationale.md +2 -2
- package/skills/bugteam/reference/github-pr-reviews.md +50 -57
- package/skills/bugteam/reference/obstacles/audit-assign-ids.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-capture-excerpts.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-walk-categories.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-write-xml.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-append-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-apply-fixes.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-add-commit.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-push.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-post-reply.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-py-compile.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-read-files.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-resolve-thread.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-test-suite.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-violation-count.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-write-xml.md +13 -0
- package/skills/bugteam/reference/team-setup.md +111 -9
- package/skills/bugteam/reference/teardown-publish-permissions.md +39 -8
- package/skills/bugteam/scripts/README.md +60 -0
- package/skills/bugteam/scripts/_claude_permissions_common.py +358 -0
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +976 -0
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +375 -0
- package/skills/bugteam/scripts/bugteam_preflight.py +328 -0
- package/skills/bugteam/scripts/config/bugteam_code_rules_gate_constants.py +25 -0
- package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +26 -0
- package/skills/bugteam/scripts/config/bugteam_preflight_constants.py +35 -0
- package/skills/bugteam/scripts/config/claude_permissions_common_constants.py +20 -0
- package/skills/bugteam/scripts/config/probe_code_rules_enforcer_check_constants.py +12 -0
- package/skills/bugteam/scripts/config/windows_safe_rmtree_constants.py +7 -0
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +175 -0
- package/skills/bugteam/scripts/probe_code_rules_enforcer_check.py +107 -0
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +220 -0
- package/skills/bugteam/scripts/test__claude_permissions_common.py +112 -0
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +400 -0
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +384 -0
- package/skills/bugteam/scripts/test_bugteam_preflight.py +309 -0
- package/skills/bugteam/scripts/test_claude_permissions_common.py +195 -0
- package/skills/bugteam/scripts/test_grant_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_probe_code_rules_enforcer_check.py +76 -0
- package/skills/bugteam/scripts/test_revoke_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_windows_safe_rmtree.py +108 -0
- package/skills/bugteam/scripts/windows_safe_rmtree.py +100 -0
- package/skills/bugteam/test_skill_additions.py +1 -11
- package/skills/code/SKILL.md +176 -0
- package/skills/copilot-review/SKILL.md +16 -0
- package/skills/doc-gist/SKILL.md +99 -0
- package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +453 -0
- package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +515 -0
- package/skills/doc-gist/references/examples/03-code-review-pr.html +638 -0
- package/skills/doc-gist/references/examples/04-code-understanding.html +491 -0
- package/skills/doc-gist/references/examples/05-design-system.html +629 -0
- package/skills/doc-gist/references/examples/06-component-variants.html +605 -0
- package/skills/doc-gist/references/examples/07-prototype-animation.html +455 -0
- package/skills/doc-gist/references/examples/08-prototype-interaction.html +396 -0
- package/skills/doc-gist/references/examples/09-slide-deck.html +592 -0
- package/skills/doc-gist/references/examples/10-svg-illustrations.html +492 -0
- package/skills/doc-gist/references/examples/11-status-report.html +528 -0
- package/skills/doc-gist/references/examples/12-incident-report.html +596 -0
- package/skills/doc-gist/references/examples/13-flowchart-diagram.html +395 -0
- package/skills/doc-gist/references/examples/14-research-feature-explainer.html +381 -0
- package/skills/doc-gist/references/examples/15-research-concept-explainer.html +368 -0
- package/skills/doc-gist/references/examples/16-implementation-plan.html +702 -0
- package/skills/doc-gist/references/examples/17-pr-writeup.html +595 -0
- package/skills/doc-gist/references/examples/18-editor-triage-board.html +573 -0
- package/skills/doc-gist/references/examples/19-editor-feature-flags.html +663 -0
- package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +722 -0
- package/skills/doc-gist/references/examples/README.md +5 -0
- package/skills/doc-gist/scripts/config/__init__.py +0 -0
- package/skills/doc-gist/scripts/config/gist_upload_constants.py +16 -0
- package/skills/doc-gist/scripts/gist_upload.py +177 -0
- package/skills/doc-gist/scripts/test_gist_upload.py +51 -0
- package/skills/findbugs/SKILL.md +96 -2
- package/skills/monitor-open-prs/SKILL.md +14 -32
- package/skills/monitor-open-prs/test_skill_contract.py +0 -11
- package/skills/pr-consistency-audit/SKILL.md +112 -0
- package/skills/pr-consistency-audit/reference/detection-rules.md +96 -0
- package/skills/pr-consistency-audit/reference/illustrations.md +78 -0
- package/skills/pr-converge/SKILL.md +229 -23
- package/skills/pr-converge/config/__init__.py +0 -0
- package/skills/pr-converge/config/constants.py +63 -0
- package/skills/pr-converge/reference/convergence-gates.md +138 -44
- package/skills/pr-converge/reference/examples.md +43 -11
- package/skills/pr-converge/reference/fix-protocol.md +6 -5
- package/skills/pr-converge/reference/ground-rules.md +5 -3
- package/skills/pr-converge/reference/multi-pr-orchestration.md +44 -19
- package/skills/pr-converge/reference/obstacles/fix-post-replies.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-push.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-read-filelines.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-reset-state.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-resolve-threads.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-stage-commit.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-trigger-bugbot.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-write-test.md +13 -0
- package/skills/pr-converge/reference/per-tick.md +107 -31
- package/skills/pr-converge/reference/state-schema.md +22 -1
- package/skills/pr-converge/reference/stop-conditions.md +9 -7
- package/skills/pr-converge/scripts/README.md +34 -46
- package/skills/pr-converge/scripts/check_bugbot_ci.py +279 -0
- package/skills/pr-converge/scripts/check_convergence.py +497 -0
- package/skills/pr-converge/scripts/check_pending_reviews.py +154 -0
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +118 -0
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +134 -0
- package/skills/pr-converge/scripts/post_fix_reply.py +168 -0
- package/skills/pr-converge/scripts/test_check_bugbot_ci.py +312 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
- package/skills/qbug/SKILL.md +157 -27
- package/skills/session-log/SKILL.md +216 -114
- package/skills/session-tidy/SKILL.md +1 -1
- package/skills/skill-builder/SKILL.md +138 -56
- package/skills/skill-builder/references/delegation-map.md +72 -113
- package/skills/skill-builder/references/progressive-disclosure.md +122 -0
- package/skills/skill-builder/references/self-audit-checklist.md +92 -0
- package/skills/skill-builder/references/skill-types.md +228 -0
- package/skills/skill-builder/references/thariq-x-post-skills.json +33 -0
- package/skills/skill-builder/templates/gap-analysis.md +15 -8
- package/skills/skill-builder/workflows/improve-skill.md +86 -57
- package/skills/skill-builder/workflows/new-skill.md +80 -168
- package/skills/skill-builder/workflows/polish-skill.md +78 -54
- package/skills/structure-prompt/SKILL.md +50 -0
- package/skills/structure-prompt/reference/adversarial-tuning.md +62 -0
- package/skills/structure-prompt/reference/block-classification.md +27 -0
- package/skills/structure-prompt/reference/canonical-case.md +48 -0
- package/skills/structure-prompt/reference/citation-depth.md +70 -0
- package/skills/structure-prompt/reference/cleanup.md +33 -0
- package/skills/structure-prompt/reference/constraints.md +33 -0
- package/skills/structure-prompt/reference/directives.md +37 -0
- package/skills/structure-prompt/reference/examples.md +72 -0
- package/skills/structure-prompt/reference/instantiation.md +51 -0
- package/skills/structure-prompt/reference/output-contract.md +72 -0
- package/skills/structure-prompt/reference/per-category.md +23 -0
- package/skills/structure-prompt/reference/persona.md +38 -0
- package/skills/structure-prompt/reference/research.md +33 -0
- package/skills/structure-prompt/reference/structure.md +28 -0
- package/agents/code-standards-agent.md +0 -93
- package/agents/groq-coder.md +0 -113
- package/agents/plan-executor.md +0 -226
- package/agents/project-docs-analyzer.md +0 -53
- package/agents/project-structure-organizer-agent.md +0 -72
- package/agents/skill-to-agent-converter.md +0 -370
- package/agents/skill-writer-agent.md +0 -470
- package/agents/user-docs-writer.md +0 -67
- package/agents/workflow-visual-documenter.md +0 -82
- package/commands/readability-review.md +0 -20
- package/hooks/mypy.ini +0 -2
- package/hooks/notification/attention_needed_notify.py +0 -71
- package/hooks/notification/claude_notification_handler.py +0 -67
- package/hooks/notification/notification_utils.py +0 -267
- package/hooks/notification/subagent_complete_notify.py +0 -381
- package/hooks/notification/test_attention_needed_notify.py +0 -47
- package/hooks/notification/test_claude_notification_handler.py +0 -54
- package/hooks/notification/test_notification_utils.py +0 -91
- package/hooks/notification/test_subagent_complete_notify.py +0 -79
- package/scripts/config/groq_bugteam_config.py +0 -230
- package/scripts/config/test_groq_bugteam_config.py +0 -83
- package/scripts/config/test_spec_implementer_prompt.py +0 -32
- package/scripts/groq_bugteam.README.md +0 -131
- package/scripts/groq_bugteam.py +0 -647
- package/scripts/groq_bugteam_dotenv.py +0 -40
- package/scripts/groq_bugteam_spec.py +0 -226
- package/scripts/test_groq_bugteam.py +0 -529
- package/scripts/test_groq_bugteam_apply_fix_from_spec.py +0 -426
- package/scripts/test_groq_bugteam_dotenv.py +0 -66
- package/scripts/test_groq_bugteam_spec.py +0 -338
- package/skills/bugteam/SKILL_EVALS.md +0 -309
- package/skills/dream/SKILL.md +0 -118
- package/skills/ingest/SKILL.md +0 -40
- package/skills/npm-creator/SKILL.md +0 -187
- package/skills/readability-review/SKILL.md +0 -127
- package/skills/resume-review/SKILL.md +0 -261
- package/skills/rule-audit/SKILL.md +0 -307
- package/skills/rule-creator/SKILL.md +0 -150
- package/skills/searching-obsidian-vault/SKILL.md +0 -131
- package/skills/skill-writer/REFERENCE.md +0 -284
- package/skills/skill-writer/SKILL.md +0 -222
- package/skills/tdd-team/SKILL.md +0 -128
package/docs/CODE_RULES.md
CHANGED
|
@@ -52,6 +52,16 @@ These rules are automatically enforced by `code_rules_enforcer.py`. Violations b
|
|
|
52
52
|
| Hardcoded user paths | No string literals naming a specific user's home directory in production code (`C:/Users/jon/...`, `/Users/alice/...`, `/home/bob/...`). Use `pathlib.Path.home()` or `os.path.expanduser('~')`. **Exempt:** test files, `config/` files, workflow registry paths (`/workflow/`, `_tab.py`, `/states.py`, `/modules.py`), Django migrations (`/migrations/`), and hook infrastructure (the enforcer embeds path patterns and must not self-block). |
|
|
53
53
|
| sys.path.insert dedup | `sys.path.insert(0, X)` must be guarded by `if X not in sys.path:` (or equivalent membership test) so reloads do not push the same entry repeatedly. **Test files exempt.** |
|
|
54
54
|
| Unused module-level imports | Module-level imports never referenced in the file body are flagged. Skipped for files declaring `__all__` (re-exports), files using `TYPE_CHECKING` (annotation-only imports), and lines marked `# noqa`. **Test files exempt.** |
|
|
55
|
+
| Banned identifiers | Single-letter or 2–4 char abbreviations in production code: `ctx`, `cfg`, `msg`, `btn`, `idx`, `cnt`, `tmp`, `elem`, `val`. Test files exempt; loop counters `i`/`j`/`k` and exception `e` exempt. See §5 for the full list and rationale. |
|
|
56
|
+
| Banned function prefixes | Function names starting with `handle_`, `process_`, `manage_`, or `do_` are flagged — these prefixes describe nothing about behavior. Name functions after the noun they produce or the verb they perform (`fetch_user`, `validate_payload`). **Test files exempt.** |
|
|
57
|
+
| Type escape hatches | `from typing import Any`, `cast()`, and inline `Any` in production are flagged outside boundary files (`__init__.py`, `protocols.py`, `types.py`, `conftest.py`). Name the concrete shape instead. |
|
|
58
|
+
| Bare except | `except:` and `except BaseException:` swallow KeyboardInterrupt/SystemExit; `except Exception:` hides bugs by catching nearly every error class. Name the specific exception(s) you intend to catch (tuple form `except (ValueError, KeyError):` is fine). **Test files and hook infrastructure exempt.** |
|
|
59
|
+
| Boundary types — Any in signatures | `Any` appearing directly or nested inside a generic in a function signature (parameters, return type) or class attribute annotation is flagged. Local variable annotations are exempt. Files named `protocols.py` or `types.py` are interface-declaration surfaces and exempt. |
|
|
60
|
+
| Stub implementations | Functions whose body is `pass`, `...`, or `raise NotImplementedError` in production code are flagged unless declared abstract (`@abstractmethod`) or part of a `Protocol`. Implement the function or remove it. |
|
|
61
|
+
| TypedDict encode/decode pairs | Every `class FooPayload(TypedDict):` in production code must have companion `_encode_foo_payload(...)` and `_decode_foo_payload(...)` functions in the same module — boundary serialization should not leak to callers. |
|
|
62
|
+
| Test-mode branching in production | Reading `TESTING`, `PYTEST_CURRENT_TEST`, `IS_TEST`, etc. from production code creates two parallel implementations. Use dependency injection so production stays single-path. **Test files and hook infrastructure exempt.** |
|
|
63
|
+
| Thin wrapper files | A non-`__init__.py` module whose body is only imports (optionally with an `__all__` assignment) is a re-export indirection with no payload. Callers should import from the real module. `__init__.py` is the canonical re-export surface and is exempt. |
|
|
64
|
+
| Docstring format (Google-style) | Public functions/methods (no leading underscore, not dunder, body > 3 lines, not `@property`/`@abstractmethod`) require Google-style `Args:` / `Returns:` (or `Yields:`) / `Raises:` sections matching the signature. **Test files exempt.** |
|
|
55
65
|
|
|
56
66
|
### Where UPPER_SNAKE is allowed
|
|
57
67
|
|
|
@@ -112,7 +122,7 @@ Full words only. No mental translation.
|
|
|
112
122
|
|
|
113
123
|
**Exception:** `i`, `j`, `k` in loops; `e` for exception.
|
|
114
124
|
|
|
115
|
-
**Extended naming rules**
|
|
125
|
+
**Extended naming rules** :
|
|
116
126
|
- Loop vars: `each_order`, `each_user` (prefix `each_`)
|
|
117
127
|
- Booleans: `is_valid`, `has_permission`, `should_retry` (prefix `is_`/`has_`/`should_`/`can_`)
|
|
118
128
|
- Collections: `all_orders`, `all_users` (prefix `all_`)
|
|
@@ -227,6 +237,57 @@ Parent knows: nothing about child's internals
|
|
|
227
237
|
|
|
228
238
|
---
|
|
229
239
|
|
|
240
|
+
## 9.5 NO THIN WRAPPER MODULES
|
|
241
|
+
|
|
242
|
+
A non-`__init__.py` module whose body is only imports (optionally with an `__all__` assignment) is a thin wrapper. Callers should import from the real module. The wrapper adds no payload — only an indirection layer that obscures where things live.
|
|
243
|
+
|
|
244
|
+
`__init__.py` is the canonical re-export surface and is exempt; package surface aggregation is its job.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 9.6 NO BACKWARDS-COMPATIBILITY SHIMS
|
|
249
|
+
|
|
250
|
+
Removed code is removed. Do not leave behind:
|
|
251
|
+
|
|
252
|
+
- Renamed functions that re-export the old name with a `# deprecated` comment
|
|
253
|
+
- `_old_*` aliases pointing to the new implementation
|
|
254
|
+
- Wrapper modules whose only purpose is to keep an old import path alive
|
|
255
|
+
- `// removed in vX` comment markers next to deleted blocks
|
|
256
|
+
|
|
257
|
+
When a symbol moves or its signature changes, update the call sites in the same commit. The git log records what changed; the codebase records what exists now.
|
|
258
|
+
|
|
259
|
+
> **See also:** [`skills/code/SKILL.md`](../skills/code/SKILL.md) §5 ("No fallback paths, no back-compat shims, no legacy code") states the same principle as a session-start prompt directive. This section is the authoritative wording; the skill amplifies it for `/code` sessions.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 9.7 NO FALLBACK / BEST-EFFORT WRAPPERS
|
|
264
|
+
|
|
265
|
+
Do not wrap a call in `try/except` that swallows the failure and returns a default unless the caller has explicitly opted in to that behavior at the boundary.
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
# BAD — silently hides every failure mode
|
|
269
|
+
def fetch_user(user_id: int) -> User | None:
|
|
270
|
+
try:
|
|
271
|
+
return _registry[user_id]
|
|
272
|
+
except Exception:
|
|
273
|
+
return None
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
# GOOD — names the specific failure and propagates the rest
|
|
278
|
+
def fetch_user(user_id: int) -> User | None:
|
|
279
|
+
try:
|
|
280
|
+
return _registry[user_id]
|
|
281
|
+
except KeyError:
|
|
282
|
+
return None
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Fallback values mask programming errors (KeyError vs RuntimeError vs AttributeError all collapse to "None"), making debugging impossible. Production code names the specific failure mode it intends to handle.
|
|
286
|
+
|
|
287
|
+
> **See also:** [`skills/code/SKILL.md`](../skills/code/SKILL.md) §2 ("No `try`/`except` in core logic that recovers, softens, or best-efforts a failure") states the same principle as a session-start prompt directive. The hook check `check_bare_except` enforces the narrowest case (bare/`Exception`/`BaseException` handlers); this section + the `code` skill cover the broader "any swallowing handler" intent.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
230
291
|
## 10. NO REDUNDANT DATA FETCHES
|
|
231
292
|
|
|
232
293
|
If you already have data, don't fetch again.
|
|
@@ -243,6 +304,53 @@ const profile = await db.profile.first();
|
|
|
243
304
|
|
|
244
305
|
---
|
|
245
306
|
|
|
307
|
+
## 11. ENFORCEMENT SURFACES
|
|
308
|
+
|
|
309
|
+
Rules in this document are enforced through three distinct surfaces, each with different latency and reach. Knowing which surface owns a rule tells you what happens when you violate it.
|
|
310
|
+
|
|
311
|
+
| Surface | What it catches | When it runs | Failure mode |
|
|
312
|
+
|---------|-----------------|--------------|--------------|
|
|
313
|
+
| **⚡ Hook** | Pattern-matchable violations: comments, magic values, banned identifiers, bare except, boundary `Any`, thin wrappers, docstring shape, etc. | PreToolUse on Write/Edit (and PostToolUse advisories) | Blocks the write — Claude must fix and retry |
|
|
314
|
+
| **🤖 Prompt** | Judgment-driven principles: SRP, Right-Sized Engineering, KISS, conservative-action, BDD discovery; strict-mode standards via the `/code` skill (no `Any`/`cast`, immutable TypedDicts, DI hooks, 100% branch coverage, no fallback `try/except`) | Read into the model context at session start (CLAUDE.md, rules/*.md, skill prepends) | Influences Claude's decisions; no automatic block |
|
|
315
|
+
| **👥 Audit rubric** | Cross-file architectural concerns: SOLID misapplication, abstraction leaks, multi-file coupling | Run on demand via `/check`, `/readability-review`, agent-driven audits | Surfaces in audit output; humans decide whether to act |
|
|
316
|
+
|
|
317
|
+
### Prompt-enforced rules (no hook coverage)
|
|
318
|
+
|
|
319
|
+
These principles cannot be reduced to a regex or AST visitor. They live in user-private `~/.claude/rules/` and `~/.claude/CLAUDE.md`, and are read into context every session:
|
|
320
|
+
|
|
321
|
+
- **Right-Sized Engineering** — concrete classes for single concretions, functions when no state, no DI frameworks for solo-scale code
|
|
322
|
+
- **SRP / SOLID misapplication signals** — see §7.5
|
|
323
|
+
- **conservative-action** — when intent is ambiguous, ask before acting
|
|
324
|
+
- **explore-thoroughly** — investigate before committing to an approach
|
|
325
|
+
- **agent-spawn-protocol** — verify context before delegating to a subagent
|
|
326
|
+
- **`code` skill ([`skills/code/SKILL.md`](../skills/code/SKILL.md))** — invoked via `/code`, prepends strict-mode standards for the entire session: no `Any`/`cast()`/`# type: ignore`, immutable TypedDicts with manual `_encode_*`/`_decode_*` and `require_*` validation, per-module `_test_hooks.py` for DI, 100% statement + branch coverage, zero mocks. Several criteria overlap with §9.6/§9.7 and the ⚡ B-series checks; the skill is the canonical entry point when the user explicitly opts into strict mode for an implementation task.
|
|
327
|
+
|
|
328
|
+
### Audit-rubric reference
|
|
329
|
+
|
|
330
|
+
For multi-file architectural reviews see [`packages/claude-dev-env/audit-rubrics/`](../audit-rubrics/). Categories A–F, I, K stay as agent rubrics rather than ⚡ blocking rules because they require multi-file reasoning that single-file hooks cannot perform.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 12. DEFERRED RULES (P1 — TRACKED, NOT ENFORCED)
|
|
335
|
+
|
|
336
|
+
The following rules are documented in `~/.claude/rules/` and applied by Claude through prompt context, but have no hook coverage in `code_rules_enforcer.py`. Promotion to ⚡ blocking enforcement is on the backlog and will land as separate hardening commits.
|
|
337
|
+
|
|
338
|
+
| Rule | Source | Promotion path |
|
|
339
|
+
|------|--------|----------------|
|
|
340
|
+
| Context7 before web search for library/SDK questions | [`rules/context7.md`](../rules/context7.md) | New PreToolUse hook on WebSearch when query mentions a library name |
|
|
341
|
+
| Verify-before-asking checklist | [`rules/verify-before-asking.md`](../rules/verify-before-asking.md) | Stop hook scanning AskUserQuestion calls for "where is", "what file", etc. |
|
|
342
|
+
| BDD naming (`should_…` / `describe…it…`) | [`rules/bdd.md`](../rules/bdd.md) | `code_rules_enforcer.py::check_test_naming` (new) — flag test functions starting with `test_` lacking corresponding `should_…` form |
|
|
343
|
+
| `gh` pagination requires `--paginate --slurp` plus external `jq` | [`rules/gh-paginate.md`](../rules/gh-paginate.md) | PreToolUse Bash hook matching `gh api .*/(reviews\|comments)` without `--paginate --slurp` |
|
|
344
|
+
| Self-contained documentation (no "as discussed", "Option A", session refs) | [`rules/self-contained-docs.md`](../rules/self-contained-docs.md) | PostToolUse Write hook scanning new `.md` content for conversational refs |
|
|
345
|
+
| Temp file cleanup at end of task | [`rules/cleanup-temp-files.md`](../rules/cleanup-temp-files.md) | Stop hook scanning for files Claude created and did not delete |
|
|
346
|
+
| No credentials committed to git | [`rules/git-workflow.md`](../rules/git-workflow.md) | PreToolUse Bash hook on `git commit` scanning staged diff for high-entropy strings, `.env` patterns, and known credential file extensions |
|
|
347
|
+
| Per-module DI hooks (`_test_hooks.py` sibling) instead of `if TESTING:` branching | [`skills/code/SKILL.md`](../skills/code/SKILL.md) §4 | New `check_test_hooks_sibling()` — when a module imports a side-effect dependency and a test exists, require a `<module>_test_hooks.py` sibling exposing the injection points |
|
|
348
|
+
| 100% statement + branch coverage with zero mocks | [`skills/code/SKILL.md`](../skills/code/SKILL.md) §3 | CI check (not write-time) — `pytest --cov-branch --cov-fail-under=100` on touched packages; covers only what the diff added |
|
|
349
|
+
| `TypedDict` `_decode_*` calls `require_*` on every field | [`skills/code/SKILL.md`](../skills/code/SKILL.md) §6 | Extend `check_typed_dict_encode_decode` (B2) — when the decoder is present, AST-verify every TypedDict field appears as a `require_*` call before the return |
|
|
350
|
+
| `Protocol` signatures match the real implementation exactly | [`skills/code/SKILL.md`](../skills/code/SKILL.md) Gotchas | mypy `--strict` over the protocol module catches this; promotion = add `[tool.mypy] strict = true` per-module override in `pyproject.toml` for files declaring `Protocol` subclasses |
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
246
354
|
## QUICK CHECKLIST
|
|
247
355
|
|
|
248
356
|
```
|
|
@@ -257,6 +365,16 @@ Hook will enforce:
|
|
|
257
365
|
[⚡] Logging format args
|
|
258
366
|
[ ] File length reasonable (advisory at 400, strong nudge at 1000 — see §6.5)
|
|
259
367
|
[⚡] Constants in config/
|
|
368
|
+
[⚡] No banned identifiers (ctx, cfg, msg, btn, idx, cnt, tmp, elem, val)
|
|
369
|
+
[⚡] No banned function prefixes (handle_, process_, manage_, do_)
|
|
370
|
+
[⚡] No type escape hatches (Any imports, cast(), inline Any)
|
|
371
|
+
[⚡] No bare except / except Exception / except BaseException
|
|
372
|
+
[⚡] No Any in function signatures or class attributes (boundary types)
|
|
373
|
+
[⚡] No stub bodies (pass / ... / raise NotImplementedError) outside abstract methods
|
|
374
|
+
[⚡] TypedDict has companion _encode_*/_decode_* in same module
|
|
375
|
+
[⚡] No test-mode branching in production (TESTING / PYTEST_CURRENT_TEST)
|
|
376
|
+
[⚡] No thin wrapper modules (imports only, optionally with __all__, outside __init__.py)
|
|
377
|
+
[⚡] Public functions have Google-style Args:/Returns:/Raises: when warranted
|
|
260
378
|
|
|
261
379
|
Manual check:
|
|
262
380
|
[ ] No abbreviations?
|
|
@@ -264,5 +382,7 @@ Manual check:
|
|
|
264
382
|
[ ] Self-contained components?
|
|
265
383
|
[ ] SRP holds (one reason to change per function/class/module)?
|
|
266
384
|
[ ] OCP/LSP/ISP/DIP only applied where abstractions already earn their keep (see §7.5)?
|
|
267
|
-
[ ]
|
|
385
|
+
[ ] No backwards-compatibility shims (§9.6)?
|
|
386
|
+
[ ] No fallback/best-effort wrappers (§9.7)?
|
|
387
|
+
[ ] Readability: /check
|
|
268
388
|
```
|
|
@@ -1,95 +1,158 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PR Description Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide describes the PR-body shape that the `pr-description-writer` agent produces and that the `pr_description_enforcer` PreToolUse hook validates against. The style mirrors merged pull requests in `anthropics/claude-code`, `anthropics/claude-code-action`, and `anthropics/claude-cli-internal`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Three shapes, picked from the diff
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Pick the shape from the size and risk of the change, not from a template.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
9
|
+
| Signal | Shape |
|
|
10
|
+
|---|---|
|
|
11
|
+
| 1-3 files, mechanical change (pin bump, link fix, typo, single-line config), no behavior change | **Trivial** -- one declarative sentence, no headers |
|
|
12
|
+
| Behavior change, bug fix, small feature; under ~15 files | **Standard** -- intro paragraph + `## Changes` + `## Test plan` (or `## Validation`) |
|
|
13
|
+
| New subsystem, refactor across many files, schema or contract change, anything with a caveat | **Heavy** -- intro + `## Problem` + `## Fix` (or `## Changes`) + `## Verification` + extra sections as needed |
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
Prefer the smaller shape when in doubt.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
- Provide business or technical context
|
|
18
|
-
- Reference related issue numbers using `#123` or `Fixes #123`, `Closes #456`
|
|
19
|
-
- If no issue exists, briefly explain the motivation
|
|
17
|
+
## Shape 1: Trivial
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
One sentence. No Markdown headers. Optional `Fixes #N` line.
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
- Note any breaking changes prominently
|
|
21
|
+
```
|
|
22
|
+
Pin third-party GitHub Actions references to immutable commit SHAs.
|
|
23
|
+
```
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
```
|
|
26
|
+
Bump pinned Bun from 1.3.6 to 1.3.14.
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
Fixes #1311.
|
|
29
|
+
```
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
- How to manually verify the changes (if applicable)
|
|
34
|
-
- Any areas of concern or limitations
|
|
35
|
-
- Performance impact (if relevant)
|
|
31
|
+
## Shape 2: Standard
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
```
|
|
34
|
+
<One short intro paragraph stating the change and why it matters.
|
|
35
|
+
Reference the failure mode or user-visible symptom when there is one.>
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
- Backward compatibility status
|
|
41
|
-
- Potential side effects
|
|
42
|
-
- Migration steps (if needed)
|
|
37
|
+
Fixes #<n>.
|
|
43
38
|
|
|
44
|
-
##
|
|
39
|
+
## Changes
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
- `path/to/file.ext`: short clause describing the change
|
|
42
|
+
- `path/to/other.ext`: short clause
|
|
43
|
+
- `tests/foo.test.ts`: 2 new cases for X
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
- Note any follow-up work needed
|
|
45
|
+
## Test plan
|
|
50
46
|
|
|
51
|
-
|
|
47
|
+
- `bun test test/foo.test.ts`
|
|
48
|
+
- `bun run typecheck`
|
|
49
|
+
- Manual: reproduce on a branch named `feature/a,b`; confirm no rejection
|
|
50
|
+
```
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
The intro paragraph carries the Why -- no `## Why` header needed when one paragraph is enough.
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
## Shape 3: Heavy
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
56
|
+
```
|
|
57
|
+
<Two- to four-sentence intro: scope, motivation, user-visible effect.
|
|
58
|
+
Link to the prior PR or issue that motivates this one if applicable.>
|
|
60
59
|
|
|
61
|
-
|
|
60
|
+
Fixes #<n>.
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
- Use second person sparingly -- focus on what the code does, not what the reviewer should do
|
|
65
|
-
- Avoid jargon -- explain technical terms if non-obvious
|
|
66
|
-
- Use markdown formatting -- bullets, code blocks, headers for readability
|
|
67
|
-
- Be honest about limitations -- acknowledge trade-offs and known issues
|
|
68
|
-
- Assume reviewers are unfamiliar -- provide sufficient context
|
|
62
|
+
## Problem
|
|
69
63
|
|
|
70
|
-
|
|
64
|
+
<Concrete description of the failure mode or gap. Include the actual
|
|
65
|
+
error text, a reproduction, or the symptomatic log line in a fenced
|
|
66
|
+
code block when it helps.>
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
```
|
|
69
|
+
<example error or reproduction>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Fix
|
|
77
73
|
|
|
78
|
-
|
|
74
|
+
<What the change does at the level a reviewer needs to evaluate it.
|
|
75
|
+
Reference the file or function by path/name. Don't restate the diff
|
|
76
|
+
line-by-line -- the reviewer can read the code.>
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Brief 1-2 sentence overview of the change.
|
|
78
|
+
- `src/path/file.ts`: brief description
|
|
79
|
+
- `src/path/other.ts`: brief description
|
|
83
80
|
|
|
84
|
-
##
|
|
85
|
-
Problem/context and reference to related issue (#123).
|
|
81
|
+
## Verification
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
- Command 1
|
|
84
|
+
- Command 2 (with output count when useful: "666 pass, 0 fail")
|
|
85
|
+
- Manual scenarios walked through
|
|
89
86
|
|
|
90
|
-
##
|
|
91
|
-
How this was tested and verified.
|
|
87
|
+
## Caveat
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
<Anything a reviewer or downstream user needs to know that isn't in
|
|
90
|
+
the diff. Omit this section when there is no caveat.>
|
|
95
91
|
```
|
|
92
|
+
|
|
93
|
+
Optional heavy-shape sections, used when they earn their place:
|
|
94
|
+
|
|
95
|
+
- `## Runtime behavior` -- when the change preserves behavior but moves it.
|
|
96
|
+
- `## Components` -- a small table when the PR introduces multiple named artifacts.
|
|
97
|
+
- `## Backward compatibility` -- when an older consumer might still hit this code path.
|
|
98
|
+
- `## Context` -- background a reviewer outside the area would need.
|
|
99
|
+
|
|
100
|
+
## Section vocabulary
|
|
101
|
+
|
|
102
|
+
Pick from these. Don't invent new ones, and don't use synonyms within one PR:
|
|
103
|
+
|
|
104
|
+
| Intent | Header (pick one) |
|
|
105
|
+
|---|---|
|
|
106
|
+
| What this PR is and why | `## Summary` -- or no header (preferred when 1-3 sentences) |
|
|
107
|
+
| The failure being fixed | `## Problem` -- or no header when the intro paragraph carries it |
|
|
108
|
+
| The change itself | `## Changes` or `## Fix` |
|
|
109
|
+
| How it was verified | `## Test plan`, `## Validation`, `## Verification`, or `## Testing` |
|
|
110
|
+
| Things to know | `## Caveat`, `## Runtime behavior`, `## Backward compatibility`, `## Context` |
|
|
111
|
+
|
|
112
|
+
## File reference style
|
|
113
|
+
|
|
114
|
+
- Always backtick file paths: `` `src/github/operations/branch.ts` ``.
|
|
115
|
+
- Use the full path from repo root, not just the basename, unless the basename is unambiguous within the PR.
|
|
116
|
+
- Bullet lists describing per-file changes lead with the backticked path and a colon:
|
|
117
|
+
- `` `src/foo.ts`: whitelists `,` in branch names ``
|
|
118
|
+
- `` `test/foo.test.ts`: 3 new cases for comma-bearing branches ``
|
|
119
|
+
- Prose calling out a single primary file bolds the backticked filename plus a colon: `` **`branch.ts`**: ... ``.
|
|
120
|
+
|
|
121
|
+
## Cross-references
|
|
122
|
+
|
|
123
|
+
- Issue/PR shorthand: `#1311` (same repo), `anthropics/claude-code#40576` (cross-repo).
|
|
124
|
+
- `Fixes #N` and `Closes #N` close the linked issue on merge -- use them deliberately.
|
|
125
|
+
- `Linear: CC-1723` -- one line, no Markdown, after the intro paragraph or at the bottom.
|
|
126
|
+
- "Same change as <repo>#<n>" / "Follow-up to #<n>" -- one-liners that orient a reviewer.
|
|
127
|
+
|
|
128
|
+
## Markers and footers
|
|
129
|
+
|
|
130
|
+
- `<!-- NO CHANGELOG -->` on its own line, at the very end, for docs-only or CI-only PRs in repos that auto-generate changelogs from PR titles.
|
|
131
|
+
- Don't add a "Generated with Claude Code" footer -- merged Anthropic PRs don't use one consistently, and the repo's commit trailer covers attribution.
|
|
132
|
+
|
|
133
|
+
## What the hook checks
|
|
134
|
+
|
|
135
|
+
`pr_description_enforcer.py` runs on `gh pr create` and `gh pr edit` invocations that include a body. It blocks when any of the following are true:
|
|
136
|
+
|
|
137
|
+
- The body, after stripping Markdown ceremony (headers, code fences, bullet markers, bold/emphasis, link text), contains fewer than 40 characters of prose. A skeleton of `## Summary` + `## Changes` + bullets with no Why paragraph fails here.
|
|
138
|
+
- The body contains vague phrases like `fix bug`, `update code`, `minor changes`, or `various fixes`.
|
|
139
|
+
|
|
140
|
+
The hook does not require any specific section headers -- `## Summary`, `## Problem`, `## Fix`, `## Changes`, `## Test plan` are all optional, including any combination of them. A single substantive sentence ("Pin third-party GitHub Actions references to immutable commit SHAs.") satisfies the check.
|
|
141
|
+
|
|
142
|
+
When the hook blocks, it points the caller at the `pr-description-writer` agent and at this guide.
|
|
143
|
+
|
|
144
|
+
## Tone
|
|
145
|
+
|
|
146
|
+
- Plain language. "The pull engine would blindly overwrite any record marked as 'synced'" -- not "PullEngine.run() exhibited non-idempotent behavior".
|
|
147
|
+
- Active voice. "Add `,` to the whitelist" -- not "`,` was added to the whitelist".
|
|
148
|
+
- No filler. Start with the content, not "This PR..." or "In this change...".
|
|
149
|
+
- No restating the diff. Trust the reviewer to read the code; explain the parts they can't infer.
|
|
150
|
+
- No hedging ("should", "might", "I think") unless the uncertainty is real -- in which case say "not yet verified" and call it out.
|
|
151
|
+
|
|
152
|
+
## What to avoid
|
|
153
|
+
|
|
154
|
+
- Code snippets that simply repeat the diff. Code blocks are for error reproductions, failing commands, or before/after when the contrast is the point.
|
|
155
|
+
- Technical jargon for non-obvious internals ("Dexie transaction" -> "database transaction").
|
|
156
|
+
- Multi-line preamble. The PR title already says what the change is.
|
|
157
|
+
- Section headers over empty content. If `## Caveat` would be empty, drop the header.
|
|
158
|
+
- Second-person commentary directed at the reviewer ("please review carefully"). The reviewer knows their job.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PreToolUse hook: block @cursor or @copilot mentions in add_issue_comment body.
|
|
3
|
+
|
|
4
|
+
Bugbot trigger requires exactly ``bugbot run`` with no other text. Copilot review
|
|
5
|
+
requires the GitHub REST API endpoint, not an issue comment mention. This hook
|
|
6
|
+
catches both mistakes and returns the correct procedure for each.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _insert_hooks_tree_for_imports() -> None:
|
|
15
|
+
hooks_tree = Path(__file__).resolve().parent.parent
|
|
16
|
+
hooks_tree_string = str(hooks_tree)
|
|
17
|
+
if hooks_tree_string not in sys.path:
|
|
18
|
+
sys.path.insert(0, hooks_tree_string)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_insert_hooks_tree_for_imports()
|
|
22
|
+
|
|
23
|
+
from config.bot_mention_comment_blocker_constants import (
|
|
24
|
+
COPILOT_MENTION_TOKEN,
|
|
25
|
+
CORRECTIVE_MESSAGE_COPILOT,
|
|
26
|
+
CORRECTIVE_MESSAGE_CURSOR,
|
|
27
|
+
CURSOR_MENTION_TOKEN,
|
|
28
|
+
TOOL_NAME,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _body_contains_token(body: str, token: str) -> bool:
|
|
33
|
+
return token.lower() in body.lower()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _detect_bot_mention(body: str) -> str | None:
|
|
37
|
+
"""Return corrective message if body contains a blocked mention, else None."""
|
|
38
|
+
if _body_contains_token(body, COPILOT_MENTION_TOKEN):
|
|
39
|
+
return CORRECTIVE_MESSAGE_COPILOT
|
|
40
|
+
if _body_contains_token(body, CURSOR_MENTION_TOKEN):
|
|
41
|
+
return CORRECTIVE_MESSAGE_CURSOR
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main() -> None:
|
|
46
|
+
try:
|
|
47
|
+
hook_input = json.load(sys.stdin)
|
|
48
|
+
except json.JSONDecodeError:
|
|
49
|
+
sys.exit(0)
|
|
50
|
+
|
|
51
|
+
if hook_input.get("tool_name", "") != TOOL_NAME:
|
|
52
|
+
sys.exit(0)
|
|
53
|
+
|
|
54
|
+
body = hook_input.get("tool_input", {}).get("body", "")
|
|
55
|
+
if not body:
|
|
56
|
+
sys.exit(0)
|
|
57
|
+
|
|
58
|
+
corrective_message = _detect_bot_mention(body)
|
|
59
|
+
if corrective_message is None:
|
|
60
|
+
sys.exit(0)
|
|
61
|
+
|
|
62
|
+
deny_payload = {
|
|
63
|
+
"hookSpecificOutput": {
|
|
64
|
+
"hookEventName": "PreToolUse",
|
|
65
|
+
"permissionDecision": "deny",
|
|
66
|
+
"permissionDecisionReason": corrective_message,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
print(json.dumps(deny_payload))
|
|
70
|
+
sys.stdout.flush()
|
|
71
|
+
sys.exit(0)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
main()
|