Skip to content

refactor(tooling): replace ESLint + Prettier with Biome v2#720

Open
kylejryan wants to merge 3 commits intocanaryfrom
refactor/biome-integration
Open

refactor(tooling): replace ESLint + Prettier with Biome v2#720
kylejryan wants to merge 3 commits intocanaryfrom
refactor/biome-integration

Conversation

@kylejryan
Copy link
Copy Markdown
Collaborator

@kylejryan kylejryan commented May 6, 2026

Summary

Switches the lint/format toolchain from ESLint + Prettier to Biome v2.4.14 for JS/TS/JSX/TSX/JSON/CSS, with a slim Prettier install kept solely for Markdown and YAML (still in-progress in Biome v2 per its language support page). All ESLint rule choices and Prettier formatting defaults are preserved; behavior parity verified against the full CI suite.

Lines changed (excluding mechanical reformat)

Bucket Files LOC
Real changes (config, scripts, intentional source edits) 15 +523 / -530
Mechanical reformat (Biome's organizeImports import-sorting) 270 +1,305 / -1,339
Total 285 +1,828 / -1,869

The 270-file reformat commit is split out (commit `8f36d01b`) so reviewers can ignore it after a spot-check — every hunk in that commit is alphabetical import sorting, with no semantics changes.

Within the "real changes" bucket, ~157 of the 523 lines are `package.json` getting alphabetized by Biome's `useSortedKeys` (intended QoL), so true intent-only is closer to ~370 LOC of human-meaningful change.

Performance

End-to-end CI lint job timing on this dev machine, 3 warm runs each, median:

Step Old (ESLint+Prettier) New (Biome+slim Prettier) Speedup
Lint `src/` 1.757s 0.131s 13.4×
Format check (full repo) 2.583s 0.576s 4.5×
Combined CI lint job 4.340s 0.707s 6.1×

Biome utilizes ~700% CPU (parallel across cores) vs ESLint/Prettier's ~200% — the gap widens further on bigger CI boxes. And the new path does strictly more in that 0.7s (lint + format + import-organize, vs old format-only).

Behavior preserved

All ESLint rule choices ported 1:1:

  • `noExplicitAny`: error
  • `noNamespace`: error
  • `noUnusedImports`: error (was `unused-imports/no-unused-imports`)
  • `noUnusedVariables`, `useExhaustiveDependencies`, `noCommonJs`, `noUselessEscape*`: off (carryover)

Prettier formatting defaults are preserved (2-space indent, double quotes, semicolons, trailing commas all, line width 80) — Biome v2 defaults match Prettier 3.x defaults.

Quality-of-life additions

  • Single tool, single config (`biome.jsonc`)
  • Built-in import organizer on save (`source.organizeImports.biome`)
  • `useSortedKeys` on `package.json` keeps the manifest alphabetized
  • `vcs.useIgnoreFile` — single source of truth for ignore patterns (`.gitignore`)
  • Domain-aware lint rules (`react`, `test`) without third-party plugins
  • New scripts: `bun run check` (unified lint+format+organize), `bun run lint:fix` (auto-fix that didn't exist before)

Documented deviations from a vanilla port

Each rationale is inline in biome.jsonc:

  1. `useSortedKeys` scoped to `package.json` only via `overrides`. Globally enabling it scrambled `tsconfig.json`'s manually-grouped sections (3,300+ extra diagnostics).
  2. `a11y` recommended set turned off. This is a TUI codebase using opentui's ``/`` terminal primitives, not DOM. The recommended a11y rules misfired on every interactive ``.
  3. Triaged disables with rationale + "revisit in follow-up triage PR" notes for `noArrayIndexKey`, `noImplicitAnyLet`, `noAssignInExpressions`, `useIterableCallbackReturn`, `useHookAtTopLevel` (false-positive in `src/tui/keybindings/registry.ts`).
  4. `mdx` removed from Prettier scope to preserve the old `.prettierignore` exclusion (Fern docs use MDX features Prettier can't parse).

Source-code fixes (not reformatting)

7 files have intentional non-formatting changes:

Test plan

  • `bun run lint` — green
  • `bun run format:check` — green
  • `bun run tsc` — green (34s)
  • `bun run test` — green (905 passed, 16 skipped, 26s)
  • `bun run build` — green
  • CI green on this PR
  • VSCode Biome extension installed by reviewers, format-on-save verified

Follow-ups (deferred to a triage PR)

The 443 warnings + 321 infos surfaced by Biome's broader `recommended` ruleset are out of scope here. The disabled-with-rationale rules in `biome.jsonc` are tagged "revisit in a follow-up triage PR" so they show up via grep when that work is picked up.

Made with Cursor


Note

Medium Risk
Switches the project’s lint/format pipeline and editor integration from ESLint/Prettier to Biome, which can cause CI failures or noisy diffs if rule/format parity isn’t exact. Runtime code behavior should be unaffected aside from any fixes driven by new lint diagnostics.

Overview
Migrates linting/formatting from ESLint + Prettier to Biome v2.4.14 for JS/TS/JSON/CSS, while keeping Prettier only for Markdown/YAML.

Updates the reusable CI lint workflow (.github/workflows/lint.yml) and VSCode defaults (.vscode/settings.json) to run/fix via Biome (including import organization), adds a new biome.jsonc with rule/formatter settings and package.json-only key-sorting, and refreshes AGENTS.md command/CI documentation. Removes the repo’s .prettierignore in favor of Biome’s ignore/include configuration.

Reviewed by Cursor Bugbot for commit a65de54. Bugbot is set up for automated code reviews on this repo. Configure here.

kylejryan and others added 2 commits May 6, 2026 16:59
Switch the lint/format toolchain to Biome 2.4.14 for JS/TS/JSX/TSX/JSON/CSS;
keep a slim Prettier install for Markdown/YAML (still in-progress in Biome v2).
ESLint stack and eslint-config-prettier removed.

Why
- One binary, one config (biome.jsonc), ~6x faster CI lint job (4.34s -> 0.71s
  end-to-end on this dev box, with Biome doing strictly more work).
- Built-in import organizer (assist.actions.source.organizeImports), plus
  vcs.useIgnoreFile and per-file useSortedKeys on package.json.
- Domain-aware rules (react, test) without third-party plugins.

Behavior preserved
- All ESLint rule choices ported: noExplicitAny=error, noNamespace=error,
  noUnusedImports=error; noUnusedVariables/useExhaustiveDependencies/
  noCommonJs/noUselessEscape* off (carryover).
- Recommended ruleset enabled, with documented disables for rules that
  misfire on this codebase (a11y on TUI, useHookAtTopLevel false-positive
  in keybindings/registry.ts) plus targeted-disable + "revisit in follow-up
  triage PR" notes for noisy rules in existing patterns.

Scripts
- lint, format, format:check kept (now hybrid: Biome owns code, Prettier
  owns MD/YAML).
- New: lint:fix, check, check:ci.

Files
- New: biome.jsonc.
- Removed: eslint.config.js, .prettierignore.
- Tweaked: package.json, .vscode/settings.json, .github/workflows/lint.yml,
  AGENTS.md, bun.lock.
- Source-code fixes (not reformatting): converted 7 eslint-disable comments
  to biome-ignore in src/tui/auto-copy.ts, src/tui/console-theme.ts,
  src/core/agents/offSecAgent/offensiveSecurityAgent.ts,
  src/core/ai/streamIdleTimeout.test.ts, scripts/validate-shell.ts; removed
  two genuinely-unused imports surfaced by Biome's stricter noUnusedImports
  in scripts/test-sandbox-playwright.ts and src/tui/components/ascii-art.tsx.

Verification: bun run lint, format:check, tsc, test (905/921), build all green.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mechanical, no-semantics diff produced by a single `biome check --write` pass
with `assist.actions.source.organizeImports: "on"` from the previous commit.

What changed in each file
- Imports sorted alphabetically by module path
- Named-import members sorted alphabetically within each `{ }` group
- Type-only imports normalized to `import type` form

No behavior changes. No code edits. Spot-check any file with `git diff` —
every hunk is import reordering only. CI is green:
bun run lint / format:check / tsc / test (905/921 passing) / build.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kylejryan kylejryan force-pushed the refactor/biome-integration branch from 8f36d01 to 7919c01 Compare May 6, 2026 23:08
@kylejryan kylejryan marked this pull request as ready for review May 6, 2026 23:12
@github-actions github-actions Bot requested a review from Yuvanesh-ux May 6, 2026 23:13
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Reviewed by Cursor Bugbot for commit 7919c01. Configure here.

Comment thread .vscode/settings.json Outdated
Comment thread .vscode/settings.json Outdated
- Add source.organizeImports.biome to codeActionsOnSave so imports are
  auto-sorted on save (separate from source.fixAll.biome which only
  applies lint fixes)
- Remove [mdx] formatter override since MDX was intentionally excluded
  from Prettier scope (Fern docs use MDX features Prettier can't parse)

Co-authored-by: Kyle Ryan <kylejryan@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants