Skip to main content
📋How-To Guide

Set Up Quality Gates

Configure pre-commit hooks to enforce code quality automatically - regardless of your programming language.

The Universal Pattern​

Quality gates implement adversarial design:

AI commits (at user approval)
↓
Pre-commit hooks run
↓
Pass?
YES
↓
✅ Commit succeeds
NO
↓
🚫 Commit blocked
• Error message
• Remediation steps

Universal benefits:

  • ✅ Structural enforcement - Non-compliance blocks commits
  • ✅ Automatic verification - Tests actually run, not just claimed
  • ✅ Path of least resistance - Auto-fix makes compliance easy
  • ✅ Language-agnostic - Same pattern for Python, Go, Rust, JavaScript, etc.

Prerequisites​

  • Git repository initialized
  • Language-specific tools installed (see your language below)
  • prAxIs OS installed (optional, but recommended)

Installation (Universal)​

1. Install Pre-commit Framework​

All languages use the same framework:

pip install pre-commit

Why Python-based? Pre-commit framework is written in Python, but it manages hooks for ANY language. Think of it as a universal hook manager.

2. Install Git Hooks​

pre-commit install

This creates .git/hooks/pre-commit that runs your language-specific checks.

Output:

pre-commit installed at .git/hooks/pre-commit

Language-Specific Configuration​

Choose your language below. All follow the same pattern: Format → Lint → Type Check → Test.

Python Setup​

Tools: Black, isort, Pylint, MyPy, pytest

Install tools:

pip install black isort pylint mypy pytest

Create .pre-commit-config.yaml:

# Pre-commit hooks for Python projects
fail_fast: true

repos:
# Phase 1: Formatting (Auto-fix)
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
args: ['--line-length=88']

- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ['--profile=black']

# Phase 2: Linting
- repo: local
hooks:
- id: pylint
name: Pylint
entry: pylint
language: system
types: [python]
args: ['--fail-under=8.0']

# Phase 3: Type Checking
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
additional_dependencies: [types-all]

# Phase 4: Testing
- repo: local
hooks:
- id: pytest
name: pytest
entry: pytest
language: system
types: [python]
args: ['tests/', '-v']
pass_filenames: false
always_run: true

Optional: Create .pylintrc for configuration:

[MASTER]
fail-under=8.0

[FORMAT]
max-line-length=88

[MESSAGES CONTROL]
disable=
missing-docstring,
too-few-public-methods

Testing Your Setup​

Universal command (works for all languages):

# Run all hooks on all files
pre-commit run --all-files

Expected output:

Black....................................................................Passed
isort....................................................................Passed
Pylint..................................................................Passed
mypy.....................................................................Passed
pytest...................................................................Passed

If any checks fail:

  • ✅ Read the error message
  • ✅ Fix the issue in your code
  • ✅ Run pre-commit run --all-files again

Universal Pattern Explained​

Notice the pattern across ALL languages:

PhasePurposeExamples by Language
1. FormatAuto-fix styleBlack (Python), Prettier (JS), gofmt (Go), rustfmt (Rust)
2. LintCatch bugsPylint (Python), ESLint (JS), golangci-lint (Go), Clippy (Rust)
3. Type CheckType safetyMyPy (Python), TSC (TypeScript), go vet (Go), cargo check (Rust)
4. TestVerify correctnesspytest (Python), Jest (JS), go test (Go), cargo test (Rust)

Same philosophy, different tools. The adversarial design principle is universal.


Common Issues (Language-Independent)​

Hook Fails: "Command not found"​

Problem: Tool not installed.

Fix: Install language-specific tools (see your language tab above).


Quality Check Fails​

Philosophy: This is working as designed! The hook caught real issues before they entered your repository.

Fix:

  1. Read the error message carefully
  2. Fix the issue in your code
  3. Stage the fixed files: git add <files>
  4. Try commit again

Example:

# Pylint fails
Pylint..................................................................Failed
- hook id: pylint
- exit code: 1

your_file.py:10:0: C0114: Missing module docstring (missing-module-docstring)

# Fix: Add docstring to your_file.py
# Stage changes and commit again

Tests Fail on Commit​

Problem: Tests are actually broken.

Fix:

# Run tests locally to see details
pytest tests/ -v # Python
npm test # JavaScript
go test ./... # Go
cargo test # Rust

# Fix failing tests
# Stage changes and commit again

Philosophy: The hook saved you from committing broken code!


Bypass (Emergency Only)​

# Skip hooks (NOT RECOMMENDED)
git commit --no-verify

Warning: Use only if hooks are broken. This defeats the entire purpose of quality gates.


Advanced: Multi-Language Projects​

If your project uses multiple languages:

repos:
# Python
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
files: '\.py$'

# JavaScript
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v4.0.0-alpha.8
hooks:
- id: prettier
files: '\.(js|jsx|ts|tsx)$'

# Go
- repo: https://github.com/dnephin/pre-commit-golang
rev: v0.5.1
hooks:
- id: go-fmt
files: '\.go$'

Pattern: Same framework, different hooks based on file extensions.


CI/CD Integration​

Language-independent CI check:

# .github/workflows/quality.yml
name: Quality Gates

on: [push, pull_request]

jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install pre-commit
- run: pre-commit run --all-files

Works for any language because pre-commit manages language-specific tools.


Philosophy: Why This Pattern Works​

Read: Adversarial Design Philosophy

Core principle: Make non-compliance structurally impossible, not just discouraged.

Universal across languages:

  1. Assume gaming: AI will claim "tests pass" without running them
  2. Structural enforcement: Hooks actually run tests, block if failing
  3. Path of least resistance: Auto-fix makes compliance automatic
  4. Language-agnostic: Same pattern, different tools

Result: AI naturally does the right thing because it's the only path forward.



Next Steps​

  1. ✅ Choose your language tab above
  2. ✅ Install language-specific tools
  3. ✅ Create .pre-commit-config.yaml
  4. ✅ Run pre-commit install
  5. ✅ Test with pre-commit run --all-files
  6. ✅ Configure CI to run same checks

Result: Code quality enforced automatically, regardless of language.