Each server.py search/rebuild invocation was a fresh process that reloaded
the embedding and reranker models from disk before answering a single
query. Add an optional daemon (server.py daemon) that keeps both models
resident in memory and serves repeated queries, across repository roots,
over a local socket/pipe.
search and rebuild now try the daemon first, spawn one on a cache miss
(guarded by an exclusive lock file to avoid duplicate spawns), and fall
back to the original one-shot in-process worker if the daemon cannot be
reached or started, so behavior is unchanged when the daemon is
unavailable. The daemon exits on its own after 30 minutes of inactivity.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pin the Qwen embedding/reranker models to specific commit revisions (and
sentence-transformers to the exact version already in use) so index
builds are reproducible instead of floating on each model's main branch.
Also move the encoder and reranker instances to module-level singletons
shared by every Index, instead of one pair per instance, so a process
serving multiple repository roots only loads each model once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Repositories with more than 2000 indexable files silently lost the
remainder during indexing. Make the cap configurable via
SEMANTIC_RETRIEVAL_MAX_FILES (default unchanged) and print an explicit
stderr warning naming the repository when it is reached, instead of
truncating without any signal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>