Samoyed
A single-binary, minimalist, ultra-fast Git hooks manager for every platform.
Samoyed keeps Git hook management small, transparent, and safe. It ships as one Rust binary plus a POSIX wrapper script, so developers can install it quickly, version it with their repositories, and stay in control of what runs on commit.

Why Samoyed?
- Single binary — Zero runtime dependencies. One Rust executable embeds everything.
- Transparent — All code in one file (
src/main.rs). No hidden complexity. - Cross-platform — Works on Linux, macOS, and Windows (WSL). POSIX wrapper ensures consistency.
- Developer-friendly —
SAMOYED=0to bypass,SAMOYED=2to debug. Simple escape hatches when you need them. - 80% smaller — 0.2.x radically simplifies the code from 6000+ lines across 23 modules to ~1000 lines of code in one file.
Quick Start
Get started in under a minute:
# Install Samoyed
|
# Navigate to your Git repository
# Initialize hooks
# Edit the starter pre-commit hook
# Test it
Table of Contents
Install
Quick Install (Linux and macOS)
The fastest way to install Samoyed is with a single command:
|
This downloads the latest pre-built binary for your platform, verifies its checksum, and places it in ~/.local/bin. To customize the installation directory:
| INSTALL_DIR=/bin
If you prefer to inspect the installer before running it:
Using Cargo
If you have Rust installed, use cargo install:
Building from Source
Clone the repository and build locally:
Windows
Windows users should install via WSL (Windows Subsystem for Linux) and follow the Linux installation instructions above, or use cargo install samoyed in a native Windows terminal with the Rust toolchain installed.
Uninstalling
To remove Samoyed:
|
Or manually:
# Remove PATH entry from your shell config if added by the installer
Usage
Initialize Hooks
Inside your Git repository, run:
The samoyed-dirname defaults to .samoyed and must reside within the repository. On success, Samoyed creates:
.samoyed/
├── _/ # Hook wrappers (git-ignored)
│ ├── pre-commit
│ ├── commit-msg
│ ├── pre-push
│ ├── ... (all 14 hooks)
│ └── samoyed # POSIX wrapper script
├── pre-commit # Your editable hook (starter template)
└── .gitignore # Ignores the _/ directory
Git's core.hooksPath is configured to point to .samoyed/_/, routing all hook events through the wrapper.
Creating Your First Hook
The starter pre-commit script includes helpful comments. Edit it to add project-specific checks:
#!/bin/sh
# .samoyed/pre-commit
# Example: Format Rust code before commit
if ! ; then
fi
# Example: Run linter
# Example: Ensure tests pass
Make it executable and commit it to version control:
Now every commit will automatically run these checks.
Bypass and Debug Modes
Bypass all hooks when you need to commit without running checks:
SAMOYED=0
Enable debug mode to see exactly what the wrapper is doing:
SAMOYED=2
This runs the wrapper with set -x, printing each command as it executes.
Bypass during initialization to prepare hooks without activating them:
SAMOYED=0
Configuration
User Init Script
Samoyed sources an optional initialization script at ${XDG_CONFIG_HOME:-$HOME/.config}/samoyed/init.sh before running any hook. Use this for environment setup shared across all hooks:
# ~/.config/samoyed/init.sh
# Load secrets
# Set project defaults
# Skip hooks in CI (optional)
if [; then
fi
Per-Hook Customization
Because hooks are standard shell scripts, customize them directly in .samoyed/<hook>:
# .samoyed/pre-push - runs before git push
# Ensure main branch is never pushed directly
branch=
if [; then
fi
# Run full test suite before pushing
Background
Samoyed was built to strip Git hook tooling down to the essentials:
- One file of Rust code (
src/main.rs) manages CLI parsing, repository safety checks, and file generation. - One POSIX shell wrapper (
assets/samoyed) bootstraps every Git hook and keeps behaviour consistent across macOS, Linux, and Windows (via WSL or compatible shells). - Zero runtime dependencies. The compiled binary embeds the wrapper---
assets/samoyed---withinclude_bytes!, so distributing Samoyed is as simple as copying the executable.
In 0.2.x, Samoyed doubles down on clarity: the samoyed init command seeds every Git hook, wires them through the shared wrapper, and leaves a template pre-commit script ready for teams to adapt. Environment variables such as SAMOYED=0 (bypass) and SAMOYED=2 (debug) give developers predictable escape hatches without extra plugins.
This represents a fundamental architectural simplification from version 0.1.17, which scattered functionality across 23 separate Rust modules totaling nearly 6,000 lines of code. The current single-file implementation achieves the same functionality* in just about 1000 lines of code---an ~80% reduction in code size. By consolidating everything into src/main.rs, the codebase becomes dramatically easier to understand, debug, and maintain, while eliminating the cognitive overhead of navigating complex module hierarchies and cross-file dependencies.
*Support for samoyed.toml is removed in version 0.2.0. However I will re-introduce a well-thought-out option for configuring hooks "declaratively" in a future release.
Development
Clone the repository and work inside a Nix shell (nix develop) or your local Rust toolchain.
Core commands:
Integration tests live under tests/integration. Each script provisions a disposable repository via mktemp; run them individually, optionally preserving the workspace for inspection:
Maintainers
Contributing
Issues and pull requests are welcome. Before submitting a change, please ensure:
cargo fmt,cargo check, andcargo testpass locally.- Relevant integration scripts succeed.
- Commit messages follow Conventional Commit style (
feat:,fix:,chore:, …).