ESLint as a pre-commit hook, not a CI surprise

Lint failures arriving from CI ten minutes after a push are a context switch for something a machine could have fixed automatically before the commit existed.

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.js": ["eslint --fix", "git add"],
    "*.{css,scss}": ["stylelint --fix", "git add"]
  }
}

Running only on staged files is what keeps it fast enough to tolerate; linting the whole project on every commit is how a hook gets bypassed. --fix doing the mechanical corrections silently is most of the value, since formatting arguments in review are pure waste. The same rules have to run in CI as well, because a hook is advisory — anyone can skip it, and someone will.