One schema, every language
The wire is validated by a single JSON Schema (Draft 2020-12): contextgraph-envelope.schema.json. The root validates one envelope; every payload shape is also exposed under $defs for granular validation.
There is no separate IDL — the contextgraph-types Rust structs serialized by serde are the protocol, and the schema mirrors them exactly. It validates with ajv, Python jsonschema, Rust jsonschema, Go gojsonschema — any Draft 2020-12 validator. Find it in the repository under schema/.
ContextFrame
| Field | Type | Notes |
|---|---|---|
| ● id | string | Non-empty, provider-scoped. |
| ● kind | FrameKind | snippet | symbol | fact | doc | memory | episode | graph |
| ● title | string | Non-empty. |
| ● score | number | Relevance in [0, 1]. |
| ● token_cost | u32 | Canonical: ceil(utf8_bytes(content)/4). |
| content | string? | Untrusted data. Governed per representation — omitted entirely for reference frames. |
| representation | enum? | full | compact | reference; absent ⇒ full. |
| content_digest | string? | sha256: + 64 hex. Omitting it makes the frame unverifiable. |
| content_ref | object? | { provider_id, uri, expires_at? } — opaque resolver handle. |
| canonical_content_hash | string? | Hash of the full canonical source. |
| content_fidelity | enum? | exact | normalized | summarized | omitted |
| transform | object? | { method, implementation, version } for compact renderings. |
| canonical_token_cost | u32? | Cost of the canonical source; tokenizer_ref names the tokenizer (e.g. openai:o200k_base). |
| valid_from / valid_to | timestamp? | Bi-temporal validity bounds. |
| recorded_at | timestamp? | When the frame was captured. |
| provenance | Provenance[] | Omitted when empty. |
| citation_label | string? | Non-empty when present. |
| embedding | object? | { fingerprint, vector? } |
| relations | Relation[] | The graph: labelled edges. Omitted when empty. |
{
"id": "frame:minimal",
"kind": "fact",
"title": "Minimal conforming frame",
"content": "Default arrays are omitted on the wire.",
"score": 1.0,
"token_cost": 10,
"citation_label": "minimal fixture"
}ContextQuery
| Field | Type | Notes |
|---|---|---|
| ● goal | string | The driving task — verbatim intent, not keywords. |
| ● kinds | FrameKind[] | Empty means “your best frames of any kind.” |
| ● anchors | string[] | Focal URIs — open files, mentioned symbols. |
| ● max_frames | u32 | Hard cap on returned frames. |
| ● max_tokens | u32 | A hard contract, not a hint. |
| query_text | string? | Optional keyword rendering of the goal. |
| embedding | number[]? | Only sendable when host and provider fingerprints match exactly (E1). |
| as_of | timestamp? | Pin retrieval to an instant. |
| representation_preferences | enum[]? | Ordered; absent ⇒ [full]. |
Provenance and Relation
A Provenance record requires a type (the Rust field kind serializes to type on the wire) and may carry uri, range, digest (pattern ^sha256:[0-9a-f]{64}$), method, and by. A Relation requires rel and target_uri, with an optional display_name.
Structural rules the schema enforces: required fields,
score ∈ [0,1], non-empty title/citation_label/id, the frame-kind enum, the contextgraph/MAJOR.MINOR(-draft)? version pattern, u32 ranges, and the per-representation content/content_ref/transform conditionals.