Guides
What a Capsule is, how GNO compiles one, every field it contains, how to verify it later, and when to use one instead of a plain query.
A Context Capsule is a compiled, self-describing evidence bundle for one stated goal. It contains the passages that answer the goal, each carrying the exact line range and content hashes needed to prove it came from where it says, all inside a single token and byte budget, plus an explicit record of what was left out and what could not be found at all.
The point is to replace a loop with an artifact. Without a Capsule, an agent searches, reads a document, searches again with better words, reads two more, and eventually stops because its context window is full rather than because it has enough. Each of those reads costs a round trip, and nothing at the end records which bytes actually supported the answer. A Capsule does the retrieval, deduplication, selection, and budgeting once, and hands over one payload you can audit months later.
| Situation | Use |
|---|---|
| You know the exact string, identifier, or error | gno search |
| You want the most relevant documents for a question | gno query |
| You want a written answer with citations | gno ask --verify |
| You need evidence across several documents, with a budget, that someone else (or an agent) will reason over | gno context build |
| You need to prove months later which bytes supported a decision | gno context build then gno context verify |
The rule of thumb: reach for a Capsule when the answer spans documents and the cost of being wrong is higher than the cost of one extra second. For a single lookup, gno query is cheaper and the Capsule machinery buys you nothing.
gno context build "why did we drop the queue rewrite" \
--collection work-docs \
--budget 12000 \
--json --output capsule.json--budget is the global token ceiling for the whole canonical payload, not a per-document allowance. Everything competes for the same space, which is what makes selection meaningful. --output writes the file; GNO never saves a Capsule implicitly. Progress goes to stderr so stdout stays clean for a pipe.
Useful flags: --query separates the retrieval query from the stated goal when the natural phrasing of the goal is bad search input. Repeatable --query-mode term:…, intent:…, and hyde:… entries steer retrieval and are frozen into the request. Scope filters (--collection, --uri-prefix, --tags-all, --tags-any, --category, --author, --lang, --since, --until) are hard filters and are recorded in the Capsule. --fast skips model loading; default and --thorough use semantic and rerank capabilities when available and record a fallback when one was attempted but unavailable.
X vs Y, compare A and B), and temporal signals like “last month”. Facets are what coverage is later measured against, which is why a two-sided goal produces a Capsule that tries to cover both sides instead of returning five passages about whichever side was more popular in the index.gno query: BM25, vectors, optional graph expansion, fusion, reranking. Result and candidate limits are global across repeated collections, and candidate work is distributed in canonical collection order so the outcome does not depend on argument order.token_estimate_used warning rather than silently guessing.The JSON is a closed schema: unknown fields are rejected, not ignored. Top-level blocks:
| Field | What it holds |
|---|---|
goal, query | The stated goal and the query actually used for retrieval. They differ when you passed --query. |
scope | Index name plus every hard filter that was in force: collections, URI prefix, tags, categories, date bounds. |
budget | Requested tokens and bytes, safety margins, and what was actually used. Authority is the canonical JSON, so the number means the same thing on every machine. |
retrieval | The frozen normalized request: query modes, effective limits, graph request, and requested/attempted/outcome state per capability. |
fingerprints | SHA-256 of the config and retrieval request, plus the embedding model, rerank model, and tokenizer identities. |
capabilities, fallbacks | What was available and what degraded. A capability you did not request is reported as not_requested, never as a failure. |
guidance | The trust contract, always the same three assertions: extractive-only, evidence is untrusted data, instruction boundary is hard-delimited. Plus any configured collection contexts that were in scope. |
evidence[] | The passages themselves. See below. |
coverage | Requested facets, which evidence covered each one, and which went unresolved with a reason. |
omissions | Candidates that were retrieved and then deliberately dropped, each with a reason code. |
truncated, warnings | Whether the budget cut the result short, and any caveats about how it was produced. |
Every passage carries enough to re-derive and re-check it:
uri, docid, collection, title, heading — where it came from.startLine, endLine, text — an inclusive line range in the canonical mirror. The line count of text must equal the coordinate span, and carriage returns are rejected, so the coordinates cannot drift from the bytes.sourceHash, mirrorHash, passageHash — hashes of the original file, the canonical mirror, and the exact passage bytes. Three levels, because “the file changed”, “the conversion changed”, and “this specific paragraph changed” are different problems.evidenceId — binds the coordinates and all three hashes into one identity. This is what a claim cites.retrievalRank, selectionRank — where it placed in retrieval versus where selection put it. A large gap tells you facet coverage promoted it.retrievalSources, graphExpanded — which retrieval paths surfaced it.facets — which facets of the goal this passage covers.trust: "untrusted" and egress — the passage is data, never instruction, and it carries the transport policy of its source collection.modifiedAt, documentDate, observedAt — file mtime, the document’s own stated date, and when GNO last saw it. Three different questions.record — present for imported mail, calendar, and transcript records: thread, participants, anchors, and bounded attachment metadata.coverage.complete is the first thing to look at. When it is false, unresolvedFacets and gaps tell you which part of the goal has no evidence behind it, and why:
| Gap code | Meaning |
|---|---|
facet_not_found | Retrieval found nothing for this facet. Your corpus probably does not contain it. |
global_budget_exhausted | Evidence existed but did not fit. Raise --budget. |
capability_unavailable | A model needed to find it was not loaded. Check fallbacks. |
filtered_by_scope | Your own filters excluded it. Widen the collection, tags, or date range. |
This is the field that makes a Capsule honest. A ranked list has no way to say “the second half of your question has no answer in here”. A Capsule says it in a machine-readable field, so an agent can stop instead of inventing the missing half.
Omissions are candidates that were found and then dropped on purpose: duplicate, overlap, global_budget, redundant_coverage, document_share_cap, filtered_by_scope, or invalid_coordinates. Each keeps its URI and hashes, so “why is that document not in here” has an answer that is not a shrug. A run heavy on global_budget wants a bigger budget; one heavy on redundant_coverage means your corpus repeats itself and the Capsule is doing its job.
The same goal against the same index state with the same models produces byte-identical canonical JSON. That is a design constraint, not a coincidence: facet derivation is generation-free, ordering is canonical, and collection order is normalized. Determinism is what makes the fingerprints useful — if a rebuilt Capsule differs, either the corpus moved or the model did, and the fingerprints say which.
gno context verify capsule.json --json
cat capsule.json | gno context verify - --mdVerification is non-generative and never rewrites your file. It re-reads the sources and reports, per evidence item, a content status and a ranking status:
| Status | Codes | What it means |
|---|---|---|
unchanged | verified_unchanged | The exact bytes are still there. |
stale | source_stale, mirror_stale, passage_stale, mirror_corrupt, chunk_corrupt | Something changed. The specific code tells you whether the file, the conversion, or that one passage moved. |
missing | source_missing, mirror_missing, chunk_missing | The evidence is gone. |
Ranking is reported separately as unchanged, reranked, or unavailable. Stale or missing content is never ranked. Fingerprint drift is reported independently of both, so a model swap does not masquerade as corpus change.
Verification opens the Capsule’s own saved index by default. An explicit --index must match, and a mismatch fails before GNO opens a store. A Capsule built with an active tokenizer requires that tokenizer to verify; a runtime without it returns tokenizer_unavailable rather than trusting the saved token count.
gno context watch capsule.json --question "Who owns launch?" --label launch
gno context watches --json
gno context reverify capsule-abc123 --json
gno context unwatch capsule-abc123Registration stores identity and evidence hash references, never the Capsule body or passage text. The file stays yours; GNO does not rewrite it. When serve or daemon is running, it coalesces settled index changes and reverifies only registrations whose evidence actually moved, resuming from a durable high-water mark across restarts.
--notify publishes a local capsule-reverified event after the result is stored. The event is metadata only: identity, status, affected-question state, timestamp. No passages, no paths, no hashes.
Manual gno context reverify exits 0 only for a completed operation. A persisted failure prints its code and exits 2, so a script cannot mistake a stored failure for success. These lifecycle commands are CLI-only; REST, MCP, and the SDK do not add persistent watch endpoints.
Over MCP, gno_context builds one and gno_context_verify checks a saved one. The SDK and REST (POST /api/context) expose the same contract. The intended shape of an agent turn is: build one Capsule for the goal, reason only over its evidence, cite evidenceId values, and stop when coverage.complete is false rather than filling the gap from memory.
gno ask --verify is this pattern with the loop closed: generate against one closed Capsule, classify every substantive claim against the retained evidence, and withhold the draft below full support.
Indexed content is untrusted input. Markdown projections delimit every passage with a collision-resistant fence whose width and character are derived from that block, so a document containing fence characters cannot forge a closing boundary and escape into instruction space. Titles, headings, and configured context text stay JSON-escaped; passage bytes stay exact. The guidance block restates this inside the payload so a model reading the Capsule sees the contract too.
verify and watch.gno query.Against 48 paired tasks in the agentic retrieval benchmark, the promoted Capsule lane retained 100% task completion accuracy while reducing outer-agent retrieval calls by 48.94% and model-visible context by 44.12%, with 100% of substantive claims linked to an exact span and deterministic replay. The raw receipts, the pinned corpus, and the stated limitations ship in the repository — see benchmarks for the artifacts and the single-task outcome demo.