Connector concepts
Packages own the plug-in; the SDK owns the import
Section titled “Packages own the plug-in; the SDK owns the import”| Layer | Owns | Decides |
|---|---|---|
| Integration package | Auth, install, config, scheduling | How a connector connects and when it runs |
Connector SDK (lib/integrations/crm-sync/) |
Inbound record import | How records flow in: discover, map, create and update, record outcomes |
When someone says “connector,” ask which layer they mean. Auth problems live in the package; import problems live in the SDK.
The inbound-import pipeline
Section titled “The inbound-import pipeline”The pipeline runs in this order: discover objects (objects and properties), map fields (object_mappings), read records (records with watermark), create and update mapped records (inbound writer), record outcomes (the watermark advances only when failed == 0).
- Discover objects: the adapter lists source objects (
objects()) and their fields (properties(objectKey)). - Map fields: field mappings bind source fields to destination targets, stored per org, package, and connection in install
settings.object_mappings. - Create and update mapped records: the shared importer (
object-mapping-runtime.ts) reads record pages (records(objectKey, properties, after)) and persists viainbound-writer.tsandinbound-transition.ts(seeupsertConnectorCrmRecordin Examples). - Record outcomes: per-run results decide the watermark. It advances only when
failed === 0. A failed run retries from the same watermark and never skips.

The adapter registry fails closed
Section titled “The adapter registry fails closed”lib/integrations/crm-sync/provider.ts is the code-owned registry: a provider must be registered there or it does not exist as far as the runtime is concerned. Unknown providers fail closed. No fallback, no guessing, no partial import.
Registered adapters per source: HubSpot (lib/integrations/hubspot/sync-provider.ts) and ConnectWise PSA (provider under lib/integrations/connectwise/; confirm the exact filename in-repo; runbook connectwise-psa-integration-package.md). That is the complete list until provider.ts says otherwise.
Bindings, identity, destinations
Section titled “Bindings, identity, destinations”- Bindings live in the install’s
settings.object_mappings, scoped to org, package, and connection. A mapping is meaningless without all three coordinates. - Identity namespace:
binding:<uuid>inai.connector_object_map. The stable identity for a bound mapping. - Destinations come from the destination catalog (
target-catalog.ts). Example shape:targetObject: 'work-items'withworkItemTypeId. The retiredtasks/deliverablesdestinations must never be used. See Extend. - Client-safe surface: browsers only ever see the shape in
object-mapping-contract.ts, edited through the shared UI (components/integrations/package-object-mappings.tsx), persisted via the Admin API/api/v1/integration-packages/[packageKey]/object-mappingsintoobject-mapping-store.ts.
Binding contract, in full: bindings in install settings.object_mappings (org, package, connection); identity binding:<uuid> in ai.connector_object_map; destination example targetObject: 'work-items' with workItemTypeId; never the retired tasks/deliverables; never expose applyConnectorMappedRecord unauthenticated.
The load-bearing rule: code is not connected
Section titled “The load-bearing rule: code is not connected”Adapter code existing, even registered-adapter code, is not the same as a connector being live for a tenant. Connected means provisioned, credentialed, enabled in the tenant’s environment, bindings in place, and verified in a session. The environment’s tool list plus the binding state are the source of truth.

