Connector authoring
Connectors are an in-app abstraction today: every integration implements one Swift protocol so the sync engine treats them uniformly. Third-party connectors aren't a shipped extension point yet — if you're building an external integration, the surface you want is the MCP tools. This page documents the connector model so you understand how sync behaves and where it's headed.
The model
A connector links a page to an external system in up to three directions: push the page out, pull items in (as seeds), and reconcile task status both ways. Each connector declares which of these it supports via a capability set, and the sync engine only calls what's declared.
The ConnectorService protocol
protocol ConnectorService: Sendable {
var connectorType: ConnectorType { get }
var capabilities: ConnectorCapabilities { get }
var displayName: String { get }
var requiresEntitlement: Bool { get } // Pro-gated?
func connectionStatus() async throws -> ConnectorStatus
func disconnect() async throws
func oauthURL() async throws -> URL
func triggerSync(pageId: UUID, journalId: UUID) async throws -> ConnectorSyncResult
func syncStats() async throws -> ConnectorSyncStats
func pullSeeds(pageId: UUID, pageDate: Date) async throws -> TaskPullResult
func updateTaskStatus(taskLinkId: String, status: String?, taskText: String?) async throws -> TaskStatusResult
} pullSeeds and updateTaskStatus have default no-op
implementations, so a connector only implements the directions it advertises.
Capabilities
| Capability | Meaning |
|---|---|
.pageSync | Render and push the page (e.g. PDF/PNG/structure) to the external system. |
.taskPull | Pull external items in as seeds materialized onto the page. |
.taskUpdate | Push task status/text changes back out to the external system. |
.oauth | Uses an OAuth connection (vs. a system permission like EventKit). |
Example: Notion
Capabilities [.pageSync, .taskPull, .taskUpdate, .oauth], and
requiresEntitlement = true (Pro). Notion is the full-fat
connector: it pushes page content, pulls tasks from the Notion Tasks DB in as
seeds, and reconciles task status in both directions over an OAuth
connection. Task identity is matched by line_id, and pushes
stamp a last-write-wins checkpoint so a pull doesn't fight a recent push.
Example: Calendar
Capabilities [.taskPull], free tier (no entitlement). The
Calendar connector is deliberately one-way and read-only: it
uses EventKit (a system permission, not OAuth) to display the day's events on
the page — the "shape of day." It never pushes, never writes to your
calendar, and there's no two-way reconciliation (the contrast with Notion is
the point: events are observed facts, not editable tasks). Event identity is
the composite (calendar, external id, occurrence start), so a
reschedule produces a new seed rather than mutating the old one.
What a new connector would implement
- Declare
connectorType,capabilities, and whether itrequiresEntitlement. - Implement connection lifecycle (
connectionStatus,oauthURL,disconnect). - Implement only the sync directions its capabilities advertise.
- Respect the shared invariants:
line_ididentity, last-write-wins checkpoints, and the pending-arrival rule (seeds onto an inked page land hidden).