corsair_entities holds your Slack messages, GitHub issues, Notion pages, and Gmail threads in one table with one shape. That’s a corpus you can search.
Ask “what’s happening with the Peterson report?” and you can look across every synced service at once, then hand the matches to a model as grounding, instead of calling six search APIs and reconciling six response formats.
Pattern: search .db across entity types, rank in your code, then feed matches to the model as context.
Searching one entity type
Use the typed client when you know where to look. String fields supportcontains, which compiles to a SQL LIKE '%value%':
Searching across services
The typed clients are scoped to one entity type at a time. To sweep the whole corpus, fan out and merge:src/server/search.ts
corsair_entities directly with your own ORM. It’s one table, so a single statement covers every service and entity type at once, which is useful when you don’t want to enumerate the plugins up front:
account_id values. The typed clients do this for you; raw SQL does not.
Grounding a model
Retrieval is the whole trick. Pass matches in as context and require citations back to the source URL:Filling the corpus
Search only finds what’s been synced. Two ways rows get there:- Backfill. Call
.apilist endpoints once per source. Every response is upserted, so a paginated crawl populates the table. - Stay fresh. Register webhooks so upstream changes update the same rows in place. See Webhooks.
Know the limits
That’s fine for names, IDs, and known phrases. For conceptual questions, keep embeddings in your own table keyed tocorsair_entities.id, and use Corsair search to fetch the current text for whatever your vector query returns. The row your embedding points at keeps updating itself, so you re-embed on change rather than rebuilding from scratch.
One more constraint. search filters top-level data fields only, and has no sort option. Order results in your code, or use SQL.
Checklist
- Reads go through
.db, never.api, so questions don’t burn rate limit. - Raw
corsair_entitiesqueries are filtered to the tenant’s accounts. - Answers cite source URLs from the entity data.
- The corpus is backfilled once and maintained by webhooks.
- Semantic needs are handled with embeddings alongside, not by
contains.
What’s next
Database
The entity table, and how to join it to your own.
Give it to an agent
Let the model search and then act on what it finds.
Webhooks
Keep the corpus current without polling.
Multi-tenancy
Keep each customer’s corpus isolated.