home / skills / shipshitdev / library / linter-formatter-init

linter-formatter-init skill

/bundles/workspace/skills/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-init

Review the files below or copy the command above to add this skill to your agents.

Files (7)
SKILL.md
9.0 KB
---
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/`

Overview

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.

How this skill works

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.

When to use it

  • Starting a new JavaScript or TypeScript project
  • Adding standardized linting/formatting to an existing repo
  • Enforcing pre-commit checks so commits are formatted and linted
  • Adding a fast, all-in-one toolchain (Biome) instead of ESLint+Prettier
  • Bootstrapping Vitest test runner with coverage enforcement

Best practices

  • Prefer the default Biome mode for speed and simplicity; Biome v2.3+ is required
  • Run the setup script from the project or monorepo root to apply configs consistently
  • Use --vitest with a coverage threshold to prevent regressions by test coverage
  • Keep biome.json or ESLint rules under source control and adjust rules incrementally
  • Install the editor extension (Biome or Prettier) and enable formatOnSave for developer consistency

Example use cases

  • New app scaffold: add Biome, Husky, lint-staged, and VS Code settings in one command
  • Existing repo without tooling: add lint/format scripts and pre-commit hooks to stop broken commits
  • Team standardization: enforce the same format and lint rules across multiple packages in a monorepo
  • Add testing: enable --vitest to create vitest.config.ts, setup file, and coverage scripts
  • Legacy projects: use --eslint to install ESLint+Prettier and framework-specific rules (Next.js, React, Nest)

FAQ

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.