1 · Author
Write YAML by hand or from the modeler. Convention: project.yml + models/
metrics/+facets/+joints/+lexicon/+contracts/.
The OpenDome Semantic Layer (OSL) is an open specification (Apache-2.0) that describes, in declarative YAML, a semantic model spanning two physical planes: structured tables in Iceberg and vector collections in Lance. One spec, one language, one governance chain.
This page fixes the vocabulary and the mental model. For the normative contract see the specification; for the API surface see the API reference.
Today’s OSS semantic layers (dbt MetricFlow, Cube, WrenAI) describe relational tables. None treats vector collections as first-class. That forces two parallel models — the SQL-semantic one and “what the RAG knows about the customer” — which diverge the day after they ship.
OSL spans both planes:
JointEntity, a logical object (Customer, Policy,
Order) that joins Iceberg columns to Lance facets under one primary key.Declare once. Governance, lineage, APIs and agents all consume the same model.
The model
OSL describes a semantic model over two physical substrates with one
declarative language. Each plane has its own primitives, FQN convention,
execution engine and evolution path. The JointEntity is the piece that
composes them.
Iceberg tables, SQL queries, aggregations, joins. Here OSL passes MetricFlow through unchanged:
semantic_models/*.yml describe physical entities with their dimensions and measures.metrics/*.yml define certified metrics (simple, ratio, cumulative, derived).saved_queries/*.yml package reusable queries.time_spine.yml defines the project’s time grain.The reference engine (tenant-semantic-api) compiles these YAML to SQL over
Trino, executed against Iceberg in the tenant’s bucket.
Lance collections with indexed chunks. Here OSL defines new primitives:
facets/*.yml (kind: UnstructuredFacet) describe a Lance collection: dataset
path, chunk schema, embedding model, indexes (vector + FTS + scalar), metadata
fields, row-level ACL and retrieval limits.The engine runs hybrid retrieval (vector ⊕ BM25 ⊕ metadata filter) over LanceDB and returns passages with citation, honoring the declared ACL and limits.
joints/*.yml (kind: JointEntity) declares a logical object whose primary
key comes from a semantic_model and which exposes composed attributes — some
from the structured plane (columns, metrics), some from the unstructured plane
(retrieval scoped by the key).The bridge is honest: each join_on maps an entity key to an
authoritative, indexed metadata field of the facet. A metadata field with
provenance: derived can never be a join key — derived extraction happens at
ingest, never at query time.
An agent calling entity_get(Customer, customer_id=X) receives, in one response,
the entity’s canonical attributes, the applicable pre-aggregated metrics, and the
Lance chunks filtered by customer_id=X. One call, one policy decision, one
audit trail.
Although the spec has separate primitives (SemanticModel, JointEntity), the
consumer sees one word: Entity. What distinguishes one Entity from
another isn’t its kind but its composition:
| Composition | What it is | Where it comes from |
|---|---|---|
structured |
Purely tabular Entity (Iceberg only) | a SemanticModel that is neither a joint anchor nor a bridge |
structured+content |
Tabular columns joined to Lance facets | a JointEntity with unstructured legs |
content |
A standalone Lance corpus, no structured anchor | an UnstructuredFacet no joint absorbs |
Relations between Entities come from two places: shared MetricFlow entities
(primary / foreign / unique) for structured ↔ structured neighbours, and
N-N via a bridge — a junction table (SemanticModel with ≥2 foreign
entities) that collapses to a direct N-N edge rather than being a node.
This vocabulary is what the domain-map (GET /osl/domain-map) serves: a
single entity node kind tagged by composition, plus metric nodes and
candidate nodes.
| Family | Kind | Purpose | MetricFlow |
|---|---|---|---|
| Structured modeling | SemanticModel, Metric, SavedQuery, TimeSpine |
Describe Iceberg tables + metrics | ✅ identical / extended |
| Unstructured modeling | UnstructuredFacet |
Describe a Lance collection | ❌ OSL-only |
| Composition | JointEntity |
Join both planes under one logical entity | ❌ OSL-only |
| Catalog & contracts | Lexicon, DataContract, PolicyBinding |
Synonyms, SLAs, hints for the PDP | ❌ OSL-only |
Every primitive carries apiVersion: osl.opendome.eu/v1, a kind, and a unique
name. An object’s identity is (kind, name) — except SemanticModel, whose
identity is (catalog, schema, table).
OSL declares; the engine executes. Between them is a compilation step.
1 · Author
Write YAML by hand or from the modeler. Convention: project.yml + models/
metrics/ + facets/ + joints/ + lexicon/ + contracts/.2 · Validate
osl validate runs JSON Schema per file plus cross-reference (every
referenced FQN must exist). Errors in E0xx (schema) or E1xx (resolve).
3 · Compile
osl compile emits a single target/manifest.json — the canonical,
reproducible representation the engine serves and the policy engine reads.
4 · Publish
osl publish uploads the manifest to the tenant’s engine. Atomic (revert
with osl publish --revert), emits an osl.publish lineage event.
From there the engine serves queries: REST for BI/apps, MCP tools for agents.
OSL is strict about names because policies depend on them. Four FQN spaces:
| Space | Form | Example |
|---|---|---|
| Structured | <catalog>.<schema>.<table>[:<column>] |
iceberg.curated.customer:email |
| Unstructured | lance://<collection>[/*][:<metadata_field>] |
lance://meeting_transcripts:attendees |
| Tools | <tool_kind>:<resource> |
metrics:revenue, joints:Customer |
| Joint-exposed | joint://<Entity>.<attribute> |
joint://Customer.recent_meeting_topics |
FQNs are case-sensitive and carry no version — versioning lives in the compiled,
SHA-signed manifest. The policy engine consumes these FQNs in its 4-D tuple
(data, action, actor, context). OSL doesn’t invent a parallel access
semantics; it emits the facts the PDP indexes.
OSL is the shared spec between all those pieces, not the pieces.