Different Stages, Different Powers
AI rules (CLAUDE.md, .cursorrules) operate at generation time: they guide the AI before code is written. The AI reads the rules and generates code that follows them. If the rule says "use async/await, not .then() chains": the AI generates async/await from the start. The code is: correct on first generation. No fix-after-the-fact needed. The power of AI rules: prevent bad patterns from being generated at all. The limitation: AI rules are suggestions — the AI may not follow them perfectly every time.
Linters (ESLint, Biome, Clippy, Ruff) operate at validation time: they analyze code after it is written and flag violations. If ESLint rule @typescript-eslint/no-floating-promises is enabled: any unhandled promise is flagged as an error. The code must be fixed before committing (pre-commit hook) or merging (CI check). The power of linters: absolute enforcement — violations cannot reach the codebase. The limitation: linters can only catch what they can statically analyze (patterns, syntax, types) — not architectural decisions, design choices, or conventions that require understanding intent.
The two tools enforce at different stages with different strengths: AI rules guide generation (intent-level, architectural, convention-based). Linters validate output (syntax-level, pattern-based, absolute enforcement). Together: the AI generates code that follows conventions (rules) and the linter catches anything the AI missed (validation). The two-layer approach: better code quality than either tool alone.
What AI Rules Handle That Linters Cannot
AI rules can enforce: architectural decisions ("use Server Components by default, add use client only for interactivity" — a linter cannot determine whether a component should be server or client), library selection ("use Zustand for global state, not Redux" — a linter cannot enforce which library to import), pattern preference ("prefer composition over inheritance for component reuse" — a linter cannot judge design patterns), and implementation approach ("for forms with 4+ fields, use React Hook Form" — a linter cannot count form fields and suggest a library).
AI rules operate at the intent level: they guide what the AI should build and how. "When implementing search, use Postgres full-text search with tsvector, not LIKE queries." A linter: can detect a LIKE query, but cannot suggest tsvector as the alternative. The AI rule: prevents the LIKE query from being generated in the first place by guiding the AI toward tsvector. The intent-level guidance is: proactive (prevents bad patterns) rather than reactive (catches bad patterns after generation).
The unique value of AI rules: they can encode team knowledge that no linter can express. "Our pagination uses cursor-based, not offset-based." "Our error responses follow the { error: { code, message, details } } format." "Our API versioning uses URL path (/api/v1/), not headers." These are: architectural conventions that require understanding the project context. Linters see: syntax and patterns. AI rules see: intent and architecture.
- Architecture: Server Components vs Client Components — linter cannot judge, AI rule guides
- Library selection: Zustand vs Redux, Drizzle vs Prisma — linter cannot enforce, AI rule directs
- Design patterns: composition vs inheritance, cursor vs offset pagination — intent-level
- Implementation approach: React Hook Form for complex forms, useState for simple — judgment-based
- AI rules are proactive (prevent bad patterns). Linters are reactive (catch bad patterns after writing)
AI rule: 'Use Postgres tsvector for search, not LIKE queries.' Linter: can detect a LIKE query but cannot suggest tsvector. The AI rule prevents the bad pattern at generation time. The linter catches it if the AI misses. Intent-level guidance (rules) + syntax-level validation (linters) = complete coverage.
What Linters Handle That AI Rules Cannot
Linters can enforce: absolute syntax rules (no unused variables — every violation caught, zero exceptions), type safety (no any type, no floating promises, no implicit returns — TypeScript strict with ESLint), import restrictions (no circular imports, no importing from internal modules, no importing deprecated packages — eslint-plugin-import), and code complexity (maximum function length, maximum nesting depth, cyclomatic complexity limits — eslint-plugin-complexity). These rules are: binary (pass or fail), exhaustive (every file checked), and enforceable (CI blocks violations).
Linters provide: absolute guarantees that AI rules cannot. An AI rule saying "never use any type" is: a suggestion the AI usually follows but may occasionally violate (under complex generic scenarios, the AI may fall back to any). An ESLint rule @typescript-eslint/no-explicit-any is: an absolute block — if any appears in the code, the commit is rejected. The linter catches: the 5% of cases where the AI did not follow the rule. The guarantee is: 100% enforcement, not 95% AI adherence.
Linters also catch: issues that AI rules cannot describe. Unused variables (the AI generated a variable it later deleted the usage for — the AI rule did not anticipate this). Circular imports (the AI created a dependency cycle across files it did not see together). Security vulnerabilities (eslint-plugin-security catches: regex DoS, prototype pollution, path traversal — patterns the AI may generate inadvertently). The linter is: the safety net that catches what the AI rules and the AI itself missed.
- Absolute enforcement: no any, no unused vars, no floating promises — 100% caught, zero exceptions
- Import restrictions: no circular imports, no deprecated packages — binary pass/fail
- Code complexity: max function length, max nesting, cyclomatic complexity — measurable limits
- Security: regex DoS, prototype pollution, path traversal — patterns AI may generate inadvertently
- Linters catch the 5% where AI did not follow the rule — the safety net for AI adherence gaps
AI rule 'never use any type': the AI follows this 95% of the time. Under complex generics, it may fall back to any. ESLint @typescript-eslint/no-explicit-any: catches the 5% with absolute enforcement. The linter is the safety net for AI adherence gaps — 100% enforcement vs 95% AI compliance.
The Overlap Zone: Preventing Conflict
Some standards appear in both AI rules and linter configs: naming conventions (AI rule: "use camelCase for variables" + ESLint: camelcase rule), async patterns (AI rule: "use async/await" + ESLint: no-floating-promises), and import style (AI rule: "use named imports" + ESLint: no-default-export). The overlap is: intentional and beneficial. The AI rule: prevents the pattern from being generated. The ESLint rule: catches it if the AI misses. Two layers of enforcement for the same standard.
Conflict risk: AI rule and linter disagree. Example: AI rule says "use default exports for page components" but ESLint has no-default-export enabled. The AI generates a default export (following the rule), ESLint rejects it (following the lint config), and the developer is stuck between two conflicting standards. Prevention: ensure AI rules and linter configs are aligned. When writing an AI rule about syntax or patterns: check that the linter config does not contradict it. Maintain: a mapping document or comment noting which AI rules have corresponding linter rules.
The alignment principle: AI rules should be a superset of linter rules. Everything the linter enforces: the AI rule should also guide toward (so the AI generates lint-clean code). Things the AI rule guides but the linter cannot enforce: are additional value from the AI rule (architecture, library selection, patterns). Things the linter enforces but the AI rule does not mention: are fine (the linter catches them post-generation). The conflict: only occurs when they disagree on the same standard. Alignment prevents this.
- Intentional overlap: AI prevents the pattern, linter catches if AI misses — two layers
- Conflict risk: AI rule says X, linter says not-X — developer stuck between contradictions
- Prevention: ensure AI rules and linter config are aligned — check for contradictions
- AI rules = superset of linter rules: guide toward everything the linter enforces, plus more
- Maintain alignment: document which AI rules have corresponding linter rules
The Two-Layer Enforcement Strategy
Layer 1 (AI rules, generation time): guide the AI toward correct architecture, patterns, library choices, and conventions. The AI generates: code that is 90-95% correct by convention. The remaining 5-10%: minor violations the AI missed (an unused import, a floating promise, a slightly wrong naming convention). Layer 1 handles: the big decisions (architecture, patterns, approach). It misses: the small details (syntax, unused code, edge cases).
Layer 2 (linter + formatter, validation time): catch and fix everything Layer 1 missed. ESLint: catches unused variables, floating promises, import issues, complexity violations. Prettier/Biome: fixes formatting (indentation, quotes, semicolons). TypeScript: catches type errors. Pre-commit hook: runs all three before the code enters the repository. CI: runs all three again to verify. Layer 2 handles: the small details with absolute enforcement. It cannot handle: the big decisions (those were made at Layer 1).
The two-layer result: the AI generates architecturally correct code (Layer 1) that is also syntactically clean (Layer 2). Without Layer 1: the linter catches syntax issues but the architecture may be wrong (correct syntax, wrong approach). Without Layer 2: the architecture is right but minor issues slip through (right approach, missed cleanup). Both layers together: the code is correct at every level — from architectural decision to semicolons.
- Layer 1 (AI rules): architecture, patterns, library choices. 90-95% correct by convention
- Layer 2 (linter + formatter): syntax, unused code, formatting. 100% enforcement on details
- Together: architecturally correct (L1) AND syntactically clean (L2) — correct at every level
- Without L1: correct syntax, possibly wrong architecture. Without L2: right approach, minor slips
- Pre-commit: linter + formatter + TypeScript. CI: same checks again for verification
Layer 1 (AI rules): generates architecturally correct code. Layer 2 (linter + formatter): catches syntax issues and auto-fixes formatting. Together: the code is correct from design decisions to semicolons. Without L1: correct syntax, wrong architecture. Without L2: right approach, minor slips. Both layers = complete quality.
Practical Setup: Rules + ESLint in Harmony
Step 1: write your AI rule file (CLAUDE.md or .cursorrules) with: architecture decisions, framework patterns, library choices, and convention rules. Step 2: configure ESLint to enforce: everything the AI rule mentions that is lint-enforceable (naming: camelcase, async: no-floating-promises, imports: no-restricted-imports for deprecated packages). Step 3: verify no conflicts (the AI rule and ESLint agree on every overlapping standard). Step 4: add a pre-commit hook (lint-staged + husky) that runs ESLint and Prettier on staged files. Step 5: add CI checks that run lint and typecheck on every PR.
The workflow in practice: developer describes a task to the AI. The AI reads CLAUDE.md (Layer 1): generates code following architecture and convention rules. The developer reviews and approves. Pre-commit hook runs (Layer 2): ESLint and Prettier catch and auto-fix minor issues. The commit enters the repository: architecturally sound and syntactically clean. CI runs: verifies the same standards on every PR. The code that reaches the main branch: passed both Layer 1 (AI generation guidance) and Layer 2 (linter validation). Double-checked at every step.
For teams using RuleSync: the dashboard maintains AI rules. The project also has: .eslintrc.js (or eslint.config.js), .prettierrc, tsconfig.json. These tools coexist: RuleSync generates CLAUDE.md (AI guidance), ESLint enforces syntax rules (validation), Prettier formats code (styling). There is no conflict because: each tool owns a different layer. RuleSync does not replace ESLint. ESLint does not replace CLAUDE.md. They complement at different stages of the code lifecycle.
Comparison Summary
Summary of AI rules vs linters.
- AI rules: generation-time, intent-level, architecture + patterns + library choices
- Linters: validation-time, syntax-level, absolute enforcement with binary pass/fail
- AI rules handle: what linters cannot (architecture decisions, design patterns, library selection)
- Linters handle: what AI rules cannot guarantee (100% enforcement, unused code, circular imports)
- Overlap: intentional — AI prevents, linter catches. Two layers better than one
- Conflict: prevent by aligning AI rules with linter config — both agree on every shared standard
- Two-layer strategy: L1 (AI rules) for big decisions + L2 (linter) for details = correct at every level
- Complement, do not replace: CLAUDE.md + ESLint + Prettier = generation guidance + validation + formatting