Skip to content

@openmoca/moca-core

The reference MOCA Reader, in TypeScript/JavaScript: open a package from a directory, a .moca archive or a host-supplied source; check it; compute its digest; verify attestations and evidence; resolve members; produce citation records; and search with one entry point over lexical, dense-sidecar or store backends. It implements the Reader class of the Reader contract, follows the Reader interface, and passes the conformance corpus.

Terminal window
npm install @openmoca/moca-core

Node.js 22 or later. Getting started takes you from install to a cited search result and a conformance run in five steps. Example packages are in moca-spec, and moca-examples has a command line and a chat built on this Reader.

The built-in lexical backend is BM25 (k1 1.2, b 0.75) over node text, or over sidecar chunks when a sidecar is bound. Every MOCA Reader tokenises the same way, so they return the same results:

  • NFKC-normalise, then lower-case each code point (simple case mapping).
  • Letters, digits and combining marks make words; anything else separates them. Words in scripts with vowel signs, such as Devanagari, stay whole.
  • Chinese, Japanese, Thai, Lao, Khmer and Myanmar text is split into each character (with its marks) and each pair of neighbouring characters.
  • No stemming. A host that needs it supplies its own lexical backend.
  • Without a locale, every language of a node is searched and its best match returned; with one, the representation package spec §5 selects.

Characters added in very recent Unicode versions can tokenise differently across Readers, because each language runtime ships its own Unicode data.

As Reader contract §14 asks:

Class Reader (the reference Reader)
Contract version 0.6.0
Optional capabilities All implemented: archives, host sources, Sigstore bundle verification (offline, online when online is set), sidecars (lexical and dense), the ontology profile
import { readPackage, Library, Search, LexicalBackend, directoryResolver } from '@openmoca/moca-core';
const pkg = await readPackage('kb', { trustRoot: 'trust-root.json', resolveMember: directoryResolver(['./packages']) });
pkg.valid; // boolean
pkg.digest; // 'sha256:…'
pkg.capabilities; // ['core', 'signed', ...]
pkg.diagnostics; // [{ code, severity, message, file?, line? }]
const library = new Library().add(pkg);
const search = new Search(library, { backend: new LexicalBackend(library), audiences: ['public'] });
await search.search('refund window', { limit: 5 }); // citation records, each with a score
library.get('https://example.com/moca/support-kb#refund-window.md', { locale: 'fr' });
Export Purpose
readPackage(target, options) Read and check a package. target: path, .moca/.zip path, or { list(), read(path) }. Options: trustRoot, resolveMember, strict, limits, online, allowOfflineFallback, tufCachePath.
Library Holds verified packages (and their sidecar chunks and index); citations(), get(), and search() as a synchronous lexical shortcut; applies relations. Takes a clock for testing.
Search One entry point over a backend: search(query, { limit, includeAll, locale, concepts, scope }), with optional hooks: { ingress, egress }. The gate always runs last (Reader contract §9). new Search({ digests, clock }, { backend }) searches a store from its ingest-time records.
LexicalBackend, DenseBackend, MemoryStoreBackend Backends: BM25 over package text or sidecar chunks; sidecar vectors with a host embedder (S006 on a model mismatch, S007 for a package without vectors); a reference in-memory store.
selectorMatches(selector, text) The evidence check behind evidence[].matched and C011.
bindSidecar(target, pkg) Check a sidecar against a package and return usable chunks.
directoryResolver(dirs) A simple member resolver over folders.
hostSource, archiveSource, directorySource Package sources.
loadTrustRoot, verifySignature, packageStatement, reviewStatement, createEnvelope Attestation primitives, shared with moca-sign.
computeDigest, packageFiles The digest algorithm.
validateAgainst(name, value), SCHEMAS The schemas/v1 schemas.
Library.structure Structure operations over the loaded packages and the host’s overlays: concept, requires, requiredBy, parts, narrower, broader, related, sequence, nodes. Each item names its layer. new Library({ overlays }) loads overlays.
ontologyGuided() The default ingress/egress hooks for Search.
HybridBackend({ lexical, dense, k, weights }) Opt-in: a lexical and a dense backend merged by Reciprocal Rank Fusion, Σ weight / (k + rank); k 60 and weights 1 by default, set by the host. Packages dense search skips come back through the lexical side.
diversify({ perNode }) Opt-in egress hook: each node’s best perNode results first (default 1), the rest after, so one node’s chunks don’t fill the list.
readStructure, structureView Parse structure.ttl (with n3) and print a sorted JSON view of it.
KNOWN_PROFILES, PROFILE_ONTOLOGY Recognised profiles; profile data stays opaque.
CODES, formatText, formatJson, formatSarif Diagnostics.

readPackage never executes package content and performs no network I/O, except online Sigstore checks when online is set. Ontology files are parsed locally; owl:imports is reported, never followed. Embedders are supplied by the host, never named by a package.

lib/schemas/ holds byte-identical copies of moca-spec’s schemas/v1, checked by npm run check:schemas.

The tests read moca-spec’s examples and fixtures. Check out moca-spec beside this repository, or set MOCA_SPEC_DIR. CI uses the tags pinned at the top of .github/workflows/test.yml (MOCA_SPEC_REF and the like); check out the same tags to match it.

Terminal window
npm install
npm test
  1. Add a dated section to CHANGELOG.md and update the version.
  2. Point the MOCA_*_REF pins in .github/workflows/test.yml at the release tags (moca-spec docs/releasing.md).
  3. npm test passes.
  4. Tag vX.Y.Z and publish a GitHub release whose notes are the changelog section.
  5. npm publish --access public from the tagged commit. Publish this package before the tools that depend on it.

Apache-2.0. See LICENSE and NOTICE.

OpenMOCA™ is a trade mark of PI & Mash Solutions Ltd. The licence covers the code, not the name: see the trade mark policy.