Vector store
Choose where Deskbell keeps its search index, pgvector inside Postgres by default or a Weaviate cluster you already run, and how to move between them.
Deskbell stores each chunk's vector in exactly one place: the vector store you
configure. DESKBELL_VECTOR_STORE selects it. Choose before you add your first
source: changing it later means re-embedding everything (see Switch vector
stores).
| Variable | Default | Description |
|---|---|---|
DESKBELL_VECTOR_STORE | pgvector | Which store holds the chunk index. pgvector uses the Postgres database Deskbell already runs on; weaviate uses a Weaviate cluster you operate. Set the same value on the web app and the worker. |
Whichever store you choose, Postgres keeps every chunk's text, position and state and records which store holds its vector. The pgvector extension stays installed on both drivers: gap clustering keeps its own embeddings in Postgres.
Backends
Switch vector stores
Vectors are not copied between stores. Switching re-embeds every chunk into the new one, with the embedding model you have configured.
Configure the new store
Set DESKBELL_VECTOR_STORE and the store's variables on the web app and the
worker, then restart both. In Docker Compose that is .env plus
docker compose up -d.
Re-embed
Open Sources. A notice reports how many chunks are still indexed in the previous store. Press Re-embed all content. The job reads every chunk's text from Postgres, embeds it and writes the configured store. It resumes after a restart; a second press is harmless.
Drop the old index
When the notice is gone, the previous index holds nothing Deskbell reads. Delete the Weaviate collection if you left Weaviate; if you left pgvector there is nothing to do, because each row's vector was cleared as it moved.
Warning: until the job finishes, retrieval searches the new store, which fills as chunks move; questions about content that has not moved yet are refused. Switch outside busy hours. The job costs embedding tokens for the whole corpus, cents to a few dollars at the sizes Deskbell indexes, with the default model.
Tested: pgvector → Weaviate and Weaviate → pgvector.
Check and repair
pnpm vector-store:prune [--org <id>] [--dry-run]Compares a Weaviate collection with the chunk rows. Objects whose chunk no longer exists are deleted. Rows that claim an object the collection does not have (after a Weaviate restore from an older backup, for example) are reported; Re-embed on the Sources page repairs them. Safe to run at any time; it never writes to Postgres.
Run Weaviate locally
One container is enough to try the driver:
docker run -d --name weaviate -p 8080:8080 -p 50051:50051 \
-e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
-e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
semitechnologies/weaviate:1.32.0Set DESKBELL_VECTOR_STORE=weaviate and WEAVIATE_URL=http://localhost:8080 for
pnpm dev and the worker, re-embed if the database already has content, and ask
the widget something. The evaluation harness runs against whichever
store is configured, which is how to confirm a switch changed nothing about answer
quality.
How retrieval uses the store
The store answers one question: which chunks are nearest to this vector, and, in hybrid mode, which match these words. Deskbell then reads the winning rows from Postgres for titles, URLs and text, and cites them. Scores are cosine similarity on both drivers, so every threshold on the configuration page keeps its meaning whichever store you run.
Models and providers
Deskbell runs on OpenAI, Anthropic for chat, Google, or a fully local model through Ollama, plus anything speaking the OpenAI-compatible protocol.
Production checklist
What to change before a Deskbell instance faces the internet, starting with claiming the owner account before anyone else can.