---
name: lint
description: 'Enforce zero-tolerance linting on every code change. This skill MUST be followed after writing or modifying any code file. Run the project linter, fix ALL violations, and never cut corners. Triggers on: lint, delint, fix lint errors, clean up code, run linter.'
---

# Lint — Zero Tolerance

**Every code change you make MUST pass the project linter with zero errors and zero warnings before you consider the work done.**

This is not optional. This is not "nice to have." This is a hard gate.

---

## The Rules

1. **Run the linter after every code change.** Not at the end. After every change.
2. **Fix ALL violations** in files you touched. Not just the ones you introduced — if you touched the file, you own it.
3. **Never disable lint rules** to make errors go away. Fix the code, not the config.
4. **Never skip files** with `// eslint-disable`, `# noqa`, `// nolint`, `@SuppressWarnings`, or any equivalent.
5. **Never leave warnings.** Warnings are errors you haven't fixed yet.
6. **Never claim "it was already there."** If you modified a line with a violation, you fix it. (Campsite Rule)
7. **Never report success with lint failures.** If the linter reports errors, you are not done.

---

## Step 1: Detect the Project Linter

Check for these in order:

| File / Config                                                     | Linter        | Command                                                     |
| ----------------------------------------------------------------- | ------------- | ----------------------------------------------------------- |
| `biome.json` or `biome.jsonc`                                     | Biome         | `pnpm biome check --write .` or `npx biome check --write .` |
| `.eslintrc.*` or `eslint.config.*` or `package.json` has `eslint` | ESLint        | `pnpm lint` or `npx eslint --fix .`                         |
| `pyproject.toml` with `[tool.ruff]`                               | Ruff          | `ruff check --fix .`                                        |
| `pyproject.toml` with `[tool.flake8]` or `.flake8`                | Flake8        | `flake8 .`                                                  |
| `pyproject.toml` with `[tool.pylint]` or `.pylintrc`              | Pylint        | `pylint **/*.py`                                            |
| `.rubocop.yml`                                                    | RuboCop       | `rubocop -a .`                                              |
| `Cargo.toml`                                                      | Clippy        | `cargo clippy --fix`                                        |
| `.golangci.yml`                                                   | golangci-lint | `golangci-lint run --fix`                                   |

Also check `package.json` scripts for a `lint` or `lint:fix` command — prefer the project's configured command over raw tool invocations.

If a `Makefile` has a `lint` target, use `make lint`.

If the project has a `.woodpecker.yml` or CI config, check what lint command CI runs — your local lint must match CI.

---

## Step 2: Run the Linter

```bash
# Preferred: use the project's configured lint command
pnpm lint          # or npm run lint, yarn lint
pnpm lint --fix    # auto-fix what can be auto-fixed

# Then check for remaining errors
pnpm lint
```

If the project doesn't have a `lint` script, run the detected tool directly (see table above).

---

## Step 3: Fix All Violations

### Auto-fixable violations

Most linters have a `--fix` flag. Use it first:

```bash
pnpm lint --fix
# or
npx eslint --fix .
# or
ruff check --fix .
```

### Manual violations

After auto-fix, re-run the linter without `--fix`. For each remaining error:

1. Read the rule name and understand WHY it exists
2. Fix the code to comply with the rule
3. Do NOT add a disable comment

### Common violations and correct fixes

| Violation                            | Wrong Fix                     | Right Fix                  |
| ------------------------------------ | ----------------------------- | -------------------------- |
| `no-unused-vars`                     | `// eslint-disable-next-line` | Delete the unused variable |
| `@typescript-eslint/no-explicit-any` | `// eslint-disable`           | Add a proper type          |
| `prefer-const`                       | Ignore it                     | Change `let` to `const`    |
| `no-console`                         | `// eslint-disable`           | Use the project's logger   |
| Import order                         | Ignore it                     | Let auto-fix sort imports  |
| `any` type                           | `as unknown as Type`          | Define the correct type    |

### The only acceptable exception

If fixing a violation would require a major refactor outside your task scope:

1. Do NOT disable the rule
2. Document it as a deferred item with rationale
3. Create a follow-up task/issue for the fix
4. The orchestrator (not you) decides if this is acceptable

---

## Step 4: Verify Clean

Run the linter one final time with no flags:

```bash
pnpm lint
```

Expected output: **zero errors, zero warnings.** If you see any output that isn't "all clear," you are not done.

---

## Step 5: Also Run Type Checking

Linting alone is not enough. If the project has TypeScript:

```bash
pnpm typecheck    # or npx tsc --noEmit
```

Fix ALL type errors too. The same zero-tolerance rules apply.

---

## For Orchestrated Workers

When you receive a task from an orchestrator, linting is part of the quality gates. Your workflow is:

```
1. Implement the change
2. Run lint --fix
3. Run lint (verify zero errors)
4. Run typecheck (if applicable)
5. Run tests
6. Only THEN report success
```

If you report `"status": "success"` with lint errors, you have failed the task.

---

## Quick Reference

```bash
# JavaScript/TypeScript
pnpm lint --fix && pnpm lint && pnpm typecheck

# Python
ruff check --fix . && ruff check . && mypy .

# Rust
cargo clippy --fix && cargo clippy

# Go
golangci-lint run --fix && golangci-lint run
```
