Skip to content

v2.0.0: Shared top-level steps, contextual staging, and removal of v1 configuration

Latest

Choose a tag to compare

@github-actions github-actions released this 13 Sep 06:59
Immutable release. Only release title and notes can be modified.
f4ad840

hk 2.0 simplifies configuration around a single shared steps map, stages fixed files only in pre-commit by default, turns builtin variants into typed options, and removes the deprecated v1 configuration files and entry points. Upgrading requires reviewing your hk.pkl; see Breaking Changes below and the v2 migration guide.

Highlights

  • Less repetition in hk.pkl: a top-level steps block now defines the check, fix, and pre-commit hooks at once, and builtin variants such as gitleaks_staged or pinact_v3 are replaced by options on the primary builtin (#1255, #1253).
  • Predictable staging: only pre-commit stages fixes automatically; hk fix and custom hooks leave the index alone unless you ask (#1256).
  • Pkl only: hk.toml/yaml/json, .hkrc.pkl, UserConfig.pkl, hk generate, and the external pkl CLI fallback are gone; hk reports a targeted replacement for each removed input (#1257).
  • Nine new builtins for Terraform, Terragrunt, Kubernetes, Markdown, and repository hygiene, plus fixes to rubocop, tf_lint, and zizmor.

Breaking Changes

Shared top-level steps and hook defaults (#1255, @jdx)

A top-level steps map materializes implicit check, fix, and pre-commit hooks, so the common "define linters once, wire them into three hooks" pattern collapses to:

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

steps {
  ["prettier"] = Builtins.prettier
  ["eslint"] = Builtins.eslint
}

Defaults: check runs checks without fixing or staging, fix applies fixes without staging, and pre-commit fixes, stages, and uses Git stashing. No implicit pre-push is created. An explicit hook with one of these names keeps its own hook-level settings and replaces same-named inherited steps; the remaining shared steps still apply. Hooks gain enabled = false to skip a hook at run time and omit it from hk install. hk init and hk migrate pre-commit now emit this shorter form. In monorepos, subproject configs contribute steps only; explicit hook-level settings in a subproject are ignored with a debug message.

Staging is contextual (#1256, @jdx)

Previously fixed files were staged for every hook. Now only pre-commit stages by default; hk fix, check, and custom hooks leave the index untouched unless stage = true is set on the hook or --stage / HK_STAGE / git config hk.stage is supplied. Precedence is CLI and settings, then the hook's stage, then the hook-name default. A step's stage patterns are now pure path filters: they narrow what gets git added once hook-level staging is on, and never enable staging by themselves. Scripts that relied on hk fix staging its changes should pass --stage.

Builtins are flat, configurable steps (#1253, @jdx)

Every builtin is a plain Config.Step; default references such as ["prettier"] = Builtins.prettier are unchanged. The separate variant exports are removed in favor of typed options amended on the primary builtin:

Removed Replacement
Builtins.gitleaks_staged (Builtins.gitleaks) { scan = "staged" }
Builtins.knip_strict (Builtins.knip) { strict = true }
Builtins.pinact_v3, Builtins.pinact_update_v3 (Builtins.pinact) { version = "3" }, (Builtins.pinact_update) { version = "3" }
Builtins.check_byte_order_marker, Builtins.fix_byte_order_marker Builtins.byte_order_marker

Generic step customization (batch, glob, depends, ...) goes in the same amended object. hk's embedded evaluator is upgraded to pklr 2.0.1.

Deprecated v1 interfaces removed (#1257, @jdx)

hk now loads Pkl configuration only. Removed inputs fail with an error that names the replacement and links to the migration guide:

Removed in v2 Replacement
hk.toml, hk.yaml, hk.yml, hk.json hk.pkl amending Config.pkl
project .hkrc.pkl hk.local.pkl
home ~/.hkrc.pkl, --hkrc <PATH> ~/.config/hk/config.pkl
UserConfig.pkl (and its environment { }, defaults { }) Config.pkl with env { } and top-level settings
Types.Regex(...), Config.Regex(...) Pkl's built-in Regex(...)
hk generate hk init
HK_PKL_BACKEND=pkl remove it; pklr remains an accepted no-op

.config/hk.pkl, .config/hk.local.pkl, and XDG config.pkl continue to work. Global XDG hooks merge additively into project hooks (adding env, a missing report, and non-conflicting steps) without overriding project execution settings. The hk runtime no longer invokes the pkl CLI, directly or through mise; the built-in pklr evaluator is always used.

Added

  • Terraform and Terragrunt builtins (@sassdavid) #1362, #1363. terraform_docs (checks with --output-check, writes and stages the README on fix) and terraform_validate (runs terraform init -backend=false only when validation fails) operate per module directory derived from the selected files. terragrunt_hcl_fmt and terragrunt_hcl_validate run from the working directory since terragrunt hcl fmt --file accepts one path. hk migrate pre-commit maps terraform_docs, terraform_validate, and terragrunt_fmt.
  • kubeconform builtin (@sassdavid) #1363. Validates Kubernetes manifests; it globs all YAML, so narrow glob to your manifest paths if the repository holds unrelated YAML.
  • mado Markdown linter (@hituzi-no-sippo) #1349. Check-only builtin for the Rust CommonMark/GFM linter.
  • Repository hygiene checks (@sassdavid) #1360. New destroyed_symlinks (symlink in HEAD staged as a regular file), forbid_submodules (gitlinks in the index), and check_shebang_scripts_are_executable builtins, each also available as hk util <name>. hk migrate pre-commit maps the matching pre-commit ids, including forbid-new-submodules.
  • Release archives ship agent skills and completions (@jdx) #1337, #1336. Every release archive includes hk-configure and hk-debug skills under skills/, and native bash, zsh, fish, and PowerShell completion scripts are published as release assets. Both are declared in the signed packslip manifest so mise-compatible installers can use them without usage or a separate setup step.

Fixed

  • rubocop and rubocop_server now fix and block offenses (@andyw8) #1355. check_list_files used --list-target-files, which always exits 0, so hk skipped the check/fix commands. It now uses rubocop --format files.
  • tf_lint lints every module directory (@sassdavid) #1361. tflint was invoked without arguments and only linted the current directory. It now runs --chdir for each directory derived from the selected files, treats tflint's exit 2 after a successful fix as success, accepts all extensions tflint supports, and excludes .terraform.
  • zizmor embedded tests pass with hash pinning (@nettlesh) #1366. Projects using Builtins.hk_test with Builtins.zizmor no longer see five fixture failures on zizmor 1.20+, which requires hash-pinned first-party actions.
  • Fail-fast status reporting (#1253). Steps are marked aborted before the run is cancelled, and structured output reports cancelled before failed when both apply.

Documentation

  • Rewritten guides and a redesigned documentation site with a new landing page, reorganized navigation, a CI guide, downloadable example configurations, and richer generated CLI reference pages (@jdx) #1340.
  • Documented {% raw %}...{% endraw %} for step commands whose tool syntax uses {{, such as kubeconform's -schema-location (@sassdavid) #1359.

New Contributors

Full Changelog: v1.58.1...v2.0.0

💚 Sponsor hk

hk is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.

If hk speeds up your pre-commit loop or makes linting less painful, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep hk fast, free, and independent.