Bruin Semantic Layer
SkillMonitoring & opsLets your agent create and edit Bruin semantic layer models, defining metrics, dimensions, joins, and queries in YAML.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Bruin Semantic Layer skill
About this capability
Use when creating, editing, reviewing, or troubleshooting Bruin semantic layer models, semantic query CLI usage, metric and dimension definitions, joins, segments, filters, windows, or semantic-layer tests and docs in a Bruin repository.
What this skill tells your AI
The instructions your AI receives, as published by bruin-data/bruin in skills/bruin-semantic-layer/SKILL.md and read by ahel’s review.
Workflow
- Find the repository root and inspect
semantic/before editing. Bruin loads every.ymland.yamlmodel under the repository-levelsemantic/directory next to.bruin.yml. - Use local source of truth before guessing:
docs/core-concepts/semantic-layer.md,docs/commands/query.md,pkg/semantic/model.go,pkg/semantic/engine.go, andpkg/semantic/graph.go. - Keep model names unique across the semantic catalog. New models should set
schema: v1, although omitted schema defaults tov1. - Prefer reusable, business-named metrics, dimensions, and segments. Avoid putting dashboard-specific logic into one large SQL query.
- Validate with a narrow semantic query first, then run the repository-required final checks before finishing.
Model Pattern
Create or edit files under semantic/:
schema: v1
name: orders
label: Orders
description: Revenue and order metrics
source:
table: analytics.orders
primary_key: order_id
joins:
- name: customers
relationship: many_to_one
foreign_key: customer_id
dimensions:
- name: order_date
type: time
expression: created_at
granularities:
day: date_trunc('day', created_at)
month: date_trunc('month', created_at)
- name: country
type: string
- name: is_first_order
type: boolean
expression: customer_order_number = 1
metrics:
- name: revenue
expression: sum(amount)
format:
type: currency
currency: USD
decimals: 2
- name: order_count
expression: count(distinct order_id)
- name: avg_order_value
expression: "{revenue} / {order_count}"
- name: completed_revenue
expression: sum(amount)
filter: "status = 'completed'"
- name: running_revenue
expression: "{revenue}"
window:
type: running_total
order_by: order_date
partition_by:
- country
segments:
- name: completed
filter: "status = 'completed'"
Default Model Behavior
source.tableis required and can be a relation name or a parenthesized SQL subquery with an alias.label,description,group,hidden, andformatmetadata help consumers but do not change SQL generation.- Dimension
expressiondefaults to the dimensionname. - Dimension
typecan bestring,number,boolean, ortime; onlytimedimensions can use granularities. - Query time dimensions as
name:granularity, for exampleorder_date:month. hidden: truehides a dimension from UI-style consumers but does not make it unqueryable.- Metrics, dimensions, and segments share a model-level namespace; duplicate names are invalid.
- Metric, dimension, and segment names should be stable API names, not display labels.
Metric Behavior
- Base metrics are SQL aggregate expressions such as
sum(amount)orcount(distinct order_id). - Derived metrics use
{metric_name}references. References must resolve and cannot form cycles. - Division by a referenced metric is guarded with
NULLIF(..., 0)during SQL generation. - Metric
filterwraps the metric aggregation. For example,sum(amount)with a filter becomes a conditional aggregate. - A metric can mix raw aggregation and
{refs}for simple queries, but do not put that mixed metric in a window metric dependency chain. - Supported format metadata types are
number,currency,percentage, anddecimal.
Window Metrics
Window metrics calculate after an inner grouped query and must use expression: "{base_metric}".
- Supported
window.typevalues:running_total,lag,lead,rank, andpercent_of_total. running_total,lag,lead, andrankrequirewindow.order_byreferencing a dimension.lagandleaddefaultoffsetto1when omitted or set to zero.partition_byentries must reference dimensions.percent_of_totaldoes not requireorder_by; it can usepartition_by.- Filters and segments are applied inside the inner query before the window expression runs.
Filters And Segments
- Segments are named SQL filters and are applied with
--segment. - Structured filters use JSON with
dimension,operator, and optionalvalue. - Supported operators:
equals,not_equals,gt,gte,lt,lte,in,not_in,between,is_null,is_not_null. betweenaccepts a two-item array or an object withstartandend.- Filters can also use raw
expression; use this sparingly because it bypasses structured validation. - Filters or segments that reference metrics or aggregates compile into
HAVING; dimension-only filters compile intoWHERE. - Filter values are SQL-formatted by type; strings are single-quoted and escaped.
Joins
- Join
nameis the relation prefix used in queries, such ascustomers.country. - If
modelis omitted, Bruin uses the join name as the target model name. - Valid relationships are
one_to_one,many_to_one,one_to_many, andmany_to_many. - Only
one_to_oneandmany_to_oneare automatically traversed in semantic queries because they avoid fanout. - A join needs either
foreign_keyor customsql. - For
foreign_keyjoins, Bruin joins the current model'sforeign_keyto the target model'starget_key; iftarget_keyis omitted, the target model must defineprimary_key. - Custom join SQL can reference aliases such as
{orders},{customers}, or the join name placeholder.
Query Pattern
Use an anchor SQL asset when Bruin should infer the pipeline, connection, and dialect:
bruin query \
--asset ./pipelines/daily-orders/assets/orders.sql \
--semantic-model orders \
--dimension order_date:month \
--metric revenue \
--filter '{"dimension":"country","operator":"equals","value":"US"}' \
--segment completed \
--sort revenue:desc \
--output json
Use a pipeline path when there is no anchor asset, and pass the connection explicitly:
bruin query \
--pipeline ./pipelines/daily-orders \
--connection warehouse \
--semantic-model orders \
--dimension customers.country \
--metric revenue \
--sort customers.country:asc
Semantic query mode requires at least one dimension or metric and cannot be combined with --query. Sort direction defaults to asc; --limit applies only when greater than zero.
Validation Notes
- Required model fields:
nameandsource.table. - Required item fields: dimension
name, metricnameandexpression, segmentnameandfilter. - Window metrics must reference exactly one metric, for example
expression: "{revenue}". - Window
order_byandpartition_byvalues must reference dimensions on the model. - Joined dimensions must resolve through a safe join path.
- Unknown metrics, dimensions, segments, filter operators, sort fields, and granularities fail semantic query compilation.
For behavior changes, update the implementation, tests, and user-facing docs together: pkg/semantic/, docs/core-concepts/semantic-layer.md, and docs/commands/query.md.
Signals
- GitHub stars
- 2k
- Forks
- 90
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
bruin-semantic-layer- Source
- github.com/bruin-data/bruin