Code Quality & Static Analysis
Deterministic feedback signals — linters, types, complexity limits, and LLM-generated lint rules.
These are the fastest feedback loops in your stack — they run on every edit, catch mistakes before tests ever need to, and require zero human attention once configured. For agents generating code at scale, deterministic quality checks are the first line of defense.
Linters, formatters & complexity
Linters and formatters are the lowest-cost, highest-leverage feedback signal available.
- Agents produce large volumes of code fast — linting catches repetitive mistakes before they accumulate
- Formatters eliminate style debates entirely; let the formatter own that
- Set up lint-on-edit and lint-on-commit as a baseline; agents should never bypass these
- Prefer autofixable rules — if a rule can't autofix, it creates friction; if it can, it's free quality
Recommended stack:
- JavaScript/TypeScript: ESLint + Prettier
- Python: Ruff (linter + formatter in one)
- Go: golangci-lint + gofmt
- SQL: prettier-plugin-sql with
/* sql */comment trigger
Complexity limits complement linters — functions above 10-15 cyclomatic complexity, 50-100 lines, or 3-4 parameters are hard for agents to modify safely. Use ESLint complexity, max-lines, and max-params rules to enforce thresholds.
Type safety
Type systems are a form of always-on automated testing. The stricter the types, the fewer runtime surprises.
- Enable strict mode in TypeScript (
"strict": true) — agents often generate code that only works in loose mode - Use Zod, Pydantic, or similar for runtime validation at system boundaries (API inputs, external data)
- Type your agent tool inputs and outputs explicitly — untyped tool interfaces cause subtle failures
- Treat
anyandunknownas technical debt - Use branded types for IDs to prevent mixing up
userIdandorderId
Use LLMs to write lint rules
Custom lint rules used to require deep AST knowledge. Now you can describe the constraint in plain English and have Claude generate the rule — including the autofix.
Example — enforce multi-line SQL queries:
// Before (triggers lint error)
const users = await db.query("SELECT * FROM users WHERE active = true")
// After (autofixed + Prettier formats the SQL)
const users = await db.query(/* sql */ `
SELECT *
FROM users
WHERE active = true
`)Any pattern worth a code review comment is worth a lint rule — enforce naming conventions, ban known-bad patterns, require logging on certain calls, codify architecture decisions as enforceable rules.