02 Core concepts

Frames, relations, and honest budgets

A frame is not a string. It is a structured record of relevance, cost, provenance, and validity — and the graph is carried in its labelled relations.

Frame kinds

Every frame declares one of seven kinds, serialized in snake_case on the wire:

KindTypical content
snippetA contiguous run of source or text, e.g. a function body.
symbolA named program entity — its signature, definition site.
factA discrete assertion with validity bounds.
docDocumentation or prose, whole or excerpted.
memoryDurable agent memory: preferences, learned constraints.
episodeA record of something that happened — an incident, a session.
graphA node with its labelled edges — structure itself as context.

Representations: content-optional by design

A frame carries its content in one of three representations, negotiated through the query’s representation_preferences and the provider’s declared capabilities:

  • full — inline content required. The default: a full frame omits the representation field entirely, so pre-representation frames are unchanged on the wire.
  • compact — inline content that is a transformed rendering (say, a signature-only view of a file), plus the canonical_content_hash of the source it was derived from, a transform identity, and a content_ref back to the original.
  • reference — no inline content at all: an opaque content_ref resolver handle plus the canonical hash. It is never encoded as content: ""; the field is omitted entirely.
Why it matters: large context can travel by name and still be verified byte-for-byte. A host that already holds the bytes (in a cache, on disk) pays near-zero tokens to re-establish trust in them.

Supporting fields make fidelity explicit: content_fidelity is one of exact, normalized, summarized, omitted; a host can demand a floor with minimum_content_fidelity or require inline bytes with inline_content_requirement.

Relations: the graph itself

CGP is named for the graph, and the graph is carried in relations: a graph frame is a node with its labelled edges, not an ad-hoc serialization format. Each relation is a directional edge { rel, target_uri, display_name? }. Six names are published — code.calls, code.imports, code.defines, code.references, doc.documents, episode.follows — and the vocabulary is open: providers namespace their own (myindex.owns), and a host must not reject unknown values.

Queries meet the graph through anchors: URIs the host considers focal — open files, mentioned symbols. A graph-capable provider should boost frames within a small number of relation hops of an anchor.

Token accounting

A budget token is an accounting unit, not a tokenizer. The canonical rule:

Budget rule B3 — exact equality, no tolerance band
token_cost = ceil( utf8_byte_length(content) / 4 )

Because the rule is deterministic in every language, budget honesty is machine-checkable: summed token_cost must not exceed the query’s max_tokens (B1), frame count must not exceed max_frames (B4), and a host must drop — with a loud report — the frames of any provider that violates the budget (B2).

A host must not treat one budget token as one model token. The 4-byte rule tracks English prose well but under-estimates dense source code (~3–3.5 bytes per model token) and CJK text (~3), so hosts map real budgets through a safety factor — the reference host suggests 1.35: 10,000 model tokens of headroom becomes a 7,407 budget-token query. The count covers content only, never titles, citation labels, or host chrome.

Identity and time

The stable identity of a frame’s exact bytes is the triple (provider_id, frame_id, content_digest) — the spine shared by deterministic composition, usage reports, and verification. A frame may omit content_digest, but such a frame is not verifiable, and a host must re-query rather than reuse it.

Frames are bi-temporal: valid_from / valid_to bound when the content was true; recorded_at says when it was captured; and a query’s as_of pins retrieval to an instant.