github jdx/hk v1.57.0
v1.57.0: Faster cold starts, workspace-aware directories, and safer partial fixes

4 hours ago

This release seeds hk with an embedded Pkl package so matching-version configs validate offline on a cold cache, adds templated dir support for workspace-aware steps, and lands a new check_after_diff mechanism that lets partial fixers (like ShellCheck) apply what they can while still reporting what they cannot. It also brings several new Go and lint builtins plus a batch of correctness fixes for Go linters, gitleaks, workspace paths, Windows shims, and stashing.

Added

  • Embedded matching-version Pkl package (@sahidvelji) #1218. hk now ships the Pkl package built for its own version and seeds HK_PKL_CACHE_DIR with it before evaluating hk.pkl, so a config pinned to that version validates with no network round trip on a cold cache — a fresh clone, CI runner, new container, or upgrade. Cached content always wins over the embedded copy, and other versions are fetched as before. Set HK_PKL_EMBEDDED=0 to disable seeding. Addresses discussion #1216.

  • Templated dir through Tera (@sahidvelji) #1219. A step's dir is now rendered through Tera, so a workspace-aware step can point its working directory at the workspace it was matched for instead of prefixing every command with cd {{workspace}} && .... The eight workspace-aware builtins (the Go ones plus cargo_deny) drop their cd prefix as a result. Literal dir values are unaffected.

    ["go-vet"] {
      glob = "**/*.go"
      workspace_indicator = "go.mod"
      dir = "{{workspace}}"
      check = "go vet ./..."
    }
  • check_after_diff for partial fixers (@jdx) #1243. New opt-in step setting that reruns check on the original file batch after a check_diff patch applies, so non-fixable findings stay visible instead of being masked by a clean apply. Requires both check and check_diff to be defined. This underpins ShellCheck's new fixer and other partial fixers.

  • ShellCheck autofix via check_diff (@sahidvelji) #1237. shellcheck now applies the fixes it can via --format=diff, and thanks to check_after_diff a file with both fixable and non-fixable findings is fixed and still fails on what remains. Implements proposal 2 of #1234.

  • go_fix builtin (@sahidvelji) #1224. Wraps Go's go fix (the Go 1.26+ analyzer-driven modernizer) — interface{}any, sort.Sliceslices.Sort, wg.Add/go/wg.Donewg.Go, and more. check_diff runs go fix -diff ./... and hk applies the patch directly. Requires Go 1.26+.

  • golangci_lint_fmt formatter builtin (@sahidvelji) #1244. Wraps golangci-lint fmt, the formatter half of golangci-lint, formatting only the changed files via check_diff (using fmt --diff) — separate from the existing golangci_lint builtin that runs the full linter.

  • ls_lint builtin (@sahidvelji) #1238. Adds a builtin for ls-lint, which enforces directory and filename naming conventions against .ls-lint.yml. Runs once per invocation. Implements proposal 3 of #1234.

  • gitleaks_staged builtin (@jdx) #1248. A new builtin that runs gitleaks git --pre-commit --staged to scan only the staged index, suited to pre-commit hooks.

  • Per-step allow_failure (@jdx) #1291. Steps can report a non-zero command exit without failing the overall hook, including conditional policies via expressions such as env('KNOWN_BROKEN') == 'true'. hk's own execution and configuration errors remain blocking, and allowed failures are surfaced in structured output.

Fixed

  • Go linters that reported success on bad code (@sahidvelji) #1225. go_imports, go_lines, revive, and go_fumpt silently passed in check mode even with real findings; they now take their exit code correctly. gomod_tidy could not run outside the repo root and is now scoped like the other Go builtins.
  • gitleaks scan modes (@jdx) #1248. Builtins.gitleaks now explicitly scans the repository working tree rather than silently changing behavior when {{files}} expanded to multiple paths.
  • gomod_tidy now runs on .go changes (@sahidvelji) #1236. Broadened the glob to **/*.go, **/go.mod, and **/go.sum so the common drift (editing an import) is caught at commit time, and its go.mod/go.sum updates are now staged when triggered by a Go change (@jdx) #1240.
  • Partial diff fixes no longer pass silently (@jdx) #1245. Enabled check_after_diff for rumdl, ryl, ryl_markdown, zizmor, and pinact_v3, so remaining violations surface after hk applies each partial patch.
  • Workspace paths in literal dir steps (@jdx) #1242. {{workspace}} and {{workspace_indicator}} are now rendered relative to a literal step directory, preventing duplicated paths like ui/ui/tsconfig.json in subprojects. Addresses discussion #1233.
  • Windows command shims (@jdx) #1221. Structured argv steps now resolve .cmd/.bat targets (including npm node_modules/.bin shims) via the effective PATH/PATHEXT and run them through cmd.exe with argument-boundary-preserving escaping. Fixes discussion #1220.
  • Empty pathspec stashes (@jdx) #1283. Pre-commit runs no longer reset the index and leave an orphaned stash when a path-limited stash has no HEAD-to-worktree diff (e.g. mode-only staged changes). Addresses discussion #1281.

New Contributors

Full Changelog: v1.56.1...v1.57.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.

AI-assisted — Tool: Codex; model: openai/gpt-5; version: unavailable.

Don't miss a new hk release

NewReleases is sending notifications on new releases.