biome — SKILL.md
Variant: standard · When to use: linting and formatting a JS/TS project with Biome v2.
Overview
Biome is a single Rust binary that lints, formats, and organizes imports for JavaScript, TypeScript, JSX, JSON, CSS, and GraphQL — one tool and one biome.json in place of the ESLint + Prettier stack. It is the JS/TS analog of Python's ruff: fast, opinionated defaults, one config. This skill covers installing Biome (v2), writing biome.json, the current CLI (including the biome ci gate), migrating an existing ESLint/Prettier setup, the v1→v2 changes that trip up stale knowledge, and authoring custom lint rules as GritQL plugins. Verified against Biome v2; confirm the exact current version when you install.
When to activate
- ✅ Adding lint + format to a JS/TS project (new or replacing ESLint/Prettier).
- ✅ Writing or fixing a
biome.json(formatter, linter rules, import organizing, VCS, overrides). - ✅ Wiring a lint/format CI gate.
- ✅ Migrating from ESLint/Prettier, or authoring a custom rule as a GritQL plugin.
Do NOT activate when:
- You need to wire Biome as a task in a Turborepo/pnpm pipeline — compose with the
turboreposkill; this skill owns Biome itself, not the task graph. - The project is Python — that's
ruff(Biome is the JS/TS counterpart, named here only as the analog).
Workflow
Step 1: Install + init
npm install --save-dev --save-exact @biomejs/biome # i.e. -D -E
npx biome init # writes biome.json
Step 2: Configure biome.json
{
"$schema": "https://biomejs.dev/schemas/<version>/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "includes": ["src/**", "!**/dist"] },
"formatter": { "enabled": true, "indentStyle": "space", "lineWidth": 100 },
"linter": { "enabled": true, "rules": { "recommended": true } },
"assist": { "enabled": true, "actions": { "source": { "organizeImports": "on" } } }
}
(biome init writes $schema with the version-pinned URL — don't ship the <version> literal.) Full schema — rule groups + linter.domains, language blocks, overrides, monorepo extends/root — in references/config.md.
Step 3: Run it
npx biome check --write . # lint + format + organize imports, apply SAFE fixes
npx biome check --write --unsafe . # also apply unsafe fixes
npx biome format --write . # format only; npx biome lint . # lint only
biome check runs all three (format, lint, import sort). Full command/flag reference + the v1→v2 CLI deltas: references/cli.md.
Step 4: CI gate
npx biome ci . # read-only: format + lint + import-sort checks, never writes
Use biome ci in CI (the analog of ruff check), never check --write (which mutates). Wire it as the lint/format job; defer the pipeline/caching to the turborepo skill.
Step 5: Migrate from ESLint / Prettier (if applicable)
npx biome migrate eslint --write # ports .eslintrc / flat config + .eslintignore
npx biome migrate prettier --write # ports .prettierrc
Details + caveats: references/migration-monorepo.md.
Step 6: Custom rules (optional) — GritQL plugins
Register a .grit plugin in biome.json plugins and write the pattern; full authoring guide (pattern syntax, register_diagnostic, a complete example, limitations) in references/gritql-plugins.md. Prefer a built-in rule first; reach for a plugin only when no rule covers the case.
Rules
Hard rules (never violate):
- Use the v2 CLI.
--write/--write --unsafeapply fixes; the v1--apply/--apply-unsafeare gone. Emitting--applyis the #1 stale-knowledge error — see Gotchas. biome ciis the CI gate, notcheck --write. CI must be read-only;check --writemutates the tree.- One
biome.jsonper project (useextendsfor nested/monorepo configs). Don't also run ESLint/Prettier for the same concerns — Biome replaces them.
Preferences (override-able):
- Biome's formatter defaults to tabs and a 2-space width with
lineWidth80. If the team standardizes on spaces (e.g. coming from Prettier), setformatter.indentStyle/lineWidthexplicitly. - Enable
vcs.useIgnoreFileso Biome respects.gitignore. - Start from
rules.recommendedand tighten per rule group as needed.
Gotchas
--applywas removed (v1→v2). v1 usedbiome check --apply/--apply-unsafe; v2 uses--write/--write --unsafe(--fixis an alias of--write). Stale snippets and old muscle memory emit--apply, which now errors. Seereferences/cli.md.- Import organizing moved. v1's top-level
organizeImportsis gone; in v2 it's an assist action underassist.actions.source.organizeImports. A v1-shaped config silently won't organize imports. include/ignore→includes(v2). v2'sfiles.includesis a single glob list using!-prefixed negations, replacing v1's separateinclude/ignore. A v1-shapedfilesblock is wrong.- Formatter default is tabs. Prettier users expecting spaces get tabs unless they set
indentStyle: "space".biome migrate prettieraligns it, but a freshbiome initdoes not. - GritQL plugins target JS and CSS only (currently). A plugin for another language won't run.
Anti-patterns
- Running ESLint + Prettier AND Biome for the same files. Double tooling, conflicting fixes, slower. Biome replaces them — migrate, don't stack.
biome check --writein CI. CI mutates the tree and can mask drift. Usebiome ci.- Reaching for a GritQL plugin when a built-in rule exists. Check the rule groups first; plugins are for genuinely custom checks.
- Duplicating the Turborepo pipeline here. Wiring Biome as a cached task belongs to the
turboreposkill; this skill stops at the Biome command.
Output
A configured biome.json plus the lint/format commands wired locally (biome check --write) and in CI (biome ci) — optionally migrated from an ESLint/Prettier setup and extended with custom GritQL rules. The consumer is the developer workflow and the CI gate that enforce a consistent, lint-clean codebase.
Related
turborepo— runbiome ci/checkas a cached pipeline task; this skill owns Biome, that one owns the task graph.vite— the build the linted/formatted code typically ships in.ruff— the Python lint+format analog Biome mirrors conceptually (different tool).
Progressive disclosure
references/config.md— load when writingbiome.json: full top-level schema, formatter/linter/assist options, rule groups,overrides, monorepoextends/root, and the v2 config-shape changes.references/cli.md— load when running Biome or wiring CI: all commands + flags, the--write/cisemantics, and the v1→v2 CLI delta table.references/gritql-plugins.md— load when authoring a custom rule: plugin registration, GritQL pattern syntax,register_diagnostic, a complete example, and limitations.references/migration-monorepo.md— load when migrating from ESLint/Prettier or configuring a monorepo: themigratecommands + caveats and theextends/rootmonorepo model.references/sources.md— research provenance.
Body budget
description≤ 1,024 chars; body ≤ ~500 lines / 5,000 tokens; heavy content inreferences/.