Skip to main content

Knowledge base & retrieval

Two settings decide whether your knowledge base answers questions semantically or only by keyword, and neither of them is named in a way that makes the answer obvious. This page is the short version of both.

Auto-indexing is opt-in since v0.1.18

LIBRA_OS_SUPERNOVA_ENABLED defaults to false from v0.1.18 onward — the current v0.1.19 line carries the same default. If you are coming from an earlier release and rely on uploaded documents being indexed automatically, set it:

LIBRA_OS_SUPERNOVA_ENABLED=true

Without it, documents are stored but never parsed, chunked, embedded or retrievable. Nothing errors at request time — retrieval simply returns nothing. Boot logs it at level=ERROR and GET /api/capabilities reports it.

The default changed because auto-indexing reads every object under your documents root. That should be a decision you make, not one you discover.

Only one backend holds vectors

LIBRA_OS_VECTOR_BACKEND chooses where knowledge chunks live. Configuring an embedding model does not by itself mean retrieval uses embeddings — that depends entirely on which store you land on.

valuevector searchsurvives restart
surrealyes — hybrid keyword + semanticyes
pgvectorno — keyword only, despite the nameyes
qdrantno — keyword only, despite the nameyes
memoryyesno — wiped on every restart
auto (default)only if SurrealDB connectsdepends

If you want semantic retrieval, deploy SurrealDB. There is no other option today.

pgvector is the one to watch: it reads like the vector-capable choice, and it is the one you would reach for if what you wanted was durability. A deployment can end up with a correctly configured embedding endpoint, a clean startup, and keyword-only search.

Confirm retrieval is actually working

Ask the deployment rather than inferring it from configuration:

curl -s $LIBRA_OS_URL/api/capabilities | jq .retrieval
{
"vector_search": true,
"backend": "surreal",
"durable": true,
"embedder_configured": true,
"embedding_model": "Qwen/Qwen3-Embedding-8B",
"verdict": "vector retrieval ACTIVE (hybrid lexical + cosine)"
}

Read verdict first — it states the consequence, not the setting. The same response carries a per-collection breakdown, including whether each collection's documents were actually embedded:

{ "id": "matters", "chunks": 437, "documents": 136, "embedded": "yes", "retrievable": true }

embedded can be no or partial on a vector-capable backend — a collection ingested before embeddings were configured, or while the embedding endpoint was failing, holds chunks that only keyword matching can reach. Re-ingest those.

Two more places answer the same question:

libraos doctor deployment # includes a "vector retrieval" check
libraos config --effective # embedding.endpoint, embedding.model, vector.backend

Scope auto-indexing before you enable it

Unconfigured, auto-indexing puts every object into one shared default collection. If your application separates content per customer, per matter or per case, that collapses those separations into a single index.

VariableEffect
LIBRA_OS_SUPERNOVA_COLLECTION_TEMPLATERoute by path: matter-{path[1]} sends cases/<id>/uploads/x.pdf to collection matter-<id>.
LIBRA_OS_SUPERNOVA_IGNORE_PREFIXESNever index these prefixes, e.g. kyc/,identity/.
LIBRA_OS_SUPERNOVA_ALLOW_PREFIXESWhen set, index only these prefixes.

Two properties worth relying on:

  • Exclusions apply before the file is opened. An ignored prefix is never read, parsed or embedded — not filtered out afterwards. If you have content you are contractually forbidden to send through AI retrieval, this is the control to use. A file-extension check is not one.
  • Ignore beats allow, and a path that cannot satisfy the collection template is skipped rather than falling back to default.

To turn auto-indexing off durably, use the environment variable above. POST /api/super-nova/emergency/pause works but is held in memory only, so a restart, upgrade or reboot resumes indexing.

Running SurrealDB

The surrealdb/surrealdb:v3 image runs as a non-root user (uid 65532) and v3.2.4 removed the file:// scheme. A fresh named volume is root-owned, so the container cannot initialise its database and restart-loops. Use a bind mount owned by the container user, a rocksdb: path, and a generated password:

mkdir -p /opt/libraos/surreal-data && chown 65532:65532 /opt/libraos/surreal-data
docker run -d --name surrealdb -p 127.0.0.1:8010:8000 \
-v /opt/libraos/surreal-data:/data surrealdb/surrealdb:v3 \
start --user root --pass "$STRONG_PASSWORD" rocksdb:/data/database.db

Bind to 127.0.0.1 and never accept a default password. Then point LibraOS at it with LIBRA_OS_SURREAL_URL=ws://127.0.0.1:8010/rpc plus LIBRA_OS_SURREAL_USER and LIBRA_OS_SURREAL_PASS.

Changing the vector backend does not move your data

LIBRA_OS_VECTOR_BACKEND selects where chunks live; changing it does not migrate what is already stored. Collection metadata survives, so listings and search still respond — from whatever fraction made it across.

Plan a backend change as a re-ingest. To move one collection without a running server:

libraos knowledge export <collection-id> -o collection.zip # from the old backend
# change LIBRA_OS_VECTOR_BACKEND, restart
libraos knowledge import collection.zip # re-embeds into the new store

Startup warns, per collection, when the active store holds materially fewer chunks than your database does.

Verify the binary you deployed

Every release carries a checksum manifest:

TAG=v0.1.19 # or the tag you are installing
gh release download "$TAG" --pattern "libraos-$TAG-*"
sha256sum -c --ignore-missing "libraos-$TAG-SHA256SUMS"

The public mirror publishes its own SHA256SUMS over the stable filenames.