Language-agnostic code quality control tool with Git hooks
A code quality control tool built in Go, distributed as a single binary with no external runtime dependencies. Provides enhanced visual feedback with spinners, execution timing, and structured JSON output.
- ποΈ Single Binary: Zero runtime dependencies (Python, Node.js)
- π§ Automatic Setup: Installs quality tools automatically
- π Multi-language: Supports multiple languages in the same repository
- π Observability: Spinners, timing, and real-time visual feedback
- π Built-in Security: Secret scanning plus Python dependency vulnerability audit (pip-audit) in commit/push workflow
- β‘ Native Performance: Instant execution without interpreters
- π CI/CD Ready: Clean JSON output for automation pipelines
- π€ MCP Server: Model Context Protocol support for AI coding agents (Claude, Cursor, etc.)
π New here? The Usage Guide walks through setup and the daily commit flow in a few minutes.
# Download the latest release for your platform
# Linux (x64)
wget https://github.com/dmux/go-quality-gate/releases/latest/download/quality-gate-linux-amd64
chmod +x quality-gate-linux-amd64
sudo mv quality-gate-linux-amd64 /usr/local/bin/quality-gate
# Linux (ARM64)
wget https://github.com/dmux/go-quality-gate/releases/latest/download/quality-gate-linux-arm64
chmod +x quality-gate-linux-arm64
sudo mv quality-gate-linux-arm64 /usr/local/bin/quality-gate
# macOS (Intel)
wget https://github.com/dmux/go-quality-gate/releases/latest/download/quality-gate-darwin-amd64
chmod +x quality-gate-darwin-amd64
sudo mv quality-gate-darwin-amd64 /usr/local/bin/quality-gate
# macOS (Apple Silicon)
wget https://github.com/dmux/go-quality-gate/releases/latest/download/quality-gate-darwin-arm64
chmod +x quality-gate-darwin-arm64
sudo mv quality-gate-darwin-arm64 /usr/local/bin/quality-gate
# Windows (download .exe from releases page)
# https://github.com/dmux/go-quality-gate/releases/latestgo install github.com/dmux/go-quality-gate/cmd/quality-gate@latestTo upgrade later, run quality-gate --update, which runs the same go install ...@latest and prints the version it moved to.
# Run directly with Docker
docker run --rm ghcr.io/dmux/go-quality-gate:latest --version
# Create alias for easier usage
echo 'alias quality-gate="docker run --rm -v $(pwd):/workspace -w /workspace ghcr.io/dmux/go-quality-gate:latest"' >> ~/.bashrc
source ~/.bashrc# Clone and build
git clone https://github.com/dmux/go-quality-gate.git
cd go-quality-gate
make build
# Install hooks in your project
./quality-gate --installCreate a quality.yml in your project:
# Generate initial configuration based on your project
./quality-gate --init# Automatic execution via Git hooks
git commit -m "feat: new feature"
# Manual execution
./quality-gate pre-commit
# JSON output for CI/CD
./quality-gate --output=json pre-commit
# Auto-fix
./quality-gate --fix pre-commit
# Run as Model Context Protocol (MCP) Server for AI Agents
./quality-gate mcptools:
- name: "Gitleaks"
check_command: "gitleaks version"
install_command: "go install github.com/zricethezav/gitleaks/v8@latest"
- name: "Ruff (Python)"
check_command: "ruff --version"
install_command: "pip install ruff"
- name: "Pip-Audit (Python Dependency Audit)"
check_command: "pip-audit --version"
install_command: "pip install pip-audit"
hooks:
security:
pre-commit:
- name: "π Security Check"
command: "gitleaks detect --no-git --source . --verbose"
output_rules:
on_failure_message: "Secret leak detected!"
python-backend:
pre-commit:
- name: "π¨ Format Check (Ruff)"
command: "ruff format ./backend --check"
fix_command: "ruff format ./backend"
output_rules:
show_on: failure
on_failure_message: "Run './quality-gate --fix' to format."
- name: "π‘οΈ Dependency Audit (pip-audit)"
command: "pip-audit -r requirements.txt --aliases"
fix_command: "pip-audit --fix -r requirements.txt"
output_rules:
show_on: failure
on_failure_message: "Vulnerable dependencies found! Run './quality-gate --fix' or upgrade manually."
pre-push:
- name: "π‘οΈ Dependency Audit (pip-audit)"
command: "pip-audit -r requirements.txt --aliases"
fix_command: "pip-audit --fix -r requirements.txt"
output_rules:
show_on: failure
on_failure_message: "Vulnerable dependencies found! Run './quality-gate --fix' or upgrade manually."
typescript-frontend:
pre-commit:
- name: "π¨ Format Check (Prettier)"
command: "npx prettier --check 'frontend/**/*.{ts,tsx}'"
fix_command: "npx prettier --write 'frontend/**/*.{ts,tsx}'"The
pip-auditdependency audit runs on bothpre-commitandpre-pushand needs network access (PyPI/OSV). Committing offline? Skip the gate withQG_SKIP="offline" git commit β¦or drop the audit commands from yourquality.yml.
go build -o quality-gate ./cmd/quality-gateThis will create an executable named quality-gate in the current directory.
./quality-gate --installThe program will automatically configure pre-commit and pre-push hooks.
./quality-gate --init: (Experimental) Analyzes your project structure and generates an initialquality.ymlfile with suggestions./quality-gate --fix: Executes automatic fix commands (fix_command) defined in yourquality.yml./quality-gate pre-commit --output=json: Executes the specified hook and returns the result in JSON format
The configuration is divided into two main sections:
-
tools: List of tools required for the projectname: Human-readable tool namecheck_command: Command that returns success (exit code 0) if the tool is installedinstall_command: Command executed to install the tool ifcheck_commandfails
-
hooks: Quality check configuration
On the first pre-commit or pre-push execution, Quality Gate runs each
configured check_command and installs any missing tool with its
install_command. After every tool has been successfully validated, it stores
a SHA-256 hash of the tools configuration in:
.git/quality-gate/tools.sha256
Subsequent executions skip the installation checks while the configuration is
unchanged. Changing a tool's name, check_command, or install_command, as
well as adding, removing, or reordering tools, invalidates the cache and causes
all tools to be validated again.
The cache is only updated after a successful validation. If it is missing, outdated, unreadable, or cannot be written, Quality Gate falls back to checking the tools normally without blocking the configured hooks. To force a new validationβfor example, after manually uninstalling a toolβdelete the cache file before running a hook:
rm .git/quality-gate/tools.sha256tools:
- name: "Gitleaks"
check_command: "gitleaks version"
install_command: "go install github.com/zricethezav/gitleaks/v8@latest"
- name: "Ruff (Python Linter/Formatter)"
check_command: "ruff --version"
install_command: "pip install ruff"
- name: "Pip-Audit (Python Dependency Audit)"
check_command: "pip-audit --version"
install_command: "pip install pip-audit"
- name: "Prettier (Code Formatter)"
check_command: "npx prettier --version"
install_command: "npm install --global prettier"
hooks:
security:
pre-commit:
- name: "π Security Check (Gitleaks)"
command: "gitleaks detect --no-git --source . --verbose"
output_rules:
on_failure_message: "Secret leak detected! Review code before committing."
python-backend:
pre-commit:
- name: "π¨ Format Check (Ruff)"
command: "ruff format ./backend --check"
fix_command: "ruff format ./backend"
output_rules:
show_on: failure
on_failure_message: "Code formatting issue. Run './quality-gate --fix' to fix."
- name: "π§ͺ Tests (Pytest)"
command: "pytest ./backend"
output_rules:
show_on: always
- name: "π‘οΈ Dependency Audit (pip-audit)"
command: "pip-audit -r requirements.txt --aliases"
fix_command: "pip-audit --fix -r requirements.txt"
output_rules:
show_on: failure
on_failure_message: "Vulnerable dependencies found! Run './quality-gate --fix' or upgrade manually."
pre-push:
- name: "π‘οΈ Dependency Audit (pip-audit)"
command: "pip-audit -r requirements.txt --aliases"
fix_command: "pip-audit --fix -r requirements.txt"
output_rules:
show_on: failure
on_failure_message: "Vulnerable dependencies found! Run './quality-gate --fix' or upgrade manually."
typescript-frontend:
pre-commit:
- name: "π¨ Format Check (Prettier)"
command: "npx prettier --check 'frontend/**/*.{ts,tsx}'"
fix_command: "npx prettier --write 'frontend/**/*.{ts,tsx}'"With
--parallel, the threepre-commithooks above (Gitleaks, Ruff format check, Pytest) run concurrently instead of one after another β useful here since Pytest can be the slow one. Run with:./quality-gate --parallel pre-commit
| Command | Description | Example |
|---|---|---|
--install |
Installs Git hooks in repository | ./quality-gate --install |
--init |
Generates initial quality.yml with intelligent analysis | ./quality-gate --init |
--fix |
Executes automatic fixes | ./quality-gate --fix pre-commit |
--install --global |
Gates every repository of the user (global core.hooksPath) |
./quality-gate --install --global |
verify |
Verifies commit watermarks (for CI) | ./quality-gate verify --range origin/main..HEAD |
doctor |
Checks hooks, binary and quality.yml are in place | ./quality-gate doctor |
mcp |
Runs as an MCP server for AI integration | ./quality-gate mcp |
--version, -v |
Shows version information | ./quality-gate --version |
--update |
Updates quality-gate to the latest version (via Go) | ./quality-gate --update |
--output=json |
Structured output for CI/CD | ./quality-gate --output=json pre-commit |
--parallel |
Runs independent hooks concurrently (opt-in) | ./quality-gate --parallel pre-commit |
# Simple version
./quality-gate --version
# Output: quality-gate version 1.4.0
# JSON version with build details
./quality-gate --version --output json
# Output:
{
"version": "1.4.0",
"build_date": "2025-10-21T16:34:44Z",
"git_commit": "f7b01a2"
}Client-side hooks can always be bypassed (git commit --no-verify, deleting the hook). quality-gate therefore works in two layers:
1. Watermark on the client. When every pre-commit check passes, quality-gate records an attestation bound to the exact staged content (git write-tree). The commit-msg hook then appends a trailer:
feat: add login
Quality-Gate: v1.4.0; tree=db228f6dβ¦; config=sha256:4feac6c2β¦; checks=3/3
--no-verifyskips both hooks, so the commit has no trailer.- Amending or rebasing without re-running the checks changes the tree, so the trailer no longer matches.
- Need to bypass on purpose?
QG_SKIP="prod hotfix" git commit β¦skips the checks but recordsQuality-Gate-Skipped: prod hotfixfor auditing.
2. Enforcement on the server. quality-gate verify checks every commit of a range and fails on missing, stale or malformed watermarks:
quality-gate verify --range origin/main..HEAD # strict
quality-gate verify --range origin/main..HEAD --policy allow-skip # accept QG_SKIP commits
quality-gate verify --range origin/main..HEAD --output jsonUse the bundled GitHub Action, then mark the job as a required status check in the branch protection / ruleset of main:
name: Quality Gate
on: pull_request
jobs:
quality-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dmux/go-quality-gate@main
with:
policy: strict # or allow-skip
run-checks: "true" # re-run the checks, so a hand-written trailer cannot passThe client watermark stops casual bypasses; it is not a cryptographic proof, since anyone can type a trailer. The required CI check, which also re-runs the gates, is what makes the gate mandatory. Squash merges create a new commit without a trailer, so verify the pull request commits, not the merge commit.
Committing step by step
quality-gate --install # once per repository (installs pre-commit, commit-msg, pre-push)
quality-gate doctor # confirm binary, hooks and quality.yml are in place
git add .
git commit -m "feat: add login"pre-commitruns the checks. A failure blocks the commit; on success the staged tree andquality.ymlhashes are stored.- You write the message.
commit-msgconfirms nothing changed and appends theQuality-Gate:trailer (π Commit watermarked by quality-gate.).- The commit is created. Check it with
git log -1 --format='%(trailers)'orquality-gate verify --range HEAD.
| Situation | Result |
|---|---|
git commit --no-verify |
No trailer β missing in CI |
QG_SKIP="reason" git commit |
Quality-Gate-Skipped: reason β accepted only with --policy allow-skip |
--amend / rebase that changes content without the hooks |
Old trailer no longer matches β tree-mismatch |
| Staged content changed between checks and message | No trailer, with a warning β commit again |
| Commit through the MCP server | Watermarked as well |
The commit-msg hook never blocks a commit; enforcement happens in CI.
Making installation automatic
quality-gate --install --globalsets a globalcore.hooksPathwhose hooks act only in repositories that contain aquality.yml(and still run repository-local hooks). It can be distributed to every machine by IT/MDM.- Add
quality-gate --installto the project bootstrap ("prepare"script inpackage.json,make setup, etc.). quality-gate doctorreports missing or tampered hooks.- The MCP server records the attestation too, so commits made by AI agents are watermarked.
{
"status": "success",
"results": [
{
"hook": {
"Name": "π Security Check",
"Command": "gitleaks detect --source ."
},
"success": true,
"output": "",
"duration_ms": 150,
"duration": "150ms"
}
]
}Go Quality Gate can act as an MCP server, providing standard AI coding agents (like Claude Desktop, Cursor, or Cline) with the ability to interact with your codebase's quality tools natively.
To use go-quality-gate with Cursor or Claude, simply configure the MCP server to run via standard I/O (stdio). For Cursor, create or update .mcp.json in your workspace:
{
"mcpServers": {
"go-quality-gate": {
"command": "./quality-gate",
"args": ["mcp"]
}
}
}The server exposes the following MCP Tools to your AI:
run_quality_checks: Executes linters and formatting checks, returning a parsed diagnostic for the AI.run_auto_fix: Allows the AI to automatically trigger the formatting fixes configured inquality.yml.
- Go 1.18+
- Git
- Package managers for your project languages (pip, npm, etc.)
# Clone the repository
git clone <repo>
cd go-quality-gate
# Install dependencies
go mod tidy
# Build
go build -o quality-gate ./cmd/quality-gate
# Run tests
go test ./...
# Test locally
./quality-gate --init
./quality-gate --installcmd/quality-gate/ # Main application
internal/
domain/ # Entities and business rules
service/ # Application logic
infra/ # Infrastructure (git, shell, logger)
repository/ # Persistence interfaces
config/ # Configuration and parsing
- Fork the project
- Create a branch:
git checkout -b feature/new-feature - Commit your changes:
git commit -m 'feat: new feature' - Push to the branch:
git push origin feature/new-feature - Open a Pull Request
See TODO.md for detailed roadmap and available tasks.
This project is under the MIT license. See the LICENSE file for more details.
Version: v1.1.x
Status: Active development
Complete documentation: TODO.md
