This release brings hk to monorepos with nested subprojects configs and per-directory mise environments, adds a --unstaged flag for linting only working-tree changes, and ships a batch of correctness fixes for branch guards, empty remotes, and conventional commit scopes.
Added
-
subprojectsfor monorepos (@jdx) #1094. The roothk.pklcan list literal directories or globs, and each subproject's ownhk.pklis merged into the root run scoped to its directory. Step working directories and glob matching are relative to the subdirectory, flat step names are prefixed with<dir>:(e.g.packages/web:eslint) for--step/skip_steps, and a subproject'senvapplies only to its own steps. Paired with this,HK_MISE=1now resolvesmise env --jsonper stepdir, so subproject-local tools land on PATH — including for structuredargvcommands.// hk.pkl (repo root) subprojects = List("frontend", "packages/*") // frontend/hk.pkl hooks { ["check"] { steps { ["eslint"] = (Builtins.eslint) { batch = true } } } }
-
--unstagedflag (@jdx) #1093. Available onhk check,hk fix, andhk run <hook>, this selects only unstaged and untracked files (excluding staged files) without stashing — the strict inverse of--staged. It's aimed at agent-stop hooks that need to lint just the files an AI agent touched in the working tree. Conflicts with--staged,--all,--files,--from-ref/--to-ref,--glob,--pr, and--stash. -
rumdl_formatbuiltin (@risu729) #1080. Adds a dedicated Markdown formatter usingrumdl fmt --check --diff/rumdl fmt, separate from the existingrumdllinter, mirroring the linter/formatter split hk already uses for ruff, taplo, and tombi.["rumdl_format"] = Builtins.rumdl_format
Fixed
-
Branch guard allows detached HEAD (@jdx) #1075. The
no_commit_to_branchguard treatedgit symbolic-refexiting nonzero as fatal, blocking commits created during operations like interactive rebase where HEAD is detached. It now treats a detached HEAD as "not on a protected branch" while still surfacing genuine Git errors. Fixes discussion #1074. -
Pre-push works against an empty remote (@sshine) #1090. When a pre-push hook runs before the first push, the unresolvable base ref no longer fails the run; hk falls back to listing all files at the target ref. This is @sshine's first contribution.
-
hk utilskips config loading (@jdx) #1078. Builtins liketrailing-whitespaceshell out tohk util, and each child was loading project and user Pkl config it never used. Utility commands now run with default settings, avoiding redundant parallel evaluation that was a likely source of intermittent failures under normal concurrency. Fixes discussion #1077. -
miseformatter no longer batches (@risu729) #1079. The builtin hadbatch = trueeven thoughmise fmtprocesses project config itself and takes no file arguments, so multiple matched files could launch duplicate whole-project jobs. It now runs once per invocation. -
Conventional commit scope validation (@LordAizen1) #1071.
check-conventional-commitnow rejects empty scopes (feat(): ...) and malformed scopes with junk after the closing paren (feat(scope)(x): ...), which the previous check accepted. Valid forms likefeat(scope)!: ...still pass. This is @LordAizen1's first contribution. -
min_hk_versionerror message (@smasato) #1070. The running and required versions were swapped in the "version is less than the minimum required" error; the message now reports them correctly.
New Contributors
- @sshine made their first contribution in #1090
- @LordAizen1 made their first contribution in #1071
Full Changelog: v1.51.0...v1.52.0
💚 Sponsor hk
hk is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, 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 jdx.dev. Sponsorships are what keep hk moving and the project independent.