2026-09-23·by Sijie Wang#node#standmeet#architecture

connector

Pillar 3 · Connector (the credentialed edge)

Parent: key-designs

Every credentialed contact with the outside world goes through one layer: connector.Hub + category slots. Consumers (agent capabilities, platform features, the IM bridge; the job-loop is still not a consumer) see fixed category contracts (CalendarProxy, MailProxybackend/internal/connector/contract/) and receive a call handle — credentials never cross the boundary (AES-256-GCM at rest via cryptobox). Two kinds: openapi (per-SaaS HTTP: spec + JSONata binding, credential form derived from securitySchemes) and protocol (SMTP/CalDAV: built-in Go impls, protocol_smtp.go / protocol_caldav.go; no IMAP). A third protocol connector, telegram (category im), shipped 2026-09-04 (8c819f26d, protocol_telegram.go): it holds only the bot token — no category contract, no Verifier — and the separate im-bridge reads it via GET /internal/im/config (cmd/server/boot_im.go). connector.Service (service.go + svc_*.go; the old connectorsvc package was merged into it on 2026-07-26, 1bc9ba8b0) is the admin plane (creds/connect/oauth/activate/disconnect); retry supplies per-call-class policies; egress/SSRF guards fence the exits. Capability dependencies (Requires:["calendar"]) resolve through capreg/depresolver.go — unmet dep ⟹ capability hidden, fail-closed.

Status: proxy layer landed first; installable landed (upload flow real; red-contract estate = 66 connector-*.spec.ts files at 36789537d; fixme tail cleared; the TODO-impl mock-infra gaps were closed on 2026-07-03, 059dc5c13 — 0 remain); sync-mode landed (2026-07-08, d51805372, backend/internal/connector/sync.go) — connector.NewSyncConnector + the SyncIngester capability made ingest a first-class connector kind, and /obsidian/import now delegates through the interface rather than calling SyncVault inline (routes/admin/obsidian.go:218; DTOs rename 1:1 at the boundary, so the connector layer stays usecase-independent). 17 sync-*.spec.ts files / 118 tests at 36789537d, behaviour identical. Deliberately deferred, and still so at 36789537d (NewSyncConnector has no caller outside sync.go): registering it in the Hub for an admin-UI card, which would need cmd→server dependency threading — the sync-mode abstraction is load-bearing without it. (Connector ≠ MCP; action vs sync — confusables.)

Superseded — everything-is-a-block (eiab), 2026-09-13 → 2026-09-18 (after the 36789537d stamp above)

This pillar no longer exists as a separate module: backend/internal/connector/ now holds 0 Go files. Every connector became a sandboxed JS block (backend/blocks/{caldav,smtp,google-calendar,telegram}/manifest.yaml + a JS MCP server); the openapi kind became a generic openapi-runtime block, the protocol impls (protocol_smtp.go/protocol_caldav.go) and the category contracts (CalendarProxy/MailProxy) are retired, and dependency resolution moved to backend/internal/plugin/effect/registry_deps.go. Credentials-at-rest + egress/SSRF fencing survive at the block-sandbox boundary. The "sync-mode landed" claim is doubly stale: there is no connector module, and vault sync (SyncVault) is still a bespoke admin endpoint (routes/admin/obsidian.go), never a connector kind (roadmap 1e). The Status line and mermaid below describe the pre-eiab shape.

Connector lifecycle (state)

Pinned by red tests: one active connector per category slot; disconnect retains creds; agent-tool exposure is a separate per-op opt-in on top of Active.

Children

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →