benchouse
semglot
Goโœจ New

Semantic-layer transpiler: one neutral IR, many dialects (dbt, Snowflake Cortex, semantic views, supersimple, nao). Written in Go.

Last updated Jul 27, 2026
10
Stars
0
Forks
3
Issues
0
Stars/day
Attention Score
35
Language breakdown
Go 100.0%
โ–ธ Files click to expand
README

semglot

A semantic-layer transpiler: one neutral IR, many dialects.

Built for benchouse.ai, the independent leaderboard for analytics agents, and open-sourced for everyone.


Where sqlglot translates across SQL dialects, semglot translates across semantic-layer dialects (dbt semantic models, Snowflake Cortex, Snowflake semantic views, Databricks metric views, and more) through one neutral intermediate representation (IR).

You point it at a source layer, pick a target dialect, and it writes the equivalent layer out. Because everything routes through the IR, adding a dialect adds every conversion into and out of it, not just one.

Semantic Layer Dialects

A source is read into the IR; a target is written from it. dbt is both, so dbt to dbt is a lossless round-trip.

| Dialect | Source | Target | |---------------------------|:------:|:------:| | dbt | โœ“ | โœ“ | | cortex | | โœ“ | | snowflake-semantic-view | | โœ“ | | supersimple | | โœ“ | | nao-yaml | | โœ“ | | nao-context-rules | | โœ“ | | databricks-metric-view | | โœ“ |

Adding a dialect is small, self-contained work: implement a Parser (dialect files to IR), an Emitter (IR to dialect files), or both โ€” the interfaces in dialect/dialect.go โ€” register it via init(), and every conversion to and from it comes for free. A target dialect is one method, Emit. See CONTRIBUTING.md. Missing one you need? Please open an issue or PR.

Install

go install github.com/benchouse/semglot/cmd/semglot@latest

or, from a clone:

go build -o semglot ./cmd/semglot

Usage

build transpiles a source semantic layer into a target dialect. Builds are configured with named profiles in semglot.yaml:

# semglot.yaml
profiles:
  catalog:
    source: ./models
    target-dialect: snowflake-semantic-view
    output: ./out
    database: ANALYTICS
    model-name: catalog

Given a small dbt table:

# models/schema.yml
models:
  - name: dim_product
    description: Product dimension.
    columns:
      - name: product_id
        description: Product surrogate key.
        data_type: number
        constraints:
          - type: primary_key
      - name: category
        description: Product category.
        data_type: varchar
      - name: title
        description: Product title.
        data_type: varchar

run the profile:

semglot build --profile catalog

semglot writes out/definition.md with the create statement:

create or replace semantic view CATALOG
	tables (
		DIMPRODUCT as ANALYTICS.MAIN.DIMPRODUCT primary key (PRODUCT_ID) comment='Product dimension.'
	)
	dimensions (
		DIMPRODUCT.PRODUCTID as dimproduct.PRODUCTID comment='Product surrogate key.',
		DIMPRODUCT.CATEGORY as dimproduct.CATEGORY comment='Product category.',
		DIMPRODUCT.TITLE as dimproduct.TITLE comment='Product title.'
	)
;

Options

  • --profile <name> selects a profile from the config. Required.
  • --config <path> points at the config file. Defaults to ./semglot.yaml.
Anything a target dialect can't express is reported rather than dropped silently (e.g. a NOTES.md sidecar listing metrics that don't map).

Configuration

A profile is a complete, self-contained build. Every field:

# semglot.yaml
profiles:
  view_prod:
    source: ./models              # required. dbt source dir, or a list of dirs
    source-dialect: dbt           # optional. default: dbt
    target-dialect: snowflake-semantic-view   # required
    output: ./out/view            # required. directory to write into
    database: ANALYTICS           # required for warehouse targets (cortex, snowflake-semantic-view, databricks-metric-view)
    schema: SEM                   # optional. default: MAIN (schema of the source tables)
    view-schema: SEM_VIEWS        # optional. schema for the emitted semantic-view object; defaults to schema
    model-name: catalog           # optional. default: source dir name
    description: Curated view.     # optional
  • Each profile is independent: there is no shared or inherited config. Staging and
production are two profiles that differ only in database and output.
  • Omitted optional fields take defaults: source-dialect is dbt, schema is
MAIN, and model-name is the source directory name.
  • build fails clearly when the config is missing or unparseable, the --profile
is not found, a required field (source, target-dialect, output) is absent, or a warehouse target has no database.

Dialect support

Every dialect maps to the same neutral IR, but targets differ in how much of it they can express. This is what each target emits today (dbt is currently the only source).

| Feature | dbt | cortex | snowflake-semantic-view | supersimple | nao-yaml | nao-context-rules | databricks-metric-view | |-------------------------|:-----:|:--------:|:-------------------------:|:-------------:|:----------:|:-------------------:|:------------------------:| | Tables | โœ“ | โœ“ | โœ“ | โœ“ | | ~ | โœ“ | | Columns | โœ“ | โœ“ | โœ“ | โœ“ | โœ“ | ~ | โœ“ | | Time dimensions | โœ“ | โœ“ | ~ | โœ“ | โœ“ | ~ | ~ | | Descriptions | โœ“ | โœ“ | โœ“ | โœ“ | ~ | โœ“ | โœ“ | | Data types | โœ“ | โœ“ | | โœ“ | | | | | Primary keys | โœ“ | โœ“ | โœ“ | โœ“ | | | | | Relationships | โœ“ | โœ“ | โœ“ | โœ“ | | โœ“ | โœ“ | | Metrics (aggregations) | โœ“ | โœ“ | โœ“ | โœ“ | ~ | โœ“ | โœ“ | | Ratio & derived metrics | โœ“ | โœ“ | โœ“ | ~ | โœ“ | โœ“ | โœ“ | | Synonyms | ~ | โœ“ | | | โ‰ˆ | โ‰ˆ | โœ“ | | Enums / allowed values | โœ“ | ~ | โ‰ˆ | โ‰ˆ | โœ“ | โœ“ | โ‰ˆ |

โœ“ structured ยท โ‰ˆ rolled up as text in a description or comment ยท ~ partial ยท blank not emitted.

Where a target has no native slot for something, semglot degrades rather than drops it:

  • โ‰ˆ means the value survives only as text inside a parent's description or
comment (Values: โ€ฆ), not as a structured field. Enums and synonyms fold this way when the target has no native slot for them.
  • cortex is the exception: it has a native synonyms field and keeps enum
sample values.
  • supersimple emits division ratios; other arithmetic is deferred to a
NOTES.md sidecar.
  • nao-yaml is a flat, model-global document, so it has no table grouping.
  • nao-context-rules is prose, so it lists only elements that carry a
description or synonyms.
  • databricks-metric-view requires Databricks Runtime 17.2+ for the base
metric-view YAML shape; display_name and synonyms are emitted whenever the IR carries a label or synonyms and require Runtime 17.3+. On an older warehouse, a view containing them is rejected.

License

MIT. See LICENSE.

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท benchouse/semglot ยท Updated daily from GitHub