Skip to main content

Breaking-change gate for PRs — detects API breaks straight from the Python code diff, no OpenAPI spec required

Project description

Oneport ApiDiff

Breaking-change gate for PRs — straight from the Python code diff. No OpenAPI spec required.

oasdiff needs an OpenAPI spec. buf breaking needs protobuf. Most Python codebases have neither — their public API is the code. Oneport ApiDiff diffs the actual public surface of your changed .py files (via the ast module, deterministically) and gates the merge when a change would break consumers.

$ oneport-apidiff check --staged

oneport-apidiff — --staged
==========================
Verdict: BREAKING   (2 breaking, 0 risky, 1 compatible; 1 file(s) checked)

[BREAKING]   charge  (pkg/payments.py:6)
    param `timeout` was removed
    - def charge(amount, currency='usd', timeout=30)
    + def charge(amount, currency='usd')
    impact:    callers passing timeout positionally or by keyword now break
    migration: drop the timeout argument; configure timeouts on the client instead
    internal callers (2):
      app/billing.py:1   from pkg.payments import charge
      app/billing.py:14  charge(total, timeout=5)

Exit code 1 on BREAKING — wire it into CI and the merge is blocked until someone consciously overrides.

How it works

Deterministic detection, LLM classification. The model never decides what changed — only what it means.

  1. Deterministic core (ast) — base and head versions of every changed .py file are compared as public API surfaces: removed symbols, added/removed/renamed/reordered required params, changed defaults, changed type annotations, sync↔async flips. If an openapi.yaml/openapi.json changed, its paths/methods/responses are diffed structurally too. Internal callers of every changed symbol are found by a deterministic repo scan and listed with file:line.
  2. LLM layer (Claude or Gemini) — each detected change is classified BREAKING / RISKY / COMPATIBLE with a one-line consumer-impact narrative and a migration note. Every change carries a deterministic default verdict, so if the model is down, wrong, or skipped (--no-llm), the gate still works.

Install

pip install oneport-apidiff
export GEMINI_API_KEY=...   # free at https://aistudio.google.com/apikey
# or: export ANTHROPIC_API_KEY=sk-ant-...

Usage

oneport-apidiff check --staged          # gate what you're about to commit (default)
oneport-apidiff check --head            # gate the last commit
oneport-apidiff check --base main       # gate your branch against main
oneport-apidiff check https://github.com/org/repo/pull/42          # gate a PR
oneport-apidiff check https://github.com/org/repo/pull/42 --post   # ...and post the verdict

Flags:

Flag Effect
--post Post a sticky verdict table + inline comments on the exact changed signatures. Re-runs update in place (hidden marker) instead of duplicating. Requires GITHUB_TOKEN.
--format inline|json Human or machine output.
--allow-breaking Report but exit 0 (adoption mode).
--no-llm Deterministic verdicts only — no API key needed at all.

Exit codes: 0 clean/compatible · 1 breaking changes · 2 usage/config/auth error.

Team guidelines

ApiDiff reads the same .oneport/guidelines.md file as oneport-review. Verdicts respect your policy:

- internal package, private API — only changes to __all__ symbols are breaking
- CLI flag names are public API too

Detection stays deterministic either way; guidelines only shape what a change means.

CI

See examples/workflows/apidiff.yml. Minimal version:

- run: pip install oneport-apidiff
- run: oneport-apidiff check "${{ github.event.pull_request.html_url }}" --post
  env:
    GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Privacy

Serverless by design: your code goes from your machine (or your CI runner) directly to the model API with your own key. No Oneport servers, no telemetry, no storage. See PRIVACY.md.

vs. the alternatives

oneport-apidiff oasdiff buf breaking
Works without a spec yes — diffs the code itself no (OpenAPI only) no (protobuf only)
Python public API (functions/classes/params) yes no no
OpenAPI paths/methods/responses yes (when a spec is present) yes (deeper) no
Consumer-impact narrative + migration notes yes (LLM) no no
Internal caller list ("these files break") yes no no

Part of the Oneport pre-ship gate suite, alongside oneport-review.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oneport_apidiff-0.1.0.tar.gz (35.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oneport_apidiff-0.1.0-py3-none-any.whl (40.4 kB view details)

Uploaded Python 3

File details

Details for the file oneport_apidiff-0.1.0.tar.gz.

File metadata

  • Download URL: oneport_apidiff-0.1.0.tar.gz
  • Upload date:
  • Size: 35.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for oneport_apidiff-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1c9ce2551cdd926142f47c6b610da65c5d74b235e72b8b6dcd6ac9b649d972a7
MD5 be3742b0538b1d4dfa1b65ce84c2fa98
BLAKE2b-256 7f666d809518dc5664b09fd2c9f7411fd23f01129ecb6301292301457b48c5cd

See more details on using hashes here.

File details

Details for the file oneport_apidiff-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for oneport_apidiff-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1f13652a746dc791d08aec537c7736cdc3dfc7d7e337d2904c758adee13c5004
MD5 9860c8d9941c73a3b69e2bd0145be119
BLAKE2b-256 5907ec24ee29e7473aa17c039d8ca71f1febb5b84cc697216ed9b24bcf6bf8cf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page