# Install: ./install.sh (or: pre-commit install && pre-commit install --hook-type pre-push) # Fast lint: pre-commit run --all-files # # Ordering rule for this repo: a hook lands only once the thing it gates is # already clean, so `pre-commit run --all-files` is green at every commit. # Hooks still to come, each blocked on its own cleanup: # - file-length blocked on the .tex/code splits and TODO-file-length-250.md # - mypy the six third-party-typing errors are GONE (ERSMS moved # to a typed DeclarativeBase; PSD has a scoped override). # Still blocked on ECOTE/NLP/EARIN, and on the fact that # mypy cannot run repo-wide -- many courses ship a main.py # and it stops at "Duplicate module named". It needs a # per-directory driver, not just a clean tree. # - dependency-freshness blocked on the upgrade itself; the gate and the # upgrade must land in the SAME commit or the repo is # instantly and permanently red # - trailing-whitespace / end-of-file-fixer these REWRITE files, so they get # their own reviewed cleanup commit first default_language_version: python: python3 default_stages: [pre-commit] fail_fast: false repos: # Landed 2026-08-29, the day the archive first reached zero ruff findings # repo-wide. Pinned exactly, per rules/dependency-freshness: 0.16.5 is the # newest stable. These hooks pass --force-exclude themselves, so the # vendored trees excluded in pyproject.toml stay excluded even though # pre-commit hands ruff explicit filenames. - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.16.5 hooks: - id: ruff-check types_or: [python, pyi, jupyter] - id: ruff-format args: [--check] types_or: [python, pyi, jupyter] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: # Structural checks only -- none of these rewrite a file. - id: check-merge-conflict - id: check-case-conflict - id: check-symlinks - id: destroyed-symlinks - id: detect-private-key # tsconfig*.json and .vscode/*.json are JSONC -- both TypeScript and # VS Code document comments and trailing commas as valid there, and # check-json uses a strict RFC parser. This is the wrong parser for # those files, not a defect being suppressed; every other .json is # still checked. (The one real failure this hook found, a committed # merge conflict in EARIN/.vscode/extensions.json, is fixed.) - id: check-json exclude: | (?x)^( .*/tsconfig[^/]*\.json| .*/\.vscode/[^/]*\.json )$ - id: check-toml - id: check-yaml args: [--unsafe] # 2 MB. The four 39 MB movies.csv copies are already tracked and stay # (approved decision 6); this stops the NEXT one. - id: check-added-large-files args: [--maxkb=2000] - repo: local hooks: # Coursework deliverables are allowed under the two course trees; # compiled output is allowed nowhere. See .binary-allowlist. - id: no-binaries name: block binary files outside the allowlist entry: scripts/check_no_binaries.sh language: script pass_filenames: true # A tracked file that .gitignore also matches fails silently on # `git add`. 130 of those were fixed by hand; this keeps them fixed. - id: ignore-consistency name: no tracked file is gitignored entry: scripts/check_ignore_consistency.sh language: script pass_filenames: false always_run: true # Thin shim into ~/src/utils, which owns the four markdown namespaces. - id: md-naming name: markdown naming convention entry: scripts/check_md_naming.sh language: system files: \.(md|markdown)$ # CLAUDE.md has always said a hook rejects these. Now one does. - id: no-suppressions name: no noqa or type-ignore comments entry: scripts/check_no_suppressions.sh language: script types_or: [python, pyi, jupyter] # -x so shellcheck FOLLOWS sourced files. The 44 per-course run.sh stubs # source scripts/course_lib.sh; without -x every one of them reports # SC1091 "not following", and the only other way to silence that is a # per-file disable, which is banned here. - id: shellcheck name: shellcheck entry: bash -c 'printf "%s\0" "$@" | xargs -0 -n 40 shellcheck -x' -- language: system types: [shell] exclude_types: [zsh]