clean-code-tools 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +66 -0
  2. package/configs/eslint.clean-code.recommended.mjs +211 -0
  3. package/configs/python.clean-code.pyproject.toml +143 -0
  4. package/data/clean-code-patterns.jsonl +264 -0
  5. package/data/vector-record.schema.json +77 -0
  6. package/docs/README.md +29 -0
  7. package/docs/eslint-custom-rules.md +74 -0
  8. package/docs/eslint-recommended-config.md +87 -0
  9. package/docs/fastmcp-local-server.md +104 -0
  10. package/docs/publishing.md +125 -0
  11. package/docs/python-lint-recommended-config.md +57 -0
  12. package/docs/python-pylint-custom-rules.md +77 -0
  13. package/docs/semantic-weaviate.md +80 -0
  14. package/docs/static-trigger-semantic-review.md +97 -0
  15. package/evals/clean-code-retrieval.jsonl +13 -0
  16. package/ops/dev/weaviate/README.md +34 -0
  17. package/ops/dev/weaviate/compose.yaml +34 -0
  18. package/ops/dev/weaviate/smoke.sh +28 -0
  19. package/package.json +96 -0
  20. package/pyproject.toml +303 -0
  21. package/sample-apps/README.md +40 -0
  22. package/sample-apps/python-app/pyproject.toml +113 -0
  23. package/sample-apps/python-app/src/clean_pricing.py +10 -0
  24. package/sample-apps/python-app/src/smelly_pricing.py +8 -0
  25. package/sample-apps/ts-backend/eslint.config.mjs +3 -0
  26. package/sample-apps/ts-backend/package.json +18 -0
  27. package/sample-apps/ts-backend/src/clean-handler.ts +19 -0
  28. package/sample-apps/ts-backend/src/smelly-handler.ts +29 -0
  29. package/sample-apps/ts-backend/tsconfig.json +9 -0
  30. package/sample-apps/ts-frontend/eslint.config.mjs +3 -0
  31. package/sample-apps/ts-frontend/package.json +18 -0
  32. package/sample-apps/ts-frontend/src/CleanWidget.tsx +18 -0
  33. package/sample-apps/ts-frontend/src/SmellyWidget.tsx +27 -0
  34. package/sample-apps/ts-frontend/tsconfig.json +10 -0
  35. package/scripts/_mcp_app.py +21 -0
  36. package/scripts/check_clean_code_review_candidates.py +302 -0
  37. package/scripts/check_fastmcp_server.py +106 -0
  38. package/scripts/check_packages.py +137 -0
  39. package/scripts/check_python_config.py +130 -0
  40. package/scripts/check_repo_python_lint.py +46 -0
  41. package/scripts/check_retrieval_evals.py +132 -0
  42. package/scripts/check_sample_apps.py +169 -0
  43. package/scripts/check_semantic_search_tooling.py +102 -0
  44. package/scripts/clean_code_eslint_triggers.py +272 -0
  45. package/scripts/clean_code_mcp_server.py +7 -0
  46. package/scripts/clean_code_python_triggers.py +318 -0
  47. package/scripts/clean_code_review_candidates.py +291 -0
  48. package/scripts/clean_code_review_io.py +36 -0
  49. package/scripts/clean_code_review_models.py +43 -0
  50. package/scripts/clean_code_semantic.py +27 -0
  51. package/scripts/set_package_versions.py +82 -0
  52. package/scripts/weaviate_ingest_clean_code.py +44 -0
  53. package/scripts/weaviate_search_clean_code.py +51 -0
  54. package/skills/clean-code-mcp-reviewer/SKILL.md +209 -0
  55. package/skills/clean-code-mcp-reviewer/evals/evals.json +30 -0
  56. package/src/js/eslint-plugin-clean-code.mjs +758 -0
  57. package/src/python/clean_code_tools_pylint/__init__.py +14 -0
  58. package/src/python/clean_code_tools_pylint/ast_checker.py +122 -0
  59. package/src/python/clean_code_tools_pylint/comments.py +83 -0
  60. package/src/python/clean_code_tools_pylint/helpers.py +196 -0
  61. package/src/python/mcp_server/__init__.py +1 -0
  62. package/src/python/mcp_server/corpus.py +160 -0
  63. package/src/python/mcp_server/markdown.py +126 -0
  64. package/src/python/mcp_server/models.py +73 -0
  65. package/src/python/mcp_server/ranking.py +125 -0
  66. package/src/python/mcp_server/ranking_scoring.py +232 -0
  67. package/src/python/mcp_server/semantic.py +192 -0
  68. package/src/python/mcp_server/server.py +235 -0
  69. package/src/python/mcp_server/server_payloads.py +83 -0
  70. package/src/python/mcp_server/text.py +104 -0
  71. package/src/python/mcp_server/utils/__init__.py +1 -0
  72. package/src/python/mcp_server/utils/httpx_loader.py +14 -0
  73. package/src/python/mcp_server/utils/increment.py +7 -0
  74. package/src/python/mcp_server/utils/sha256_text.py +8 -0
  75. package/src/python/mcp_server/utils/unique_strings.py +15 -0
  76. package/src/python/mcp_server/weaviate.py +182 -0
  77. package/uv.lock +2012 -0
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "CleanCodePatternVectorRecord",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": [
7
+ "id",
8
+ "title",
9
+ "topic",
10
+ "rule_family",
11
+ "aliases",
12
+ "problem",
13
+ "use_when",
14
+ "avoid_when",
15
+ "good_examples",
16
+ "bad_examples",
17
+ "lint_candidates",
18
+ "lintability",
19
+ "embedding_text",
20
+ "display_text",
21
+ "source"
22
+ ],
23
+ "properties": {
24
+ "id": { "type": "string", "pattern": "^CC-[0-9]{3}$" },
25
+ "title": { "type": "string", "minLength": 3 },
26
+ "topic": { "type": "string", "minLength": 3 },
27
+ "rule_family": { "type": "string", "minLength": 3 },
28
+ "aliases": {
29
+ "type": "array",
30
+ "items": { "type": "string", "minLength": 2 },
31
+ "minItems": 3,
32
+ "uniqueItems": true
33
+ },
34
+ "problem": { "type": "string", "minLength": 20 },
35
+ "use_when": { "type": "string", "minLength": 20 },
36
+ "avoid_when": { "type": "string", "minLength": 20 },
37
+ "good_examples": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["typescript", "python"],
41
+ "properties": {
42
+ "typescript": { "type": "string", "minLength": 5 },
43
+ "python": { "type": "string", "minLength": 5 }
44
+ }
45
+ },
46
+ "bad_examples": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": ["typescript", "python"],
50
+ "properties": {
51
+ "typescript": { "type": "string", "minLength": 5 },
52
+ "python": { "type": "string", "minLength": 5 }
53
+ }
54
+ },
55
+ "lint_candidates": {
56
+ "type": "array",
57
+ "items": { "type": "string", "minLength": 10 },
58
+ "minItems": 1
59
+ },
60
+ "lintability": {
61
+ "type": "string",
62
+ "enum": ["high", "medium", "low", "review_only"]
63
+ },
64
+ "embedding_text": { "type": "string", "minLength": 300 },
65
+ "display_text": { "type": "string", "minLength": 300 },
66
+ "source": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["kind", "version"],
70
+ "properties": {
71
+ "kind": { "type": "string" },
72
+ "version": { "type": "integer", "minimum": 1 }
73
+ }
74
+ }
75
+ }
76
+ }
77
+
package/docs/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Documentation Index
2
+
3
+ Production-facing docs for clean-code lint packages, MCP pattern lookup, and
4
+ release operations.
5
+
6
+ ## Package Usage
7
+
8
+ - [ESLint recommended config](./eslint-recommended-config.md): install and use
9
+ the TypeScript ESLint preset from the npm package.
10
+ - [ESLint custom rules](./eslint-custom-rules.md): project-owned TypeScript
11
+ clean-code rules included in the ESLint plugin.
12
+ - [Python recommended config](./python-lint-recommended-config.md): install and
13
+ use the Ruff/Pylint config from the Python package.
14
+ - [Python custom Pylint rules](./python-pylint-custom-rules.md): project-owned
15
+ Python clean-code rules exposed by the Pylint plugin.
16
+
17
+ ## Agent And MCP Workflows
18
+
19
+ - [FastMCP local server](./fastmcp-local-server.md): run the local MCP server,
20
+ inspect exposed tools, and query clean-code patterns from an agent.
21
+ - [Semantic Weaviate search](./semantic-weaviate.md): run local Weaviate,
22
+ ingest the pattern corpus, and test semantic retrieval.
23
+ - [Static trigger to semantic review](./static-trigger-semantic-review.md):
24
+ convert deterministic lint output into clean-code MCP review candidates.
25
+
26
+ ## Operations
27
+
28
+ - [Publishing](./publishing.md): package registry setup, branch flow, automated
29
+ versioning on `develop`, and publishing on `main`.
@@ -0,0 +1,74 @@
1
+ # ESLint Custom Clean-Code Rules
2
+
3
+ The local plugin lives at [src/js/eslint-plugin-clean-code.mjs](../src/js/eslint-plugin-clean-code.mjs). These rules cover TypeScript clean-code checks that are not well covered by common ESLint rule sets.
4
+
5
+ ## Rules
6
+
7
+ ### `clean-code/todo-format`
8
+
9
+ Requires TODO/FIXME/XXX comments to include an issue-like owner by default:
10
+
11
+ ```ts
12
+ // TODO(BILL-412): remove fallback after migration.
13
+ ```
14
+
15
+ Default pattern:
16
+
17
+ ```text
18
+ ^(TODO|FIXME|XXX)\([A-Z][A-Z0-9]+-\d+\):\s+\S
19
+ ```
20
+
21
+ Corpus: `CC-068`
22
+
23
+ ### `clean-code/no-commented-out-code`
24
+
25
+ Flags comments that look like disabled JavaScript or TypeScript code.
26
+
27
+ Corpus: `CC-083`
28
+
29
+ ### `clean-code/no-boolean-flag-arguments`
30
+
31
+ Flags boolean literals passed at call sites and boolean selector parameters with mode-like names such as `dryRun`, `force`, `skip`, `include`, or `mode`.
32
+
33
+ Corpus: `CC-043`, `CC-208`, `CC-224`
34
+
35
+ ### `clean-code/no-output-argument-mutation`
36
+
37
+ Flags assignments, updates, and common mutator calls that mutate function parameters.
38
+
39
+ Corpus: `CC-050`, `CC-207`
40
+
41
+ ### `clean-code/no-redundant-comment`
42
+
43
+ Flags comments whose words heavily overlap the following line of code.
44
+
45
+ Corpus: `CC-071`, `CC-073`
46
+
47
+ ### `clean-code/no-noisy-comments`
48
+
49
+ Flags separator comments, author/date byline comments, and comments after closing braces.
50
+
51
+ Corpus: `CC-080`, `CC-081`, `CC-082`
52
+
53
+ ### `clean-code/no-business-policy-literals`
54
+
55
+ Flags hard-coded policy-looking literals outside named constants and allowlisted calls. The heuristic catches:
56
+
57
+ - numbers other than `-1`, `0`, and `1`
58
+ - all-caps string values
59
+ - ISO date strings
60
+ - common domain statuses such as `active`, `approved`, `draft`, `failed`, `pending`, and `rejected`
61
+
62
+ Corpus: `CC-002`, `CC-018`, `CC-234`
63
+
64
+ ### `clean-code/no-train-wrecks`
65
+
66
+ Flags deep property chains beyond a configurable maximum depth.
67
+
68
+ Corpus: `CC-106`, `CC-107`, `CC-245`
69
+
70
+ ## Recommended Config
71
+
72
+ The rules are enabled in [configs/eslint.clean-code.recommended.mjs](../configs/eslint.clean-code.recommended.mjs).
73
+
74
+ They are intentionally warnings because each rule is heuristic and should be tuned per repository.
@@ -0,0 +1,87 @@
1
+ # ESLint Recommended Clean-Code Config
2
+
3
+ This config combines mature existing ESLint rule sets with a small local clean-code plugin for the TypeScript gaps that are not well covered elsewhere.
4
+
5
+ ## Target
6
+
7
+ Use [configs/eslint.clean-code.recommended.mjs](../configs/eslint.clean-code.recommended.mjs) in TypeScript projects that already run ESLint flat config.
8
+
9
+ This preset currently targets Node `^22.13.0 || >=24`, matching the tested ESLint 10/plugin stack.
10
+
11
+ Install the npm package with its peer dependencies:
12
+
13
+ ```bash
14
+ npm install --save-dev clean-code-tools eslint @eslint/js typescript-eslint eslint-plugin-sonarjs eslint-plugin-unicorn
15
+ ```
16
+
17
+ Then import the preset from the consuming project's `eslint.config.mjs`:
18
+
19
+ ```js
20
+ import cleanCode from "clean-code-tools/configs/eslint.clean-code.recommended.mjs";
21
+
22
+ export default cleanCode;
23
+ ```
24
+
25
+ If a project already has a config, spread this preset before project-specific overrides:
26
+
27
+ ```js
28
+ import cleanCode from "clean-code-tools/configs/eslint.clean-code.recommended.mjs";
29
+
30
+ export default [
31
+ ...cleanCode,
32
+ {
33
+ rules: {
34
+ "max-lines": ["warn", { max: 300, skipBlankLines: true, skipComments: true }],
35
+ "max-lines-per-function": ["warn", { max: 50, skipBlankLines: true, skipComments: true }],
36
+ },
37
+ },
38
+ ];
39
+ ```
40
+
41
+ ## TypeScript Project Setup
42
+
43
+ The config uses type-aware `typescript-eslint` rules with `projectService: true` for TypeScript files. Linted `*.ts`, `*.tsx`, `*.mts`, and `*.cts` files must be included by the consuming project's `tsconfig.json`.
44
+
45
+ If a project intentionally lints generated files, config files, or one-off scripts outside `tsconfig.json`, add a project-specific override rather than broadening this preset globally.
46
+
47
+ The package declares these peer dependencies:
48
+
49
+ - `eslint@^10.4.0`
50
+ - `@eslint/js@^10.0.0`
51
+ - `typescript-eslint@^8.0.0`
52
+ - `eslint-plugin-sonarjs@^4.0.0`
53
+ - `eslint-plugin-unicorn@^69.0.0`
54
+
55
+ ## Existing Rule Coverage
56
+
57
+ | Corpus area | Existing ESLint coverage |
58
+ | --- | --- |
59
+ | Small files, functions, and complexity, `CC-033..CC-059`, `CC-137..CC-142`, `CC-206` | `complexity`, `max-depth`, `max-lines`, `max-lines-per-function`, `max-params`, `sonarjs/cognitive-complexity` |
60
+ | Magic numbers and repeated literals, `CC-018`, `CC-234` | `@typescript-eslint/no-magic-numbers`, `sonarjs/no-duplicate-string` |
61
+ | TODO/FIXME visibility, `CC-068` | `clean-code/todo-format` |
62
+ | Duplicate conditions and branches, `CC-160`, `CC-214` | `sonarjs/no-duplicated-branches`, `sonarjs/no-identical-conditions`, `sonarjs/no-identical-functions` |
63
+ | Complex and negative conditionals, `CC-237`, `CC-238` | `no-nested-ternary`, `no-negated-condition`, `sonarjs/no-inverted-boolean-check`, `unicorn/no-negated-condition` |
64
+ | Null avoidance, `CC-118`, `CC-119` | `unicorn/no-null`, `@typescript-eslint/no-unnecessary-condition`, `@typescript-eslint/prefer-nullish-coalescing` |
65
+ | Dead and redundant code, `CC-209`, `CC-218`, `CC-221` | `@typescript-eslint/no-unused-vars`, `no-empty`, `no-useless-return`, `sonarjs/no-dead-store` |
66
+ | Long import lists, `CC-246` | `no-restricted-syntax` custom selector over `ImportDeclaration[specifiers.length>10]` |
67
+ | Naming consistency, `CC-011`, `CC-025`, `CC-249..CC-255` | `@typescript-eslint/naming-convention` |
68
+ | Async precision and type clarity, `CC-235` | `@typescript-eslint/no-floating-promises`, `@typescript-eslint/no-misused-promises`, `@typescript-eslint/switch-exhaustiveness-check`, `eqeqeq` |
69
+
70
+ ## Custom Gap Coverage
71
+
72
+ These corpus candidates are implemented by the local clean-code plugin:
73
+
74
+ - commented-out TypeScript code detection: `clean-code/no-commented-out-code`, `CC-083`
75
+ - TODO format such as `TODO(PROJ-123): ...`: `clean-code/todo-format`, `CC-068`
76
+ - boolean literal arguments at call sites and boolean selector parameters: `clean-code/no-boolean-flag-arguments`, `CC-043`, `CC-208`
77
+ - output argument mutation: `clean-code/no-output-argument-mutation`, `CC-207`
78
+ - comments that restate the following line: `clean-code/no-redundant-comment`, `CC-071`, `CC-073`
79
+ - byline/date comments, separator comments, and closing-brace comments: `clean-code/no-noisy-comments`, `CC-080..CC-082`
80
+ - business-policy string/date/status literals: `clean-code/no-business-policy-literals`, `CC-002`, `CC-234`
81
+ - Law of Demeter / train-wreck chains: `clean-code/no-train-wrecks`, `CC-106`, `CC-107`, `CC-245`
82
+
83
+ See [eslint-custom-rules.md](./eslint-custom-rules.md) for rule details.
84
+
85
+ ## Python Config
86
+
87
+ Python projects should use the Ruff + Pylint config in [python-lint-recommended-config.md](./python-lint-recommended-config.md).
@@ -0,0 +1,104 @@
1
+ # FastMCP Local Server
2
+
3
+ This server exposes clean-code pattern lookup tools through FastMCP. Coding
4
+ agents should use the pattern-first tools for review/refactor decisions and keep
5
+ the lower-level chunk search for diagnostics.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ uv sync
11
+ ```
12
+
13
+ ## Prepare Weaviate
14
+
15
+ ```bash
16
+ bun run weaviate:dev:start
17
+ bun run weaviate:dev:smoke
18
+ bun run semantic:ingest -- --reset
19
+ ```
20
+
21
+ If the default port is busy, use the same alternate port for all commands:
22
+
23
+ ```bash
24
+ WEAVIATE_HTTP_PORT=38080 WEAVIATE_GRPC_PORT=35051 bun run weaviate:dev:start
25
+ WEAVIATE_HTTP_PORT=38080 bun run weaviate:dev:smoke
26
+ bun run semantic:ingest -- --url http://127.0.0.1:38080 --reset
27
+ ```
28
+
29
+ ## Run MCP
30
+
31
+ Stdio:
32
+
33
+ ```bash
34
+ bun run mcp:stdio
35
+ ```
36
+
37
+ HTTP:
38
+
39
+ ```bash
40
+ bun run mcp:http
41
+ ```
42
+
43
+ The HTTP server defaults to `http://127.0.0.1:8765`.
44
+
45
+ ## Exposed Tools
46
+
47
+ - `clean_code_corpus_summary`: returns corpus chunk counts.
48
+ - `clean_code_weaviate_schema`: returns the `CleanCodeChunks` schema payload.
49
+ - `search_clean_code`: low-level compatibility search over populated Weaviate chunks.
50
+ - `search_clean_code_patterns`: pattern-first search for concrete code smells.
51
+ - `get_clean_code_pattern`: full canonical lookup by `CC-###` ID.
52
+ - `recommend_clean_code_lint_rules`: lint-rule candidate guidance for repeated smells.
53
+ - `list_clean_code_facets`: available filter values and counts.
54
+
55
+ Pattern-first search arguments:
56
+
57
+ ```json
58
+ {
59
+ "query": "typescript boolean parameter controls behavior",
60
+ "language": "typescript",
61
+ "lintability": ["high", "medium"],
62
+ "limit": 5,
63
+ "weaviate_url": "http://127.0.0.1:8080"
64
+ }
65
+ ```
66
+
67
+ Full pattern lookup:
68
+
69
+ ```json
70
+ {
71
+ "pattern_id": "CC-043"
72
+ }
73
+ ```
74
+
75
+ Lint-rule recommendation:
76
+
77
+ ```json
78
+ {
79
+ "query": "TODO comments without issue IDs",
80
+ "language": "typescript",
81
+ "targets": ["eslint", "semgrep"]
82
+ }
83
+ ```
84
+
85
+ ## Agent Workflow
86
+
87
+ Use the MCP after inspecting code and forming a concrete smell hypothesis. Send
88
+ short queries such as `python function mutates output argument and returns
89
+ status`, not whole files or full diffs.
90
+
91
+ Recommended review loop:
92
+
93
+ 1. Read the changed code and nearby tests.
94
+ 2. Identify one maintainability concern.
95
+ 3. Query `search_clean_code_patterns` with language and narrow filters.
96
+ 4. Fetch detail with `get_clean_code_pattern` only for a relevant result.
97
+ 5. Use the pattern as support for a local code finding, not as the finding
98
+ itself.
99
+ 6. Suppress weak results or framework-idiomatic near-misses.
100
+
101
+ `search_clean_code_patterns` returns `confidence`, `score`, `match_reasons`,
102
+ and top-level `no_strong_match`. Treat `no_strong_match` as a signal to avoid
103
+ surfacing a clean-code recommendation unless the local code evidence is already
104
+ strong.
@@ -0,0 +1,125 @@
1
+ # Publishing
2
+
3
+ This repo publishes two native package shapes from the same source tree.
4
+
5
+ ## Registries
6
+
7
+ - npm registry: `clean-code-tools`
8
+ - PyPI: `clean-code-tools-python`
9
+
10
+ These are production registry names. If either name is already taken, rename the
11
+ package in `package.json` or `pyproject.toml` before the first publish.
12
+
13
+ ## TypeScript / ESLint
14
+
15
+ The npm package exposes:
16
+
17
+ - `clean-code-tools`
18
+ - `clean-code-tools/eslint-plugin`
19
+ - `clean-code-tools/configs/eslint.clean-code.recommended.mjs`
20
+ - `clean-code-tools/configs/python.clean-code.pyproject.toml`
21
+
22
+ Before publishing:
23
+
24
+ ```bash
25
+ bun run check:packages
26
+ npm publish --dry-run --provenance
27
+ ```
28
+
29
+ The package must not set `private: true`; otherwise npm refuses publication. The
30
+ GitHub Actions workflows use npm trusted publishing with provenance, so configure
31
+ the npm package's trusted publisher to allow this repository and these workflow
32
+ files:
33
+
34
+ - `.github/workflows/publish-main.yml`
35
+
36
+ The workflows use Node 24 so the bundled npm supports trusted publishing.
37
+
38
+ ## Python / Pylint
39
+
40
+ The PyPI package is `clean-code-tools-python`. It installs:
41
+
42
+ - the `clean_code_tools_pylint` plugin package
43
+ - Ruff and Pylint runtime dependencies
44
+ - the reusable config as package data at
45
+ `clean_code_tools_pylint/configs/python.clean-code.pyproject.toml`
46
+
47
+ Before publishing:
48
+
49
+ ```bash
50
+ bun run check:packages
51
+ uv build
52
+ uv publish --dry-run
53
+ ```
54
+
55
+ Configure PyPI trusted publishers for this repository and these workflow files:
56
+
57
+ - `.github/workflows/publish-main.yml`
58
+
59
+ The workflows use `uv publish --trusted-publishing always`, so no PyPI token is
60
+ stored in GitHub secrets.
61
+
62
+ The package smoke check builds a wheel, installs it into an isolated virtualenv,
63
+ loads the packaged config through `importlib.resources`, then runs Ruff and
64
+ Pylint against a fixture that must trigger the custom `clean-code-*` messages.
65
+
66
+ ## Versioning
67
+
68
+ The source manifests keep a stable release base:
69
+
70
+ - `package.json`
71
+ - `pyproject.toml`
72
+
73
+ Use `scripts/set_package_versions.py` to update them together:
74
+
75
+ ```bash
76
+ uv run python scripts/set_package_versions.py --release 1.2.3
77
+ uv run python scripts/set_package_versions.py --bump patch --base 1.2.3
78
+ ```
79
+
80
+ `bun run check:packages` requires exact version parity between npm and Python.
81
+ Packages are never given a development suffix.
82
+
83
+ Every push or merge to `develop` runs `.github/workflows/version-develop.yml`.
84
+ It reads the latest `vX.Y.Z` tag, bumps the patch version, writes that version to
85
+ `package.json` and `pyproject.toml`, runs the full check, then commits the
86
+ version update back to `develop` and creates a matching `vX.Y.Z` tag on that
87
+ develop commit.
88
+
89
+ Publishing happens only from `main`. Merge `develop` into `main` after the
90
+ versioning workflow has created the version commit and tag. A push to `main`
91
+ runs `.github/workflows/publish-main.yml`, verifies that the manifest version has
92
+ a matching `vX.Y.Z` tag reachable from `main`, runs the full check, then
93
+ publishes npm `latest` plus the PyPI final release.
94
+
95
+ If a change needs a minor or major bump, run the version script manually on
96
+ `develop` before merging, or adjust the workflow bump type for that release.
97
+
98
+ ## SemVer Policy
99
+
100
+ Publish the Python package and npm package with matching versions when rule
101
+ semantics change. Patch-only documentation or packaging fixes can ship
102
+ independently if the lint behavior is unchanged.
103
+
104
+ The package check enforces version parity between `package.json` and
105
+ `pyproject.toml`, so bump both manifests in the same release change.
106
+
107
+ Use SemVer for both registries:
108
+
109
+ - patch: documentation, packaging, or false-positive tuning that reduces noise
110
+ - minor: new rules, new recommended warnings, or new MCP candidate mappings
111
+ - major: removed rules, renamed public exports, or stricter defaults that create
112
+ a large new failure surface
113
+
114
+ ## References
115
+
116
+ - npm publishing and provenance:
117
+ <https://docs.github.com/en/actions/tutorials/publish-packages/publish-nodejs-packages>
118
+ - npm package versions are immutable after publish:
119
+ <https://docs.npmjs.com/cli/v11/commands/npm-publish/>
120
+ - PyPI trusted publishing:
121
+ <https://docs.pypi.org/trusted-publishers/adding-a-publisher/>
122
+ - GitHub OIDC setup for PyPI:
123
+ <https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi>
124
+ - uv publishing with trusted publishers:
125
+ <https://docs.astral.sh/uv/guides/package/>
@@ -0,0 +1,57 @@
1
+ # Python Recommended Clean-Code Config
2
+
3
+ Use [configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml) as a reusable `pyproject.toml` fragment for Python projects that want clean-code-oriented linting.
4
+
5
+ The config intentionally mixes Ruff and Pylint:
6
+
7
+ - Ruff owns fast local checks: syntax/correctness, imports, bug-prone patterns, simple refactors, commented-out code, TODO shape, unused arguments, return-flow cleanup, magic-value comparisons, and Ruff-specific quality checks.
8
+ - Pylint owns broader design pressure: too many module lines, arguments, locals, branches, returns, statements, nested blocks, public methods, instance attributes, duplicate code, cyclic imports, and the custom Python clean-code plugin.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ python -m pip install clean-code-tools-python
14
+ ```
15
+
16
+ Copy the config into a project root as `pyproject.toml`, or merge its `[tool.ruff]`, `[tool.ruff.lint]`, and `[tool.pylint.*]` sections into an existing `pyproject.toml`.
17
+
18
+ The Python package installs Ruff, Pylint, and the custom Pylint plugin module
19
+ `clean_code_tools_pylint`. The canonical reusable config is packaged as
20
+ `clean_code_tools_pylint/configs/python.clean-code.pyproject.toml`; this repo
21
+ also keeps a copy at [configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml)
22
+ for local and JavaScript-package consumers.
23
+
24
+ Run:
25
+
26
+ ```bash
27
+ ruff check .
28
+ pylint .
29
+ ```
30
+
31
+ ## Clean-Code Coverage
32
+
33
+ | Corpus area | Tool coverage |
34
+ | --- | --- |
35
+ | Commented-out code, `CC-083` | Ruff `ERA` |
36
+ | TODO/FIXME visibility and tracking, `CC-068` | Ruff `TD` |
37
+ | Magic numbers / named constants, `CC-018`, `CC-234` | Ruff `PLR2004` |
38
+ | Dead and unused code, `CC-209`, `CC-218`, `CC-221` | Ruff `F`, `ARG`, `B` |
39
+ | Import readability and ordering, `CC-246` | Ruff `I`, `F401` |
40
+ | Return-flow cleanup, `CC-237`, `CC-238` adjacent | Ruff `RET`, `SIM` |
41
+ | File, function, and class size pressure, `CC-033..CC-059`, `CC-137..CC-142`, `CC-206` | Pylint `too-many-lines` plus design messages |
42
+ | Duplication and coupling signals, `CC-004`, `CC-160`, `CC-214` | Pylint `duplicate-code`, `cyclic-import` |
43
+ | Custom clean-code gaps matching the TypeScript plugin, `CC-043`, `CC-050`, `CC-068`, `CC-071`, `CC-073`, `CC-080`, `CC-083`, `CC-106`, `CC-107`, `CC-207`, `CC-208`, `CC-224`, `CC-245` | Pylint plugin `clean-code-*` messages |
44
+
45
+ ## Notes
46
+
47
+ Ruff does not currently support project-local custom rule plugins, so the config only uses built-in Ruff rule families. Pylint is included because its design checker still provides useful clean-code pressure that Ruff either does not cover or would duplicate less flexibly.
48
+
49
+ The thresholds are intentionally strict enough to act as early architecture-smell signals: modules warn above 300 lines, functions warn through statement count, and classes warn when public methods or attributes accumulate. Relax them for framework entrypoints, generated code, migrations, tests, and compatibility layers through project-local overrides.
50
+
51
+ ## Remaining Custom Candidates
52
+
53
+ The remaining custom candidates are mostly domain-specific allowlists and
54
+ project-specific suppression policies around the `clean-code-*` messages.
55
+
56
+ See [python-pylint-custom-rules.md](./python-pylint-custom-rules.md) for the
57
+ custom rule details.
@@ -0,0 +1,77 @@
1
+ # Python Custom Clean-Code Rules
2
+
3
+ The local Pylint plugin lives at
4
+ [src/python/clean_code_tools_pylint/](../src/python/clean_code_tools_pylint/). These rules
5
+ mirror the project-owned ESLint clean-code rules where Python syntax gives us a
6
+ reasonably precise static signal.
7
+
8
+ ## Rules
9
+
10
+ ### `clean-code-todo-format`
11
+
12
+ Requires TODO/FIXME/XXX comments to include an issue-like owner by default:
13
+
14
+ ```python
15
+ # TODO(BILL-412): remove fallback after migration.
16
+ ```
17
+
18
+ Corpus: `CC-068`
19
+
20
+ ### `clean-code-commented-out-code`
21
+
22
+ Flags comments that look like disabled Python code.
23
+
24
+ Corpus: `CC-083`
25
+
26
+ ### `clean-code-boolean-flag-argument`
27
+
28
+ Flags boolean literals passed at call sites and boolean selector parameters with
29
+ mode-like names such as `dry_run`, `force`, `skip`, `include`, or `mode`.
30
+
31
+ Corpus: `CC-043`, `CC-208`, `CC-224`
32
+
33
+ ### `clean-code-output-argument-mutation`
34
+
35
+ Flags assignments, updates, and common mutator calls that mutate function
36
+ parameters.
37
+
38
+ Corpus: `CC-050`, `CC-207`
39
+
40
+ ### `clean-code-redundant-comment`
41
+
42
+ Flags comments whose words heavily overlap the following line of code.
43
+
44
+ Corpus: `CC-071`, `CC-073`
45
+
46
+ ### `clean-code-noisy-comment`
47
+
48
+ Flags separator comments and author/date byline comments.
49
+
50
+ Corpus: `CC-080`, `CC-081`
51
+
52
+ ### `clean-code-business-policy-literal`
53
+
54
+ Flags hard-coded policy-looking literals outside named constants and allowlisted
55
+ calls. The heuristic catches:
56
+
57
+ - numbers other than `-1`, `0`, and `1`
58
+ - all-caps string values
59
+ - ISO date strings
60
+ - common domain statuses such as `active`, `approved`, `draft`, `failed`,
61
+ `pending`, and `rejected`
62
+
63
+ Corpus: `CC-002`, `CC-018`, `CC-234`
64
+
65
+ ### `clean-code-train-wreck`
66
+
67
+ Flags deep attribute chains beyond the default maximum depth.
68
+
69
+ Corpus: `CC-106`, `CC-107`, `CC-245`
70
+
71
+ ## Recommended Config
72
+
73
+ The plugin is loaded and these messages are enabled in
74
+ [configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml).
75
+
76
+ They are intentionally warnings/design signals because each rule is heuristic
77
+ and should be tuned per repository.