Problem statement
Open issue #196 specifies JSON Schemas for contextweaver's public on-the-wire types: catalog YAML/JSON files, ChoiceCard, ResultEnvelope, RouteTrace, BuildStats, GraphManifest. All have to_dict() / from_dict() and are documented in code — but no schemas are published.
Schemas unlock:
The schemas exist implicitly in to_dict/from_dict and the dataclasses; codifying them is mechanical.
Proposed solution
jsonschema_gen helper in serde.py — small Python function that introspects a dataclass and emits a JSON Schema. Or, if cleaner, a separate src/contextweaver/_schema_gen.py (≤300 lines).
schemas/*.schema.json — six new committed schemas:
catalog.schema.json (for SelectableItem[])
choice_card.schema.json
result_envelope.schema.json
route_trace.schema.json
build_stats.schema.json
graph_manifest.schema.json
- Stable
$id URLs — host under the mkdocs site at https://dgenio.github.io/contextweaver/schemas/v0/<name>.schema.json.
make schemas — regenerates schemas from dataclasses.
make schemas-check — fails on drift; wired into make ci.
docs/contracts.md — describes the schemas, links each to its dataclass, and explains versioning (/v0/, /v1/, …).
# yaml-language-server: $schema=... header on examples/sample_catalog.yaml (and any other committed YAML catalogs) so VS Code picks the schema up automatically.
Alternatives considered
- Hand-write schemas. Rejected — drift inevitable; generator + drift check is the right discipline.
- Use
pydantic.TypeAdapter for generation. Rejected — Pydantic isn't a core dep; introducing it for schema generation alone is overkill.
- Use
dataclasses-jsonschema (external). Rejected — small custom generator is more controllable and matches the repo's stdlib-only preference.
- Skip the
make schemas-check step. Rejected — without it, drift ships silently; defeats the purpose.
Affected modules
src/contextweaver/_schema_gen.py (new) or extend serde.py, schemas/*.schema.json (6 new), Makefile, docs/contracts.md (new), mkdocs.yml, examples/sample_catalog.yaml, .github/workflows/ci.yml.
Estimated effort
M (3–5 days)
Baseline
No JSON Schemas published. VS Code YAML autocomplete doesn't work on catalog files. No cross-language contract. Drift between dataclass and prose documentation in docs/gateway_spec.md is checked manually only.
Success metric
Scope
Schema generator + 6 schemas + 1 docs page + make targets + CI step + YAML header on the sample catalog.
Non-goals
- Not adding cross-language ports (out of scope; the schemas enable them).
- Not auto-publishing schemas to a third-party registry (
schemastore.org); host on mkdocs only for now.
- Not adding
pydantic as a dep.
- Not changing any dataclass fields to fit a schema (the schemas conform to the dataclasses).
Design constraints
- Generator stdlib-only.
- Deterministic generation: same dataclasses → byte-identical schemas.
- Schema content must match the prose in
docs/gateway_spec.md for ChoiceCard size bounds; where prose is ambiguous, take it as authoritative and surface the ambiguity rather than guessing.
- Sub-300-line module guideline.
Depends on
None.
Suggested order
Last in M2 (closes #196).
Acceptance Criteria
Validation
pip install -e ".[dev]"
make schemas
git diff --quiet schemas/ # passes on clean tree
# Mutate ChoiceCard field name (e.g. in a fixture branch):
# (edit src/contextweaver/envelope.py)
make schemas-check # exits non-zero
make schemas # regenerate
git diff schemas/ # shows the rename
make ci
Manual: open examples/sample_catalog.yaml in VS Code with the Red Hat YAML extension; confirm tab-completion on a SelectableItem field works.
Files likely touched
src/contextweaver/_schema_gen.py (new) or extension of serde.py, schemas/*.schema.json (6 new), Makefile, docs/contracts.md (new), mkdocs.yml, examples/sample_catalog.yaml, .github/workflows/ci.yml.
Risk / rollback
Low — schemas + generator are additive. CI step is gated; can be soft if needed. Revert by removing the schema files, the generator, and the CI step.
Security/privacy notes
None. Schemas contain field names and types only.
Agent-ready notes
- Starting points:
src/contextweaver/serde.py for the existing serialization layer. src/contextweaver/envelope.py for the dataclasses needing schemas. JSON Schema Draft 2020-12 spec. docs/gateway_spec.md for ChoiceCard size bounds.
- Constraints: Generator stdlib-only. Schemas must match
to_dict() output exactly. ChoiceCard size bounds must reflect the gateway spec prose.
- Review focus for Copilot code review:
- Generator handles all dataclass field types (str, int, float, bool, list, dict, Optional, enums, nested dataclasses).
- Schemas validate against fixtures produced by
to_dict().
$id URLs are stable + versioned under /v0/.
- Drift check actually fails when a field renames.
Cross-references
References
Size
M
Problem statement
Open issue #196 specifies JSON Schemas for contextweaver's public on-the-wire types: catalog YAML/JSON files,
ChoiceCard,ResultEnvelope,RouteTrace,BuildStats,GraphManifest. All haveto_dict()/from_dict()and are documented in code — but no schemas are published.Schemas unlock:
The schemas exist implicitly in
to_dict/from_dictand the dataclasses; codifying them is mechanical.Proposed solution
jsonschema_genhelper inserde.py— small Python function that introspects a dataclass and emits a JSON Schema. Or, if cleaner, a separatesrc/contextweaver/_schema_gen.py(≤300 lines).schemas/*.schema.json— six new committed schemas:catalog.schema.json(forSelectableItem[])choice_card.schema.jsonresult_envelope.schema.jsonroute_trace.schema.jsonbuild_stats.schema.jsongraph_manifest.schema.json$idURLs — host under the mkdocs site athttps://dgenio.github.io/contextweaver/schemas/v0/<name>.schema.json.make schemas— regenerates schemas from dataclasses.make schemas-check— fails on drift; wired intomake ci.docs/contracts.md— describes the schemas, links each to its dataclass, and explains versioning (/v0/,/v1/, …).# yaml-language-server: $schema=...header onexamples/sample_catalog.yaml(and any other committed YAML catalogs) so VS Code picks the schema up automatically.Alternatives considered
pydantic.TypeAdapterfor generation. Rejected — Pydantic isn't a core dep; introducing it for schema generation alone is overkill.dataclasses-jsonschema(external). Rejected — small custom generator is more controllable and matches the repo's stdlib-only preference.make schemas-checkstep. Rejected — without it, drift ships silently; defeats the purpose.Affected modules
src/contextweaver/_schema_gen.py(new) or extendserde.py,schemas/*.schema.json(6 new),Makefile,docs/contracts.md(new),mkdocs.yml,examples/sample_catalog.yaml,.github/workflows/ci.yml.Estimated effort
M (3–5 days)
Baseline
No JSON Schemas published. VS Code YAML autocomplete doesn't work on catalog files. No cross-language contract. Drift between dataclass and prose documentation in
docs/gateway_spec.mdis checked manually only.Success metric
$idURLs.make schemas-checkpasses on a clean tree; fails when a dataclass field is renamed without regenerating the schema.examples/sample_catalog.yaml.Scope
Schema generator + 6 schemas + 1 docs page +
maketargets + CI step + YAML header on the sample catalog.Non-goals
schemastore.org); host on mkdocs only for now.pydanticas a dep.Design constraints
docs/gateway_spec.mdforChoiceCardsize bounds; where prose is ambiguous, take it as authoritative and surface the ambiguity rather than guessing.Depends on
None.
Suggested order
Last in M2 (closes #196).
Acceptance Criteria
schemas/catalog.schema.jsonexists.schemas/choice_card.schema.jsonexists (covers the size bounds fromdocs/gateway_spec.mdasmaxLength/maxProperties).schemas/result_envelope.schema.jsonexists.schemas/route_trace.schema.jsonexists.schemas/build_stats.schema.jsonexists.schemas/graph_manifest.schema.jsonexists.$id(https://dgenio.github.io/contextweaver/schemas/v0/<name>.schema.json).make schemasregenerates all 6 schemas from dataclasses deterministically.make schemas-checkexits non-zero on drift; wired intomake ci.docs/contracts.mddocuments the schemas, links each to its dataclass, and explains the versioning policy.examples/sample_catalog.yamlgains a top-of-file# yaml-language-server: $schema=...header.to_dict()validates against the schema.make cipasses.Validation
Manual: open
examples/sample_catalog.yamlin VS Code with the Red Hat YAML extension; confirm tab-completion on aSelectableItemfield works.Files likely touched
src/contextweaver/_schema_gen.py(new) or extension ofserde.py,schemas/*.schema.json(6 new),Makefile,docs/contracts.md(new),mkdocs.yml,examples/sample_catalog.yaml,.github/workflows/ci.yml.Risk / rollback
Low — schemas + generator are additive. CI step is gated; can be soft if needed. Revert by removing the schema files, the generator, and the CI step.
Security/privacy notes
None. Schemas contain field names and types only.
Agent-ready notes
src/contextweaver/serde.pyfor the existing serialization layer.src/contextweaver/envelope.pyfor the dataclasses needing schemas. JSON Schema Draft 2020-12 spec.docs/gateway_spec.mdforChoiceCardsize bounds.to_dict()output exactly. ChoiceCard size bounds must reflect the gateway spec prose.to_dict().$idURLs are stable + versioned under/v0/.Cross-references
$schemaheader becomes self-documenting.References
$schemaheader pattern.Size
M