Capabilities
Contract Checks
Breaking-change checks for OpenAPI, GraphQL, protobuf and JSON Schema contracts, with the file and line on both sides of every break.
A renamed field in an API spec breaks every client that reads it; contract checks catch those breaks before release, for teams that publish APIs or schemas.
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:contract_checks.
Contract checks compare the API contracts a release changes, old against new, and report every change that breaks a client. They cover OpenAPI and Swagger specs, GraphQL schemas, protobuf files and JSON Schema payloads. Each finding gives the file and line on both sides, so you can see exactly what was and what is.
Contract checks run as part of every release check once the flag is on. There is nothing to configure.
Which files are checked
| Format | Detected when |
|---|---|
| protobuf | The file ends in .proto |
| GraphQL | The file ends in .graphql, .graphqls or .gql |
| OpenAPI / Swagger | A .yaml, .yml or .json file with a top-level openapi or swagger key |
| JSON Schema | A .yaml, .yml or .json file whose name ends in .schema.json, or whose $schema names a JSON Schema |
Files under testdata/, fixtures/, __fixtures__/, examples/, example/ or samples/, and generated files, are skipped. Both versions of a file must be the same format to be compared.
The CLI (bumpkit check, bumpkit gate) sends the old and new text of each changed contract with the check, up to 20 files of at most 1 MB each. The GitHub App fetches them from the repository instead. Each file reports at most 50 changes, breaking ones first.
A contract file that is deleted is a break ("Removed the OpenAPI contract …"), unless a file with the same name and format was added elsewhere in the same release; then the two are compared as a move.
Findings
| Kind | Severity | Meaning |
|---|---|---|
contract_breaking |
high | The change breaks existing clients |
contract |
info | A compatible change, such as a new operation, field or enum value, or a deprecation |
Findings come from the contracts checker, with deterministic evidence and high confidence. A contract_breaking finding makes the release a major version bump. The detail reads "Was: … (file:line). Now: … (file:line)."
What counts as breaking
OpenAPI
- Removing an operation, or a parameter
- Making a parameter or the request body required, adding a required parameter, or requiring a request body where there was none
- Changing the security scheme or the authentication an operation requires
- No longer accepting a request media type, or no longer returning a response media type
- Removing a success response
- Changing a property's type or format in a way the other side can't handle (narrowing what a request accepts, or widening what a response returns)
- Closing an object to properties it doesn't list (
additionalProperties) - Restricting a value to a fixed set (
enum), or removing an enum value that requests use - Removing a response property, making a property required, or making a response property no longer always present
- Adding a required property to a request
GraphQL
- Removing a type, field, argument, enum value or union member
- Changing a type's kind, such as an object to an interface
- Changing a field's type, or an argument's type, unsafely
- Adding a required argument or required input field
- A type no longer implementing an interface
protobuf
- Changing the package
- Removing a message, enum, service or RPC
- Changing an RPC's request or response type or streaming
- Removing a field or enum value without reserving its number
- Renaming a field (the binary encoding is unchanged, but JSON clients and generated code break)
- Changing a field's number, type or cardinality, or moving it into or out of a
oneof - Reusing a reserved number or name, or no longer reserving one
Removing a field and reserving it is reported as a compatible change.
JSON Schema
A JSON Schema payload is compared in both directions, as data that is both sent and received. Type and format changes, closing an object, restricting or removing enum values, removing properties and making properties required are all breaking.
Use them in the gate
contract_breaking findings work with the usual policy keys:
gate:
block_on: [secret, data_loss, contract_breaking]
require_approval:
- contract_breaking
hotfix:
block_on: [breaking, contract_breaking, data_loss, migration]block_onacceptscontract_breakingto fail on any high-severity break.require_approvalaccepts acontract_breakingrule. Thebreakingrule also asks for approval on contract breaks.hotfix.block_onacceptscontract_breaking, and includes it by default.
Without a policy entry, a contract break gives the check a review verdict and needs approval under the default breaking rule.
Compatibility matrix
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:compatibility_matrix.
The compatibility matrix is an explicit table of the version pairs you support: client vX with server vY, SDK with API, schema with app. Each pair gets one verdict, read from your recorded release checks:
| Verdict | What it means |
|---|---|
compatible |
Every recorded release of the provider inside the range was checked in full, and none has a proven break. |
breaking |
A recorded release inside the range has a proven break. The pair names it, with its file and version. Later versions in the range carry it. |
not_checked |
The evidence isn't complete, and the pair says why. Not checked never means compatible. |
There are no AI verdicts and no percentages. Bumpkit doesn't run your client against your server: a verdict states what the provider's recorded checks prove.
Set it up
- Get access to
compatibility_matrix,contract_checksandversion_consistency. A check run without contract checks or version consistency counts as not checked. - Declare your components and the ranges you support in
bumpkit.yml:
compatibility:
components:
- name: web
role: client
repository: acme/web
- name: api
role: server
paths: ["openapi/**", "proto/**"]
- name: db
role: schema
paths: ["db/migrations/**"]
supported:
- consumer: web
consumer_versions: ">=1.4.0 <2.0.0"
provider: api
provider_versions: ">=2.0.0"
- consumer: api
consumer_versions: ">=2.0.0"
provider: db
provider_versions: ">=2.0.0"- Run the gate, which reads the section every time, or read it now:
bumpkit compatibility sync --repository acme/api- Open Release decisions, or run
bumpkit compatibility. Each row leads with a status lamp. Open a row to see the pair version by version. Seecompatibilityin bumpkit.yml for every key.
Where a verdict comes from
Bumpkit looks at the provider's repository and the recorded releases inside provider_versions. A version counts as released once Bumpkit published it or a check ran with that version's tag as its head. A check counts when both its previous version and its new version are inside the range.
| Provider role | What counts as a break |
|---|---|
client, server, sdk, api, app |
contract_breaking findings from these contract checks, and breaking findings such as a removed export or route |
schema |
data_loss findings from migration safety checks, such as a dropped table or column |
A break counts when it is high severity, deterministic, not marked as a false positive, and inside the component's paths. With no paths, the whole repository counts.
A pair is not checked when a release in the range has no recorded check, the diff was too large to check in full, contract checks or version consistency weren't on, a contract file couldn't be read on both sides, version consistency disputes the version number, or data retention deleted the check's findings. Checks recorded before you turned on compatibility_matrix don't count either.
Block a release that breaks a pair
The rule is opt-in. Without it, the gate only reports the break:
gate:
block_on: [secret, data_loss, compatibility_break]The gate reads the pairs in the bumpkit.yml of the repository it runs on, and applies each pair whose provider is that repository. A release breaks a pair when its previous and new versions are both inside provider_versions. A proven break makes a release a major version, so a closed range such as >=2.0.0 <3.0.0 doesn't cover the release that leaves it: 3.0.0 isn't a version you declared as supported. To block that release, leave the range open, such as >=2.0.0.
A pair the gate can't prove adds a compatibility_not_checked finding, which never blocks.
Export it for a procurement review
Use Export CSV or Export JSON on the Release decisions page, or the CLI:
bumpkit compatibility export --format csv > compatibility.csvThe CSV has one row for each pair, with provider_version set to all in range, then one row per version and per break, with the file, line and check it came from.
Internal contract alerts
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:contract_alerts.
Contract checks cover the contracts you publish. For code shared between branches, bumpkit contracts alerts other open branches when a Go function, method or type they call changes signature:
bumpkit contracts sync
bumpkit contracts alerts --branch feature/export
bumpkit contracts ack ALERT_ID
bumpkit contracts close --branch feature/exportRun sync on every push, in CI or from an agent. It records this push's Go signature changes and the symbols the branch calls; branches calling an old signature are alerted by pull request comment, webhook and MCP. See Agent Swarms.