Canonical reference: This guide describes the extensibility contract as it is actually implemented in the repository. Read it in full before creating a single file.
Eight traps, each one measured
Every item below is a place where an earlier version of this guide described something the repository does not do. Each carries the command that re-establishes the fact and the gate that catches it — or the honest admission that nothing does.
There are six conformance layers, not four (see the table at the end of this page).
Overview
What You Get for Free (The Shared Base)
Any connector that respects the contract inherits the following mechanisms without writing a single line inserver/core/:
What You Must Write (The Cost of a New Connector)
server/core/ may be modified: a connector is added by its own folder and its manifest, never by editing the platform.
A new daily connector is registered in two places, and skipping the second one produces rows
nothing reads:
dbt/dbt_project.yml→model-paths: add../server/modules/<name>/dbt, thendbt parse.dbt/models/marts/fact_daily_kpi.sql: add the connector’sstg_<name>_dailyto the UNION.
Choosing the Landing Kind
Themodule_kind field in manifest.json declares the structure of rows produced by the module:
Walkthrough: read a shipped connector, then copy its shape
The fastest way to write a connector is to open one that works.server/modules/brevo/
is complete and passes every conformance layer — manifest 1.2, connector.py, dbt staging
model, seed loader, fixtures, generated catalog. Every excerpt below is copied from it.
server/modules/README.md carries the Connector Standard Playbook — the exhaustive
field catalog, the doc↔code contract, account topology and the error taxonomy. Read it
alongside this page: it is what separates a connector that runs from one that can be
operated. server/modules/meta-ads/ is its most complete implementation.Step 1 — What lives on disk
server/core/ may be touched.
Step 2 — The manifest is the contract
The header declares who you are and how you authenticate:source_capabilities.reports[] declares what can actually be asked for — the metrics, the
dimensions, the supported grains, and the function the worker will call:
canonical_metric_mapping translates the provider’s vocabulary into the platform’s, so the
same figure is comparable across sources:
Step 3 — connector.py: a closed signature
account_topology.pull_parameter. Make it required and the first real
call dies with TypeError, which is exactly what happened to gsc on 2026-07-31.
Two more rules the shared base enforces:
- land rows through
core.warehouse_write.open_raw_writer, never a bareduckdb.connect— a bare connection writes into everyone’s raw zone; - raise through
classify_http_error(status, body, error_map)fromcore/pull_errors.py. A bareRuntimeErroron a non-200 means the worker cannot tell an expired token from a bad request: no reconnection offered, no breaker, no evidence kept.
Step 4 — The staging model deduplicates by pull
Re-running an extraction must not double a figure. The staging model keeps the newest pull per grain, and that is the whole of it:dbt/staging/schema.yml carries the grain_unique test that fails if that partition ever
lets a duplicate through.
Step 5 — Register in two places
Skipping the second produces rows nothing reads:dbt/dbt_project.yml→model-paths: add../server/modules/<name>/dbt, thendbt parse.dbt/models/marts/fact_daily_kpi.sql: addstg_<name>_dailyto the UNION.
Step 6 — Prove it offline
seeds/load_<name>_seed.py loads a fixture into the local warehouse so the staging model
runs without a single API call. Without it, dbt run breaks on your model and the connector
counts as covered while its warehouse half was never exercised.
tests/fixtures/golden_pull.json and expected_facts.json are the recorded provider
response and the facts it must produce. The conformance suite replays one into the other, so
a change in your transform that alters a figure fails before it reaches a warehouse.
Final Conformance Checklist
-
manifest.jsonschema version1.2withsource_capabilities(conformance_layer_1pass). -
source_capabilities.reports[].dispatch.callablenames a function that EXISTS (test_pull_contract). -
pull()keeps the closed signature; every reachable return carriespull_id,row_count,date_from,date_to. -
transform()is manifest-driven (no hardcoded field names). - Rows land through
core.raw_landing/warehouse_write— no bareduckdb.connect. - Non-200 raises through
classify_http_error+error_map— no bareRuntimeError. - No account in an environment variable, and none as a required argument.
- Google connector: manifest
authblock with its scope (test_google_consent.pygreen). -
QUALIFYsupersede staging model with the mandatorystg_<name>_daily_grain_uniquetest. - Registered in
dbt_project.yml → model-pathsand in thefact_daily_kpiUNION. - Seed loader written and run;
dbt build --select stg_<name>_dailygreen. - Fixture files
golden_pull.jsonandexpected_facts.jsonverified (conformance_layer_4pass). - All six conformance layers pass cleanly before merging.
Next Steps & Cross-References
Universal Datastreams
Learn how datastreams manage ingestion, mappings, and versioning.
Semantic Layer
Understand canonical fact surfaces and dbt semantic ratio views.
Platform Constraints
Review multi-tenant isolation rules and security invariants.
Quickstart Guide
Test your new connector in the local developer sandbox.

