# ============================================================================== # Pre-commit Configuration - Multi-language Linting & Formatting # ============================================================================== # Install: pre-commit install && pre-commit install --hook-type pre-push # Fast lint: pre-commit run --all-files (linters only, ~10 s) # Full suite: pre-commit run --all-files --hook-stage pre-push (+ tests) # Update hooks: pre-commit autoupdate # ============================================================================== # Global settings default_language_version: python: python3 # By default every hook runs ONLY at commit-time. Pre-push runs only the # hooks that explicitly opt in via `stages: [pre-push]` (currently # pytest-coverage + prettier). This keeps `git push` cheap; commit-time # already enforces the full lint suite. default_stages: [pre-commit] # Fail fast on first error (set to false to see all errors) fail_fast: false # Configuration ci: autofix_commit_msg: "style: auto-fix by pre-commit hooks" autoupdate_commit_msg: "chore: update pre-commit hooks" repos: # =========================================================================== # GENERAL HOOKS - File formatting and validation # =========================================================================== - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: end-of-file-fixer - id: check-yaml args: [--unsafe] - id: check-json # Exclude JSONC files (VS Code configs, TypeScript configs) exclude: ^(\.vscode/|.*/\.vscode/|.*tsconfig.*\.json) - id: check-toml - id: check-xml - id: check-added-large-files args: [--maxkb=2000] - id: check-merge-conflict - id: check-case-conflict - id: check-symlinks - id: check-executables-have-shebangs - id: check-shebang-scripts-are-executable - id: detect-private-key - id: debug-statements - id: name-tests-test args: [--pytest-test-first] - id: check-ast - id: check-builtin-literals - id: check-docstring-first - id: fix-byte-order-marker - id: mixed-line-ending args: [--fix=lf] - id: requirements-txt-fixer # =========================================================================== # BINARY BLOCKER - Prevent binary/image files from being committed # =========================================================================== - repo: local hooks: - id: no-binaries name: Block binary/image files entry: meta/scripts/check_no_binaries.sh language: script always_run: false - id: ai-evidence-contract name: Require AI evidence artifacts for code changes entry: meta/scripts/check_ai_evidence.sh language: script pass_filenames: false always_run: true - id: ai-multifile-contract name: Require workflow contract for multi-file code changes entry: meta/scripts/check_agent_contract.sh language: script pass_filenames: false always_run: true - id: append-only-sessions name: Enforce append-only session logs entry: meta/scripts/check_append_only_sessions.sh language: script pass_filenames: false always_run: true # =========================================================================== # POLLING SCRIPT LINTER - Detect fork-storm anti-patterns in shell scripts # =========================================================================== - repo: local hooks: - id: no-polling-antipatterns name: Block polling script anti-patterns entry: meta/scripts/check_polling_antipatterns.sh language: script types: [shell] require_serial: true exclude: ^(\.git/|phone_focus_mode/lib/tests/|tests/) # =========================================================================== # NOQA BLOCKER - Zero tolerance for noqa/type:ignore suppression comments # =========================================================================== - repo: local hooks: - id: no-noqa name: Block noqa comments entry: '(?i)#\s*(noqa|type:\s*ignore)' language: pygrep types: [python] - id: no-ruff-noqa name: Block ruff noqa file-level comments entry: '(?i)#\s*ruff:\s*noqa' language: pygrep types: [python] # =========================================================================== # RUFF - Fast Python linter and formatter (replaces black, isort, flake8, etc.) # =========================================================================== - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.2 hooks: # Linter - run first to catch issues - id: ruff args: - --fix - --unsafe-fixes - --exit-non-zero-on-fix - --show-fixes types_or: [python, pyi] # Formatter - run after linting - id: ruff-format types_or: [python, pyi] # =========================================================================== # MYPY - Static type checking (per-commit on changed files only) # Was on pre-push, but force-push diffs caused full-repo scans + OOM. On # pre-commit it sees only the file(s) currently staged → near-instant. # =========================================================================== - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.13.0 hooks: - id: mypy stages: [pre-commit] args: - --ignore-missing-imports - --no-error-summary - --disable-error-code=no-untyped-def - --disable-error-code=no-untyped-call - --disable-error-code=var-annotated - --disable-error-code=no-any-unimported - --disable-error-code=type-arg - --disable-error-code=no-any-return - --disable-error-code=misc - --disable-error-code=unused-ignore - --disable-error-code=unreachable - --disable-error-code=assignment - --disable-error-code=no-redef - --disable-error-code=attr-defined - --disable-error-code=arg-type - --disable-error-code=union-attr - --disable-error-code=call-overload - --disable-error-code=return-value - --disable-error-code=redundant-cast - --disable-error-code=empty-body - --disable-error-code=list-item exclude: >- (?x)^( Bash/.*| \.venv/.*| linux_configuration/scripts/single_use/misc/testsAndMisc-bash/tools/.* )$ additional_dependencies: - types-requests - types-PyYAML - types-python-dateutil # =========================================================================== # PYLINT - Comprehensive Python linter (per-commit on changed files only) # Was on pre-push, but force-push diffs caused full-repo scans + OOM. # =========================================================================== - repo: https://github.com/pylint-dev/pylint rev: v3.3.2 hooks: - id: pylint stages: [pre-commit] args: - --rcfile=pyproject.toml - --fail-under=8.0 - --jobs=4 additional_dependencies: - pytest - python-chess - requests - pygame exclude: ^(Bash/|\.venv/) # =========================================================================== # BANDIT - Security linter (per-commit on changed files only) # Was on pre-push, but force-push diffs caused full-repo scans + OOM. # =========================================================================== - repo: https://github.com/PyCQA/bandit rev: 1.7.10 hooks: - id: bandit stages: [pre-commit] args: - -c - pyproject.toml - --severity-level=high - --confidence-level=medium - --skip=B113 additional_dependencies: ["bandit[toml]"] exclude: ^(Bash/|\.venv/|tests/|.*test.*\.py$) # =========================================================================== # PYTEST + COVERAGE - Run tests and enforce 100% code coverage # Only tests for subpackages with changed files are run (see script). # Uses pytest-xdist (-n auto) to parallelize across all CPUs. # =========================================================================== - repo: local hooks: - id: pytest-coverage name: pytest with coverage enforcement entry: python meta/scripts/pytest_changed_packages.py language: system types: [python] pass_filenames: true require_serial: true stages: [pre-commit] # =========================================================================== # VULTURE - Dead code detection (disabled - doesn't work well with pre-commit) # =========================================================================== # - repo: https://github.com/jendrikseipp/vulture # rev: v2.13 # hooks: # - id: vulture # args: # - --min-confidence=80 # - --exclude=.venv,Bash,__pycache__ # exclude: ^(Bash/|\.venv/) # =========================================================================== # PYUPGRADE - Upgrade Python syntax (disabled - incompatible with Python 3.14) # =========================================================================== # - repo: https://github.com/asottile/pyupgrade # rev: v3.19.0 # hooks: # - id: pyupgrade # args: # - --py310-plus # =========================================================================== # CODESPELL - Spell checking in code (expanded ignore list for non-English) # =========================================================================== - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: - id: codespell args: - --skip=*.json,*.lock,*.min.js,*.min.css,.git,__pycache__,.venv,*.txt - --ignore-words-list=als,ans,ect,nd,som,sur,te,nam,numer,lew,sie,wil,postion,clen,ther,folow,derrive,ony,tje,noe,theses,crate,doubleclick,wile,tabel,pary,blok,bloc,proces,serwer,parametr,adres,hart,dout,metod,tekst,synonim,grup,mosty,lokal,skalar,milion,nowe,tre,hel,alph exclude: ^(Bash/ffmpeg-build/|LaTeX/|.*\.geojson$) # =========================================================================== # DOCFORMATTER - Format docstrings (disabled - causes recursion errors) # =========================================================================== # - repo: local # hooks: # - id: docformatter # name: docformatter # entry: docformatter # language: system # types: [python] # args: # - --in-place # - --wrap-summaries=88 # - --wrap-descriptions=88 # =========================================================================== # INTERROGATE - Docstring coverage (disabled - causes recursion on large files) # =========================================================================== # - repo: https://github.com/econchick/interrogate # rev: 1.7.0 # hooks: # - id: interrogate # args: # - --fail-under=0 # - --verbose # - --ignore-init-method # - --ignore-init-module # - --ignore-magic # - --ignore-private # - --ignore-semiprivate # - --exclude=Bash,.venv,__pycache__ # pass_filenames: false # =========================================================================== # AUTOFLAKE - Remove unused imports/variables # Disabled: fully redundant with ruff (F401, F841, F811) + --fix # =========================================================================== # - repo: https://github.com/PyCQA/autoflake # rev: v2.3.1 # hooks: # - id: autoflake # args: # - --in-place # - --remove-all-unused-imports # - --remove-unused-variables # - --remove-duplicate-keys # - --expand-star-imports # =========================================================================== # SAFETY - Check for security vulnerabilities in dependencies # =========================================================================== # Note: Safety requires API key for full functionality, disabled by default # - repo: https://github.com/Lucas-C/pre-commit-hooks-safety # rev: v1.3.2 # hooks: # - id: python-safety-dependencies-check # files: requirements.*\.txt$ # =========================================================================== # PYRIGHT - Microsoft's type checker (very strict, optional) # =========================================================================== # Uncomment to enable - can be slow and very strict # - repo: https://github.com/RobertCraiworthy/pyright-action # rev: v1.1.350 # hooks: # - id: pyright # =========================================================================== # CHECK JSON/YAML/TOML formatting (runs on push only — slow Node.js startup) # =========================================================================== - repo: local hooks: - id: prettier name: prettier (capped scope) # Wrapper runs prettier inside its own systemd-run scope so its # memory budget is independent of the outer pre-push cgroup that # has already accumulated page cache from pytest/mypy/pylint. entry: meta/scripts/run_prettier_capped.sh language: system types_or: [yaml, json, markdown] exclude: >- (?x)^( Bash/.*| \.venv/.*| third_party/.*| \.github/skills/.*| docs/superpowers/(plans|specs)/.*| linux_configuration/report/.*| .*\.lock )$ stages: [pre-push] # =========================================================================== # SHELLCHECK - Shell script linting # Wrapper batches files to avoid OOM on large repos. # =========================================================================== - repo: local hooks: - id: shellcheck name: shellcheck entry: bash -c 'printf "%s\0" "$@" | xargs -0 -n 40 shellcheck --severity=warning' -- language: system types: [shell] # shellcheck only understands sh/bash/dash/ksh; it cannot parse zsh # syntax (e.g. extended globs like (#s)). zsh files are checked by the # zsh-syntax hook below instead. exclude_types: [zsh] # =========================================================================== # ZSH SYNTAX - zsh -n parse check (shellcheck has no zsh mode) # =========================================================================== - repo: local hooks: - id: zsh-syntax name: zsh syntax check entry: bash -c 'for f in "$@"; do zsh -n "$f" || exit 1; done' -- language: system types: [zsh] # =========================================================================== # CHECK PYTHON LOCATION - All Python files must be under python_pkg/ # =========================================================================== - repo: local hooks: - id: check-python-location name: check Python files are under python_pkg/ entry: meta/scripts/check_python_location.sh language: script types: [python] # =========================================================================== # REMOVE EMPTY DIRECTORIES - Clean up empty folders in the repo # =========================================================================== - repo: local hooks: - id: remove-empty-dirs name: remove empty directories entry: find . -type d -empty -not -path './.git/*' -delete -print language: system pass_filenames: false always_run: true # =========================================================================== # SECRET PATTERNS - Block commits containing sensitive data # =========================================================================== - repo: local hooks: - id: check-no-secrets name: check for leaked secrets entry: meta/scripts/check_no_secrets.sh language: script exclude: ^(\.secret-patterns|\.pre-commit-config\.yaml|.*\.geojson)$ # =========================================================================== # COMMITIZEN - Conventional commits (optional) # =========================================================================== # - repo: https://github.com/commitizen-tools/commitizen # rev: v3.13.0 # hooks: # - id: commitizen # - id: commitizen-branch # stages: [push]