Claude Code Biome ESLint Prettier CLAUDE.md AI Coding 2026

Biome Ignores Your AI Agent's eslint-disable Comments. Here's the CLAUDE.md Fix (2026)

The Prompt Shelf ·

Biome is now a default recommendation for new JavaScript and TypeScript projects in 2026 — Vercel, Cloudflare, Discord, Microsoft, and Google all run it in production, and the headline benchmark (10,000 files linted in well under a second, formatting roughly 35x faster than Prettier) is real enough that “just use Biome” has become the standard answer in greenfield setup threads. The current stable release is 2.5.10 (August 2026). None of that is the problem. The problem is that most CLAUDE.md and AGENTS.md files were written — or absorbed into an agent’s habits — during the years when ESLint and Prettier were the only serious option, and an agent that reaches for eslint-disable-next-line in a Biome project doesn’t get an error. It gets a comment that does nothing at all.

The core gotcha: eslint-disable comments are just text to Biome

This is the one that causes real damage, because it fails silently. Biome does not parse, recognize, or honor eslint-disable in any form. If an agent hits a lint violation it wants to suppress and writes the ESLint comment out of habit, the comment sits there looking like a suppression — and the underlying rule still fires, in the editor and in CI, exactly as if the comment weren’t there.

// ❌ ESLint habit — Biome doesn't parse this comment at all.
// The rule still fires. CI still fails. The comment is dead text.
// eslint-disable-next-line no-unused-vars
const debugToken = getToken()
// ✅ Biome's suppression comment, with the exact rule path
// biome-ignore lint/correctness/noUnusedVariables: kept for a debug session, remove before merge
const debugToken = getToken()

The failure mode here isn’t “the agent’s fix doesn’t work” — it’s worse than that. The agent believes the violation is suppressed, moves on, and the diff looks clean in a quick read. The rule only reveals itself when CI runs biome ci (or whatever check step gates the merge) and the same violation comes back. If your CLAUDE.md doesn’t say anything about this, an agent trained on years of ESLint-dominant code will keep making this exact mistake project after project, because nothing about the syntax looks wrong to it.

Gotcha 2: biome-ignore requires a reason — eslint-disable doesn’t

Even once an agent knows to write biome-ignore instead of eslint-disable, the syntax itself trips a second habit. eslint-disable-next-line no-unused-vars is a complete, valid comment on its own. Biome’s suppression comment is not complete without a : reason clause after the rule path — and Biome 2.x actively warns when that reason is left as a placeholder like <explanation> rather than an actual sentence.

// ❌ Missing the required reason — Biome flags this
// biome-ignore lint/suspicious/noExplicitAny
function parseResponse(data: any) { ... }
// ✅ Rule path + mandatory reason
// biome-ignore lint/suspicious/noExplicitAny: third-party SDK ships no types
function parseResponse(data: any) { ... }

Biome also supports range suppressions (biome-ignore-start / biome-ignore-end, with the end comment optional if the range runs to the end of the file) and file-wide suppressions (biome-ignore-all, which must sit at the top of the file). None of these have an ESLint equivalent an agent can pattern-match from — /* eslint-disable */ at the top of a file is close in spirit to biome-ignore-all, but the rule-path-plus-reason requirement still applies.

Gotcha 3: the reflex to run eslint --fix or prettier --write

Command muscle memory is its own trap. An agent that’s about to commit formatted code reaches for npx eslint --fix . or npx prettier --write . because that’s the fix-it command that’s shown up thousands of times in its training data. In a Biome project, one of two things happens: the command fails outright because the packages were removed during migration, or — worse — they’re still installed as leftover dependencies and silently reformat files to different rules than biome.json specifies, creating a diff that fights the project’s actual formatter on the next biome check.

# ❌ Old muscle memory — either missing, or fighting biome.json's config
npx eslint --fix .
npx prettier --write .
# ✅ Biome's combined check-and-fix command
npx biome check --write .

# Lint only, no formatting
npx biome lint --write .

# CI-safe: fails without writing, for gating merges
npx biome ci .

Gotcha 4: “helpfully” scaffolding .eslintrc.json or prettier.config.js

Ask an agent to “set up standard tooling” for a project and there’s a real chance it creates .eslintrc.json and prettier.config.js from a general best-practices instinct — even in a repo that already has biome.json sitting at the root. The two configuration surfaces don’t merge or defer to each other; you end up with two formatters and two linters disagreeing about the same files, and whichever one runs last in a given script wins by accident. The instruction that closes this gap has to be explicit, because “don’t create redundant config” is exactly the kind of thing an agent won’t infer on its own from a repo that (to a model trained mostly on ESLint-era code) simply looks like it’s missing standard files.

The one-time migration commands — not something an agent should run repeatedly

If your project is migrating rather than starting fresh, Biome ships conversion commands that read existing config and port it over:

biome migrate eslint --write
biome migrate prettier --write

These are worth documenting in CLAUDE.md as reference, not as something an agent invokes on its own initiative. The official migration guide is specific about the gaps: YAML-format ESLint configs aren’t supported, “inspired” rules need an explicit --include-inspired flag to carry over, and rule naming conventions differ outright — ESLint uses kebab-case (no-unused-vars), Biome uses camelCase (noUnusedVariables). An agent that goes looking for a rule to configure using the ESLint spelling will search a namespace that doesn’t exist in biome.json, find nothing, and may conclude the rule isn’t supported at all when it’s just named differently. A migration is a one-time, human-reviewed event — not a step to fold into a routine feature branch.

The other quiet difference: VCS-aware ignoring

ESLint and Prettier both read .eslintignore / .prettierignore (or their ignorePatterns config) by default. Biome doesn’t ignore anything by default beyond its own hardcoded defaults unless you turn on VCS integration explicitly:

{
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  }
}

Without useIgnoreFile: true, Biome will happily lint and format files your .gitignore excludes — build output, generated code, vendored directories — which produces noisy diffs and violations in files nobody intended to touch. This is a one-line config fix, but it’s easy to miss precisely because ESLint and Prettier both did this automatically and never made you think about it.

Proof this isn’t a fringe concern: Biome’s own repo runs on AGENTS.md

Biome’s own AGENTS.md governs contributions to the Biome codebase itself, with task-specific detail pushed into .claude/skills/. The rules it states for its own contributors are worth noting for the pattern, not the specifics: claims about behavior require an exact file-and-line reference or a reproducible command, not “this is how Biome works” from memory, and narrow tests are run before broad ones. A project that builds a lint/format tool takes it seriously that an AI agent working on that tool needs explicit, checkable rules rather than vibes-based instructions — which is exactly the same argument for writing Biome-specific rules into the CLAUDE.md of every project that merely uses it.

The CLAUDE.md block

## Linting & Formatting (Biome)

- This project uses Biome, not ESLint or Prettier. Do NOT create
  `.eslintrc.json`, `eslint.config.js`, or `prettier.config.js` — the only
  config file is `biome.json`.
- Run `npx biome check --write .` to lint and format together. Do NOT run
  `eslint --fix` or `prettier --write` — those commands either fail (the
  packages aren't installed) or produce a diff that conflicts with
  `biome.json`.
- To suppress a lint rule, use `// biome-ignore <rule-path>: <reason>`
  (e.g. `// biome-ignore lint/suspicious/noExplicitAny: reason here`).
  A reason is REQUIRED — a comment without one is flagged as invalid.
  NEVER write `// eslint-disable-next-line` — Biome does not parse it,
  the comment does nothing, and the rule still fires in CI.
- Rule names are camelCase (`noUnusedVariables`), not ESLint's kebab-case
  (`no-unused-vars`). If a rule name from an ESLint doc doesn't resolve,
  check the camelCase spelling before assuming it's unsupported.
- `biome migrate eslint --write` / `biome migrate prettier --write` are
  one-time, human-run commands for porting old config. Don't run them as
  part of a routine feature change.
- `biome.json` needs `"vcs": { "enabled": true, "clientKind": "git",
  "useIgnoreFile": true }` or Biome will lint/format files `.gitignore`
  excludes.
- CI gating command: `npx biome ci .` (fails without writing — use this
  in pipelines, not `biome check --write`).

Drop this in alongside your framework-specific rules — it doesn’t conflict with anything else in a typical CLAUDE.md, since it only touches the lint/format layer. Our TypeScript CLAUDE.md rules guide is a natural companion if you’re setting up a new TypeScript project’s rules file from scratch, and the AI Coding Rules gallery has more verified CLAUDE.md and AGENTS.md examples if you want to see how other projects structure this section.

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules