# https://hk.jdx.dev/ llms-full.txt <|firecrawl-page-1-lllmstxt|> ## Git Hook Tool [Skip to content](https://hk.jdx.dev/#VPContent) # hk A tool for running hooks on files in a git repository. [Getting Started](https://hk.jdx.dev/getting_started.html) [About](https://hk.jdx.dev/about.html) [GitHub](https://github.com/jdx/hk) [Discord](https://discord.gg/UBa7pJUN7Z) <|firecrawl-page-2-lllmstxt|> ## About hk Git Hook Manager [Skip to content](https://hk.jdx.dev/about.html#VPContent) On this page # About [​](https://hk.jdx.dev/about.html\#about) hk is built by [@jdx](https://github.com/jdx). ## Why does this exist? [​](https://hk.jdx.dev/about.html\#why-does-this-exist) git hooks need to be fast above all else or else developers won't use them. Parallelism is the best (and likely only) way to achieve acceptable performance at the git hook manager level. Existing alternatives to hk such as [lefthook](https://github.com/evilmartians/lefthook) support very basic parallel execution of shell script however because linters may edit files—this naive approach can break down if multiple linters affect the same file. I felt that a git hook manager that had tighter integration with the linters would be able to leverage read/write file locks to enable more aggressive parallelism while preventing race conditions. This read/write locking is the primary reason I built hk, however there are other design decisions worth noting that I think makes hk a better experience than its peers: - hk has a bunch of [builtins](https://github.com/jdx/hk/tree/main/pkl/builtins) you can use for common linters like `prettier` or `black`. - hk stashes unstaged changes before running "fix" hooks. This prevents a common issue with pre-commit hooks where files containing both staged and unstaged changes get modified and the unstaged changes end up being staged erroneously. - By default, hk uses libgit2 to directly interact with git instead of shelling out many times to `git`. (This generally makes hk much faster but there are situations like `fsmonitor` where it may perform worse) - hk is a Rust CLI which gives it great startup performance. - hk is designed to work well with my other project [mise-en-place](https://mise.jdx.dev/) which makes it easy to manage dependencies for hk linters. ## Contributing [​](https://hk.jdx.dev/about.html\#contributing) Contributions are welcome! Please open an issue or submit a PR. I always encourage reaching out to me first before submitting a feature PR to make sure it's something I will be interested in maintaining. <|firecrawl-page-3-lllmstxt|> ## Builtin Linters Overview [Skip to content](https://hk.jdx.dev/cli/builtins.html#VPContent) Return to top # `hk builtins` [​](https://hk.jdx.dev/cli/builtins.html\#hk-builtins) - **Usage**: `hk builtins` Lists all available builtin linters <|firecrawl-page-4-lllmstxt|> ## Clear Cache Command [Skip to content](https://hk.jdx.dev/cli/cache/clear.html#VPContent) Return to top # `hk cache clear` [​](https://hk.jdx.dev/cli/cache/clear.html\#hk-cache-clear) - **Usage**: `hk cache clear` Clear the cache directory <|firecrawl-page-5-lllmstxt|> ## HK Check Command Guide [Skip to content](https://hk.jdx.dev/cli/check.html#VPContent) On this page # `hk check` [​](https://hk.jdx.dev/cli/check.html\#hk-check) - **Usage**: `hk check [FLAGS] [FILES]…` - **Aliases**: `c` Fixes code ## Arguments [​](https://hk.jdx.dev/cli/check.html\#arguments) ### `[FILES]…` [​](https://hk.jdx.dev/cli/check.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/check.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/check.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/check.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/check.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/check.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/check.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/check.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/check.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/check.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/check.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/check.html\#s-step-step) Run specific step(s) <|firecrawl-page-6-lllmstxt|> ## Shell Completion Scripts [Skip to content](https://hk.jdx.dev/cli/completion.html#VPContent) On this page # `hk completion` [​](https://hk.jdx.dev/cli/completion.html\#hk-completion) - **Usage**: `hk completion ` Generates shell completion scripts ## Arguments [​](https://hk.jdx.dev/cli/completion.html\#arguments) ### `` [​](https://hk.jdx.dev/cli/completion.html\#shell) The shell to generate completion for <|firecrawl-page-7-lllmstxt|> ## HK Config Command [Skip to content](https://hk.jdx.dev/cli/config.html#VPContent) Return to top # `hk config` [​](https://hk.jdx.dev/cli/config.html\#hk-config) - **Usage**: `hk config` - **Aliases**: `cfg` Generate a default hk.toml configuration file <|firecrawl-page-8-lllmstxt|> ## Code Fix Command Guide [Skip to content](https://hk.jdx.dev/cli/fix.html#VPContent) On this page # `hk fix` [​](https://hk.jdx.dev/cli/fix.html\#hk-fix) - **Usage**: `hk fix [FLAGS] [FILES]…` - **Aliases**: `f` Fixes code ## Arguments [​](https://hk.jdx.dev/cli/fix.html\#arguments) ### `[FILES]…` [​](https://hk.jdx.dev/cli/fix.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/fix.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/fix.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/fix.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/fix.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/fix.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/fix.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/fix.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/fix.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/fix.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/fix.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/fix.html\#s-step-step) Run specific step(s) <|firecrawl-page-9-lllmstxt|> ## HK CLI Commands Overview [Skip to content](https://hk.jdx.dev/cli/#VPContent) On this page # `hk` [​](https://hk.jdx.dev/cli/\#hk) **Usage**: `hk [FLAGS] ` **Version**: 1.2.0 - **Usage**: `hk [FLAGS] ` ## Global Flags [​](https://hk.jdx.dev/cli/\#global-flags) ### `--hkrc ` [​](https://hk.jdx.dev/cli/\#hkrc-path) Path to user configuration file ### `-j --jobs ` [​](https://hk.jdx.dev/cli/\#j-jobs-jobs) Number of jobs to run in parallel ### `-p --profile… ` [​](https://hk.jdx.dev/cli/\#p-profile-profile) Profiles to enable/disable prefix with ! to disable e.g. --profile slow --profile !fast ### `-s --slow` [​](https://hk.jdx.dev/cli/\#s-slow) Shorthand for --profile=slow ### `-v --verbose…` [​](https://hk.jdx.dev/cli/\#v-verbose) Enables verbose output ### `-n --no-progress` [​](https://hk.jdx.dev/cli/\#n-no-progress) Disables progress output ### `-q --quiet` [​](https://hk.jdx.dev/cli/\#q-quiet) Suppresses output ### `--silent` [​](https://hk.jdx.dev/cli/\#silent) Suppresses all output ## Subcommands [​](https://hk.jdx.dev/cli/\#subcommands) - [`hk builtins`](https://hk.jdx.dev/cli/builtins.html) - [`hk cache clear`](https://hk.jdx.dev/cli/cache/clear.html) - [`hk check [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/check.html) - [`hk completion `](https://hk.jdx.dev/cli/completion.html) - [`hk config`](https://hk.jdx.dev/cli/config.html) - [`hk fix [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/fix.html) - [`hk init [-f --force] [--mise]`](https://hk.jdx.dev/cli/init.html) - [`hk install [--mise]`](https://hk.jdx.dev/cli/install.html) - [`hk run [FLAGS] [FILES]… `](https://hk.jdx.dev/cli/run.html) - [`hk run commit-msg [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/run/commit-msg.html) - [`hk run pre-commit [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/run/pre-commit.html) - [`hk run pre-push [FLAGS] [ARGS]…`](https://hk.jdx.dev/cli/run/pre-push.html) - [`hk run prepare-commit-msg [FLAGS] …`](https://hk.jdx.dev/cli/run/prepare-commit-msg.html) - [`hk uninstall`](https://hk.jdx.dev/cli/uninstall.html) - [`hk validate`](https://hk.jdx.dev/cli/validate.html) - [`hk version`](https://hk.jdx.dev/cli/version.html) <|firecrawl-page-10-lllmstxt|> ## HK Init Command [Skip to content](https://hk.jdx.dev/cli/init.html#VPContent) On this page # `hk init` [​](https://hk.jdx.dev/cli/init.html\#hk-init) - **Usage**: `hk init [-f --force] [--mise]` Generates a new hk.pkl file for a project ## Flags [​](https://hk.jdx.dev/cli/init.html\#flags) ### `-f --force` [​](https://hk.jdx.dev/cli/init.html\#f-force) Overwrite existing hk.pkl file ### `--mise` [​](https://hk.jdx.dev/cli/init.html\#mise) Generate a mise.toml file with hk configured Set HK\_MISE=1 to make this default behavior. <|firecrawl-page-11-lllmstxt|> ## HK Install Command [Skip to content](https://hk.jdx.dev/cli/install.html#VPContent) On this page # `hk install` [​](https://hk.jdx.dev/cli/install.html\#hk-install) - **Usage**: `hk install [--mise]` - **Aliases**: `i` Sets up git hooks to run hk ## Flags [​](https://hk.jdx.dev/cli/install.html\#flags) ### `--mise` [​](https://hk.jdx.dev/cli/install.html\#mise) Use `mise x` to execute hooks. With this, it won't be necessary to activate mise in order to run hooks with mise tools. Set HK\_MISE=1 to make this default behavior. <|firecrawl-page-12-lllmstxt|> ## Run Hooks Command [Skip to content](https://hk.jdx.dev/cli/run.html#VPContent) On this page # `hk run` [​](https://hk.jdx.dev/cli/run.html\#hk-run) - **Usage**: `hk run [FLAGS] [FILES]… ` - **Aliases**: `r` Run a hook ## Arguments [​](https://hk.jdx.dev/cli/run.html\#arguments) ### `[FILES]…` [​](https://hk.jdx.dev/cli/run.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/run.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/run.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/run.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/run.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/run.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/run.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/run.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/run.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/run.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/run.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/run.html\#s-step-step) Run specific step(s) ## Subcommands [​](https://hk.jdx.dev/cli/run.html\#subcommands) - [`hk run commit-msg [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/run/commit-msg.html) - [`hk run pre-commit [FLAGS] [FILES]…`](https://hk.jdx.dev/cli/run/pre-commit.html) - [`hk run pre-push [FLAGS] [ARGS]…`](https://hk.jdx.dev/cli/run/pre-push.html) - [`hk run prepare-commit-msg [FLAGS] …`](https://hk.jdx.dev/cli/run/prepare-commit-msg.html) <|firecrawl-page-13-lllmstxt|> ## Commit Message Command [Skip to content](https://hk.jdx.dev/cli/run/commit-msg.html#VPContent) On this page # `hk run commit-msg` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#hk-run-commit-msg) - **Usage**: `hk run commit-msg [FLAGS] [FILES]…` - **Aliases**: `cm` ## Arguments [​](https://hk.jdx.dev/cli/run/commit-msg.html\#arguments) ### `` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#commit-msg-file) The path to the file that contains the commit message ### `[FILES]…` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/run/commit-msg.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/run/commit-msg.html\#s-step-step) Run specific step(s) <|firecrawl-page-14-lllmstxt|> ## Pre-commit Hook Setup [Skip to content](https://hk.jdx.dev/cli/run/pre-commit.html#VPContent) On this page # `hk run pre-commit` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#hk-run-pre-commit) - **Usage**: `hk run pre-commit [FLAGS] [FILES]…` - **Aliases**: `pc` Sets up git hooks to run hk ## Arguments [​](https://hk.jdx.dev/cli/run/pre-commit.html\#arguments) ### `[FILES]…` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/run/pre-commit.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/run/pre-commit.html\#s-step-step) Run specific step(s) <|firecrawl-page-15-lllmstxt|> ## Pre-Push Command Guide [Skip to content](https://hk.jdx.dev/cli/run/pre-push.html#VPContent) On this page # `hk run pre-push` [​](https://hk.jdx.dev/cli/run/pre-push.html\#hk-run-pre-push) - **Usage**: `hk run pre-push [FLAGS] [ARGS]…` - **Aliases**: `pp` ## Arguments [​](https://hk.jdx.dev/cli/run/pre-push.html\#arguments) ### `[REMOTE]` [​](https://hk.jdx.dev/cli/run/pre-push.html\#remote) Remote name ### `[URL]` [​](https://hk.jdx.dev/cli/run/pre-push.html\#url) Remote URL ### `[FILES]…` [​](https://hk.jdx.dev/cli/run/pre-push.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/run/pre-push.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/run/pre-push.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/run/pre-push.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/run/pre-push.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/run/pre-push.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/run/pre-push.html\#s-step-step) Run specific step(s) <|firecrawl-page-16-lllmstxt|> ## Prepare Commit Message [Skip to content](https://hk.jdx.dev/cli/run/prepare-commit-msg.html#VPContent) On this page # `hk run prepare-commit-msg` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#hk-run-prepare-commit-msg) - **Usage**: `hk run prepare-commit-msg [FLAGS] …` - **Aliases**: `pcm` ## Arguments [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#arguments) ### `` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#commit-msg-file) The path to the file that contains the commit message so far ### `[SOURCE]` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#source) The source of the commit message (e.g., "message", "template", "merge") ### `[SHA]` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#sha) The SHA of the commit being amended (if applicable) ### `[FILES]…` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#files) Run on specific files ## Flags [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#flags) ### `-a --all` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#a-all) Run on all files instead of just staged files ### `-f --fix` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#f-fix) Run fix command instead of run command This is the default behavior unless HK\_FIX=0 ### `-c --check` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#c-check) Run run command instead of fix command ### `-e --exclude… ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#e-exclude-exclude) Exclude files that otherwise would have been selected ### `--exclude-glob… ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#exclude-glob-exclude-glob) Exclude files that match these glob patterns that otherwise would have been selected ### `--from-ref ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#from-ref-from-ref) Start reference for checking files (requires --to-ref) ### `--to-ref ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#to-ref-to-ref) End reference for checking files (requires --from-ref) ### `-g --glob… ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#g-glob-glob) Run on files that match these glob patterns ### `-P --plan` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#p-plan) Print the plan instead of running the hook ### `-S --step… ` [​](https://hk.jdx.dev/cli/run/prepare-commit-msg.html\#s-step-step) Run specific step(s) <|firecrawl-page-17-lllmstxt|> ## Uninstall hk Hooks [Skip to content](https://hk.jdx.dev/cli/uninstall.html#VPContent) Return to top # `hk uninstall` [​](https://hk.jdx.dev/cli/uninstall.html\#hk-uninstall) - **Usage**: `hk uninstall` Removes hk hooks from the current git repository <|firecrawl-page-18-lllmstxt|> ## Config File Validator [Skip to content](https://hk.jdx.dev/cli/validate.html#VPContent) Return to top # `hk validate` [​](https://hk.jdx.dev/cli/validate.html\#hk-validate) - **Usage**: `hk validate` Validate the config file <|firecrawl-page-19-lllmstxt|> ## HK CLI Version Info [Skip to content](https://hk.jdx.dev/cli/version.html#VPContent) Return to top # `hk version` [​](https://hk.jdx.dev/cli/version.html\#hk-version) - **Usage**: `hk version` Print the version of hk <|firecrawl-page-20-lllmstxt|> ## Configuration for hk [Skip to content](https://hk.jdx.dev/configuration.html#VPContent) On this page # Configuration [​](https://hk.jdx.dev/configuration.html\#configuration) ## `hk.pkl` [​](https://hk.jdx.dev/configuration.html\#hk-pkl) hk is configured via `hk.pkl` which is written in [pkl-lang](https://pkl-lang.org/) from Apple. Here's a basic `hk.pkl` file: pkl ``` amends "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Config.pkl" import "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Builtins.pkl" local linters = new Mapping { // linters can be manually defined ["eslint"] { // the files to run the linter on, if no files are matched, the linter will be skipped // this will filter the staged files and return the subset matching these globs glob = List("*.js", "*.ts") // these files will be staged after the fix step modifies them stage = List("*.js", "*.ts") // the command to run that makes no changes check = "eslint {{files}}" // the command to run that fixes the files (used by default) fix = "eslint --fix {{files}}" } // linters can also be specified with the Builtins pkl library ["prettier"] = Builtins.prettier } hooks { ["pre-commit"] { fix = true // runs the fix step to make modifications stash = "git" // stashes unstaged changes before running fix steps steps = linters } ["pre-push"] { steps = linters } // "fix" and "check" are special steps for `hk fix` and `hk check` commands ["fix"] { fix = true steps = linters } ["check"] { steps = linters } } ``` The first line ( `amends`) is critical because that imports the base configuration pkl for extending. ## `env: Mapping` [​](https://hk.jdx.dev/configuration.html\#env-mapping-string-string) Environment variables can be set in hk.pkl for configuring hk or the linters. pkl ``` env { ["HK_FAIL_FAST"] = "0" ["NODE_ENV"] = "production" } ``` ## `hooks.` [​](https://hk.jdx.dev/configuration.html\#hooks-hook) Hooks define when and how linters are run. See [hooks](https://hk.jdx.dev/hooks.html) for more information. ## `hooks..fix: bool` [​](https://hk.jdx.dev/configuration.html\#hooks-hook-fix-bool) Default: `false` ( `true` for `pre-commit` and `fix`) If true, hk will run the fix step to make modifications. ## `hooks..stash: String` [​](https://hk.jdx.dev/configuration.html\#hooks-hook-stash-string) Default: `git` - `git`: Use `git stash` to stash unstaged changes before running fix steps. - `patch-file`: Use an hk generated patch file to stash unstaged changes before running fix steps—typically faster. - `none`: Do not stash unstaged changes before running fix steps. ## `hooks..steps.` [​](https://hk.jdx.dev/configuration.html\#hooks-hook-steps-step-group) Steps are the individual linters that make up a hook. They are executed in the order they are defined in parallel up to [`HK_JOBS`](https://hk.jdx.dev/configuration.html#hk-jobs) at a time. ### `.glob: List` [​](https://hk.jdx.dev/configuration.html\#step-glob-list-string) Files the step should run on. By default this will only run this step if at least 1 staged file matches the glob patterns. If no patterns are provided, the step will always run. ### `.check: (String | Script)` [​](https://hk.jdx.dev/configuration.html\#step-check-string-script) A command to run that does not modify files. This typically is a "check" command like `eslint` or `prettier --check` that returns a non-zero exit code if there are errors. Parallelization works better with check commands than fix commands as no files are being modified. pkl ``` hooks { ["pre-commit"] { ["prettier"] { check = "prettier --check {{files}}" } } } ``` If you want to use a different check command for different operating systems, you can define a Script instead of a String: pkl ``` hooks { ["pre-commit"] { ["prettier"] { check = new Script { linux = "prettier --check {{files}}" macos = "prettier --check {{files}}" windows = "prettier --check {{files}}" other = "prettier --check {{files}}" } } } } ``` Template variables: - `{{files}}`: A list of files to run the linter on. ### `.check_list_files: (String | Script)` [​](https://hk.jdx.dev/configuration.html\#step-check-list-files-string-script) A command that returns a list of files that need fixing. This is used to optimize the fix step when `check_first` is enabled. Instead of running the fix command on all files, it will only run on files that need fixing. pkl ``` hooks { ["pre-commit"] { ["prettier"] { check_list_files = "prettier --list-different {{files}}" } } } ``` ### `.check_diff: (String | Script)` [​](https://hk.jdx.dev/configuration.html\#step-check-diff-string-script) A command that shows the diff of what would be changed. This is an alternative to `check` that can provide more detailed information about what would be changed. ### `.fix: (String | Script)` [​](https://hk.jdx.dev/configuration.html\#step-fix-string-script) A command to run that modifies files. This typically is a "fix" command like `eslint --fix` or `prettier --write`. Templates variables are the same as for `check`. pkl ``` local linters = new Mapping { ["prettier"] { fix = "prettier --write {{files}}" } } ``` By default, hk will use `fix` commands but this can be overridden by setting [`HK_FIX=0`](https://hk.jdx.dev/configuration.html#hk-fix) or running `hk run --run`. ### `.check_first: bool` [​](https://hk.jdx.dev/configuration.html\#step-check-first-bool) Default: `true` If true, hk will run the check step first and only run the fix step if the check step fails. ### `.batch: bool` [​](https://hk.jdx.dev/configuration.html\#step-batch-bool) Default: `false` If true, hk will run the linter on batches of files instead of all files at once. This takes advantage of parallel processing for otherwise single-threaded linters like eslint and prettier. pkl ``` local linters = new Mapping { ["eslint"] { batch = true } } ``` ### `.stomp: bool` [​](https://hk.jdx.dev/configuration.html\#step-stomp-bool) Default: `false` If true, hk will get a write lock instead of a read lock when running fix/fix\_all. Use this if the tool has its own locking mechanism or you simply don't care if files may be written to by multiple linters simultaneously. ### `.workspace_indicator: String` [​](https://hk.jdx.dev/configuration.html\#step-workspace-indicator-string) If set, run the linter on workspaces only which are parent directories containing this filename. This is useful for tools that need to be run from a specific directory, like a project root. pkl ``` local linters = new Mapping { ["cargo-clippy"] { workspace_indicator = "Cargo.toml" glob = "*.rs" workspace_indicator = "Cargo.toml" check = "cargo clippy --manifest-path {{workspace_indicator}}" } } ``` In this example, given a file list like the following: ``` └── workspaces/ ├── proj1/ │ ├── Cargo.toml │ └── src/ │ ├── lib.rs │ └── main.rs └── proj2/ ├── Cargo.toml └── src/ ├── lib.rs └── main.rs ``` hk will run 1 step for each workspace even though multiple rs files are in each workspace: - `cargo clippy --manifest-path workspaces/proj1/Cargo.toml` - `cargo clippy --manifest-path workspaces/proj2/Cargo.toml` ### `.prefix: String` [​](https://hk.jdx.dev/configuration.html\#step-prefix-string) If set, run the linter scripts with this prefix, e.g.: "mise exec --" or "npm run". pkl ``` local linters = new Mapping { ["eslint"] { prefix = "npm run" } } ``` ### `.dir: String` [​](https://hk.jdx.dev/configuration.html\#step-dir-string) If set, run the linter scripts in this directory. pkl ``` local linters = new Mapping { ["eslint"] = (Builtins.eslint) { dir = "frontend" } } ``` ### `.profiles: List` [​](https://hk.jdx.dev/configuration.html\#step-profiles-list-string) Profiles are a way to enable/disable linters based on the current profile. The linter will only run if its profile is in [`HK_PROFILE`](https://hk.jdx.dev/configuration.html#hk-profile). pkl ``` local linters = new Mapping { ["prettier"] = (Builtins.prettier) { profiles = List("slow") } } ``` Profiles can be prefixed with `!` to disable them. pkl ``` local linters = new Mapping { ["prettier"] = (Builtins.prettier) { profiles = List("!slow") } } ``` ### `.depends: List` [​](https://hk.jdx.dev/configuration.html\#step-depends-list-string) A list of steps that must finish before this step can run. pkl ``` hooks { ["pre-commit"] { steps { ["prettier"] { depends = List("eslint") } } } } ``` ### `.shell: (String | Script)` [​](https://hk.jdx.dev/configuration.html\#step-shell-string-script) If set, use this shell instead of the default `sh -o errexit -c`. pkl ```` hooks { ["pre-commit"] { steps { ["prettier"] { shell = "bash -o errexit -c" } } } } ### `.stage: List` A list of globs of files to add to the git index after running a fix step. ```pkl hooks { ["pre-commit"] { steps { ["prettier"] { stage = List("*.js", "*.ts") } } } } ```` ### `.exclusive: bool` [​](https://hk.jdx.dev/configuration.html\#step-exclusive-bool) Default: `false` If true, this step will wait for any previous steps to finish before running. No other steps will start until this one finishes. Under the hood this groups the previous steps into a group. pkl ``` hooks { ["pre-commit"] { steps { ["prelint"] { exclusive = true // blocks other steps from starting until this one finishes check = "mise run prelint" } // ... other steps will run in parallel ... ["postlint"] { exclusive = true // wait for all previous steps to finish before starting check = "mise run postlint" } } } } ``` ### `.exclude: (String | List)` [​](https://hk.jdx.dev/configuration.html\#step-exclude-string-list-string) A list of glob patterns to exclude from the step. Files matching these patterns will be skipped. pkl ``` local linters = new Mapping { ["prettier"] { exclude = List("*.js", "*.ts") } } ``` ### `.interactive: bool` [​](https://hk.jdx.dev/configuration.html\#step-interactive-bool) Default: `false` If true, connects stdin/stdout/stderr to hk's execution. This implies `exclusive = true`. pkl ``` local linters = new Mapping { ["show-warning"] { interactive = true check = "echo warning && read -p 'Press Enter to continue'" } } ``` ### `.condition: String` [​](https://hk.jdx.dev/configuration.html\#step-condition-string) If set, the step will only run if this condition evaluates to true. Evaluated with [`expr`](https://github.com/jdx/expr-rs). pkl ``` local linters = new Mapping { ["prettier"] { condition = "eval('test -f check.js')" } } ``` ### `.hide: bool` [​](https://hk.jdx.dev/configuration.html\#step-hide-bool) Default: `false` If true, the step will be hidden from output. pkl ``` local linters = new Mapping { ["prettier"] { hide = true } } ``` ### `.env: Mapping` [​](https://hk.jdx.dev/configuration.html\#step-env-mapping-string-string) Environment variables specific to this step. These are merged with the global environment variables. pkl ``` local linters = new Mapping { ["prettier"] { env { ["NODE_ENV"] = "production" } } } ``` ### `` [​](https://hk.jdx.dev/configuration.html\#group) A group is a collection of steps that are executed in parallel, waiting for previous steps/groups to finish and blocking other steps/groups from starting until it finishes. This is a naive way to ensure the order of execution. It's better to make use of read/write locks and depends. pkl ``` hooks { ["pre-commit"] { steps { ["build"] = new Group { steps = new Mapping { ["ts"] = new Step { fix = "tsc -b" } ["rs"] = new Step { fix = "cargo build" } } } // these steps will run in parallel after the build group finishes ["lint"] = new Group { steps = new Mapping { ["prettier"] = new Step { check = "prettier --check {{files}}" } ["eslint"] = new Step { check = "eslint {{files}}" } } } } } } ``` ## `hkrc` [​](https://hk.jdx.dev/configuration.html\#hkrc) The `hkrc` is a global configuration file that allows you to customize hk's behavior across all projects. By default, hk will look for this file in your home directory. You can override its location using the `--hkrc` flag. The hkrc file follows the same format as `hk.pkl` and can be used to define global hooks and linters that will be applied to all projects. This is useful for setting up consistent linting rules across multiple repositories. Example hkrc file: pkl ``` amends "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Config.pkl" import "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Builtins.pkl" local linters { ["prettier"] = Builtins.prettier ["eslint"] { glob = List("*.js", "*.ts") check = "eslint {{files}}" fix = "eslint --fix {{files}}" } } hooks { ["pre-commit"] { fix = true steps = linters } } ``` The hkrc configuration is applied after loading the project configuration ( `hk.pkl`), which means: - User configuration takes precedence over project configuration - Project-specific settings in `hk.pkl` can override or extend the global configuration <|firecrawl-page-21-lllmstxt|> ## Environment Variables Configuration [Skip to content](https://hk.jdx.dev/environment_variables.html#VPContent) On this page # Environment Variables [​](https://hk.jdx.dev/environment_variables.html\#environment-variables) Environment variables can be used to configure hk. ## `HK_CACHE_DIR` [​](https://hk.jdx.dev/environment_variables.html\#hk-cache-dir) Type: `path` Default: `~/.cache/hk` The cache directory to use. ## `HK_CHECK_FIRST` [​](https://hk.jdx.dev/environment_variables.html\#hk-check-first) Type: `bool` Default: `true` If true, hk will run check commands first then run fix commands if check fails iff there are multiple linters with the same file in a matching glob pattern. The reason for this is to make hk able to parallelize as much as possible. We can have as many check commands running in parallel against the same file as we want without them interfering with each other—however we can't have 2 fix commands potentially writing to the same file. So we optimistically run the check commands in parallel, then if any fail we run their fix commands potentially in series. If this is disabled hk will have simpler logic that just uses fix commands in series in this situation. ## `HK_PROFILE` [​](https://hk.jdx.dev/environment_variables.html\#hk-profile) Type: `string[]` (comma-separated list) The profile(s) to use. ## `HK_FILE` [​](https://hk.jdx.dev/environment_variables.html\#hk-file) Type: `string` Default: `hk.pkl` \| `hk.toml` \| `hk.yaml` \| `hk.yml` \| `hk.json` The file to use for the configuration. ## `HK_FIX` [​](https://hk.jdx.dev/environment_variables.html\#hk-fix) Type: `bool` Default: `true` If set to `false`, hk will not run fix steps. ## `HK_JOBS` [​](https://hk.jdx.dev/environment_variables.html\#hk-jobs) Type: `usize` Default: `(number of cores)` The number of jobs to run in parallel. ## `HK_LOG` [​](https://hk.jdx.dev/environment_variables.html\#hk-log) Type: `trace` \| `debug` \| `info` \| `warn` \| `error` Default: `info` The log level to use. ## `HK_LOG_FILE` [​](https://hk.jdx.dev/environment_variables.html\#hk-log-file) Type: `path` Default: `~/.local/state/hk/hk.log` The log file to use. ## `HK_LOG_FILE_LEVEL` [​](https://hk.jdx.dev/environment_variables.html\#hk-log-file-level) Type: `trace` \| `debug` \| `info` \| `warn` \| `error` Default: `HK_LOG` The log level to use for the log file. ## `HK_MISE` [​](https://hk.jdx.dev/environment_variables.html\#hk-mise) Type: `bool` Default: `false` If set to `true`: - When installing hooks with `hk install`, hk will use `mise x` to execute hooks which won't require activating mise to use mise tools - When generating files with `hk init`, hk will create a `mise.toml` file with hk configured ## `HK_SKIP_STEPS` [​](https://hk.jdx.dev/environment_variables.html\#hk-skip-steps) Type: `string[]` (comma-separated list) A comma-separated list of step names to skip when running pre-commit and pre-push hooks. For example: `HK_SKIP_STEPS=lint,test` would skip any steps named "lint" or "test". ## `HK_SKIP_HOOK` [​](https://hk.jdx.dev/environment_variables.html\#hk-skip-hook) Type: `string[]` (comma-separated list) Default: `(empty)` A comma-separated list of hook names to skip entirely. This allows you to disable specific git hooks from running. For example: `HK_SKIP_HOOK=pre-commit,pre-push` would skip running those hooks completely. This is useful when you want to temporarily disable certain hooks while still keeping them configured in your `hk.pkl` file. Unlike `HK_SKIP_STEPS` which skips individual steps, this skips the entire hook and all its steps. ## `HK_STASH` [​](https://hk.jdx.dev/environment_variables.html\#hk-stash) Type: `git` \| `patch-file` \| `none` Default: `git` - `git`: Use `git stash` to stash unstaged changes before running hooks. - `patch-file`: Use an hk generated patch file to stash unstaged changes before running hooks (typically faster and avoids `index is locked` errors). - `none`: Do not stash unstaged changes before running hooks. Much faster but will stage unstaged changes if they are in the same file as staged changes with fix modifications. ## `HK_STASH_UNTRACKED` [​](https://hk.jdx.dev/environment_variables.html\#hk-stash-untracked) Type: `bool` Default: `true` If set to `true`, hk will stash untracked files when stashing before running hooks. ## `HK_FAIL_FAST` [​](https://hk.jdx.dev/environment_variables.html\#hk-fail-fast) Type: `bool` Default: `true` If `true`, hk will abort running steps after the first one fails. ## `HK_STATE_DIR` [​](https://hk.jdx.dev/environment_variables.html\#hk-state-dir) Type: `path` Default: `~/.local/state/hk` The state directory to use. ## `HK_HIDE_WHEN_DONE` [​](https://hk.jdx.dev/environment_variables.html\#hk-hide-when-done) Type: `bool` Default: `false` If set to `true`, hk will hide the progress output when the hook finishes if there are no errors. ## `HK_LIBGIT2` [​](https://hk.jdx.dev/environment_variables.html\#hk-libgit2) Type: `bool` Default: `true` If set to `false`, hk will not use libgit2 to interact with git and instead use shelling out to git commands. This may provide better performance in some cases such as when using `fsmonitor` to watch for changes. <|firecrawl-page-22-lllmstxt|> ## Getting Started with hk [Skip to content](https://hk.jdx.dev/getting_started.html#VPContent) On this page # Getting Started [​](https://hk.jdx.dev/getting_started.html\#getting-started) A tool for running hooks on files in a git repository. ## Installation [​](https://hk.jdx.dev/getting_started.html\#installation) Use [mise-en-place](https://github.com/jdx/mise) to install hk (you'll also need the `pkl` cli): sh ``` mise use hk pkl hk --version ``` TIP mise-en-place integrates well with hk. Features common in similar git-hook managers like dependency management, task dependencies, and env vars can be provided by mise. See [mise integration](https://hk.jdx.dev/mise_integration.html) for more information. Or install from source with `cargo`: sh ``` cargo install hk ``` Other installation methods: - [`brew install hk`](https://formulae.brew.sh/formula/hk) - [`aqua g -i jdx/hk`](https://github.com/aquaproj/aqua-registry/blob/main/pkgs/jdx/hk/registry.yaml) ## Project Setup [​](https://hk.jdx.dev/getting_started.html\#project-setup) Use [`hk init`](https://hk.jdx.dev/cli/init.html) to generate a `hk.pkl` file: sh ``` hk init ``` ## Global Configuration [​](https://hk.jdx.dev/getting_started.html\#global-configuration) You can create a global configuration file that will be applied to all projects. This is useful for setting up consistent linting rules across multiple repositories. By default, hk will look for this file in your home directory. The global configuration file follows the same format as `hk.pkl` and can be used to define global hooks and linters. Project-specific settings in `hk.pkl` can override or extend the global configuration. ## `hk.pkl` [​](https://hk.jdx.dev/getting_started.html\#hk-pkl) This will generate a `hk.pkl` file in the root of the repository, here's an example `hk.pkl` with eslint and prettier linters: pkl ``` amends "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Config.pkl" import "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Builtins.pkl" local linters = new Mapping { // linters can be manually defined ["eslint"] { // the files to run the linter on, if no files are matched, the linter will be skipped // this will filter the staged files and return the subset matching these globs glob = List("*.js"; "*.ts") // a command that returns non-zero to fail the check check = "eslint {{files}}" } // linters can also be specified with the builtins pkl library ["prettier"] = Builtins.prettier // with pkl, builtins can also be extended: ["prettier-yaml"] = (Builtins.prettier) { glob = List("*.yaml"; "*.yml") } } hooks { ["pre-commit"] { fix = true // runs the "fix" step of linters to modify files stash = "git" // stashes unstaged changes when running fix steps steps { ["prelint"] { check = "mise run prelint" exclusive = true // blocks other steps from starting until this one finishes } ...linters ["postlint"] { check = "mise run postlint" exclusive = true } } } } ``` See [configuration](https://hk.jdx.dev/configuration.html) for more information on the `hk.pkl` file. ## Usage [​](https://hk.jdx.dev/getting_started.html\#usage) Inside a git repository with a `hk.pkl` file, run [`hk install`](https://hk.jdx.dev/cli/install.html) to configure git to use the hooks defined in `hk.pkl`: sh ``` hk install ``` This will install the hooks for the repository like `pre-commit` and `pre-push` if they are defined in `hk.pkl`. Running `git commit` would now run the linters defined above in our example through the pre-commit hook. ## Checking and Fixing Code [​](https://hk.jdx.dev/getting_started.html\#checking-and-fixing-code) You can check or fix code with [`hk check`](https://hk.jdx.dev/cli/check.html) or [`hk fix`](https://hk.jdx.dev/cli/fix.html)—by convention, "check" means files should not be modified and "fix" should verify everything "check" does but also modify files to fix any issues. By default, `hk check|fix` run against any modified files in the repo. TIP Use `hk check --all` in CI to lint all the files in the repo or `hk check --from-ref main` to lint files that have changed since the `main` branch. ## Running Hooks [​](https://hk.jdx.dev/getting_started.html\#running-hooks) To explicitly run a hook without going through git, use the [`hk run`](https://hk.jdx.dev/cli/run.html) command. This is generally useful for testing hooks locally. sh ``` hk run pre-commit ``` <|firecrawl-page-23-lllmstxt|> ## Git Hooks Behavior [Skip to content](https://hk.jdx.dev/hooks.html#VPContent) On this page # Hooks [​](https://hk.jdx.dev/hooks.html\#hooks) The following describes the behavior of git hooks that hk supports. Each linter provides a "check" and "fix" commands. "check" commands are read-only and can be run in parallel. "fix" commands can edit files and will block other "fix" or "check" commands from running at the same time. Note that hk does not enforce that "check" commands do not write to files for performance reasons however you still should try to follow this convention in order for hk to behave as expected. It's the read/write locking behavior that hk makes use of in order to run hooks as fast as possible while still being safe. ## Hook Behavior [​](https://hk.jdx.dev/hooks.html\#hook-behavior) hk hooks perform the following assuming `fix = true`: - Stashes any untracked/unstaged changes (disable with [`HK_STASH=none`](https://hk.jdx.dev/configuration.html#hk-stash)) - Gathers list of files with staged changes (or all files if running `hk run pre-commit --all`) - Runs linters and hook steps in parallel up to [`HK_JOBS`](https://hk.jdx.dev/configuration.html#hk-jobs) at a time, with caveats: - `exclusive = true` hook steps will wait until all previous steps finished and block later steps from starting - if any hook step has any dependencies, hk will wait for them to complete before starting - hk will create read/write locks for each file (according to the linter's glob patterns) to check/fix in the linters unless `stomp = true` - if `check_first = true` on the linter, hk will run the "check" command first with read locks, if that fails, it will run the "fix" command with write locks on all the files - if a `check_list_files` command is available on the linter, hk will use the output of that command to filter the list of files to get write locks for and call "fix" on. - if `check_first = false` on the linter, hk will run the "fix" command after fetching write locks, blocking other linters from running. You should avoid this performance. - if any of the files have been modified and match the `stage` globs, they will be added to the git index - untracked/unstaged changes are unstashed If `fix = false`, hk will just run the `check` steps and won't need to deal with read/write locks as nothing should be making modifications. ## `pre-commit` [​](https://hk.jdx.dev/hooks.html\#pre-commit) Runs when `git commit` is run before `git commit` creates the commit. pkl ``` hooks { fix = true ["pre-commit"] { steps { ["cargo-fmt"] { glob = "*.rs" stage = "*.rs" check_first = true check = "cargo fmt --check" fix = "cargo fmt" } ["cargo-clippy"] { glob = "*.rs" check_first = true check = "cargo clippy" fix = "cargo clippy --fix --allow-dirty --allow-staged" } } } } ``` ## `prepare-commit-msg` [​](https://hk.jdx.dev/hooks.html\#prepare-commit-msg) Runs when `git commit` is run before the commit message is created. Useful for rendering a default commit message template. pkl ``` hooks { ["prepare-commit-msg"] { steps { ["render-commit-msg"] { check = "echo 'default commit message' > {{commit_msg_file}}" } } } } ``` ## `commit-msg` [​](https://hk.jdx.dev/hooks.html\#commit-msg) Runs when `git commit` is run after the commit message is created. Useful for validating the commit message. pkl ``` hooks { ["commit-msg"] { steps { ["validate-commit-msg"] { check = "grep -q '^(fix|feat|chore):' {{commit_msg_file}} || exit 1" } } } } ``` ## Other Hooks [​](https://hk.jdx.dev/hooks.html\#other-hooks) Other git hooks are also supported. See [https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). <|firecrawl-page-24-lllmstxt|> ## Mise Integration Guide [Skip to content](https://hk.jdx.dev/mise_integration.html#VPContent) On this page # mise integration [​](https://hk.jdx.dev/mise_integration.html\#mise-integration) Most git-hook managers provide features that hk's sister project, [mise-en-place](https://github.com/jdx/mise), already provides. For this reason, you will want to use mise and hk together if you'd like to use any of the features described below. To default hk to enable these mise features, set [`HK_MISE=1`](https://hk.jdx.dev/configuration.html#hk-mise). ## `hk init --mise` [​](https://hk.jdx.dev/mise_integration.html\#hk-init-mise) Use the `--mise` flag on generate to have hk create a new `mise.toml` file in the root of the repository that installs hk and defines a `pre-commit` task so users can run `mise run pre-commit` as a "shortcut" for `hk run pre-commit`. Of course, that's actually longer, but the advantage here is that tasks can be used consistently for all the project actions, not just git hooks. ## `hk install --mise` [​](https://hk.jdx.dev/mise_integration.html\#hk-install-mise) Use the `--mise` flag on install to make the hook use `mise x` to execute the hooks. This will setup the mise environment (namely, add tools to PATH) for them to be used in hk. By using `mise x`, other developers will not need to have mise already activated in their environment to use the hooks. It's useful for working with developers who don't typically use mise but want hooks on a particular project to work with the tools defined in `mise.toml`. ## Tool Management [​](https://hk.jdx.dev/mise_integration.html\#tool-management) mise's tool management feature lets you define the version of all of the tools used in `hk.pkl` in a single place. To use, run `mise use` on all the tools you wish to use: sh ``` mise use hk mise use jq mise use npm:prettier ``` This will create a `mise.toml` file that can be committed into the project. See the [mise dev tool docs](https://mise.jdx.dev/dev-tools/) for more information. ## Task Management [​](https://hk.jdx.dev/mise_integration.html\#task-management) [mise tasks](https://mise.jdx.dev/tasks/) can be used inside hk steps which provide a lot of functionality like dependency management, option parsing, parallel execution, and more. Just run mise in `hk.pkl` like any other command: pkl ``` amends "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Config.pkl" `pre-commit` { ["prelint"] { check = "mise run prelint" exclusive = true // ensures this completes before the next steps } // ... more steps ... } ``` ## Environment Variables [​](https://hk.jdx.dev/mise_integration.html\#environment-variables) You can define an `[env]` section in `mise.toml` for defining env vars to be used in the hooks: toml ``` [env] PRETTIER_CONFIG = ".prettierrc.json" ``` mise has much more functionality around environment variables, so see the [mise docs](https://mise.jdx.dev/environments/) for more information. <|firecrawl-page-25-lllmstxt|> ## Introduction to pkl [Skip to content](https://hk.jdx.dev/pkl_introduction.html#VPContent) On this page # Introduction to pkl [​](https://hk.jdx.dev/pkl_introduction.html\#introduction-to-pkl) hk uses [pkl](https://pkl-lang.org/) for configuration. As this is a new configuration language, this doc gives an overview of how to write it and work with it for hk configuration. ## Dependencies [​](https://hk.jdx.dev/pkl_introduction.html\#dependencies) You'll need the pkl cli to use hk. This is because the rust library currently shells out to the pkl cli to parse the configuration. I'm sure someday we'll have a native pkl parser in rust (maybe you could write it?) but for now, you'll need pkl. These are easily installed with mise though: sh ``` mise use -g pkl ``` ## Why pkl? [​](https://hk.jdx.dev/pkl_introduction.html\#why-pkl) - Schema validation is built into the language so your IDE can display errors not just with pkl syntax, but ensure that the types are correct - pkl can import other pkl files from the file system or HTTP URLs—so hk doesn't need its own logic around "importing" files - You can create/amend shared objects which can really help clean up your config. It even has things like functions and string templates for advanced use cases. - pkl is comprehensive enough—but static—that I found I didn't need a plugin system for hk. I had looked at wasm and lua for plugins, but by using (cached) pkl files this helps hk stay much faster than it would be otherwise. ## Downsides? [​](https://hk.jdx.dev/pkl_introduction.html\#downsides) - Editor/syntax highlighting support is young—though being a project driven by Apple I suspect this will improve quicker than most languages - Some of the behavior with the "amends" line and how `hk.pkl` files are used in hk I wish was a little more streamlined—but this is more of an issue with hk than pkl. - It's more complex than simple formats like yaml or toml and there is more to learn, however: - AI tools make this much easier since you can just ask cursor or whoever to help you write pkl - It's complex because it has a lot of features that don't exist in simple formats - Some of the quirks of pkl I can't say I'm a fan of: - `List(a, b, c)` instead of `[a, b, c]` - `default` behavior is quite confusing - amending is a little weird I have looked at many other esoteric languages for a long time now for hk and other projects though. IMO schema validation being built in is an absolute killer feature that on its own is worth the tradeoffs. If you find yourself bristling at pkl, just remember that by using features in pkl that means a lot of features didn't need to be implemented in hk—so you'll just be learning pkl features instead of hk features. pkl itself is also young and being improved so I am optimistic they may add some syntax sugar that would address some of these problems—or at least what I see as problems. ## Testing pkl config [​](https://hk.jdx.dev/pkl_introduction.html\#testing-pkl-config) While I strongly encourage setting up your editor with a pkl extension to view errors inside the editor, you can also use the pkl cli to evaluate pkl files which is a great way to see what pkl is outputting without needing to run it through hk: sh ``` $ pkl eval hk.pkl hooks { ["pre-commit"] { fix = true steps { ["prelint"] { command = "lint" args = ["--fix"] } } } } ``` Especially if you're doing dynamic configuration things I would strongly recommend doing this. ## Basic syntax [​](https://hk.jdx.dev/pkl_introduction.html\#basic-syntax) While of course pkl provides a [full reference](https://pkl-lang.org/main/current/language-reference/index.html), here I'll just show the pkl concepts we use in hk. ### Basic Types [​](https://hk.jdx.dev/pkl_introduction.html\#basic-types) pkl ``` my_string = "hello" my_number = 1 my_boolean = true list_of_strings = List("a", "b", "c") ``` ### Mapping [​](https://hk.jdx.dev/pkl_introduction.html\#mapping) Mappings are key-value pairs: pkl ``` my_mapping = new Mapping { ["key"] = "value" } ``` ### Listings/Lists [​](https://hk.jdx.dev/pkl_introduction.html\#listings-lists) Lists are for basic ordered collections: pkl ``` my_list = List("a", "b", "c") ``` Listings are for more complex ordered collections: pkl ``` my_listing = new Listing { new LinterStep { check = "make lint" } new LinterStep { check = "make format" } } ``` ### Local variables [​](https://hk.jdx.dev/pkl_introduction.html\#local-variables) hk will complain if you attempt to export variables that it doesn't expect, so you'll likely need to use the `local` keyword to create local variables: pkl ``` local my_step = new LinterStep { check = "make lint" } ``` ### Classes [​](https://hk.jdx.dev/pkl_introduction.html\#classes) You typically won't define your own class with an hk config, but you will instantiate the ones provided by [Config.pkl](https://github.com/jdx/hk/blob/main/pkl/Config.pkl): pkl ``` local my_step = new LinterStep { check = "make lint" } ``` ### Amending objects [​](https://hk.jdx.dev/pkl_introduction.html\#amending-objects) If you want to use shared object but amend it with modifications, you do that with this syntax: pkl ``` local make_lint = new LinterStep { check = "make lint" } local linters = new Mapping { ["make-lint"] = (make_lint) { dir = "proj_a" } ["make-lint"] = (make_lint) { dir = "proj_b" } } ``` Essentially this is the same as: pkl ``` local linters = new Mapping { ["make-lint"] = new LinterStep { check = "make lint" dir = "proj_a" } ["make-lint"] = new LinterStep { check = "make lint" dir = "proj_b" } } ``` ### Comments [​](https://hk.jdx.dev/pkl_introduction.html\#comments) pkl ``` // This is a comment /* This is a multi-line comment */ /// This is a doc comment (not used by hk at least today) ``` ### Amends [​](https://hk.jdx.dev/pkl_introduction.html\#amends) Every `hk.pkl` should start with this line which essentially schema validates the config and provides base classes: pkl ``` amends "package://github.com/jdx/hk/releases/download/v1.2.0/hk@1.2.0#/Config.pkl" ``` ### Imports [​](https://hk.jdx.dev/pkl_introduction.html\#imports) Share code between files by importing: pkl ``` import "./extra.pkl" # do something with `extra` import "https://example.com/remote.pkl" # do something with `remote` ``` ## Caching [​](https://hk.jdx.dev/pkl_introduction.html\#caching) hk will cache the output of parsing each `hk.pkl` file until it is modified. For now, I would discouraging using features like env vars inside of `hk.pkl` files as the cache will not be invalidated if the env vars change. Perhaps this could be fixed somehow. <|firecrawl-page-26-lllmstxt|> ## Environment Variables Configuration [Skip to content](https://hk.jdx.dev/environment_variables#VPContent) On this page # Environment Variables [​](https://hk.jdx.dev/environment_variables\#environment-variables) Environment variables can be used to configure hk. ## `HK_CACHE_DIR` [​](https://hk.jdx.dev/environment_variables\#hk-cache-dir) Type: `path` Default: `~/.cache/hk` The cache directory to use. ## `HK_CHECK_FIRST` [​](https://hk.jdx.dev/environment_variables\#hk-check-first) Type: `bool` Default: `true` If true, hk will run check commands first then run fix commands if check fails iff there are multiple linters with the same file in a matching glob pattern. The reason for this is to make hk able to parallelize as much as possible. We can have as many check commands running in parallel against the same file as we want without them interfering with each other—however we can't have 2 fix commands potentially writing to the same file. So we optimistically run the check commands in parallel, then if any fail we run their fix commands potentially in series. If this is disabled hk will have simpler logic that just uses fix commands in series in this situation. ## `HK_PROFILE` [​](https://hk.jdx.dev/environment_variables\#hk-profile) Type: `string[]` (comma-separated list) The profile(s) to use. ## `HK_FILE` [​](https://hk.jdx.dev/environment_variables\#hk-file) Type: `string` Default: `hk.pkl` \| `hk.toml` \| `hk.yaml` \| `hk.yml` \| `hk.json` The file to use for the configuration. ## `HK_FIX` [​](https://hk.jdx.dev/environment_variables\#hk-fix) Type: `bool` Default: `true` If set to `false`, hk will not run fix steps. ## `HK_JOBS` [​](https://hk.jdx.dev/environment_variables\#hk-jobs) Type: `usize` Default: `(number of cores)` The number of jobs to run in parallel. ## `HK_LOG` [​](https://hk.jdx.dev/environment_variables\#hk-log) Type: `trace` \| `debug` \| `info` \| `warn` \| `error` Default: `info` The log level to use. ## `HK_LOG_FILE` [​](https://hk.jdx.dev/environment_variables\#hk-log-file) Type: `path` Default: `~/.local/state/hk/hk.log` The log file to use. ## `HK_LOG_FILE_LEVEL` [​](https://hk.jdx.dev/environment_variables\#hk-log-file-level) Type: `trace` \| `debug` \| `info` \| `warn` \| `error` Default: `HK_LOG` The log level to use for the log file. ## `HK_MISE` [​](https://hk.jdx.dev/environment_variables\#hk-mise) Type: `bool` Default: `false` If set to `true`: - When installing hooks with `hk install`, hk will use `mise x` to execute hooks which won't require activating mise to use mise tools - When generating files with `hk init`, hk will create a `mise.toml` file with hk configured ## `HK_SKIP_STEPS` [​](https://hk.jdx.dev/environment_variables\#hk-skip-steps) Type: `string[]` (comma-separated list) A comma-separated list of step names to skip when running pre-commit and pre-push hooks. For example: `HK_SKIP_STEPS=lint,test` would skip any steps named "lint" or "test". ## `HK_SKIP_HOOK` [​](https://hk.jdx.dev/environment_variables\#hk-skip-hook) Type: `string[]` (comma-separated list) Default: `(empty)` A comma-separated list of hook names to skip entirely. This allows you to disable specific git hooks from running. For example: `HK_SKIP_HOOK=pre-commit,pre-push` would skip running those hooks completely. This is useful when you want to temporarily disable certain hooks while still keeping them configured in your `hk.pkl` file. Unlike `HK_SKIP_STEPS` which skips individual steps, this skips the entire hook and all its steps. ## `HK_STASH` [​](https://hk.jdx.dev/environment_variables\#hk-stash) Type: `git` \| `patch-file` \| `none` Default: `git` - `git`: Use `git stash` to stash unstaged changes before running hooks. - `patch-file`: Use an hk generated patch file to stash unstaged changes before running hooks (typically faster and avoids `index is locked` errors). - `none`: Do not stash unstaged changes before running hooks. Much faster but will stage unstaged changes if they are in the same file as staged changes with fix modifications. ## `HK_STASH_UNTRACKED` [​](https://hk.jdx.dev/environment_variables\#hk-stash-untracked) Type: `bool` Default: `true` If set to `true`, hk will stash untracked files when stashing before running hooks. ## `HK_FAIL_FAST` [​](https://hk.jdx.dev/environment_variables\#hk-fail-fast) Type: `bool` Default: `true` If `true`, hk will abort running steps after the first one fails. ## `HK_STATE_DIR` [​](https://hk.jdx.dev/environment_variables\#hk-state-dir) Type: `path` Default: `~/.local/state/hk` The state directory to use. ## `HK_HIDE_WHEN_DONE` [​](https://hk.jdx.dev/environment_variables\#hk-hide-when-done) Type: `bool` Default: `false` If set to `true`, hk will hide the progress output when the hook finishes if there are no errors. ## `HK_LIBGIT2` [​](https://hk.jdx.dev/environment_variables\#hk-libgit2) Type: `bool` Default: `true` If set to `false`, hk will not use libgit2 to interact with git and instead use shelling out to git commands. This may provide better performance in some cases such as when using `fsmonitor` to watch for changes.