boundver
A Git-aware lockfile and CI check for contracts shared across components.
Did we change something other teams depend on?
Declare what each component publishes and who consumes it. Boundver records those declarations in a lockfile committed with the code. In CI, it compares that lockfile with an exact Git snapshot and reports:
- what kind of declared contract changed;
- which direct or transitive consumers may need verification; and
- enough machine-readable output to route the next check.
Boundver does not replace a compiler, build graph, compatibility checker, or consumer test. It supplies the repository-level signal that connects them.
Try it in one minute
Run this in a Git repository with tracked code under src/:
python -m pip install "boundver[schema,yaml]"
boundver init
boundver validate-config
boundver generate --source working-tree
boundver verify --source working-tree --facets exact
Review and commit boundary.config.json and boundary.lock.json together.
Plain boundver init creates a placeholder component rooted at src/. For a
different layout, use boundver init --discover and review its proposal, or
edit the generated component path before validation. Add a real boundary,
version source, and consumers before gating those signals.
For a runnable repository and expected output, use the one-minute demo.
The gap between existing tools
A compiler protects the code it understands. In a repository with a Python service, a TypeScript client, generated OpenAPI, and JSON Schema, a shared contract can cross language and build-system boundaries.
Git reports changed files. A build graph schedules known targets. A format-specific checker can judge one schema family. Boundver records which artifacts form each component's contract and who consumes them, so CI can send the changed contract to the appropriate checks.
Four signals, one result
Each component can provide up to four facets. More than one facet can change in the same comparison.
| Facet | What changed | Exit code when gated |
|---|---|---|
exact |
Tracked content, path, or file identity; text CRLF/LF are equivalent | 1 |
behavior |
A declared runtime-relevant input | 3 |
boundary |
A declared published artifact | 4 |
compat |
The configured compatibility family | 5 |
Exit 0 means no unacknowledged gated facet drift remains. With a verification
baseline, acknowledged drift can still be present. Exit 2 means boundver
could not complete the check reliably, such as when configuration, history, or
declared files are missing. When several gated facets drift, the highest
applicable drift code is returned.
A common policy is to gate boundary and compat, report the other signals,
then run a format-specific compatibility check and the affected consumer suites.
See exit-code handling
and the comparison guide.
What it will not tell you
Boundver reports drift in what you declared. It does not decide whether a change breaks a consumer, run consumer tests, or discover dependencies. Files left out of a selector are invisible to that facet.
A clean result means no unacknowledged gated drift remains. With a verification baseline, acknowledged lock drift can still be present. It does not prove backward compatibility or guarantee that every consumer is safe. Use oasdiff, Buf, GraphQL Inspector, compilers, and consumer tests for the judgments they are designed to make.
A practical configuration
{
"$schema": "https://raw.githubusercontent.com/yzm1/boundver/v0.15.2/boundary.config.schema.json",
"project": "payments-platform",
"defaults": {
"compat_mode": "major",
"verify_facets": ["boundary", "compat"]
},
"components": {
"payment-api": {
"path": "services/payment",
"version_source": {"file": "package.json", "field": "version"},
"boundary": {
"provider": "openapi-canonical",
"paths": ["openapi/**/*.yaml"]
},
"behavior": {
"paths": ["openapi/**/*.yaml", "config/**/*.json"]
},
"consumers": ["checkout-web"],
"external_consumers": ["external-risk-service"]
},
"checkout-web": {
"path": "apps/checkout",
"version_source": {"file": "package.json", "field": "version"},
"boundary": {"provider": "leaf", "paths": []},
"verify_facets": ["exact"]
}
},
"slices": {
"checkout-contracts": {
"description": "Contracts required by checkout",
"mode": "boundary",
"components": ["payment-api"]
}
}
}
This records one API boundary, one direct internal consumer, one external consumer, and a named slice. Paths are repository-relative for components and component-relative inside boundary, behavior, and version declarations.
The configuration reference documents providers, selectors, source modes, facets, and graph limits. The glossary defines the terms used throughout the project.
Reconcile a branch, then review the range
review compares reconciled checkpoints. Both endpoint commits must already
contain locks that match their source trees.
# Inspect the candidate before accepting its drift.
boundver verify --source working-tree
boundver why payment-api --source working-tree
# Record intentional drift, inspect the lock change, and commit the checkpoint.
boundver verify --source working-tree --update
git diff -- boundary.lock.json
git add boundary.lock.json path/to/changed-file
git commit -m "chore: reconcile boundver lock"
boundver verify --source head
# Now compare the two reconciled commits.
boundver review origin/main..HEAD --merge-base --transitive
review is read-only and compares two immutable Git trees. verify remains
the integrity gate for the current candidate. Repositories that update locks
only periodically can review their reconciled checkpoints, but cannot use an
unreconciled pull-request tip as a review endpoint. Generated boundary artifacts
need their own deterministic freshness check before verification; see
troubleshooting.
GitHub Actions
Pin the Action to the same release used to write the lock:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: yzm1/boundver@v0.15.2
with:
operation: verify
source: head
Omitting facets applies each component's configured verify_facets policy.
The CI cookbook covers GitHub, GitLab, pre-commit, range review, outputs, and shallow-history failures.
Install and run
- PyPI:
python -m pip install "boundver[schema,yaml]" - GitHub Action: Marketplace
- GitLab CI/CD: Catalog project
- Container:
docker run --rm ghcr.io/yzm1/boundver:0.15.2 --version - Homebrew:
brew install yzm1/boundver/boundver - Standalone archive: download
boundver-0.15.2.pyzfrom GitHub Releases
The project supports Python 3.10 or newer and requires Git. Release channels and least-privilege container use are documented in the distribution guide.
Trust and privacy
The built-in boundver CLI is telemetry-free. It does not send source, usage, analytics, update checks, or crash reports anywhere. Custom Python providers are explicitly enabled trusted code and are outside that built-in guarantee.
Read the privacy policy, the security model, and the normative specification.
Using or evaluating boundver? You can identify yourself voluntarily in the adopter discussion.
Project
Boundver is beta software under the MIT license. Issues and pull requests are welcome. Start with CONTRIBUTING.md; maintainers should use the checked-in release process.
The changelog records user-visible changes. The v0.15 line is focused on historical range review, security hardening, and making the public documentation easier to use. Semantic-provider implementation remains separately gated work for a later release.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file boundver-0.15.2.tar.gz.
File metadata
- Download URL: boundver-0.15.2.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f27634b928b09b71eeb5d12c214eccaaeff92685391317b03717d0e8d35f50b
|
|
| MD5 |
fb4c3ec27b0ad50be1e91ac6fa542154
|
|
| BLAKE2b-256 |
70dff6632384eb0d2b3f4deb3f37d8ccd85b1f7ea60e5bada8cdf2d7013dcb44
|
Provenance
The following attestation bundles were made for boundver-0.15.2.tar.gz:
Publisher:
publish.yml on yzm1/boundver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
boundver-0.15.2.tar.gz -
Subject digest:
6f27634b928b09b71eeb5d12c214eccaaeff92685391317b03717d0e8d35f50b - Sigstore transparency entry: 2748017356
- Sigstore integration time:
-
Permalink:
yzm1/boundver@b8c886100694a0b9f9d45502d072876f07c43444 -
Branch / Tag:
refs/tags/v0.15.2 - Owner: https://github.com/yzm1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b8c886100694a0b9f9d45502d072876f07c43444 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file boundver-0.15.2-py3-none-any.whl.
File metadata
- Download URL: boundver-0.15.2-py3-none-any.whl
- Upload date:
- Size: 929.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9619c3e426c7a5e09ad376511967c11657cdaad06c21efecfda57d7e7fd89913
|
|
| MD5 |
887e38aecd10cf1edc0ced5c0e9372c4
|
|
| BLAKE2b-256 |
6990cb9cd1b97553459047e5ae3852bb98072b7e6ff36cad063359a816fe4845
|
Provenance
The following attestation bundles were made for boundver-0.15.2-py3-none-any.whl:
Publisher:
publish.yml on yzm1/boundver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
boundver-0.15.2-py3-none-any.whl -
Subject digest:
9619c3e426c7a5e09ad376511967c11657cdaad06c21efecfda57d7e7fd89913 - Sigstore transparency entry: 2748017371
- Sigstore integration time:
-
Permalink:
yzm1/boundver@b8c886100694a0b9f9d45502d072876f07c43444 -
Branch / Tag:
refs/tags/v0.15.2 - Owner: https://github.com/yzm1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b8c886100694a0b9f9d45502d072876f07c43444 -
Trigger Event:
workflow_dispatch
-
Statement type: