Search, embeddings and retrieval-augmented generation
Memories supports keyword and semantic retrieval over authorized ordinary memory and knowledge cards. Document ingestion accepts UTF-8 text and Markdown and creates a normal encrypted knowledge card. PDF/DOCX/binary file extraction is not automatic; convert them to text before explicit ingestion. Private content, credentials and file assets are excluded from retrieval.
Quick start
Use the same home/config for the CLI and running daemon. Restart the daemon after upgrading or changing model configuration. Initialize/unlock as usual, then:
memories rag ingest VAULT_ID notes.md --title "Research notes"
memories memory search VAULT_ID "Chinese English keywords"
memories rag search VAULT_ID "keywords" --mode bm25 --match-mode all
memories rag model-install
memories rag index VAULT_ID
memories rag search VAULT_ID "Find similar meaning" --mode vector
memories rag search VAULT_ID "Find evidence" --mode hybrid --limit 8
memories rag status VAULT_ID
memories rag ask VAULT_ID "What does the evidence say?"
rag ask requires a generation URL in the daemon configuration. To use lexical
RAG without an embedding model, add --mode bm25; the generation URL is still
required. memory_search remains lexical. Advanced search returns document
chunks with asset/revision IDs, stable chunk hashes, original UTF-8 byte offsets,
scores and citation labels. [S1] identifies a source within one result; use its
id and revision fields for ordinary memory read, not the chunk hash.
Chinese BM25 and chunks
Chinese and mixed-language text are tokenized with Jieba. Titles, bodies and safe
metadata participate in FTS5 BM25 ranking, weighted 5/1/2. any (default) combines
keywords; all requires every query term; phrase requires the original phrase.
Strict all/phrase constraints also filter vector/hybrid candidates. Queries
are escaped, not interpreted as arbitrary FTS operators.
Text is split near sentence/paragraph boundaries into chunks of up to 768 Unicode
characters, normally overlapping by 128 characters. Returned offsets address the
original UTF-8 body. Search is bounded to 100 requested results, 64 lexical terms
and 1,024 query bytes. Basic memory search groups chunks by document; advanced
RAG retrieval returns individual chunks. --cards-only narrows retrieval.
Indexes are reused between queries. A vault mutation, sync or policy change invalidates its cached index; locking/restarting clears all indexes and vectors. They are not persisted as plaintext or added to encrypted sync payloads. Limits per cached vault are 10,000 chunks, 16 MiB of source text/metadata and 32 MiB of vectors; at most two vaults are cached. Large libraries still face the underlying whole-state persistence limits described in performance.
In-process EmbeddingGemma
The default embedding backend is Google's EmbeddingGemma 300M Q4 via native ONNX inference. It runs inside the Memories daemon, with no Ollama, Python or separate inference service required. The application includes the inference engine with ONNX telemetry explicitly disabled before session creation; the model/tokenizer files (about 209 MiB) are installed once by the app:
memories rag model-install
The installer downloads a pinned onnx-community/embeddinggemma-300m-ONNX
revision, verifies SHA-256, supports ranged downloads/retries, and never replaces
an existing mismatching file. Existing verified files are reused. The default
directory is models/embeddinggemma under the selected Memories home. Supply an
existing directory with rag.local_model_dir; it must contain the Q4 ONNX graph,
its external data and the tokenizer/config files. Restart the daemon after
changing model files. Weights are governed separately by the Gemma Terms of Use
and Prohibited Use Policy; the installer writes a notice and upstream model card.
[rag]
local_model_dir = "./models/embeddinggemma"
local_threads = 4
max_tokens = 2048
# Optional mirror of the exact pinned files:
# model_download_base_url = "https://your-mirror.example/embeddinggemma"
Relative model paths are resolved beside the config file. Lower local_threads
limits CPU use; max_tokens bounds tokenizer input and can truncate long inputs
when set below the chunk's token count. Embeddings are 768-dimensional normalized
vectors. The model uses separate query/document task prefixes. rag index warms
the index; vector/hybrid retrieval also computes missing embeddings on demand.
A five-minute operation budget is checked between steps; completed batches can
be reused on retry while the vault/model remain unchanged and unlocked.
Customer-supplied model URLs
Gemini Embedding is an online API, not the offline EmbeddingGemma model. Add
rag.embedding to select a remote provider; omit it to keep embeddings local.
Use full operation URLs and configure the model expected by your service:
[rag.embedding]
protocol = "gemini"
url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:embedContent"
model = "gemini-embedding-001"
dimensions = 768
api_key_env = "GEMINI_API_KEY"
[rag.generation]
protocol = "gemini"
url = "https://generativelanguage.googleapis.com/v1beta/models/YOUR_MODEL:generateContent"
model = "YOUR_MODEL"
api_key_env = "GEMINI_API_KEY"
Set the named API-key environment variable in the daemon's environment. Do not
put key values in TOML, URLs or command arguments. Gemini uses x-goog-api-key;
protocol = "compatible" uses Bearer authentication and common
{model,input} embedding / chat-completion JSON formats. The compatible
embedding response must contain indexed data entries with embedding arrays;
generation returns choices[0].message.content. Keys are optional for local
services. Remote URLs require HTTPS; HTTP is accepted for loopback only.
Optional embedding dimensions is sent as Gemini outputDimensionality or
compatible dimensions, checked on receipt and bound into the vector-space key.
Credentials, query strings and fragments are not accepted in operation URLs.
There is no implicit public model endpoint. Configuring a remote embedding URL allows eligible document chunks to be sent there. Generation sends only the selected chunks and question; no stored credential/private/file content enters this pipeline. These configuration settings belong to the daemon, not individual MCP calls. See security.
Hybrid search and reranking
Vector mode uses cosine similarity. Hybrid mode merges BM25 and vector rankings
with reciprocal-rank fusion (k=60). Default lightweight reranking boosts term
coverage and phrase matches. It does not claim to be a learned cross-encoder.
Configure a learned reranker service when desired:
[rag.rerank]
protocol = "compatible"
url = "https://your-reranker.example/rerank"
model = "YOUR_RERANKER"
api_key_env = "RERANK_API_KEY"
The request is {model, query, documents, top_n}. Its response must contain
results with a unique valid index and finite relevance_score for every
candidate. Unknown/duplicate entries fail instead of silently reordering the
wrong document. --no-rerank skips both optional reranking stages.
Proxies, timeouts and retries
[rag.http]
use_env_proxy = true
proxy_url = "http://127.0.0.1:7890"
retries = 2
backoff_ms = 500
connect_timeout_seconds = 10
timeout_seconds = 60
download_timeout_seconds = 900
Explicit proxies override environment proxy discovery. HTTP, HTTPS, SOCKS5 and SOCKS5h URLs are supported. Authenticated proxy values can be supplied through the proxy environment; TOML proxy URLs cannot contain credentials. Loopback model/mirror endpoints always connect directly. TLS verification stays enabled.
retries is the number of extra attempts (0-5). Model API connection/read
failures, 429 and 500/502/503/504 can retry with exponential backoff; Retry-After
seconds are honored up to 30 seconds. Authentication/validation errors, unsafe
redirects and malformed model output are not retried. Model API redirects are
disabled. Download redirects require HTTPS and every final file is hash-checked.
The download timeout is a per-file budget. Retrying generation can incur extra
provider billing. Authorization/cancellation is rechecked between attempts.
Answers, citations and MCP
memory_retrieve exposes scoped retrieval to MCP clients; memory_ask calls the
configured generation service. Both preserve the grant's vault and ordinary-data
restrictions. They cannot select an arbitrary endpoint or access a credential.
Device-only vaults reject operations that would send data to non-loopback model
endpoints; local inference and explicitly configured loopback services work.
The older memory_search and memory_read tools continue to work. The bundled
Memories skill documents memory_retrieve and memory_ask for AI clients.
After upgrading, replace an older installed skill with
memories inject all --force.
Generation receives source text as untrusted data and has no application tools.
The model must return structured answer/citation JSON, with citations such as
[S1] that actually exist in the result. Invalid or invented IDs are rejected.
When there is no evidence, no generation call is made and the result marks
insufficient_evidence. Citation validation checks references, not whether every
claim is factually supported; review important answers against their sources.
Lock, expired/revoked grants and changed source state invalidate in-flight work and suppress late results. An already started remote request cannot be recalled. No model-backed RAG interface is added to the mobile FFI in this release; mobile ordinary search receives the Chinese/BM25 improvements and can use BM25 retrieval.