Commands
Every command is a thin wrapper over one named GraphQL operation. This page documents each command exactly as the package implements it: synopsis, flags, the operation it maps to, and output examples.
Global flags
Section titled “Global flags”These apply to every command and may appear before or after the command path:
| Flag | Effect |
|---|---|
--json | Emit the GraphQL data payload, pretty-printed. |
--jsonl | Emit one JSON object per line (for the streamable list of a result). |
--human | Force the human table/record view (e.g. into a pipe). |
--no-color | Disable ANSI color. |
--quiet | Suppress non-error stderr chrome. |
--profile <name> | Select the config profile. |
--endpoint <url> | Override the profile’s api_url. |
--help, -h | Print top-level usage. |
--version, -v | Print the CLI version. |
Format precedence is --jsonl > --json > --human; with none given, the CLI emits human at a TTY and json when piped. See Scripting.
login / logout / whoami
Section titled “login / logout / whoami”Covered in full on Install & Authentication. In brief: login stores a token (verifying it via query stats), logout forgets it, and whoami prints identity + corpus size (also via query stats). None maps to a dedicated GraphQL auth operation — auth is Clerk; whoami reuses stats.
The highest-leverage group. Each is --json-capable, and the human view echoes the [doc:ID] handle convention the Core tools use, so output reads like what an agent sees.
search
Section titled “search”trove search <query…> [--source <name|id>] [--source-type <t>] [--author <a>] [--after <date>] [--before <date>] [--type <ct>] [--tag <t>]… [--feed <id>] [--limit <n> | -l <n>]Semantic top-K search → query search. Positional words are joined into the query string. --source accepts a name or id; a name is resolved to its id client-side via sources (an id-shaped value, src_…, is used as-is). --tag is repeatable. --type is upper-cased to the ContentType enum.
$ trove search "database indexing" --source "arXiv Papers" --limit 5SCORE TITLE SOURCE HANDLE0.847 Learned Indexes for Range Queries arXiv Papers [doc:d_8f2a]0.812 B-Tree vs LSM under Write Amplification arXiv Papers [doc:d_31c0]
2 match(es) in 41ms--json emits the SearchResults object ({ totalMatches, queryTimeMs, results[] }); --jsonl emits one results[] entry per line.
discover
Section titled “discover”trove discover <topic…> [--source <name|id>] [--source-type <t>] [--feed <id>] [--limit <n> | -l <n>]Broad thematic browse → query discover. Only source/feed filters take effect — the wider search filters (--author, --after, --type, --tag) are accepted but ignored. Output shape matches search.
recent
Section titled “recent”trove recent [--source <name|id>] [--author <a>] [--since <date>] [--limit <n> | -l <n>]Chronological by indexedAt → query recent. Renders a TITLE / AUTHOR / SOURCE / HANDLE table. --json/--jsonl emit the document array.
trove get <doc-id…> [--offset-words <n>] [--max-words <n>]Fetch one or more documents with full text → query document(id), once per id. A missing document fails with exit code 5. The human view prints a record header (title, author, source, url, handle) followed by the full text — built for piping into $EDITOR/less:
trove get d_8f2a | $EDITOR -In --json, a single id emits one document object; multiple ids emit an array. In --jsonl, each document is one line.
Word paging. --offset-words / --max-words page a long transcript client-side: the CLI fetches the document’s fullText, slices it by words, and prints just that window. The human view writes the slice to stdout plus a continuation hint (the next offset) to stderr; --json returns { id, offsetWords, returnedWords, totalWords, nextOffset, text }. Paging applies to a single document id at a time.
trove get d_8f2a --offset-words 0 --max-words 800 # first 800 wordstrove get d_8f2a --offset-words 800 --max-words 800 # next page (use nextOffset)trove list [--source <name|id>] [--type <ct>] [--tag <t>]… [--search <text>] [--sort <field>] [--order <asc|desc>] [--limit <n> | -l <n>] [--offset <n>]The exhaustive lister with an authoritative totalCount → query documents. This is the right tool for “all X”, counts, and pagination — search is semantic top-K. --sort maps to DocumentSortField and --order to SortOrder (both upper-cased); --type upper-cases to ContentType.
$ trove list --source "The Guardian" --json | jq '.totalCount'675The human view appends a <N> total footer (with (more available) when hasMore). --jsonl emits the nodes[] one per line.
sources
Section titled “sources”trove sources [--type <t>] [--status <s>]List your sources → query sources. --status upper-cases to SourceStatus. Renders an ID / NAME / TYPE / STATUS / DOCS table.
source
Section titled “source”trove source <id|name> [--feeds] [--sync-runs]One source with feeds, top authors, date range, and recent sync runs → query source(id). The name/id argument is resolved via sources. A missing source fails with exit code 5. (--feeds/--sync-runs are accepted; the operation already requests feeds and sync runs.)
trove statsCorpus aggregates → query stats: total documents, total/active sources, breakdowns by source type and content type, and recent sync runs.
Capture
Section titled “Capture”trove save (--text <text> | --text - | --url <url>) [--title <t>] [--tag <t>]… [--source <s>]Manual capture of free text or a URL into the Manual Saves source → mutation saveDocument. One of --text or --url is required. --text - reads the body from stdin, so:
cat notes.md | trove save --text - --title "Meeting notes"trove save --url https://example.com/post --tag reading --tag aiHere --source is free-form attribution text (e.g. "conversation with Claude"), not a source id. On success the human view writes ✓ saved [doc:…] to stderr and the record (id, title, url, tags) to stdout. --json/--jsonl emit the saved Document.
ingest
Section titled “ingest”trove ingest --source <id> --feed <id> --documents <file.jsonl|-> [--cursor <new>] [--cursor-before <expected>]The lower-level ingest boundary for source-adapter authors and bulk scripts → mutation ingestDocuments. --documents accepts a JSONL stream or a JSON array of IngestDocumentInput; - reads from stdin.
It honors the cursor compare-and-swap: pass --cursor (the new watermark) and --cursor-before (the expected current value). On a CAS rejection the CLI exits with code 8 (retryable) so a script can re-read IngestResult.cursor and retry. Re-sent documents are reported as documentsSkipped, not errors.
generate-docs | trove ingest --source src_123 --feed feed_456 --documents -The human view prints indexed, skipped, transcriptions queued, cursor, and errors. --json emits the full IngestResult; --jsonl emits the per-document errors[] one per line.
Source authoring (@ontrove/sdk)
Section titled “Source authoring (@ontrove/sdk)”The CLI is the local dev toolchain for source adapters. A source adapter is a folder with manifest.json + index.ts (a defineSource({ sync }) export against @ontrove/sdk). Locally, the CLI runs the adapter on your machine — dev/test run sync(ctx) (transpiled with esbuild) and never upload; sync runs it then pushes via ingestDocuments. In production, most sources run in Trove’s cloud; the ones that need a browser or local files run on the Mac app.
source init
Section titled “source init”trove source init <name>Scaffold <name>/manifest.json + <name>/index.ts (a defineSource stub with a sample sync). No GraphQL.
source dev
Section titled “source dev”trove source dev [path] [--config <file.json>] [--cursor <json>]Load the source adapter’s index.ts (esbuild → @ontrove/sdk’s runSource), run sync(ctx), and print the produced documents (human table or --json/--jsonl). --config supplies the source’s preference values; --cursor supplies the starting watermark. Nothing is uploaded.
source test
Section titled “source test”trove source test [path] [--fixtures <file.json>] [--config <file.json>]Run sync(ctx) against a fixtures file (a JSON map of request URL → canned response body, default fixtures/responses.json) so the run is deterministic and offline, then assert the document shape. Exits 2 if assertions fail.
source validate
Section titled “source validate”trove source validate [path]Validate manifest.json with @ontrove/sdk’s validateSourceManifest — required fields, the id/version patterns, and the credential-key lint (a source’s config must hold preferences only, never credentials). Exits 2 on an invalid manifest.
source sync
Section titled “source sync”trove source sync [path] [--source <name|id>] [--feed <key>] [--create] [--config <file.json>]The real upload: run sync(ctx) locally, then push the documents via mutation ingestDocuments with cursor compare-and-swap. The CLI reads the target feed’s current cursor as cursorBefore and advances it with the watermark sync returns. --source (defaults to the manifest name) and --feed (defaults to default) select the target; --create creates the source/feed (via createSource/addFeed) if they don’t exist yet.
Toolkit authoring & deployment (@ontrove/mcp)
Section titled “Toolkit authoring & deployment (@ontrove/mcp)”mcp init/mcp dev are the local toolchain for toolkits (manifest.json + server.ts exporting defineMcpServer({ tools }) — every toolkit runs as a full MCP server on Trove’s cloud). The remaining commands wrap the toolkit control-plane operations; the deployed runtime is PROPOSED, and they ship with the control plane. A toolkit argument is a slug or id, resolved via mcpServers.
mcp init
Section titled “mcp init”trove mcp init <name>Scaffold <name>/manifest.json + <name>/server.ts (a defineMcpServer stub with a sample tool, annotations, and an output schema). No GraphQL.
mcp dev
Section titled “mcp dev”trove mcp dev [path] [--port <n>] [--once]Bundle server.ts (esbuild), wrap it in @ontrove/mcp’s runtime fetch handler, and serve it over http://127.0.0.1:<port> (default 8788) so a client can connect: GET returns tools/list, POST runs a tool. Prints the local URL and the tool list; ctx.secret/ctx.trove resolve against the configured endpoint. Runs until interrupted (--once serves and returns, used in tests).
mcp ls
Section titled “mcp ls”trove mcp lsList your toolkits → query mcpServers. Renders a SLUG / NAME / STATUS / VIS / TOOLS / ACTIVE table (ACTIVE is the active deployment’s version).
mcp deploy (alias deploy)
Section titled “mcp deploy (alias deploy)”trove mcp deploy [--dir <path>] [--name <name>] [--slug <slug>]trove deploy [--dir …] [--name …] [--slug …]Register/version a toolkit → mutation deployServer. Reads manifest.json from --dir (default .), derives name/slug from the manifest (slug falls back to the manifest id) unless overridden by --name/--slug, bundles server.ts locally (esbuild — a Bundling … (esbuild)… line is written to stderr), and registers the deployment. On success it prints the namespaced tool names ({slug}__{tool}) to stdout and a ✓ deployed … line to stderr. --json emits the McpDeployment. Missing manifest.json is a usage error (exit 2). See Toolkits — Deploying.
mcp pause / mcp resume / mcp rm
Section titled “mcp pause / mcp resume / mcp rm”trove mcp pause <toolkit>trove mcp resume <toolkit>trove mcp rm <toolkit>Lifecycle, each over a single id → mutation pauseServer, mutation resumeServer, mutation deleteServer (a soft-delete). The human view writes ✓ paused|resumed|deleted <name> to stderr; --json emits the returned McpServer.
mcp rollback
Section titled “mcp rollback”trove mcp rollback <toolkit> <deploymentId>Repoint a toolkit to a prior deployment → mutation rollbackServer. Both positionals are required. The human view writes ✓ rolled back <name> → <version> to stderr.
mcp logs
Section titled “mcp logs”trove mcp logs <toolkit>There is no logs GraphQL operation: per-script logs are produced by the deployed toolkit runtime, not the GraphQL API. Rather than invent a fake op, this command explains where logs live (the deployed endpoint, once the runtime ships) and exits 0. --json returns { server, available: false, reason }.
secret set
Section titled “secret set”trove secret set <toolkit> <name> (--value <v> | --from-file <path> | --from-stdin)Seal a secret into the encrypted vault → mutation setServerSecret. The value comes from --value, --from-file <path>, or --from-stdin so it need never land in argv history; it is stored server-side in the vault, never in D1. The human view writes ✓ secret '<name>' sealed for <toolkit> to stderr.
secret ls
Section titled “secret ls”trove secret ls <toolkit>List a toolkit’s declared secret names → backed by query mcpServers (the secrets field). Values are unreadable by design — only the names are ever returned. The human view prints one name per line (or notes when the toolkit declares none); --json emits { server, secrets } and --jsonl emits one name per line.
Escape hatch
Section titled “Escape hatch”trove gql <file|-> [--variables <json|->]Run a raw, user-supplied GraphQL document over the same endpoint with the same token. The document is read from a file path or stdin (-); --variables takes inline JSON or stdin. Unlike the wrapped commands, gql emits the full { data, errors } envelope (so scripts can branch on .errors) and exits 7 if errors[] is non-empty, 0 otherwise. It is the same authz the server enforces for every client — there is nothing reachable here that the token could not do with curl.
echo '{ stats { totalDocuments } }' | trove gql -trove gql query.graphql --variables '{"id":"d_8f2a"}'Command → GraphQL operation mapping
Section titled “Command → GraphQL operation mapping”This table is the contract: every command resolves to a named operation in schema.graphql (or a marked local step). It is a strict subset of the published GraphQL surface — the CLI never exceeds the API, it only makes a slice of it ergonomic.
| Command | GraphQL operation | Kind |
|---|---|---|
login / logout / whoami | — (Clerk; whoami calls query stats) | Auth |
search <query> | query search | Read |
discover <topic> | query discover | Read |
recent | query recent | Read |
get <id…> | query document(id) (once per id) | Read |
list | query documents | Read |
sources | query sources | Read |
source <id|name> | query source(id) | Read |
stats | query stats | Read |
save | mutation saveDocument | Write |
ingest | mutation ingestDocuments (cursor CAS) | Write |
source init | — (scaffold @ontrove/sdk project) | Local |
source dev | — (local sync(ctx) via esbuild) | Local |
source test | — (local fixtures assertion) | Local |
source validate | — (validateSourceManifest) | Local |
source sync | mutation ingestDocuments (+ createSource/addFeed w/ --create) | Write |
mcp init | — (scaffold @ontrove/mcp project) | Local |
mcp dev | — (local server over 127.0.0.1) | Local |
mcp logs | — (no log op; explains the deployed-runtime gap) | Info |
mcp ls | query mcpServers | Read · PROPOSED |
mcp deploy / deploy | mutation deployServer | Write · PROPOSED |
mcp pause | mutation pauseServer | Write · PROPOSED |
mcp resume | mutation resumeServer | Write · PROPOSED |
mcp rollback | mutation rollbackServer | Write · PROPOSED |
mcp rm | mutation deleteServer (soft-delete) | Write · PROPOSED |
secret set | mutation setServerSecret | Write · PROPOSED |
secret ls | query mcpServers (secrets — names only) | Read · PROPOSED |
gql <file|-> | arbitrary, user-supplied | Escape hatch |