PyQA is Blackcat Informatics Inc.'s opinionated quality-assurance harness. It ships as the pyqa_lint package (install via pip install pyqa_lint) and can also be vendored as a git submodule so teams can run the Typer-based CLI (pyqa) with zero external dependencies.
TL;DR: Deterministic lint orchestration, SOLID-aware reporting, curated tool catalogs, and provenance-backed releases for modern Python repositories.
- Getting Started
- CLI Overview
- Feature Highlights
- Architecture & Docs
- Releases & Provenance
- Configuration & Tooling Schema
- Advanced Capabilities
- Contributing & Support
- Why PyQA?
- Installation Options
- Getting Started
- CLI Overview
- Feature Highlights
- Architecture & Docs
- Releases & Provenance
- Configuration & Tooling Schema
- Advanced Capabilities
- Contributing & Support
- License
- Curated multi-language linting powered by ruff, pylint, bandit, mypy, pyright, sqlfluff, yamllint, and more.
- Polyglot coverage across Python, JavaScript/TypeScript, Go, Rust, SQL, YAML, TOML, Markdown, Dockerfiles, Bash, and Lua via the built-in catalog.
- Deterministic environments built with
uv, with optional system-tool reuse when explicitly allowed. - Explainable orchestration via
--explain-toolsand--explain-tools-json, so contributors see why tools ran or skipped. - SOLID advice + refactor navigator driven by tree-sitter and spaCy to highlight structural issues, hotspots, and symbols.
- First-class reporting to Markdown, SARIF 2.1.0, JSON, and PR summaries, plus machine-readable tool catalogs.
- Interface-first design: runtime modules consume Protocols from
pyqa.interfaces.*, keeping extensions pluggable and testable.
PyQA's catalog bundles analyzers, formatters, and value-type rules for multiple ecosystems. Highlights include:
- Python – ruff, pylint, bandit, mypy, pyright, pytest helpers, value-type analysis.
- JavaScript / TypeScript – eslint, prettier, tsc, markdownlint cross-checks for front-end code.
- Go – golangci-lint, gofmt, module tidy helpers.
- Rust – clippy, cargo fmt, cargo check integrations.
- Shell & Containers – shellcheck, shfmt, hadolint, dockerfilelint.
- Data & Config – sqlfluff (SQL), yamllint (YAML), taplo (TOML), markdownlint/mdformat (Markdown), terraformer rules.
- Scripting & DSLs – luacheck (Lua), phpcs (PHP), generic tree-sitter hooks for custom DSLs.
Refer to tooling/catalog/ for the authoritative list and metadata for each tool.
pip install pyqa_lint
# exposes the `pyqa` CLI globallygit submodule add https://github.com/paudley/pyqa_lint.git pyqa-lintThis layout keeps the managed scripts (lint, check-quality, security-scan, install, install-hooks, etc.) inside your repository without publishing a wheel.
Clone the repo and sync the toolchain:
uv sync --group devThe shims in the repo root (./lint, ./check-quality, ./install, ./security-scan) automatically target the synced .venv.
git submodule add https://github.com/paudley/pyqa_lint.git pyqa-lintcd pyqa-lint && uv sync --group dev./install-hooksto wirepre-commit,pre-push, andcommit-msg./lint(orpyqa lint) to run the curated pipeline
Hooks and CI both execute pyqa check-quality + pyqa lint, so the same guardrails apply everywhere.
| Command | How to run | Summary |
|---|---|---|
lint |
pyqa lint or ./lint |
Runs the orchestrated lint/test pipeline, explain mode, exporters, and cache management. |
check-quality |
pyqa check-quality or ./check-quality |
Enforces SPDX headers, notices, schema freshness, file-size limits, and repo guardrails. |
security-scan |
pyqa security-scan or ./security-scan |
Performs secret scanning plus Bandit/semgrep-style analyzers. |
install |
pyqa install or ./install |
Installs the managed toolchain into the current project (legacy shell workflow parity). |
install-hooks |
pyqa install-hooks or ./install-hooks |
Symlinks vetted Git hooks that call pyqa check-quality. |
config ... |
pyqa config <subcommand> |
Show/diff/validate layered configuration, export tool schemas, inspect explainable plans. |
update |
pyqa update or ./update-packages |
Refresh pinned dependencies across Python/Node/Go/Rust workspaces. |
sparkly-clean |
./sparkly-clean |
Remove caches and artefacts without touching tracked files. |
Run pyqa --help or pyqa <command> --help for detailed options.
- Explainable selection:
pyqa lint --explain-tools [--json]renders the tool order, reasons, eligibility, and registry descriptions. Tests assert table + JSON output so UX changes stay stable. - SOLID advice + highlighting:
--adviceadds the SOLID panel, Refactor Navigator stats, and tree-sitter/spaCy highlighting. Exporters can embed the same data viapyqa.reporting.emitters.write_pr_summary(include_advice=True). - Value-type analysis: opt into
[tool.pyqa.generic_value_types]inpyproject.tomland runpyqa lint --check-value-types-generalto enforce structural traits (for example repositories must implement__len__+__contains__). - Deterministic envs:
uvmanages every dependency. PyQA reuses system binaries only when they are newer and you have not forced--use-local-linters. - Rich reporting: emit Markdown, SARIF, JSON, or PR summaries, and pipe catalogs into
ref_docs/tool-schema.jsonwithpyqa config export-tools. - Typed catalog + DI seams: runtime modules only import from
pyqa.interfaces.*, while the reusable schema lives insrc/tooling_spec/for downstream consumers.
The REORG initiative is complete and all guidance now lives in first-class docs:
docs/ARCHITECTURE.md– package responsibilities, SOLID guardrails, and interface boundaries.SELECTION.md,SOLID_CLI.md,docs/orchestration/*– orchestration internals, DI seams, progress rendering, and state machines.docs/tooling/– catalog schemas, shared knobs, and authoring guides.docs/release/0.3.0.md– highlights for the rename + provenance work.
Key takeaways:
pyqa.cachehandles persistence and cache repositories behindpyqa.interfaces.cache.pyqa.analysisprovides spaCy/tree-sitter integrations and refactor analytics.pyqa.reportingowns console/Markdown/SARIF emitters and the SOLID advice builder.pyqa.clihosts the Typer app, option builders, and launcher shims (mirrored by./lint,./install, etc.).pyqa.toolsdefines built-in tool registrations plus parser Protocols.tooling_specis a standalone distribution exporting the catalog schema for external tooling.
- Package name:
pyqa_lint; CLI/import namespace:pyqa. v*tags trigger.github/workflows/release.yml, which:- Runs
uv sync --group dev - Builds sdist + wheel via
python -m build - Uploads artefacts for inspection
- Generates a GitHub attestation (
actions/attest-build-provenance@v1) - Publishes to PyPI via
pypa/gh-action-pypi-publishwith attestations enabled
- Runs
- Required repo secret:
PYPI_API_TOKEN(trusted publisher token forpyqa_lint). - Release checklist: bump
pyproject.toml, updatedocs/release/<version>.md, regenerateref_docs/tool-schema.json(uv run pyqa config export-tools --check ref_docs/tool-schema.json), commit, tagvX.Y.Z, push tag.
- Layered configuration: defaults →
~/.pyqa_lint.toml→[tool.pyqa]inpyproject.toml→<project>/.pyqa_lint.toml. Inspect withpyqa config show --root <path> --traceor compare layers viapyqa config diff. - Strict validation: pass
--strict-config(orpyqa config validate --strict) to fail on unknown keys. - License policy:
[tool.pyqa.license]declares SPDX identifiers, notices, year ranges, and exceptions enforced bypyqa check-quality. - Quality defaults:
[tool.pyqa.quality]centralizes enabled checks, schema targets, skip globs, and protected branches for hooks/CI. - Shared knobs:
[complexity]and[strictness]propagate limits to ruff, pylint, luacheck, mypy, pyright, tsc, etc. Sensitivity presets (--sensitivity low|medium|high|maximum) shift multiple thresholds together. - Tool overrides: configure
[tool.pyqa.<tool>](or.pyqa_lint.toml's[tools.<tool>]) to customize args/env per tool; CLI flags still win for ad-hoc overrides. - Schema exports:
pyqa config schema --format markdowndocuments every option;pyqa config schema --format json-tools --out ref_docs/tool-schema.jsonandpyqa config export-toolskeep the checked-in schema current.
[tool.pyqa.generic_value_types]
enabled = true
[[tool.pyqa.generic_value_types.rules]]
pattern = "myapp.repositories.*"
traits = ["iterable", "value"]
require = ["__len__", "__contains__"]
recommend = ["__repr__"]
[[tool.pyqa.generic_value_types.implications]]
trigger = "method:__len__"
require = ["__bool__"]
severity = "warning"Run pyqa lint --check-value-types-general (or ./lint --check-value-types-general). Diagnostics such as generic-value-types:missing-required demand a suppression_valid justification when they cannot be satisfied.
./lint --validate-schema
# or
uv run python -m jsonschema -F errors \
-i tooling/catalog/languages/python/bandit.json \
tooling/schema/tool_definition.schema.jsonThe catalog schemas are intentionally reusable so other orchestrators can adopt the same contracts. See tooling/schema/SCHEMA.md and tooling/catalog/docs/SHARED_KNOBS.md for field-by-field detail.
Tree-sitter grammars are pinned in pyproject.toml and installed via uv. Install spaCy's English model once per environment:
uv run python -m spacy download en_core_web_smOverride with PYQA_NLP_MODEL=<model> or disable highlighting entirely with --no-color in strict CI logs.
- Review CONTRIBUTING.md and the Code of Conduct before submitting PRs.
- Run
uv run pyqa check-qualityanduv run pytestlocally prior to opening a PR. - File issues or feature requests directly on GitHub; include the output from
pyqa lint --explain-toolswhen reporting orchestration bugs.
This project is licensed under the MIT License. See LICENSE for details.