This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Reason given by maintainers: Had to change the name , now called breakwatch
PactWatch
Your microservices have a contract. PactWatch enforces it before merge.
An OpenAPI breaking-change detector that knows which downstream consumers will actually break. Most API diff tools tell you what changed. PactWatch tells you who cares.
The Problem
Team A changes their API. Team B's mobile app breaks in production. The spec diff showed "field removed" — but nobody connected it to Team B.
PactWatch maintains a service-to-consumer graph (pactwatch.yaml). When a producer's spec changes, it classifies each change as BREAKING, RISKY, or SAFE, then filters the results per consumer. Same spec change, different verdict per team.
How It Works
1. Diff — structurally compare two OpenAPI 3.x specs
2. Classify — label each change: BREAKING / RISKY / SAFE
3. Filter — check the consumer graph: who uses the affected endpoints?
Installation
pip install pactwatch
Quick Start
Raw diff (Phase 1)
Compare two specs and get classified changes:
# Rich terminal output
pactwatch diff old-spec.yaml new-spec.yaml
# JSON for CI
pactwatch diff old-spec.yaml new-spec.yaml --format json
Per-consumer impact (Phase 2)
Define your service topology in pactwatch.yaml:
version: 1
producers:
api:
spec: ./services/api/openapi.yaml
consumers:
mobile-app:
consumes:
- producer: api
endpoints:
- GET /users/{id}
- POST /orders
web-dashboard:
consumes:
- producer: api
endpoints:
- GET /users/{id}
- GET /admin/*
Then check per-consumer impact:
# Check all consumers
pactwatch check -c pactwatch.yaml -p api --old old.yaml --new new.yaml
# Check a single consumer
pactwatch check -c pactwatch.yaml -p api --old old.yaml --new new.yaml --consumer mobile-app
# JSON for CI
pactwatch check -c pactwatch.yaml -p api --old old.yaml --new new.yaml -f json
GitHub Action (Phase 3)
Add to your workflow:
name: API Contract Check
on: pull_request
jobs:
pactwatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pyjeebz/pactwatch@v1
with:
config: pactwatch.yaml
producer: api
old-spec: services/api/openapi.yaml # from base branch
new-spec: services/api/openapi.yaml # from PR branch
github-token: ${{ secrets.GITHUB_TOKEN }}
PactWatch will:
- Post a PR comment showing per-consumer impact
- Set a commit status check (pass/fail)
- Exit with code 1 if breaking changes affect any consumer
Classification Rules
Breaking
| Change | Why |
|---|---|
| Endpoint removed | Consumers calling it will get 404s |
| Required response field removed | Consumers parsing it will crash |
| Response field type changed | Consumers deserializing it will get wrong types |
| New required request field | Existing client code won't send it |
| Status code removed | Consumers handling it will get unexpected responses |
| Auth scheme changed | Existing tokens/keys will stop working |
Risky
| Change | Why |
|---|---|
| Optional field made required | Consumers not sending it may start failing |
| Field made nullable | Consumers not handling null may crash |
| Enum value removed | Consumers matching on it will miss cases |
Safe
| Change | Why |
|---|---|
| New endpoint | Existing consumers unaffected |
| New optional request field | Old clients just don't send it |
| New response field | Old clients ignore extra fields |
| New enum value | Old clients still see their known values |
| Documentation changes | No runtime impact |
CLI Reference
pactwatch diff
pactwatch diff OLD NEW [--format text|json]
Compare two OpenAPI specs. Exits with code 1 if BREAKING changes found.
pactwatch check
pactwatch check --config PATH --producer NAME --old PATH --new PATH
[--consumer NAME] [--format text|json]
Check per-consumer impact using the consumer graph. Exits with code 1 if any consumer has BREAKING changes.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | No breaking changes |
| 1 | Breaking changes detected |
| 2 | Input error (bad spec, bad config, unknown producer) |
Demo
See the demo monorepo for a working example with 3 services.
# Run the demo
pactwatch check \
-c examples/demo-monorepo/pactwatch.yaml \
-p user-api \
--old examples/demo-monorepo/services/producer-api/openapi.yaml \
--new examples/demo-monorepo/services/producer-api/openapi-breaking.yaml
License
Apache 2.0
Metadata
Release files for pactwatch 0.1.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 | |
|---|---|---|---|
| pactwatch-0.1.0.tar.gz | 30.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pactwatch-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.1 kB
Release files / pactwatch-0.1.0.tar.gz
| Download URL | pactwatch-0.1.0.tar.gz |
|---|---|
| Size | 30.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5260cd4523d61cb21f04b9bc0fffca812adda3fac0506817babe794f6e802683
|
|
BLAKE2b-256 checksum How to use checksums |
640019ce16498c61c34ee63a7e2c899e37416b44b54f2ed34a21abb444a8b8ad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / pactwatch-0.1.0-py3-none-any.whl
| Download URL | pactwatch-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6007cff22f2effbfa114d9e0f1c07542c28e77816f65fef8358a372df4abb3af
|
|
BLAKE2b-256 checksum How to use checksums |
06e960594e7191318fb75c375bbdf4b08f0189090e1f6c9be92c0e68fd958098
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|