# Pre-commit hooks for this repository: ruff, Pyrefly, project-specific lint, # and standard file-hygiene checks. # # A built web-UI bundle may be committed at this path (vendored, minified # JS/CSS) — never lint or "fix" it. exclude: ^omnigent/server/static/web-ui/ repos: - repo: local hooks: - id: ruff-format name: ruff format language: system entry: .venv/bin/python -m ruff format --force-exclude types: [python] - id: ruff-check name: ruff check language: system entry: .venv/bin/python -m ruff check --fix --force-exclude types: [python] - id: pyrefly name: pyrefly language: system entry: .venv/bin/pyrefly check pass_filenames: false files: ^(omnigent/.*\.pyi?|sdks/python-client/.*\.py|pyproject\.toml|pyrefly\.toml|uv\.lock)$ # Project-specific test-quality lint rules (dev/lint/). Run on test # files only — the patterns never occur in production code. - id: no-global-asyncio-patch name: no globally-clobbering asyncio monkeypatch language: system entry: .venv/bin/python dev/lint/lint_no_global_asyncio_patch.py types: [python] files: ^tests/ - id: no-skipped-tests name: no unconditional `@pytest.mark.skip` language: system entry: .venv/bin/python dev/lint/lint_no_skipped_tests.py types: [python] files: ^tests/ - id: no-hardcoded-models name: no new hardcoded LLM model ids language: system entry: .venv/bin/python dev/lint/lint_no_hardcoded_models.py pass_filenames: false files: \.(py|ya?ml|json|toml|sh)$ exclude: (^|/)tests/|^openapi\.json$ - id: web-prettier name: web prettier language: system entry: bash -c 'test -x web/node_modules/.bin/prettier && web/node_modules/.bin/prettier --write "$@"' -- files: ^web/.*\.(css|html|js|jsx|json|md|mdx|ts|tsx|yaml|yml)$ # Exclude generated assets: web-ui build output, Xcode asset catalogs, # and Apple Icon Composer `.icon` bundles (machine-formatted; prettier # fights the tooling). exclude: ^(omnigent/server/static/web-ui/assets/|web/.*\.xcassets/|web/.*\.icon/) - id: web-oxlint name: web oxlint language: system entry: bash -c 'test -x web/node_modules/.bin/oxlint && cd web && node_modules/.bin/oxlint --deny-warnings --report-unused-disable-directives .' files: ^(web/.*\.[cm]?[jt]sx?|web/\.oxlintrc\.json|web/package\.json|pnpm-lock\.yaml)$ pass_filenames: false - id: web-tsc name: web TypeScript type check language: system entry: bash -c 'test -x web/node_modules/.bin/tsc && cd web && node_modules/.bin/tsc -b' files: ^(web/.*\.[cm]?[jt]sx?|web/tsconfig(?:\.[^.]+)?\.json|web/package\.json|pnpm-(?:lock|workspace)\.yaml)$ pass_filenames: false - id: vscode-tsc name: VS Code extension TypeScript type check language: system entry: bash -c 'test -x editors/vscode/node_modules/.bin/tsc && cd editors/vscode && node_modules/.bin/tsc --noEmit' files: ^(editors/vscode/.*\.[cm]?[jt]sx?|editors/vscode/tsconfig\.json|editors/vscode/package\.json|pnpm-(?:lock|workspace)\.yaml)$ pass_filenames: false # Android Kotlin formatting + linting via ktlint (config: # web/android/.editorconfig). The wrapper no-ops when ktlint is absent, # so local machines without ktlint installed skip cleanly. CI installs # ktlint before running pre-commit, so the check is enforced there. # Install locally with `brew install ktlint` (macOS) or download from # https://github.com/pinterest/ktlint/releases. - id: android-ktlint-format name: android ktlint format language: system entry: web/android/bin/ktlint.sh --format files: ^web/android/.*\.kts?$ exclude: ^web/android/(build|\.gradle)/ - id: android-ktlint-check name: android ktlint check language: system entry: web/android/bin/ktlint.sh files: ^web/android/.*\.kts?$ exclude: ^web/android/(build|\.gradle)/ # iOS Swift formatting + linting via Apple's `swift format` (config: # web/ios/.swift-format). The wrapper no-ops when the Swift toolchain # is absent, so these run on macOS dev machines but skip the ubuntu-latest # CI pre-commit job — there is no Swift there. Enforcement is local. - id: web-ios-swift-format name: web ios swift-format language: system entry: web/ios/bin/swift-format.sh format --in-place --parallel files: ^web/ios/.*\.swift$ exclude: ^web/ios/(build|vendor)/ - id: web-ios-swift-lint name: web ios swift format lint language: system entry: web/ios/bin/swift-format.sh format lint --strict --parallel files: ^web/ios/.*\.swift$ exclude: ^web/ios/(build|vendor)/ # Keep omnigent/version.py's VERSION constant equal to the canonical # [project].version in pyproject.toml (the runtime imports the constant; # the build reads pyproject). Fixer: rewrites the constant and re-stages. - id: sync-version-py name: sync omnigent/version.py to pyproject version language: system entry: .venv/bin/python scripts/sync_version_py.py files: ^(pyproject\.toml|omnigent/version\.py)$ pass_filenames: false # Local `uv` runs rewrite uv.lock's registry to whatever index is # configured on the developer's machine (e.g. the Databricks PyPI # proxy). This OSS repo must always commit the public PyPI URL, so # normalize it back before it lands. Fixer: re-stage if it changes. - id: normalize-uv-lock-registry name: normalize uv.lock registry to pypi.org language: system entry: .venv/bin/python scripts/normalize_uv_lock_registry.py files: ^uv\.lock$ pass_filenames: true # Fail if routing.proto changed without regenerating the committed # bindings (or vice versa). Verify-only, not a fixer: regen needs # grpcio-tools, so CI's `uv sync --group lint` enforces it (like ktlint). - id: routing-pb2-fresh name: routing protobuf bindings are up to date language: system entry: .venv/bin/python scripts/gen_routing_pb2.py --check files: ^omnigent/api/routing/v1/routing(\.proto|_pb2\.pyi?)$ pass_filenames: false # ── File hygiene ──────────────────────────────────────────────── - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: trailing-whitespace name: trim trailing whitespace exclude: \.(md|svg)$ - id: end-of-file-fixer name: ensure files end with newline # AppIcon.icon/ is generated by Apple's Icon Composer, which writes # icon.json without a trailing newline — don't "fix" it. exclude: (\.(md|svg)$|/AppIcon\.icon/) - id: check-yaml name: check yaml syntax # docker-compose override files use non-standard tags # (`!reset`, `!override`) that PyYAML can't parse. exclude: ^deploy/docker/docker-compose\.[a-z]+\.yaml$ - id: check-merge-conflict name: check for merge conflicts - id: check-added-large-files name: prevent large files args: ['--maxkb=1000'] - id: check-case-conflict name: check for case conflicts - id: mixed-line-ending name: check line endings args: ['--fix=lf']