Skip to content

Built-in linters ​

Builtins are reusable Pkl step definitions for linters, formatters, and hk’s own utilities. They supply file patterns, check and fix commands, and optimizations such as diff output.

Install the tools separately. A builtin invokes executables from your environment; it does not install them. Use your project’s package manager or mise; most entries in the catalogue list the mise use command that installs their tool, or the tool’s project page when mise can’t install it. Builtins that run only hk util commands have no Install line because they need no separate tool, except python-check-ast, which needs Python on PATH.

Use a builtin ​

pkl
amends "package://github.com/jdx/hk/releases/download/v2.10.0/hk@2.10.0#/Config.pkl"
import "package://github.com/jdx/hk/releases/download/v2.10.0/hk@2.10.0#/Builtins.pkl"

hooks {
  ["check"] {
    steps {
      ["oxfmt"] = Builtins.oxfmt
      ["eslint"] = Builtins.eslint
    }
  }
}

Builtins.oxfmt is the Pkl property name. The step name, "oxfmt", is your label for selecting the step in commands such as hk check --step oxfmt.

Keep the schema and Builtins imports on the same version. The catalogue below describes the version of the source used to build this website; an older pinned package may differ.

Customize a builtin ​

Amend a builtin to keep its defaults while changing specific properties:

pkl
["oxfmt"] = (Builtins.oxfmt) {
  glob = List("*.js", "*.ts", "*.json")
  exclude = List("**/generated/**")
  batch = false
}

A property assignment replaces that property. If you override glob or exclude, include every pattern you want to retain.

Use dependencies for ordering and profiles for optional checks:

pkl
["oxfmt"] = (Builtins.oxfmt) {
  depends = "eslint"
}
["mypy"] = (Builtins.mypy) {
  profiles = List("types")
}

Run the type checker with hk check --profile types. See configuration for groups, workspaces, and command templates.

Utilities included with hk ​

Steps such as Builtins.trailing_whitespace, Builtins.newlines, and Builtins.check_merge_conflict invoke hk util commands. These need no separate linter executable.

Tool availability ​

Builtins configure how hk invokes a tool; they do not install that tool. The executable used by the builtin must be on PATH, or the step must use a prefix that resolves it.

With HK_MISE=1, hk resolves the mise environment for the step's directory, so tools declared in a subproject's mise.toml are available without a prefix. For a Node tool installed locally by aube, prefix its builtin with aube exec:

pkl
["eslint"] = (Builtins.eslint) {
  prefix = List("aube", "exec")
}

Use an argv list for builtins backed by structured commands. A string prefix such as "aube exec" or "mise x --" cannot be combined with those commands.

Available builtins ​

The following catalogue is generated from the builtin definitions. Each entry includes the exact Pkl property to use. Refer to the source definitions for additional options and tests.

.NET ​

dotnet-format ​

Pkl: Builtins.dotnet_format

Format C# and Visual Basic with the .NET SDK

  • Files: **/*.cs, **/*.vb
  • Install: mise use dotnet
  • Check: dotnet format --verify-no-changes --include {{files}}
  • Fix: dotnet format --include {{files}}
  • Options: exclusive = true

AsciiDoc ​

asciidoctor ​

Pkl: Builtins.asciidoctor

AsciiDoc syntax validator and processor

  • Files: asciidoc files
  • Install: mise use gem:asciidoctor
  • Check: asciidoctor --failure-level=WARNING --out-file=/dev/null {{files}}

Build Systems ​

buildifier-format ​

Pkl: Builtins.buildifier_format

Formatter for Bazel BUILD, WORKSPACE, and Starlark files

  • Files: **/BUILD, **/BUILD.bazel, WORKSPACE, WORKSPACE.bazel, MODULE.bazel, **/*.bzl, **/*.star, **/*.sky
  • Install: mise use buildifier
  • Check: buildifier -mode=check {{files}}
  • Check (diff): hk util format-diff {{files}} -- buildifier '-path={}'
  • Fix: buildifier {{files}}

buildifier-lint ​

Pkl: Builtins.buildifier_lint

Linter for Bazel BUILD, WORKSPACE, and Starlark files

  • Files: **/BUILD, **/BUILD.bazel, WORKSPACE, WORKSPACE.bazel, MODULE.bazel, **/*.bzl, **/*.star, **/*.sky
  • Install: mise use buildifier
  • Check: buildifier -mode=check -lint=warn {{files}}
  • Fix: buildifier -lint=fix {{files}}

CSS ​

stylelint ​

Pkl: Builtins.stylelint

CSS linter

  • Files: **/*.css, **/*.scss, **/*.sass, **/*.less
  • Install: mise use npm:stylelint
  • Check: stylelint {{files}}
  • Fix: stylelint --fix {{files}}

Configuration ​

sort-package-json ​

Pkl: Builtins.sort_package_json

Sort package.json keys

  • Files: **/package.json
  • Install: mise use npm:sort-package-json
  • Check: sort-package-json --check {{files}}
  • Fix: sort-package-json {{files}}

Data Formats ​

buf-format ​

Pkl: Builtins.buf_format

Protocol Buffers formatter

  • Files: **/*.proto
  • Install: mise use buf
  • Check (diff): buf format {{workspace}} --diff --exit-code
  • Fix: buf format {{workspace}} --write
  • Options: workspace_indicator = "buf.yaml"

buf-lint ​

Pkl: Builtins.buf_lint

Protocol Buffers linter

  • Files: **/*.proto
  • Install: mise use buf
  • Check: buf lint {{workspace}}
  • Options: workspace_indicator = "buf.yaml"

dotenv-linter ​

Pkl: Builtins.dotenv_linter

.env file linter

  • Files: **/.env, **/.env.*, **/*.env
  • Check: dotenv-linter check --skip-updates {{files}}
  • Fix: dotenv-linter fix --no-backup {{files}}

jq ​

Pkl: Builtins.jq

JSON processor

  • Files: **/*.json

  • Install: mise use jq

  • Check (diff):

    sh
    failed=0
    broken=0
    trap 'rm -f "$out" "$patch" "$new"' EXIT
    trap 'exit 2' HUP INT TERM
    out=$(mktemp) && patch=$(mktemp) && new=$(mktemp) || exit 2
    n=0
    set --
    for f in {{ files }}; do
    n=$((n + 1))
    set -- "$@" --rawfile "f$n" "$f"
    done
    # Each file's output follows \u001e, which formatted JSON never
    # contains, and is \u001f if jq cannot parse the file.
    todo=all
    if [ "$n" -gt 1 ] && jq -n -j -S --argjson n "$n" "$@" '
    range(1; $n + 1) as $i | "\u001e", ($ARGS.named["f\($i)"]
    | try (fromjson | if type == "string" then tojson else . end, "\n") catch "\u001f")
    ' > "$new" 2>/dev/null; then
    todo=$(jq -n -r --argjson n "$n" --rawfile new "$new" "$@" '
    ($new | split("\u001e")) as $new
    | [range(1; $n + 1) | select($new[.] != $ARGS.named["f\(.)"]
    or ($new[.] | contains("\u001f") or contains("\ufffd"))) | tostring]
    | " " + join(" ") + " "
    ' 2>/dev/null) || todo=all
    fi
    i=0
    for f in {{ files }}; do
    i=$((i + 1))
    case $todo in
    all | *" $i "*) ;;
    *) continue ;;
    esac
    if jq -S . "$f" > "$out"; then
    # hk runs this with `set -e`, so take diff's status through `||`.
    status=0
    diff -u -L "a/$f" -L "b/$f" "$f" "$out" >> "$patch" || status=$?
    case $status in
    0) ;;
    1) failed=1 ;;
    *) broken=1 ;;
    esac
    else
    broken=1
    fi
    done
    # When a file failed to parse or diff, print no patch: hk then runs the
    # fixer on every file, and the fixer reports the error.
    [ "$broken" = 1 ] && exit 1
    cat "$patch" || exit 2
    exit $failed
  • Fix:

    sh
    failed=0
    tmp=
    trap 'rm -f "$tmp"' EXIT
    trap 'exit 2' HUP INT TERM
    for f in {{ files }}; do
    # Write a copy beside the file, with its permissions, then rename it
    # over the file, so a failed write never truncates the original. A
    # file that is already formatted is left alone, links and all.
    tmp=$(mktemp "$f.XXXXXX") &&
    cp -p "$f" "$tmp" &&
    jq -S . "$f" > "$tmp" &&
    { cmp -s "$f" "$tmp" || mv "$tmp" "$f"; } || failed=1
    rm -f "$tmp"
    tmp=
    done
    exit $failed
  • Options: batch = true

protolint ​

Pkl: Builtins.protolint

Protocol Buffers linter

  • Files: **/*.proto

  • Check: protolint lint {{files}}

  • Fix:

    sh
    # Windows:
    protolint lint -fix {{files}} 2>NUL || protolint lint {{files}}
    # other platforms:
    protolint lint -fix {{files}} 2>/dev/null || protolint lint {{files}}

sql-fluff ​

Pkl: Builtins.sql_fluff

SQL linter and formatter

  • Files: **/*.sql
  • Install: mise use pipx:sqlfluff
  • Check: sqlfluff lint {{files}}
  • Fix: sqlfluff fix {{files}}

taplo ​

Pkl: Builtins.taplo

TOML linter

  • Files: **/*.toml
  • Install: mise use taplo
  • Check: taplo lint {{files}}

taplo-format ​

Pkl: Builtins.taplo_format

TOML formatter

  • Files: **/*.toml

  • Install: mise use taplo

  • Check: taplo format --check --diff {{files}}

  • Check (diff):

    sh
    # Windows: nothing runs
    # other platforms:
    set --
    for f in {{ files }}; do
    taplo format --check --colors never "$f" > /dev/null 2>&1 || set -- "$@" "$f"
    done
    [ $# -eq 0 ] && exit 0
    hk util format-diff "$@" -- taplo format --colors never --stdin-filepath {} -
  • Fix: taplo format {{files}}

tombi ​

Pkl: Builtins.tombi

TOML linter

  • Files: **/*.toml
  • Install: mise use tombi
  • Check: tombi lint --quiet {{files}}

tombi-format ​

Pkl: Builtins.tombi_format

TOML formatter

  • Files: **/*.toml
  • Install: mise use tombi
  • Check: tombi format --quiet --check --diff {{files}}
  • Check (diff): hk util format-diff {{files}} -- tombi format --quiet --stdin-filename '{}' -
  • Fix: tombi format --quiet {{files}}

xmllint ​

Pkl: Builtins.xmllint

XML validator

  • Files: **/*.xml
  • Install: project page
  • Check: xmllint --noout {{files}}

yamlfmt ​

Pkl: Builtins.yamlfmt

YAML formatter

  • Files: **/*.yml, **/*.yaml

  • Install: mise use yamlfmt

  • Check: yamlfmt -lint {{files}}

  • Check (diff):

    sh
    # Windows: nothing runs
    # other platforms:
    # If yamlfmt fails, print no patch: hk runs the fixer, which reports it.
    list=$(yamlfmt -dry -quiet {{ files }}) || exit $?
    set --
    # After a heading, `-dry -quiet` lists the files that would change.
    # Anything else it lists, such as part of a name containing a newline,
    # prints no patch, so hk runs the fixer instead of skipping the file.
    # The here-document expands `$list` once; the names in it are not
    # expanded again, so `$(...)` in a name is just text.
    while IFS= read -r f; do
    case $f in
    '' | 'The following files would be formatted:') continue ;;
    esac
    if [ ! -f "$f" ]; then
    echo "yamlfmt listed a file that does not exist: $f" >&2
    exit 1
    fi
    set -- "$@" "$f"
    done <<EOF
    $list
    EOF
    [ $# -eq 0 ] && exit 0
    hk util format-diff "$@" -- yamlfmt -in
  • Fix: yamlfmt {{files}}

yamllint ​

Pkl: Builtins.yamllint

YAML linter

  • Files: **/*.yml, **/*.yaml
  • Install: mise use yamllint
  • Check: yamllint --strict {{files}}

yq ​

Pkl: Builtins.yq

YAML processor

  • Files: **/*.yaml, **/*.yml

  • Install: mise use yq

  • Check (diff):

    sh
    failed=0
    broken=0
    trap 'rm -rf "$out" "$patch" "$split"' EXIT
    trap 'exit 2' HUP INT TERM
    out=$(mktemp) && patch=$(mktemp) && split=$(mktemp -d) || exit 2
    set --
    for f in {{ files }}; do
    case $f in
    *.[yY][aA][mM][lL] | *.[yY][mM][lL]) set -- "$@" "$f" ;;
    esac
    done
    fast=0
    if [ $# -gt 1 ] && YQ_SPLIT="$split/" yq -P -N -s 'strenv(YQ_SPLIT) +
    (file_index | tostring) + "-" + (document_index | tostring)' "$@" > /dev/null 2>&1; then
    fast=1
    fi
    i=0
    for f in {{ files }}; do
    new=
    case $f in
    *.[yY][aA][mM][lL] | *.[yY][mM][lL])
    new="$split/$i-0.yml"
    i=$((i + 1))
    ;;
    esac
    if [ "$fast" = 1 ] && [ -n "$new" ] && [ -f "$new" ] &&
    [ ! -e "${new%-0.yml}-1.yml" ] && cmp -s "$f" "$new"; then
    continue
    fi
    if yq -P "$f" > "$out"; then
    # hk runs this with `set -e`, so take diff's status through `||`.
    status=0
    diff -u -L "a/$f" -L "b/$f" "$f" "$out" >> "$patch" || status=$?
    case $status in
    0) ;;
    1) failed=1 ;;
    *) broken=1 ;;
    esac
    else
    broken=1
    fi
    done
    # When a file failed to parse or diff, print no patch: hk then runs the
    # fixer on every file, and the fixer reports the error.
    [ "$broken" = 1 ] && exit 1
    cat "$patch" || exit 2
    exit $failed
  • Fix:

    sh
    failed=0
    for f in {{ files }}; do
    yq -iP "$f" || failed=1
    done
    exit $failed
  • Options: batch = true

EditorConfig ​

editorconfig-checker ​

Pkl: Builtins.editorconfig_checker

Validate files against EditorConfig rules

  • Files: text files
  • Install: mise use editorconfig-checker
  • Check: editorconfig-checker {{files}}
  • Fix: editorconfig-checker --fix {{files}}

Elixir ​

mix-compile ​

Pkl: Builtins.mix_compile

Compile Elixir with Mix

  • Files: **/*.ex
  • Install: mise use elixir
  • Check: mix compile --warnings-as-errors --strict-errors {{files}}
  • Options: exclude = List("deps/**/*")

mix-fmt ​

Pkl: Builtins.mix_fmt

Format Elixir with Mix

  • Files: **/*.ex, **/*.exs
  • Install: mise use elixir
  • Check: mix format --check-formatted {{files}}
  • Fix: mix format {{files}}
  • Options: exclude = List("deps/**/*")

mix-test ​

Pkl: Builtins.mix_test

Test Elixir with Mix

  • Files: **/*.ex, **/*.exs
  • Install: mise use elixir
  • Check: mix test --warnings-as-errors {{files}}
  • Options: exclude = List("deps/**/*")

Go ​

err-check ​

Pkl: Builtins.err_check

Error handling checker

  • Files: **/*.go
  • Install: mise use go:github.com/kisielk/errcheck
  • Check: errcheck ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

go-fix ​

Pkl: Builtins.go_fix

Go modernizer (requires Go 1.26+)

  • Files: **/*.go
  • Install: mise use go
  • Check (diff): go fix -diff ./...
  • Fix: go fix ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

go-fmt ​

Pkl: Builtins.go_fmt

Go formatter

  • Files: **/*.go

  • Install: mise use go

  • Check (diff):

    sh
    DIFF=$(gofmt -s -d {{files}})
    if [ -n "$DIFF" ]; then
    echo "$DIFF"
    exit 1
    fi
  • Check (list files):

    sh
    FILES=$(gofmt -s -l {{files}})
    if [ -n "$FILES" ]; then
    echo "$FILES"
    exit 1
    fi
  • Fix: gofmt -s -w {{files}}

go-fumpt ​

Pkl: Builtins.go_fumpt

Strict Go formatter

  • Files: **/*.go

  • Install: mise use gofumpt

  • Check (diff): gofumpt -d {{files}}

  • Check (list files):

    sh
    FILES=$(gofumpt -l {{files}})
    if [ -n "$FILES" ]; then
    echo "$FILES"
    exit 1
    fi
  • Fix: gofumpt -w {{files}}

go-imports ​

Pkl: Builtins.go_imports

Go import management

  • Files: **/*.go

  • Install: mise use go:golang.org/x/tools/cmd/goimports

  • Check (diff):

    sh
    DIFF=$(goimports -d {{files}})
    if [ -n "$DIFF" ]; then
    echo "$DIFF"
    exit 1
    fi
  • Check (list files):

    sh
    FILES=$(goimports -l {{files}})
    if [ -n "$FILES" ]; then
    echo "$FILES"
    exit 1
    fi
  • Fix: goimports -w {{files}}

go-lines ​

Pkl: Builtins.go_lines

Long line fixer

  • Files: **/*.go
  • Install: mise use golines
  • Check (diff): hk util format-diff {{files}} -- golines
  • Fix: golines -w {{files}}

go-sec ​

Pkl: Builtins.go_sec

Security scanner

  • Files: **/*.go
  • Install: mise use aqua:securego/gosec
  • Check: gosec ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

go-vet ​

Pkl: Builtins.go_vet

Go code vetting

  • Files: **/*.go
  • Install: mise use go
  • Check: go vet ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

go-vuln-check ​

Pkl: Builtins.go_vuln_check

Vulnerability scanner

  • Files: **/*.go
  • Install: mise use go:golang.org/x/vuln/cmd/govulncheck
  • Check: govulncheck ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

golangci-lint ​

Pkl: Builtins.golangci_lint

Go meta-linter

  • Files: **/*.go
  • Install: mise use golangci-lint
  • Check: golangci-lint run --fix=false ./...
  • Fix: golangci-lint run --fix ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

golangci-lint-fmt ​

Pkl: Builtins.golangci_lint_fmt

Go formatter (part of golangci-lint)

  • Files: **/*.go
  • Install: mise use golangci-lint
  • Check (diff): golangci-lint fmt --diff {{files}}
  • Fix: golangci-lint fmt {{files}}

gomod-tidy ​

Pkl: Builtins.gomod_tidy

Go module maintenance

  • Files: **/*.go, **/go.mod, **/go.sum
  • Install: mise use go
  • Check (diff): go mod tidy -diff
  • Fix: go mod tidy
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}", stage = List("go.mod", "go.sum")

revive ​

Pkl: Builtins.revive

Fast Go linter

  • Files: **/*.go
  • Install: mise use revive
  • Check: revive -set_exit_status ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

staticcheck ​

Pkl: Builtins.staticcheck

Go static analysis

  • Files: **/*.go
  • Install: mise use staticcheck
  • Check: staticcheck ./...
  • Options: workspace_indicator = "go.mod", dir = "{{workspace}}"

Infrastructure ​

actionlint ​

Pkl: Builtins.actionlint

GitHub Actions workflow linter

  • Files: .github/workflows/*.yml, .github/workflows/*.yaml
  • Install: mise use actionlint
  • Check: actionlint {{files}}
  • Options: batch = true

ansible-lint ​

Pkl: Builtins.ansible_lint

Ansible playbook, role and collection linter

  • Files: **/*.yml, **/*.yaml

  • Install: mise use pipx:ansible-lint

  • Check: ansible-lint {{files}}

  • Fix:

    sh
    # Windows: nothing runs
    # other platforms:
    ansible-lint --fix {{files}} || [ $? -eq 8 ]

dclint ​

Pkl: Builtins.dclint

Docker Compose linter

  • Files: **/compose*.yml, **/compose*.yaml, **/docker-compose*.yml, **/docker-compose*.yaml
  • Install: mise use npm:dclint
  • Check: dclint {{files}}
  • Fix: dclint --fix {{files}}
  • Options: batch = true

droast ​

Pkl: Builtins.droast

Dockerfile linter for security, layer hygiene, and best-practice violations

  • Files: **/Dockerfile, **/Dockerfile.*, **/*.Dockerfile, **/*.dockerfile, **/Containerfile, **/Containerfile.*
  • Install: mise use github:immanuwell/dockerfile-roast
  • Check: droast {{files}}
  • Fix: droast --fix {{files}}

ghalint-action ​

Pkl: Builtins.ghalint_action

GitHub Actions action linter

  • Files: **/action.* that are yaml files
  • Install: mise use ghalint
  • Check: ghalint run-action {{files}}

ghalint-workflow ​

Pkl: Builtins.ghalint_workflow

GitHub Actions workflow linter

  • Files: .github/workflows/* that are yaml files
  • Install: mise use ghalint
  • Check: ghalint run

hadolint ​

Pkl: Builtins.hadolint

Dockerfile linter

  • Files: **/Dockerfile*
  • Install: mise use hadolint
  • Check: hadolint {{files}}

hclfmt ​

Pkl: Builtins.hclfmt

Hashicorp's hclfmt

  • Files: **/*.hcl
  • Install: mise use go:github.com/hashicorp/hcl/v2/cmd/hclfmt
  • Fix: hclfmt -w {{files}}

jactionlint ​

Pkl: Builtins.jactionlint

GitHub Actions workflow linter (jdx/jactionlint, a maintained actionlint fork)

  • Files: .github/workflows/*.y*ml, .github/actions/**/action.y*ml, .github/dependabot.y*ml
  • Install: mise use jactionlint
  • Check: jactionlint --format gcc {{files}}
  • Check (diff): hk util sarif-diff -- jactionlint --format sarif {{files}}
  • Fix: jactionlint --fix {{files}}
  • Options: batch = true

kube-linter ​

Pkl: Builtins.kube_linter

Check Kubernetes manifests for security and reliability issues

  • Files: **/k8s/**/*.yaml, **/k8s/**/*.yml, **/kubernetes/**/*.yaml, **/kubernetes/**/*.yml, **/manifests/**/*.yaml, **/manifests/**/*.yml, **/deploy/**/*.yaml, **/deploy/**/*.yml, **/deployments/**/*.yaml, **/deployments/**/*.yml
  • Install: mise use kube-linter
  • Check: kube-linter lint --fail-if-no-objects-found {{files}}
  • Options: exclude = List("**/templates/**", "**/values.yaml", "**/values.yml", "**/values-*.yaml", "**/values-*.yml", "**/kustomization.yaml", "**/kustomization.yml")

kubeconform ​

Pkl: Builtins.kubeconform

Kubernetes manifest validator

  • Files: **/k8s/**/*.yaml, **/k8s/**/*.yml, **/kubernetes/**/*.yaml, **/kubernetes/**/*.yml, **/manifests/**/*.yaml, **/manifests/**/*.yml, **/deploy/**/*.yaml, **/deploy/**/*.yml, **/deployments/**/*.yaml, **/deployments/**/*.yml
  • Install: mise use kubeconform
  • Check: kubeconform -summary -strict -ignore-missing-schemas {{files}}
  • Options: exclude = List("**/templates/**", "**/values.yaml", "**/values.yml", "**/kustomization.yaml", "**/kustomization.yml")

mise ​

Pkl: Builtins.mise

mise-en-place's built-in formatter and linter

  • Files: mise.toml, mise.*.toml, .mise.toml, .mise.*.toml, mise/config.toml, mise/config.*.toml, .mise/config.toml, .mise/config.*.toml, .config/mise.toml, .config/mise.*.toml, .config/mise/config.toml, .config/mise/config.*.toml, .config/mise/mise.toml, .config/mise/mise.*.toml, .config/mise/conf.d/*.toml
  • Install: project page
  • Check: mise fmt --check
  • Fix: mise fmt

mise-config-dir ​

Pkl: Builtins.mise_config_dir

mise formatter for a global config repository checked out at ~/.config/mise (e.g. mise bootstrap --adopt)

  • Files: config.toml, config.*.toml, conf.d/*.toml, conf.d/*/mise.toml, conf.d/*/mise.*.toml

  • Install: project page

  • Check: hk util format-diff {{files}} -- mise fmt --stdin

  • Check (diff): hk util format-diff {{files}} -- mise fmt --stdin

  • Fix:

    sh
    sh -c 'status=0
    for f in "$@"; do
      tmp=$(mktemp) || exit 1
      # An empty result for a non-empty file is a formatter failure, as in `hk util format-diff`.
      if mise fmt --stdin < "$f" > "$tmp" && { [ -s "$tmp" ] || [ ! -s "$f" ]; }; then
        cat "$tmp" > "$f" || status=1
      else
        status=1
      fi
      rm -f "$tmp"
    done
    exit $status' sh {{files}}
  • Options: exclude = List("conf.d/*/[!m]*.toml", "conf.d/*/m[!i]*.toml", "conf.d/*/mi[!s]*.toml", "conf.d/*/mis[!e]*.toml", "conf.d/*/mise[!.]*.toml")

packer-fmt ​

Pkl: Builtins.packer_fmt

Packer HCL2 template formatter

  • Files: **/*.pkr.hcl, **/*.pkrvars.hcl
  • Install: mise use packer
  • Check: packer fmt -check {{files}}
  • Check (diff): hk util format-diff {{files}} -- packer fmt -
  • Fix: packer fmt {{files}}

pinact ​

Pkl: Builtins.pinact

Pin GitHub Actions to commit SHA for security

  • Files: .github/workflows/*, **/action.* that are yaml files
  • Install: mise use pinact
  • Check: pinact run --verify-comment --check {{files}}
  • Check (diff): hk util sarif-diff -- pinact run --verify-comment --check --format sarif {{files}}
  • Fix: pinact run --verify-comment {{files}}

pinact-update ​

Pkl: Builtins.pinact_update

Pin GitHub Actions to update actions to latest versions

  • Files: .github/workflows/*, **/action.* that are yaml files
  • Install: mise use pinact
  • Check: pinact run --update --verify-comment --check {{files}}
  • Check (diff): hk util sarif-diff -- pinact run --update --verify-comment --check --format sarif {{files}}
  • Fix: pinact run --update --verify-comment {{files}}

terraform ​

Pkl: Builtins.terraform

Terraform formatter

  • Files: **/*.tf, **/*.tfvars, **/*.tftest.hcl
  • Install: mise use terraform
  • Check: terraform fmt -check {{files}}
  • Check (diff): hk util format-diff {{files}} -- terraform fmt -
  • Fix: terraform fmt {{files}}

terraform-docs ​

Pkl: Builtins.terraform_docs

Terraform module documentation generator

  • Files: **/*.tf, **/*.tf.json, **/*.tofu, **/.terraform.lock.hcl

  • Install: mise use terraform-docs

  • Check:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    terraform-docs markdown table --output-check --output-file README.md --output-mode inject "$dir" || code=1
    done; exit $code; }
  • Fix:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    terraform-docs markdown table --output-file README.md --output-mode inject "$dir" || code=1
    done; exit $code; }
  • Options: exclude = "**/.terraform/**"

terraform-validate ​

Pkl: Builtins.terraform_validate

Terraform configuration validator

  • Files: **/*.tf, **/*.tfvars, **/*.tf.json, **/*.tofu, **/.terraform.lock.hcl

  • Install: mise use terraform

  • Check:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    terraform -chdir="$dir" validate && continue
    terraform -chdir="$dir" init -backend=false -input=false > /dev/null || { code=1; continue; }
    terraform -chdir="$dir" validate || code=1
    done; exit $code; }
  • Options: exclude = "**/.terraform/**"

terragrunt-hcl-fmt ​

Pkl: Builtins.terragrunt_hcl_fmt

Terragrunt HCL formatter

  • Files: **/*.hcl

  • Install: mise use terragrunt

  • Check:

    sh
    set --
    for f in {{ files }}; do set -- "$@" "--filter=./$f"; done
    if [ "$#" -eq 0 ]; then exit 0; fi
    terragrunt hcl fmt --check --diff "$@"
  • Fix:

    sh
    set --
    for f in {{ files }}; do set -- "$@" "--filter=./$f"; done
    if [ "$#" -eq 0 ]; then exit 0; fi
    terragrunt hcl fmt "$@"
  • Options: exclude = List("**/.terraform/**", "**/.terragrunt-cache/**")

terragrunt-hcl-validate ​

Pkl: Builtins.terragrunt_hcl_validate

Terragrunt HCL validator

  • Files: **/*.hcl

  • Install: mise use terragrunt

  • Check:

    sh
    set --
    for f in {{ files }}; do
    case "$f" in */*) d="./${f%/*}" ;; *) d="." ;; esac
    set -- "$@" "--filter=$d" "--filter=reading=./$f"
    done
    if [ "$#" -eq 0 ]; then exit 0; fi
    terragrunt hcl validate --show-config-path --log-level error "$@"
  • Options: exclude = List("**/.terraform/**", "**/.terragrunt-cache/**")

tf-lint ​

Pkl: Builtins.tf_lint

Terraform linter

  • Files: **/*.tf, **/*.tfvars, **/*.tofu

  • Install: mise use tflint

  • Check:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    tflint --chdir="$dir" || code=1
    done; exit $code; }
  • Fix:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    tflint --chdir="$dir" --fix || tflint --chdir="$dir" || code=1
    done; exit $code; }
  • Options: exclude = "**/.terraform/**"

tofu ​

Pkl: Builtins.tofu

OpenTofu formatter

  • Files: **/*.tf, **/*.tfvars, **/*.tftest.hcl
  • Install: mise use opentofu
  • Check: tofu fmt -check {{files}}
  • Check (diff): hk util format-diff {{files}} -- tofu fmt -
  • Fix: tofu fmt {{files}}

tofu-validate ​

Pkl: Builtins.tofu_validate

OpenTofu configuration validator

  • Files: **/*.tf, **/*.tfvars, **/*.tf.json, **/*.tofu, **/*.tofu.json, **/.terraform.lock.hcl

  • Install: mise use opentofu

  • Check:

    sh
    for f in {{ files }}; do dirname "$f"; done | sort -u | { code=0; while IFS= read -r dir; do
    tofu -chdir="$dir" validate && continue
    tofu -chdir="$dir" init -backend=false -input=false > /dev/null || { code=1; continue; }
    tofu -chdir="$dir" validate || code=1
    done; exit $code; }
  • Options: exclude = "**/.terraform/**"

zizmor ​

Pkl: Builtins.zizmor

GitHub Actions security static analysis tool

  • Files: .github/workflows/*.yml, .github/workflows/*.yaml, .github/dependabot.yml, **/action.yml, **/action.yaml
  • Install: mise use zizmor
  • Check: zizmor --no-progress {{files}}
  • Fix: zizmor --no-progress --fix {{files}}

Java ​

google-java-format ​

Pkl: Builtins.google_java_format

Google Java Format

  • Files: **/*.java
  • Install: mise use google-java-format
  • Check: google-java-format --dry-run --set-exit-if-changed {{files}}
  • Check (list files): google-java-format --dry-run {{files}}
  • Fix: google-java-format --replace {{files}}

JavaScript/TypeScript ​

biome ​

Pkl: Builtins.biome

Fast formatter and linter

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx, **/*.json
  • Install: mise use biome
  • Check: biome check --no-errors-on-unmatched {{files}}
  • Fix: biome check --write --no-errors-on-unmatched {{files}}

deno ​

Pkl: Builtins.deno

Deno formatter

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx
  • Install: mise use deno
  • Check: deno fmt --check {{files}}
  • Fix: deno fmt {{files}}

deno-check ​

Pkl: Builtins.deno_check

Deno type checker

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx
  • Install: mise use deno
  • Check: deno check {{files}}

eslint ​

Pkl: Builtins.eslint

Pluggable JavaScript linter

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx
  • Install: mise use npm:eslint
  • Check: eslint {{files}}
  • Fix: eslint --fix {{files}}
  • Options: batch = true

knip ​

Pkl: Builtins.knip

Find unused files, dependencies, and exports

  • Files: javascript, typescript files
  • Install: mise use npm:knip
  • Check: knip --no-progress --directory {{workspace}}
  • Fix: knip --fix --no-progress --directory {{workspace}}
  • Options: workspace_indicator = "package.json"

ox-lint ​

Pkl: Builtins.ox_lint

Oxidation compiler linter

  • Files: **/*.js, **/*.mjs, **/*.cjs, **/*.ts, **/*.mts, **/*.cts, **/*.jsx, **/*.tsx, **/*.vue, **/*.svelte, **/*.astro
  • Install: mise use oxlint
  • Check: oxlint --deny-warnings {{files}}
  • Fix: oxlint --deny-warnings --fix {{files}}

oxfmt ​

Pkl: Builtins.oxfmt

Fast Rust-powered code formatter (Prettier compatible)

  • Files: **/*.js, **/*.mjs, **/*.cjs, **/*.ts, **/*.mts, **/*.cts, **/*.jsx, **/*.tsx, **/*.mdx, **/*.vue, **/*.json, **/*.jsonc, **/*.json5, **/*.yaml, **/*.yml, **/*.toml, **/*.md, **/*.markdown, **/*.html, **/*.htm, **/*.css, **/*.scss, **/*.less, **/*.graphql, **/*.gql, **/*.handlebars, **/*.hbs
  • Install: mise use oxfmt
  • Check: oxfmt --check --no-error-on-unmatched-pattern {{files}}
  • Check (diff): hk util format-diff {{files}} -- oxfmt --stdin-filepath '{}'
  • Fix: oxfmt --write --no-error-on-unmatched-pattern {{files}}
  • Options: exclude = List("**/pnpm-lock.yaml", "**/package-lock.json")

prettier ​

Pkl: Builtins.prettier

Opinionated code formatter

  • Files: **/*.js, **/*.jsx, **/*.mjs, **/*.cjs, **/*.ts, **/*.tsx, **/*.mts, **/*.cts, **/*.css, **/*.scss, **/*.less, **/*.html, **/*.json, **/*.json5, **/*.jsonc, **/*.yaml, **/*.yml, **/*.markdown, **/*.markdown.mdx, **/*.md, **/*.graphql, **/*.handlebars, **/*.svelte, **/*.astro, **/*.htmlangular, **/*.vue
  • Install: mise use prettier
  • Check: prettier --check {{files}}
  • Check (list files): prettier --list-different {{files}}
  • Fix: prettier --write {{files}}
  • Options: batch = true

sherif ​

Pkl: Builtins.sherif

Opinionated, zero-config linter for TypeScript & JavaScript monorepos

  • Files: **/package.json, **/pnpm-workspace.yaml
  • Install: mise use sherif
  • Check: sherif
  • Fix: sherif --fix --no-install

standard-js ​

Pkl: Builtins.standard_js

JavaScript Standard Style

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx
  • Install: mise use npm:standard
  • Check: standard {{files}}
  • Fix: standard --fix {{files}}

tsc ​

Pkl: Builtins.tsc

TypeScript type checker

  • Files: **/*.ts, **/*.tsx
  • Install: mise use npm:typescript
  • Check: tsc --noEmit -p {{workspace_indicator}}
  • Options: workspace_indicator = "tsconfig.json"

tsserver ​

Pkl: Builtins.tsserver

TypeScript language server diagnostics

  • Files: **/*.ts, **/*.tsx
  • Install: mise use npm:tsc-files npm:typescript
  • Check: tsc-files --noEmit {{files}}

vp-check ​

Pkl: Builtins.vp_check

Formats, lints, and type checks code together

  • Files: **/*.js, **/*.mjs, **/*.cjs, **/*.ts, **/*.mts, **/*.cts, **/*.jsx, **/*.tsx, **/*.mdx, **/*.vue, **/*.svelte, **/*.astro, **/*.json, **/*.jsonc, **/*.json5, **/*.yaml, **/*.yml, **/*.md, **/*.markdown, **/*.html, **/*.htm, **/*.css, **/*.scss, **/*.less, **/*.graphql, **/*.gql, **/*.handlebars, **/*.hbs, **/*.toml
  • Install: mise use vp
  • Check: vp check --no-error-on-unmatched-pattern {{files}}
  • Fix: vp check --fix --no-error-on-unmatched-pattern {{files}}
  • Options: workspace_indicator = "package.json"

vp-fmt ​

Pkl: Builtins.vp_fmt

Formats code with Oxfmt

  • Files: **/*.js, **/*.mjs, **/*.cjs, **/*.ts, **/*.mts, **/*.cts, **/*.jsx, **/*.tsx, **/*.mdx, **/*.vue, **/*.json, **/*.jsonc, **/*.json5, **/*.yaml, **/*.yml, **/*.toml, **/*.md, **/*.markdown, **/*.html, **/*.htm, **/*.css, **/*.scss, **/*.less, **/*.graphql, **/*.gql, **/*.handlebars, **/*.hbs
  • Install: mise use vp
  • Check: vp fmt --check --no-error-on-unmatched-pattern {{files}}
  • Check (list files): vp fmt --list-different --no-error-on-unmatched-pattern {{files}}
  • Fix: vp fmt --no-error-on-unmatched-pattern {{files}}
  • Options: workspace_indicator = "package.json"

vp-lint ​

Pkl: Builtins.vp_lint

Lints code with OxLint

  • Files: **/*.js, **/*.mjs, **/*.cjs, **/*.ts, **/*.mts, **/*.cts, **/*.jsx, **/*.tsx, **/*.mdx, **/*.vue, **/*.svelte, **/*.astro
  • Install: mise use vp
  • Check: vp lint --deny-warnings --no-error-on-unmatched-pattern {{files}}
  • Fix: vp lint --deny-warnings --fix --no-error-on-unmatched-pattern {{files}}
  • Options: workspace_indicator = "package.json"

xo ​

Pkl: Builtins.xo

JavaScript/TypeScript linter with great defaults

  • Files: **/*.js, **/*.jsx, **/*.ts, **/*.tsx
  • Install: mise use npm:xo
  • Check: xo {{files}}
  • Fix: xo --fix {{files}}

Lua ​

luacheck ​

Pkl: Builtins.luacheck

Lua linter

  • Files: lua files
  • Install: project page
  • Check: luacheck {{files}}

selene ​

Pkl: Builtins.selene

Lua linter

  • Files: lua files
  • Install: mise use aqua:Kampfkarren/selene/light
  • Check: selene {{files}}

stylua ​

Pkl: Builtins.stylua

Lua formatter

  • Files: lua files
  • Install: mise use stylua
  • Check: stylua --check {{files}}
  • Check (diff): hk util format-diff {{files}} -- stylua --stdin-filepath '{}' -
  • Fix: stylua {{files}}

Markdown ​

contextlint ​

Pkl: Builtins.contextlint

Rule-based linter for structured Markdown documents

  • Files: markdown files
  • Install: mise use npm:@contextlint/cli
  • Check: contextlint {{files}}
  • Options: workspace_indicator = "contextlint.config.json"

mado ​

Pkl: Builtins.mado

Fast Markdown linter (CommonMark/GFM)

  • Files: markdown files
  • Install: mise use aqua:akiomik/mado
  • Check: mado check {{files}}

markdown-lint ​

Pkl: Builtins.markdown_lint

Markdown linter

  • Files: **/*.md, **/*.markdown
  • Install: mise use npm:markdownlint-cli
  • Check: markdownlint {{files}}
  • Fix: markdownlint --fix {{files}}

mdschema ​

Pkl: Builtins.mdschema

Schema-based Markdown documentation validator

  • Files: markdown files
  • Install: mise use aqua:jackchuka/mdschema
  • Check: mdschema check {{files}}
  • Options: workspace_indicator = ".mdschema.yml"

rumdl ​

Pkl: Builtins.rumdl

Markdown linter

  • Files: **/*.md, **/*.markdown
  • Install: mise use rumdl
  • Check: rumdl check {{files}}
  • Check (diff): rumdl check --diff {{files}}
  • Fix: rumdl check --fix {{files}}
  • Options: check_after_diff = true

rumdl-format ​

Pkl: Builtins.rumdl_format

Markdown formatter

  • Files: **/*.md, **/*.markdown
  • Install: mise use rumdl
  • Check (diff): rumdl fmt --check --diff {{files}}
  • Fix: rumdl fmt {{files}}

ryl-markdown ​

Pkl: Builtins.ryl_markdown

Lint YAML embedded in Markdown (front matter + fenced yaml blocks) with ryl

  • Files: markdown files
  • Install: mise use aqua:owenlamont/ryl
  • Check: ryl check --markdown {{files}}
  • Check (diff): ryl check --diff --markdown {{files}}
  • Check (list files): ryl check --list-files --markdown {{files}}
  • Fix: ryl check --fix --markdown {{files}}
  • Options: check_after_diff = true

ryl-markdown-format ​

Pkl: Builtins.ryl_markdown_format

Format YAML embedded in Markdown (front matter + fenced yaml blocks) with ryl

  • Files: markdown files
  • Install: mise use aqua:owenlamont/ryl
  • Check: ryl format --check --markdown {{files}}
  • Check (diff): ryl format --diff --markdown {{files}}
  • Fix: ryl format --markdown {{files}}

Nix ​

alejandra ​

Pkl: Builtins.alejandra

Alternative Nix formatter

  • Files: **/*.nix
  • Install: project page
  • Check: alejandra --check {{files}}
  • Fix: alejandra {{files}}

deadnix ​

Pkl: Builtins.deadnix

Scan Nix files for dead code

  • Files: **/*.nix
  • Install: mise use cargo:deadnix
  • Check: deadnix --fail {{files}}
  • Fix: deadnix --edit {{files}}

nil ​

Pkl: Builtins.nil

Nix Language server

  • Files: **/*.nix
  • Install: project page
  • Check: nil diagnostics --deny-warnings {{files}}

nix-fmt ​

Pkl: Builtins.nix_fmt

Nix formatter

  • Files: **/*.nix

  • Install: project page

  • Check:

    sh
    # Windows: nothing runs
    # other platforms:
    nixfmt --check {{ files }}
  • Fix:

    sh
    # Windows: nothing runs
    # other platforms:
    nixfmt {{ files }}

nixf-diagnose ​

Pkl: Builtins.nixf_diagnose

Nix linter based on libnixf

  • Files: **/*.nix
  • Install: project page
  • Check: nixf-diagnose {{files}}

nixpkgs-format ​

Pkl: Builtins.nixpkgs_format

Nixpkgs formatter

  • Files: **/*.nix
  • Install: project page
  • Check: nixpkgs-fmt --check {{files}}
  • Fix: nixpkgs-fmt {{files}}

Other Languages ​

astro ​

Pkl: Builtins.astro

Astro component checker

  • Files: **/*.astro
  • Install: project page
  • Check: astro check {{files}}

clang-format ​

Pkl: Builtins.clang_format

C/C++ formatter

  • Files: **/*.c, **/*.h, **/*.cpp, **/*.hpp, **/*.cc, **/*.hh, **/*.cxx, **/*.hxx
  • Install: mise use pipx:clang-format
  • Check: clang-format --dry-run -Werror {{files}}
  • Fix: clang-format -i {{files}}

cmake-format ​

Pkl: Builtins.cmake_format

Source code formatter for cmake listfiles

  • Files: **/CMakeLists.txt, **/*.cmake
  • Install: mise use pipx:cmakelang
  • Check: cmake-format --check {{files}}
  • Fix: cmake-format --in-place {{files}}

cpp-lint ​

Pkl: Builtins.cpp_lint

C++ style checker

  • Files: **/*.c, **/*.h, **/*.cpp, **/*.hpp, **/*.cc, **/*.hh, **/*.cxx, **/*.hxx
  • Install: mise use pipx:cpplint
  • Check: cpplint {{files}}

dprint ​

Pkl: Builtins.dprint

Pluggable code formatter

  • Files: text files
  • Install: mise use dprint
  • Check: dprint check --allow-no-files {{files}}
  • Check (list files): dprint check --allow-no-files --list-different {{files}}
  • Fix: dprint fmt --allow-no-files {{files}}

ktlint ​

Pkl: Builtins.ktlint

Kotlin linter and formatter

  • Files: **/*.kt
  • Install: mise use ktlint
  • Check: ktlint {{files}}
  • Fix: ktlint -F {{files}}

swiftlint ​

Pkl: Builtins.swiftlint

Swift style and conventions

  • Files: **/*.swift
  • Install: mise use swiftlint
  • Check: swiftlint lint {{files}}
  • Fix: swiftlint --fix {{files}}

vacuum ​

Pkl: Builtins.vacuum

Fast OpenAPI linter

  • Files: **/*openapi*.yaml, **/*openapi*.yml, **/*openapi*.json, **/*swagger*.yaml, **/*swagger*.yml, **/*swagger*.json
  • Install: mise use vacuum
  • Check: vacuum lint {{files}}
  • Fix: vacuum lint --fix {{files}}

PHP ​

php-cs ​

Pkl: Builtins.php_cs

PHP coding standards

  • Files: **/*.php
  • Install: project page
  • Check: phpcs {{files}}
  • Fix: phpcbf {{files}}

phpstan ​

Pkl: Builtins.phpstan

PHP static analyzer

  • Files: **/*.php
  • Check: phpstan analyse --no-progress {{files}}

Package ​

aqua-update-checksum ​

Pkl: Builtins.aqua_update_checksum

create or update aqua checksums

  • Files: {aqua,.aqua}.{yml,yaml}, {aqua,.aqua}/**/*.{yml,yaml}, aqua-checksums.json, {aqua,.aqua}/aqua-checksums.json
  • Install: mise use aqua
  • Fix: aqua update-checksum --prune

Pkl ​

pkl ​

Pkl: Builtins.pkl

Pkl configuration language

  • Files: pkl files
  • Install: mise use pkl
  • Check: pkl eval {{files}} >/dev/null

pkl-format ​

Pkl: Builtins.pkl_format

Pkl formatter

  • Files: pkl files

  • Install: mise use pkl

  • Check (list files): pkl format --diff-name-only {{ files }}

  • Fix:

    sh
    pkl format --write {{ files }}
    code=$?
    if [ $code -eq 11 ]; then
    exit 0
    else
    exit $code
    fi
  • Options: shell = "sh -c"

Python ​

black ​

Pkl: Builtins.black

Opinionated Python formatter

  • Files: **/*.py

  • Install: mise use black

  • Check: black --check {{files}}

  • Check (list files):

    sh
    # Windows: nothing runs
    # other platforms:
    set -- {{ files }}
    out=$(black --check "$@" 2>&1) && exit 0
    status=$?
    printf '%s\n' "$out" | while IFS= read -r line; do
    case "$line" in
    "would reformat "*) printf '%s\n' "${line#would reformat }" ;;
    "error: cannot format "*)
      # The message after the path may contain ": ", so match the inputs.
      for f; do
      case "$line" in "error: cannot format $f: "*) printf '%s\n' "$f" ;; esac
      done
      ;;
    esac
    done
    exit $status
  • Fix: black {{files}}

flake8 ​

Pkl: Builtins.flake8

Python style guide enforcement

  • Files: **/*.py
  • Install: mise use pipx:flake8
  • Check: flake8 {{files}}

isort ​

Pkl: Builtins.isort

Python import sorter

  • Files: **/*.py
  • Install: mise use pipx:isort
  • Check: isort --check-only {{files}}
  • Check (diff): isort --check-only --diff {{files}}
  • Fix: isort {{files}}

mypy ​

Pkl: Builtins.mypy

Static type checker for Python

  • Files: **/*.py, **/*.pyi
  • Install: mise use pipx:mypy
  • Check: mypy {{files}}

pylint ​

Pkl: Builtins.pylint

Python code analysis

  • Files: **/*.py
  • Install: mise use pipx:pylint
  • Check: pylint {{files}}

pyright ​

Pkl: Builtins.pyright

Static type checker for Python

  • Files: **/*.py, **/*.pyi, **/*.pyw
  • Check: pyright {{files}}

python-check-ast ​

Pkl: Builtins.python_check_ast

Validate Python syntax by parsing the AST

  • Files: **/*.py
  • Install: mise use python
  • Check: hk util python-check-ast {{files}}

python-debug-statements ​

Pkl: Builtins.python_debug_statements

Detect debug statements in Python code

  • Files: **/*.py
  • Check: hk util python-debug-statements {{files}}

ruff ​

Pkl: Builtins.ruff

Fast Python linter

  • Files: python files
  • Install: mise use ruff
  • Check: ruff check --force-exclude {{files}}
  • Check (diff): ruff check --force-exclude --diff --exit-non-zero-on-fix {{ files }} && ruff check --force-exclude {{ files }}
  • Fix: ruff check --force-exclude --fix {{files}}
  • Options: check_after_diff = true

ruff-format ​

Pkl: Builtins.ruff_format

Fast Python formatter (part of ruff)

  • Files: python files
  • Install: mise use ruff
  • Check (diff): ruff format --quiet --force-exclude --diff {{files}}
  • Fix: ruff format --quiet --force-exclude {{files}}

ty ​

Pkl: Builtins.ty

Fast Python type checker

  • Files: **/*.py, **/*.pyi
  • Install: mise use ty
  • Check: ty check {{files}}

Ruby ​

brakeman ​

Pkl: Builtins.brakeman

Security scanner for Rails

  • Files: ruby files
  • Install: mise use gem:brakeman
  • Check: brakeman -q -w2

bundle-audit ​

Pkl: Builtins.bundle_audit

Dependency security audit

  • Files: **/Gemfile.lock
  • Install: mise use gem:bundler-audit
  • Check: bundle-audit check {{files}}
  • Fix: bundle-audit update

erb ​

Pkl: Builtins.erb

ERB template linter

  • Files: **/*.erb
  • Install: mise use ruby
  • Check: erb -P -x -T - {{ files }} | ruby -c

fasterer ​

Pkl: Builtins.fasterer

Performance suggestions

  • Files: ruby files
  • Install: mise use gem:fasterer
  • Check: fasterer {{files}}

herb-format ​

Pkl: Builtins.herb_format

HTML+ERB formatter (experimental)

  • Files: **/*.herb, **/*.html.herb, **/*.html, **/*.rhtml, **/*.html.erb, **/*.html+*.erb, **/*.turbo_stream.erb
  • Install: mise use npm:@herb-tools/formatter
  • Check: herb-format --check {{files}}
  • Check (diff): hk util format-diff {{files}} -- herb-format -
  • Fix: herb-format {{files}}
  • Options: batch = true

herb-lint ​

Pkl: Builtins.herb_lint

HTML+ERB linter

  • Files: **/*.herb, **/*.html.herb, **/*.html, **/*.rhtml, **/*.html.erb, **/*.html+*.erb, **/*.turbo_stream.erb
  • Install: mise use npm:@herb-tools/linter
  • Check: herb-lint {{files}}
  • Fix: herb-lint --fix {{files}}
  • Options: batch = true

reek ​

Pkl: Builtins.reek

Code smell detector

  • Files: ruby files
  • Install: mise use gem:reek
  • Check: reek {{files}}

rubocop ​

Pkl: Builtins.rubocop

Ruby style guide

  • Files: **/*.rb, **/*.arb, **/*.axlsx, **/*.builder, **/*.gemfile, **/*.gemspec, **/*.jb, **/*.jbuilder, **/*.mspec, **/*.opal, **/*.pluginspec, **/*.podspec, **/*.rabl, **/*.rake, **/*.rbw, **/*.ru, **/*.ruby, **/*.schema, **/*.spec, **/*.thor, **/.irbrc, **/.pryrc, **/.simplecov, **/buildfile, **/Appraisals, **/Berksfile, **/Brewfile, **/Buildfile, **/Capfile, **/Dangerfile, **/Deliverfile, **/Fastfile, **/*Fastfile, **/Gemfile, **/Guardfile, **/Jarfile, **/Mavenfile, **/Podfile, **/Puppetfile, **/Rakefile, **/rakefile, **/Schemafile, **/Snapfile, **/Steepfile, **/Thorfile, **/Vagrantfile
  • Install: mise use gem:rubocop
  • Check: rubocop --force-exclusion {{files}}
  • Check (list files): rubocop --force-exclusion --format files {{files}}
  • Fix: rubocop --force-exclusion --autocorrect {{files}}
  • Options: exclude = List("node_modules/**/*", "tmp/**/*", "vendor/**/*", ".git/**/*")

rubocop-server ​

Pkl: Builtins.rubocop_server

Ruby style guide (using RuboCop's --server mode)

  • Files: **/*.rb, **/*.arb, **/*.axlsx, **/*.builder, **/*.gemfile, **/*.gemspec, **/*.jb, **/*.jbuilder, **/*.mspec, **/*.opal, **/*.pluginspec, **/*.podspec, **/*.rabl, **/*.rake, **/*.rbw, **/*.ru, **/*.ruby, **/*.schema, **/*.spec, **/*.thor, **/.irbrc, **/.pryrc, **/.simplecov, **/buildfile, **/Appraisals, **/Berksfile, **/Brewfile, **/Buildfile, **/Capfile, **/Dangerfile, **/Deliverfile, **/Fastfile, **/*Fastfile, **/Gemfile, **/Guardfile, **/Jarfile, **/Mavenfile, **/Podfile, **/Puppetfile, **/Rakefile, **/rakefile, **/Schemafile, **/Snapfile, **/Steepfile, **/Thorfile, **/Vagrantfile
  • Install: mise use gem:rubocop
  • Check: rubocop --server --force-exclusion {{files}}
  • Check (list files): rubocop --server --force-exclusion --format files {{files}}
  • Fix: rubocop --server --force-exclusion --autocorrect {{files}}
  • Options: exclude = List("node_modules/**/*", "tmp/**/*", "vendor/**/*", ".git/**/*")

sorbet ​

Pkl: Builtins.sorbet

Type checker for Ruby

  • Files: ruby files
  • Install: mise use gem:sorbet
  • Check: srb tc {{files}}

standard-rb ​

Pkl: Builtins.standard_rb

Ruby Standard Style

  • Files: ruby files
  • Install: mise use gem:standard
  • Check: standardrb --force-exclusion {{files}}
  • Fix: standardrb --force-exclusion --fix {{files}}

Rust ​

cargo-check ​

Pkl: Builtins.cargo_check

Fast Rust type checking

  • Files: **/*.rs
  • Install: mise use rust
  • Check: cargo check --quiet
  • Fix: cargo fix --allow-dirty --allow-staged --quiet

cargo-clippy ​

Pkl: Builtins.cargo_clippy

Rust linter

  • Files: **/*.rs
  • Install: mise use rust
  • Check: cargo clippy --manifest-path {{workspace_indicator}} --quiet
  • Fix: cargo clippy --manifest-path {{workspace_indicator}} --fix --allow-dirty --allow-staged --quiet
  • Options: workspace_indicator = "Cargo.toml"

cargo-deny ​

Pkl: Builtins.cargo_deny

Rust dependency linter

  • Files: **/Cargo.toml, **/Cargo.lock, **/deny.toml, **/.deny.toml, **/deny.exceptions.toml, **/.deny.exceptions.toml
  • Install: mise use cargo-deny
  • Check: cargo-deny --locked --workspace check
  • Options: workspace_indicator = "Cargo.toml", dir = "{{workspace}}"

cargo-fmt ​

Pkl: Builtins.cargo_fmt

Rust code formatter

  • Files: **/*.rs, **/rustfmt.toml, **/.rustfmt.toml
  • Install: mise use rust
  • Check: cargo fmt --check --manifest-path {{workspace_indicator}}
  • Check (list files): cargo fmt --check --manifest-path {{workspace_indicator}} -- --files-with-diff
  • Fix: cargo fmt --manifest-path {{workspace_indicator}}
  • Options: workspace_indicator = "Cargo.toml"

rustfmt ​

Pkl: Builtins.rustfmt

Rust code formatter (standalone)

  • Files: **/*.rs
  • Install: mise use rust
  • Check: rustfmt --check --edition 2024 {{files}}
  • Check (list files): rustfmt --check --edition 2024 --files-with-diff {{files}}
  • Fix: rustfmt --edition 2024 {{files}}

Secrets ​

betterleaks ​

Pkl: Builtins.betterleaks

A Better Secrets Scanner built for configurability and speed

  • Files: text files
  • Install: mise use betterleaks
  • Check: betterleaks dir --redact --verbose --no-banner {{files}}

gitleaks ​

Pkl: Builtins.gitleaks

Secret scanner for repository working trees

  • Install: mise use gitleaks
  • Check: gitleaks dir --redact --verbose --no-banner .

kingfisher ​

Pkl: Builtins.kingfisher

Secret scanner with live validation and 1,000+ rules

  • Files: text files
  • Install: mise use kingfisher
  • Check: kingfisher scan {{files}} --no-update-check --no-validate --quiet

trufflehog ​

Pkl: Builtins.trufflehog

Secret scanner that classifies 800+ credential types

  • Files: text files
  • Check: trufflehog filesystem {{files}} --fail --no-update --no-verification

Shell ​

shellcheck ​

Pkl: Builtins.shellcheck

Shell script analyzer

  • Files: **/*.sh, **/*.bash; or sh, bash files
  • Install: mise use shellcheck
  • Check: shellcheck {{files}}
  • Check (diff): shellcheck --format=diff {{files}}
  • Options: batch = true, check_after_diff = true

shellharden ​

Pkl: Builtins.shellharden

The corrective bash syntax highlighter

  • Files: bash, sh files
  • Install: mise use shellharden
  • Check: shellharden --check {{files}}
  • Check (diff): hk util format-diff --no-stdin {{files}} -- shellharden --transform '{}'
  • Fix: shellharden --replace {{files}}
  • Options: batch = true

shfmt ​

Pkl: Builtins.shfmt

Shell formatter

  • Files: **/*.sh, **/*.bash, **/*.mksh, **/*.bats, **/*.zsh; or sh, bash, zsh files

  • Install: mise use shfmt

  • Check (diff): shfmt -d --apply-ignore {{ files }}

  • Check (list files):

    sh
    files=$(shfmt -l --apply-ignore {{ files }})
    if [ -n "$files" ]; then
    echo "$files"
    exit 1
    fi
  • Fix: shfmt -w --apply-ignore {{ files }}

  • Options: batch = true

Special Purpose ​

byte-order-marker ​

Pkl: Builtins.byte_order_marker

Detect UTF-8 BOM

  • Files: text files
  • Check (diff): hk util check-byte-order-marker --diff {{files}}
  • Fix: hk util fix-byte-order-marker {{files}}

check-added-large-files ​

Pkl: Builtins.check_added_large_files

Prevent committing large files

  • Files: **/*
  • Check: hk util check-added-large-files {{files}}
  • Options: allow_binary = true

check-case-conflict ​

Pkl: Builtins.check_case_conflict

Detect case-insensitive filename conflicts

  • Files: **/*
  • Check: hk util check-case-conflict {{files}}
  • Options: allow_binary = true, allow_symlinks = true

check-conventional-commit ​

Pkl: Builtins.check_conventional_commit

Verify commit message matches conventional commits formatting

  • Check: hk util check-conventional-commit {{commit_msg_file}}

check-executables-have-shebangs ​

Pkl: Builtins.check_executables_have_shebangs

Verify executable files have shebang lines

  • Files: text files
  • Check: hk util check-executables-have-shebangs {{files}}

check-merge-conflict ​

Pkl: Builtins.check_merge_conflict

Detect merge conflict markers

  • Files: text files
  • Check: hk util check-merge-conflict --assume-in-merge {{files}}

check-shebang-scripts-are-executable ​

Pkl: Builtins.check_shebang_scripts_are_executable

Verify files with shebang lines are executable

  • Files: text files
  • Check: hk util check-shebang-scripts-are-executable {{files}}

Pkl: Builtins.check_symlinks

Detect broken symlinks

  • Files: **/*
  • Check: hk util check-symlinks {{files}}
  • Options: allow_symlinks = true

cocogitto-commit-msg ​

Pkl: Builtins.cocogitto_commit_msg

Conventional commits linter

  • Install: mise use cocogitto
  • Check: cog --quiet verify --file {{commit_msg_file}}

Pkl: Builtins.destroyed_symlinks

Detect symlinks replaced by regular files holding their target path

  • Check: hk util destroyed-symlinks

detect-private-key ​

Pkl: Builtins.detect_private_key

Detect accidentally committed private keys

  • Files: text files
  • Check: hk util detect-private-key {{files}}

fix-smart-quotes ​

Pkl: Builtins.fix_smart_quotes

Replace smart quotes with regular quotes

  • Files: text files
  • Check (diff): hk util fix-smart-quotes --diff {{files}}
  • Fix: hk util fix-smart-quotes {{files}}

forbid-submodules ​

Pkl: Builtins.forbid_submodules

Forbid git submodules in the repository

  • Check: hk util forbid-submodules

harper ​

Pkl: Builtins.harper

Grammar checker for prose and documentation

  • Files: text files
  • Install: mise use harper-cli
  • Check: harper-cli lint {{files}}

harper-commit-message ​

Pkl: Builtins.harper_commit_message

Grammar checker for commit message

  • Install: mise use harper-cli
  • Check: harper-cli lint {{commit_msg_file}}

hk-test ​

Pkl: Builtins.hk_test

Run step-defined hk's tests

  • Files: hk.pkl, .config/hk.pkl
  • Check: hk test --quiet

just-format ​

Pkl: Builtins.just_format

Justfile formatter

  • Files: **/justfile, **/*.just

  • Install: mise use just

  • Fix:

    sh
    xargs -d'
    ' -I {} -- just --fmt --unstable --justfile {}

ls-lint ​

Pkl: Builtins.ls_lint

Directory and filename naming linter

  • Files: **/*
  • Install: mise use ls-lint
  • Check: ls-lint
  • Options: allow_binary = true, allow_symlinks = true

lychee ​

Pkl: Builtins.lychee

Fast, async, stream-based link checker

  • Files: text files
  • Install: mise use lychee
  • Check: lychee --no-progress {{files}}

lychee-extended ​

Pkl: Builtins.lychee_extended

Flint's repository-aware link check (requires flint and lychee). See https://github.com/grafana/flint/blob/main/docs/linters/lychee.md

  • Files: text files
  • Install: mise use packslip:grafana/flint lychee
  • Check: flint checker lychee --files-from -

mixed-line-ending ​

Pkl: Builtins.mixed_line_ending

Detect and fix mixed line endings

  • Files: text files
  • Check (diff): hk util mixed-line-ending --diff {{files}}
  • Fix: hk util mixed-line-ending --fix {{files}}

newlines ​

Pkl: Builtins.newlines

Ensure files end with newline

  • Files: text files
  • Check (diff): hk util end-of-file-fixer --diff {{files}}
  • Fix: hk util end-of-file-fixer --fix {{files}}

no-commit-to-branch ​

Pkl: Builtins.no_commit_to_branch

Prevent direct commits to protected branches

  • Check: hk util no-commit-to-branch

osv-scanner ​

Pkl: Builtins.osv_scanner

Vulnerability scanner for dependency lockfiles using the OSV database

  • Files: **/*.deps.json, **/*requirements*.txt, **/buildscript-gradle.lockfile, **/bun.lock, **/cabal.project.freeze, **/Cargo.lock, **/composer.lock, **/conan.lock, **/Gemfile.lock, **/gems.locked, **/go.mod, **/gradle.lockfile, **/gradle/verification-metadata.xml, **/mix.lock, **/npm-shrinkwrap.json, **/package_config.json, **/package-lock.json, **/packages.config, **/packages.lock.json, **/pdm.lock, **/Pipfile.lock, **/pnpm-lock.yaml, **/poetry.lock, **/pom.xml, **/pubspec.lock, **/pylock.toml, **/renv.lock, **/stack.yaml.lock, **/uv.lock, **/yarn.lock
  • Check: osv-scanner scan source --allow-no-lockfiles {{files}}

renovate-deps ​

Pkl: Builtins.renovate_deps

Flint's repository-aware dependency check (requires flint and renovate). See https://github.com/grafana/flint/blob/main/docs/linters/renovate-deps.md

  • Files: **/*
  • Install: mise use packslip:grafana/flint npm:renovate
  • Check: flint checker renovate-deps --files-from -
  • Fix: flint checker renovate-deps --fix --files-from -
  • Options: stage = List(".github/renovate-tracked-deps.json")

textlint ​

Pkl: Builtins.textlint

Pluggable natural language linter

  • Files: **/*.md, **/*.markdown, **/*.txt
  • Install: mise use npm:textlint
  • Check: textlint {{files}}
  • Fix: textlint --fix {{files}}
  • Options: batch = true

trailing-whitespace ​

Pkl: Builtins.trailing_whitespace

Detect and remove trailing whitespace

  • Files: text files
  • Check (diff): hk util trailing-whitespace --diff {{files}}
  • Fix: hk util trailing-whitespace --fix {{files}}

typos ​

Pkl: Builtins.typos

Source code spell checker

  • Files: text files

  • Install: mise use typos

  • Check (diff):

    sh
    status=0
    output=$(typos --force-exclude --diff {{files}}) || status=$?
    [ -z "$output" ] && exit "$status"
    printf "%s" "$output"
    exit 1
  • Fix: typos --force-exclude --write-changes {{ files }}

vale ​

Pkl: Builtins.vale

Prose linter for markup and code comments

  • Files: text files
  • Install: mise use vale
  • Check: vale sync && vale {{ files }}

Typst ​

tinymist ​

Pkl: Builtins.tinymist

Typst linter (requires tinymist 0.14.20 or newer)

  • Files: **/*.typ

  • Install: mise use tinymist

  • Check:

    sh
    code=0
    for f in {{ files }}; do
      tinymist lint "$f" || code=$?
    done
    exit "$code"
  • Options: batch = true, shell = "sh -c"

typstyle ​

Pkl: Builtins.typstyle

Typst formatter

  • Files: **/*.typ
  • Install: mise use typstyle
  • Check (diff): typstyle --diff {{files}}
  • Fix: typstyle --inplace {{files}}

YAML ​

ryl ​

Pkl: Builtins.ryl

Re-implementation of yamllint in Rust

  • Files: yaml files
  • Install: mise use aqua:owenlamont/ryl
  • Check: ryl check {{files}}
  • Check (diff): ryl check --diff {{files}}
  • Check (list files): ryl check --list-files {{files}}
  • Fix: ryl check --fix {{files}}
  • Options: check_after_diff = true

ryl-format ​

Pkl: Builtins.ryl_format

YAML formatter from ryl

  • Files: yaml files
  • Install: mise use aqua:owenlamont/ryl
  • Check: ryl format --check {{files}}
  • Check (diff): ryl format --diff {{files}}
  • Fix: ryl format {{files}}

Add a tool of your own ​

If there is no builtin, define a step with glob, check, and an optional fix command. Only enable batching if the tool can process independent subsets of files correctly.

See custom steps for a complete example, or contributing to contribute a reusable definition.

MIT LicenseCopyright © 2026jdx.dev