Skip to content

Instantly share code, notes, and snippets.

@d6veteran
Created March 26, 2026 23:17
Show Gist options
  • Select an option

  • Save d6veteran/67099611f15e3793291e7b4d8e13d065 to your computer and use it in GitHub Desktop.

Select an option

Save d6veteran/67099611f15e3793291e7b4d8e13d065 to your computer and use it in GitHub Desktop.
AI Writes Code Fast. Lint Keeps It Honest.

AI Writes Code Fast. Lint Keeps It Honest.

Why every AI-assisted codebase needs a linter before it needs a feature.


Your AI coding assistant just wrote 200 lines in 30 seconds. It's syntactically correct. It passes the tests you asked for. It looks clean.

But does it import a module it never uses? Does it shadow a variable three scopes up? Does it build a SQL query with string interpolation instead of parameterized inputs? Does it silently swallow an exception that will cost you a weekend in six months?

The AI doesn't know. It wasn't asked.

This is the gap that no one talks about when they celebrate AI-assisted development velocity. The code gets written faster. The review capacity doesn't scale with it. And the kinds of defects that linters catch — unused imports, unreachable branches, security anti-patterns, inconsistent style — are exactly the ones that human reviewers skip when they're drowning in AI-generated pull requests.


The velocity trap

Here's what I've seen happen, and you probably have too.

A team adopts AI-assisted coding. Velocity goes up. PRs go up. Lines changed per sprint go up. Everyone celebrates.

Six weeks later, the codebase has three different patterns for error handling. There are dead imports in half the files. Someone's AI assistant generated a database query using f-strings instead of parameterized queries — and it passed code review because the reviewer was looking at 14 other AI-generated PRs that day.

The problem isn't the AI. The AI is doing exactly what you asked — writing code quickly. The problem is that you removed the bottleneck on producing code without adding a corresponding check on qualifying it.

Lint is that check. It's the cheapest, fastest, most reliable quality gate you can put between AI-generated code and your main branch.


What lint actually catches

This isn't about tabs versus spaces. Modern linters are static analysis engines. Here's what a properly configured linter flags before a human reviewer ever sees the code:

Security anti-patterns. Ruff with bandit rules catches SQL injection via string formatting, hardcoded passwords, use of eval(), insecure deserialization, and weak cryptographic algorithms. ESLint with security plugins catches innerHTML, document.write, and eval in frontend code. These are the OWASP Top 10 in code form — and AI assistants generate them routinely because they optimize for "works" over "works safely."

Dead code. Unused imports, unreachable branches, variables assigned but never read. AI assistants are prolific generators of dead code because they write functions in isolation without full awareness of what the rest of the codebase already provides. A linter removes the noise before it accumulates.

Type and logic errors. Undefined variables, incorrect comparison operators, unreachable code after a return statement. These are the bugs that are trivial to write, invisible in a quick review, and expensive to debug in production.

Consistency. When three different AI sessions produce three different patterns for the same operation, the codebase drifts. Import ordering, naming conventions, string formatting — a linter enforces a single standard across every contributor, human or AI.


The math that should worry engineering leaders

Here's the calculation most teams skip.

Before AI, a senior engineer produces maybe 200 meaningful lines of code per day. A team of five produces 1,000. Your code review process, your CI pipeline, and your QA strategy are all calibrated for that volume.

With AI assistance, that same team produces 3,000-5,000 lines per day. But you didn't triple your reviewers. You didn't triple your QA capacity. You didn't change your CI pipeline at all.

So where does the quality check happen?

If the answer is "code review," you're already behind. Human reviewers catch architectural problems, logic errors, and design issues. They are terrible at catching unused imports, inconsistent style, and security anti-patterns buried on line 847 of a 900-line diff. That's not a criticism — it's a cognitive load problem. Linters don't get tired. They don't skip the boring parts. They don't rubber-stamp a PR because it's the ninth one they've reviewed today.

A linter running in CI catches an entire category of defects before a human reviewer ever opens the diff. That's not a nice-to-have. At AI-assisted velocity, it's the difference between a codebase that scales and one that quietly rots.


What "properly configured" means

Not all lint configurations are equal. Here's what matters:

Pick the right linter for your stack. Ruff for Python — it's fast, it replaces five tools (flake8, isort, pyupgrade, bandit, pydocstyle), and it runs in milliseconds. ESLint or Biome for JavaScript/TypeScript. SwiftLint for Swift. golangci-lint for Go. clippy for Rust. SQLFluff if your team writes SQL transformations.

Enable security rules. Most linters ship with security rule sets disabled by default. Turn them on. Ruff's S rules (bandit) catch the ten most common Python security mistakes. ESLint's security plugins catch the frontend equivalents. These rules exist because real codebases shipped real vulnerabilities that a linter would have caught.

Run it in CI as a blocking gate. A linter that only runs locally is a suggestion. A linter in CI that blocks the merge is a policy. If it doesn't block, it doesn't count.

Run it locally too. .pre-commit-config.yaml runs the linter before every commit. Developers — and the AI assistants they're using — get feedback in seconds instead of waiting for CI. The feedback loop matters more than the enforcement point.


The real cost of skipping it

I've watched projects accumulate what I call invisible debt — the kind that doesn't show up in any tracker because no one knows it's there.

An unused import isn't a bug. But 200 unused imports across 50 files make every search result noisier, every refactor riskier, and every new team member's onboarding slower. A hardcoded password in a test fixture isn't a production vulnerability — until someone copies that fixture into a deployment script. An inconsistent error handling pattern isn't a defect — until an engineer assumes the wrong convention and swallows an exception that causes a data loss incident at 2am.

These aren't dramatic failures. They're the slow, quiet erosion of codebase quality that makes everything take 20% longer than it should. And AI-assisted development accelerates the accumulation because the code is being produced faster than the conventions can be enforced manually.

Lint is the cheapest insurance policy in software engineering. It costs nothing to run, it catches defects that humans reliably miss, and it scales linearly with code volume — which is exactly the property you need when AI is multiplying that volume.


How I solved this for my team

I build with claude-team-cli — a CLI that gives Claude Code eleven specialist personas, each with deep domain expertise and structured behaviors. When I realized that AI-assisted velocity was outpacing my quality checks, I didn't add more review steps. I made lint a requirement that every engineering persona enforces automatically.

Now, when any engineer persona — backend, frontend, DevOps, security, QA, or data — encounters a new codebase, they check for lint configuration before writing a single line of code. If it's missing, they flag it. They don't proceed until it's addressed. Each persona frames it through their own lens: the backend engineer sees security anti-patterns, the QA lead sees a pre-test quality gate, the DevOps engineer sees a missing CI pipeline step, the security engineer sees a static analysis gap.

It's not a reminder. It's a prerequisite. And it's the single cheapest thing I've done to keep AI-assisted velocity from becoming AI-assisted technical debt.

The linter doesn't replace code review. It doesn't replace testing. It doesn't replace architecture decisions. But it clears the noise so that reviews, tests, and design discussions can focus on the things that actually require human judgment — instead of catching an unused import on line 12.


GitHub: code-katz/claude-team-cli | Works with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment