Biome Setup skill for Codex

Swap ESLint and Prettier for Biome, knowing what you lose. Codex decides whether Biome should replace ESLint fully or only Prettier, runs biome migrate for both tools, and writes a rule coverage table showing which lint rules were mapped, replaced or dropped. It measures formatting churn before committing, isolates the reformat in its own commit, enables git ignore integration, and removes the old tools only after biome ci passes.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- biome-setup

Installs to ~/.agents/skills/biome-setup/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $biome-setup, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Sets up Biome 2 as the single linter and formatter for JavaScript, TypeScript, JSX, JSON and CSS - biome.json with files.includes, vcs integration, rule presets and domains, import sorting via assist, monorepo nested configs - and migrates from ESLint and Prettier with biome migrate eslint and biome migrate prettier while measuring formatting churn and lost rule coverage. Use when replacing ESLint plus Prettier with Biome, adding Biome to a new project, upgrading Biome 1 configs to v2, or wiring biome ci into pipelines and editors.

Use it when

  • Replacing ESLint plus Prettier with one faster tool
  • Starting a JS or TS project and choosing a linter and formatter
  • Upgrading a Biome 1.x configuration to Biome 2
  • Formatting differs between editors, hooks and CI

Use something else when

  • The project depends on ESLint plugins or deep typed rules Biome lacks: use eslint-setup
  • The code is Python rather than JavaScript or TypeScript: use ruff-setup

How to check the result

biome ci passes on the whole repo, the reformat commit is the only large diff, and the coverage table accounts for every ESLint rule that fired before the migration.

The mistake it prevents

Leaving vcs.useIgnoreFile off, so Biome formats and lints build output and vendored files that ESLint and Prettier used to skip via .gitignore.

~/.agents/skills/biome-setup/SKILL.md

--- name: biome-setup description: Sets up Biome 2 as the single linter and formatter for JavaScript, TypeScript, JSX, JSON and CSS - biome.json with files.includes, vcs integration,… license: MIT ---

Done well means Biome is the only formatter for the files it owns, lint coverage after a migration is known (what was kept, what was dropped, what was replaced), the one-time reformat is a single isolated commit, and biome ci gates pull requests.

Decide first: is Biome the right move?

SituationRecommendation
New JS/TS project, no strong plugin needsBiome for lint and format
ESLint + Prettier, mostly core and typescript-eslint rulesMigrate; Biome covers most of them and runs far faster
Heavy reliance on ESLint plugins Biome lacks (custom org rules, niche framework plugins)Biome as formatter only, keep ESLint for lint; or write GritQL plugins first
Needs full type-aware rules equal to typescript-eslint strictTypeCheckedKeep ESLint for those rules; Biome’s type inference covers some (for example floating promises) but not all
Vue, Svelte, Astro templatesCheck current Biome support for the template parts before committing; script blocks are supported, template linting is partial

State the trade-off to the user when rules will be lost. Do not migrate silently.

Inspect

ls biome.json biome.jsonc .eslintrc* eslint.config.* .prettierrc* prettier.config.* .editorconfig 2>/dev/null
npx @biomejs/biome --version 2>/dev/null
grep -nE '"(lint|format|check)' package.json

Read AGENTS.md for the package manager and existing scripts.

Install and initialise

npm install --save-dev --save-exact @biomejs/biome   # pin exact: formatting output changes between versions
npx @biomejs/biome init                               # writes biome.json

Needs network for the install; ask for approval in an offline sandbox.

Reference biome.json

{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true, "defaultBranch": "main" },
  "files": {
    "includes": ["**", "!**/dist", "!**/coverage", "!**/*.generated.ts", "!!**/node_modules"]
  },
  "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 100 },
  "javascript": {
    "formatter": { "quoteStyle": "double", "semicolons": "always", "trailingCommas": "all" }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "preset": "recommended",
      "suspicious": { "noExplicitAny": "error" },
      "correctness": { "noUnusedVariables": "error", "noUnusedImports": "error" }
    },
    "domains": { "react": "recommended", "test": "recommended" }
  },
  "assist": { "actions": { "source": { "organizeImports": "on" } } },
  "overrides": [
    { "includes": ["**/*.test.ts", "tests/**"], "linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } } }
  ]
}

Key behaviours:

  • files.includes is an allow list processed in order; ! excludes from lint and format, !! also stops the scanner from indexing the path (use for huge or vendored directories).
  • Without vcs.useIgnoreFile, Biome does not read .gitignore, unlike ESLint and Prettier. Turn it on or build output gets formatted.
  • linter.rules.preset (recommended, all, none) replaces the older recommended: true flag; biome migrate --write updates old configs.
  • Domains (react, next, solid, test, project, types) switch on rule groups for a framework. project and types make Biome scan dependencies, which costs time.
  • The $schema path pointing into node_modules keeps editor validation in sync with the installed version.

Migrating from ESLint and Prettier

npx @biomejs/biome migrate eslint --write                     # rules identical to ESLint originals
npx @biomejs/biome migrate eslint --write --include-inspired  # also rules "inspired by" ESLint ones
npx @biomejs/biome migrate prettier --write                   # writes every formatter option explicitly
  • migrate eslint reads the resolved ESLint config (flat or legacy), replaces the linter section of biome.json, sets the preset to none and enables only the mapped rules. Review the output; it reports rules it could not map.
  • If it fails with a cyclic reference, comment out plugins and shared configs, migrate, and add their rules back by hand.
  • Record coverage before deleting ESLint: list the ESLint rules that produced violations in the last month of CI or on the current tree, and mark each as mapped, replaced by another Biome rule, or dropped.
npx eslint . -f json -o /tmp/eslint.json   # before removing ESLint
node -e 'const r=require("/tmp/eslint.json");const c={};for(const f of r)for(const m of f.messages)c[m.ruleId]=(c[m.ruleId]||0)+1;console.table(c)'
  • Formatting: Biome matches Prettier output closely but not byte for byte. Measure churn on a clean tree before committing to it:
npx @biomejs/biome format --write . && git diff --shortstat && git diff --stat | tail -5

If churn is large, check lineWidth, quoteStyle, trailingCommas, arrowParentheses and bracketSameLine against the old Prettier config. Then decide with the user whether to accept the remaining differences.

Daily commands

npx @biomejs/biome check --write .               # format + lint + organize imports, safe fixes
npx @biomejs/biome check --write --unsafe .      # also unsafe fixes; review the diff
npx @biomejs/biome check --staged --write        # pre-commit: staged files only
npx @biomejs/biome check --changed --since=main  # CI on a branch: changed files only
npx @biomejs/biome ci .                          # read-only, CI-friendly reporter, non-zero on any issue
npx @biomejs/biome explain noFloatingPromises    # rule documentation offline

Package scripts:

{ "scripts": { "check": "biome check --write .", "ci:check": "biome ci ." } }

Suppressions need a reason: // biome-ignore lint/suspicious/noExplicitAny: third-party callback. biome-ignore-all (top of file) and biome-ignore-start / biome-ignore-end ranges exist for generated or legacy sections.

Monorepos

Put one biome.json at the root. A package that needs different settings gets its own biome.json with "extends": "//", which inherits from the root and is treated as non-root automatically. Other nested configs must set "root": false. Run Biome from the root; it applies the nearest config per file.

Cut-over workflow

- [ ] 1. Inspect configs; decide full migration vs formatter-only
- [ ] 2. Install pinned Biome; run migrate eslint and migrate prettier
- [ ] 3. Write the rule coverage table (mapped / replaced / dropped)
- [ ] 4. Measure format churn; tune options; get the user's go-ahead
- [ ] 5. Commit config; then commit the reformat alone; add its SHA to .git-blame-ignore-revs
- [ ] 6. Remove ESLint/Prettier packages, configs and editor settings only after CI is green
- [ ] 7. Update scripts, hooks, CI and the editor extension recommendation

Editors: recommend the biomejs.biome VS Code extension and set it as the default formatter for JS/TS/JSON in .vscode/settings.json, with Prettier disabled for those languages, or the two will race on save.

Gotchas

  • Not pinning the exact version: a patch release can change formatting and turn CI red on unrelated PRs.
  • Forgetting vcs.useIgnoreFile and then reformatting dist/ or vendored code.
  • Keeping Prettier in lint-staged or the editor after the switch, so files flip between two formats on every save.
  • Treating a quieter lint run as success. Fewer findings after migration usually means rules were dropped; the coverage table is the evidence.
  • JSON with comments: name it .jsonc or configure json.parser.allowComments for files like tsconfig.json, which Biome handles as JSONC by known name.

Report: Biome version, rule coverage table, formatting churn (files and lines), removed packages, and new scripts and CI steps.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Biome Setup"
  short_description: "Swap ESLint and Prettier for Biome, knowing what you lose"
  default_prompt: "$biome-setup Replace ESLint and Prettier with Biome in this repo and tell me which rules we lose"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
New

Introducing Codex Skills Pro

79 professional skills that take Codex through complete engagements, each with its own scripts, references and a report that verifies the result.

All-AccessOne-time payment, no subscription
$49
Get All-AccessOr browse individual skills from $2.99 →

Secure checkout by Creem