Skip to content

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.

SourcesToolkits
DirectionCollect data in (batch)Serve tools out (live)
Entry pointsync(ctx) → documentsdefineMcpServer({ tools }) → results
SDK@ontrove/sdk@ontrove/mcp
ExecutesTrove cloud by default; Mac app for browser/local sourcesTrove cloud
Author filesmanifest.json + index.tsmanifest.json + server.ts
Ship viaAdd in the Mac apptrove 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.

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.

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) function

manifest.json declares the source’s identity, schedule, and the preference fields the user fills in during setup. See the manifest.json Reference.

manifest.json
{
"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.

index.ts
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.

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 documentStore full text in R2, index vectors in Vectorize
Track the per-feed sync cursor
Deduplicate by (feed, id)
Serve to Claude — search, recent, get

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.