An Ossie Converter translates between the Ossie semantic model format and a specific vendor's semantic implementation. This enables teams to author a semantic model once in the Ossie standard and then generate the corresponding vendor-specific representation automatically.
Ossie converters follow a hub-and-spoke architecture:
- Hub: The Ossie core specification acts as the central, vendor-neutral format.
- Spokes: Each converter handles translation to or from a specific vendor format.
┌─────────────┐
│ Snowflake │
└──────┬──────┘
│
┌─────────────┐ ┌─────┴─────┐ ┌─────────────┐
│ dbt ├────┤ Ossie ├────┤ Salesforce │
└─────────────┘ └─────┬─────┘ └─────────────┘
│
┌──────┴──────┐
│ Databricks │
└─────────────┘
This approach avoids the need for point-to-point converters between every pair of vendors. With N vendors, a point-to-point strategy would require N*(N-1) converters. With Ossie as the hub, only 2*N converters are needed (one import and one export per vendor), and interoperability with all other vendors comes for free.
A converter handles two directions of translation:
Read an Ossie semantic model and produce the equivalent vendor-specific representation. For example:
- Ossie → Snowflake semantic model definition
- Ossie → dbt
semantic_modelsYAML - Ossie → Tableau data source / Salesforce semantic layer
- Ossie → Databricks semantic layer definition
Read a vendor-specific semantic model and produce a valid Ossie model, including mapping vendor-specific metadata into custom_extensions.
The Ossie specification currently defines extensions for the following vendors:
| Vendor | Description |
|---|---|
SNOWFLAKE |
Snowflake semantic model |
SALESFORCE |
Salesforce / Tableau semantic layer |
DBT |
dbt semantic models |
DATABRICKS |
Databricks semantic layer |
OMNI |
Omni semantic model |
WISDOM |
WisdomAI domain |
NVIDIA_GSF |
NVIDIA Generative Semantic Fabric standalone YAML |
Each vendor may define custom extensions (via the custom_extensions field in the Ossie spec) to carry vendor-specific metadata that does not have an equivalent in the core specification.
The following table shows how each Ossie construct maps conceptually to vendor equivalents. A converter must handle each of these:
The top-level container. Maps to the root object in each vendor's format.
| Ossie Field | Description | Converter Consideration |
|---|---|---|
name |
Model identifier | Map to vendor's model/project name |
description |
Human-readable description | Most vendors support a description field |
ai_context |
Instructions, synonyms for AI tools | Map if vendor supports AI/LLM annotations |
datasets |
Logical datasets (fact/dimension tables) | See dataset mapping below |
relationships |
Foreign key connections | See relationship mapping below |
metrics |
Aggregate measures | See metric mapping below |
custom_extensions |
Vendor-specific metadata | Extract extensions matching the target vendor |
Datasets represent logical tables (fact or dimension tables). They contain fields and define the structure of the data.
| Ossie Field | Description | Converter Consideration |
|---|---|---|
name |
Dataset identifier | Map to table/entity/model name |
source |
Physical table reference (e.g., database.schema.table) |
Parse into vendor-specific catalog/schema/table components |
primary_key |
Single or composite primary key | Map to vendor's PK syntax; note composite keys use arrays like [order_id, line_number] |
unique_keys |
Alternative unique identifiers | Map if vendor supports unique constraints |
fields |
Row-level attributes (columns) | See field mapping below |
ai_context |
Synonyms and context for AI | Map if vendor supports semantic annotations |
custom_extensions |
Vendor-specific metadata | Extract extensions matching the target vendor |
Fields represent row-level attributes. They can be simple column references or computed expressions.
Note:
datatype(onFieldandMetric) declares a field's logical data type;dimension.is_timeis an independent temporal-role marker. A field may carry both, either, or neither. Usedatatypefor data-type questions (casting, serialization); useis_timefor role questions (classifying time dimensions). Whenis_timeis unset it defaults totrueifdatatypeis one ofDate,Time,DateTime,DateTimeTz, andfalseotherwise. Explicitis_timealways wins.
| Ossie Field | Description | Converter Consideration |
|---|---|---|
name |
Field identifier | Map to column/attribute name |
expression.dialects |
Multi-dialect SQL expressions | Select the dialect matching the target vendor; fall back to ANSI_SQL |
datatype |
Logical data type of the field (one of String, Integer, Decimal, Float, Boolean, Date, Time, DateTime, DateTimeTz, Opaque). |
Converters SHOULD consult datatype for the field's logical data type. Decimal is exact base-10 with unspecified precision and scale; Float is approximate. Prefer the temporal members (Date, Time, DateTime, DateTimeTz) to classify time dimensions. Omit datatype when unknown; use Opaque + custom_extensions for a known type outside the portable vocabulary. |
dimension.is_time |
Temporal-role marker. When true, the field should be treated as a time dimension regardless of its datatype (e.g. an Integer year grain, a String month name, or a Date column). When unset, defaults to true for temporal datatypes (Date, Time, DateTime, DateTimeTz) and false otherwise. |
Map to vendor-specific time dimension markers. Converters SHOULD classify as a time dimension when is_time resolves to true (either explicit or defaulted from a temporal datatype). An explicit is_time: false suppresses the time-dimension classification even on temporal-typed columns. |
label |
Categorization label | Map if vendor supports field labels/tags |
description |
Human-readable description | Most vendors support field descriptions |
ai_context |
Synonyms and business context | Map if vendor supports semantic annotations |
Expression dialect selection: A field may provide expressions in multiple dialects. For example:
expression:
dialects:
- dialect: ANSI_SQL
expression: LOWER(email)
- dialect: SNOWFLAKE
expression: LOWER(email)::VARCHARA Snowflake converter should pick the SNOWFLAKE dialect when available, and fall back to ANSI_SQL otherwise.
Relationships define foreign key connections between datasets. They support both simple and composite keys.
| Ossie Field | Description | Converter Consideration |
|---|---|---|
name |
Relationship identifier | Map to vendor's join/relationship name |
from |
Many-side dataset | Map to the referencing table |
to |
One-side dataset | Map to the referenced table |
from_columns |
Foreign key columns (array) | Positional correspondence with to_columns; handle composite keys |
to_columns |
Primary/unique key columns (array) | Must have same cardinality as from_columns |
Composite key example: A composite relationship like:
from_columns: [product_id, variant_id]
to_columns: [id, variant_id]means from.product_id = to.id AND from.variant_id = to.variant_id. The converter must generate the equivalent multi-column join in the target vendor format.
Metrics are aggregate measures defined at the semantic model level. They can span multiple datasets via relationships.
| Ossie Field | Description | Converter Consideration |
|---|---|---|
name |
Metric identifier | Map to vendor's measure/KPI name |
expression.dialects |
Multi-dialect aggregate expressions | Select the appropriate dialect; fall back to ANSI_SQL |
datatype |
Logical data type of the metric result (one of String, Integer, Decimal, Float, Boolean, Date, Time, DateTime, DateTimeTz, Opaque). |
Converters SHOULD consult datatype to declare the result type of the aggregation. Numeric measures should distinguish exact Decimal or Integer results from approximate Float results. Omit datatype when unknown; use Opaque + custom_extensions for a known type outside the portable vocabulary. |
description |
What the metric measures | Most vendors support descriptions |
ai_context |
Synonyms and business context | Map if vendor supports semantic annotations |
Cross-dataset metric example:
- name: customer_lifetime_value
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(store_sales.ss_ext_sales_price) / COUNT(DISTINCT customer.c_customer_sk)The converter must ensure that the dataset references (store_sales, customer) are resolved correctly in the target vendor's format and that any required joins are established.
Custom extensions carry vendor-specific metadata as a JSON string. A converter should:
- On export (Ossie → Vendor): Extract extensions where
vendor_namematches the target vendor, parse thedataJSON, and apply the vendor-specific settings. - On import (Vendor → Ossie): Capture vendor-specific settings that have no Ossie core equivalent and store them as a
custom_extensionentry.
Example: A Snowflake export converter would extract:
custom_extensions:
- vendor_name: SNOWFLAKE
data: '{"warehouse": "ANALYTICS_WH", "database": "PROD", "schema": "PUBLIC"}'and apply warehouse, database, and schema to the appropriate places in the Snowflake model definition.
The ai_context field appears at every level (model, dataset, field, relationship, metric). It can be a simple string or a structured object:
# Simple string
ai_context: "orders, purchases, sales"
# Structured object
ai_context:
instructions: "Use this for sales analysis"
synonyms:
- "orders"
- "purchases"
examples:
- "Show total sales last month"A converter should map ai_context when the target vendor supports equivalent constructs (e.g., LLM instructions, column descriptions with business terms). When the target vendor does not support AI annotations natively, the converter may encode them in custom_extensions on import to avoid data loss.
-
Validate input: Use the Ossie JSON Schema and the validation script to ensure the source Ossie model is valid before conversion.
-
Parse the Ossie model: Load the YAML file and iterate over the top-level
semantic_modelentries. -
Map datasets: For each dataset, translate the
name,source,primary_key,unique_keys, andfieldsto the vendor's format. Parse thesourcestring (typicallydatabase.schema.table) into the vendor's catalog structure. -
Map fields with dialect selection: For each field, select the expression dialect that matches the target vendor. Implement a fallback chain:
- Prefer the vendor-specific dialect (e.g.,
SNOWFLAKEfor a Snowflake converter) - Fall back to
ANSI_SQLif the vendor dialect is not available - Raise a warning or error if neither is available
- Prefer the vendor-specific dialect (e.g.,
-
Map relationships: Translate relationship definitions into the vendor's join syntax. Ensure composite key column ordering is preserved.
-
Map metrics: Translate metric expressions using the same dialect selection logic as fields. Resolve dataset references (e.g.,
store_sales.ss_ext_sales_price) into the vendor's qualified column format. -
Apply custom extensions: Extract
custom_extensionsentries matching the targetvendor_nameand apply vendor-specific settings to the output. -
Preserve AI context: Map
ai_contextto vendor-equivalent annotations where supported. -
Validate output: Verify the generated vendor model is valid according to the vendor's own schema or tooling.
| Scenario | Recommended Approach |
|---|---|
| Missing vendor-specific dialect for a field/metric | Fall back to ANSI_SQL; log a warning |
| Computed fields with vendor-specific SQL syntax | Require the vendor dialect in the source Ossie model; error if neither vendor nor ANSI dialect is available |
| Composite primary keys | Ensure the vendor format supports composite keys; if not, flatten or document the limitation |
| Cross-dataset metrics referencing multiple tables | Ensure all referenced datasets exist and relationships are defined; resolve qualified column names |
| Custom extensions with unknown vendor | Ignore (do not discard) — preserve for round-tripping |
ai_context on a vendor that doesn't support it |
Store in a custom_extension with vendor_name: COMMON to preserve for round-tripping |
A well-implemented converter pair (import + export) should preserve as much information as possible during round-tripping:
Vendor A model → [Import] → Ossie model → [Export] → Vendor A model
To achieve this:
- Never discard information silently. If a vendor-specific attribute has no Ossie core equivalent, store it in
custom_extensions. - Preserve field ordering where possible, as some vendors are sensitive to declaration order.
- Preserve
custom_extensionsfor all vendors, not just the target vendor. This allows a model to carry metadata for multiple vendors simultaneously (e.g., a single Ossie model with both Snowflake and dbt extensions).
Given the TPC-DS example included in this repository, a Snowflake export converter would:
- Read the
tpcds_retail_modelsemantic model. - Create a Snowflake semantic model with name
tpcds_retail_model. - Map each dataset (
store_sales,date_dim,customer,item,store) to Snowflake table references, parsingsourcevalues liketpcds.public.store_salesinto Snowflake'sdatabase.schema.tableformat. - For each field, select the
ANSI_SQLdialect expression (since noSNOWFLAKEdialect is provided in this example). - Translate relationships into Snowflake join definitions, mapping
from_columnsandto_columnspairs. - Translate metrics like
total_sales(SUM(store_sales.ss_ext_sales_price)) into Snowflake metric definitions. - Extract the
SALESFORCEandDBTcustom extensions — these would not be applied to the Snowflake output but should be preserved if the model is later imported back to Ossie.
To add support for a new vendor:
- Use a stable
vendor_namestring in each custom extension emitted by the converter. - Define the custom extension schema for the vendor (what vendor-specific metadata fields are supported in the
dataJSON). - Implement the export converter (Ossie → Vendor).
- Implement the import converter (Vendor → Ossie).
- Add tests using the TPC-DS example model as a baseline.
- Document any limitations or unsupported constructs.