Skip to content

dbt

Author in dbt. Serve through OnlyMetrix.

omx dbt sync reads your target/manifest.json after dbt run, compiles your metric definitions through the OM IR compiler, and makes them queryable by AI agents.

Install

bash
pip install onlymetrix

The omx CLI ships with the SDK. No separate install.

Set credentials

bash
export OMX_API_URL=https://api.onlymetrix.com
export OMX_API_KEY=omx_sk_...

Connect your warehouse

bash
omx dbt connect

Reads your ~/.dbt/profiles.yml — the same credentials dbt uses — and registers the datasource with OnlyMetrix. No manual credential entry.

Reading ~/.dbt/profiles.yml

Profile: my_project | Target: dev | Type: postgres
  Host: db.example.com:5432
  Database: analytics
  User: dbt_user
  Password: ********

These credentials will be sent to OnlyMetrix to
execute metric queries against your warehouse.

Connect? [y/n] y
Connected: my_project_dev (postgres)
Run `omx dbt sync` to register your metrics.

Use --profile and --target to override which profile to connect:

bash
omx dbt connect --profile my_project --target prod

Environment variables in profiles.yml (like {{ env_var('DBT_PASSWORD') }}) are resolved automatically from your current environment.

Sync metrics

bash
dbt run
omx dbt sync

Output:

Synced 5 metrics (3 created, 2 updated)
Compile: 4 structured, 1 opaque, 0 failed
Tier updates: 1

Your metrics are now agent-queryable. Agents call query_metric("total_revenue") and get a deterministic result.

Preview with dry-run

bash
omx dbt sync --dry-run
Found 5 metrics in manifest

  total_revenue     -> structured    (tier: core)      [create]
  customer_count    -> structured    (tier: standard)  [unchanged]
  active_users      -> structured    (tier: standard)  [update]
  churn_rate        -> opaque        (tier: standard)  [create, ratio -> splits]
  ltv_estimate      -> opaque        (tier: standard)  [create, derived]

Would sync: 3 metrics (1 structured, 2 opaque), skip 1 unchanged
Would update: 1 tier

No API calls. Shows exactly what would change.

Configure via meta

Control OnlyMetrix behavior from your dbt YAML using meta.onlymetrix:

yaml
# schema.yml
metrics:
  - name: total_revenue
    description: "Total paid revenue in USD"
    type: simple
    type_params:
      measure: order_total
    meta:
      onlymetrix:
        tier: core              # core / standard / foundation
        autoresearch: true      # enable overnight improvement loops
        scorer: revenue_corr    # autoresearch scoring function
FieldValuesDefaultDescription
tiercore, standard, foundationstandardControls visibility and search ranking
autoresearchtrue, falsefalseEnable automated metric improvement
scorerscorer namenoneWhich scoring function for autoresearch
pii_columnslist of column names[]Flag PII columns for masking

Tier behavior

  • Core -- pinned to top of catalog, highest search rank, always visible
  • Standard -- default for authored/imported metrics, shown in main catalog
  • Foundation -- collapsed by default, basic aggregations. The sync never overwrites a tier you set manually in the UI.

Metric type support

dbt typeOM compile resultWhat happens
simple (sum, count, avg, min, max)StructuredFull IR decomposition, filters + dimensions work
count_distinctStructured
ratioOpaqueNumerator + denominator synced as separate Structured metrics
derivedOpaqueExpression preserved, not decomposed
Legacy (dbt < 1.6)Structuredtype + sql + model translated to SQL template

Ratio metrics are flagged clearly in the dry-run output:

churn_rate -> opaque (ratio -> splits into churned_count + total_subscriptions)

The components (churned_count, total_subscriptions) are synced as Structured metrics that agents can query individually.

Change detection

Sync is idempotent. Each metric definition is hashed (SHA256 of name + description + SQL + tags + meta). Unchanged metrics are skipped automatically.

bash
# First run: creates all metrics
omx dbt sync
# Synced 5 metrics (5 created, 0 updated)

# Second run: nothing changed
omx dbt sync
# All 5 metrics unchanged. Nothing to sync.

# After editing a metric description in dbt
omx dbt sync
# Synced 1 metrics (0 created, 1 updated), skip 4 unchanged

Hashes are stored in target/.onlymetrix_sync_state.json.

dbt test: compiles_as_structured

Validate that your metrics compile as Structured IR in your dbt test suite.

Install the dbt package

yaml
# packages.yml
packages:
  - git: "https://github.com/dreynow/dbt-onlymetrix.git"
    revision: main
bash
dbt deps

Add the test

yaml
# schema.yml
models:
  - name: orders
    columns:
      - name: revenue
        tests:
          - onlymetrix.compiles_as_structured:
              metric_name: total_revenue

Run

bash
omx dbt sync --write-status-table    # writes _onlymetrix_compile_status to warehouse
dbt test                              # test queries the status table

The test passes if the metric compiled as Structured. Fails if Opaque or failed. This catches compiler issues at PR time, not in production.

CI/CD

GitHub Actions

yaml
jobs:
  dbt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install
        run: pip install dbt-core onlymetrix

      - name: dbt run
        run: dbt deps && dbt run

      - name: Sync metrics to OnlyMetrix
        run: omx dbt sync
        env:
          OMX_API_URL: ${{ secrets.OMX_API_URL }}
          OMX_API_KEY: ${{ secrets.OMX_API_KEY }}

      - name: dbt test
        run: dbt test

Strict mode for CI

bash
omx dbt sync --strict

Exits non-zero if any metric is opaque or failed. Use this to enforce Structured IR compilation on every PR.

CLI reference

omx dbt sync [OPTIONS]

Options:
  --manifest PATH          Path to manifest.json
                           Default: ./target/manifest.json
  --project-dir PATH       dbt project directory
  --dry-run                Preview sync without calling API
  --write-status-table     Write compile status to warehouse table
  --strict                 Exit non-zero if any metric is opaque/failed
  --url TEXT               OnlyMetrix API URL (overrides OMX_API_URL)
  --api-key TEXT           API key (overrides OMX_API_KEY)

How it works

omx dbt connect          # reads profiles.yml, registers datasource
  |
  v
dbt run                  # your normal workflow
  |
  v
omx dbt sync             # reads manifest.json, registers metrics
  |-- parse metrics block (MetricFlow + legacy)
  |-- translate type_params to SQL templates
  |-- hash comparison (skip unchanged)
  |-- POST /v1/metrics/sync-dbt
  |
  v
OM IR compiler
  |-- Structured: full decomposition, filters, dimensions
  |-- Opaque: SQL preserved as-is
  |
  v
Governed API
  |
  v
AI agents query deterministically

What's next

MIT Licensed (SDK) | Proprietary (Server)