Skip to content

When content becomes searchable — indexing (Desktop vs. Web)

All

For content to appear in chat (RAG) and in search, it must be indexed. Which search backend handles that is explained in RAG & search. This article answers the other question: when indexing happens — and why it differs between Desktop and Web and across write paths.

Write pathDesktopWeb
KB editor (save / rename / move / delete)incremental, immediateincremental, immediate
Chat & agent tool (create_knowledge_article / update_knowledge_article)incremental after saveincremental after save
Import promotionno incremental trigger — picked up by the periodic runno incremental trigger — picked up by the periodic run
”Re-index” (force re-index)full run over the corpusfull run over the corpus

“Incremental” means only the affected path is re-indexed — the content is searchable practically immediately. The editor and the chat/agent tools trigger this right after saving.

Note: Until cw-app#348, articles created via the chat/agent tool on Desktop were not indexed automatically. That is fixed — these write paths now behave like the editor.

At application startup an “only-if-empty” gate applies: a full index runs only if the vector store is empty or absent (e.g. first launch). An already-populated store is deliberately not re-run at startup — otherwise every boot would re-embed the corpus, which is expensive and unnecessary.

Practical consequence: after the first successful index, the incremental triggers and the periodic run keep things current — not the restart.

In addition, a periodic reconciliation synchronizes the corpus with the index (this is what picks up import promotions, for example):

  • Web: scheduled via the interval Knowledge:IndexIntervalMinutes (default: 60 minutes). → Environment variables & appsettings
  • Desktop: also runs since cw-app#348 — but only ticks while the app is open. Closed app = no cron. (This applies to scheduled tasks on Desktop in general. → Web vs. Desktop)

Every local vault (internally “Local-typed”) marked as indexed is captured automatically — both the built-in personal vault and every user-created local vault. Concretely:

  • Immediately on writes via the editor or the chat/agent tool (incremental).
  • Otherwise within IndexIntervalMinutes at the latest, via the periodic run.

Api-typed vaults (content of a peer/server) are indexed where they live and skipped locally — no double indexing.

The lightweight in-memory BM25 file search is always warm and serves two roles (see RAG & search): when a vector backend is active it runs alongside as the second hit list of hybrid search; when no vector backend is reachable it carries search alone. In either case there is no incremental IndexPathAsync — the BM25 file search maintains itself separately from the vector index. The current backend status, and whether a vector store is active, is shown in the admin Vector store tab (visible when sqlite-vec is the active backend).

Troubleshooting: “My article doesn’t show up in search”

Section titled “Troubleshooting: “My article doesn’t show up in search””
  1. Wait briefly / check the write path. Editor and chat/agent writes index immediately; an import promotion is only picked up by the periodic run (up to IndexIntervalMinutes).
  2. Desktop: Was the app closed in the meantime? Then the periodic run didn’t tick — open the app and wait briefly.
  3. Vault indexed? In the admin Vaults tab the vault must be marked as indexed. → Knowledge areas (vaults) & indexing
  4. Check the backend. Status in the admin Vector store tab; if no vector service is reachable, BM25 applies (lower result quality). → Set up Qdrant
  5. Force it. If the content still doesn’t appear, trigger “Re-index” (force re-index) in the admin area — a full run over the corpus. A re-index is also required after an embedding change.