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)