Skip to content

Built-in Hooks

This page lists the built-in Rust hooks, their supported arguments, and behavior notes. For setup examples and how to choose between the automatic fast path and repo: builtin, see Built-in Hooks.

Supported Hooks

For repo: builtin, the following hooks are supported:

Automatic Fast Path

Currently, only part of hooks from https://github.com/pre-commit/pre-commit-hooks is supported. More popular repositories may be added over time.

Notes

  • pretty-format-json is currently available only via repo: builtin while parity coverage against upstream Python behavior is still being expanded.
  • Other hooks from the repository which have no fast path implementation will run via the standard method.

Hook Reference

Configuration notes

  • Configure arguments via args: [...] just like pre-commit.
  • For repo: builtin, entry is not allowed and language must be system (it is fine to omit language).
  • Some hooks are fixers (they modify files). Like pre-commit-hooks, they typically exit non-zero after making changes so you can re-run the commit.

Example:

repos:
  - repo: builtin
    hooks:
      - id: trailing-whitespace
        args: [--markdown-linebreak-ext=md]
      - id: check-added-large-files
        args: [--maxkb=1024]

trailing-whitespace

Trims trailing whitespace from each line.

Supported arguments:

  • --check (prek only)
    • Report files that would change and exit nonzero without modifying them.
  • --markdown-linebreak-ext=<ext> (repeatable / comma-separated)
    • Preserves Markdown hard line breaks (two trailing spaces) for files with the given extension(s).
    • Use --markdown-linebreak-ext=* to treat all files as Markdown.
  • --chars=<chars>
    • Trim only the specified set of characters instead of “all trailing whitespace”.
    • Example: args: [--chars, " \t"] (space + tab).

Caveats

  • --markdown-linebreak-ext values must be extensions only (no path separators).

check-added-large-files

Prevents giant files from being committed.

Supported arguments (compatible with pre-commit-hooks):

  • --maxkb=<N> (default: 500)
    • Maximum allowed file size, in kibibytes. File sizes are rounded up, so --maxkb=0 accepts only empty files.
  • --enforce-all
    • Check all matched files, not just those staged for addition.

Caveats

  • By default, only files staged for addition are checked.
  • Files configured with filter=lfs (via git attributes) are skipped.

check-case-conflict

Checks for paths that would conflict on a case-insensitive filesystem (for example macOS / Windows).

Supported arguments

  • None.

Caveats

  • The check includes parent directories as well as file paths, to catch directory-level case conflicts.

check-illegal-windows-names

Checks for filenames that cannot be created on Windows.

Supported arguments

  • None.

Behavior / caveats

  • Reports filenames containing Windows-reserved device names such as CON, PRN, AUX, NUL, COM1, and LPT1.
  • Reports filenames containing characters forbidden by Windows, including <, >, :, ", \, |, ?, *, and control characters.
  • Reports path segments ending with a trailing . or space.

end-of-file-fixer

Ensures files end in a newline and only a newline.

Supported arguments

  • --check (prek only)
    • Report files that would change and exit nonzero without modifying them.

Behavior / caveats

  • Empty files are left unchanged.
  • Files containing only newlines are truncated to empty.
  • If a file has no trailing newline, a single \n is appended (even if the file otherwise uses CRLF).
  • If a file has trailing newlines, they are reduced to exactly one trailing line ending.

file-contents-sorter

Sorts the non-empty lines in each matched file and rewrites the file when the normalized order changes.

Supported arguments:

  • --check (prek only)
    • Report files that would change and exit nonzero without modifying them.
  • --ignore-case
    • Sort using ASCII case-folded ordering.
    • Mutually exclusive with --unique.
  • --unique
    • Sort and deduplicate lines.
    • Mutually exclusive with --ignore-case.

Behavior / caveats

  • Blank lines and whitespace-only lines are removed before sorting.
  • Line endings are normalized to \n in the rewritten file.
  • Like upstream, the builtin hook defaults to files: '^$', so you must configure files: explicitly to target specific files.

Example:

repos:
  - repo: builtin
    hooks:
      - id: file-contents-sorter
        files: ^requirements(-dev)?\.txt$

requirements-txt-fixer

Sorts entries in Python requirements*.txt and constraints*.txt files by their case-insensitive requirement name.

Supported arguments

  • --check (prek only)
    • Report files that would change and exit nonzero without modifying them.

Behavior / caveats

  • The default file pattern is (requirements|constraints).*\.txt$.
  • Leading comments and continuation lines stay attached to their requirement while sorting. Top-of-file and trailing comment blocks are preserved.
  • Exact duplicate entries are collapsed, preferring the copy with an attached comment.
  • Exact pkg-resources==0.0.0 and pkg_resources==0.0.0 entries are removed, matching upstream.
  • This is a sorter, not a full PEP 508 validator. It uses the same lightweight name extraction as pre-commit-hooks.

fix-byte-order-marker

Removes a UTF-8 byte order marker (BOM) from the beginning of a file.

Supported arguments

  • --check (prek only)
    • Report files that would change and exit nonzero without modifying them.

Caveats

  • Only removes the UTF-8 BOM (EF BB BF).

forbid-new-submodules

Prevents the addition of new Git submodules.

Supported arguments

  • None.

Behavior / caveats

  • Existing submodules are allowed; only submodules newly added by the checked changes are reported.
  • Staged changes are checked by default. When PRE_COMMIT_FROM_REF and PRE_COMMIT_TO_REF are both set, their revision range is checked instead.

check-json

Attempts to load all JSON files to verify syntax. Empty files are rejected.

Supported arguments

  • None.

Caveats / differences

  • This implementation rejects duplicate object keys (errors with duplicate key ...).
  • The parser disables the default recursion limit and uses a stack-friendly drop strategy for deeply nested JSON.

check-json5

Attempts to load all JSON5 files to verify syntax.

Supported arguments

  • None.

Caveats / differences

  • This implementation rejects duplicate object keys (errors with duplicate key ...).

check-jsonc

Checks .jsonc files for parseable syntax.

To check JSONC stored in .json files, such as tsconfig.json, override the default file-type filter:

repos:
  - repo: builtin
    hooks:
      - id: check-jsonc
        types: [json]
        files: '(^|/)tsconfig\.json$'
        args: [--allow-trailing-commas]

Supported arguments

  • --allow-trailing-commas
    • Allow trailing commas in objects and arrays (rejected by default).

Caveats / differences

  • This implementation rejects duplicate object keys (errors with duplicate key ...).

pretty-format-json

Checks that JSON files are pretty-formatted and can optionally rewrite them in place.

Supported arguments (compatible with pre-commit-hooks):

  • --autofix
    • Rewrite files in place when formatting changes are needed.
  • --indent=<indent> (default: 2)
    • Use <indent> for each indentation level.
    • Numeric values mean that many spaces.
    • Non-numeric values are used literally, so --indent=\t uses tabs.
  • --no-ensure-ascii
    • Keep non-ASCII characters as UTF-8 instead of escaping them as \uXXXX.
  • --no-sort-keys
    • Preserve the original key order instead of sorting object keys.
  • --top-keys=<k1,k2,...>
    • In every JSON object, move matching keys to the front in the given order.
    • Duplicate names after the first one are ignored.
    • Remaining keys come after that prefix and are sorted unless --no-sort-keys is set.
    • This applies recursively to nested objects too, not just the root object.

Caveats

  • This hook is currently available only via repo: builtin; automatic fast-path replacement of the upstream Python hook remains disabled until parity coverage is broader.
  • Rewritten files always use LF (\n) line endings and end with exactly one trailing newline.

check-toml

Attempts to load all TOML files to verify syntax.

Supported arguments

  • None.

Caveats

  • Files must be valid UTF-8; invalid UTF-8 is reported as an error.
  • May report multiple parse errors for a single file.

Ensures that links to VCS websites are permalinks.

Supported arguments (compatible with pre-commit-hooks):

  • --additional-github-domain=<domain> (repeatable)
    • Adds extra GitHub-style domains to check in addition to the default github.com.

Behavior / caveats

  • Flags links of the form https://<domain>/<owner>/<repo>/blob/<branch>/...#L....
  • Does not flag commit-hash permalinks where <branch> is already a 4-64 character hexadecimal revision.
  • The builtin and fast-path implementations currently follow the upstream hook's GitHub-family matching behavior.

check-yaml

Attempts to load all YAML files to verify syntax.

Supported arguments (partially compatible with pre-commit-hooks):

  • -m, --allow-multiple-documents (alias: --multi)
    • Allow YAML multi-document syntax (---).
  • --disallow-unknown-tags
    • Reject unrecognized YAML tags.
  • --unsafe
    • Parse YAML syntax without loading it. Implies --allow-multiple-documents.

Behavior / caveats

  • Unrecognized YAML tags are allowed by default. This differs from the pinned pre-commit-hooks implementation, which rejects them while loading. Use --disallow-unknown-tags to match that behavior.

check-xml

Attempts to load all XML files to verify syntax.

Supported arguments

  • None.

Caveats

  • Empty files are treated as invalid XML.
  • Fails if there is “junk after the document element” (multiple top-level roots).

deny-filename-pattern

Fails when the final path component (the basename) of any selected file matches a configured regular expression. When multiple patterns are provided, the hook fails when a basename matches any one of them.

The standard files, exclude, and type filters select which project-relative paths are checked. The patterns passed to this hook are then matched only against each selected basename.

Supported arguments

  • PATTERN... (required)
    • Positional regular expressions to deny.
    • Use -- before a pattern that begins with -.
  • -i, --ignore-case
    • Match all patterns case-insensitively.

Each matching file is reported once as path: filename matches a denied pattern.

repos:
  - repo: builtin
    hooks:
      - id: deny-filename-pattern
        name: disallow spaces in filenames
        args: ['\s']

deny-pattern

Fails when any selected text file matches a configured regular expression. When multiple patterns are provided, matching any one of them is sufficient.

Supported arguments

  • PATTERN... (required)
    • Positional regular expressions to deny.
    • Use -- before a pattern that begins with -.
  • -i, --ignore-case
    • Match all patterns case-insensitively.
  • -m, --multiline
    • Search each file as a whole, with ^ and $ matching line boundaries and . matching newlines.
    • Reads each selected file into memory.

By default, each matching line is reported as path:line:contents. A line matching more than one pattern is reported only once. With --multiline, the earliest match in each file is reported as path:start-line:matched-block.

repos:
  - repo: builtin
    hooks:
      - id: deny-pattern
        name: disallow wildcard imports
        args: ['^\s*#import\s+.+:\s*\*']
        files: \.typ$

require-filename-pattern

Fails when the final path component (the basename) of any selected file does not match at least one configured regular expression. This is a per-file requirement: every selected basename must match, while different basenames may match different patterns.

require-filename-pattern supports the same positional PATTERN... and -i / --ignore-case arguments as deny-filename-pattern. Matching uses search semantics; use ^ and $ when the pattern must match the entire basename. Files without a match are reported as path: filename does not match any required pattern.

repos:
  - repo: builtin
    hooks:
      - id: require-filename-pattern
        name: python tests naming
        args:
          - '^test_.*\.py$'
          - '^__init__\.py$'
          - '^conftest\.py$'
        files: '(^|/)tests/.+\.py$'

require-pattern

Fails when any selected text file does not match at least one configured regular expression. This is a per-file requirement: every file must match, while different files may match different patterns.

require-pattern supports the same positional PATTERN..., -i / --ignore-case, and --multiline arguments as deny-pattern. Files without a match are reported as path: file does not match any required pattern.

repos:
  - repo: builtin
    hooks:
      - id: require-pattern
        name: require a copyright notice
        args: [--ignore-case, copyright]
        files: '\.(rs|py)$'

mixed-line-ending

Replaces or checks mixed line endings.

Supported arguments (compatible with pre-commit-hooks, plus one extra mode):

  • --fix=<mode> (default: auto)
    • auto: replace with the most frequent line ending in the file.
    • no: check only (do not modify files).
    • lf: convert to LF (\n).
    • crlf: convert to CRLF (\r\n).
    • cr: convert to CR (\r) (extra mode in prek).

Caveats

  • Empty and binary files (containing NUL) are skipped.
  • Upstream note: forcing lf / crlf may not behave as expected with git CRLF conversion settings (for example core.autocrlf).

Checks for symlinks which do not point to anything.

Supported arguments

  • None.

Caveats

  • Relies on filesystem symlink support. On Windows, symlink creation and detection can be permission-dependent.

Detects files staged as regular files whose HEAD version is a symlink, which usually happens when a repository is checked out in an environment without symlink support.

Supported arguments

  • None.

Caveats

  • This matches upstream pre-commit-hooks behavior: it only checks tracked entries reported by git status --porcelain=v2.
  • It intentionally ignores differences consisting only of trailing ASCII whitespace (including spaces, tabs, and newline/CRLF conversions) when comparing the staged file against the original symlink target path, because those differences are commonly introduced by formatting hooks.

check-merge-conflict

Checks for merge conflict markers.

Supported arguments (compatible with pre-commit-hooks):

  • --assume-in-merge
    • Allow running the hook even when there is no merge/rebase state detected.

Caveats

  • By default, this hook exits successfully when not in a merge/rebase state.
  • Detects conflict markers only when they appear at the start of a line.
  • Detects standard conflict blocks (<<<<<<<, =======, >>>>>>>) and diff3 ancestor markers (|||||||).
  • ======= is only reported after a preceding <<<<<<<, which avoids false positives for content such as reStructuredText headings.

detect-private-key

Detects the presence of private keys.

Supported arguments

  • None.

Caveats

  • This is a heuristic substring scan for common PEM/key headers (e.g. BEGIN RSA PRIVATE KEY, BEGIN OPENSSH PRIVATE KEY, BEGIN PGP PRIVATE KEY BLOCK, etc.). It can produce false positives/negatives.

no-commit-to-branch

Protects specific branches from direct commits.

Supported arguments (compatible with pre-commit-hooks):

  • -b, --branch <branch> (repeatable, default: main, master)
  • -p, --pattern <regex> (repeatable)

Caveats

  • This hook is configured as always_run: true by default, and does not take filenames. As a result, files, exclude, types, etc. are ignored unless you explicitly set always_run: false.
  • If HEAD is detached (no current branch), the hook does nothing.

check-signed-commit

Ensures commits are signed with a valid GPG/SSH signature before they're pushed.

Supported arguments

  • None.

Behavior / caveats

  • Defaults to the pre-push and manual stages. This hook is configured as always_run: true and does not take filenames.
  • Checks the commits being pushed. Root/orphan pushes check the entire branch history.
  • Manual runs check only HEAD.
  • Merge commits are skipped.
  • Commits must pass git verify-commit using your local Git GPG/SSH configuration. Unsigned commits and verification failures, including missing tools or public keys, fail the hook.

check-commit-trailers

Checks required and denied trailers in commit messages, such as Signed-off-by, Co-authored-by, or Reviewed-by. At commit-msg, it checks the message before the commit is created. At pre-push, it checks the messages of commits being pushed.

Supported arguments

  • --require KEY[=REGEX]: Require a trailer with a non-empty value. If a regular expression is supplied, at least one value for that key must match it. Other values for the same key are still allowed.
  • --deny KEY[=REGEX]: Reject commits containing this key. Add a regular expression to reject only matching values. A single matching value is enough to fail the check, even if other values for the same key are allowed.

Configure at least one rule. You can repeat either argument and combine required and denied rules. For example, --require Signed-off-by --require Co-authored-by requires both trailers. A commit passes only when all required rules are satisfied and none of the denied rules match.

Trailer keys are case-insensitive, so Signed-off-by and signed-off-by are equivalent. Value patterns are case-sensitive by default; prefix a pattern with (?i) to ignore case. Patterns can match part of a value; use ^ and $ to match the whole value.

For example, require a sign-off and reject co-authors named Claude:

default_install_hook_types: [commit-msg, pre-push]
repos:
  - repo: builtin
    hooks:
      - id: check-commit-trailers
        args:
          - --require=Signed-off-by
          - '--deny=Co-authored-by=(?i)^claude\b'

This configuration allows commits without a co-author. If co-authors are listed, none may match the denied pattern: a commit listing both Alice and Claude still fails. Add --require=Co-authored-by to also require at least one co-author.

To forbid a trailer entirely, regardless of its value, use a rule without a pattern, such as --deny=AI-generated-by.

Caveats

  • Trailers must form a Key: value block at the end of the message, separated from the subject or body by a blank line. Repeated keys and indented continuation lines are supported. Matching text in the subject or an earlier paragraph does not count as a trailer.
  • Merge commits are skipped. Squash commits are checked. When amending an existing merge commit, its message is still checked at commit-msg.
  • pre-push checks commits being pushed, including empty commits. When pushing multiple refs, only the first ref with pending commits is checked.

check-executables-have-shebangs

Checks that non-binary executables have a proper shebang.

Supported arguments

  • None.

Caveats

  • The check is intentionally lightweight: it only verifies that the file starts with #!.
  • On systems where the executable bit is not tracked by the filesystem, prek consults git’s staged mode bits.

check-shebang-scripts-are-executable

Checks that non-binary files with a shebang are marked executable.

Supported arguments

  • None.

Caveats

  • The check is intentionally lightweight: it only verifies that the file starts with #!.
  • To work on filesystems which do not track the executable bit, prek consults git’s staged mode bits.