DarDev Ops becomes a runtime when connectors expose capabilities—discrete actions like check-drift, draft-campaign, or count-by-tag—that the UI renders as buttons and the integration bus executes. A connector is not merely a label on an integrations card; it is a typed instance with config, optional secret_ref to VPS env, and a capability subset registered by provider type. This model replaces one-off panels and aligns with crm-orchestrates-bus-executes: Ops and CRM orchestrate; capabilities with runsOn bus execute.
Connector instance anatomy
- id — unique within solution (e.g. hesabi-listmonk)
- type — registered provider (list-listmonk, dns-godaddy, crm-twenty)
- config — provider-specific JSON validated by provider schema
- capabilities — subset of what the type can expose
- secret_ref — env var name on VPS, never plaintext in git
- scope — optional company-shared vs solution-dedicated
Example: Hesabi marketing lists connector type list-listmonk with list_slugs hesabi-marketing and hesabi-news, capabilities list-subscribers, create-template, draft-campaign, sync-templates. The UI never hardcodes Listmonk panel—it flatMaps connectors to capability definitions filtered by workspace tab and RBAC role.
Provider interface
Each connector type implements once in dardev-platform/connectors/ or ops/lib/connectors/ for read-only probes. The contract: configSchema (JSON Schema), declared capabilities with labels, HTTP methods, confirm flags, requiredRole viewer|operator|admin, and runsOn ops|bus|operator-pc.
health(instance) returns live status; execute(instance, capabilityId, params) performs the action. Adding dns-ovh means one new file implementing the same capability IDs as dns-godaddy—manifest, UI tabs, and bus routing stay unchanged. That is the payoff over legacy DNS drift panel code forked per registrar.
Registered provider types (initial set)
- dns-godaddy / dns-ovh — check-drift, list-records, verify-spf-dkim
- smtp-stalwart / smtp-external — peek-queue, verify-dkim, send-direct or verify-auth
- crm-twenty — count-by-tag, open-view, import-progress
- list-listmonk — list-subscribers, draft-campaign, sync-templates
- github-repo / github-org — ci-status, list-repos
- webhook-inbound — list-routes, last-event, test-payload
- scraper-oect / scraper-custom — staging-status, trigger-resume (operator PC)
- news-cms — list-articles, publish, unpublish
- server-host — discover-stack, host-metrics, site-health
Capability to UI mapping
Ops loads solution manifest connectors[], resolves each capability from the provider registry, filters by tab (Integrations, Mail, Pipelines, Settings) and roleAllows(requiredRole). Hesabi Integrations tab shows Sync templates and Draft campaign rendered from list-listmonk—not bespoke React copied from Services workspace.
Capability to bus routing
Capabilities with runsOn bus map to integration bus handlers via central registry—replacing scattered createXRoutes imports. Entry shape: capability id, connector_type, bus_handler path, method POST, auth bearer. Catalog lives in packages/contracts/bus-route-catalog.json validated by ops-validate bus-parity.
Ops Domain A calls bus over HTTPS with internal credentials—it never imports Go packages. Frozen contracts enabled platform-bus Go migration without breaking Twenty webhooks documented in inside-unified-mailer-stack.
Heterogeneous graphs
Hesabi: CRM plus lists plus SMTP plus DNS plus GitHub plus OECT scraper. DarDevLab might add webhook-inbound and deploy-static, skip scraper entirely. EscaHire waitlist might use api-third-party plus Listmonk opt-in only. Same six-tab shell, different connector arrays—deployed-realities-explained for which shells are active versus pending.
Runtime configuration (M11)
Manifest config is git baseline. Ops persists runtime overrides per connector—effectiveConfig equals merge(manifest, runtime). config.source manifest|api|manual|hybrid controls whether live API fetch supplements static JSON. Configuration dashboard on Settings tab is admin-only.
Live intelligence (M14)
Integration Inspector enriches GET config routes from bus—Twenty tags, Listmonk lists, Stalwart queue depth. Smart links in integration-link-map.js open native apps at correct screens. Non-goals: edit records in Ops, iframe embeds, replace analytics.
Validation
validate-connectors.mjs checks type registered, capabilities valid for type, config schema OK. validate-manifests.mjs ensures every solution connectors[] passes. JSON Schema under packages/contracts/schemas/connectors-registry.schema.json types the registry file itself.
Company-shared vs solution-dedicated
Most DarDev products share one Twenty and one Listmonk on dardev-vps; solution scope comes from CRM tags and list slugs in connector config, not separate servers. config.scope company-shared vs solution-dedicated badges connectors in the Configuration dashboard. Validators warn when two DNS connectors in one solution claim the same zone—preventing accidental overlap between dardev.net mail profile and hesabi.tn records.
Hesabi may attach both dns-godaddy for hesabi.tn domain records and dns-ovh for VPS PTR on company IP—different capability instances, same check-drift UX. DarDev company mail uses dardev-mail DNS profile on GoDaddy; product zones stay isolated by manifest config.
Integration clients (M13)
Third-party connectors prefer official SDKs: Octokit for GitHub, OVH npm package for PTR zones, fetch for GoDaddy domains API. crm-twenty, list-listmonk, and smtp-stalwart route through integration bus REST—no first-party Node SDK. Configuration pickers load live domain and repo lists from the same clients so manifest editing does not rely on hand-typed zone strings that typo easily.
Migration from legacy
- ops/integrations/hesabi.json → crm-twenty + list-listmonk instances
- DNS drift panel → dns-godaddy capability check-drift
- tracks.json actions → pipeline + scraper capabilities
- Stalwart queue peek → smtp-stalwart peek-queue
What is the difference between connector type and capability?
Type is the implementation (list-listmonk). Capability is an action ID (draft-campaign) that UI and bus invoke on that instance.
Can one capability exist on multiple provider types?
Yes—check-drift is shared by dns-godaddy and dns-ovh with different backend code but identical capability IDs for UI consistency.
Where do operator-PC capabilities run?
scraper-oect trigger-resume executes on the laptop. Ops shows status; bus is not in the hot path for Playwright.
Does Ops store API keys in connector config?
No. secret_ref names a VPS env var. Third-party keys stay in repo root .env per CONNECTOR-MODEL security rules.
How does this relate to CRM orchestration?
crm-twenty capabilities surface counts and views; outreach send capabilities call bus routes. CRM decides who; capabilities execute how—crm-orchestrates-bus-executes.



