Skip to main content

Python quality gate CLI for Ruff, Pyright, and pytest with bounded auto-repair and escalation artifacts

Project description

PyGate

Python CI failures are noisy, tool-specific, and expensive to triage when Ruff, Pyright, and pytest all disagree about what matters first.

PyGate turns those gate results into one deterministic Python quality gate with bounded auto-repair and structured escalation evidence for humans or agents.

  • "The PR failed, but I have to dig through Ruff, Pyright, and pytest separately to understand why."
  • "We want fail-fast Python CI, not another lint dashboard."
  • "Auto-fix should stop when it stops helping instead of thrashing the repo."
  • "If repair cannot finish the job, I want a clean escalation artifact instead of a pile of logs."
pip install pygate-ci
pygate summarize --input demo/artifacts/failures.json
{
  "brief_json_path": ".pygate/agent-brief.json",
  "brief_md_path": ".pygate/agent-brief.md",
  "status": "fail"
}

When To Use It

Use PyGate when you want one deterministic Python CI gate that can normalize Ruff, Pyright, and pytest output, attempt bounded deterministic repair, and escalate with machine-readable evidence when it cannot finish safely.

When Not To Use It

Do not use PyGate as a generic lint aggregator, a semantic code fixer, or a replacement for the underlying tools. It is a fail-fast gate-and-escalate wrapper around them.

pygate preview

License Python CI PyPI version

PyPI package: pygate-ci
CLI command: pygate


Table of Contents

Quick Start

# Prerequisites: ruff, pyright, and pytest must be available in your environment
pip install pygate-ci

# Run quality gates on changed files
echo "src/app.py" > changed.txt
pygate run --mode canary --changed-files changed.txt

# Generate agent brief from failures
pygate summarize --input .pygate/failures.json

# Attempt bounded repair
pygate repair --input .pygate/failures.json --max-attempts 3

Note: The PyPI package is pygate-ci but the CLI command is pygate.

What It Does

PyGate runs deterministic quality gates on your Python project and produces structured, machine-readable artifacts designed for both humans and AI agents.

Gates

Gate Tool Canary Full
lint ruff yes yes
typecheck pyright yes yes
test pytest configurable yes

How It Works

Changed Files ──> Run Gates ──> Findings? ──No──> Pass
                                    |
                                   Yes
                                    |
                                    v
                              Repair Loop ──> Improved? ──Fixed──> Pass
                                                  |
                                                  No
                                                  |
                                                  v
                                        Escalate with Evidence
  1. You tell PyGate which files changed (from your CI diff, PR, etc.)
  2. It runs lint, typecheck, and optionally tests
  3. Findings are normalized into a unified schema with severity, rule codes, and evidence
  4. The repair loop applies safe deterministic fixes (ruff --fix + format)
  5. If it can't fix everything, it escalates with structured evidence explaining why

Commands

pygate run --mode canary|full --changed-files <path>
pygate summarize --input .pygate/failures.json
pygate repair --input .pygate/failures.json [--max-attempts N]

Exit codes: 0 = pass, 1 = fail (run), 2 = escalated (repair)

Artifacts

All artifacts are written to .pygate/:

File Description
failures.json Structured findings with severity, rule codes, and evidence
run-metadata.json Gate execution traces (commands, stdout, stderr, durations)
agent-brief.json Priority actions and retry policy for AI agents
agent-brief.md Human-readable summary
repair-report.json Repair attempt history (on success)
escalation.json Escalation reason and evidence (on failure)

JSON Schema files for all artifact types are available in schemas/ for downstream validation and code generation. See demo/artifacts/ for sample output.

Repair Loop

The repair command runs a bounded deterministic repair loop:

  1. Backup workspace
  2. Fix via ruff check --fix + ruff format on scoped files
  3. Re-run gates to measure improvement
  4. Decide: pass (done), worsened (rollback), no improvement (escalate)

Policy Defaults

Parameter Default
Max attempts 3
Max patch lines 150
No-improvement abort 2 consecutive
Time cap 20 minutes

Escalation Codes

Code Meaning
NO_IMPROVEMENT 2+ consecutive attempts with no finding reduction
PATCH_BUDGET_EXCEEDED Edit exceeded line budget
UNKNOWN_BLOCKER Max attempts exhausted
UNRESOLVED_DETERMINISTIC_FAILURES Deterministic failures remain after repair
ARCHITECTURAL_CHANGE_REQUIRED Structural issues beyond repair scope (reserved)
FLAKY_EVALUATOR Gate produces inconsistent results (reserved)
ENVIRONMENT_DRIFT Python version or dependency mismatch (reserved)
TEST_FIXTURE_OR_EXTERNAL_DEP Tests depend on network, DB, or time (reserved)

Configuration

Configure via pygate.toml (standalone) or [tool.pygate] in pyproject.toml:

pygate.toml:

[policy]
max_attempts = 3
max_patch_lines = 150
abort_on_no_improvement = 2
time_cap_seconds = 1200

[commands]
lint = "ruff check --output-format json ."
typecheck = "pyright --outputjson ."
test = "pytest --json-report --json-report-file=.pygate/pytest-report.json -q"

[gates]
test_in_canary = false

Or in pyproject.toml:

[tool.pygate.policy]
max_attempts = 3

[tool.pygate.commands]
lint = "ruff check --output-format json ."

[tool.pygate.gates]
test_in_canary = false

GitHub Action

PyGate ships with a composite GitHub Action for CI integration:

- uses: actions/checkout@v4
- uses: roli-lpci/quick-gate-python/.github/actions/pygate@main
  with:
    mode: canary          # or "full"
    repair: "true"        # attempt auto-repair on failures
    max-attempts: 3
    python-version: "3.12"

The action detects changed files from the PR, runs gates, optionally repairs, and uploads .pygate/ artifacts. The post-comment feature requires pull-requests: write permission in your workflow.

Limitations

  • Deterministic repair only (v1): The repair loop uses ruff --fix and ruff format. It cannot fix type errors, failing tests, or issues requiring semantic understanding.
  • No incremental analysis: All specified gates run on every invocation. There is no caching or incremental mode.
  • Tool availability: PyGate requires ruff, pyright, and pytest to be installed in the target environment. It does not install them.
  • Single-repo scope: Designed for single Python projects, not monorepos with multiple packages.

Roadmap

  • Model-assisted repair (LLM-powered fixes for type errors and test failures)
  • Coverage gate (fail on coverage drops)
  • Security gate (bandit / safety integration)
  • Incremental mode (only re-run gates on changed files)
  • PyPI trusted publishing via GitHub Actions
  • Plugin system for custom gates

Contributing

See CONTRIBUTING.md for development setup and guidelines.

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygate_ci-0.1.2.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygate_ci-0.1.2-py3-none-any.whl (26.5 kB view details)

Uploaded Python 3

File details

Details for the file pygate_ci-0.1.2.tar.gz.

File metadata

  • Download URL: pygate_ci-0.1.2.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pygate_ci-0.1.2.tar.gz
Algorithm Hash digest
SHA256 10b9a61ae17a0857faddfe858d9b9b7b0e4b1d5a889c055eff77cd64b8708807
MD5 e8034ba2be3a7148ea51b06bfce099b3
BLAKE2b-256 b8b4c9eab75e50755293d26ec8ce944b6dfc35c3a6f075aacf0065b14b9377fd

See more details on using hashes here.

File details

Details for the file pygate_ci-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: pygate_ci-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 26.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pygate_ci-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1e17e191997795696bfcd98e4c97d90305e1a6d31a70c0c29e15e214ef40eda8
MD5 5b8817e858a758bc7ba5cc5638258af1
BLAKE2b-256 59647d72275a9f1bddb3d91cb55e62f6996af70e3a3ef219ea296880dbe7a7d5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page