Samoyed
A modern, fast, and secure Git hooks manager written in Rust. Samoyed is inspired by Husky with improved performance, better error handling, and enhanced security features.
You don’t have to fuss with that pesky package.json file in your projects anymore! 🤌

Test Coverage
Features
- 🚀 Fast: Built with Rust for optimal performance
- 🔒 Secure: Comprehensive path validation and security checks
- 🛡️ Robust: Detailed error handling with actionable suggestions
- 🧪 Well-tested: Comprehensive test coverage with extensive integration tests
- 🌍 Cross-platform: Supports Linux, macOS, and Windows
- 📦 Minimal dependencies: Small set of essential Rust dependencies
Installation
Samoyed is published on crates.io:
Quick Start
Initialize Git hooks in your repository:
This will:
- Configure Git to use
.samoyed/_as the hooks directory - Create the hooks directory structure
- Install hook files that delegate to the
samoyed-hookrunner
Usage
Basic Commands
# Initialize hooks (one-time setup)
# Install hooks with custom directory
Environment Variables
SAMOYED=0- Skip hook installation entirelySAMOYED_DEBUG=1- Enable debug logging
Architecture
Samoyed uses a three-layer architecture that provides both flexibility and performance:
Binary Components
samoyed: CLI interface for initialization and managementsamoyed-hook: Lightweight hook runner executed by Git
Execution Flow
sequenceDiagram
participant Git as Git
participant Hook as .samoyed/_/pre-commit
participant Runner as samoyed-hook
participant Config as samoyed.toml
participant Script as .samoyed/scripts/pre-commit
participant Shell as Shell
Git->>Hook: git commit triggers
Hook->>Runner: exec samoyed-hook "pre-commit" "$@"
Runner->>Config: 1. Check for [hooks] pre-commit
alt Command found in samoyed.toml
Config-->>Runner: "cargo fmt --check && cargo clippy"
Runner->>Shell: Execute command via shell
Shell-->>Runner: Exit code
else No command in samoyed.toml
Runner->>Script: 2. Look for .samoyed/scripts/pre-commit
alt Script exists
Runner->>Script: Execute script file
Script-->>Runner: Exit code
else No script found
Runner-->>Git: Exit silently (0)
end
end
Runner-->>Git: Propagate exit code
Directory Structure
When you run samoyed init, three key components are created:
1. samoyed.toml - Primary Configuration
Raison d'être: The primary configuration mechanism where you define commands for each hook.
[]
= "cargo fmt --check && cargo clippy -- -D warnings"
= "cargo test --release"
2. .samoyed/_/ - Git Hook Delegation Layer
Raison d'être: Git integration. These files tell Git "when you want to run a hook, call samoyed-hook instead."
All files contain identical delegation code:
#!/usr/bin/env sh
Git's core.hooksPath=.samoyed/_ points here, so git commit → .samoyed/_/pre-commit → samoyed-hook.
3. .samoyed/scripts/ - Fallback & Examples
Raison d'être: Fallback mechanism for complex scenarios and examples for users who prefer script files.
Two-Tier Lookup System
The hook runner implements a sophisticated two-tier lookup:
- Primary: Check
samoyed.tomlfor a command string - Fallback: Look for executable script in
.samoyed/scripts/
This provides maximum flexibility:
- Simple cases: Use TOML configuration for straightforward commands
- Complex cases: Use full script files for multi-line logic or complex workflows
Environment Variables
SAMOYED=0- Skip all hook execution (useful for CI/deployment)SAMOYED=1- Normal execution mode (default)SAMOYED=2- Enable debug mode with detailed script tracing
Performance Design
This architecture ensures minimal overhead:
- Git only spawns one process:
samoyed-hook - No file system scanning during execution
- Direct command execution via shell when possible
- Graceful fallback with silent exit when no hooks are defined
Development
Prerequisites
- Rust 1.85+ (Rust 2024 edition)
- Git
Building
# Build debug version
# Build release version
# Run tests
# Run benchmarks
Testing
The project uses comprehensive testing with dependency injection:
# Run all tests
# Run specific test categories
# Run platform-specific tests
Code Coverage
Generate coverage reports:
Tarpaulin is configured in .tarpaulin.toml to store reports in <target/tarpaulin/coverage/>.
Contributing
- Let's discuss
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Inspired by Husky
- Built with 🤟 🫡 in Rust