Declarative quality gate loops for AI-assisted development
Project description
pyqual
AI Cost Tracking
- ๐ค LLM usage: $1.0500 (7 commits)
- ๐ค Human dev: ~$500 (5.0h @ $100/h, 30min dedup)
Generated on 2026-03-29 using openrouter/qwen/qwen3-coder-next
Declarative quality gate loops for AI-assisted development.
One YAML file. One command. Pipeline iterates until your code meets quality thresholds.
pip install pyqual
pyqual init
pyqual run
The problem
You use Copilot, Claude, GPT. They generate code. But nobody checks if that code meets your quality standards before it hits code review. And nobody automatically iterates if it doesn't.
pyqual closes that gap: define metrics โ run tools โ check gates โ if fail, LLM fixes โ re-check โ repeat until pass.
How it works
pyqual.yaml defines everything:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ metrics: โ
โ cc_max: 15 โ quality gates โ
โ vallm_pass_min: 90 โ
โ coverage_min: 80 โ
โ โ
โ stages: โ
โ - analyze (code2llm) โ
โ - validate (vallm) โ
โ - fix (llx/aider, when: fail) โ
โ - test (pytest) โ
โ โ
โ loop: โ
โ max_iterations: 3 โ
โ on_fail: report โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pyqual run:
Iteration 1 โ analyze โ validate โ fix โ test โ check gates
โ
โโโ PASS โโโดโโ FAIL โโโ
โ โ
Done โ
Iteration 2...
pyqual.yaml
pipeline:
name: quality-loop
metrics:
cc_max: 15 # cyclomatic complexity per function
vallm_pass_min: 90 # vallm validation pass rate (%)
coverage_min: 80 # test coverage (%)
stages:
- name: analyze
run: code2llm ./ -f toon,evolution
- name: validate
run: vallm batch ./ --recursive --errors-json > .pyqual/errors.json
- name: fix
run: echo "Connect your LLM fixer here"
when: metrics_fail # only runs if gates fail
- name: test
run: pytest --cov --cov-report=json:.pyqual/coverage.json
loop:
max_iterations: 3
on_fail: report # report | create_ticket | block
CLI
pyqual init # create pyqual.yaml
pyqual run # execute full loop
pyqual run --dry-run # preview without executing
pyqual gates # check gates without running stages
pyqual status # show current metrics
pyqual doctor # check tool availability
pyqual mcp-fix # run the llx-backed MCP fix workflow
pyqual mcp-refactor # run the llx-backed MCP refactor workflow
pyqual mcp-service # start the persistent llx MCP service
pyqual tickets todo # sync TODO.md through planfile
pyqual tickets github # sync GitHub issues through planfile
pyqual tickets all # sync TODO.md and GitHub tickets
# Plugin management
pyqual plugin list # list all plugins
pyqual plugin list --tag security # filter by tag
pyqual plugin search <query> # search plugins
pyqual plugin info <name> # show plugin details
pyqual plugin add <name> # add plugin to config
pyqual plugin remove <name> # remove plugin from config
pyqual plugin validate # validate configuration
Python API
from pyqual import Pipeline, PyqualConfig
config = PyqualConfig.load("pyqual.yaml")
pipeline = Pipeline(config, workdir="./my-project")
result = pipeline.run()
if result.final_passed:
print(f"All gates passed in {result.iteration_count} iterations")
else:
print("Gates not met โ check result.iterations for details")
LLM Integration
pyqual includes built-in LLM support via liteLLM. Configure via .env:
The convenience wrapper now lives upstream in llx.llm; pyqual re-exports it so existing imports keep working.
OPENROUTER_API_KEY=sk-or-v1-...
LLM_MODEL=openrouter/qwen/qwen3-coder-next
Use in your code:
from pyqual import get_llm
llm = get_llm() # Auto-loads config from .env
# Simple completion
response = llm.complete("Explain Python decorators")
print(response.content)
# Fix code issues
response = llm.fix_code(
code="def foo(x): return x + 1", # missing type hints
error="Function lacks type annotations"
)
print(response.content)
# Access cost info
print(f"Cost: ${response.cost:.4f}")
Docker-backed MCP fixer/refactor
If you want pyqual to delegate automatic fixes or refactors to a Dockerized llx MCP service:
The MCP client, service, workflow orchestration (LlxMcpRunResult, run_llx_fix_workflow,
run_llx_refactor_workflow), issue parsing and prompt building all live in the upstream
llx package (โฅ 0.1.47). pyqual re-exports them for backward compatibility.
Install pyqual[llx] or pyqual[mcp] so those shared helpers are available.
docker compose -f examples/llm_fix/docker-compose.yml up --build -d
pyqual plugin add llx-mcp-fixer
pyqual run
The plugin writes results to .pyqual/llx_mcp.json, which is also collected by pyqual status and can be gated with llx_fix_* metrics.
If you only want to run the workflows directly, use:
pyqual mcp-fix --workdir . --project-path /workspace/project
pyqual mcp-refactor --workdir . --project-path /workspace/project
If you want to run the service standalone in development, use:
pyqual mcp-service --host 0.0.0.0 --port 8000
See examples/llm_fix/ for complete examples.
Metric sources
pyqual automatically collects metrics from:
| Source | File | Metrics |
|---|---|---|
| Analysis | analysis_toon.yaml |
cc (CCฬ), critical |
| Validation | validation_toon.yaml |
vallm_pass |
.pyqual/errors.json |
error_count |
|
| Coverage | .pyqual/coverage.json |
coverage |
| Performance | .pyqual/asv.json |
bench_regression, bench_time |
.pyqual/mem.json |
mem_usage, cpu_time |
|
| Security | .pyqual/secrets.json |
secrets_severity, secrets_count |
.pyqual/vulns.json |
vuln_critical, vuln_count |
|
.pyqual/sbom.json |
sbom_compliance, license_blacklist |
|
| Project Health | .pyqual/vulture.json |
unused_count |
.pyqual/pyroma.json |
pyroma_score |
|
.pyqual/git_metrics.json |
git_branch_age, todo_count |
|
| LLM/AI | .pyqual/humaneval.json |
llm_pass_rate |
.pyqual/llm_analysis.json |
llm_cc, hallucination_rate, prompt_bias_score, agent_efficiency |
|
.pyqual/llx_mcp.json |
llx_fix_success, llx_fix_returncode, llx_tool_calls, llx_fix_tier_rank |
|
.pyqual/costs.json |
ai_cost |
|
| Linting | .pyqual/ruff.json |
ruff_errors, ruff_fatal, ruff_warnings |
.pyqual/pylint.json |
pylint_errors, pylint_fatal, pylint_error, pylint_warnings, pylint_score |
|
.pyqual/flake8.json |
flake8_violations, flake8_errors, flake8_warnings, flake8_conventions |
|
| Documentation | .pyqual/interrogate.json |
docstring_coverage, docstring_total, docstring_missing |
Custom metrics: extend GateSet._collect_metrics() or add your own collector.
Gate operators
metrics:
cc_max: 15 # cc โค 15
coverage_min: 80 # coverage โฅ 80
critical_max: 0 # critical โค 0
error_count_max: 5 # error_count โค 5
vallm_pass_min: 90 # vallm_pass โฅ 90
Suffixes: _max โ โค, _min โ โฅ, _lt โ <, _gt โ >, _eq โ =
Integration with ecosystem
pyqual is intentionally small (~800 lines). It orchestrates, not implements:
- code2llm does analysis โ pyqual reads the
.toonoutput - vallm does validation โ pyqual reads pass rates
- llx does LLM routing, MCP workflows, issue parsing โ pyqual calls it as a stage (requires Python โฅ 3.10)
- planfile manages tickets โ pyqual syncs TODO.md and GitHub tickets through planfile
- costs tracks spending โ pyqual can gate on budget
- algitex can import pyqual as a dependency for its
gocommand
Examples
See examples/ directory for real-world configurations:
Project setups:
python-packageโ Standard Python package (src-layout)python-flatโ Simple project without src/monorepoโ Multiple packages in one repository
CI/CD:
github-actionsโ CI/CD with GitHub Actionsgitlab-ciโ CI/CD with GitLab CI
Python API usage:
basicโ Using Pipeline and GateSet from Pythonllm_fixโ LLM integration for auto-fixing codecustom_gatesโ Custom quality gates and metrics
Why not add this to algitex?
algitex has 29,448 lines, CCฬ=3.6, 64 critical issues, vallm pass 42.8%. Adding more features makes it worse. pyqual does one thing well: declarative quality gate loops. algitex imports pyqual. Both improve.
License
Licensed under Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyqual-0.1.36.tar.gz.
File metadata
- Download URL: pyqual-0.1.36.tar.gz
- Upload date:
- Size: 621.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d80414e8945e102f4b7002ac8f58a08b638aaf59616b3c65893a771cc97debff
|
|
| MD5 |
864b1a5a6120bee8bcfb69cc80b0a361
|
|
| BLAKE2b-256 |
8f89afc907c85a43e2622744a9dc833a948bf4f95133cc93c0581960c10d5326
|
File details
Details for the file pyqual-0.1.36-py3-none-any.whl.
File metadata
- Download URL: pyqual-0.1.36-py3-none-any.whl
- Upload date:
- Size: 42.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b39ce6598ed8aeb48780e8bfe66012302a7200da35ad5bd1938e53ddcd0afdcb
|
|
| MD5 |
f311e9eabf80e36ffea3a3bc62242e97
|
|
| BLAKE2b-256 |
4dd77da2f7908cb1b0fc830e4e4679432e7af95afb3edf12972c1c937cc98951
|