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.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- biome-setup Installs to ~/.agents/skills/biome-setup/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install biome-setup The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project biome-setup Installs to .agents/skills/biome-setup/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/biome-setup.zipunzip -o biome-setup.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) biome-setup PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
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.
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?
| Situation | Recommendation |
|---|---|
| New JS/TS project, no strong plugin needs | Biome for lint and format |
| ESLint + Prettier, mostly core and typescript-eslint rules | Migrate; 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 strictTypeChecked | Keep ESLint for those rules; Biome’s type inference covers some (for example floating promises) but not all |
| Vue, Svelte, Astro templates | Check 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.includesis 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 olderrecommended: trueflag;biome migrate --writeupdates old configs.- Domains (
react,next,solid,test,project,types) switch on rule groups for a framework.projectandtypesmake Biome scan dependencies, which costs time. - The
$schemapath pointing intonode_moduleskeeps 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 eslintreads the resolved ESLint config (flat or legacy), replaces the linter section ofbiome.json, sets the preset tononeand 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.useIgnoreFileand then reformattingdist/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
.jsoncor configurejson.parser.allowCommentsfor files liketsconfig.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.yaml
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.