mise install installs the configured mbx version. mise run activates the project's transparent
Cargo wrapper, so compilation-heavy mise tasks and hk checks use ordinary
cargo commands. Standalone Cargo commands require an activated mise shell. If
the wrapper fails or creates a development papercut, rerun the exact equivalent
command from CONTRIBUTING.md with MBX_DISABLE=1; this unblocks work without
weakening the check. If bypassed Cargo succeeds, surface the mismatch and recommend a
mr-boxington Discussion with
the repository and commit, OS, mbx --version, mbx doctor, and both commands
and outputs. Redact secrets, absolute cache paths, remote URLs, namespaces, and
other sensitive or identifying details. Do not permanently disable the wrapper,
and do not post externally without user authorization.
This file provides guidance to AI coding agents when working with code in this repository.
PR titles MUST follow conventional commit format. Intermediate commit subjects SHOULD use the same format:
Format: <type>(<scope>): <description>
Types:
feat:- New featuresfix:- Bug fixes that affect the CLI behavior (not CI, docs, or infrastructure)refactor:- Code refactoringdocs:- Documentation changesstyle:- Code style/formatting (no logic changes)perf:- Performance improvementstest:- Testing changeschore:- Maintenance tasks, releases, dependency updates, CI/infrastructure changessecurity:- Security-related changesci:- CI and automation changesrevert:- Reverting a previous change
Scopes:
- For command-specific changes, use the command name:
check,fix,run,init,install,validate, etc. - For subsystem changes:
hook,step,config,lock,pkl,builtins,stash,deps
Description Style:
- Start the description with a lowercase character
- Use imperative mood ("add feature" not "added feature")
- Keep it concise but descriptive
Examples:
fix(step): resolve race condition in file lockingfeat(check): add --slow flag for expensive lintersfeat(builtins): add biome linterdocs: update pkl configuration exampleschore: release 0.5.0
CI validates the pull request title and re-runs when it is edited. Intermediate commit subjects are not checked because pull requests are squash-merged. CI mechanically checks the allowed type, syntax, and lowercase-leading description; imperative mood remains a review rule.
- Use the lowest compatibility-significant specificity in
Cargo.toml(for example,"1"for stable 1.x dependencies). - When the existing manifest requirement accepts a routine dependency update, change only
Cargo.lock. - Keep lockfile updates focused and avoid unrelated transitive dependency churn.
Build the project:
mise run buildRun tests:
# Run all tests (Rust unit tests + bats integration tests)
mise run test
# Run only Rust tests
mise run test:cargo
# Run a single Rust test by name
cargo test test_name
# Run only bats tests
mise run test:bats
# Run a specific bats test file
mise run test:bats test/check.batsLint and format code:
# Run all linters and checks
hk check --all
hk check --all --slow # includes slower checks (cargo clippy)
# Fix formatting and linting issues
hk fix --all
hk fix --all --slowhk is a git hook manager and project linting tool written in Rust with emphasis on performance and concurrent execution. The architecture leverages file locks to maximize concurrency while preventing race conditions.
The root Cargo package builds the hk CLI and the generate-docs utility. It depends on separately published crates for shared functionality:
- xx: HTTP client and utilities
- clx: CLI/terminal UI utilities (progress indicators, styling)
- ensembler: Script/command execution engine
Configuration System (src/config.rs):
- Main config file:
hk.pklin project root - Uses Pkl (github.com/apple/pkl) as the configuration language
- Config amends a base schema from
pkl/Config.pkl
Hook System (src/hook.rs):
- Manages git hooks (pre-commit, pre-push, commit-msg, prepare-commit-msg)
- Supports custom hooks like "check" and "fix" for manual runs
- Implements stashing strategies for git hooks
- Handles concurrent step execution with proper locking
Step Execution (src/step/):
- Steps are individual linting/formatting tasks
- Each step can have: check, fix, shell commands
- Steps support glob patterns for file filtering
- Steps can depend on other steps
- Steps use read/write file locks to prevent conflicts
File Locking (src/file_rw_locks.rs):
- Implements a sophisticated file locking system
- Allows multiple readers or single writer per file
- Prevents race conditions during concurrent execution
- Critical for maximizing parallelism
Built-in Linters (pkl/builtins/):
- Extensive library of pre-configured linters and formatters
- Each builtin is a Pkl file defining step configuration
- Used via
Builtins.linter_namein hk.pkl
CLI Interface (src/cli/):
- Subcommands: init, install, uninstall, check, fix, run, validate, config
- Uses usage-rs for argument parsing
- Supports running specific hooks or steps
- Preview or build the website with
mise run docsormise run docs:build. - Edit generated reference content at its source:
pkl/Config.pkl,settings.toml, builtin definitions, and Rust CLI help comments. scripts/enrich-cli-docs.pyadds maintained examples after CLI reference generation.- Example pages include
docs/public/*.pkldirectly. Validate them withscripts/generate-examples.shin the mise environment.
- Concurrent Execution: Steps run in parallel when possible, using tokio for async runtime
- File-based Coordination: Uses in-memory read/write locks keyed by file path to coordinate steps within a hook run
- Pluggable Configuration: Pkl-based config allows easy extension and customization
- Progressive Enhancement: Works with or without git, libgit2, mise, etc.
- Git Integration: Can use either libgit2 or shell git commands (controlled by
HK_LIBGIT2env var, default: true) - Mise Integration: Deeply integrated with mise for task running and tool management
- Tool Discovery: Automatically finds tools via PATH or mise shims
Bats integration tests are in test/*.bats. Each test file uses a common setup pattern:
setup() {
load 'test_helper/common_setup'
_common_setup
}Tests run in isolated temp directories with a clean git repo. The $PKL_PATH variable points to the pkl config directory for amending Config.pkl.
Builtins should have pkl-level tests defined via the tests field on the Step (see pkl/Config.pkl StepTest). These tests are run by hk test and exercised in CI via test/builtins_tests.bats, which loads all builtins and runs their tests.
Tool stubs in test/builtin_tool_stubs/ use mise tool-stub to auto-install the correct tool version on demand. Each stub is a small script:
#!/usr/bin/env -S mise tool-stub
version = "2"
tool = "aqua:golangci/golangci-lint"To add a new builtin with tests:
- Define the builtin in
pkl/builtins/<name>.pklwith atestsblock - Add a tool stub in
test/builtin_tool_stubs/<tool-name>if the tool isn't already available - Use the
TestMakerhelper frompkl/builtins/test/helpers.pklfor standard check/fix test patterns - Run
hk test --step <step_name>to verify, ormise run test:bats test/builtins_tests.batsto run all builtin tests
When AI contributes GitHub content—including a pull request description, review, pull request comment, or discussion post—append this disclosure:
*AI-assisted — Tool: <tool>; model: <provider>/<model>; version: <version-or-unavailable>.*
Use the exact model and version identifiers exposed by the runtime. Never infer or guess them; use
unavailable when either value is not exposed.