Skip to content

Pre-commit Hooks

Scythe provides pre-commit / prek hooks for SQL formatting, linting, code generation, and validation.

Setup

Add scythe to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/Goldziher/scythe
    rev: v0.9.0  # use the latest release tag
    hooks:
      - id: scythe-fmt
      - id: scythe-lint
      - id: scythe-audit

Then install the hooks:

# pre-commit
pre-commit install

# prek
prek install

Available Hooks

Hook ID Description Modifies files Requires config
scythe-fmt Format SQL files in-place Yes No
scythe-lint Lint SQL files with auto-fix (includes audit rules) Yes No
scythe-audit SC-SEC/SC-RLS/SC-MIG/SC-CHK security/migration audit No No
scythe-inspect Live-DB health checks (SC-INS*) — CI mode, requires $DATABASE_URL No No
scythe-generate Generate code from SQL schema and queries Yes Yes
scythe-check Validate SQL without generating code No Yes

scythe-fmt

Formats SQL files using sqruff integration. Runs on changed .sql files and modifies them in-place. Failed formatting (exit code 1) blocks the commit until files are re-staged.

scythe-lint

Lints SQL files and auto-fixes violations where possible. Runs scythe lint --fix by default. When run without a scythe.toml, only sqruff rules apply. With a config, both scythe rules (schema-aware) and sqruff rules run — and the canonical SC-SEC*, SC-RLS*, SC-MIG*, and SC-CHK* audit packs run too, dialect-gated by the [[sql]].engine field. A mysql project will not see postgres-only SC-MIG* findings; they're silently skipped.

scythe-audit

Static SQL audit — runs the canonical security, RLS, migration-safety, and CHECK-integrity rule packs over staged .sql files. No scythe.toml or database connection required. Defaults to the postgres dialect; override via args: [--dialect, mysql] (or any other supported engine). Exits 2 when any error-severity rule fires; pass --exit-zero for advisory CI integration that publishes findings without blocking the commit.

scythe-inspect

CI-mode hook. Connects to a live Postgres database and runs the SC-INS* operational health checks (missing FK indexes, RLS misconfig with policies, duplicate indexes). Requires $DATABASE_URL (or $SCYTHE_DATABASE_URL) to be set in the hook's environment — local pre-commit runs without the variable fail loudly with the same error as the CLI. Designed for CI pre-merge gates and pre-deploy checks, not interactive commit blocking. Exits 2 on error-severity findings; pass --exit-zero via args: for advisory mode. Phase 1 (v0.11.0) will add [inspect] config sourcing so local pre-commit use becomes natural.

scythe-generate

Regenerates code when .sql files or scythe.toml change. Requires a scythe.toml in the repository root. Generated files must be staged and re-committed if they change.

scythe-check

Validates SQL schema and queries without generating code. Exits with code 1 if any lint errors are found. Useful in CI or as a read-only validation step.

Customization

Override default arguments in your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/Goldziher/scythe
    rev: v0.6.0
    hooks:
      # Format with a specific SQL dialect
      - id: scythe-fmt
        args: ["--dialect", "postgres"]

      # Lint without auto-fix (check-only)
      - id: scythe-lint
        args: []

      # Use a custom config path
      - id: scythe-generate
        args: ["--config", "db/scythe.toml"]

Using a Pre-installed Binary

By default, hooks use language: rust which compiles scythe from source on first run. If you already have scythe installed (via cargo install or brew), use language: system for faster execution:

repos:
  - repo: local
    hooks:
      - id: scythe-fmt
        name: Format SQL (scythe)
        entry: scythe fmt
        language: system
        types: [sql]

      - id: scythe-lint
        name: Lint SQL (scythe)
        entry: scythe lint --fix
        language: system
        types: [sql]

Most projects -- format and lint SQL on every commit:

hooks:
  - id: scythe-fmt
  - id: scythe-lint

Code generation projects -- also regenerate code when SQL changes:

hooks:
  - id: scythe-fmt
  - id: scythe-lint
  - id: scythe-generate

CI-only validation -- check without modifying files:

hooks:
  - id: scythe-check

Testing Hooks

Verify hooks work in your project:

# Test a specific hook on all files
prek run scythe-fmt --all-files

# Test with try-repo (no installation needed)
prek try-repo https://github.com/Goldziher/scythe scythe-fmt --all-files

# Dry run to preview what would execute
prek run scythe-lint --dry-run

Notes

  • First run: language: rust compiles scythe from source, which takes a few minutes. Subsequent runs use the cached binary. Use language: system to skip compilation if scythe is already installed.
  • Config path: Hooks that require a config (scythe-generate, scythe-check) default to scythe.toml in the repository root. Override with args: ["--config", "path/to/scythe.toml"].
  • Auto-staging: When scythe-fmt or scythe-lint --fix modify files, pre-commit/prek reports the hook as failed. Stage the changes and commit again.