Skip to content

Semantic Model

A bundle can carry what its data means, not just its shape. Two things make up its semantic model:

  • Column descriptions — what a column actually is (amt is "order total in USD, net of refunds").
  • Named metrics — the canonical way to compute a number (total_revenue is SUM(amount), and nothing else).

Both are recorded as operations, so they travel inside the bundle, are versioned like any other change, and survive commit and reopen. Anyone who opens the bundle — a teammate, a BI tool, or an AI agent — gets the same definitions, along with the history of who set each one and when.

This is not a semantic layer in the dbt or Cube sense. There is no query gateway in front of your warehouse. The definitions are stored with the data, in the same versioned directory, and go wherever the bundle goes.

Why it matters

A bare schema tells a reader that a column is called amt and holds a number. It does not say whether that number includes refunds, tax, or shipping — so two people asking "what was revenue?" write two different SUMs and get two different answers, both of which look right.

This is especially acute for AI assistants. Given only column names and types, an assistant writes plausible SQL that can quietly disagree with the ground truth. Giving it the column's meaning and the author's canonical metric definition is what turns a plausible answer into a correct one.

Describing columns

Attach a description to any column. A later DESCRIBE COLUMN on the same column replaces the earlier one.

DESCRIBE COLUMN amount AS 'order total in USD, net of refunds'
DESCRIBE COLUMN status AS 'one of: pending, shipped, cancelled'
c = await c.describe_column("amount", "order total in USD, net of refunds")
c.describe_column("amount", "order total in USD, net of refunds")

Defining metrics

A metric is a named, reusable aggregate expression — a measure. Unlike a view (a whole query), a metric is a single expression meant to be composed with different dimensions: group it by region this time, by month the next. A later CREATE METRIC with the same name replaces the earlier one.

The expression is checked against the bundle when you define it, so a misspelled column fails right away rather than the first time someone uses the metric. Column references follow the columns themselves: if you later RENAME COLUMN amount TO total, the metric keeps working and is listed as SUM(total). Column descriptions follow renames the same way.

CREATE METRIC total_revenue AS 'SUM(amount)' DESCRIPTION 'gross revenue in USD'
CREATE METRIC avg_order_value AS 'SUM(amount) / COUNT(DISTINCT order_id)'

DROP METRIC avg_order_value
c = await c.define_metric("total_revenue", "SUM(amount)", "gross revenue in USD")
c = await c.drop_metric("avg_order_value")
c.define_metric("total_revenue", "SUM(amount)", "gross revenue in USD")
c.drop_metric("avg_order_value")

How consumers see it

Python. Any bundle, opened or being built, exposes the definitions and can evaluate them:

bundle.metrics()              # [{"name": "total_revenue", "expression": "SUM(amount)", "description": ...}]
bundle.column_descriptions()  # {"amount": "order total in USD, net of refunds", ...}

result = await bundle.compute_metric("total_revenue", ["region"])
df = await result.to_pandas()

report = await bundle.data_quality()  # per-column null/distinct counts, suggested casts
bundle.metrics()
bundle.column_descriptions()
df = bundle.compute_metric("total_revenue", ["region"]).to_pandas()
report = bundle.data_quality()

AI assistants (MCP). The describe tool returns the schema with column descriptions, plus the list of metrics — so the assistant knows what the data is before it writes any SQL. The metric tool then computes a metric by name, using the bundle author's definition rather than one the assistant invented:

metric(bundle="sales", name="total_revenue")
metric(bundle="sales", name="total_revenue", dimensions=["region"])

See the MCP Server Guide.

BI tools (Arrow Flight SQL). Column descriptions are exported as Arrow field metadata under the key description, so clients that read field metadata display them alongside the column. See Column Descriptions in BI Tools.

Practical advice

Describe the columns whose meaning is not obvious from the name, and define the metrics people will actually ask for. A bundle whose numbers everyone computes the same way is worth considerably more than one that merely holds the rows.