Linting and formatting setup expert using Biome and markdownlint-cli2. Use when users need to set up linters, configure Biome for TypeScript/JavaScript/CSS/JSON, configure markdownlint for Markdown files, migrate from ESLint/Prettier, or add code quality tooling to a project.
Configures Biome and markdownlint-cli2 for linting, formatting, and code quality in JavaScript, TypeScript, CSS, JSON, and Markdown projects.
npx claudepluginhub leobrival/topographic-plugins-officialThis skill is limited to using the following tools:
reference/commands-reference.mdreference/common-patterns.mdreference/troubleshooting.mdBiome is a fast all-in-one linter, formatter, and import organizer for JavaScript, TypeScript, JSX, CSS, JSON, GraphQL, and HTML. markdownlint-cli2 is the standard linter for Markdown files. This guide provides workflows for setting up both tools in any project.
# Install Biome (pin exact version)
bun add -D -E @biomejs/biome
# Initialize Biome config
bunx --bun biome init
# Check code (lint + format + imports)
bunx --bun biome check .
# Auto-fix all issues
bunx --bun biome check --write .
# Install markdownlint-cli2
bun add -D markdownlint-cli2
# Lint Markdown files
bunx markdownlint-cli2 '**/*.md' '!node_modules/**'
# Fix Markdown issues
bunx markdownlint-cli2 --fix '**/*.md' '!node_modules/**'
# Install both tools
bun add -D -E @biomejs/biome markdownlint-cli2
# Initialize Biome
bunx --bun biome init
Create biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"formatter": {
"indentStyle": "tab",
"lineWidth": 80
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "all"
}
},
"json": {
"formatter": {
"trailingCommas": "none"
}
}
}
Create .markdownlint.json:
{
"default": true,
"MD013": false,
"MD029": false,
"MD033": {
"allowed_elements": ["br", "details", "summary", "img"]
},
"MD060": false
}
Add npm scripts to package.json:
{
"scripts": {
"lint": "biome check .",
"lint:fix": "biome check --write .",
"format": "biome format --write .",
"lint:md": "markdownlint-cli2 '**/*.md' '!node_modules/**'",
"fix:md": "markdownlint-cli2 --fix '**/*.md' '!node_modules/**'"
}
}
# Migrate ESLint rules to Biome
bunx --bun biome migrate eslint --write
# Include inspired rules (slightly different behavior)
bunx --bun biome migrate eslint --write --include-inspired
# Migrate Prettier options to Biome
bunx --bun biome migrate prettier --write
# Suppress existing violations (clean migration)
bunx --bun biome lint --write --unsafe --suppress="migration from ESLint"
# Verify migration
bunx --bun biome check .
# Remove ESLint and Prettier when satisfied
bun remove eslint prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-react
rm .eslintrc* .prettierrc* .eslintignore .prettierignore
# CI mode: read-only check, exits non-zero on errors
bunx --bun biome ci .
# With GitHub reporter for annotations
bunx --bun biome ci --reporter=github .
# With JUnit for CI dashboards
bunx --bun biome ci --reporter=junit . > biome-report.xml
# Markdown lint in CI
bunx markdownlint-cli2 '**/*.md' '!node_modules/**'
GitHub Actions example:
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bunx --bun biome ci --reporter=github .
- uses: DavidAnson/markdownlint-cli2-action@main
with:
globs: "**/*.md"
# Install lint-staged and lefthook (or husky)
bun add -D lint-staged lefthook
Configure package.json:
{
"lint-staged": {
"*.{js,ts,jsx,tsx,css,json}": ["biome check --write --no-errors-on-unmatched"],
"*.md": ["markdownlint-cli2 --fix"]
}
}
Or use Biome's built-in git integration:
# Lint only staged files
bunx --bun biome check --staged --write
# Lint changes since default branch
bunx --bun biome check --changed --write
# Lint changes since specific ref
bunx --bun biome check --since=main --write
# Root biome.json (shared config)
# Each package can have its own biome.json that inherits
Root biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"formatter": {
"indentStyle": "tab"
},
"linter": {
"rules": {
"recommended": true
}
}
}
Package packages/frontend/biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"extends": ["../../biome.json"],
"linter": {
"domains": {
"react": "recommended"
}
}
}
Package packages/backend/biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"extends": ["../../biome.json"],
"javascript": {
"globals": ["Bun"]
}
}
When to use which tool:
biome checkbiome formatmarkdownlint-cli2biome check --writemarkdownlint-cli2 --fixbiome cibiome migrate eslint --writebiome migrate prettier --writebiome check --stagedbiome check --changed{
"linter": {
"rules": {
"recommended": true,
"style": {
"noNonNullAssertion": "warn",
"useConst": "error",
"useTemplate": "error"
},
"suspicious": {
"noExplicitAny": "warn",
"noDebugger": "error"
},
"complexity": {
"noForEach": "off"
}
},
"domains": {
"react": "recommended",
"test": "recommended"
}
}
}
{
"overrides": [
{
"includes": ["**/*.test.ts", "**/*.spec.ts"],
"linter": {
"rules": {
"suspicious": {
"noExplicitAny": "off"
}
}
}
},
{
"includes": ["scripts/**"],
"formatter": {
"lineWidth": 120
}
}
]
}
// Biome: suppress a specific rule
// biome-ignore lint/suspicious/noDebugger: needed for development
debugger;
// Biome: suppress formatting
// biome-ignore format: keep manual alignment
const matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
<!-- markdownlint-disable MD013 -->
Long line that should not be flagged.
<!-- markdownlint-enable MD013 -->
<!-- markdownlint-disable-next-line MD041 -->
Not a heading on the first line.
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
Common Issues:
Biome not found after install
bunx --bun biome or npx @biomejs/biome instead of bare biomeConfig not picked up
biome.json is in project root with biome rageESLint migration misses rules
--include-inspired --include-nursery flagsmarkdownlint too strict
MD013 (line length) in .markdownlint.jsonConflicts between Prettier and Biome
For detailed troubleshooting steps, see the Troubleshooting Guide.
Load as needed for detailed information:
Commands Reference - Complete CLI documentation for Biome and markdownlint-cli2 with all flags, configuration schema, and rule groups. Use when you need exact syntax or config options.
Common Patterns - Real-world patterns for project setup, migration recipes, monorepo configs, CI/CD integration, editor setup, and advanced rule configuration. Use for implementing specific setups.
Troubleshooting Guide - Detailed error messages, diagnosis steps, and resolution strategies for installation, configuration, migration, and runtime issues. Use when encountering errors or unexpected behavior.
When to use each reference:
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.