Skip to content

MOCA Reader Interface

Specification version: 0.6.0 Status: Before 1.0.0. A minor version may still change the format; each change is in MIGRATIONS.md. License: Apache License 2.0

The Reader contract says what a Reader must conclude and how it must behave. This document names the operations and objects every MOCA Reader offers, once for all languages, so that the Readers for different languages look alike to the people who use them.

The names here are logical. Each language uses its own conventions: for example readPackage in TypeScript, ReadPackageAsync in .NET and read_package in Python are the same operation. Where this document and the contract disagree, the contract takes precedence.

MOCA has three pillars:

Pillar What it is
MOCA Package The open standard.
MOCA Reader The open-source library that reads packages, one per language. Applications read package content through it: for RAG or any other search, for structure navigation and for citation.
MOCA Application The product built on a Reader and an agent harness.

Each language has its own Reader repository. The TypeScript reference Reader is @openmoca/moca-core.

The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY and OPTIONAL are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in capitals. Terms are as defined in package specification §2.

Part Does Must not
Read Open, check, digest, verify, resolve members, and build citation records. Execute package content, or act on a location or setting a package supplies.
Search One search over a backend the host chooses, with the retrieval policy applied in its gate. Reimplement a vector database or an embedding stack.
Structure Answer structure operations over the packages and the host’s overlays. Enforce what the structure says; that is the application’s job.
Bindings Present citation records in a framework’s own types. Change what a citation record says.

Everything a Reader touches outside a package’s bytes comes from the host (Reader contract §4).

Object Shape Used for
Package source Lists a package’s file paths; returns the bytes of a listed path. Reading packages from memory, blob storage or a database.
Member resolver Given a member’s id, version and pinned digest, returns a package target or nothing. Composition.
Trust root A trust-root document (schema). Verifying attestations.
Clock Returns the current time. stale, inForce, and whether a trust-root key has expired.
Limits Entry, byte, frontmatter, structure and evidence limits (contract §3). Safety with untrusted packages.
Overlays { id, layer, source }, where layer is application or organisation and source is Turtle. Adding the application’s and the organisation’s structure and vocabulary.
Search backend §5.2. Search.
Embedder §5.3. Dense search.
Retrieval hooks ingress and egress (§5.4). Ontology-guided retrieval strategies.
Audience set A list of audience labels. Removing records outside it.

A package never supplies any of these.

Operation Takes Returns
readPackage A target (a directory, archive path, archive bytes or package source) and options: trust root, member resolver, limits, strict, clock, require signature. A package result. Never throws for a malformed package.
bindSidecar A sidecar target and a package result. { usable, index, chunks, diagnostics }.
Library(options) Clock, overlays, limits. An empty library.
Library.add A valid package result, and optionally its sidecar chunks and index. The library, with the package and its resolved members loaded.
Library.citations Options: locale, include text. Every node’s citation record.
Library.get A node id or a versioned node reference, and options: locale. One citation record, or nothing.

A package result has at least these fields, with the meanings in the contract:

  • manifest, digest and payloadManifest;
  • nodes, members and profiles;
  • structure;
  • diagnostics, valid and capabilities.

A diagnostic has code, severity and message, and optionally file and line.

Operation Takes Returns
Search(source, options) A library, or, for a store backend, the loaded packages’ states (packageState) and a clock; then a backend, an audience set and optional hooks. A search.
Search.search A query and options: limit, includeAll, locale, concepts, scope. Citation records, each with a score. Best first, unless an egress hook ordered them.

Every call follows Reader contract §9.2. includeAll is the host’s opt-in from contract §8; a host that lets a caller set it has chosen to.

A backend has:

  • features: lexical or dense, plus filterPushdown;
  • search(query, { limit, filters }), which returns hits valid against search-hit.schema.json;
  • diagnostics: findings about the backend itself, for example S006_MODEL_MISMATCH or S007_NO_VECTORS.

Every Reader provides a lexical backend over the loaded packages’ own text. A Reader that reads sidecars may provide a dense backend (semantic search) over their vectors. A hybrid backend combines a lexical and a dense backend by Reciprocal Rank Fusion, with weights and a constant the host sets (Reader contract §9.6). A store backend wraps the host’s own vector store. It is usually part of a binding. It stores whole citation records at ingest, and returns each one with its hit.

The host supplies the embedder:

  • name, an optional version, and dimensions, compared with an index’s model (Reader contract §9.3);
  • optionally queryPrefix and documentPrefix: the text it puts before each query and each document, declared so they can be compared with an index’s;
  • embed(texts, { role }), which returns one vector per text. role is query or document: a Reader passes query when it embeds a search query, and document when a store backend ingests content. The embedder applies its own model’s convention for each role, such as the query: and passage: prefixes of e5.

A Reader MUST NOT choose, download or configure an embedder, and MUST NOT add text to what it embeds.

Ontology-guided retrieval is a strategy, not a fact, so it is pluggable:

  • ingress(query, ctx) may return { query, concepts, scope }, which change what the backend searches;
  • egress(candidates, ctx) returns the candidates, possibly reordered, and possibly with records added from structure operations. Each added record is tagged retrieval: { via, from }.

ctx holds the request, the library, its structure operations, the audience set and the clock, all read-only. The gate runs after both hooks, so no hook can return what the retrieval policy excludes. Each Reader ships a default strategy, ontologyGuided, which the conformance corpus tests, and which behaves the same in every Reader:

  • ingress: every declared concept whose preferred label’s words (letters and digits, lower-cased) all occur among the query’s words is matched; the search is then narrowed to those concepts and their descendants;
  • egress: after each candidate, for each concept it is bound to, the nodes bound to every concept that concept transitively requires are added, in dependency order, each once, in the request’s locale and tagged retrieval: { via: "requires", from: <concept> }.

Domain extensions. A domain extension, such as a legal, procedures or course extension, is a set of hooks plus a vocabulary overlay. It is built on the standard Reader, never as a separate Reader, and lives in its own repository with its own tests.

Library.structure answers the operations in Reader contract §10. They run over the merged structure of every loaded package and every overlay, and each item carries its layer:

Operation Returns
concept(iri) The concept, or nothing
requires(iri, { transitive }), requiredBy(iri) Concept items
parts(iri), narrower(iri, { transitive }), broader(iri), related(iri) Concept items
sequence(iri) Ordered concept items, or nothing
nodes(iri, { include }) Citation records

A binding maps citation records to a framework’s own types, and a framework’s query to Search.search. It lives in the language Reader’s repository or its own, never in the framework.

Framework Type a binding provides Language
LangChain / LangGraph A retriever returning documents Python, TypeScript
LlamaIndex A retriever returning nodes with scores Python, TypeScript
Microsoft Agent Framework A context provider .NET, Python
Microsoft.Extensions.VectorData A store backend over any supported vector store .NET
Model Context Protocol Server resources and tools Any; the reference is moca-mcp

A binding MUST carry the whole citation record in the framework type’s metadata, including node.ref. When the framework needs flat metadata, the binding MUST at least use the fields in the consuming guide’s metadata table, including the package digest. The text it hands to a model follows Reader contract §12.

Library.get, Library.citations and nodes are unfiltered host APIs: a host ingests from them into its own store, which applies the policy at query time. A binding that hands a record to a model or a user (a search tool, a node lookup, a resource list or read, an AG-UI citation) MUST apply the host’s audience set and, unless the host opted in, the default retrieval policy (Reader contract §8) to every such record. In a binding a model calls, the opt-in to excluded content and to unlabelled content is host configuration, never a tool argument.

A Reader in any language shows conformance by running the corpus through the runner protocol in conformance/README.md. It ships only when it passes every case, except those that need an optional feature it names as not implemented (Reader contract §14).