home / skills / shipshitdev / library / linter-formatter-init
This skill initializes Biome-based linting, formatting, and testing with optional ESLint/Prettier and pre-commit hooks for JS/TS projects.
npx playbooks add skill shipshitdev/library --skill linter-formatter-initReview the files below or copy the command above to add this skill to your agents.
---
name: linter-formatter-init
description: Set up Biome (default) or ESLint + Prettier, Vitest testing, and pre-commit hooks for any JavaScript/TypeScript project. Uses Bun as the package manager. Use this skill when initializing code quality tooling for a new project or adding linting to an existing one.
---
# Linter Formatter Init
Set up comprehensive linting, formatting, and testing for JavaScript/TypeScript projects using **Biome 2.3+** (default), **Vitest**, and **Bun**.
**IMPORTANT**: Always uses Biome 2.3+ (latest) - never older versions.
## Purpose
This skill automates the setup of:
- **Biome** for linting + formatting (default, recommended)
- **Vitest** for testing with coverage (use `--vitest` flag)
- ESLint + Prettier (legacy, use `--eslint` flag)
- Husky + lint-staged for pre-commit hooks
- VS Code/Cursor settings for auto-format on save
- bun scripts for manual linting, formatting, and testing
## When to Use
Use this skill when:
- Starting a new JS/TS project
- Adding linting to an existing project without tooling
- Standardizing code quality across a team
- Setting up pre-commit hooks to enforce quality
## Quick Start
```bash
# Default setup (Biome) - RECOMMENDED
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project
# Use ESLint + Prettier instead (legacy)
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--eslint
# ESLint + Prettier with TypeScript
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--eslint \
--typescript
# Skip pre-commit hooks
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--no-hooks
# Add Vitest testing with 80% coverage threshold
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--vitest
# Full setup: Biome + Vitest + Husky
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--vitest \
--coverage 80
```
## What Gets Installed
### Dependencies
**Biome 2.3+ (default):**
- @biomejs/biome@latest (always latest, minimum 2.3+)
**Vitest (with --vitest):**
- vitest
- @vitest/coverage-v8
**ESLint + Prettier (legacy, with --eslint):**
- eslint
- prettier
- eslint-config-prettier
- eslint-plugin-prettier
- @typescript-eslint/parser (if --typescript)
- @typescript-eslint/eslint-plugin (if --typescript)
**Pre-commit hooks:**
- husky
- lint-staged
### Configuration Files (Biome - Default)
```
project/
├── biome.json # Biome config (lint + format)
├── .vscode/
│ └── settings.json # Auto-format on save
├── .husky/
│ └── pre-commit # Pre-commit hook
└── package.json # Updated with scripts + lint-staged
```
### Configuration Files (ESLint + Prettier - Legacy)
```
project/
├── .eslintrc.json # ESLint config
├── .prettierrc # Prettier config
├── .prettierignore # Prettier ignore patterns
├── .eslintignore # ESLint ignore patterns
├── .vscode/
│ └── settings.json # Auto-format on save
├── .husky/
│ └── pre-commit # Pre-commit hook
└── package.json # Updated with scripts + lint-staged
```
### Bun Scripts Added (Biome)
```json
{
"scripts": {
"lint": "biome lint .",
"lint:fix": "biome lint --write .",
"format": "biome format --write .",
"format:check": "biome format .",
"check": "biome check .",
"check:fix": "biome check --write ."
}
}
```
### Bun Scripts Added (Vitest)
```json
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui"
}
}
```
### Bun Scripts Added (ESLint + Prettier)
```json
{
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
```
## Biome Configuration (Default)
Biome is a fast, all-in-one linter and formatter. The default config includes:
```json
{
"$schema": "https://biomejs.dev/schemas/2.3.12/schema.json",
"assist": {
"actions": {
"source": { "organizeImports": "on" }
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": { "noForEach": "off" },
"style": { "noNonNullAssertion": "off" },
"suspicious": { "noArrayIndexKey": "off", "noExplicitAny": "warn" }
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "es5",
"semicolons": "always"
}
}
}
```
### Customization
After setup, customize `biome.json` to adjust:
- Linting rules
- Formatting preferences
- File ignore patterns
## Vitest Configuration (with --vitest)
When you use the `--vitest` flag, this skill creates a `vitest.config.ts`:
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node", // or "jsdom" for frontend
include: ["src/**/*.{test,spec}.{ts,tsx}", "**/*.{test,spec}.{ts,tsx}"],
exclude: ["node_modules", "dist", ".next", "build"],
coverage: {
provider: "v8",
reporter: ["text", "json", "html", "lcov"],
include: ["src/**/*.ts", "src/**/*.tsx"],
exclude: ["src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"],
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80,
},
},
mockReset: true,
restoreMocks: true,
},
});
```
### Coverage Thresholds
Default threshold is 80%. Customize with:
```bash
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/project \
--vitest \
--coverage 90 # Set to 90%
```
### Test Setup File
Creates `src/test/setup.ts` for global test configuration:
```typescript
import { expect, afterEach } from "vitest";
import { cleanup } from "@testing-library/react"; // For React projects
// Cleanup after each test
afterEach(() => {
cleanup();
});
```
## Pre-commit Hooks
When enabled (default), lint-staged runs on every commit:
**Biome (default):**
```json
{
"lint-staged": {
"*.{js,jsx,ts,tsx,json,css}": ["bunx biome check --write"]
}
}
```
**ESLint + Prettier (legacy):**
```json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml,yaml}": ["prettier --write"]
}
}
```
This ensures:
- All committed code passes linting
- All committed code is formatted
- No broken code enters the repo
## VS Code / Cursor Integration
The skill creates `.vscode/settings.json`:
**Biome (default):**
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.organizeImports.biome": "explicit",
"quickfix.biome": "explicit"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
```
**ESLint + Prettier (legacy):**
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
```
## Why Biome Over ESLint + Prettier?
- **Faster**: Written in Rust, 10-100x faster than ESLint + Prettier
- **Simpler**: One tool instead of two, one config file
- **No conflicts**: No need for eslint-config-prettier or similar workarounds
- **Better defaults**: Sensible rules out of the box
## Monorepo Support
For monorepos, run from the root:
```bash
python3 ~/.claude/skills/linter-formatter-init/scripts/setup.py \
--root /path/to/monorepo \
--monorepo
```
This adds root-level config that applies to all packages.
## Troubleshooting
### Pre-commit hooks not running
```bash
# Reinstall husky
bunx husky
chmod +x .husky/pre-commit
```
### Format on save not working (Biome)
1. Install the Biome extension in VS Code/Cursor
2. Set Biome as default formatter
3. Enable "Format on Save" in settings
### Format on save not working (ESLint + Prettier)
1. Install the Prettier extension in VS Code/Cursor
2. Set Prettier as default formatter
3. Enable "Format on Save" in settings
## Framework-Specific Configs (ESLint mode only)
When using `--eslint`, the skill detects common frameworks and adjusts config:
- **Next.js**: Adds `next/core-web-vitals` to ESLint
- **React**: Adds `eslint-plugin-react` and `eslint-plugin-react-hooks`
- **NestJS**: Adds rules for decorators and DI patterns
## Manual Setup (Alternative)
If you prefer manual setup over the script:
**Biome:**
```bash
bun add -D @biomejs/biome husky lint-staged
bunx biome init
bunx husky
```
**ESLint + Prettier:**
```bash
bun add -D eslint prettier eslint-config-prettier eslint-plugin-prettier husky lint-staged
bun add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
bunx eslint --init
bunx husky
```
Then copy configs from `~/.claude/skills/linter-formatter-init/assets/configs/`
This skill automates setup of linting, formatting, testing, and pre-commit hooks for JavaScript and TypeScript projects. It defaults to Biome (v2.3+), supports optional ESLint+Prettier legacy mode, adds Vitest for testing, and uses Bun as the package manager. Use it to quickly standardize developer tooling and enforce code quality.
Run the provided setup script pointing at your project root and choose flags for ESLint, TypeScript, Vitest, coverage thresholds, hooks, or monorepo mode. The script installs dependencies with Bun, writes config files (biome.json or .eslintrc/.prettierrc), updates package.json scripts and lint-staged, creates VS Code settings, and adds Husky pre-commit hooks. Vitest mode adds a vitest.config.ts, test setup file, and coverage thresholds.
Can I use ESLint and Prettier instead of Biome?
Yes—pass the --eslint flag to install ESLint and Prettier and generate the legacy config files and scripts.
How do I enable Vitest with coverage?
Use the --vitest flag; optionally pass --coverage <percent> to set the coverage thresholds (default 80%).
Will this modify package.json and add hooks automatically?
Yes. The script updates package.json with Bun scripts and lint-staged configuration and sets up Husky pre-commit hooks by default; use --no-hooks to skip hooks.
Does it support monorepos?
Yes. Run with --monorepo from the repo root to add root-level configs that apply across packages.