How Trove Works
Trove is a Cloudflare Worker that ingests content from your sources, stores it across three storage layers, and makes it searchable through the Trove connection and a GraphQL API.
Sources --> Sync --> Ingest Pipeline --> Storage --> Search/API --> AI Assistants & AppsStorage Layers
Section titled “Storage Layers”Trove splits storage across three services, each optimized for a different access pattern.
Metadata (D1)
Section titled “Metadata (D1)”Each user gets their own SQLite database (Cloudflare D1) for document metadata: titles, authors, dates, tags, and preview text. There are no user_id columns. The database itself is the user’s data.
Search results, document listings, and source stats all read from D1 without touching object storage.
Full Text (R2)
Section titled “Full Text (R2)”Complete document text stored in Cloudflare R2. Keys are prefixed with the user ID ({userId}/docs/{documentId}/{artifact}), so one prefix is a user’s entire footprint. Full text is loaded only when explicitly requested. List views and search results use preview text from D1.
Embeddings (Vectorize)
Section titled “Embeddings (Vectorize)”Semantic embeddings stored in Cloudflare Vectorize. A shared index across all users with a mandatory user_id metadata filter on every query. Documents are represented as 1024-dimensional vectors. Search queries are compared against them using cosine similarity.
Ingest Pipeline
Section titled “Ingest Pipeline”When content arrives — pushed by a sync client through the Sync API, or written by a manual save — it passes through a deterministic pipeline.
- Dedup. Check if
(feed_id, external_id)already exists. Skip duplicates. - Preview. Extract the first ~300 words for fast display in search results and list views.
- Store. Write metadata to D1, full text to R2.
- Chunk. Split text into overlapping chunks using a content-type-aware splitter.
- Embed. Generate vector embeddings via Workers AI using the bge-m3 model (1024 dimensions), batched up to 100 chunks per call.
- Index. Upsert vectors to Vectorize with user_id and other metadata for filtering.
The pipeline processes batches of up to 50 documents and typically completes in 5-10 seconds.
Search Pipeline
Section titled “Search Pipeline”When you search:
- Your query is embedded using the same bge-m3 model.
- Vectorize performs a cosine similarity search with a mandatory user_id filter plus any additional filters (source, author, date range, content type, tags).
- Matching document IDs fetch metadata from D1.
- Results are assembled with snippets (the most relevant text chunk), document metadata, and relevance scores.
- Optionally, an AI reranker refines the result ordering.
Total search latency is typically 35-55ms without reranking, 55-75ms with reranking.
The Connection
Section titled “The Connection”AI assistants reach all of this through one connection, served over MCP. It supports two transports.
- Streamable HTTP (
POST /mcp). Stateless Workers with sessions backed by KV (1-hour TTL). Used by most MCP clients including Claude Desktop and Cursor. - WebSocket. Durable Objects per user with hibernation (zero cost when idle).
Both transports run the same JSON-RPC 2.0 protocol and expose the same 8 Core tools, plus the tools of any toolkits you’ve enabled.
Syncing
Section titled “Syncing”Trove does not fetch from your sources on its own. A sync client — the Trove Mac app, or your own code built against the Sync API — owns the sync loop.
- The sync client reads the source’s stored cursor to know where it left off.
- It fetches new content from the upstream system (handling its own scheduling, credentials, and retries).
- It pushes the results to Trove via the Sync API, which runs the ingest pipeline.
- Trove advances the source’s cursor and sync timestamp, and the client records a
SyncRun.