Crux
GuidesRetrieval & Knowledge

Knowledge Bases

Index, reindex, remove, retrieve, ground, scope, and inspect a Connected Knowledge base.

knowledgeBase() is the high-level facade for indexing and reading one corpus. Use it when one definition should own storage, embeddings, lifecycle, retrieval, tools, grounding, views, assertions, communities, and namespace scoping.

Use the lower-level Retrieval APIs when you only need a custom retriever() or direct indexer() control. See Querying and Indexing documents for those layers.

Minimal Setup

import { embedding } from "@use-crux/core/embedding";
import { knowledgeBase } from "@use-crux/core/knowledge";
import { inMemoryStorage } from "@use-crux/core/storage";

const dense = embedding({
  kind: "dense",
  name: "demo-dense",
  dimensions: 2,
  maxInputTokens: 1000,
  batch: { maxSize: 8 },
  embed: async (inputs) =>
    inputs.map((input) => {
      const text = input.type === "text" ? input.text.toLowerCase() : "";
      return text.includes("refund") ? [1, 0] : [0, 1];
    }),
});

const docs = knowledgeBase({
  id: "docs",
  storage: inMemoryStorage(),
  embeddings: dense,
});

await docs.index([
  {
    namespace: "docs",
    sourceId: "refunds.md",
    content: "Refunds are available within 30 days of purchase.",
    metadata: { section: "policy" },
  },
]);

const hits = await docs.retriever({ limit: 3 }).retrieve("refund window");

id is the stable identity used by the indexer, retriever, recipe traces, and knowledge records. If you do not pass a corpus, the default namespace is the same as id.

Configuration

OptionUse it for
storageOne bundle that supplies records and search.
records and searchExplicit store overrides when you do not use a bundle.
embeddingsDense vector indexing and dense retrieval.
sparseEmbeddingsSparse or fused retrieval.
chunkingShorthand chunking options for simple document indexing.
pipelineNamed indexing pipeline with transforms, chunker, cache identity, and derive stages.
metadataSchemaRuntime metadata validation plus typed filters and views.
lifecycle.retentioncleanup by default, or retain-inactive for replaced generations.
sourceDeferred input used when index() or reindex() is called without arguments.
corpusReuse an existing corpus ledger. Its id must match the knowledge base id.
communitiesCommunity report configuration for broad connected search.

Pass either chunking or pipeline, not both:

import { chunker, indexingPipeline } from "@use-crux/core/indexing";

const docs = knowledgeBase({
  id: "docs",
  storage,
  embeddings: dense,
  pipeline: indexingPipeline({
    chunker: chunker.structured({ maxChars: 1200, overlapChars: 150 }),
  }),
});

Use Embeddings and Chunkers for the embedding and chunking choices. The Connected Knowledge pages focus on the surfaces built on top.

Index, Reindex, And Remove

index() replaces each source it receives. reindex() treats the input as a complete source set and removes stale sources. remove(sourceId) deletes a source from active retrieval immediately.

await docs.index([
  { namespace: "docs", sourceId: "a.md", content: "Alpha" },
]);

await docs.reindex([
  { namespace: "docs", sourceId: "b.md", content: "Beta" },
]);

await docs.remove("b.md");

When metadataSchema is configured, invalid metadata is rejected per source. Direct indexing can write valid sources and then throw an aggregate metadata error for invalid sources. Corpus-backed indexing reports invalid sources as failed source outcomes.

Mutation Effects

Public source mutations emit native Effect receipts for the durable mutation: index(), reindex(), remove(sourceId), and corpus-backed sync. The receipt uses the knowledge-base id, namespace, operation, source ids, and safe outcome counts as its resource summary. Inspect and recover these receipts through the Effects APIs; knowledge bases do not keep a separate receipt store.

Recovery is audit-first. index() reports recovery unavailable: an interrupted generation replacement normally leaves the prior active records serving until a new generation durably publishes, but Crux does not keep a generic restore handler for the mutation. reindex() and remove() report irreversible because they can delete active sources or stale sources that cannot be reconstructed from the receipt. Corpus-backed index() reports unavailable, while corpus-backed reindex() reports irreversible when it deletes stale sources.

Connected Knowledge derivation, claim compilation, view maintenance, retrieval, and community materialization are ordinary internal work. They run after the mutation receipt settles, and their failures do not change the mutation Effect outcome.

Read Surfaces

A knowledge base exposes the Retrieval surfaces directly:

const retriever = docs.retriever({ search: { dense: true }, limit: 6 });
const recipe = docs.recipe();
const tools = docs.tools({ prefix: "docs", include: ["search", "getSource"] });
const grounded = docs.grounding({
  query: ({ input }) => input.question as string,
  citations: { required: true, quotes: "required" },
});

recipe() with no arguments creates a default retrieve() recipe. Pass steps when retrieval should include relation expansion, reranking, compression, or global search.

Scope By Namespace

Use scope() when one definition serves multiple tenants or logical corpora. The scoped handle changes storage keys and graph visibility, not just a query filter.

const tenantDocs = docs.scope({ namespace: "tenant-a" });

await tenantDocs.index([
  {
    namespace: "tenant-a",
    sourceId: "policy.md",
    content: "Tenant A policy.",
  },
]);

const tenantHits = await tenantDocs.retriever().retrieve("policy");

Scoped handles do not expose scope() again. Views, assertions, communities, relations, and hydrated recipe hits stay inside the scoped namespace.

Inspect Lifecycle

const inspection = docs.inspect();

console.log(inspection.namespace);
console.log(inspection.capabilities.legs.lexical);
console.log(inspection.lifecycle.indexedSources);

inspect() reports configured storage, per-leg search capabilities, fusion, filter support, source strategy, and lifecycle counters. It does not read retrieved content.

On this page