Connector Runner
Bidirectional sync with external systems (EHR, FHIR store, CRM): entity resolution, confidence-gated writes, outbound handler registry, and call dispatch.
The connector runner is the bidirectional data pipeline between external systems and the workspace's world model. It polls external systems (EHR platforms, FHIR stores, CRMs), writes events with entity resolution (matching records from different systems to the same real-world entity), syncs agent-created data back to source systems after quality review, dispatches scheduled outbound calls, and runs the automated data quality pipeline.
Inbound data arrives via polling (dispatched by source type: ehr, fhir_store, smart_fhir, rest_api, webhook, file_drop, lakebase_schema) or real-time webhooks (for EHR systems that support FHIR Subscriptions or event notifications). Outbound write-back routes on the workspace's connector type (fhir_store, smart_fhir, athenahealth, charmhealth, eclinicalworks, meditab, hazelhealth, mbp, lakebase_schema) through a handler registry. The epic, cerner, and allscripts connector types exist in the enum but route through the fhir_store and smart_fhir handlers rather than dedicated handlers.
The connector runner has no public-facing API. It operates as a background service. Data sources and sync configuration are managed through the Data Sources endpoints on the Platform API, and its health is visible through the Pipeline Observability endpoints below. For the full architecture narrative - sync design, confidence gating, and review workflow - see the Connectors & EHR conceptual documentation.
Inbound Sync
Data sources feed the world model through two mechanisms:
Polling: sources are polled according to their sync strategy. Per-source locking prevents duplicate polling, content-hash deduplication prevents duplicate writes on repeated polls, and each resource-type batch is durable immediately, so partial failures never lose already-written data. Individual record failures are retried on the next poll cycle without blocking other records.
Real-time webhooks: EHR systems that support FHIR Subscriptions or event notifications push changes directly. Incoming webhooks are cryptographically verified, deduplicated, and the full resource is fetched and mapped to FHIR before writing to the world model. Subscription lifecycle (creation, renewal, cleanup) is managed per data source.
Both paths converge on the same world model event pipeline with identical entity resolution, enrichment, and confidence handling.
Polling behavior:
Full vs light cycles
Full sync polls all resource types. Light sync polls only high-frequency types using cached reference data
Business hours gate
Polling can be restricted to defined operating hours to respect external API usage patterns
Reference data caching
Frequently-accessed reference data (locations, carrier lists) is reused between polls to reduce external API call volume
Configurable poll cadences
Per-resource poll intervals via poll_cadences in the data source connection config
Entity Resolution
Events arrive with references to external entities (for example, an appointment references a patient by external ID). Entity resolution maps those references to canonical IDs, creates or finds the matching world model entity, links the events, and projects graph relationships - all idempotently.
Patient
person
{source}:Patient:{id}
Practitioner
person
{source}:Practitioner:{id}
Location
place
{source}:Location:{id}
Appointment
appointment
{source}:Appointment:{id}
Coverage / Encounter
Linked to patient
Via participant references
Slot
Skipped
Marked to prevent re-fetching
When a workspace has multiple data sources, entity resolution automatically detects when entities from different sources represent the same real-world thing. Matched entities are linked and their projected state is unified, so a single patient view reflects data from every connected system.
Patient
Phone number (E.164 normalized)
High
Patient
Email address
High
Patient
Name + date of birth
Moderate
Practitioner
NPI
High
Practitioner
Name + specialty
Moderate
After events are committed, background enrichment runs with zero added latency to the write path: vector embeddings are generated for every event and entity write, and AI-powered enrichment extracts and enhances fields on events that need it.
Outbound Sync
Data captured by the voice agent during calls is gated before syncing to external systems:
Source allowlist: only
voice_agent,encounter_finalized, andplatform_api_mcp(clinical writes made through the MCP server, which must reach the EHR like the voice path) events are eligible for outbound sync. Events fromapi,outbound_sync_agent,ehr_sync, andconnector_runnersources are excluded. This is an allowlist, not a blocklist - new sources must be explicitly added to become eligible.Confidence gate: only events at or above the verified confidence threshold sync on the automatic path. Below-threshold writes never reach external systems automatically. The threshold is enforced independently at every outbound path as defense in depth.
Review-gated sinks: a sink can be configured to require human review. When it does, outbound write intents are staged as external write proposals instead of auto-pushing. An operator approves or rejects each proposal through the Review Queue, and approved proposals are then delivered to the sink. Because a human decision is the authority, review-gated sinks capture writes at any confidence; the confidence gate governs only the un-reviewed automatic path. Staging is idempotent, so a redelivered write intent never creates a duplicate proposal or re-proposes an already-decided write.
Write-Back
A workspace can write back to multiple external systems simultaneously (multi-sink). For example, a workspace might sync patient and appointment data to the EHR while syncing patient and contact data to the CRM. Each sink is configured independently with its own outbound_entity_types, and sync progress is tracked per sink. A failure writing to one system does not block writes to others.
Outbound events are routed through a handler registry that maps each sink's connector_type to the correct write-back handler. The registry is the single routing authority for all outbound paths.
fhir_store
FHIR R4 (ETag optimistic locking)
Managed credentials
smart_fhir
SMART-compliant FHIR R4
SMART Backend Services (RS384/ES384 JWT assertion)
athenahealth
athenahealth EHR adapter (Patient create/update, Appointment book/cancel)
OAuth2 client credentials
charmhealth
Charm EHR adapter
OAuth2 + API key
eclinicalworks
eClinicalWorks EHR adapter
Managed credentials
meditab
Meditab EHR adapter
Managed credentials
hazelhealth
Hazel Health EHR adapter
Managed credentials
mbp
MBP EHR adapter
Managed credentials
lakebase_schema
Workspace database schema adapter
Managed credentials
For approved events, the connector runner translates world model data into the target system's format:
patient.created
Create patient record in EHR (with AI translation for complex field mapping plus deterministic fallback)
patient.updated
Merge demographics with current EHR record
appointment.booked
Create appointment (patient resolved from entity external IDs)
appointment.confirmed / cancelled
Update appointment status
coverage.created
Create insurance record (carrier fuzzy-matched from EHR carrier list)
Write-back safeguards:
Optimistic locking: for FHIR stores, ETag-based locking prevents lost updates. On conflict (412), the write is re-read and retried up to 3 times.
Confidence-aware dependencies: when a write depends on another entity (for example, appointment creation requires the patient to exist in the EHR), the dependency check evaluates confidence. A below-threshold dependency fails fast rather than waiting indefinitely on unverified voice data.
Duplicate prevention: when the voice agent creates a patient not yet in the target EHR, an autonomous check verifies no duplicates exist before creating the record.
Loop prevention: events that originated from EHR sync are always skipped in outbound paths.
Outbound Call Dispatch
The connector runner dispatches outbound calls when scheduled outbound_task entities become due. This implements the execution side of the voice agent's outbound system. For each due task, the runner loads the patient entity from the world model, builds a rich system prompt from the patient projection, resolves the outbound phone number, and dispatches the call - writing an outbound.dispatched or outbound.failed event with the result.
Business hours gate
Per-task timezone-aware window (e.g., 9am-5pm ET). Outside hours, the task waits for the next window
Priority ordering
Tasks dispatched highest-priority first (1-10 scale)
Dispatch locking
Per-entity locking prevents double-dispatch
Retry with backoff
Configurable max attempts and backoff interval. Failed tasks automatically schedule the next attempt
Rich context
Patient projection enriches the system prompt, so the voice agent starts with full patient knowledge
Idempotency
Dispatch keyed by outbound:{entity_id}:{attempt}, safe to retry
Pipeline Observability
The Platform API exposes 10 read-only pipeline observability endpoints under /v1/{workspace_id}/pipeline/ that combine live connector runner state with stored pipeline data. These power the pipeline dashboard in the Developer Console.
Endpoints
GET /v1/{workspace_id}/pipeline/status
Composite pipeline status: overall health, active polls, total events/entities, per-source status, all loop states
GET /v1/{workspace_id}/pipeline/sources
Data sources with live health from recent poll results
GET /v1/{workspace_id}/pipeline/sources/{source_id}/overview
Aggregated overview of a source's pipeline health: event counts by status, last sync time, error summary
GET /v1/{workspace_id}/pipeline/sources/{source_id}/history
Sync history bucketed by time window (1h or 1d) for a specific source
GET /v1/{workspace_id}/pipeline/sources/{source_id}/events
Paginated events for a specific source (sortable by ingested_at, event_type, confidence)
GET /v1/{workspace_id}/pipeline/outbound
Per-sink outbound sync summary: synced/failed/pending counts
GET /v1/{workspace_id}/pipeline/outbound/{data_source_id}/log
Paginated outbound sync log for a specific sink (sortable by created_at, synced_at, attempt_count)
GET /v1/{workspace_id}/pipeline/entity-resolution
Entity resolution metrics: total same-as edges, recent merges (24h), loop status
GET /v1/{workspace_id}/pipeline/review
Review pipeline metrics: queue depth, pending by priority, approved/rejected (7d), average review time
GET /v1/{workspace_id}/pipeline/throughput
Event throughput time series across all sources (configurable date range and interval)
All endpoints require viewer+ permissions and are workspace-scoped.
Health Snapshot
The /v1/{workspace_id}/pipeline/status endpoint returns a composite view:
status
healthy, degraded, starting, or unavailable
connector_runner_status
Live connector runner status (same values)
uptime_seconds
Connector runner uptime
active_polls
Number of sources currently polling
total_events / total_entities
Workspace-level counts
sources
Per-source status with poll metrics, error counts, and connection health
entity_resolution, outbound_dispatch, outbound_subscriber, gap_scanner
Per-component operational state (a component field is null when that component is not running)
Source Health
Each source in the listing includes live health enrichment:
health_status
string
healthy, degraded, or unknown
last_poll.at
ISO timestamp
When the last poll completed
last_poll.duration_ms
integer
Poll duration in milliseconds
last_poll.event_count
integer
Number of events written
last_poll.error
string or null
Error message if the poll failed
Connection health is tracked per source using consecutive error counts. A source is marked degraded after 3+ consecutive poll failures and recovers automatically on the next successful poll.
Live health metrics reflect recent poll activity and reset when the connector runner restarts; stored pipeline data (event counts, sync history, review stats) is unaffected.
Graceful Degradation
If the connector runner is temporarily unavailable, the pipeline endpoints still return stored data (event counts, sync history, review stats, entity resolution metrics). Only live component states and active poll counts are omitted. The dashboard stays functional during connector runner restarts or deployments.
Connector Settings
Connector definitions are managed through workspace settings with typed configuration models. Each connector definition includes:
connector_type
The external system type (maps to the handler registry)
sync_strategy
Sync cadence: continuous, scheduled, manual, or webhook
connection_config
System-specific connection parameters (endpoints, credentials, resource scoping)
poll_cadences
Per-resource type polling intervals
The connector settings endpoint validates sync strategy values with strict type checking, preventing misconfiguration bugs. The data source response includes an is_stale field computed from the connector's last successful sync and its configured cadence. Configuration changes are picked up automatically on the next sync cycle - no restart is needed.
API Reference
Last updated
Was this helpful?

