Connectors overview
A connector is a third-party integration that pulls signal into Carabase — pull requests from GitHub, events from Calendar, emails from Gmail, meetings from Granola, etc. Every connector self-describes via a ConnectorManifest so the Admin SPA can render its config UI without hardcoding per-connector knowledge.
Built-in connectors
Section titled “Built-in connectors”| Connector | Tier | Auth | Cadence |
|---|---|---|---|
| GitHub | core | OAuth (device flow) | Hourly |
| Google (Calendar + Gmail) | core | OAuth (auth code, multi-account) | Every 30 min – 2h depending on source |
| Granola | core | Edge harvester | Pushed by the macOS app |
| Apple Notes | core | Edge harvester | Pushed by the macOS app |
| Safari | core | Edge harvester | Pushed by the macOS app |
| Beeper | core | Local OAuth (dynamic client registration) | Hourly REST sweep against Beeper Desktop |
| Strava | community | OAuth (auth code, multi-account) | Hourly |
| Tidal | core | OAuth (auth code + PKCE, multi-account) | Hourly |
core connectors load on the Desktop client AND the Admin SPA;
community connectors load only on the Admin SPA. The tier is declared in
the manifest and gated at the GET /api/v1/connectors?tier=… route.
Substrate-table connectors. Strava and Tidal declare
manifest.substrateTable and write every observation to dedicated
substrate tables (strava_activities, tidal_listens) before any sync
rule applies. Substrate is always populated — the rule only controls
whether the connector additionally creates daily-note entries, folio
commits, harvest jobs, or timeline injections on top. Substrate data is
queryable from the agent via carabase_query_timeseries (Phase 3 PR-B),
so trend questions stay accurate even when no rule matches.
Artifact-shaped connectors with their own caches. Safari, Beeper,
Granola, and Apple Notes are NOT substrate-table connectors —
carabase_query_timeseries rejects them because their data shape isn’t
metric/timeseries-friendly. Each maintains its own purpose-built cache
table (safari_reading_list, beeper_room_policies,
apple_notes_cache, granola_cache), and the agent reaches their
content via the standard semantic / graph / metadata search tools or
via the JIT mesh resolver.
Plugin-backed connectors register through the getAllMcpTools() plugin
registry and can ship as their own npm packages.
Sync rules
Section titled “Sync rules”Every connector reads its config from a sync_rules row keyed on (workspace_id, integration_name). The config is a JSONB blob:
{ "rules": [ { "id": "uuid", "name": "PRs from acme/main", "enabled": true, "filters": { "repos": ["acme/main"], "states": ["open"], "lookbackHours": 24 }, "routing": { "folioName": "acmebase", "tags": ["github", "pr"], "harvestToGraph": true, "injectToTimeline": true } } ]}Multiple rules per integration are supported. When an item matches more than one rule, tags are merged, all folios are resolved, and harvest/timeline are OR’d.
The Admin SPA’s Sync Rules page renders the per-rule filter form from the connector’s filterSchema (a JSON Schema in the manifest), so adding a new connector doesn’t require any UI work.
Edge harvesters
Section titled “Edge harvesters”Some signal is only available locally — Granola meeting notes are stored in ~/Library/Application Support/Granola/cache-v3.json on whichever Mac runs Granola, not in any cloud. For these, Carabase exposes an edge harvester push pattern:
- The Desktop client (or any local script) reads the local source
- Pairs once via
POST /api/v1/harvester-devices/pairing-codes→POST /api/v1/harvester-devices/claim, getting a bearer token - Pushes data to
POST /api/v1/granola/sync(or the relevant connector route) with the bearer token
Multiple devices can register against the same workspace — e.g. Granola on a Mac mini and a laptop both pushing into the same host.
See Edge harvesters for the full pairing protocol.
Adding a new connector
Section titled “Adding a new connector”There’s a /new-connector skill in .claude/skills/new-connector/SKILL.md that scaffolds the full playbook (manifest, filter type, registry registration, cron/push wiring, tests, docs). The short version:
- Write the manifest in
src/connectors/<name>.ts(exportmanifest: ConnectorManifest) - Register it in
src/services/connector-registry.ts - Add the cron job in
src/server.ts(or the push route if it’s an edge harvester) - Add a corresponding
<Name>Filterstype insrc/types/sync-rules.ts - Test + docs
The Admin SPA picks up the new connector automatically through the GET /api/v1/connectors endpoint.