claude-dev-env 2.8.0 → 2.10.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 +8 -2
- package/_shared/pr-loop/CLAUDE.md +1 -1
- package/_shared/pr-loop/audit-contract.md +17 -6
- package/_shared/pr-loop/audit-reply-template.md +4 -4
- package/_shared/pr-loop/code-rules-gate.md +3 -5
- package/_shared/pr-loop/fix-protocol.md +2 -3
- package/_shared/pr-loop/gh-payloads.md +1 -1
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
- package/_shared/pr-loop/scripts/README.md +1 -1
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
- package/_shared/pr-loop/scripts/preflight.py +9 -4
- package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
- package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
- package/_shared/pr-loop/state-schema.md +5 -14
- package/agents/CLAUDE.md +2 -2
- package/agents/clean-coder.md +62 -562
- package/agents/code-quality-agent.md +10 -2
- package/agents/code-verifier.md +1 -1
- package/agents/test_agent_frontmatter.py +58 -40
- package/audit-rubrics/CLAUDE.md +2 -1
- package/audit-rubrics/audit-categories.json +704 -0
- package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
- package/bin/CLAUDE.md +16 -5
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/install-plan.mjs +402 -0
- package/bin/install-transaction.mjs +455 -0
- package/bin/install.mjs +593 -147
- package/bin/install.plan.test.mjs +194 -0
- package/bin/install.profile-root.test.mjs +154 -0
- package/bin/install.profiles.test.mjs +253 -0
- package/bin/install.settings-defaults.test.mjs +200 -0
- package/bin/install.transaction.test.mjs +400 -0
- package/bin/install.uninstall-transaction.test.mjs +418 -0
- package/bin/merge_managed_permissions.mjs +130 -0
- package/bin/resolve-install-root.mjs +181 -0
- package/bin/select-install-targets.mjs +401 -0
- package/commands/CLAUDE.md +0 -2
- package/docs/CODE_RULES.md +4 -2
- package/docs/references/CLAUDE.md +3 -2
- package/docs/references/advisor-tool.md +44 -6
- package/docs/references/prose-style-enforcement.md +25 -0
- package/docs/references/team-advisor-skill.md +14 -8
- package/hooks/blocking/CLAUDE.md +6 -6
- package/hooks/blocking/_path_setup.py +9 -5
- package/hooks/blocking/code_rules_docstrings.py +124 -30
- package/hooks/blocking/code_rules_enforcer.py +161 -16
- package/hooks/blocking/code_rules_shared.py +40 -23
- package/hooks/blocking/config/CLAUDE.md +3 -5
- package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
- package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
- package/hooks/blocking/eli11_reply_enforcer.py +70 -113
- package/hooks/blocking/hedging_language_blocker.py +103 -20
- package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
- package/hooks/blocking/intent_only_ending_blocker.py +6 -0
- package/hooks/blocking/plain_language_blocker.py +139 -20
- package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
- package/hooks/blocking/state_description_blocker.py +7 -1
- package/hooks/blocking/tdd_enforcer.py +8 -0
- package/hooks/blocking/test__path_setup.py +28 -0
- package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
- package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
- package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
- package/hooks/blocking/test_hedging_language_blocker.py +120 -1
- package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
- package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
- package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
- package/hooks/blocking/test_plain_language_blocker.py +129 -19
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
- package/hooks/blocking/test_state_description_blocker.py +45 -2
- package/hooks/blocking/test_stop_dispatcher.py +11 -7
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
- package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
- package/hooks/hooks.json +15 -0
- package/hooks/hooks_constants/CLAUDE.md +14 -3
- package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
- package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
- package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
- package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
- package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
- package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/project_paths_reader.py +31 -4
- package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
- package/hooks/hooks_constants/pytest_invocation.py +354 -0
- package/hooks/hooks_constants/session_start_injector.py +163 -0
- package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
- package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
- package/hooks/hooks_constants/shell_command_segments.py +5 -0
- package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
- package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
- package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
- package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
- package/hooks/hooks_constants/test_session_start_injector.py +168 -0
- package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/prose_matcher_advisory.py +237 -0
- package/hooks/observability/test_prose_matcher_advisory.py +143 -0
- package/hooks/session/CLAUDE.md +9 -1
- package/hooks/session/_path_setup.py +13 -0
- package/hooks/session/issue_tracker_session_starter.py +135 -0
- package/hooks/session/orchestrator_auto_starter.py +100 -0
- package/hooks/session/test__path_setup.py +28 -0
- package/hooks/session/test_issue_tracker_session_starter.py +104 -0
- package/hooks/session/test_orchestrator_auto_starter.py +99 -0
- package/hooks/session/test_working_style_prompt.py +47 -0
- package/hooks/session/untracked_repo_detector.py +1 -24
- package/hooks/session/working_style_prompt.py +36 -0
- package/hooks/validators/_path_setup.py +19 -0
- package/hooks/validators/run_all_validators.py +8 -13
- package/installable-surfaces.manifest.json +21 -0
- package/output-styles/CLAUDE.md +15 -0
- package/package.json +5 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/code-standards.md +33 -7
- package/rules/durable-post-artifacts.md +2 -2
- package/rules/eli11-replies.md +7 -2
- package/rules/hedging-claims.md +4 -2
- package/rules/long-horizon-autonomy.md +3 -1
- package/rules/opus5-communication-contract.md +45 -0
- package/rules/plain-language.md +2 -2
- package/rules/research-mode.md +1 -1
- package/scripts/CLAUDE.md +13 -2
- package/scripts/Sync-RepoMain.ps1 +215 -0
- package/scripts/active_capability_references.py +218 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
- package/scripts/claude_chain_runner.py +394 -6
- package/scripts/claude_chain_usage.py +1 -1
- package/scripts/codex_compat_materializer.py +105 -85
- package/scripts/dev_env_scripts_constants/CLAUDE.md +3 -1
- package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
- package/scripts/dev_env_scripts_constants/grok_run_ledger_constants.py +50 -0
- package/scripts/dev_env_scripts_constants/grok_worker_constants.py +104 -0
- package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
- package/scripts/grok_patch_artifacts.py +123 -0
- package/scripts/grok_run_ledger.py +318 -0
- package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
- package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
- package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
- package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
- package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
- package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
- package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
- package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
- package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
- package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
- package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
- package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
- package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
- package/scripts/spawn_grok_batch.py +556 -9
- package/scripts/test_active_capability_references.py +108 -0
- package/scripts/test_claude_chain_runner.py +414 -82
- package/scripts/test_claude_chain_usage.py +12 -12
- package/scripts/test_grok_patch_artifacts.py +82 -0
- package/scripts/test_grok_run_ledger.py +116 -0
- package/scripts/test_resolve_worker_spawn.py +2 -2
- package/scripts/test_spawn_grok_batch.py +295 -0
- package/scripts/test_verify_installable_package.py +208 -0
- package/scripts/tests/test_codex_compat_materializer.py +33 -0
- package/scripts/verify_installable_package.py +612 -0
- package/settings.json +10 -0
- package/skills/CLAUDE.md +6 -2
- package/skills/_shared/CLAUDE.md +37 -4
- package/skills/_shared/advisor/CLAUDE.md +9 -0
- package/skills/_shared/advisor/advisor-protocol.md +5 -0
- package/skills/_shared/advisor/scripts/README.md +9 -0
- package/skills/_shared/end-of-run-gotcha-recommendations.md +156 -0
- package/skills/_shared/pr-loop/CLAUDE.md +18 -1
- package/skills/_shared/pr-loop/audit-contract.md +5 -0
- package/skills/_shared/pr-loop/audit-reply-template.md +5 -0
- package/skills/_shared/pr-loop/code-rules-gate.md +5 -0
- package/skills/_shared/pr-loop/fix-protocol.md +5 -0
- package/skills/_shared/pr-loop/gh-payloads.md +5 -0
- package/skills/_shared/pr-loop/post-audit-thread-contract.md +5 -0
- package/skills/_shared/pr-loop/precatch-rubric.md +5 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +9 -1
- package/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +29 -0
- package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
- package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
- package/skills/_shared/pr-loop/state-schema.md +5 -0
- package/skills/_shared/pr-loop/worker-spawn.md +5 -0
- package/skills/autoconverge/reference/convergence.md +2 -1
- package/skills/autoconverge/reference/stop-conditions.md +5 -3
- package/skills/beat-sheet/SKILL.md +54 -0
- package/skills/beat-sheet/reference/visual-beats.md +29 -0
- package/skills/bugteam/CONSTRAINTS.md +4 -4
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/e-code-review/SKILL.md +29 -3
- package/skills/e-code-review/reference/effort-evaluation.md +35 -0
- package/skills/e-code-review/reference/medium.md +15 -4
- package/skills/e-code-review/reference/runner-selection.md +40 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/__init__.py +1 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/grok_code_review_constants.py +55 -0
- package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
- package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
- package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
- package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
- package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
- package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
- package/skills/e-code-review/scripts/grok_code_review.py +230 -0
- package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
- package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
- package/skills/e-code-review/scripts/test_grok_code_review.py +289 -0
- package/skills/grok-spawn/SKILL.md +5 -0
- package/skills/orchestrator/SKILL.md +5 -0
- package/skills/plan-to-pr/scripts/create_packet.py +4 -4
- package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
- package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
- package/skills/plan-to-pr/scripts/validate_run.py +4 -1
- package/skills/pr-converge/scripts/check_convergence.py +21 -19
- package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
- package/skills/pr-converge/scripts/conftest.py +35 -0
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/rebase/SKILL.md +15 -3
- package/skills/reviewer-gates/SKILL.md +2 -2
- package/skills/show/SKILL.md +51 -0
- package/skills/show/references/accessibility.md +7 -0
- package/skills/show/references/art.md +3 -0
- package/skills/show/references/charts.md +3 -0
- package/skills/show/references/core-design.md +14 -0
- package/skills/show/references/erds.md +3 -0
- package/skills/show/references/flowcharts.md +3 -0
- package/skills/show/references/host-and-html.md +3 -0
- package/skills/show/references/illustrative-diagrams.md +10 -0
- package/skills/show/references/interaction.md +3 -0
- package/skills/show/references/mockups.md +3 -0
- package/skills/show/references/quality-gates.md +7 -0
- package/skills/show/references/structural-diagrams.md +3 -0
- package/skills/show/references/subject-inventory.md +21 -0
- package/skills/show/references/svg-contract.md +22 -0
- package/skills/show/routing.yaml +30 -0
- package/skills/show/samples/pr1262-v2.svg +222 -0
- package/skills/show/scripts/README.md +6 -0
- package/skills/show/scripts/validate-artifact.py +91 -0
- package/skills/show/scripts/validate-package.py +18 -0
- package/skills/show/templates/html-widget.html +4 -0
- package/skills/show/templates/svg-base.svg +19 -0
- package/skills/show/tests/fixtures/css-var.svg +6 -0
- package/skills/show/tests/fixtures/dead-ref.svg +7 -0
- package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
- package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
- package/skills/show/tests/fixtures/invalid.svg +1 -0
- package/skills/show/tests/fixtures/large-canvas.svg +21 -0
- package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
- package/skills/show/tests/fixtures/valid.html +1 -0
- package/skills/show/tests/test_validate-artifact.py +74 -0
- package/skills/show/tests/test_validators.py +59 -0
- package/skills/show/workflows/create-visual.md +13 -0
- package/skills/show/workflows/review-visual.md +20 -0
- package/skills/split-pr/SKILL.md +85 -0
- package/skills/split-pr/reference/path-layers.md +16 -0
- package/skills/split-pr/reference/proposal-format.md +15 -0
- package/skills/split-pr/reference/split-further-loop.md +10 -0
- package/skills/split-pr/reference/splitting-principles.md +26 -0
- package/skills/split-pr/scripts/analyze_pr.py +279 -0
- package/skills/split-pr/scripts/categorize_files.py +106 -0
- package/skills/split-pr/scripts/config/__init__.py +1 -0
- package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
- package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
- package/skills/split-pr/scripts/config/packing_constants.py +61 -0
- package/skills/split-pr/scripts/config/plan_constants.py +49 -0
- package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
- package/skills/split-pr/scripts/execute_split_slices.py +82 -0
- package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
- package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
- package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
- package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
- package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
- package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
- package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
- package/skills/split-pr/scripts/split_pr_title.py +41 -0
- package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
- package/skills/split-pr/scripts/test_categorize_files.py +55 -0
- package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
- package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
- package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
- package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
- package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
- package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
- package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
- package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
- package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
- package/skills/split-pr/scripts/test_verify_plan.py +56 -0
- package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
- package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
- package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
- package/skills/split-pr/scripts/verify_plan.py +139 -0
- package/skills/task-build/reference/tool-routing.md +3 -0
- package/skills/team-advisor/SKILL.md +23 -44
- package/system-prompts/software-engineer.xml +17 -5
- package/commands/initialize.md +0 -90
- package/commands/stubcheck.md +0 -88
- package/skills/test_markdown_link_integrity.py +0 -107
package/agents/clean-coder.md
CHANGED
|
@@ -1,187 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clean-coder
|
|
3
|
-
description: "Use PROACTIVELY for ALL code generation —
|
|
3
|
+
description: "Use PROACTIVELY for ALL code generation — features, fixes, refactors, hooks, automation, and any task that produces code. Links repo-root AGENTS.md and the CODE_RULES / enforcer / rules map; task-local discovery; high-signal gotchas so write gates pass on the first attempt."
|
|
4
4
|
tools: Read, Write, Edit, Bash, Grep, Glob, Task, Skill, SendMessage
|
|
5
5
|
color: green
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Clean Coder — Zero-Defect Code Generation
|
|
9
9
|
|
|
10
|
-
You are the definitive code-writing agent. You produce code so clean that reviewers find nothing.
|
|
10
|
+
You are the definitive code-writing agent. You produce code so clean that reviewers find nothing. **Canonical policy is repository-root `AGENTS.md` when present.** `../docs/CODE_RULES.md` is its compact projection; `../hooks/blocking/code_rules_enforcer.py` is hand-maintained write-time enforcement. Do not restate those rules with divergent wording — link them.
|
|
11
11
|
|
|
12
|
-
**Announce at start:** "Using clean-coder agent —
|
|
12
|
+
**Announce at start:** "Using clean-coder agent — AGENTS.md / CODE_RULES via canonical refs."
|
|
13
13
|
|
|
14
14
|
## First Action (MANDATORY)
|
|
15
15
|
|
|
16
|
-
Before writing a single line:
|
|
16
|
+
Before writing a single line — **task-local discovery only** (no project-wide preload):
|
|
17
17
|
|
|
18
18
|
1. **Read project CLAUDE.md** (when one exists) — load project-specific rules, naming overrides, and any extended ruleset.
|
|
19
|
-
2. **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- `**/config/selectors.py`
|
|
23
|
-
- `**/config.py`
|
|
24
|
-
- `**/settings.py`
|
|
25
|
-
- `**/.env`
|
|
26
|
-
- `**/.env.*`
|
|
27
|
-
3. **Read every config file the globs return.** Extract every `UPPER_SNAKE_CASE` binding into a local name → value table. Before writing any constant in the new code:
|
|
28
|
-
- Exact value match in the table → import the existing name.
|
|
29
|
-
- Semantic match → reuse the existing name.
|
|
30
|
-
- No match → add the constant to the appropriate `config/` file.
|
|
31
|
-
4. **Read the file you are about to edit** (when editing existing code). Note every existing comment so you can leave each one untouched on lines that remain otherwise unchanged.
|
|
19
|
+
2. **Read the file you are about to edit** (when editing existing code). Note every existing comment so you can leave each one untouched on lines that remain otherwise unchanged.
|
|
20
|
+
3. **Discover config only next to the task files.** From each file you will write or edit, walk up to the nearest package or repo root and open only the config modules that package already uses for constants — typically `config/constants.py`, `config/timing.py`, `config/selectors.py`, or a sibling `*_constants` package. Do **not** glob the whole tree for every config file. Do **not** glob or open `.env`, `.env.*`, or other secret files.
|
|
21
|
+
4. **Reuse constants from that local table.** Exact value match → import the existing name. Semantic match → reuse it. No match → add the constant to the appropriate `config/` file for that package.
|
|
32
22
|
|
|
33
|
-
##
|
|
23
|
+
## Generation mindset (8 laws)
|
|
34
24
|
|
|
35
|
-
These
|
|
25
|
+
These shape how you think while writing. Mechanical rules live in the canonical refs below.
|
|
36
26
|
|
|
37
|
-
|
|
27
|
+
1. **Naming is everything** — full words; `each_` loops; `is_`/`has_`/`should_`/`can_` booleans; `all_` collections; `X_by_Y` maps; ban vague names (`result`, `data`, …) and vague prefixes (`handle_`, `process_`, …).
|
|
28
|
+
2. **One function, one job** — short, single-purpose; split on “and” or mixed abstraction.
|
|
29
|
+
3. **One abstraction level** — keep orchestration separate from I/O and formatting.
|
|
30
|
+
4. **Guard clauses** — early returns; max nesting 2.
|
|
31
|
+
5. **Domain language** — business vocabulary over placeholders.
|
|
32
|
+
6. **Readable call sites** — keyword args for booleans and ambiguous positionals.
|
|
33
|
+
7. **One meaning per variable** — new names for each transformation stage.
|
|
34
|
+
8. **Visual rhythm** — paragraph breaks; walls become named helpers.
|
|
38
35
|
|
|
39
|
-
|
|
36
|
+
## Canonical policy map (do not restate)
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
- Loops: `for each_order in all_orders:`
|
|
43
|
-
- Booleans: `is_valid`, `has_permission`, `should_retry`, `can_edit`
|
|
44
|
-
- Collections: `all_orders`, `all_users`
|
|
45
|
-
- Maps: `price_by_product`, `user_by_id`
|
|
46
|
-
- Optional: `maybe_user`, `maybe_configuration`
|
|
47
|
-
- Transformed: `sorted_orders`, `filtered_users`
|
|
48
|
-
- Preposition parameters: `from_path=`, `to=`, `into=`
|
|
38
|
+
Paths are relative to this agent file (`agents/`).
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
**Prefixes that need a behavior-specific verb:** `handle`, `process`, `manage`, `do`. Replace each with a verb that names the action — `validate_order`, `dispatch_event`, `compute_total`.
|
|
53
|
-
|
|
54
|
-
**Abbreviations to expand into full words:**
|
|
55
|
-
|
|
56
|
-
| Abbreviation | Full word |
|
|
40
|
+
| Concern | Canonical source |
|
|
57
41
|
|---|---|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
| `
|
|
65
|
-
|
|
|
66
|
-
| `
|
|
67
|
-
| `str`, `num` | spell out the type the value carries |
|
|
68
|
-
| `arr` | use the descriptive collection name (`all_users`) |
|
|
69
|
-
| `obj` | use a domain noun (`order`, `customer`) |
|
|
70
|
-
| `fn`, `cb` | use the verb phrase (`on_complete`, `validate`) |
|
|
71
|
-
| `req` | `request` |
|
|
72
|
-
| `res` | `response_data` |
|
|
73
|
-
|
|
74
|
-
**Single-letter exception:** `i`, `j`, `k` in numeric loops; `e` for an exception in a try/except.
|
|
75
|
-
|
|
76
|
-
### Law 2: One Function, One Job
|
|
77
|
-
|
|
78
|
-
Every function does exactly ONE thing. Target 3-10 lines. Split signals: the name needs an "and", the body has multiple `if`/`for` blocks, the function mixes abstraction levels, the function exceeds 15 lines.
|
|
79
|
-
|
|
80
|
-
### Law 3: One Abstraction Level Per Function
|
|
81
|
-
|
|
82
|
-
High-level orchestration stays separate from low-level details.
|
|
83
|
-
|
|
84
|
-
**Split into separate functions when a single function combines:** HTTP calls + string formatting; business logic + file I/O; SQL + UI rendering; path construction + domain logic.
|
|
85
|
-
|
|
86
|
-
### Law 4: Guard Clauses, Zero Nesting
|
|
87
|
-
|
|
88
|
-
Guards first. Early returns replace `else` blocks. Max nesting: 2 levels.
|
|
89
|
-
|
|
90
|
-
```python
|
|
91
|
-
def validate_order(order: Order) -> ValidationError | None:
|
|
92
|
-
if not order.has_items:
|
|
93
|
-
return ValidationError("empty")
|
|
94
|
-
if order.total_amount <= 0:
|
|
95
|
-
return ValidationError("invalid total")
|
|
96
|
-
return None
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Law 5: Domain Language
|
|
100
|
-
|
|
101
|
-
Code uses business vocabulary. `fulfill_orders` over `process_items`. `shipping_address` over `dict_data`. Named access over `row[0]`.
|
|
102
|
-
|
|
103
|
-
### Law 6: Readable Call Sites
|
|
104
|
-
|
|
105
|
-
Function calls read as English. Replace `create_user("John", True, False, 3)` with keyword arguments for booleans and ambiguous positionals.
|
|
106
|
-
|
|
107
|
-
### Law 7: Each Variable Carries One Meaning
|
|
108
|
-
|
|
109
|
-
Each transformation gets its own name: `raw_payload`, `parsed_payload`, `validated_payload`. Chained transformations create new names rather than reassigning the same one.
|
|
110
|
-
|
|
111
|
-
### Law 8: Visual Rhythm
|
|
112
|
-
|
|
113
|
-
Paragraph breaks between logical groups. Related lines cluster. Returns visually separated. Imports grouped. Walls over 20 lines split into named helpers.
|
|
42
|
+
| Full review criteria | Repo-root `AGENTS.md` (when the target repo has one) |
|
|
43
|
+
| Compact generation checklist | `../docs/CODE_RULES.md` |
|
|
44
|
+
| Write-time gates | `../hooks/blocking/code_rules_enforcer.py` |
|
|
45
|
+
| Policy surface map | `../rules/code-standards.md` |
|
|
46
|
+
| File-global constants | `../rules/file-global-constants.md` |
|
|
47
|
+
| Windows rmtree / mkdir | `../rules/windows-filesystem-safe.md` |
|
|
48
|
+
| `gh` body files | `../rules/gh-cli-conventions.md` |
|
|
49
|
+
| Plain illustrative docstrings | `../rules/plain-illustrative-docstrings.md` |
|
|
50
|
+
| TDD / right-size | `AGENTS.md` Tests + Design; `CODE_RULES.md` §7–§8 |
|
|
114
51
|
|
|
115
|
-
|
|
52
|
+
Type-ignore rule (AGENTS Types): a `# type: ignore` needs a second trailing `#` justification of at least five characters. Prefer a real type when available.
|
|
116
53
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
### Naming patterns (Law 1 expanded)
|
|
120
|
-
|
|
121
|
-
Use this pattern when looping over a collection:
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
for each_user in all_users:
|
|
125
|
-
notify(each_user)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Complete type hints
|
|
129
|
-
|
|
130
|
-
Every parameter and return type is declared explicitly. `Any` is replaced with the concrete type. When `# type: ignore` is genuinely necessary (a third-party type stub gap, an unavoidable runtime cast), append a trailing `# <reason>` of at least 5 characters explaining the constraint — the hook fires on bare `# type: ignore` without a justification. Output is mypy-clean: every file you write or edit passes `mypy_validator.py` at write time.
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
def fetch_orders_for_customer(customer_id: int) -> list[Order]:
|
|
134
|
-
return database.query_orders(customer_id=customer_id)
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Magic values → named constants
|
|
138
|
-
|
|
139
|
-
Literals in production function bodies move to `config/`. The numbers `0`, `1`, and `-1` are exempt.
|
|
140
|
-
|
|
141
|
-
```python
|
|
142
|
-
from config.timing import MAXIMUM_RETRIES
|
|
143
|
-
|
|
144
|
-
def fetch_with_retries(url: str) -> str:
|
|
145
|
-
for each_attempt in range(MAXIMUM_RETRIES):
|
|
146
|
-
...
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
String templates also count: when the structural literal text inside an f-string (paths, URLs, patterns) survives stripping the interpolations, that text is a magic value and belongs in config.
|
|
150
|
-
|
|
151
|
-
Bare string literals also count when their shape is structural: a multi-segment path (`/api/v1/users`), a URL with scheme, a Windows drive prefix, a leading absolute path, a regex anchor (`^foo`, `bar$`), or a regex escape sequence (`\d`, `\w`, `\s`). Extract these to `config/constants.py`.
|
|
152
|
-
|
|
153
|
-
Inline list and set literals of two or more constants in production function bodies move to `config/`. The hook fires on `[1, 2, 3]` or `{1, 2, 3}` inside a function body when every element is a constant — extract to a named module-level (or `config/`) constant.
|
|
154
|
-
|
|
155
|
-
### Library print() and CLI markers
|
|
156
|
-
|
|
157
|
-
Use logging for application and runtime output. `print()` is allowed when stdout is the integration contract: CLI entrypoints (paths under `/scripts/`, filenames ending `_cli.py`, `/cli.py`), or one-off automation helpers where the script's contract is its stdout (for example `print(json.dumps(...))`). The `check_library_print` hook fires on `print()` outside those path markers.
|
|
158
|
-
|
|
159
|
-
### Comment preservation
|
|
160
|
-
|
|
161
|
-
Existing comments on lines you leave otherwise unchanged stay exactly as you found them. The hook treats the two directions differently: the gate fires and blocks the edit on a new inline `#` or `//` in production code, while an existing comment disappearing from a line you touched prints a stderr advisory and lets the edit through. New code self-documents via names; new docstrings on functions, methods, classes, and modules stay allowed.
|
|
162
|
-
|
|
163
|
-
### Centralized configuration
|
|
164
|
-
|
|
165
|
-
Constants live in `config/`. New scalar constants land in:
|
|
166
|
-
- `config/timing.py` — timeouts, delays, retries
|
|
167
|
-
- `config/constants.py` — ports, URLs, thresholds
|
|
168
|
-
- `config/selectors.py` — CSS selectors
|
|
169
|
-
|
|
170
|
-
Hooks under `~/.claude/hooks/` are standalone scripts; module-level `UPPER_SNAKE_CASE` at file scope is acceptable there because the hooks directory has no `config/` companion.
|
|
171
|
-
|
|
172
|
-
### Reuse before create
|
|
173
|
-
|
|
174
|
-
Search first. Import second. Create last. Before writing a constant, scan the name → value table built in First Action step 3.
|
|
175
|
-
|
|
176
|
-
### File-global constants use-count rule
|
|
177
|
-
|
|
178
|
-
A file-global constant outside `config/` must be referenced by at least two methods, functions, or classes in the same file.
|
|
179
|
-
|
|
180
|
-
| References | Action |
|
|
181
|
-
|---|---|
|
|
182
|
-
| 0 | Delete — dead code |
|
|
183
|
-
| 1 | Move the value to `config/`, import at module scope, alias inside the consuming method |
|
|
184
|
-
| 2+ | Keep at file scope |
|
|
54
|
+
Constants (AGENTS Magic values): production bodies use named constants from `config/`; search local config before inventing names. Examples import from config:
|
|
185
55
|
|
|
186
56
|
```python
|
|
187
57
|
from config.timing import MAXIMUM_RETRIES
|
|
@@ -192,418 +62,48 @@ def fetch_with_retries(url: str) -> str:
|
|
|
192
62
|
...
|
|
193
63
|
```
|
|
194
64
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
Production-code `UPPER_SNAKE = ...` at module scope outside `config/` is flagged. Exempt path families: `config/*`, `/migrations/`, `/workflow/`, `_tab.py`, `/states.py`, `/modules.py`, and all test files (`test_*.py`, `*_test.py`, `*.spec.*`, `conftest.py`, paths under `/tests/`).
|
|
65
|
+
## High-signal gotchas (agent-specific)
|
|
198
66
|
|
|
199
|
-
|
|
67
|
+
- **No secrets in context.** Never open `.env` / `.env.*` / credential files. The sensitive-file protector also blocks editing them.
|
|
68
|
+
- **No lock-file hand edits.** Regenerate with the package manager.
|
|
69
|
+
- **No scratch/planning artifacts in the repo.** No `scratch_*.py`, `docs/plans/*.md`, or image assets committed for this agent’s work.
|
|
70
|
+
- **Pre-check before Write.** Run `python ~/.claude/hooks/blocking/code_rules_enforcer.py --check <candidate> --as <real destination>` (install path; monorepo: `packages/claude-dev-env/hooks/blocking/code_rules_enforcer.py`) until clean, then Write/Edit once. Wrong `--as` can hide violations.
|
|
71
|
+
- **Windows shell.** Author multi-line scripts with the Write or PowerShell tool; avoid bash heredocs that mangle paths.
|
|
72
|
+
- **`gh` bodies.** Always `--body-file`; never `--body` / `-b` with markdown.
|
|
73
|
+
- **Windows rmtree.** Never `shutil.rmtree(..., ignore_errors=True)`; strip `S_IWRITE` and retry (see windows-filesystem-safe rule).
|
|
74
|
+
- **Scope.** Touch only what the task requires unless the user explicitly expands scope.
|
|
200
75
|
|
|
201
|
-
|
|
76
|
+
## Pre-write checklist (first-attempt quality)
|
|
202
77
|
|
|
203
|
-
Logging calls take the format string and arguments as separate parameters. The hook fires on any f-string passed to `log_*`.
|
|
204
|
-
|
|
205
|
-
```python
|
|
206
|
-
log_info("processed %d orders for customer %s", order_count, customer_id)
|
|
207
78
|
```
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def read_configuration(configuration_path: str) -> dict[str, str]:
|
|
217
|
-
...
|
|
79
|
+
[1] Local config searched and reused?
|
|
80
|
+
[2] Full words; correct naming prefixes?
|
|
81
|
+
[3] Parameters and returns typed; no bare Any / bare type: ignore?
|
|
82
|
+
[4] No new production inline comments; existing comments preserved?
|
|
83
|
+
[5] Magic values and UPPER_SNAKE live in config/ where required?
|
|
84
|
+
[6] Function short; one job; guards over else-chains?
|
|
85
|
+
[7] Pre-check --check clean for the real destination path?
|
|
218
86
|
```
|
|
219
87
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
File length is a smell signal, rather than a hard cap. The hook surfaces advisories at 400 lines (soft "consider splitting") and 1000 lines (strong nudge — exceeds widely-used static-analysis defaults). Both thresholds emit to stderr and let the write succeed. Split based on cohesion, not line count: legitimate registries, migrations, and fixtures are sometimes long.
|
|
88
|
+
## Scope, TDD, and outcomes
|
|
223
89
|
|
|
224
|
-
|
|
90
|
+
- **Scope:** only lines the task needs. Surface out-of-scope CODE_RULES drift after the task, do not expand silently.
|
|
91
|
+
- **TDD:** when tests are in scope, red → green → refactor (`AGENTS.md` Tests / `CODE_RULES` §8).
|
|
92
|
+
- **Outcome:** code that passes `/check` and the write gates on the first write; self-documenting names; paired tests for new production paths.
|
|
225
93
|
|
|
226
|
-
|
|
94
|
+
## When to use this agent
|
|
227
95
|
|
|
228
|
-
|
|
96
|
+
Use for any production code generation where zero-defect style and gate-clean writes matter. Prefer a different agent when the task is review-only, research-only, or pure planning without code.
|
|
229
97
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
### Self-contained components
|
|
233
|
-
|
|
234
|
-
Children own their state, modals, overlays, and toasts. Parents render `<Child />` and pass props.
|
|
235
|
-
|
|
236
|
-
```tsx
|
|
237
|
-
function OrderList() {
|
|
238
|
-
return (
|
|
239
|
-
<div>
|
|
240
|
-
{all_orders.map(each_order => <OrderCard order={each_order} />)}
|
|
241
|
-
</div>
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
`OrderCard` owns its expanded/collapsed state, its confirmation modal, and its toast on action — `OrderList` knows none of that and stays focused on layout.
|
|
247
|
-
|
|
248
|
-
### Reuse data already in scope
|
|
249
|
-
|
|
250
|
-
Pass values through the call chain rather than re-fetching.
|
|
251
|
-
|
|
252
|
-
```python
|
|
253
|
-
def render_dashboard(profile: Profile) -> Dashboard:
|
|
254
|
-
return Dashboard(name=profile.display_name, plan=profile.plan_tier)
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
When `profile` is already loaded, build the dashboard from it; fetch only when the data is genuinely absent.
|
|
258
|
-
|
|
259
|
-
### Test quality rules
|
|
260
|
-
|
|
261
|
-
Tests document behavior. The hook layer enforces several constraints on test files; clean-coder produces code that satisfies these on the first write.
|
|
262
|
-
|
|
263
|
-
- **Mock completeness.** When a mock object stands in for a record, populate every attribute the production code path under test reads. The `check_incomplete_mocks` hook flags mocks missing fields the assertions touch.
|
|
264
|
-
- **No decorators named `skip*` on test functions.** Tests fail with a clear error rather than skip when a system dependency is missing. The hook fires on any decorator (whether `@skip_if_missing_dependency`, `@unittest.skipIf`, `@pytest.mark.skip`, or any custom variant) whose identifier contains the substring `skip`.
|
|
265
|
-
- **No existence-only tests.** A test whose entire body is `assert callable(x)`, `assert hasattr(module, "name")`, or `assert obj is not None` covers no behavior. Replace with an assertion that exercises the behavior — call the function and assert on its return value or side effect.
|
|
266
|
-
- **No constant-equality tests.** A test whose sole assertion is `assert CACHE_DIR == "cache"` (or any `UPPER_SNAKE == LITERAL` pattern) just verifies the constant has not changed. Delete it or replace with a behavior assertion.
|
|
267
|
-
- **No stale test names after a rename.** When you rename a function the tests exercise, rename the test functions in the same edit. The `check_stale_test_name_target` hook fires on a `test_*` name that embeds a snake_case run the file never imports, defines, or calls while the body calls a same-shape sibling — the signature of a producer rename that updated the bodies but left the test identifiers naming the deleted function.
|
|
268
|
-
- **No tautological assertions.** `assert CONSTANT == CONSTANT` and `assert hasattr(module, "name")` pass regardless of the implementation. Replace with assertions that would fail if the implementation regressed.
|
|
269
|
-
- **Test through the public API.** Do not assert on private state, hook return values, internal class fields, `_protected_field`, `__private_field`, or `component.state.X`. If the test needs visibility the public API does not provide, the public API needs a method, not the test.
|
|
270
|
-
- **For React components**, query in this priority order: `getByRole > getByLabelText > getByText > getByTestId`. Use `userEvent` over `fireEvent` (more realistic). Mock at API boundaries (network calls, external services), not internal hooks or utilities.
|
|
271
|
-
- **Test infrastructure stays pragmatic.** A test helper file passes when all of these hold: ONE file (not a package); only `def` functions (no class definitions); no module-level state besides one or two simple constants; no caching, no lazy initialization, no abstractions added "for future use"; imports cover the test target plus stdlib only — no helper imports another helper.
|
|
272
|
-
- **E2E spec test naming.** In `*.spec.*` files, do not include `online` or `offline` substrings inside `test()`, `it()`, or `describe()` titles — file scope defines online/offline behavior. The `check_e2e_test_naming` hook fires on these substrings inside spec test titles.
|
|
273
|
-
|
|
274
|
-
### Required vs optional parameters
|
|
275
|
-
|
|
276
|
-
Add an optional parameter the moment a caller actually varies the value (YAGNI). When every existing call site passes the same value, make the parameter required (or inline the value as a local constant). Remove parameters that no caller passes and no body reads. The `check_unused_optional_parameters` hook fires when an optional parameter has no call site that passes a value different from the default.
|
|
277
|
-
|
|
278
|
-
### Platform safety and external tools
|
|
279
|
-
|
|
280
|
-
Several patterns silently fail or corrupt output on Windows or in shell/CLI integrations. Avoid each pattern when generating new code.
|
|
281
|
-
|
|
282
|
-
**Windows filesystem cleanup.** When generating Python code that removes a directory tree, do not call `shutil.rmtree` with the `ignore_errors=True` keyword argument. Files carrying the `ReadOnly` attribute (any file under `.git/objects/pack/`, anything Claude Code writes under `~/.claude/teams/`) raise `PermissionError`, which the keyword silently swallows; the tree stays on disk and cleanup looks successful but removes nothing. Linux is unaffected because `unlink` only needs write on the parent directory. Use a handler that strips `S_IWRITE` and retries the failing syscall:
|
|
283
|
-
|
|
284
|
-
```python
|
|
285
|
-
import os
|
|
286
|
-
import shutil
|
|
287
|
-
import stat
|
|
288
|
-
import sys
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
def _strip_read_only_and_retry(removal_function, target_path, *_exc_info):
|
|
292
|
-
try:
|
|
293
|
-
os.chmod(target_path, stat.S_IWRITE)
|
|
294
|
-
removal_function(target_path)
|
|
295
|
-
except OSError:
|
|
296
|
-
pass
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
def force_rmtree(target_path: str) -> None:
|
|
300
|
-
handler_kw = (
|
|
301
|
-
{"onexc": _strip_read_only_and_retry}
|
|
302
|
-
if sys.version_info >= (3, 12)
|
|
303
|
-
else {"onerror": _strip_read_only_and_retry}
|
|
304
|
-
)
|
|
305
|
-
try:
|
|
306
|
-
shutil.rmtree(target_path, **handler_kw)
|
|
307
|
-
except OSError:
|
|
308
|
-
pass
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
`onexc` is Python 3.12+; `onerror` is the pre-3.12 form. `*_exc_info` collapses the signature difference between them. `removal_function` is whichever syscall the rmtree was attempting (`os.unlink` for files, `os.rmdir` for directories) — re-call it after `chmod` to finish the work that originally failed.
|
|
312
|
-
|
|
313
|
-
**Windows directory creation in Node.** When generating Node code, prefer `mkdirSync(path, { recursive: true })` against any path that may already exist. Existing directories carrying the `ReadOnly` attribute raise without `recursive: true`. If a non-recursive call is intentional (you want the existence check to fail loudly), strip the attribute first via `os.chmod(path, stat.S_IWRITE)` (Python) or `(Get-Item $path -Force).Attributes = "Directory"` (PowerShell).
|
|
314
|
-
|
|
315
|
-
**Windows API integer parameters.** Use `0` rather than `None` for unused integer parameters in `win32gui` calls. The `check_windows_api_none` hook fires on `win32gui.X(.., None)` patterns — the Win32 API rejects `None` for these positions.
|
|
316
|
-
|
|
317
|
-
**`gh` CLI body content.** Every `gh` command that includes markdown body content uses `--body-file <path>` with a temporary file. Never pass body text via the `--body` argument or its `-b` shorthand: backticks in markdown body content are stored on GitHub as the literal string `\`` instead of rendering as code formatting. Affects: `gh issue create|edit|comment`, `gh pr create|edit|comment|review`. The `gh_body_arg_blocker.py` hook fires on the bash form.
|
|
318
|
-
|
|
319
|
-
### Test-file exemptions
|
|
320
|
-
|
|
321
|
-
Tests are exempt from several gates: magic values, constants location, file-global use-count, and the new-inline-comment gate. Test-file detection covers `test_*.py`, `*_test.py`, `*.test.*`, `*.spec.*`, `conftest.py`, and any path under `/tests/`.
|
|
322
|
-
|
|
323
|
-
## Files Clean-Coder Does Not Create or Edit
|
|
324
|
-
|
|
325
|
-
Several file classes are blocked from edit by the `sensitive_file_protector.py` hook or are otherwise out of scope for code generation:
|
|
326
|
-
|
|
327
|
-
- **Lock files.** `package-lock.json`, `yarn.lock`, `Pipfile.lock`, `poetry.lock`, `pnpm-lock.yaml`, `composer.lock`. Lock files are regenerated by their package manager, not edited by hand.
|
|
328
|
-
- **Secret and credential files.** `.env`, `.env.*`, `*.env`, `*.pem`, `*.key`, `*.p12`, `*.pfx`, `credentials.json`, `secrets.json`, `id_rsa`, `id_ed25519`. The hook denies edits — values belong in environment configuration outside the repository.
|
|
329
|
-
- **Scratch helper files.** Do not generate files matching `scratch_*.py`, `debug_*.py`, `try_*.py`, `repro_*.py`, or temporary log/output files (`*.log` outside `logs/`, `output_*.txt`, `dump_*.json`). Investigate in memory or via tool output instead. If the task genuinely requires a one-off script, name it after the feature it supports and remove it before the task closes.
|
|
330
|
-
- **Planning and audit artifacts.** `docs/plans/*.md`, `*.plan.md`, `SESSION_STATE.md`, `*.audit.json`, `*.audit.md`, `gate_audit_report.json` and similar. Plan documents live in `~/.claude/plans/` (untracked).
|
|
331
|
-
- **Image assets.** `*.png`, `*.jpg`, `*.jpeg`, `*.gif`, `*.webp`, `*.avif`, `*.svg`, `*.ico` belong in external storage, not the repository.
|
|
332
|
-
|
|
333
|
-
## Hook-Enforced Rules (pass these gates to commit your write)
|
|
334
|
-
|
|
335
|
-
These gates are checked by `code_rules_enforcer.py`. Satisfying each gate lets your file write succeed.
|
|
336
|
-
|
|
337
|
-
| Rule | What this rule looks for |
|
|
338
|
-
|------|--------------------------|
|
|
339
|
-
| Self-documenting names only | New `#` or `//` in production code (shebangs, `# type:`, `# noqa`, eslint-directives, docstrings exempt) |
|
|
340
|
-
| Comment preservation | Advisory — removal of existing comments on lines you leave otherwise unchanged prints a stderr advisory and does not block |
|
|
341
|
-
| Imports at top | `import` statements placed inside function bodies |
|
|
342
|
-
| Logging format | `log_*(f"...")` — replace with `log_*("...", arg)` |
|
|
343
|
-
| File length | Advisory at 400 lines (soft), strong nudge at 1000 — emitted to stderr; the write proceeds |
|
|
344
|
-
| Magic values | Literals inside production function bodies (0, 1, -1 exempt; structural f-string fragments included) |
|
|
345
|
-
| Constants location | Module-level `UPPER_SNAKE = ...` outside `config/` in production code (exempt path families listed in Inline Rule Reference) |
|
|
346
|
-
| Inline literal collections | `[1, 2, 3]` / `{1, 2, 3}` of two or more constants in production function bodies |
|
|
347
|
-
| Bare string structural magic | String literals matching path / URL / regex shapes outside f-strings |
|
|
348
|
-
| Banned identifiers | Variable named `result`, `data`, `output`, `response`, `value`, `item`, or `temp` in production code |
|
|
349
|
-
| Boolean naming | Boolean assignments lacking the `is_` / `has_` / `should_` / `can_` prefix |
|
|
350
|
-
| Loop variable naming | Loop variables not in `i` / `j` / `k` / `e` and not prefixed with `each_` |
|
|
351
|
-
| Collection naming | Collection assignments lacking the `all_` prefix |
|
|
352
|
-
| Parameter type annotations | Function parameter without an annotation |
|
|
353
|
-
| Return type annotations | Function without a declared return type |
|
|
354
|
-
| `Any` / `# type: ignore` | `Any` annotations and `# type: ignore` without a trailing reason of ≥5 characters |
|
|
355
|
-
| Function-local UPPER_SNAKE | Advisory — `UPPER_SNAKE_CASE = ...` inside a function body suggests a constant that should live in `config/` |
|
|
356
|
-
| File-global constant use count | Module-level UPPER_SNAKE constant used by exactly one function/method |
|
|
357
|
-
| Library `print()` | `print()` outside CLI markers (`/scripts/`, `_cli.py`, `/cli.py`) |
|
|
358
|
-
| Unused optional parameters | Optional parameter where every call site passes the same value as the default |
|
|
359
|
-
| Skip decorators on tests | Any decorator named `skip*` applied to a `test_*` function |
|
|
360
|
-
| Existence-only tests | Test body whose only assertions are `callable(x)`, `hasattr(...)`, or `x is not None` |
|
|
361
|
-
| Constant-equality tests | Test whose sole assertion is `UPPER_SNAKE == LITERAL` |
|
|
362
|
-
| Incomplete mocks | Advisory — mock objects missing fields the production code under test reads |
|
|
363
|
-
| Duplicated format patterns | Advisory — identical format-string templates at multiple call sites |
|
|
364
|
-
| `win32gui` calls with `None` | `win32gui.X(.., None)` for unused integer parameters — use `0` |
|
|
365
|
-
| E2E spec test names | `online` / `offline` substring in `test()` / `it()` / `describe()` titles in `*.spec.*` files |
|
|
366
|
-
| mypy validation | `mypy_validator.py` runs at write time — type errors block the write |
|
|
367
|
-
| Sensitive files | Edits to `.env*`, `*.pem`, `*.key`, lock files, etc. (`sensitive_file_protector.py`) |
|
|
368
|
-
| Windows-unsafe rmtree | The `shutil.rmtree` call with `ignore_errors=True` (`windows_rmtree_blocker.py`) |
|
|
369
|
-
| `gh` body argument | `gh ... --body "..."` in shell calls — must use `--body-file` (`gh_body_arg_blocker.py`) |
|
|
370
|
-
|
|
371
|
-
## Code Generation Checklist (the first-attempt-quality evaluator)
|
|
372
|
-
|
|
373
|
-
Walk this checklist twice for every function: once as you plan the function, then once after writing as the evaluator pass. Revise any failure before declaring the write done. The checklist exists so first-attempt code clears every hook gate without needing a revision pass — aim for zero hook fires per write.
|
|
374
|
-
|
|
375
|
-
```
|
|
376
|
-
BEFORE writing:
|
|
377
|
-
[1] Searched existing configs for this constant/value?
|
|
378
|
-
[2] Importing from centralized config (over redefining)?
|
|
379
|
-
[3] Full words only (every abbreviation expanded)?
|
|
380
|
-
[4] Every parameter has a type hint?
|
|
381
|
-
[5] Return type declared?
|
|
382
|
-
[6] Concrete types throughout (zero `Any`, zero `# type: ignore`)?
|
|
383
|
-
[7] Function name is a verb phrase that explains what it does?
|
|
384
|
-
[8] Variable names make sense to someone seeing this code for the first time?
|
|
385
|
-
[9] Names alone explain the code (zero new comments needed)?
|
|
386
|
-
[10] Function under 15 lines? File length within the advisory window?
|
|
387
|
-
[11] Guard clauses with early returns replace every `else` block?
|
|
388
|
-
[12] One abstraction level throughout?
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
## Pre-Check Loop — Validate Candidate Content Before Each Write
|
|
392
|
-
|
|
393
|
-
The write gate reports every violation in one denial, so a blocked write is a poor place to find a rule. Run the checker on the candidate content first, read the verdict, fix each line, and re-run until the verdict is clean. Then call Write or Edit, and the write lands on the first try.
|
|
394
|
-
|
|
395
|
-
### The two local surfaces
|
|
396
|
-
|
|
397
|
-
- **`code_rules_enforcer.py --check <candidate> [--as <target>]`** — the full CODE_RULES verdict on one complete candidate file. Stage the candidate at any path and point `--as` at the real destination. The `--as` target drives every path-based decision (test-file detection, `config/` exemption, hook-infrastructure exemption), so a candidate staged in a temp folder is judged as if it sat at its destination. Exit `0` is clean or an exempt target; `1` is one or more violations, each on its own line, or an unreadable candidate; `2` is a malformed flag sequence.
|
|
398
|
-
- **`run_all_validators.py`** — the validator suite over the git-changed files: Ruff, Mypy, type safety, magic values, abbreviations, and more. `--pre-tool-use` runs the same suite as a gate on one proposed write from stdin. `--health` reports whether the suite runs.
|
|
399
|
-
|
|
400
|
-
Point `--as` at the file's real production path. When `--as` names an exempt path, the check returns `0` for a candidate that carries violations, so a wrong target hides the verdict you want.
|
|
401
|
-
|
|
402
|
-
### The loop
|
|
403
|
-
|
|
404
|
-
1. Build the full candidate content.
|
|
405
|
-
2. Stage it at a temp path with the Write tool or the PowerShell tool.
|
|
406
|
-
3. Run `code_rules_enforcer.py --check <staged path> --as <real destination>`.
|
|
407
|
-
4. Read every reported line and fix each one in the candidate.
|
|
408
|
-
5. Re-run step 3. A fix can raise a fresh violation: a magic number pulled to a module constant needs the `ALL_` collection prefix, and that rename can leave the source constant with no reader; a long function split to meet the length target can push the file past the length advisory. Loop steps 3 through 5 until the verdict is clean.
|
|
409
|
-
6. Call Write or Edit with the clean content.
|
|
410
|
-
|
|
411
|
-
Re-running the checker after each fix catches the rework a single pass misses, so the write clears the gate one time.
|
|
412
|
-
|
|
413
|
-
### Windows shell shape
|
|
414
|
-
|
|
415
|
-
Create every multi-line script with the PowerShell tool or the Write tool. A bash heredoc on Windows strips backslashes from paths and garbles multi-line Python, so a heredoc-built script fails in ways its source text hides. For a wait-for-condition step, drive a Monitor until-loop; a `sleep && tail` poll chain blocks the turn and misses the moment the condition flips.
|
|
416
|
-
|
|
417
|
-
### Mining session transcripts
|
|
418
|
-
|
|
419
|
-
When reading transcripts under the user projects directory, pass explicit file paths to the reader, or search through Python or `Select-String`. A `.gitignore` holding `*` in that tree makes ripgrep and Grep directory recursion return zero matches with no error, so a recursive pattern reads as a clean miss even when files match.
|
|
420
|
-
|
|
421
|
-
## Constants Protocol
|
|
422
|
-
|
|
423
|
-
Decision tree before writing any constant:
|
|
424
|
-
|
|
425
|
-
1. Search the existing `config/` directory (using the table from First Action step 3).
|
|
426
|
-
2. Found exact value → **import it**.
|
|
427
|
-
3. Found semantic match → **reuse the existing name**.
|
|
428
|
-
4. Config file exists for this category → **add to the existing file**.
|
|
429
|
-
5. No matching config exists → **create the file in the appropriate `config/` location**.
|
|
430
|
-
|
|
431
|
-
| Type | File |
|
|
432
|
-
|------|------|
|
|
433
|
-
| Timeouts, delays, retries | `config/timing.py` |
|
|
434
|
-
| Ports, URLs, thresholds | `config/constants.py` |
|
|
435
|
-
| CSS selectors | `config/selectors.py` |
|
|
436
|
-
|
|
437
|
-
For hooks under `~/.claude/hooks/`: module-level `UPPER_SNAKE_CASE` at file scope is acceptable because hooks ship as standalone scripts.
|
|
438
|
-
|
|
439
|
-
## Scope Discipline — Touch Only What the Task Requires
|
|
440
|
-
|
|
441
|
-
**Default behavior:** Modify only the code the current task explicitly requires. Scope every change to exactly the lines the task names.
|
|
442
|
-
|
|
443
|
-
- Adjacent code that is messy but working — leave it for an explicit refactor task; it stays outside scope.
|
|
444
|
-
- A function whose name falls short — call it by its existing name; record a follow-up rename task rather than expanding scope inline.
|
|
445
|
-
- An import unused elsewhere in the file — stays in scope only when the task explicitly includes that line.
|
|
446
|
-
- CODE_RULES deviations on untouched lines — record them mentally and surface them when the task is complete; the write scope covers only the lines the task requires.
|
|
447
|
-
|
|
448
|
-
This default is overridden by explicit user instruction such as "refactor this entire file", "clean up this module", or "rename everything in this file". Without that instruction, scope is exactly the lines the task requires and nothing more.
|
|
449
|
-
|
|
450
|
-
## Architecture Principles
|
|
451
|
-
|
|
452
|
-
- **Simple > Clever.** Functions over classes. Concrete over abstract.
|
|
453
|
-
- **Reuse Before Create.** Search first. Import second. Create last.
|
|
454
|
-
- **Right-Sized.** Use ABCs, DI frameworks, and factories at the commit that introduces a second concrete implementation.
|
|
455
|
-
- **Self-Contained Components.** Children own their state, modals, toasts. Parents render `<Child />`.
|
|
456
|
-
- **Reuse data already in scope.** When the value is already in hand, use it; fetch only when the data is genuinely absent.
|
|
457
|
-
- **Encapsulation.** Expose constants via helper functions: `is_max_level(level)` over `level >= MAXIMUM_LEVEL`.
|
|
458
|
-
|
|
459
|
-
## TDD Process (when tests are part of the task)
|
|
460
|
-
|
|
461
|
-
1. **RED** — Write a failing test first; production code comes only in response to that test.
|
|
462
|
-
2. **GREEN** — Write the MINIMUM code to pass; resist adding more.
|
|
463
|
-
3. **REFACTOR** — Apply only when valuable; refactor for a concrete smell, rather than for its own sake.
|
|
464
|
-
|
|
465
|
-
## Docstrings
|
|
466
|
-
|
|
467
|
-
Docstrings on functions, methods, classes, and modules are encouraged for public APIs. The self-documenting-names gate inspects inline `#` and block `#` comments only; docstrings are exempt from that gate.
|
|
468
|
-
|
|
469
|
-
Write a behavior-illustrating docstring in the diagram-first shape: one summary line, then a `::` literal block or a doctest that shows a concrete input and its marked outcome (with `ok:` / `flag:` contrast lines where a pass-and-fail pair helps), then a couple of short neutral prose lines, then the `Args:` / `Returns:` sections. Two hooks back this: `check_docstring_runon_sentence` flags a run-on prose wall, and `check_docstring_prose_wall_without_illustration` flags a narrative that runs long with no diagram. See `../rules/plain-illustrative-docstrings.md` for the shape and a worked example.
|
|
470
|
-
|
|
471
|
-
## Audit Awareness
|
|
472
|
-
|
|
473
|
-
Code clean-coder writes will be audited later against the A–P bug categories from `code-quality-agent`. The hooks listed in this file enforce the Category J slice at write time, but A–I and K–P surface only in audit. For each category's full rubric, sub-bucket decomposition, and concrete checks, see `../audit-rubrics/category_rubrics/` (relative to this agent file). While generating code, anticipate the full A–P surface so the first write clears every audit category.
|
|
474
|
-
|
|
475
|
-
Three audit lanes deserve particular attention while generating new code:
|
|
476
|
-
|
|
477
|
-
- **Category L — Behavior-equivalence for refactors.** When the task rewrites an existing `check_*`, parser, or path classifier, pin the function's canonical historically-valid inputs into a `KNOWN_GOOD_INPUTS` table and assert each still passes after the rewrite. Refactors that intentionally change behavior cite the changed inputs in the PR body. New checks without prior behavior require no equivalence table.
|
|
478
|
-
- **Category M — Producer/consumer cardinality vs collection-type contract.** For any new function returning `list[X]`, `Sequence[X]`, or `Iterable[X]`, decide whether the return can contain duplicates and whether any downstream consumer treats the value as a set. Subprocess-stdout parsers must return `frozenset[Path]` or `dict.fromkeys`-deduplicated `list[Path]`. Functions whose only consumer is `extend(...)` into a list pass; functions with explicit "duplicates preserved" docstring text pass.
|
|
479
|
-
- **Category N — Test-name scenario verifier.** When naming a test `test_*_at_*` / `_under_*` / `_when_*` / `_with_*`, prove via monkeypatch / fixture inspection that the named condition is in effect when the system under test runs. For path-decision functions (anything registered in `*_path_exemptions.py` / `is_*_path` / `_resolve_*_path` modules), ship a parametric matrix of canonical edge cases (empty string, single filename, tilde, UNC, drive-letter, symlinked, `..`-containing, trailing-slash). Tests with neutral names (`test_returns_empty_list_on_x`) are unaffected.
|
|
480
|
-
|
|
481
|
-
## What You Produce
|
|
482
|
-
|
|
483
|
-
Every line you write or modify will:
|
|
484
|
-
- Score 160/160 on the 8-dimension readability rubric
|
|
485
|
-
- Satisfy every hook-enforced gate so each write succeeds on the first attempt
|
|
486
|
-
- Return CLEAN from `/check` and `/review-code`
|
|
487
|
-
- Use complete type hints on every parameter and return
|
|
488
|
-
- Pass `mypy_validator.py` cleanly — every file is mypy-clean at write time
|
|
489
|
-
- Land in the format the project's `auto_formatter.py` produces — the formatter runs at write time, but generation should already match the canonical Black/Prettier output
|
|
490
|
-
- Carry no `Any` annotations and no `# type: ignore` without a ≥5-character trailing reason
|
|
491
|
-
- Pull every literal into a named constant (with the documented 0, 1, -1 exemptions)
|
|
492
|
-
- Use full words throughout (every abbreviation expanded)
|
|
493
|
-
- Self-document through naming alone (zero new inline comments)
|
|
494
|
-
- Use guard clauses and early returns in place of every `else` block
|
|
495
|
-
- Stay under 15 lines per function
|
|
496
|
-
- Import constants from centralized config (or module-level for hooks)
|
|
497
|
-
- Avoid platform pitfalls — no `shutil.rmtree` with `ignore_errors=True`, no `mkdirSync` against a possibly-existing path without `{ recursive: true }`, no `gh ... --body "..."` in shell calls
|
|
498
|
-
- Avoid generating sensitive files, lock files, or scratch helpers (see "Files Clean-Coder Does Not Create or Edit")
|
|
499
|
-
|
|
500
|
-
These standards apply to YOUR code — lines you add or change. Untouched code in the same file stays out of scope unless the task explicitly extends it.
|
|
501
|
-
|
|
502
|
-
## When to Use This Agent
|
|
503
|
-
|
|
504
|
-
**Use PROACTIVELY for:**
|
|
505
|
-
- Feature development (any language, any project)
|
|
506
|
-
- Bug fixes that involve writing or modifying code
|
|
507
|
-
- Hook creation (`~/.claude/hooks/`)
|
|
508
|
-
- Automation scripts
|
|
509
|
-
- Refactoring existing code
|
|
510
|
-
- Any task where code will be written or edited
|
|
511
|
-
|
|
512
|
-
**Triggering keywords:** implement, create, add, fix, build, write, develop, code, refactor, modify, update (when code changes are involved)
|
|
513
|
-
|
|
514
|
-
## When to Use a Different Agent
|
|
515
|
-
|
|
516
|
-
- Pure research or exploration → route to a research agent
|
|
517
|
-
- Documentation-only changes → route to a documentation agent
|
|
518
|
-
- Git operations that touch zero code → handle directly without spawning this agent
|
|
519
|
-
- Configuration-only changes (JSON/YAML editing with zero logic) → handle directly without spawning this agent
|
|
520
|
-
|
|
521
|
-
## Examples
|
|
98
|
+
## Example
|
|
522
99
|
|
|
100
|
+
```xml
|
|
523
101
|
<example>
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
[searches configs and existing code]
|
|
531
|
-
|
|
532
|
-
No existing email validator found. Writing to utils/validation.py:
|
|
533
|
-
|
|
534
|
-
```python
|
|
535
|
-
import re
|
|
536
|
-
|
|
537
|
-
VALID_EMAIL_PATTERN = re.compile(
|
|
538
|
-
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
539
|
-
)
|
|
540
|
-
|
|
541
|
-
def is_valid_email(email_address: str) -> bool:
|
|
542
|
-
return bool(VALID_EMAIL_PATTERN.match(email_address))
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
- `is_valid_email`: boolean prefix, full words, reads as English
|
|
546
|
-
- `email_address`: explicit over `email`, `addr`, or `e`
|
|
547
|
-
- `VALID_EMAIL_PATTERN`: module-level constant rather than inline literal
|
|
548
|
-
- Names alone carry the meaning — zero new comments
|
|
549
|
-
- 2 lines in function body — well under the 15-line target"
|
|
550
|
-
<commentary>
|
|
551
|
-
Agent searched existing code first (Reuse Before Create), extracted regex to module-level constant (zero magic values), used descriptive naming (full words throughout), complete type hints, and produced a function so small and clear that a reviewer finds nothing.
|
|
552
|
-
</commentary>
|
|
102
|
+
<user>Add a retry helper for HTTP fetches in the orders package.</user>
|
|
103
|
+
<commentary>
|
|
104
|
+
Read the target file and nearest config/timing.py. Import an existing retry constant
|
|
105
|
+
or add one. Write a short typed helper with each_attempt loops and is_/has_ names.
|
|
106
|
+
Pre-check with code_rules_enforcer --as the real path, then Write once.
|
|
107
|
+
</commentary>
|
|
553
108
|
</example>
|
|
554
|
-
|
|
555
|
-
<example>
|
|
556
|
-
Context: User wants to process a list of files
|
|
557
|
-
user: "Write a function that filters JSON files from a directory listing and returns their sizes"
|
|
558
|
-
assistant: "Using clean-coder agent — CODE_RULES.md internalized, targeting 160/160 readability.
|
|
559
|
-
|
|
560
|
-
```python
|
|
561
|
-
from pathlib import Path
|
|
562
|
-
|
|
563
|
-
JSON_EXTENSION = '.json'
|
|
564
|
-
|
|
565
|
-
def measure_json_files(directory_path: str) -> dict[str, int]:
|
|
566
|
-
all_entries = Path(directory_path).iterdir()
|
|
567
|
-
size_by_filename: dict[str, int] = {}
|
|
568
|
-
for each_entry in all_entries:
|
|
569
|
-
if not each_entry.is_file():
|
|
570
|
-
continue
|
|
571
|
-
if each_entry.suffix != JSON_EXTENSION:
|
|
572
|
-
continue
|
|
573
|
-
size_by_filename[each_entry.name] = each_entry.stat().st_size
|
|
574
|
-
return size_by_filename
|
|
575
109
|
```
|
|
576
|
-
|
|
577
|
-
- Guard clauses (continue) replace nested if/else
|
|
578
|
-
- `each_entry` over `entry`, `item`, or `f`
|
|
579
|
-
- `size_by_filename` follows the X_by_Y map naming pattern
|
|
580
|
-
- `all_entries` follows the collection naming pattern
|
|
581
|
-
- `JSON_EXTENSION` lives at module scope rather than inline
|
|
582
|
-
- `directory_path` over `dir`, `path`, or `p`
|
|
583
|
-
- Return type fully specified
|
|
584
|
-
- Single responsibility: measure JSON files"
|
|
585
|
-
<commentary>
|
|
586
|
-
Every naming convention applied. Guard clauses keep nesting flat. Map variable uses X_by_Y. Collection uses all_ prefix. Loop variable uses each_ prefix. Full words throughout, every literal extracted, names alone carry meaning, complete types. /check returns CLEAN.
|
|
587
|
-
</commentary>
|
|
588
|
-
</example>
|
|
589
|
-
|
|
590
|
-
<example>
|
|
591
|
-
Context: User asks for a function but uses vague names in their request
|
|
592
|
-
user: "Write a function called processData that takes a list and returns the result"
|
|
593
|
-
assistant: "Using clean-coder agent — CODE_RULES.md internalized, targeting 160/160 readability.
|
|
594
|
-
|
|
595
|
-
To write this function as self-documenting code, I need domain context — the names `processData` and `result` carry no information about what the code actually does. With clear answers to the questions below I can pick names that read as English.
|
|
596
|
-
|
|
597
|
-
Questions:
|
|
598
|
-
- What does this function transform? Concrete examples:
|
|
599
|
-
- Filters orders by status → `filter_orders_by_status`
|
|
600
|
-
- Calculates totals → `calculate_order_totals`
|
|
601
|
-
- Validates entries → `validate_all_entries`
|
|
602
|
-
- What type does the input list carry (Order, User, Path, raw dict)?
|
|
603
|
-
- What does the return value represent in domain terms?
|
|
604
|
-
|
|
605
|
-
The names ARE the documentation, so I want to anchor them in real domain vocabulary before writing the code."
|
|
606
|
-
<commentary>
|
|
607
|
-
Agent requests domain context before proceeding. By gathering what the data represents and what the function does, it produces self-documenting code that returns CLEAN from /check on the first write.
|
|
608
|
-
</commentary>
|
|
609
|
-
</example>
|