ADR-0015: Code Quality Tooling — ESLint + Prettier ⚠️ SUPERSEDED
Status: This ADR has been superseded. The project migrated from ESLint + Prettier to Biome (single-tool linter + formatter) on 2026-06-25. See
biome.jsonat repo root for the current configuration. This document is kept for historical reference.
Context
The Neemias monorepo (pnpm workspace) lacked automated code quality checks for JavaScript/TypeScript code. While markdownlint existed for documentation and Husky ran tests on pre-commit, there was no linter or formatter for the primary codebase (~200+ source files across app/, workers/, packages/).
The CI pipeline (deploy.yml) only triggered on version tags; PRs and push to main had no automated quality gates.
Decision
We introduce ESLint (static analysis) + Prettier (formatting) as the code quality foundation, deferring Turborepo (task orchestration + caching) to a future round.
Tool selection
| Concern | Choice | Why |
|---|---|---|
| Linter | ESLint 10 (flat config) | Industry standard, TypeScript-native via typescript-eslint, ESLint 10 is the latest major with stable flat config |
| TypeScript rules | typescript-eslint (tseslint.configs.recommended) | First-class eslint.config.js integration, @typescript-eslint rules tuned for strictness |
| React rules | @eslint-react/eslint-plugin | ESLint 10-compatible replacement for eslint-plugin-react (which broke on ESLint 10). Includes recommended rules + React Hooks checks built-in |
| Vite HMR safety | eslint-plugin-react-refresh | Warns when components are exported in ways that break React Refresh HMR |
| Formatter | Prettier 3 | Zero-config, widely adopted, eslint-config-prettier disables conflicting ESLint rules |
| Pre-commit | Husky + lint-staged | Runs ESLint --fix + Prettier --write on staged files, then unit tests, then smoke E2E |
Configuration approach
ESLint flat config (eslint.config.js) at workspace root, covering all packages:
- Ignores:
dist/,node_modules/,.wrangler/, generated docs, lock files - Base:
@eslint/jsrecommended - TypeScript:
typescript-eslintrecommended — strict mode reserved for future - React (tsx):
@eslint-reactrecommended +react-refresh/only-export-components - Relaxations:
no-console: off(console logging is intentional), unused vars with_prefix ignored - Prettier:
eslint-config-prettieras last layer to disable conflicting rules
Prettier (.prettierrc) at workspace root — single source of truth for formatting across all contributors.
lint-staged configured in package.json — only touches staged files, keeping pre-commit fast (~2s for a typical commit).
Scripts added to root package.json
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --check \"**/*.{ts,tsx,js,json,css,md}\"",
"format:fix": "prettier --write \"**/*.{ts,tsx,js,json,css,md}\""CI integration
The existing deploy.yml (tag-triggered) and future PR workflow (ci.yml) should run:
pnpm lintpnpm formatpnpm -r testpnpm docs:check
Consequences
Positive:
- Consistent code style enforced automatically (no more bikeshedding in reviews)
- TypeScript errors caught earlier (
no-unused-vars,no-explicit-any) - Pre-commit hook catches formatting + lints before code leaves the dev machine
- Flat config is future-proof and easy to extend per-package
Negative:
- Initial
eslint .may surface pre-existing warnings — these are expected and can be addressed incrementally; the config is intentionally lenient @eslint-reactis newer thaneslint-plugin-react; its rule set may differ slightly — adjust as the project's React patterns evolve
Risks:
- Pre-commit hook may feel slow on large commits (lint-staged mitigates by only scanning staged files)
- Turborepo (deferred) would bring caching — without it,
pnpm lintalways scans everything
🚫 Hard rule: no force push
During the v0.39.0 release a git push --force was mistakenly used to overwrite a tag (v0.35.0), requiring tag deletion, re-creation, and a corrective version bump to v0.39.0. This is a process incident.
Rule: git push --force and git push --force-with-lease are strictly prohibited on any shared branch or tag. See docs/community/contributing.md for the full policy.