Skip to main content

ContractWatch

Catch breaking FastAPI changes before your clients do.

CI PyPI Python License

Your unit tests pass, you rename a response field, and the frontend breaks in production. ContractWatch snapshots your app's OpenAPI contract, then fails your commit or CI run if a change would break existing clients.

contractwatch check blocking a removed endpoint and a removed response field

What it catches

  • Breaking changes: removed endpoints, removed or retyped response fields, newly required request fields, removed status codes, narrowed enums.
  • Schema-name collisions: two Pydantic models with the same name in different modules, which makes OpenAPI component names ambiguous.
  • Reliability pitfalls: blocking calls inside async endpoints, HTTP calls without a timeout, duplicate routes, conflicting operation IDs.
  • Fixes, not just errors: every finding says what broke, who it hurts, and how to fix it.

Install

pip install contractwatch    # or: uv add --dev contractwatch

Python 3.11+, FastAPI, Pydantic v2.

Use it

contractwatch init     # save the current contract as the baseline (commit .contractwatch/baseline.json)
contractwatch check    # compare against the baseline

Exit codes: 0 safe, 1 blocking change, 2 analysis error.

Changed the API on purpose? Accept it:

contractwatch baseline update

Collisions that aren't breaking show up as warnings:

contractwatch check warning about two models named Item

Commands

Command What it does
init Create the baseline and optionally install the pre-commit hook
check Compare against the baseline; saves a report on failure
inspect Show the current routes and schemas
baseline update Accept the current contract as the new baseline
report --latest Re-open the last report (--format json, --output <path>, --list, --open)

Run contractwatch <command> --help for all options.

Pre-commit and CI

contractwatch init offers to install the hook for you (skip with --no-install-hook). Or add it by hand:

repos:
  - repo: local
    hooks:
      - id: contractwatch
        name: ContractWatch
        entry: contractwatch check
        language: system
        pass_filenames: false

In CI, just run contractwatch check; the exit code does the rest.

Configuration

Optional. Put it in contractwatch.toml or [tool.contractwatch] in pyproject.toml:

[tool.contractwatch]
app = "app.main:app"           # skip auto-detection
severity_threshold = "error"   # error | warning | info
baseline = ".contractwatch/baseline.json"
ignore = ["CW110"]             # silence specific codes

[tool.contractwatch.retention]
keep = 20                      # keep the last 20 reports...
days = 7                       # ...or the last 7 days, whichever is stricter

Env vars: CONTRACTWATCH_HOME (reports/cache location), NO_COLOR.

Diagnostic codes

Code Meaning Severity
CW101 Removed endpoint error
CW102 Removed response field error
CW103 Incompatible type change error
CW104 Newly required request field error
CW105 Requiredness / nullability change error
CW106 Removed response status error
CW107 Breaking enum change error
CW108 Incompatible schema shape error
CW110 Compatible addition info
CW201 Confirmed schema collision error
CW202 Ambiguous repeated model name warning
CW203 Repeated model name, not exposed info
CW204 Component reference change warning
RL101 Blocking call in async endpoint warning
RL102 HTTP client call without a timeout warning
RL103 Duplicate route/method registration warning
RL104 Conflicting operationId values warning

Contributing

uv sync --group dev
uv run ruff check . && uv run mypy && uv run pytest -q

License

MIT

Metadata

Release files for contractwatch 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for contractwatch 1.0.0
File Size Uploaded Provenance
contractwatch-1.0.0.tar.gz 193.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for contractwatch 1.0.0
File Interpreter ABI Platform
contractwatch-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 248.6 kB

Release files / contractwatch-1.0.0.tar.gz

Download URL contractwatch-1.0.0.tar.gz
Size 193.0 kB
Tags Source
SHA-256 checksum
How to use checksums
fb29c656fe0690b7978f420ec7648af96bc1b98ed0ffd2d5b5a6b4654557d893
BLAKE2b-256 checksum
How to use checksums
26bd0a3fdea8573f5d305558cf2114ef910c5691a7d9945ff71ff82dd0f33aee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.14

Release files / contractwatch-1.0.0-py3-none-any.whl

Download URL contractwatch-1.0.0-py3-none-any.whl
Size 55.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
22ccd84d032b599b07ef5bb2a26ea4e3c5bc2fa77542d680920cd2ba8362c80a
BLAKE2b-256 checksum
How to use checksums
db3028259290cc063347e084b20c12d07f865fe0bf5ac33eb68610015f2a7e2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.14

Security for contractwatch 1.0.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page