Releases: jdx/hk
v1.48.0: Group inheritance and builtin polish
Groups can now define defaults that child steps inherit, plus a new aqua checksum builtin, expanded RuboCop file matching, and a pklr fix for inline group configs.
Added
-
Inherit step settings from groups (@RobertDeRose) #982. A
Groupcan now setdir,prefix,workspace_indicator,shell,stage, andexclude, and child steps inherit any field they don't define themselves. Override semantics are simple: a child value fully replaces the group value, never merges.local frontend = new Group { dir = "packages/frontend" prefix = "mise x --" steps { ["prettier"] = (Builtins.prettier) { batch = true } ["eslint"] = (Builtins.eslint) { dir = "different/path" // overrides the group dir batch = true // still inherits prefix } } }
-
aqua_update_checksumbuiltin (@hituzi-no-sippo) #977. A fix-only step that runsaqua update-checksum --prunewhenever your aqua config or checksum files change, keepingaqua-checksums.jsonup to date and pruning unused entries.
Changed
-
rylandryl_markdownswitch tocheck_diff(@hituzi-no-sippo) #978. Both builtins now runryl --diffforcheck, surfacing exactly which YAML edits the linter wants to make. They also pick up project indicators (ryl.toml,.ryl.toml,.yamllint*) so the builtins are auto-suggested, and the bundled ryl tool stub moves to 0.15.0. -
RuboCop builtin file filter mirrors RuboCop's defaults (@hituzi-no-sippo) #969. Replaces the
types = List("ruby")matcher with the explicit glob list from RuboCop 1.87.0's default config, covering.rb,.gemspec,.rake,Gemfile,Rakefile,Vagrantfile, and friends, and applies RuboCop's default excludes (node_modules/**,tmp/**,vendor/**,.git/**). The bundled rubocop stub bumps to 1.87.0.
Fixed
- pklr validation of inline
new Groupentries (@jdx) #983. Bumpspklrto 1.0.6, which fixes validation ofMapping<String, Step | Group>properties initialized withnew Mapping<String, Step> {}— the shape used by hk's default hook config. Configs with inlinenew Group { ... }step entries no longer fail under the default pklr backend. Refs #981.
New Contributors
- @RobertDeRose made their first contribution in #982
Full Changelog: v1.47.0...v1.48.0
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.47.0: pklr by default, sturdier stash restores
hk now ships with the built-in pklr evaluator as the default config backend — no pkl CLI required — plus three stash, merge-base, and Windows batching fixes that close out reported regressions, and a handful of builtin improvements from @hituzi-no-sippo.
Added
-
pklris now the default pkl backend (@jdx) #976.hk.pklis evaluated with the embedded pklr interpreter out of the box, so the ApplepklCLI is no longer required to use hk. The CLI backend is still available viaHK_PKL_BACKEND=pkl; unrecognized values now warn and fall through topklr. The config cache also switched from mtime comparisons to hashing file contents, so edits to imported.pklfiles reliably invalidate the cache.# Default (no setup required) hk check # Opt back into the pkl CLI HK_PKL_BACKEND=pkl hk check
-
rylbuiltin gainsfixandcheck_list_files(@hituzi-no-sippo) #967. Bumps the underlyingrylto v0.13.0 and wires in the new commands. The yamllint config dependency is dropped. -
ryl_markdownbuiltin (@hituzi-no-sippo) #968. Lints YAML embedded inside Markdown documents using ryl's markdown support. -
hk_testbuiltin (@hituzi-no-sippo) #973. Runshk test --quietwhenever your hk configuration file changes so step-defined inline tests catch regressions automatically. -
hk sponsorscommand (@jdx) #961. A small no-config subcommand that prints the projects and companies sponsoring hk and the en.dev project family. Works withouthk.pkl.
Fixed
-
Last-line edits of partially-staged files no longer get corrupted on restore (@ad1269) #966. The "pure tail insertion" special case in the manual stash restore had a newline-tolerant fallback that stripped the index snapshot's trailing newline before the prefix check, so a last-line edit like
l3: tail→l3: tail UNSTAGEDwas misclassified as a tail insertion and re-emitted asfixer content + " UNSTAGED\n". The fallback now only accepts an empty remainder (the original case from #304); real last-line edits fall through to the three-way merge, which handles them correctly. The recovery patch written under the state dir also restores the trailing newline thatcmd.read()strips, sogit apply --checkno longer fails withcorrupt patch at line N. Fixes #965. -
hk checkworks when there is no merge base (@jdx) #975.files_between_refspreviously bailed when libgit2 or git couldn't find a common ancestor (e.g. shallow clones or unrelated histories). It now falls back to a shellgit merge-base, then to a directfrom..totree/shell diff. Both the libgit2 and shell-git paths use the same range logic, covered by new bats tests withHK_LIBGIT2=1andHK_LIBGIT2=0. Refs #972. -
Auto-batching respects the
cmd.execommand-line limit (@jdx) #974.auto_batch_jobsnow selects a shell-specific safe length: 4095 bytes (half of Windows' ~8191-character cap) forcmd.exe, andARG_MAX / 2for everything else. Medium-sized{{files}}expansions that fit under UnixARG_MAXno longer blow past thecmdlimit unbatched. Fixes #971. -
git2updated to 0.21 (#956).
Documentation
Full Changelog: v1.46.0...v1.47.0
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.46.0: --staged scope, global install, and a stash trilogy
A feature-and-fix release: hooks can now target staged files without touching your worktree, hk install cooperates with global installs, and three separate stash/merge bugs that could clobber fixer output or staged deletions are fixed.
Added
-
--stagedflag forhk run,check,fix, and hook subcommands (@jdx) #950. Runs hooks against the staged file set while leaving unstaged and untracked changes alone — no stash, no worktree mutation. It conflicts with--alland--stash, and forcesStashMethod::Noneeven when the hook config opts into stashing. Fixes #940.hk run pre-commit --staged hk fix --staged
-
hk installskips when hk is configured globally (@jdx) #934. If anyhook.hk-*entry exists in~/.gitconfig,hk installis a no-op and additionally cleans up stale per-repo hooks left behind from a prior install, so the global install is the single source of truth and hk doesn't fire twice per event. Pass--force-localto install per-repo hooks anyway. This means postinstall workarounds likegit config --get-regexp hook\.hk- || hk installcan now be replaced with a plainhk install. Closes #933. -
Named template variables for
post-checkouthooks (@jdx) #951. Steps can now referenceprev_head,new_head, andis_branch_checkout(a real boolean, mapped from git's1/0flag) instead of having to parse the combinedhook_argsstring.docs/hooks.mddocuments the per-hook variables forprepare-commit-msg,commit-msg, andpost-checkout. -
oxfmtbuiltin (@hituzi-no-sippo) #914. Adds oxfmt as a builtin formatter for JS/TS, JSON, YAML, and TOML. -
Vite+ builtin (@hituzi-no-sippo) #913. Adds Vite+ as a builtin formatter/linter for JavaScript/TypeScript.
-
oxlintbuiltin upgrades (@hituzi-no-sippo) #911. Adds--deny-warningsso violations exit non-zero, extends the file glob to.vue,.svelte,.astro,.mjs,.cjs,.mts, and.cts, and registers oxlint config files as project indicators so the builtin is auto-suggested.
Fixed
-
pre-pushref filter was inverted (@jdx) #932. The filter was checking the local sha for all-zeros (a deletion) when the intent was to check the remote sha (a new branch). Two visible consequences:- First push of a new branch was dropped and fell through to resolving
refs/remotes/origin/HEAD, which often failed withFailed to parse reference: refs/remotes/origin/HEAD(likely the root cause of #172). - Branch deletions were kept and triggered linting against the deleted ref.
The filter now drops only deletions, falls back to the real remote-tracking branch (or
Git::resolve_default_branch()) for new-branch pushes, and uses a newgit::is_zero_sha()helper that works for both SHA-1 and SHA-256 repos. - First push of a new branch was dropped and fell through to resolving
-
hk install --globalnow uses absolute paths (@jdx) #939. Global hook commands previously assumedhk/misewere onPATHwhen git invoked the hook, which broke in environments with a sanitizedPATH. The installer now resolveshk(ormise) to an absolute path at install time (using~/when home-relative and quoting otherwise), and--miseglobal installs usemise x hk -- hkso thehktool is requested explicitly. Global installs also pick hook events from the project'shk.pklwhen present. Fixes #937. -
fail_on_fixno longer loses fixer output throughstash = "git"(@jdx) #909.git stash show --name-onlycan list staged files stored in the stash commit that were not part of the unstaged set being restored, so the manual unstash could rewrite a staged-only file and discard the fixer's output that should remain visible as an unstaged diff. hk now tracks the exact path set selected for stashing and filters restore to that set. Follow-up to thefail_on_fixfix in v1.44.3. -
Staged deletions survive
pop_stash(@jdx) #927.pop_stash()walked every path returned bygit stash show --name-onlyand wrote a merged blob to disk, even for paths the user had staged for deletion withgit rm. After the commit, the deleted file reappeared on disk as untracked. hk now queriesgit diff --cached --diff-filter=Dbefore unstashing and skips those paths. Fixes #926. -
Fixer tail-line deletions are preserved across three-way merge (@jdx) #931. In
merge.rs::diff_hunks, when the LCS walk consumedotherentirely after a matching line, a pure tail deletion ofbase[i..n]was dropped, sothree_way_merge_hunkssilently copied the removed lines back in. The classic symptom: a fixer that strips trailing blank lines, applied to a file where you have an unrelated unstaged change in the middle, would have its trailing-line cleanup silently undone. Fixes #929. -
check_difffailures get accurate fix suggestions (@jdx) #949. When a step defined bothcheck_diffandcheck_list_files, the "To fix, run" hint always parsed output with the list-files parser regardless of which check actually ran. hk now passes the executed command intocollect_fix_suggestionand dispatches to the diff parser forcheck_diffoutput, so the suggested files match the real failure. Fixes #942.
Full Changelog: v1.45.0...v1.46.0
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.45.0: Buildifier built-ins and smarter auto-batching
A small feature release: Bazel users get first-class buildifier built-ins, and hk's auto-batching is now smart enough to leave steps alone when their commands don't actually reference the file list.
Added
-
buildifier_formatandbuildifier_lintbuilt-ins (@plx) #896. Two new built-ins for Bazel projects, modeled onbuf_format/buf_lint. They coverBUILD,BUILD.bazel,WORKSPACE,WORKSPACE.bazel,MODULE.bazel,*.bzl,*.star, and*.skyfiles, and ship with the usual project-indicator metadata so they're auto-suggested for Bazel repos.import "package://github.com/jdx/hk/releases/download/v1.45.0/hk@1.45.0#/Builtins.pkl" hooks { ["pre-commit"] { steps = new { ["buildifier-format"] = Builtins.buildifier_format ["buildifier-lint"] = Builtins.buildifier_lint } } }
Fixed
-
Auto-batching no longer splits jobs whose command doesn't reference
{{files}}(@jdx) #901. Previously, hk decided whether to split a step into multipleARG_MAX-safe batches purely from the size of the file-list expansion. On Windows — whereARG_MAXfalls back to 128KB — a step like:local vscodeCommitHint = new Step { exclusive = true check = "echo If you see this message in a pop-up, the pre-commit steps failed." }
…against a ~20K-file repo would be fanned out into ~29 jobs, printing the message 29 times even though the command never used
{{files}}. Auto-batching now happens at execution time with the full tera context available, renders the real run command for each candidate batch, and only splits when the rendered command exceeds the safe limit. Byte estimation is kept as a fallback if rendering fails. The split path also now correctly preservescheck_firstandworkspace_indicatoracross batches (the old code dropped them with a TODO).
Documentation
New Contributors
Full Changelog: v1.44.3...v1.45.0
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.44.3: Honest fail_on_fix and readable CI logs
A small patch release fixing two notable rough edges: fail_on_fix=true no longer silently re-stages the fixer's output over your git add, and hk's text-mode progress output is finally readable in CI logs.
Fixed
-
fail_on_fix=trueno longer overwrites your staged changes with the fix (@jdx) #892. Previously, when a hook hadfail_on_fix = true, the step's auto-staging would silently merge the fixer's output into the index over your explicitgit addchoices. After the failed commit, the fix was no longer visible as an unstaged change for review, and a re-commit would silently succeed with the fix baked in — defeating the entire point offail_on_fix.should_stageis now forced off forRunType::Fixruns whenfail_on_fixis set, so the fixer's output stays in the worktree as an unstaged change for you to inspect, and the commit keeps failing until you accept it. Fixes #888. -
Text-mode progress output is usable in CI again (@jdx) #890. hk's output in GitHub Actions and other piped-stderr environments was a mess: raw
[9A[80D[0Jcursor-control escapes leaked into the log, every status change was duplicated, failure stderr was suppressed, and a step matching hundreds of files dumped ~4KB of paths into every progress line. This release fixes the lot:- Bumps
clxto 2.0.1, which makesrefresh_once()a no-op in text mode (no more leaked UI escape codes) and dedupes consecutive identical job lines per job. - Failure summaries are now emitted in text mode by default. Successful steps stay quiet (their output already streamed during execution), but failed steps get a full diagnostic block at the end so you can see the failure in one place.
HK_SUMMARY_TEXT=1still forces every step's summary to print. - Per-step progress messages are bounded. A new display-only tera context truncates
files/workspace_filestofirst_file …when more than one file matches, and the rendered message itself is capped at 2048 printable chars (ANSI-aware). The execution command is rendered against the full file list as before — only the human-readable progress line is truncated. - Stops truncating text-mode messages at 60 chars. The previous
truncate_textfilter clamped toterm_width - 20, which is 60 in non-TTY environments — exactly enough to hide the diagnostic detail you actually need to debug a CI failure.
A typical
dbgstep matching 98.rsfiles now reads:dbg – 98 files – **/*.rs – ! rg -e 'dbg!' bin/generate_docs.rs …instead of unrolling all 98 paths on every prop update.
- Bumps
Full Changelog: v1.44.2...v1.44.3
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.44.2: pklr cache freshness and quieter Builtins
A small patch release focused on two HK_PKL_BACKEND=pklr rough edges: edits to hk.pkl are now picked up immediately, and loading Builtins.pkl no longer spams deprecation warnings on every run.
Fixed
-
hk.pkledits are now picked up underHK_PKL_BACKEND=pklr(@jdx) #879. The two pkl backends return different things fromanalyze_imports— thepklCLI happens to include the source file inresolvedImports, butpklronly returns transitiveimportURIs. As a result, withpklrthe mainhk.pklwas missing from the config cache'sfresh_files, so edits didn't invalidate the cache andhkkept reusing the staleConfiguntil you ranhk cache clear. The main config path is now always added tofresh_files. Fixes #877. -
No more
pklrdeprecation warnings on everyBuiltins.pklload (@jdx) #880. Previously, every invocation underHK_PKL_BACKEND=pklrprinted:[pklr] WARNING: property 'check_byte_order_marker' is deprecated [pklr] WARNING: property 'fix_byte_order_marker' is deprecated…even when your
hk.pkldidn't reference those aliases. This release bumpspklrto 0.4.2 (which evaluates@Deprecatedlazily, on field access) and reworksBuiltins.pklso its own internal bindings no longer touch the deprecated aliases at load time. The migration nudge still fires if you explicitly referenceBuiltins.check_byte_order_markerorBuiltins.fix_byte_order_marker. Fixes #878. -
Mobile docs banner layout (@jdx) #865, #867. At
<=640px, the banner now stacks the message and "Read more" link vertically, with the close button pinned to the top-right corner instead of floating in the middle of the taller stacked layout.
Documentation
- The VitePress site nav now surfaces the current release version (parsed from
Cargo.toml) and a GitHub star counter, matching the mise and aube docs (@jdx) #872.
Full Changelog: v1.44.1...v1.44.2
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.44.1: post-commit / pre-rebase and faster YADM-style worktrees
A small patch release fixing two rough edges introduced with the v1.44.0 global-hooks work: post-commit and pre-rebase now have proper hk run subcommands, and HK_STASH_UNTRACKED=false finally skips the untracked-file scan (not just the stash), which makes hk usable on YADM-style dotfile repos where GIT_WORK_TREE is $HOME.
Fixed
-
hk run post-commitandhk run pre-rebaseare now first-class subcommands (@jdx) #858. Both events are written byhk install, but previously fell through to the genericotherhandler — so they didn't show up inhk run --helpand their arguments got mixed into the positional file collector, occasionally producing confusingUsage: hk run --from-ref <FROM_REF> [FILES]...errors duringgit rebase.pre-rebasenow has a typed<upstream> [branch]signature matching git's spec, andpost-commitis a proper no-args handler. -
HK_STASH_UNTRACKED=falsenow also skips the untracked scan ingit status(@jdx) #861. Before this, the flag only suppressed stashing — hk still rangit status --untracked-files=allon every invocation, which could take tens of seconds and emit hundreds of megabytes of output whenGIT_WORK_TREEpoints at a large directory like$HOME(as in YADM). Both the libgit2 and shell-git code paths now honor the setting, so large-worktree users can opt out of the scan entirely. Fixes #860.export HK_STASH_UNTRACKED=false hk check --all # no longer scans the entire worktree for untracked files
Documentation
- Getting-started docs now lead with
hk install --globalas the recommended setup path, since the--from-hookshort-circuit added in v1.44.0 makes it safe to enable once per machine (@jdx) #855. - Added a dismissible cross-site announcement banner to hk.jdx.dev, with an optional
expiresfield so banners auto-hide on their own (@jdx) #857, #862.
Full Changelog: v1.44.0...v1.44.1
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.44.0: Install Globally, Plan Before You Run
This release is all about understanding and controlling where hk runs. hk check --plan lets you dry-run a hook and see exactly which steps would execute and why, hk install --global registers hk against every repo on your machine using Git 2.54's new config-based hooks, and bare-repo dotfile managers like YADM are now supported via GIT_DIR/GIT_WORK_TREE.
Highlights
hk check --plan/--why/--json— dry-run any hook to see which steps would run, which would skip, and why, with JSON output for toolinghk install --global— install hooks once in~/.gitconfigand have hk apply to every repo (Git 2.54+)- Bare-repo dotfile support — hk now respects
GIT_DIRandGIT_WORK_TREE, so YADM and similar setups work out of the box - New
cocogitto_commit_msgbuiltin for Conventional Commits validation
Added
-
hk check --plan/-P,--why [STEP]/-W,--json/-J: You can now dry-run a hook to see what hk would do without executing any commands.--planprints the parallel groups, matched file counts, and included/skipped steps with reasons;--whydrills into the skip reasons for every step (or a specific one);--jsonemits the plan as structured JSON for tooling. (@jdx) #848$ hk check --plan Plan: check Run type: check [parallel group] group_0 ○ actionlint (no files matched filters) ✓ cargo-fmt (6 files matched) ○ cargo-clippy (required profile(s) not enabled: slow) ✓ cargo-check (6 files matched)
The planner reuses hk's real job-building and skip-evaluation logic, so the plan accurately reflects what would happen — including filter matches, profile gating,
conditionevaluation,dependsOn, and--step/--skip-stepselections. It never executes step commands. -
Git 2.54 config-based hook installation with
--global: On Git 2.54+,hk installnow writes config-based hooks (hook.hk-<event>.command/.event) instead of shell shims in.git/hooks/. The hooks directory is left untouched, and hk composes cleanly with other hook managers. Use--legacyto force the old shim behavior; older Git falls back automatically. (@jdx) #853More importantly,
hk install --globalwrites those entries to your~/.gitconfigso hk runs in every repository on your machine:$ hk install --globalIn repos without an
hk.pkl(or without a matching event), the invocation is a silent no-op via a new hiddenhk run --from-hookflag — install once, forget, and repos that don't use hk are unaffected.hk uninstallnow cleans up both script shims and config entries regardless of current Git version, andhk uninstall --globalremoves the global entries. -
GIT_DIR/GIT_WORK_TREEsupport for bare-repo dotfile managers: hk now honors these environment variables during repository discovery, so it works with YADM and similar bare-repo dotfile setups where there is no.gitdirectory in the work tree. When libgit2 opens a bare repo, hk falls back to shellgitfor status/diff operations (libgit2 refuses those on bare repos). As a bonus,hk builtinsno longer loads project settings, so it runs outside a repo instead of panicking. Fixes #831. (@jdx) #847 -
cocogitto_commit_msgbuiltin: A new builtin linter that validates commit messages against the Conventional Commits spec using cocogitto'scog verify. Uses the{{commit_msg_file}}template variable, making it a drop-in for thecommit-msghook. (@hituzi-no-sippo) #838
Fixed
- Text progress in CI: Some CI systems allocate a pseudo-TTY, which made
console::user_attended_stderr()report an interactive stderr while the log collector stripped cursor-control escapes and recorded spinner frames as noisy log rows. hk now detects CI environments viais_ciand forces clx progress into text mode, while leaving local interactive behavior unchanged. (@jdx) #845
Changed
Full Changelog: v1.43.0...v1.44.0
💚 Sponsor hk
hk is developed by @jdx at en.dev — a small independent studio behind developer tools like mise, aube, hk, and more. Work on hk is funded by sponsorships.
If hk has sped up your pre-commit loop or made linting feel less painful, please consider sponsoring at en.dev. Sponsorships are what keep hk moving and the project independent.
v1.43.0: Stdin forwarding, harper builtin, and musl binaries
This release adds {{ hook_stdin }} for forwarding git hook stdin to step commands (completing git-lfs support started in v1.42.0), introduces a built-in harper grammar checker, and ships Linux musl binaries for Alpine and other musl-based distributions.
Highlights
{{ hook_stdin }}template variable completes git-lfs pre-push support -- LFS objects are now properly uploaded duringgit push- harper-cli builtin adds grammar checking as a first-class linter
- Linux musl release binaries for Alpine and other musl-based distros
- hk is back on crates.io -- installable via
cargo install hkagain
Added
-
{{ hook_stdin }}template variable: Step commands can now receive the raw stdin that git passes to hook scripts via thestdinfield. This is essential forgit lfs pre-push, which needs the ref data piped through stdin to know which LFS objects to upload. Without this,git lfs pre-pushwould silently succeed but upload nothing, causing the remote to reject the push. The variable is available inpre-pushandpost-rewritehooks. (@JohanLorenzo) #825hooks { ["pre-push"] { steps { ["git-lfs"] { check = "git lfs pre-push {{ hook_args }}" stdin = "{{ hook_stdin }}" } } } }
For
pre-push,{{ hook_stdin }}contains the ref lines that git pipes in (e.g.,refs/heads/main <local-sha> refs/heads/main <remote-sha>). Forpost-rewrite, it contains the old/new SHA mapping lines. When stdin is a terminal (no piped data), it expands to an empty string. -
Built-in
harperandharper_commit_messagelinter steps: harper-cli is now available as a builtin linter for grammar checking prose and documentation. Theharperstep runs against text files, whileharper_commit_messagechecks commit messages. (@hituzi-no-sippo) #714 -
Linux musl release binaries: Pre-built binaries for
x86_64-unknown-linux-muslandaarch64-unknown-linux-muslare now included in releases, making hk easy to install on Alpine Linux and other musl-based distributions. (@jdx) #829 -
hk is published to crates.io again: The crate had been stuck at v1.10.1 since August 2025 after the publish step was accidentally dropped during a build system migration. Starting with this release,
cargo install hkwill get the latest version. (@jdx) #830
New Contributors
- @hituzi-no-sippo made their first contribution in #714
Full Changelog: v1.42.0...v1.43.0
v1.42.0: Hook args template and Windows quoting fix
This release adds a new {{ hook_args }} template variable for forwarding git hook arguments to downstream commands, and fixes a Windows-specific bug where {{files}} expansion silently broke file-based checks.
Added
-
{{ hook_args }}template variable: Step commands can now access the arguments that git passes to hook scripts via{{ hook_args }}. This is essential for tools like git-lfs, whose hooks (post-checkout,post-merge,pre-push) require the original positional arguments from git to function correctly. Without this, commands likegit lfs post-checkoutwould fail with "This should be run through Git's post-checkout hook." (@JohanLorenzo) #807hooks { ["post-checkout"] { steps { ["git-lfs"] { check = "git lfs post-checkout {{ hook_args }}" } } } ["post-merge"] { steps { ["git-lfs"] { check = "git lfs post-merge {{ hook_args }}" } } } ["pre-push"] { steps { ["git-lfs"] { check = "git lfs pre-push {{ hook_args }}" } } } }
The variable is populated for all hook types:
pre-pushgets<remote-name> <remote-url>,commit-msggets the message file path,post-checkoutgets<prev-head> <new-head> <is-branch>, and so on. For hooks that receive no arguments (likepre-commit), it expands to an empty string. -
First-class
post-checkout,post-merge, andpost-rewritehooks: These three hook types now have dedicated subcommands (hk run post-checkout,hk run post-merge,hk run post-rewrite) with proper argument parsing, rather than being handled as generic hooks. (@JohanLorenzo) #807
Fixed
{{files}}expansion on Windows no longer silently breaks checks: On Windows, Rust'sCommand::argapplies MSVCRT-style argv escaping that collides withcmd.exe's own quoting rules. This caused the already-quoted{{files}}payload to reach tools with literal"characters embedded in arguments. Tools like ruff, biome, and others would silently exit 0 while processing zero files, making hk report success on broken invocations. The fix switches the Windowscmd.exe /ccode path to useraw_arg, passing the rendered command string verbatim so cmd.exe can parse its own quoting without Rust interference. This also affects{{workspace_files}}. (@jdx) #824
New Contributors
- @JohanLorenzo made their first contribution in #807
Full Changelog: v1.41.1...v1.42.0