Skip to content

setup: recommended linter configs for Go, Python and TypeScript - #105

Merged
buzzdan merged 3 commits into
mainfrom
claude/recommended-setup
Oct 20, 2026
Merged

buzzdan merged 3 commits into
mainfrom
claude/recommended-setup

Conversation

@buzzdan

@buzzdan buzzdan commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

What

Every plugin gets a setup/ directory with the recommended linter configuration for Go, Python and TypeScript:

File Linter How to adopt it on an existing codebase
setup/golangci.yaml golangci-lint v2, on top of its standard linters issues.new-from-merge-base: main, so only code changed since main fails; CI needs main in the clone
setup/ruff.toml ruff run ruff on the files changed since the merge base, with the command in the file
setup/eslint.config.ldd.mjs ESLint flat-config fragment, spread before the repository's own entries so its limits win npx eslint --suppress-all records today's violations, so only new ones fail

Each file enables the linter rules that the plugin's routing tables route to a design rule (R1, R2, R3, R5, R8, R10, R11, R12), at the limits the rules name. For R3 those are more than 50 lines or more than 2 nesting levels. Each rule line names the design rule that its failures feed. The file-length limit comes from the {{.FileMaxLines}} scalar, which the gap linter also uses. The plugin never writes these files into a repository. The owners copy them, or the parts they want, and limits that a repository already sets stay the repository's.

Changes

  • Three new core templates under core/setup/. They render into every plugin, so the generic plugin has all three for the languages it reviews. Each file has a residue-exempt: marker because it names its linter on purpose.
  • The gap linter's threshold line. It names the rule and the setup file that would hold the file-length limit, for example revive file-length-limit, as the plugin's setup/golangci.yaml sets it. For Python it says that ruff has no file-length rule and that the gap linter holds the limit. It no longer proposes adding pylint, because that would add a tool the repository may not use (house rule A1).
  • Matrix cases. One case reads each plugin's routing table and checks that the language's recommended config names every rule id routed to a design rule. The ids left out on purpose are listed with a reason: cyclop, which is the alternative to gocyclo, and no-restricted-syntax, which needs the repository's config module path. A second case checks that the named setup file sets the file-length rule at the scalar's value. When golangci-lint, ruff or node is on PATH, a case also runs that tool's own check of its file. In CI none of the three is on PATH, so those cases skip.
  • Fix: ldd-lint.sh under bash 3.2. macOS's /bin/bash stopped the merged script with a syntax error. bash 3.2 misreads a case pattern inside a process substitution, so the case moves into a function. The matrix now passes under bash 3.2 and bash 5.
  • Docs. The Go README and docs/quick-start.md say "zero configuration to run" and name the recommended setup. The Python, ts-react and generic READMEs name it too.

Departures from the plan

  • No YAML source and no Go renderer. The plan generated each config from a lint-rules.yaml through three writers in the generator. Hand-written core templates are shorter than that, and they give the same guarantee, because the threshold is a substituted scalar and a test pins it.
  • doctor moves to its own PR. It is the part that reads linter output, and it should be written against real output from golangci-lint linters and ruff check --show-settings.
  • No Taskfile fragment. Each config carries its own ratchet. Go's ratchet is built into the config, and the ESLint and ruff files name the command to run.
  • max-public-structs is left out. No routing-table row routes it, so the configs include only rules that already have a route.
  • The routing check is a matrix case, not a lint-core check. The plan put it in the generator. A shell case over the rendered routing table needed no Go code.
  • Python is ruff only. pylint counts every line, and the repository may not use it.

Checks

  • golangci-lint config verify accepts setup/golangci.yaml. A run with it over tools/ldd-gen works and reports 20 errcheck and wrapcheck issues, because the repository's own exclusions are not in the recommended file.
  • ruff runs setup/ruff.toml. Over py-mini it reports 42 issues: 24 for PLR1702, because nesting is held at R3's limit of 2, and 18 for PLR2004.
  • node --check parses setup/eslint.config.ldd.mjs. ESLint is not installed here, so ESLint itself has not loaded the fragment.
  • task check, task lint-core and task docs:check pass. The ldd-lint, ldd-detect, ldd-scope and check-repo-brain matrices pass for all four plugins.
  • No skill, rule or command text changed, so no eval run is needed.

🤖 Generated with Claude Code

buzzdan and others added 2 commits October 20, 2026 14:43
Add three core templates under setup/, rendered into every plugin:
golangci.yaml, ruff.toml and eslint.config.ldd.mjs. Each enables the
linter rules that the routing tables route to a design rule, at the
limits the rules name, and takes the file-length limit from
{{.FileMaxLines}}. Each says how to adopt it on an existing codebase:
golangci-lint's new-from-merge-base, ESLint's bulk suppressions, ruff on
changed files. The plugin never writes them into a repository.

- The gap linter's threshold line names the rule and the setup file that
  would hold a file-length limit. For Python it says that ruff has no
  file-length rule and the gap linter holds it; it no longer proposes
  adding pylint, a tool the repository may not use.
- The ldd-lint matrix checks that the named setup file sets the rule at
  the scalar's value. When golangci-lint, ruff or node is on PATH, it
  also runs each tool's own check of its file.
- Fix: ldd-lint.sh did not parse under bash 3.2 (macOS /bin/bash). bash
  3.2 misreads a case pattern inside a process substitution; the case
  moves into a function, dir_of.
- The READMEs and docs/quick-start.md say "zero configuration to run" and
  name the recommended setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- eslint.config.ldd.mjs: spread the fragment before the repository's own
  entries. Later entries win in flat config, so every limit the repository
  already sets stays the repository's. Before, the example put the fragment
  last, and it replaced those limits.
- eslint.config.ldd.mjs: add the routed rules it lacked: no-magic-numbers,
  react/no-array-index-key, @typescript-eslint/no-unsafe-*,
  @typescript-eslint/no-unnecessary-condition, react-hooks/set-state-in-effect.
  State the type-information requirement, and why no-restricted-syntax is
  left out.
- golangci.yaml: "default: standard" keeps golangci-lint's standard linters
  on; "none" turned off staticcheck, unused and ineffassign for anyone who
  copied the file. Note that the ratchet needs main in a CI clone.
- ruff.toml: say what preview mode also turns on.
- A matrix case reads each plugin's routing table and checks that the
  language's recommended config names every rule id routed to a design rule,
  except the ids the fixture row lists as left out on purpose.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Configuration thresholds and adoption behavior need correction to reliably enforce the documented design rules.

4 open issues
What changed in this PR

Adds recommended Go, Python, and TypeScript linter configurations to every generated plugin, connecting setup guidance to existing design-rule routing.

Changes:

  • Adds shared configuration templates and generated copies with incremental adoption guidance.
  • Updates gap-linter messages, restores Bash 3.2 compatibility, and extends configuration checks.
  • Documents recommended setup across plugin READMEs and changelogs.
File Description
ts-react-linter-driven-development/​setup/​ruff.toml Generated Ruff configuration.
ts-react-linter-driven-development/​setup/​golangci.yaml Generated Go configuration.
ts-react-linter-driven-development/​setup/​eslint.config.ldd.mjs Generated ESLint fragment.
ts-react-linter-driven-development/​scripts/​ldd-scope_test.sh Adds setup fixture metadata.
ts-react-linter-driven-development/​scripts/​ldd-lint.sh Updates guidance and Bash compatibility.
ts-react-linter-driven-development/​scripts/​ldd-lint_test.sh Adds configuration checks.
ts-react-linter-driven-development/​scripts/​ldd-detect_test.sh Adds setup fixture metadata.
ts-react-linter-driven-development/​README.md Documents ESLint adoption.
ts-react-linter-driven-development/​CHANGELOG.md Records setup and compatibility changes.
python-linter-driven-development/​setup/​ruff.toml Generated Ruff configuration.
python-linter-driven-development/​setup/​golangci.yaml Generated Go configuration.
python-linter-driven-development/​setup/​eslint.config.ldd.mjs Generated ESLint fragment.
python-linter-driven-development/​scripts/​ldd-scope_test.sh Adds setup fixture metadata.
python-linter-driven-development/​scripts/​ldd-lint.sh Updates guidance and Bash compatibility.
python-linter-driven-development/​scripts/​ldd-lint_test.sh Adds configuration checks.
python-linter-driven-development/​scripts/​ldd-detect_test.sh Adds setup fixture metadata.
python-linter-driven-development/​README.md Documents Ruff setup and file-length checking.
python-linter-driven-development/​CHANGELOG.md Records setup and compatibility changes.
linter-driven-development/​setup/​ruff.toml Generated Ruff configuration.
linter-driven-development/​setup/​golangci.yaml Generated Go configuration.
linter-driven-development/​setup/​eslint.config.ldd.mjs Generated ESLint fragment.
linter-driven-development/​scripts/​ldd-scope_test.sh Adds setup fixture metadata.
linter-driven-development/​scripts/​ldd-lint.sh Updates guidance and Bash compatibility.
linter-driven-development/​scripts/​ldd-lint_test.sh Adds configuration checks.
linter-driven-development/​scripts/​ldd-detect_test.sh Adds setup fixture metadata.
linter-driven-development/​README.md Introduces recommended configurations.
linter-driven-development/​CHANGELOG.md Records setup and compatibility changes.
lang/​ts-react/​scripts/​ldd-fixture.sh Defines TypeScript setup expectations.
lang/​ts-react/​passthrough/​README.md Source for ESLint adoption guidance.
lang/​ts-react/​passthrough/​CHANGELOG.md Source for release notes.
lang/​python/​scripts/​ldd-fixture.sh Defines Python setup expectations.
lang/​python/​passthrough/​README.md Source for Ruff setup guidance.
lang/​python/​passthrough/​CHANGELOG.md Source for release notes.
lang/​go/​scripts/​ldd-fixture.sh Defines Go setup expectations.
lang/​go/​passthrough/​README.md Source for Go setup guidance.
lang/​go/​passthrough/​CHANGELOG.md Source for release notes.
lang/​generic/​scripts/​ldd-fixture.sh Defines generic setup expectations.
lang/​generic/​passthrough/​README.md Source for configuration guidance.
lang/​generic/​passthrough/​CHANGELOG.md Source for release notes.
go-linter-driven-development/​setup/​ruff.toml Generated Ruff configuration.
go-linter-driven-development/​setup/​golangci.yaml Generated Go configuration.
go-linter-driven-development/​setup/​eslint.config.ldd.mjs Generated ESLint fragment.
go-linter-driven-development/​scripts/​ldd-scope_test.sh Adds setup fixture metadata.
go-linter-driven-development/​scripts/​ldd-lint.sh Updates guidance and Bash compatibility.
go-linter-driven-development/​scripts/​ldd-lint_test.sh Adds configuration checks.
go-linter-driven-development/​scripts/​ldd-detect_test.sh Adds setup fixture metadata.
go-linter-driven-development/​README.md Documents optional Go setup.
go-linter-driven-development/​CHANGELOG.md Records setup and compatibility changes.
docs/​quick-start.md Introduces optional recommended configurations.
core/​setup/​ruff.toml Shared Ruff configuration template.
core/​setup/​golangci.yaml Shared Go configuration template.
core/​setup/​eslint.config.ldd.mjs Shared ESLint configuration template.
core/​scripts/​ldd-lint.sh Updates threshold messages and directory handling.
core/​scripts/​ldd-lint_test.sh Adds routing, threshold, and tool checks.
core/​README.md Documents setup generation and validation.
core/​includes/​scripts/​ldd-lint-langs.sh Adds setup checks and threshold guidance.

Review effort: Balanced

Comment thread core/setup/eslint.config.ldd.mjs
Comment thread core/setup/eslint.config.ldd.mjs Outdated
Comment thread core/setup/ruff.toml Outdated
Comment thread core/setup/ruff.toml Outdated
- eslint.config.ldd.mjs: sonarjs/max-lines-per-function 50 and
  sonarjs/nested-control-flow 2, the limits R3 names (more than 50 lines or
  more than 2 nesting levels). They were 200 and 4.
- ruff.toml: max-nested-blocks 2, R3's nesting limit. It was 5.
- ruff.toml: the changed-files command passes NUL-delimited paths and
  exits 0 without running ruff when no Python file changed. Before, GNU
  xargs ran ruff once with no paths, and ruff checked the whole repository.
- The gap linter treats eslint.config.ldd.mjs at the repository root as a
  linter config. A repository that keeps the fragment as its own file and
  imports it hands file length to ESLint. Before, the gap linter still
  measured with its own default. A matrix case covers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@buzzdan
buzzdan merged commit aa70fbf into main Oct 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants