Sources
A source is a thing that fills your Library — it continuously pulls content into your Trove knowledge base: a blog’s RSS feed, your Hacker News upvotes, a podcast subscription, a folder of notes. The code behind a source is a source adapter: a small project — manifest.json + index.ts — and Trove handles everything downstream: transcription, embedding, indexing, dedup, search, and serving to Claude.
A source is the unit of “a thing you connected.” Each source has one or more feeds (individual publications or accounts) and produces documents: full text plus metadata. Your code’s only job is to return documents; Trove takes it from there.
Collect vs. serve: the two authoring paths
Section titled “Collect vs. serve: the two authoring paths”Trove is built around a symmetric pair of authoring patterns. Knowing which one you want is the first decision.
| Sources | Toolkits | |
|---|---|---|
| Direction | Collect data in (batch) | Serve tools out (live) |
| Entry point | sync(ctx) → documents | defineMcpServer({ tools }) → results |
| SDK | @ontrove/sdk | @ontrove/mcp |
| Executes | Trove cloud by default; Mac app for browser/local sources | Trove cloud |
| Author files | manifest.json + index.ts | manifest.json + server.ts |
| Ship via | Add in the Mac app | trove deploy |
A source feeds your knowledge base on a schedule — its documents become searchable through trove_search and the other core tools. A toolkit answers live questions against a system of record at call time. A developer who has written one can write the other in minutes.
This series covers the collect path. For the serve path, see Toolkits.
When to build a source adapter
Section titled “When to build a source adapter”Build a source adapter when you have an upstream system Trove doesn’t index yet and you want its content continuously synced and searchable — not fetched live on demand. Good candidates:
- A public feed: an RSS/Atom feed, a Substack, an arXiv topic, a JSON API of articles.
- An account you log into: your Hacker News upvotes, your Twitter bookmarks, your Readwise highlights.
- Audio you want transcribed: a podcast subscription, voice memos, meeting recordings.
- Local content: a folder of Markdown notes, an Obsidian vault, your Apple Notes.
If instead you want Claude to call a tool that returns a live answer (a stock quote, the status of an internal order), build a toolkit instead.
The two-file model
Section titled “The two-file model”A source adapter is a folder with two files. Nothing else is required.
my-source/ manifest.json ← what the source is (id, name, schedule, config fields) index.ts ← your sync(ctx) functionmanifest.json declares the source’s identity, schedule, and the preference fields the user fills in during setup. See the manifest.json Reference.
{ "id": "hacker-news", "name": "Hacker News Upvotes", "description": "Index stories you've upvoted on HN.", "version": "1.0.0", "category": "reading", "schedule": "every 6 hours", "config": { "username": { "label": "HN Username", "type": "text" } }, "needs_browser": false}index.ts exports a sync(ctx) function that fetches data and returns an array of documents. The @ontrove/sdk types give you autocomplete on ctx and the document shape.
import type { TroveSource } from "@ontrove/sdk";
export default { async sync(ctx) { const res = await ctx.fetch( `https://hn.algolia.com/api/v1/search?tags=upvoted_${ctx.config.username as string}` ); const data = await res.json();
return data.hits.map((story) => ({ id: story.objectID, title: story.title, text: `${story.title}\n\n${story.story_text ?? story.url ?? ""}`, url: `https://news.ycombinator.com/item?id=${story.objectID}`, author: story.author, date: story.created_at, })); },} satisfies TroveSource;That’s the whole contract. Your source adapter returns documents; Trove uploads the text to the vector store, tracks the sync cursor, deduplicates by document id, and makes everything searchable from Claude.
What you provide vs. what Trove does
Section titled “What you provide vs. what Trove does”You (in sync(ctx)) | Trove (after ingestDocuments) |
|---|---|
Fetch data (ctx.fetch, Playwright, filesystem) | Transcribe audio → text (Whisper) |
Return documents (text, or audioUrl for audio) | Embed text → vectors |
Use a stable id per document | Store full text in R2, index vectors in Vectorize |
| Track the per-feed sync cursor | |
Deduplicate by (feed, id) | |
| Serve to Claude — search, recent, get |
Where the SDK lives
Section titled “Where the SDK lives”The @ontrove/sdk package is published to npm as @ontrove/sdk. The source-adapter catalog is just a git repo with a folder per adapter — the Mac app reads its registry.json, lists the adapters, and adds them, much like a Homebrew tap.
Next steps
Section titled “Next steps”- Quickstart — build your first source adapter in about 10 minutes
- SDK Reference — the
@ontrove/sdkAPI, thectxobject, and the document shape - manifest.json Reference — every manifest field explained
- Cursors and Feeds — multi-feed sources, watermarks, and the cursor protocol