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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions