Local contract registry¶
Use a local registry when multiple ODCS contracts live in one repository and consumers reference providers by fully-qualified name (FQN) — for example provider-contract/customers/customer_id.
The registry builds an index at <registry-root>/.odcs/registry.json. Validation with --registry resolves FQN relationship endpoints without listing every dependency with --dep.
When to use a registry¶
| Scenario | Approach |
|---|---|
| Single contract, no cross-file references | odcs validate contract.yaml |
| One consumer, one known provider | odcs validate consumer.yaml --dep provider.yaml |
| Several contracts in a directory | odcs registry index ./contracts/ then odcs validate … --registry ./contracts/ |
| Monorepo CI gate | Index once, validate each changed contract with --registry |
Single-file validate does not load dependencies
odcs validate consumer.yaml alone does not resolve FQN endpoints against other contracts. Validation may still print valid while cross-contract references are unchecked. See CI/CD integration.
Quick start¶
From the repository root:
odcs registry index examples/registry/
odcs validate examples/registry/consumer.yaml --registry examples/registry/
Expected output: valid (exit code 0).
See examples/registry/ for provider and consumer files.
Workflow¶
- Index — scan the registry root recursively and write
.odcs/registry.json. - Validate — pass
--registry <root>so FQN references resolve against indexed contracts. - Re-index — run
registry indexagain after adding, removing, or changing contracts under the root. There is no auto-reindex on validate.
odcs registry index ./contracts/
odcs validate consumer.yaml --registry ./contracts/
Lookup and list¶
odcs registry lookup ./contracts/ provider-contract
odcs registry lookup ./contracts/ provider-contract --version 1.0.0
odcs registry list ./contracts/
Add --json for structured output. Lookup without --version returns the highest semver entry for the id. Exit code 1 when no entry is found.
Python¶
import pyodcs
pyodcs.registry_index_and_save("./contracts/")
report = pyodcs.parse_and_validate_paths(
"consumer.yaml",
registry="./contracts/",
)
assert pyodcs.is_valid(report)
entry = pyodcs.registry_lookup("./contracts/", "provider-contract")
entries = pyodcs.registry_list("./contracts/")
CLI parity: pyodcs registry index, pyodcs registry lookup, and pyodcs registry list mirror the Rust odcs commands.
CI recipe¶
odcs registry index ./contracts/
for f in contracts/*.yaml; do
odcs validate "$f" --registry ./contracts/ --json > /dev/null
done
Do not run odcs registry index in parallel against the same directory — concurrent jobs can race even though writes are atomic.
Set ODCS_VERBOSE=1 for per-file index progress on stderr (does not affect stdout JSON).
See CI/CD integration for GitHub Actions examples and untrusted-input guidance.
Limits and security¶
| Limit | Value |
|---|---|
| Maximum indexed file count | 10,000 contract files per scan |
| Maximum index file size | 16 MiB (.odcs/registry.json) |
| Maximum parse size per contract | 16 MiB (MAX_PARSE_BYTES) |
- Indexed paths whose canonical form escapes the registry root are rejected.
- Symlink cycles during directory scan are rejected.
- Treat pull-request YAML as potentially hostile — see SECURITY.md.
Implementation details: Local registry (implementation) · Cross-file references
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| FQN references not validated | Validated without --registry or --dep |
Pass --registry or explicit --dep paths |
registry entry not found on lookup |
Index missing or stale | Run odcs registry index <dir> |
| Index fails with duplicate entry | Two files share the same id and version |
Use unique (id, version) pairs or separate registry roots |
| Index fails on symlink | Path resolves outside registry root | Remove or replace the symlink |
| CI passes locally but fails in CI | Unpinned tool version | Pin cargo install odcs --version 0.9.1 --locked |
See also Troubleshooting and FAQ.