Context as evidence,
not on faith.
The Context Graph Protocol is an open wire protocol for context retrieval. It treats a piece of context as a typed, budgeted, provenance-carrying, consent-gated, and conformance-verified unit of exchange called a frame — never a blob.
reference frame: no inline content, still verifiable by hash.Why frames, not blobs
Agents today receive context as opaque strings: a retrieval pipeline concatenates whatever it found, and the model is asked to trust it. Nothing states where a passage came from, what it costs against the window, whether it is still true, or how to cite it. When the answer is wrong, there is nothing to audit.
CGP replaces the blob with the frame: a structured record of relevance, cost, provenance, and validity. A host asks providers for frames relevant to a goal, under a hard token budget. Each provider returns frames that carry their own origin, their honest cost, and a human-readable citation label. The host composes them into a prompt it can trust as evidence — and frame content is always delimited as quoted material, never as instructions.
The protocol is deliberately narrow. It does not specify tool invocation — that is MCP’s scope, and CGP will not absorb it. An agent needing both composes them: CGP frames feed the prompt, MCP tools do the work.
The unit of exchange
A frame states what it is, where it came from, what it costs, when it was true, and how to cite it. Seven kinds cover the shapes agent context actually takes: snippet, symbol, fact, doc, memory, episode, and graph — and the graph is carried in relations: a graph frame is a node with its labelled edges, not an ad-hoc serialization format.
{
"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"
}Every count is checkable: token_cost must equal ceil(utf8_bytes(content) / 4) — exact equality, no tolerance band — and the sum across returned frames must never exceed the query’s max_tokens.
The typed, budgeted, provenance-carrying unit of context exchange. Identified by (provider_id, frame_id, content_digest) — a content-addressed spine that makes reuse verifiable.
A labelled, directional edge from a frame to a target_uri. Six published names — code.calls, code.imports, code.defines, code.references, doc.documents, episode.follows — and an open namespace for the rest.
An accounting unit, not a tokenizer: ceil(utf8_bytes / 4). Deterministic in every language, so budget honesty is machine-checkable across implementations.
A wire you can read
The semantic layer — frames, queries, capabilities — is defined independently of transport. The current binding is NDJSON: every message is a single JSON envelope, internally tagged by type. Over stdio, one envelope per line; over streamable HTTP, one envelope per request and response. CGP is not JSON-RPC — there is no jsonrpc member and no method/params split.
No query payload moves before the handshake completes, and capabilities are negotiated explicitly — never inferred by observation. Two versions interoperate if and only if they share a major family, which is what lets 1.0-draft freeze into 1.0 without a flag day.
{"type":"handshake","protocol_version":"contextgraph/1.0-draft"}
{"type":"handshake_ack","protocol_version":"contextgraph/1.0-draft",
"provider":{"name":"docs-provider","version":"0.1.0",
"data_flow":{"reads":true,"writes":false,"egress":false}},
"capabilities":{"query":{"kinds":["doc","snippet"]},"correlation":true}}
{"type":"query","id":"q1","query":{
"goal":"why does the retry loop give up",
"kinds":["snippet"],"anchors":["file:///repo/src/net.rs"],
"max_frames":8,"max_tokens":2000}}
{"type":"frames","id":"q1","result":{"frames":[…],"truncated":false}}
{"type":"shutdown"}Conformance you can falsify
“CGP conformant” means green on the conformance suite for your declared capability set — a checkable claim, not a self-attestation. Seven checks cover the handshake, consent scopes, frame validity, verify honesty, budget honesty, clean shutdown, and malformed-input tolerance.
The suite must also prove it can catch a cheat: the bundled reference provider ships fourteen --misbehave modes that each break exactly one guarantee — lying about costs, flooding past max_frames, rubber-stamping verification — and CI asserts every mode is caught. A suite that only ever passes proves nothing.
Four independent implementations
The reference: contextgraph-types, contextgraph-host, and the conformance suite with the contextgraph-inspect prober.
@contextgraphprotocol/typescript-sdk on npm. Zero-dependency; implement three methods, call runStdioProvider.
contextgraph_sdk, stdlib-only. Any object with info(), capabilities(), query() is a provider.
Package contextgraph. Implement the interface, call cg.RunStdioProvider; verification is one optional interface away.
Every SDK is validated by the same Rust oracle — conformance-external.sh points the suite at any binary in any language. That shared oracle is the point. SDK quickstarts →
A trust architecture for context: the technical report
The whitepaper develops the argument end to end: why context windows fail as they fill, why the unit of exchange must carry provenance and honest cost, how deterministic composition turns prompt caches from an accident into a contract, and how an adversarial conformance suite keeps every guarantee falsifiable.