Skip to content

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.

ConnectorTierAuthCadence
GitHubcoreOAuth (device flow)Hourly
Google (Calendar + Gmail)coreOAuth (auth code, multi-account)Every 30 min – 2h depending on source
GranolacoreEdge harvesterPushed by the macOS app
Apple NotescoreEdge harvesterPushed by the macOS app
SafaricoreEdge harvesterPushed by the macOS app
BeepercoreLocal OAuth (dynamic client registration)Hourly REST sweep against Beeper Desktop
StravacommunityOAuth (auth code, multi-account)Hourly
TidalcoreOAuth (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.

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.

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:

  1. The Desktop client (or any local script) reads the local source
  2. Pairs once via POST /api/v1/harvester-devices/pairing-codesPOST /api/v1/harvester-devices/claim, getting a bearer token
  3. 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.

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:

  1. Write the manifest in src/connectors/<name>.ts (export manifest: ConnectorManifest)
  2. Register it in src/services/connector-registry.ts
  3. Add the cron job in src/server.ts (or the push route if it’s an edge harvester)
  4. Add a corresponding <Name>Filters type in src/types/sync-rules.ts
  5. Test + docs

The Admin SPA picks up the new connector automatically through the GET /api/v1/connectors endpoint.