Pre-commit Hooks
vx uses prek (a Rust-based pre-commit replacement) to enforce code quality checks before every commit. This document describes the hooks configured in .pre-commit-config.yaml and how they protect the codebase.
Overview
Pre-commit hooks run automatically when you execute git commit. If any hook fails, the commit is blocked until the issue is resolved. This catches problems early — before they reach CI or break other developers' builds.
# Install hooks (one-time setup)
vx prek install
# Run all hooks manually on all files
vx prek run --all-files
# Run a specific hook
vx prek run --hook-id cargo-hakariConfigured Hooks
1. Spell Checking (typos)
Catches common typos in source code and documentation.
- repo: https://github.com/crate-ci/typos
rev: v1.43.4
hooks:
- id: typos2. Rust Formatting (cargo-fmt)
Ensures all Rust code is formatted with rustfmt.
- id: cargo-fmt
entry: vx cargo fmt --all --
types: [rust]3. Rust Linting (cargo-clippy)
Runs Clippy and treats all warnings as errors.
- id: cargo-clippy
entry: vx cargo clippy --workspace -- -D warnings
types: [rust]4. Test Compilation Check (cargo-check-tests)
Compiles all test code to catch errors like E0061 (wrong number of arguments) that only appear in test files.
- id: cargo-check-tests
entry: vx cargo check --workspace --tests
types: [rust]5. YAML/JSON Formatting (prettier)
Formats YAML and JSON files with Prettier.
- id: prettier
entry: vx npx prettier --write --ignore-unknown
types_or: [yaml, json]6. Workspace-Hack Auto-Fix (cargo-hakari-fix) ⭐ New
Automatically regenerates the workspace-hack crate and stages the result when dependencies change.
- id: cargo-hakari-fix
name: cargo hakari generate (auto-fix)
entry: bash -c 'vx cargo hakari generate && vx cargo hakari manage-deps && git add crates/workspace-hack/Cargo.toml && vx cargo hakari generate --diff'
language: system
files: Cargo\.(toml|lock)$
pass_filenames: falseWhy this matters: vx uses cargo-hakari to optimize build times by unifying feature flags across the workspace. When you add or update a dependency in any Cargo.toml, the workspace-hack crate must be regenerated. Previously this was a manual step that was easy to forget; now the hook handles it automatically.
How it works:
- Triggers on any change to
Cargo.tomlorCargo.lock - Runs
cargo hakari generateandcargo hakari manage-depsto regenerate workspace-hack - Stages the updated
crates/workspace-hack/Cargo.tomlviagit add - Verifies with
cargo hakari generate --diffto confirm no remaining drift - The regenerated file is included in your commit automatically — no manual intervention needed
7. Justfile Duplicate Recipe Detection (justfile-no-duplicate-recipes) ⭐ New
Detects duplicate recipe definitions in the justfile.
- id: justfile-no-duplicate-recipes
name: justfile no duplicate recipes
entry: vx just --list
language: system
files: ^justfile$
pass_filenames: falseWhy this matters: The just command runner does not silently ignore duplicate recipe definitions — it exits with an error like:
error: Recipe `test-pkgs` first defined on line 74 is redefined on line 155
——▶ justfile:155:1
│
155 │ test-pkgs PKGS:
│ ^^^^^^^^^
Error: Process completed with exit code 1.This error would cause any just command to fail, breaking the entire development workflow and CI pipeline.
How it works:
- Triggers only when the
justfileis modified - Runs
just --listwhich parses the entire justfile and fails immediately on duplicate recipes - Catches the problem at commit time, before it reaches CI
When it fails: Find and remove the duplicate recipe definition:
# Find duplicate recipe names
grep -n "^[a-zA-Z_-]*:" justfile | sort | uniq -d
# Or use just to show the error location
just --list8. Common Safety Checks
Standard checks from pre-commit-hooks:
| Hook | Description |
|---|---|
check-merge-conflict | Prevents committing unresolved merge conflict markers |
check-added-large-files | Blocks files larger than 500 KB |
end-of-file-fixer | Ensures files end with a newline |
check-toml | Validates TOML syntax |
trailing-whitespace | Removes trailing whitespace |
Setup
Install prek
# Install prek via vx (auto-installs if needed)
vx prek installVerify Installation
# Check that hooks are installed
ls .git/hooks/pre-commit
# Run all hooks on all files to verify everything passes
vx prek run --all-filesBypassing Hooks (Emergency Only)
In rare cases where you need to commit without running hooks:
# Skip all hooks (use sparingly!)
git commit --no-verify -m "emergency fix"WARNING
Bypassing hooks should be a last resort. The CI pipeline runs the same checks, so skipping hooks locally just delays the failure to CI.
Troubleshooting
cargo-hakari-fix fails after adding a dependency
The hook should auto-fix most cases. If it still fails:
# Manually regenerate workspace-hack
vx cargo hakari generate
vx cargo hakari manage-deps
# Verify it's now clean
vx cargo hakari generate --diff
# Or use the justfile shortcut
vx just hakari-fixjustfile-no-duplicate-recipes fails
# Show the error with line numbers
vx just --list
# Search for the duplicate
grep -n "^recipe-name:" justfileHook runs slowly
The cargo-clippy and cargo-check-tests hooks compile Rust code, which can be slow on first run. Subsequent runs use the incremental compilation cache and are much faster.
Reset all hooks
# Uninstall and reinstall
vx prek uninstall
vx prek installAdvanced Usage
Run hooks on specific files
# Run all hooks on a specific file
vx prek run --files src/main.rs
# Run a specific hook on specific files
vx prek run --hook-id cargo-fmt --files src/lib.rs src/main.rsRun hooks in CI
The CI pipeline runs the same hooks via vx prek run --all-files. This ensures that:
- Local development and CI use identical checks
- No "works on my machine" issues with formatting or linting
- The workspace-hack is always in sync
Adding a new hook
To add a new pre-commit hook, edit .pre-commit-config.yaml:
- repo: local
hooks:
- id: my-new-check
name: my new check description
entry: vx cargo my-check
language: system
types: [rust]
pass_filenames: falseThen run vx prek run --all-files to verify the new hook works correctly.