Skip to content

Implement ADR-0096: declarative connector instances (provider-bound connectors: materialized by generic executors) #2977

Description

@os-zhuang

Development tracking issue for ADR-0096. The ADR (docs/adr/0096-declarative-connector-instances.md, Status: Proposed) landed with the #2612 interim PR (#2985, merged). This issue tracks moving it from Proposed → Accepted → implemented.

Why

#2612 established that declarative connectors: stack entries never reach the automation connector registry — they are catalog descriptors with no behavior. The interim fix (#2985) stops the silent trap (descriptor-only contract + boot audit warning + enabled: false marker). But for a metadata platform whose goal is AI-built enterprise core systems, integrations must be expressible and executable as pure metadata:

  • AI generates metadata, not plugin code; a schema collection the AI can author but the runtime ignores is the worst failure mode (plausible, validated, dead).
  • Every comparable platform treats declarative connectors as table stakes: Salesforce External Services (OpenAPI → invocable Flow actions, zero code), Power Platform custom connectors (the connector is an OpenAPI document; connections carry credentials per environment), ServiceNow IntegrationHub spokes.
  • The runtime substrate already exists: connector-openapi (ADR-0023) and connector-mcp (ADR-0024) are generic executors that materialize { def, handlers } from declarative inputs. What's missing is the last mile from stack metadata to those factories.

Approach (per ADR-0096)

Type/instance separation, mirroring the datasource pattern (declared in stack, adapter in code):

connectors: [{
  name: 'billing',
  provider: 'openapi',            // ← which installed executor materializes this
  providerConfig: { spec: './billing-openapi.json', baseUrl: 'https://billing.example.com' },
  auth: { type: 'bearer', credentialRef: 'billing_api_token' },  // reference, never inline secrets
}]

At boot, the plugin registered for provider acts as a factory: materializes action handlers from the declarative config and calls engine.registerConnector(def, handlers). Declared provider with no installed factory ⇒ hard boot error (upgrade of the #2985 audit warning).

Task breakdown

  • D0 — ADR review & acceptance. Circulate ADR-0096; resolve open questions (credential-resolution degraded story without a secrets service; provider-key namespace). Flip Status: Proposed → Accepted.
  • D1 — Schema evolution (@objectstack/spec). Add provider, providerConfig, and credentialRef (on the auth shapes) to the connector schema; reject inline secrets at authoring/publish; changeset + .describe() for AI authoring. No execution bindings on ConnectorActionSchema (ADR-0023 non-goal).
  • D2 — Provider factory registration surface. Define how a connector plugin registers a provider factory (providerConfig, resolvedAuth) => { def, handlers }; wire the registry into the automation engine.
  • D3 — Boot materialization + credentialRef resolution. In service-automation, resolve each provider-bound instance at kernel:ready, resolve credentialRef via the secrets layer, register the materialized connector. Upgrade findInertDeclaredConnectors warning → hard error for provider-bound entries; keep the warning for plain descriptors.
  • D4 — Conflict rule. Provider-bound instance name-colliding with a plugin-registered connector ⇒ loud boot failure (no silent precedence). Tests.
  • D5 — Provider implementations. connector-openapi and connector-mcp (and connector-rest) expose provider factories reusing their existing generator/adapter APIs (ADR-0023/0024).
  • D6 — Showcase upgrade. Add a live provider-bound declarative connector (e.g. provider: 'mcp') dispatched by a flow connector_action; GET /connectors lists the materialized instance. (Complements the descriptor-only demo shipped in feat(automation,spec): descriptor-only contract + boot audit for declarative connectors (#2612) #2985.)
  • D7 — Open/enterprise line. Static credentials open-source; managed vault + OAuth2 refresh + per-tenant connection lifecycle enterprise (per ADR-0015). Document the boundary.

Acceptance

An AI-generated app declares a connector instance (e.g. pointing at an MCP server) as pure metadata and a flow connector_action dispatches one of its actions end-to-end; boot fails loudly for unknown provider / invalid providerConfig / unresolvable credentialRef / name conflict.

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions