Linting
Fix machine-detectable code issues — run the project's linters and static analyzers, resolve or
justifiably suppress findings, and tighten config so real issues surface and noise dies down. This
is the automated quality gate, not a substitute for human review.
When to use
- Fixing a failing lint/static-analysis gate in CI or a pre-commit hook
- Tightening lint rules — turning on stricter rules, removing broad ignores, paying down
eslint-disable debt
- Running static analysis (type checkers, security linters, complexity analyzers) and triaging findings
- Establishing lint config for a new project or after a toolchain migration
- Triggers on "lint", "linting", "fix eslint", "static analysis", "lint 修复", "静态分析", "格式检查", "代码规范检查"
Not for: human-judgment review of a diff — smells, spec faithfulness, design (use code-review); diagnosing runtime behavior bugs (use debugging); behavior-preserving structural moves like extracting or splitting modules (use refactoring).
Steps
1. Detect the toolchain
Read the project before running anything. Don't impose a linter the project doesn't use.
- Find lint config and scripts:
package.json (lint script, eslint/biome/prettier config), pyproject.toml/setup.cfg (ruff/flake8/mypy), Cargo.toml (clippy), .golangci.yml, .editorconfig.
- Find the CI gate — what command does CI actually run? Lint locally with the same command, or you'll fix issues CI doesn't see and miss issues CI blocks on.
- If no toolchain exists, ask before introducing one — adding a linter is a project decision, not a drive-by.
2. Run and capture all findings
Run the linter/analyzer and capture the full output. Don't fix as you go — get the complete picture
first so you can triage by category, not react to the first error.
- Run with the project's configured command. For a first pass, also run with
--max-warnings 0 (or equivalent) so warnings don't slip past.
- Capture the raw output; note the rule code for every finding (e.g.
@typescript-eslint/no-explicit-any, F401, E501). The rule code is how you triage and how you suppress.
3. Triage — fix, suppress, or tighten
Sort every finding into one of three buckets. Never blanket-silence (eslint-disable *, # noqa: noqa, broad ignorePatterns) — that's the failure mode this skill exists to prevent.
- Fix — the finding is real. Fix the code. This is the default; most findings are real.
- Suppress with reason — the finding is a false positive or an intentional, justified exception. Suppress at the narrowest scope (inline, not file-level) and write the reason in the suppression comment. A suppression without a reason is noise that hides future real issues.
- Tighten config — the same noisy false positive recurs across the codebase. Rather than suppress everywhere, adjust the rule config (narrow its scope, set a threshold) so it fires only on real cases. This pays down the noise permanently.
If a finding is real but fixing it now is too risky (large behavior-touching change), suppress with a TODO and a reason and file it — don't silently disable.
4. Fix incrementally — re-run after each batch
Fix by rule category, not file-by-file at random. Resolving all no-unused-vars together is
reviewable; mixing five rule fixes into one change is not. Re-run the linter after each batch to
confirm the category is clear before moving on.
- Fix a category → re-run → clean for that category → next category.
- If a fix triggers new findings (common when tightening types), resolve those before moving on — don't leave the tree noisier than you found it.
5. Verify clean and config improved
- Full lint run is clean (or only justified suppressions remain).
- Every suppression carries a reason. No blanket silences, no file-level disables without justification.
- Config is tighter than before — recurring noise addressed at the config level, not suppressed ad hoc.
- The fix command matches what CI runs.
Verify
Red flags: blanket-disabling a rule to make the gate pass; file-level or project-level suppressions without reasons; fixing lint findings by editing the lint config to permit the smell; introducing a linter the project doesn't use without asking; a "lint fix" PR that also changes behavior; leaving the tree with more findings than it started because a fix triggered new ones.
References
- ${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md — shared discipline (verify don't assume, fix root causes not symptoms, surgical scope)
1---2name: linting3description: Use when fixing machine-detectable code issues — run linters and static analyzers (ESLint, Ruff, Clippy, golangci-lint), resolve findings, suppress false positives with justification, tighten config. Automated quality gate, distinct from human-judgment review. Triggers on "lint", "linting", "fix eslint", "static analysis", "lint 修复", "静态分析", "格式检查", "代码规范检查". Not for human-judgment code review (use code-review), runtime behavior bugs (use debugging), or behavior-preserving structural refactoring (use refactoring).4---56# Linting78Fix machine-detectable code issues — run the project's linters and static analyzers, resolve or9justifiably suppress findings, and tighten config so real issues surface and noise dies down. This10is the automated quality gate, not a substitute for human review.1112## When to use1314- Fixing a failing lint/static-analysis gate in CI or a pre-commit hook15- Tightening lint rules — turning on stricter rules, removing broad ignores, paying down `eslint-disable` debt16- Running static analysis (type checkers, security linters, complexity analyzers) and triaging findings17- Establishing lint config for a new project or after a toolchain migration18- Triggers on "lint", "linting", "fix eslint", "static analysis", "lint 修复", "静态分析", "格式检查", "代码规范检查"1920**Not for:** human-judgment review of a diff — smells, spec faithfulness, design (use `code-review`); diagnosing runtime behavior bugs (use `debugging`); behavior-preserving structural moves like extracting or splitting modules (use `refactoring`).2122## Steps2324### 1. Detect the toolchain2526Read the project before running anything. Don't impose a linter the project doesn't use.2728- Find lint config and scripts: `package.json` (`lint` script, `eslint`/`biome`/`prettier` config), `pyproject.toml`/`setup.cfg` (`ruff`/`flake8`/`mypy`), `Cargo.toml` (`clippy`), `.golangci.yml`, `.editorconfig`.29- Find the CI gate — what command does CI actually run? Lint locally with the same command, or you'll fix issues CI doesn't see and miss issues CI blocks on.30- If no toolchain exists, ask before introducing one — adding a linter is a project decision, not a drive-by.3132### 2. Run and capture all findings3334Run the linter/analyzer and capture the full output. Don't fix as you go — get the complete picture35first so you can triage by category, not react to the first error.3637- Run with the project's configured command. For a first pass, also run with `--max-warnings 0` (or equivalent) so warnings don't slip past.38- Capture the raw output; note the rule code for every finding (e.g. `@typescript-eslint/no-explicit-any`, `F401`, `E501`). The rule code is how you triage and how you suppress.3940### 3. Triage — fix, suppress, or tighten4142Sort every finding into one of three buckets. Never blanket-silence (`eslint-disable *`, `# noqa: noqa`, broad `ignorePatterns`) — that's the failure mode this skill exists to prevent.4344- **Fix** — the finding is real. Fix the code. This is the default; most findings are real.45- **Suppress with reason** — the finding is a false positive or an intentional, justified exception. Suppress at the narrowest scope (inline, not file-level) and write the reason in the suppression comment. A suppression without a reason is noise that hides future real issues.46- **Tighten config** — the same noisy false positive recurs across the codebase. Rather than suppress everywhere, adjust the rule config (narrow its scope, set a threshold) so it fires only on real cases. This pays down the noise permanently.4748If a finding is real but fixing it now is too risky (large behavior-touching change), suppress *with a TODO and a reason* and file it — don't silently disable.4950### 4. Fix incrementally — re-run after each batch5152Fix by rule category, not file-by-file at random. Resolving all `no-unused-vars` together is53reviewable; mixing five rule fixes into one change is not. Re-run the linter after each batch to54confirm the category is clear before moving on.5556- Fix a category → re-run → clean for that category → next category.57- If a fix triggers new findings (common when tightening types), resolve those before moving on — don't leave the tree noisier than you found it.5859### 5. Verify clean and config improved6061- Full lint run is clean (or only justified suppressions remain).62- Every suppression carries a reason. No blanket silences, no file-level disables without justification.63- Config is tighter than before — recurring noise addressed at the config level, not suppressed ad hoc.64- The fix command matches what CI runs.6566## Verify6768- [ ] Lint/static-analysis run is clean — no unresolved findings, or only narrow suppressions with reasons69- [ ] Every suppression has a written reason; no blanket silences (`eslint-disable *`, `# noqa: noqa`, broad ignores)70- [ ] Config tightened where noise recurred — recurring false positives fixed at the rule level, not suppressed everywhere71- [ ] Local fix command matches the CI gate command72- [ ] Fixes grouped by rule category, each batch re-run clean before moving on73- [ ] No behavior change introduced by fixes (if a lint fix requires behavior change, it's suppressed with TODO + filed, not forced)7475**Red flags:** blanket-disabling a rule to make the gate pass; file-level or project-level suppressions without reasons; fixing lint findings by editing the lint config to permit the smell; introducing a linter the project doesn't use without asking; a "lint fix" PR that also changes behavior; leaving the tree with more findings than it started because a fix triggered new ones.7677## References7879- [${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md](${CLAUDE_PLUGIN_ROOT}/references/engineering-principles.md) — shared discipline (verify don't assume, fix root causes not symptoms, surgical scope)