Skip to content

Latest commit

 

History

History
116 lines (87 loc) · 6.56 KB

File metadata and controls

116 lines (87 loc) · 6.56 KB

Context Graph Protocol wire examples

Reference wire transcripts for the Context Graph Protocol. These are the exact JSON shapes a host and provider exchange — useful when implementing a provider in any language, because you can diff your own output against them.

There is no separate IDL; the contextgraph-types structs serialized by serde_json are the protocol. For the type definitions see protocol-surface.md; for the build guide see implementing-a-provider.md; for the normative rules these examples follow see protocol-surface.md § Conformance requirements.

These examples are machine-checked against the JSON Schema. Run python3 schema/validate-examples.py to verify they conform, or point your own validator (any language — ajv, Python jsonschema, Rust jsonschema crate, Go gojsonschema) at the schema to validate your provider's output.

Files

  • full-stdio-session.ndjson — a complete stdio session: one compact JSON object per line, in wire order. This is what actually travels over the pipe — diff your provider's output against it.
  • reference-messages.json — the same shapes, pretty-printed, with one example of each message type (including an egress provider variant).

Framing

Every message is one Context Graph Protocol envelope — an internally-tagged enum (#[serde(tag = "type", rename_all = "snake_case")]). The type field selects the variant and sits at the same level as the payload fields:

type direction payload
handshake host → provider protocol_version
handshake_ack provider → host protocol_version, provider, capabilities
query host → provider query (a ContextQuery)
frames provider → host result (a ContextQueryResult)
shutdown host → provider (none)
error provider → host message

Over stdio, each envelope is one line of compact JSON (NDJSON) on the provider's stdin/stdout. Over streamable HTTP, each exchange is one POST whose body is one envelope, with one envelope returned as the response.

Optional (Option<T>) fields may be omitted or sent as null — both are valid on the wire, and a conforming implementation should accept either. The examples below omit null optional fields to show the minimal valid form.

A complete stdio session (annotated)

full-stdio-session.ndjson contains exactly these five lines, in this order. Labels show direction; they are not part of the wire data.

1. host → provider — handshake. The host names the protocol version it speaks.

{"type":"handshake","protocol_version":"contextgraph/1.0"}

2. provider → host — handshake_ack. The provider replies with its own version, its identity, and its capabilities. This provider reads workspace content locally and has no egress, so a host may auto-enable it.

{"type":"handshake_ack","protocol_version":"contextgraph/1.0","provider":{"name":"repo-graph","version":"0.2.0","data_flow":{"reads":true,"writes":false,"egress":false}},"capabilities":{"query":{"kinds":["doc","symbol"]},"correlation":true,"graph":true,"embeddings_fingerprint":null,"verify":true}}

3. host → provider — query. A retrieval request carrying a hard token budget (max_tokens).

{"type":"query","query":{"goal":"how do I configure the retry policy?","query_text":"retry policy configuration","kinds":["doc","symbol"],"anchors":["src/config.rs"],"max_frames":5,"max_tokens":1024}}

4. provider → host — frames. The answer: two frames whose token_cost sums to 64, within the 1024-token budget, each with a non-empty title and citation_label, scores in [0,1], and a file provenance chain.

{"type":"frames","result":{"frames":[{"id":"repo-graph:retry-doc","kind":"doc","title":"Retry policy","content":"Retry behavior is set in Config::retry. max_attempts bounds the tries; backoff_ms is the initial delay, doubled each attempt.","uri":"file:///repo/docs/retry.md","score":0.92,"token_cost":41,"provenance":[{"type":"file","uri":"file:///repo/docs/retry.md","range":"L1-20","digest":"sha256:9f2c3e7a","method":"file-read","by":"repo-graph"}],"citation_label":"retry.md L1-20"},{"id":"repo-graph:retry-sym","kind":"symbol","title":"Config::retry","content":"pub struct RetryPolicy { pub max_attempts: u32, pub backoff_ms: u64 }","uri":"file:///repo/src/config.rs","score":0.81,"token_cost":23,"provenance":[{"type":"file","uri":"file:///repo/src/config.rs","range":"L42-44","digest":"sha256:1a2b3c4d","method":"tree-sitter-symbol-extraction","by":"repo-graph"}],"citation_label":"config.rs L42-44"}],"truncated":false}}

5. host → provider — shutdown. The host is done; a well-behaved provider exits cleanly (stdio) or simply expects no further requests (HTTP).

{"type":"shutdown"}

The egress variant

If a provider sends data off the local machine — a cloud documentation search, a remote embedding API — it declares egress: true:

{"type":"handshake_ack","protocol_version":"contextgraph/1.0","provider":{"name":"cloud-docs","version":"1.4.0","data_flow":{"reads":true,"writes":false,"egress":true}},"capabilities":{"query":{"kinds":["doc"]},"correlation":true,"graph":false,"embeddings_fingerprint":null}}

A conforming host does not auto-enable this provider. It gates the provider behind explicit, named, one-time consent and never transmits the query payload before consent is recorded. The host's HTTP transport treats every remote provider as egress regardless of this claim, so a remote cannot lie its way past the gate. This is the single most security-relevant shape in Context Graph Protocol; see protocol-surface.md § Conformance requirements.

Reporting an error without dying

A bad query should be answered with error, not a crash. A provider that exits on a bad request fails the malformed-input-tolerance conformance check.

{"type":"error","message":"unsupported frame kind: 'image'"}