RustyHook
RustyHook is a blazing-fast, Rust-native Git hook runner designed to be a modern, drop-in replacement for pre-commit
. It is language-agnostic, monorepo-friendly, and automatically provisions environments for linters and checkers written in Python, Node.js, Ruby, and more.
Features
- 🚀 Fast and concurrent execution powered by Rust
- 🧰 Automatic setup of Python virtualenvs, Node/npm environments, and Ruby/bundler installs
- 🌐 Language-agnostic support with consistent hook interface
- 🏗️ Monorepo-first with per-directory or per-project configurations
- 🪝 Compatibility with
.pre-commit-config.yaml
- 🧙 Migration tool to convert pre-commit configs to native
.rustyhook/config.yaml
- 📦 Cache-aware tool installs and version pinning
- 🆔 CLI alias:
rh
Quick Start
# Install RustyHook
cargo install rustyhook
# Initialize a new configuration
rh init
# Run your hooks
rh run
For more detailed information, check out the Getting Started guide.
Documentation Sections
- User Guide: Learn how to install, configure, and use RustyHook
- Reference: Detailed reference for supported languages, hook types, and configuration options
- Advanced: Advanced topics like monorepo support, custom hooks, and performance tuning
- Contributing: Information for developers who want to contribute to RustyHook
License
RustyHook is licensed under the MIT License.
Acknowledgments
- Inspired by
pre-commit
,lefthook
,moonrepo
, and the Rust community - Shoutout to contributors and early testers helping shape this project
Getting Started with RustyHook
This guide will help you get up and running with RustyHook quickly. We'll cover installation, basic configuration, and running your first hooks.
Prerequisites
Before you begin, make sure you have:
- Rust and Cargo installed (if installing via Cargo)
- Git installed and initialized in your project
- Basic familiarity with Git hooks
Installation
You can install RustyHook using one of the following methods:
Using Cargo
cargo install rustyhook
Manual Installation
Clone the repository and build from source:
git clone https://github.com/your-org/rustyhook.git
cd rustyhook
cargo build --release
The binary will be available at ./target/release/rustyhook
.
Verifying Installation
To verify that RustyHook is installed correctly, run:
rustyhook --version
# or using the alias
rh --version
Creating Your First Configuration
RustyHook uses a YAML configuration file to define your hooks. You can create a new configuration file using the init
command:
rh init
This will create a .rustyhook/config.yaml
file in your project root with some example hooks.
Basic Configuration Example
Here's a simple configuration example:
hooks:
- id: ruff
language: python
version: "==0.4.0"
entry: "ruff check"
files: "\\.py$"
- id: biome
language: node
version: "^1.6.2"
entry: "biome lint"
files: "\\.(ts|js|json)$"
Running Hooks
To run all configured hooks:
rh run
To run specific hooks:
rh run --hook ruff
Setting Up Git Hooks
To set up RustyHook as a Git pre-commit hook:
rh install
This will create a Git hook that runs RustyHook before each commit.
Next Steps
Now that you have RustyHook set up, you might want to:
- Learn more about CLI Usage
- Explore Configuration options
- Set up Shell Completions
- If you're migrating from pre-commit, check out the Migration Guide
Installation
This guide provides detailed instructions for installing RustyHook on different platforms.
Prerequisites
- Rust and Cargo: Required if installing via Cargo
- Git: Required for version control integration
Installation Methods
Using Cargo (Recommended)
The simplest way to install RustyHook is using Cargo, Rust's package manager:
cargo install rustyhook
This will download, compile, and install the latest version of RustyHook.
Using Package Managers
Homebrew (macOS and Linux)
brew install rustyhook
Chocolatey (Windows)
choco install rustyhook
Scoop (Windows)
scoop install rustyhook
Manual Installation
If you prefer to build from source:
-
Clone the repository:
git clone https://github.com/your-org/rustyhook.git
-
Navigate to the directory:
cd rustyhook
-
Build the project:
cargo build --release
-
The binary will be available at
./target/release/rustyhook
-
(Optional) Add to your PATH:
# On Unix-like systems cp ./target/release/rustyhook /usr/local/bin/ # On Windows, move to a directory in your PATH or add the release directory to your PATH
Verifying Installation
To verify that RustyHook is installed correctly:
rustyhook --version
# or using the alias
rh --version
Updating RustyHook
To update to the latest version:
cargo install rustyhook --force
Uninstalling
To uninstall RustyHook:
cargo uninstall rustyhook
Troubleshooting
Common Issues
- Command not found: Ensure the installation directory is in your PATH
- Permission denied: You may need to use
sudo
on Unix-like systems - Compilation errors: Make sure you have the latest version of Rust and Cargo
Getting Help
If you encounter any issues during installation, please:
- Check the FAQ for common problems
- Search for existing issues on the GitHub repository
- Open a new issue if your problem hasn't been reported
Next Steps
After installation, you might want to:
- Get started with RustyHook
- Learn about CLI usage
- Set up shell completions
CLI Usage
RustyHook provides a powerful command-line interface (CLI) for managing and running Git hooks. This guide covers all available commands and their options.
Command Overview
RustyHook can be invoked using either rustyhook
or the shorter alias rh
. Both commands provide identical functionality.
# These are equivalent
rustyhook [command] [options]
rh [command] [options]
Available Commands
run
Run hooks based on your configuration.
rh run [options]
Options:
--hook <HOOK_ID>
: Run only the specified hook--all-files
: Run on all files, not just changed ones--files <FILES>
: Run on specific files (comma-separated)--verbose
: Show detailed output--no-cache
: Skip using cached environments
Examples:
# Run all hooks on changed files
rh run
# Run only the 'ruff' hook
rh run --hook ruff
# Run all hooks on all files
rh run --all-files
# Run hooks on specific files
rh run --files src/main.rs,src/lib.rs
compat
Run hooks using a .pre-commit-config.yaml
file for compatibility with pre-commit.
rh compat [options]
Options:
- Same as
run
command
Example:
# Run pre-commit compatible hooks
rh compat
convert
Convert a pre-commit configuration to RustyHook's native format.
rh convert [options]
Options:
--from-precommit
: Convert from.pre-commit-config.yaml
--output <FILE>
: Output file (default: stdout)
Example:
# Convert pre-commit config to RustyHook config
rh convert --from-precommit > .rustyhook/config.yaml
init
Initialize a new RustyHook configuration.
rh init [options]
Options:
--force
: Overwrite existing configuration--template <TEMPLATE>
: Use a specific template (basic, full, minimal)
Example:
# Create a new configuration
rh init
# Create a new configuration with the full template
rh init --template full
list
List all configured hooks.
rh list [options]
Options:
--verbose
: Show detailed information
Example:
# List all hooks
rh list
doctor
Diagnose and fix issues with your RustyHook setup.
rh doctor [options]
Options:
--fix
: Attempt to fix issues automatically
Example:
# Check for issues
rh doctor
# Check and fix issues
rh doctor --fix
clean
Clean cached environments and tools.
rh clean [options]
Options:
--all
: Remove all cached data--language <LANGUAGE>
: Clean only specific language environments
Example:
# Clean all caches
rh clean --all
# Clean only Python environments
rh clean --language python
completions
Generate shell completion scripts.
rh completions <SHELL>
Arguments:
SHELL
: The shell to generate completions for (bash, zsh, fish, powershell)
Example:
# Generate Bash completions
rh completions bash > ~/.bash_completion.d/rustyhook
install
Install RustyHook as a Git hook.
rh install [options]
Options:
--hook-type <TYPE>
: Hook type to install (pre-commit, pre-push, etc.)--force
: Overwrite existing hooks
Example:
# Install as pre-commit hook
rh install --hook-type pre-commit
uninstall
Remove RustyHook Git hooks.
rh uninstall [options]
Options:
--hook-type <TYPE>
: Hook type to uninstall (pre-commit, pre-push, etc.)--all
: Uninstall all hook types
Example:
# Uninstall all hooks
rh uninstall --all
Global Options
These options can be used with any command:
--help
: Show help information--version
: Show version information--config <FILE>
: Use a specific configuration file--no-color
: Disable colored output--quiet
: Suppress all output except errors
Environment Variables
RustyHook respects the following environment variables:
RUSTYHOOK_CONFIG
: Path to configuration fileRUSTYHOOK_CACHE_DIR
: Directory for cached environmentsRUSTYHOOK_LOG_LEVEL
: Log level (debug, info, warn, error)RUSTYHOOK_NO_COLOR
: Disable colored output if set to any value
Exit Codes
0
: Success1
: Hook failure2
: Configuration error3
: System error4
: User error
Next Steps
- Learn about Configuration options
- Set up Shell Completions
- Explore Supported Languages
Configuration
RustyHook uses a YAML-based configuration file to define hooks and their behavior. This guide explains how to configure RustyHook for your project.
Configuration File Location
By default, RustyHook looks for configuration in the following locations (in order of precedence):
- Path specified by
--config
command-line option - Path specified by
RUSTYHOOK_CONFIG
environment variable .rustyhook/config.yaml
in the current directory.rustyhook/config.yml
in the current directory.pre-commit-config.yaml
(compatibility mode)
Basic Configuration Structure
A basic RustyHook configuration file looks like this:
# .rustyhook/config.yaml
hooks:
- id: ruff
language: python
version: "==0.4.0"
entry: "ruff check"
files: "\\.py$"
- id: biome
language: node
version: "^1.6.2"
entry: "biome lint"
files: "\\.(ts|js|json)$"
Hook Configuration Options
Each hook in the hooks
array can have the following properties:
Property | Required | Description |
---|---|---|
id | Yes | Unique identifier for the hook |
language | Yes | Language runtime (python, node, ruby, system) |
entry | Yes | Command to execute |
files | No | Regex pattern for files to include |
exclude | No | Regex pattern for files to exclude |
args | No | Additional arguments to pass to the command |
version | No | Version requirement for the tool |
pass_filenames | No | Whether to pass filenames to the command (default: true) |
always_run | No | Run even when no matching files are changed (default: false) |
verbose | No | Show verbose output for this hook (default: false) |
stages | No | Git stages to run on (pre-commit, pre-push, etc.) |
fail_fast | No | Stop execution on first failure (default: false) |
env | No | Environment variables to set |
working_dir | No | Directory to run the hook in |
Language-Specific Configuration
Python
hooks:
- id: ruff
language: python
version: "==0.4.0" # Pinned version
entry: "ruff check"
files: "\\.py$"
args: ["--fix"]
Python hooks use virtualenv to create isolated environments. The version
field specifies the package version to install with pip.
Node.js
hooks:
- id: eslint
language: node
version: "^8.0.0" # Semver compatible version
entry: "eslint"
files: "\\.(js|jsx|ts|tsx)$"
args: ["--fix"]
Node hooks use npm to install packages. The version
field specifies the package version to install with npm.
Ruby
hooks:
- id: rubocop
language: ruby
version: "~> 1.0" # Compatible version
entry: "rubocop"
files: "\\.(rb)$"
args: ["--auto-correct"]
Ruby hooks use bundler to install gems. The version
field specifies the gem version to install with bundler.
System
hooks:
- id: shellcheck
language: system
entry: "shellcheck"
files: "\\.(sh)$"
System hooks use commands available on the system PATH. No environment setup is performed.
Advanced Configuration
Global Settings
You can specify global settings that apply to all hooks:
default_stages: [pre-commit, pre-push]
fail_fast: true
exclude: "^vendor/"
hooks:
# Hook definitions...
Environment Variables
You can set environment variables for hooks:
hooks:
- id: my-hook
language: system
entry: "./my-script.sh"
env:
DEBUG: "true"
NODE_ENV: "development"
Working Directory
You can specify a working directory for hooks:
hooks:
- id: frontend-lint
language: node
entry: "eslint"
files: "\\.(js|jsx)$"
working_dir: "./frontend"
Multiple Configurations
For monorepos, you can have multiple configuration files in different directories. RustyHook will use the closest configuration file to the Git root.
Configuration Templates
RustyHook provides templates to help you get started:
# Create a basic configuration
rh init
# Create a configuration with more examples
rh init --template full
Migrating from pre-commit
If you're migrating from pre-commit, you can convert your existing configuration:
rh convert --from-precommit > .rustyhook/config.yaml
Next Steps
- Learn about CLI Usage
- Explore Supported Languages
- Set up Shell Completions
Migration from pre-commit
RustyHook is designed to be a drop-in replacement for pre-commit, making migration as seamless as possible. This guide will help you transition from pre-commit to RustyHook.
Compatibility Mode
The easiest way to start using RustyHook is with compatibility mode, which allows RustyHook to use your existing .pre-commit-config.yaml
file without any changes:
# Run hooks using your existing pre-commit configuration
rh compat
This command will:
- Read your
.pre-commit-config.yaml
file - Set up the necessary environments
- Run the hooks as defined in your pre-commit configuration
Converting Your Configuration
While compatibility mode works well, you'll get the best performance and features by converting to RustyHook's native configuration format:
# Convert pre-commit config to RustyHook config
rh convert --from-precommit > .rustyhook/config.yaml
This will create a new .rustyhook/config.yaml
file based on your existing pre-commit configuration.
Configuration Differences
Here's how pre-commit and RustyHook configurations compare:
pre-commit Configuration
# .pre-commit-config.yaml
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.262'
hooks:
- id: ruff
args: [--fix]
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.38.0
hooks:
- id: eslint
files: \.(js|jsx|ts|tsx)$
types: [file]
additional_dependencies:
- eslint@8.38.0
- eslint-config-standard@17.0.0
Equivalent RustyHook Configuration
# .rustyhook/config.yaml
hooks:
- id: ruff
language: python
version: "==0.0.262"
entry: "ruff"
args: ["--fix"]
files: "\\.py$"
- id: eslint
language: node
version: "^8.38.0"
entry: "eslint"
files: "\\.(js|jsx|ts|tsx)$"
args: []
dependencies:
- "eslint-config-standard@17.0.0"
Key Differences
-
Repository References: RustyHook doesn't use the
repos
structure. Instead, it directly defines hooks with their language and version. -
Version Specification:
- pre-commit uses Git revisions (
rev
) - RustyHook uses package version specifiers (
version
)
- pre-commit uses Git revisions (
-
Dependencies:
- pre-commit uses
additional_dependencies
- RustyHook uses
dependencies
- pre-commit uses
-
Entry Point:
- pre-commit infers the entry point from the hook ID
- RustyHook requires an explicit
entry
field
-
File Patterns:
- Both use similar regex patterns, but RustyHook always requires the
files
field if you want to filter by file type
- Both use similar regex patterns, but RustyHook always requires the
Migrating Git Hooks
If you've installed pre-commit as a Git hook, you'll need to uninstall it and install RustyHook instead:
# Uninstall pre-commit hooks
pre-commit uninstall
# Install RustyHook hooks
rh install
Handling Custom Hooks
If you have custom hooks defined in your pre-commit configuration, you'll need to adapt them for RustyHook:
pre-commit Custom Hook
repos:
- repo: local
hooks:
- id: custom-script
name: Custom Script
entry: ./scripts/custom.sh
language: script
files: \.txt$
RustyHook Custom Hook
hooks:
- id: custom-script
language: system
entry: "./scripts/custom.sh"
files: "\\.txt$"
Handling Local Hooks
RustyHook treats all hooks as "local" by default. There's no need for a special local
repository designation.
Troubleshooting Migration Issues
Common Issues
-
Missing Dependencies: If your pre-commit hooks had implicit dependencies, you might need to add them explicitly in RustyHook.
-
Path Differences: RustyHook executes hooks from the Git root by default. Use
working_dir
if you need to change this. -
Hook Execution Order: RustyHook executes hooks in the order they're defined in the configuration file.
Debugging
If you encounter issues during migration, use the --verbose
flag to get more information:
rh run --verbose
You can also use the doctor
command to diagnose issues:
rh doctor
Next Steps
After migrating to RustyHook, you might want to:
- Explore Configuration options to take advantage of RustyHook-specific features
- Learn about CLI Usage to optimize your workflow
- Set up Shell Completions for a better command-line experience
Shell Completions
RustyHook provides shell completion scripts for Bash, Zsh, Fish, and PowerShell. This guide explains how to generate and install these completion scripts to enhance your command-line experience.
Generating Completion Scripts
RustyHook can generate completion scripts for various shells using the completions
command:
rustyhook completions <SHELL>
Replace <SHELL>
with one of the following:
bash
: For Bash shellzsh
: For Zsh shellfish
: For Fish shellpowershell
: For PowerShell
Installing Completion Scripts
Bash
# Create completion directory if it doesn't exist
mkdir -p ~/.bash_completion.d
# Generate and save completion script
rustyhook completions bash > ~/.bash_completion.d/rustyhook
# For the alias (rh)
rustyhook completions bash | sed 's/rustyhook/rh/g' > ~/.bash_completion.d/rh
# Source the completion script
echo 'source ~/.bash_completion.d/rustyhook' >> ~/.bashrc
echo 'source ~/.bash_completion.d/rh' >> ~/.bashrc
# Apply changes
source ~/.bashrc
Zsh
# Create completion directory if it doesn't exist
mkdir -p ~/.zsh/completions
# Generate and save completion script
rustyhook completions zsh > ~/.zsh/completions/_rustyhook
# For the alias (rh)
rustyhook completions zsh | sed 's/rustyhook/rh/g' > ~/.zsh/completions/_rh
# Make sure ~/.zsh/completions is in your fpath
echo 'fpath=(~/.zsh/completions $fpath)' >> ~/.zshrc
echo 'autoload -U compinit && compinit' >> ~/.zshrc
# Apply changes
source ~/.zshrc
Fish
# Create completion directory if it doesn't exist
mkdir -p ~/.config/fish/completions
# Generate and save completion script
rustyhook completions fish > ~/.config/fish/completions/rustyhook.fish
# For the alias (rh)
rustyhook completions fish | sed 's/rustyhook/rh/g' > ~/.config/fish/completions/rh.fish
# Fish automatically loads completions from this directory
PowerShell
# Create a directory for the completion script if it doesn't exist
if (-not (Test-Path -Path "$PROFILE\.." -PathType Container)) {
New-Item -Path "$PROFILE\.." -ItemType Directory -Force
}
# Generate and save completion script
rustyhook completions powershell > $PROFILE.CurrentUserCurrentHost/rustyhook.ps1
# For the alias (rh)
rustyhook completions powershell | ForEach-Object { $_ -replace "rustyhook", "rh" } > $PROFILE.CurrentUserCurrentHost/rh.ps1
# Source the completion script
echo '. $PROFILE.CurrentUserCurrentHost/rustyhook.ps1' >> $PROFILE
echo '. $PROFILE.CurrentUserCurrentHost/rh.ps1' >> $PROFILE
# Apply changes
. $PROFILE
Verifying Completions
After installing the completion scripts, you can verify they're working by typing rustyhook
or rh
followed by a space and pressing the Tab key. You should see available commands and options.
Troubleshooting
Completions Not Working
If completions aren't working after installation:
- Make sure you've sourced your shell configuration file (
.bashrc
,.zshrc
, etc.) - Verify that the completion script was generated correctly
- Check that the completion script is in the correct location
- Ensure your shell is configured to use completions
Bash Completions
If Bash completions aren't working:
# Add this to your .bashrc if it's not already there
if [ -d ~/.bash_completion.d ]; then
for file in ~/.bash_completion.d/*; do
. "$file"
done
fi
Zsh Completions
If Zsh completions aren't working:
# Make sure compinit is loaded
autoload -Uz compinit && compinit
Next Steps
- Learn about CLI Usage
- Explore Configuration options
- Check out the Migration Guide if you're coming from pre-commit
Supported Languages
Hook Types
Configuration Reference
Monorepo Support
Custom Hooks
Performance Tuning
Development Setup
Architecture
Testing
Frequently Asked Questions
General Questions
What is RustyHook?
RustyHook is a blazing-fast, Rust-native Git hook runner designed to be a modern, drop-in replacement for pre-commit
. It is language-agnostic, monorepo-friendly, and automatically provisions environments for linters and checkers written in Python, Node.js, Ruby, and more.
How does RustyHook compare to pre-commit?
RustyHook is designed to be a faster, more efficient alternative to pre-commit with these key advantages:
- Written in Rust for better performance
- Concurrent hook execution
- Native support for monorepos
- Automatic environment setup for multiple languages
- Compatible with existing pre-commit configurations
Is RustyHook compatible with pre-commit configurations?
Yes! RustyHook can run your existing .pre-commit-config.yaml
files using the rh compat
command. You can also convert your pre-commit configuration to RustyHook's native format using rh convert
.
Installation and Setup
How do I install RustyHook?
The easiest way to install RustyHook is using Cargo:
cargo install rustyhook
For other installation methods, see the Installation Guide.
How do I set up RustyHook in my project?
To set up RustyHook in your project:
- Install RustyHook
- Initialize a configuration file:
rh init
- Edit the
.rustyhook/config.yaml
file to configure your hooks - Install the Git hooks:
rh install
Can I use RustyHook with CI/CD systems?
Yes, RustyHook works well in CI/CD environments. You can run hooks using:
rh run --all-files
This will run all hooks on all files, not just changed ones.
Configuration
How do I configure RustyHook?
RustyHook uses a YAML configuration file located at .rustyhook/config.yaml
. See the Configuration Guide for details.
Can I use RustyHook in a monorepo?
Yes, RustyHook is designed with monorepos in mind. You can have multiple configuration files in different directories, and RustyHook will use the closest configuration file to the Git root.
How do I add a new hook?
To add a new hook, edit your .rustyhook/config.yaml
file and add a new entry to the hooks
array:
hooks:
- id: my-new-hook
language: python
version: "==1.0.0"
entry: "my-hook-command"
files: "\\.py$"
Troubleshooting
My hooks aren't running. What should I check?
- Make sure RustyHook is installed correctly (
rh --version
) - Check that your configuration file is valid (
rh doctor
) - Verify that Git hooks are installed (
ls -la .git/hooks
) - Run hooks manually to see any errors (
rh run --verbose
)
How do I debug hook failures?
Use the --verbose
flag to get more detailed output:
rh run --verbose
You can also use the doctor
command to diagnose issues:
rh doctor
How do I clean up cached environments?
To clean up cached environments:
rh clean --all
Or to clean only specific language environments:
rh clean --language python
Advanced Usage
Can I run hooks on specific files?
Yes, you can run hooks on specific files:
rh run --files src/main.rs,src/lib.rs
How do I skip hooks for a specific commit?
To skip hooks for a specific commit:
git commit --no-verify
Or with the -n
shorthand:
git commit -n
Can I use RustyHook with hooks other than pre-commit?
Yes, RustyHook supports various Git hooks:
rh install --hook-type pre-push
Contributing
How can I contribute to RustyHook?
We welcome contributions! See the Contributing Guide for details on how to get started.
Where can I report bugs or request features?
You can report bugs or request features on the GitHub issue tracker.