Schema Hosting Policy
May 16, 2026 · View on GitHub
This document defines how the JSON Schema $id URIs in contracts/json/ are constructed, what guarantees the project makes about them, and where the canonical list of schemas (with content hashes) lives.
For the underlying versioning rules, see docs/VERSIONING.md. For schema design conventions, see contracts/json/README.md.
Canonical URL pattern
Every Core JSON Schema declares an $id of the form:
https://weaver-spec.dev/contracts/v{MAJOR}/{name}.schema.json
The {MAJOR} segment tracks the contract MAJOR version (currently v0). The {name} segment is the schema's snake_case basename (e.g. frame, routing_decision).
The base URI is also exposed programmatically as weaver_contracts.version.SCHEMA_BASE_URI (defined in contracts/python/src/weaver_contracts/version.py).
Current hosting status
The $id URI is currently an identifier, not a guaranteed-resolvable URL.
- The
weaver-spec.devdomain is the canonical namespace claimed by this project. It is not currently serving the schemas at a stable HTTPS endpoint. - Cross-schema
$refresolution in this repository uses a local store (seecontracts/python/tests/test_json_schema_alignment.py) that maps$idstrings to local schema files. - Adopters who need live resolution must bundle the schemas from this repository (via a release tag) or vendor them through their own build.
Serving the schemas at the documented URL is a planned follow-up; the URL pattern above is the contract.
Immutability rule
A published $id URL never changes meaning.
Once a schema is released under a given $id (e.g. https://weaver-spec.dev/contracts/v0/frame.schema.json), the structural meaning of that URL is fixed for the lifetime of that MAJOR version. Field semantics, type definitions, and invariants attached to that schema do not silently change.
- Additive changes (new optional fields, new enum values where the schema permits) reuse the same
$id. The MINOR or PATCH version bump inweaver_contractsrecords the addition. - Breaking changes require a new MAJOR version. A new
/v{N+1}/path is introduced; the/v{N}/path is preserved alongside it for migration. Old schemas are never overwritten.
This is the same promise documented in docs/VERSIONING.md. It is restated here because the $id is the public-facing surface of that promise.
Content-addressed index
The canonical list of published schemas — with the SHA-256 of each schema file's contents — lives at well-known/contracts.json. The index is generated by scripts/generate_contracts_index.py (stdlib-only Python).
Adopters can verify a downloaded schema matches the published bytes by:
- Locating the schema in
well-known/contracts.jsonby its$id. - Comparing the
sha256field to the SHA-256 of the locally-downloaded bytes.
The index structure:
{
"schema_version": 1,
"contract_version": "0.2.0",
"core": [
{
"name": "frame",
"version": "v0",
"$id": "https://weaver-spec.dev/contracts/v0/frame.schema.json",
"path": "contracts/json/frame.schema.json",
"sha256": "..."
}
],
"extended": []
}
The extended array is currently empty; it will be populated when JSON Schemas for the Extended types are introduced (see the open issue tracking that work).
The index is checked in CI: the validate-contracts-index job in .github/workflows/ci.yml runs the generator with --check and fails the build if the on-disk file is stale relative to the schemas. PRs that change any file under contracts/json/ must regenerate the index in the same PR:
python scripts/generate_contracts_index.py
Future work
- Serve the schemas at
weaver-spec.dev. Wire the domain to a content host (e.g. GitHub Pages) so the documented$idURLs resolve. Tracked separately. - Mirror to schemastore.org. Submit the schemas to the public schemastore catalog so JSON Schema-aware editors discover them automatically.
- Extended schemas. Populate the
extendedarray of the index when Extended type schemas are introduced.
None of these is required to close the policy described above.