This guide takes a Git repository from no configuration to a reviewed lockfile and a useful pull-request gate.
- Python 3.9 or newer
- Git
- At least one tracked component or manifest
Run every command below from the repository root.
python -m pip install boundver
boundver --versionOptional extras add a full JSON Schema validator and robust YAML parsing:
python -m pip install "boundver[schema,yaml]"For an existing repository, start with tracked manifests:
boundver discover
boundver init --discoverDiscovery uses Git instead of crawling ignored dependency trees. It recognizes common Python, JavaScript/TypeScript, Rust, and Go manifests. Review the generated boundary.config.json; discovery cannot decide which files form your public contract.
If discovery finds nothing useful, create a minimal scaffold:
boundver initinit is non-interactive. Edit the placeholder component before continuing.
Here is a useful starting configuration:
{
"$schema": "https://raw.githubusercontent.com/yzm1/boundver/main/boundary.config.schema.json",
"project": "checkout-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",
"paths": ["openapi/*.yaml", "*.service-definition.json"]
},
"behavior": {
"paths": ["openapi/*.yaml", "*.service-definition.json", "config/*.json"]
},
"consumers": ["checkout-web", "admin-portal"]
}
},
"slices": {
"checkout-contracts": {
"description": "Contracts used by checkout",
"mode": "boundary",
"components": ["payment-api"]
}
}
}Component path values are relative to the repository root. Boundary and behavior paths are relative to the component; they may be literal files or glob patterns. ** matches recursively. A pattern that matches nothing stops generation instead of silently hashing an empty contract.
The four facets have different jobs:
| Facet | Tracks | Typical policy |
|---|---|---|
exact |
All tracked component content | Observe or gate release hygiene |
behavior |
Declared behavior-relevant artifacts | Gate runtime-contract-sensitive systems |
boundary |
Declared public contract artifacts | Gate consumer-facing changes |
compat |
The configured version family | Gate coordinated breaking changes |
behavior.paths should normally be a superset of boundary.paths. consumers declares direct downstream systems. When a producer's boundary or compatibility facet changes, boundver names those consumers in the verification result.
defaults.verify_facets controls what fails a plain boundver verify. Starting with boundary and compat prevents internal refactors from making the check noisy. A command-line --facets value overrides the default.
boundver validate-configFix every reported error. Validation checks the schema, component roots, providers, unsafe paths, slices, consumers, and source declarations.
Use working-tree for both local generation and local verification:
boundver generate --source working-tree
boundver status
boundver verify --source working-tree --facets boundary,compatWorking-tree mode reads on-disk content but only for files known to Git. If you added a component or contract file, stage it before generating:
git add services/payment/openapi/new-route.yaml
boundver generate --source working-treeInspect the generated boundary.lock.json; it should contain non-null exact and declared boundary fingerprints. Generation fails if a required digest cannot be computed.
git add boundary.config.json boundary.lock.json
git commit -m "chore: add boundver contract baseline"After the commit, a source-consistent HEAD check should pass:
boundver verify --source head --facets boundary,compatDo not compare a lock generated from uncommitted working-tree content against head; the snapshots intentionally differ.
Create .github/workflows/boundary-check.yml:
name: Contract boundary
on: [pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: yzm1/boundver@v0
with:
config: boundary.config.json
lock: boundary.lock.json
source: head
facets: boundary,compathead is correct here because both the source and lockfile are committed in the pull request. The selected gate passes for an internal-only refactor and fails when a declared boundary or compatibility family drifts.
First inspect a local change against the matching snapshot:
boundver verify --source working-tree --facets boundary,compat
boundver why payment-api --source working-treeIf the gated change is intentional, review its consumer impact and update in one step:
boundver verify --source working-tree --facets boundary,compat --update
git diff -- boundary.lock.jsonTo refresh exact and behavior observations even when they are not part of your normal gate, explicitly include all facets:
boundver verify \
--source working-tree \
--facets exact,behavior,boundary,compat \
--updateCommit the source change and updated lockfile together. After committing, verify them together with --source head.
The highest-severity selected drift determines the process status:
| Code | Meaning |
|---|---|
0 |
Selected facets match |
1 |
Exact or metadata drift |
2 |
Usage or configuration error |
3 |
Behavior drift |
4 |
Boundary drift |
5 |
Compatibility drift |
This lets CI warn or fail differently without parsing human-readable output. --format json also returns structured issues, non-gating observations, selected facets, and update status.
boundver proves that the declared files produced the same fingerprints. It does not prove semantic compatibility, exercise consumers, or replace contract tests. The canonical JSON and OpenAPI providers reduce formatting and documentation noise, but you still decide which artifacts represent the real boundary and which consumer checks to run when it moves.
- Choose a provider in the provider guide.
- Add components gradually with the adoption guide.
- Copy a pipeline pattern from the CI cookbook.
- Explore runnable configurations in the examples index.
- Resolve concurrent updates with the lockfile merge strategy.