tempest-cli
Documentação: Português (BR) · English (US)
One command for the quality gate of any Python project — ruff +
mypy + pytest, with a typing-strictness dial that lives in your
pyproject.toml instead of in four different Makefile targets.
Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
library, a script. It brings ruff along, so the gate runs the moment
you install it; typer is the only other runtime dependency.
uv add --dev tempest-cli
tempest-cli check # lint + fmt-check + type + test, in order, stops at the first failure
tempest-cli fix # every ruff autofix, then format
tempest-cli type -s strict # override the configured strictness for one run
tc check # `tc` is the short alias for the same program
Why it exists
The four commands are always the same, and every project rewrites them
slightly differently — a Makefile here, a tox.ini there, a CI job that
drifts from what runs locally. tempest-cli check is the same gate on
your machine and in CI, and --strictness makes "how much typing do we
enforce" a value in pyproject.toml rather than a flag someone
remembered to pass.
Commands
| Command | Runs |
|---|---|
tempest-cli lint |
ruff check |
tempest-cli fix |
ruff check --fix then ruff format (--unsafe for the risky autofixes) |
tempest-cli format |
ruff format (writes) |
tempest-cli fmt-check |
ruff format --check (read-only) |
tempest-cli type |
mypy |
tempest-cli test |
pytest (--fast spreads it across cores with pytest-xdist: -n auto -p no:cacheprovider, -w N to choose) |
tempest-cli check |
all four, in order, stopping at the first failure (--fast runs the test step in parallel) |
tempest-cli pr-prompt |
builds the prompt that makes an AI write this branch's PR description |
Every command takes an optional path (tempest-cli lint src/) and
returns the underlying tool's exit code, so CI reads it exactly as it
would read ruff directly.
Typing strictness
[tool.tempest]
typing_strictness = "strict" # lenient | standard | strict
The level adds flags on top of your own [tool.ruff] /
[tool.mypy] — it never relaxes what you already configured:
| Level | ruff (extra ANN rules) |
mypy |
|---|---|---|
lenient |
none | none |
standard |
ANN001, ANN201, ANN202, ANN205, ANN206 |
--disallow-untyped-defs --disallow-incomplete-defs |
strict |
the above plus ANN204 |
--strict |
ANN401 is never enabled at any level: Any is a legitimate
annotation. The levels enforce that things are annotated, never that
they avoid Any.
Override per run with --strictness / -s. Absent config means
standard.
Everything that is not typing — silencing an untyped library, skipping
generated code, dropping a rule that does not fit your framework — is
ordinary [tool.ruff] / [tool.mypy] configuration. The recipes,
including the one that takes a legacy Django project to a green gate,
are in Tuning the rules
(EN).
PR descriptions from the branch itself
tempest-cli pr-prompt | claude -p
tempest-cli pr-prompt develop --lang en --out pr_prompt.txt
The prompt carries the repository's own pull-request template (or a bundled PT-BR / EN-US default), the rules that stop a model from handing back the template with its placeholders intact, and the branch context: commit subjects, changed files, and a bounded excerpt of each patch.
Diffs are read as base...head — the merge-base diff the forge shows —
so commits that landed on the base after the branch started are not
attributed to it. Whatever the bounds leave out is stated inside the
prompt, so a partial diff reads as partial.
Use it as a library
from tempest_cli import load_tempest_config, run_full_check
config = load_tempest_config()
exit_code = run_full_check(".", config=config)
And to expose the same gate from your own CLI, without copying command bodies:
import typer
from tempest_cli.main import register_commands
cli: typer.Typer = typer.Typer(name="mytool")
register_commands(cli)
Where the tools come from
ruff comes with the package — six of the eight commands are ruff,
so lint, fix, format and fmt-check work straight after
uv add --dev tempest-cli, with nothing else to install. It is a static
binary wheel with no Python dependencies of its own, so nothing of its
propagates into your resolution.
mypy and pytest are deliberately left to you — a mypy bump changes
which errors your code reports, and pytest has to match your plugins and
your suite. Add them yourself, or take the bundle:
uv add --dev "tempest-cli[tools]" # mypy + pytest + pytest-xdist
pytest-xdist is what test --fast runs the suite with; its
requires-dist (execnet>=2.1, pytest>=7.0.0) carries no upper bound.
Whatever you pin wins over the bundled ruff. The lookup runs in this order:
- the project's environment —
$VIRTUAL_ENV, then the nearest.venvup the tree; - the environment
tempest-cliitself runs from (where the bundled ruff lives); PATH, skipping a pyenv/asdf shim that dispatches nowhere (the one that answerspyenv: ruff: command not found);uv run --with <tool> <tool>, whenuvis available.
Relationship with tempest-fastapi-sdk
This package was extracted from
tempest-fastapi-sdk,
where the same gate shipped as tempest check. Getting it meant
installing FastAPI, SQLAlchemy, Alembic and Pydantic — 38.7 MB of
dependencies and roughly 0.5 s of import time per invocation, for four
commands that never touch any of it.
tempest check keeps working: the SDK depends on this package and
registers the same commands. Both stay in sync because there is now one
implementation.
License
MIT — see LICENSE.
Metadata
Release files for tempest-cli 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tempest_cli-0.4.0.tar.gz | 146.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tempest_cli-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 177.2 kB
Release files / tempest_cli-0.4.0.tar.gz
| Download URL | tempest_cli-0.4.0.tar.gz |
|---|---|
| Size | 146.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
10199afc042919268597d5992c1275bee74a87160b1f6fc2af4e6d187bec2646
|
|
BLAKE2b-256 checksum How to use checksums |
9267d7a325f59524f1265e4061686522dc4b5386c4c4e68409445cdbecce8f16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.
Transparency logRelease files / tempest_cli-0.4.0-py3-none-any.whl
| Download URL | tempest_cli-0.4.0-py3-none-any.whl |
|---|---|
| Size | 31.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
79bc001ef0472cc4837c83bb2cf50f3867e3b70dc319ce0a0194fa58761557d7
|
|
BLAKE2b-256 checksum How to use checksums |
311cb832ccf7686c3a6414b9934e9c896805888ce3858b447eb5f39de800a8bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.
Transparency log