Maturity Matrix

Basic linter rules

A shared linter configuration enforced in CI is the fastest, cheapest quality investment a team can make - and the essential foundation for every higher-level quality automation.

  • ·AI-assisted review tool (CodeRabbit, Qodo, or equivalent) is active on all repositories
  • ·Linter rules are configured and run in CI on every PR
  • ·PRs clearly indicate whether code is AI-generated or AI-assisted (labels, tags, or commit metadata)
  • ·AI review suggestions are triaged (accepted/rejected) rather than ignored
  • ·Linter configuration is committed to the repository and versioned

Evidence

  • ·AI review tool configuration in CI pipeline
  • ·Linter configuration file in repository
  • ·PR labels or commit metadata distinguishing AI-generated code

What It Is

Linting is automated static analysis that enforces code quality rules without running the code. ESLint for JavaScript/TypeScript, Pylint or Ruff for Python, golangci-lint for Go, Checkstyle for Java, RuboCop for Ruby - every major language ecosystem has one or more linting tools. These tools check for a range of issues: syntax errors, undefined variables, unused imports, potential null pointer dereferences, inconsistent formatting, overly complex functions, security anti-patterns, and violations of style conventions.

At L2 (Guided), the team has moved past individual developer choice on linting. A shared linter configuration is committed to the repository, every developer uses the same rules, and - critically - CI fails if linting fails. A PR that introduces lint errors cannot be merged until the errors are resolved. This is the key difference between L1 (where linting might exist on some developers' machines, informally) and L2: the rules are enforced by the build system, not by reviewer diligence.

Basic linter rules cover the obvious things: code formatting (indentation, line length, spacing), naming conventions, unused variables and imports, unreachable code, obvious potential errors (comparing with == instead of === in JavaScript, for example). The configuration is shared across the team but is deliberately not over-engineered - it catches the things everyone agrees on, without creating friction from overly opinionated rules.

This simplicity is intentional. At L2, the goal is getting the team to agree on and enforce a baseline. The more sophisticated use cases - custom lint rules that enforce architectural decisions - are the domain of L3 (Lint-as-architecture).

Why It Matters

Linting is among the highest-ROI investments in software quality because it catches a predictable class of issues automatically, before any human sees the code:

  • Eliminates the lowest-value review comments - "Use const instead of let here," "this import is unused," "missing semicolon" - these are review comments that waste reviewer attention. Linting handles them automatically, freeing reviewers for substantive feedback.
  • Enforces consistency without conflict - Style debates ("tabs vs spaces," "80 vs 120 column limit") are resolved once in the linter configuration, not relitigated in every PR review. The linter is the authority.
  • Catches errors before tests - Some lint rules catch real bugs (undefined variables, unreachable code, potential type errors). Finding these during lint is faster and cheaper than finding them during testing or production.
  • Makes onboarding easier - New team members don't need to memorize style conventions - the linter tells them when they've violated one. The configuration file serves as machine-readable documentation of team standards.
  • Foundation for advanced automation - L3's lint-as-architecture, L4's auto-merge policies, and L5's continuous auto-refactoring all depend on a trustworthy linting infrastructure. You can't build on top of inconsistent quality gates.

The key cultural shift at L2 is accepting that a machine will block your PR. Some developers initially resist having a bot tell them their code is wrong. The right framing is: "The linter is our agreed-upon standards, running automatically. It's what we would have told you in review anyway, just faster."

Tip

Start with a well-known shared configuration (Airbnb style guide for JavaScript, Google's Python style guide) and selectively override rules your team disagrees with. This is faster than building from scratch and ensures you're starting from a community-vetted baseline.

Getting Started

  1. Choose your linter - For JavaScript/TypeScript: ESLint (with Prettier for formatting). For Python: Ruff (fast, modern, covers most Pylint and Flake8 rules). For Go: golangci-lint. For Java: Checkstyle or SpotBugs. Pick the de facto standard for your ecosystem.
  2. Start from a shared community configuration - eslint:recommended, pylint --rcfile=google-style, golangci-lint defaults. Extend from there rather than building from scratch. This avoids hundreds of bikeshedding decisions about which rules to include.
  3. Commit the configuration to the repository - .eslintrc.json, pyproject.toml, .golangci.yml - whatever format your linter uses, commit it to the root of the repository. Every developer and CI uses the same file. No "works on my machine" linting.
  4. Add a CI check that fails on lint errors - In GitHub Actions, GitLab CI, or your CI system of choice, add a lint step that runs before tests. A failing lint check blocks the PR from merging. This is the step that makes linting real - without CI enforcement, it's just advisory.
  5. Fix existing violations in a dedicated PR - Before enforcing the linter on all PRs, fix the existing violations in one focused cleanup PR. Running eslint --fix or ruff --fix handles most automatically. This ensures the baseline is green before enforcement begins.
  6. Install the IDE plugin for every developer - ESLint, Pylint, and golangci-lint all have IDE plugins that show violations inline as you type. Catching lint errors before a push is faster than catching them in CI. Make IDE plugin installation a team onboarding step.

Common Pitfalls

Introducing too many rules at once. A linter configuration with 200 opinionated rules will generate hundreds of existing violations and substantial team pushback. Start with the minimum: errors (not warnings), the rules that every team member agrees matter. Add rules incrementally as the team builds tolerance for enforcement.

Using warnings instead of errors for important rules. Lint warnings that don't block CI are ignored. If a rule matters enough to have, make it an error that fails CI. If it doesn't matter enough to fail CI, consider removing it to reduce noise.

Inconsistent formatter and linter setup. ESLint (or Pylint) handles rule enforcement; Prettier (or Black) handles formatting. These tools need to be configured to not conflict. A common source of friction is running eslint --fix and having it conflict with Prettier's output. Use eslint-config-prettier to turn off ESLint formatting rules that conflict with Prettier.

Not auto-fixing in CI. Many lint violations can be automatically fixed by the linter itself. Consider adding a CI step that runs eslint --fix and commits the result if there are only auto-fixable violations. This reduces developer friction significantly for minor style issues.

How Different Roles See It

B
BobHead of Engineering

Bob's PRs frequently get comments like "add this import," "unused variable," "use camelCase here." These comments are taking up reviewer attention and creating unnecessary revision cycles. Two of his teams use ESLint, three don't. Codebases from different teams look visibly different in style, which causes friction when developers rotate between them.

What Bob should do: Bob should mandate a shared ESLint (or Ruff, or golangci-lint) configuration across all repositories within 30 days. This is not a big-bang change - it's adding a config file and a CI step. The immediate payoff: review comments about style and obvious errors disappear. The longer-term payoff: all codebases in the organization look similar, reducing friction when developers move between teams. Bob should treat the linter configuration as an organizational artifact owned by the tech leads collectively - they agree on it, it goes in a shared repository, and teams adopt it.

S
SarahProductivity Lead

Sarah's metrics show that style and convention comments account for about 25% of all PR review comments. She's calculated that eliminating these comments would save approximately 8 minutes per PR reviewed - across 45 PRs per day, that's 6 hours of reviewer time per day. She wants to propose linting as a cost-saving measure but needs to frame it in business terms.

What Sarah should do: Sarah has exactly the right framing already: 25% of review comments are automatable, and the cost to automate them is half a day of engineering work to configure the linter and CI check. She should present this as a 1-day investment that recovers 6 hours per day in perpetuity. The ROI is immediate and measurable - she can track it by tagging review comment categories before and after the linter is deployed. One caveat she should flag: the first sprint after deployment will involve fixing existing violations across the codebase. That's a one-time cost that pays for itself in the first week.

V
VictorStaff Engineer - AI Champion

Victor has been maintaining a personal ESLint configuration that he applies to his code, but it's not enforced on the rest of the team. He keeps leaving comments in review about issues his linter catches automatically on his machine. He's frustrated that the same issues recur every sprint.

What Victor should do: Victor should take his personal ESLint configuration, clean it up (remove the rules that are just personal preference, keep the ones that catch real issues), and propose it as the team's shared configuration. He should open a PR with the configuration file, the CI check, and a script to auto-fix existing violations. He can frame it as: "This is the review comments I leave most often, automated." Getting buy-in from 2-3 teammates before the PR is better than springing it on everyone. Once the linter PR is merged, Victor has removed himself as the enforcer of those rules - the CI is enforcing them instead, which is healthier for the team.

Where does your team actually sit on this?

This guide describes one level of one area. Run the assessment to place your team across all 16 areas, see which gates you have passed, and get a report you can take to your stakeholders.

Start the assessment