Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

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

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:

  1. Clone the repository:

    git clone https://github.com/your-org/rustyhook.git
    
  2. Navigate to the directory:

    cd rustyhook
    
  3. Build the project:

    cargo build --release
    
  4. The binary will be available at ./target/release/rustyhook

  5. (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:

  1. Check the FAQ for common problems
  2. Search for existing issues on the GitHub repository
  3. Open a new issue if your problem hasn't been reported

Next Steps

After installation, you might want to:

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 file
  • RUSTYHOOK_CACHE_DIR: Directory for cached environments
  • RUSTYHOOK_LOG_LEVEL: Log level (debug, info, warn, error)
  • RUSTYHOOK_NO_COLOR: Disable colored output if set to any value

Exit Codes

  • 0: Success
  • 1: Hook failure
  • 2: Configuration error
  • 3: System error
  • 4: User error

Next Steps

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):

  1. Path specified by --config command-line option
  2. Path specified by RUSTYHOOK_CONFIG environment variable
  3. .rustyhook/config.yaml in the current directory
  4. .rustyhook/config.yml in the current directory
  5. .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:

PropertyRequiredDescription
idYesUnique identifier for the hook
languageYesLanguage runtime (python, node, ruby, system)
entryYesCommand to execute
filesNoRegex pattern for files to include
excludeNoRegex pattern for files to exclude
argsNoAdditional arguments to pass to the command
versionNoVersion requirement for the tool
pass_filenamesNoWhether to pass filenames to the command (default: true)
always_runNoRun even when no matching files are changed (default: false)
verboseNoShow verbose output for this hook (default: false)
stagesNoGit stages to run on (pre-commit, pre-push, etc.)
fail_fastNoStop execution on first failure (default: false)
envNoEnvironment variables to set
working_dirNoDirectory 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

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:

  1. Read your .pre-commit-config.yaml file
  2. Set up the necessary environments
  3. 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

  1. Repository References: RustyHook doesn't use the repos structure. Instead, it directly defines hooks with their language and version.

  2. Version Specification:

    • pre-commit uses Git revisions (rev)
    • RustyHook uses package version specifiers (version)
  3. Dependencies:

    • pre-commit uses additional_dependencies
    • RustyHook uses dependencies
  4. Entry Point:

    • pre-commit infers the entry point from the hook ID
    • RustyHook requires an explicit entry field
  5. File Patterns:

    • Both use similar regex patterns, but RustyHook always requires the files field if you want to filter by file type

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

  1. Missing Dependencies: If your pre-commit hooks had implicit dependencies, you might need to add them explicitly in RustyHook.

  2. Path Differences: RustyHook executes hooks from the Git root by default. Use working_dir if you need to change this.

  3. 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:

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 shell
  • zsh: For Zsh shell
  • fish: For Fish shell
  • powershell: 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:

  1. Make sure you've sourced your shell configuration file (.bashrc, .zshrc, etc.)
  2. Verify that the completion script was generated correctly
  3. Check that the completion script is in the correct location
  4. 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

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:

  1. Install RustyHook
  2. Initialize a configuration file:
    rh init
    
  3. Edit the .rustyhook/config.yaml file to configure your hooks
  4. 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?

  1. Make sure RustyHook is installed correctly (rh --version)
  2. Check that your configuration file is valid (rh doctor)
  3. Verify that Git hooks are installed (ls -la .git/hooks)
  4. 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.