Migrate from Omni
Convert your Omni shared model, topics, and views into governed Malloy semantic models
Omni's model spans layers — a shared model every workbook inherits, per-workbook extensions, and branches in between. Credible reads across all of them, reconciles the definitions into one canonical set, and rebuilds your analytical domain as governed Malloy.
What Credible Reads
Your Omni model — .view files (dimensions and measures over tables) and .topic files (views joined into queryable units, with AI context and default filters), authored in YAML. The agent works from those files directly, inventorying workbook-level extensions too — logic often lives there, not just in the shared model. Connecting Omni's MCP server or Model API is optional and adds live validation (and can round-trip the model files).
What Comes Across
The everyday modeling carries over. Here's how the bigger pieces land — and where they get better:
| In Omni | In Credible |
|---|---|
| Shared model, topics, views | Malloy sources (base + joined); import/export curate exposure |
| Dimensions & measures | Carried over, filtered and ratio measures included |
Field-level sql: with ${…} refs | Resolved into Malloy expressions with explicit types |
| Logic split across shared / branch / workbook layers | Reconciled into one canonical definition per field |
| Model access controls | Fine-grained access control in the model, versioned and enforced on every surface |
ai_context and descriptions | #(doc) / #(index), indexed by the AI Analytics Engine |
| Workbooks & dashboards | Rebuilt as data apps or notebooks |
The Migration Flow
Credible reads the shared model, topics, and workbook layers, translates views to sources and topics to joined sources, enriches with #(doc)/#(index) tags (seeded from ai_context), and — where you connect it — validates against Omni's query engine.
What Credible Handles
- Logic split across layers — the "real" definition of a field may live in an un-promoted workbook model, not the shared model. Credible reconciles the shared, branch, and workbook layers into one canonical Malloy definition, resolving promotion lineage as it goes.
- Field-level inline SQL — Omni encourages
sql:with${…}references and implicit typing. Credible resolves the references and makes Malloy types explicit. - Removable default filters belong in the query, not the model, so query-time defaults become part of a named view rather than a source-level filter.
Before & After
An Omni .view and .topic:
# order_items.view
views:
- name: order_items
sql_table_name: analytics.public.order_items
dimensions:
status:
type: string
sql: ${TABLE}.order_status
value_tier:
type: string
sql: |
CASE WHEN ${TABLE}.sale_price >= 100 THEN 'High'
WHEN ${TABLE}.sale_price >= 25 THEN 'Medium'
ELSE 'Low' END
measures:
total_revenue:
description: Gross merchandise value across all order items
sql: ${TABLE}.sale_price
aggregate_type: sum
completed_revenue:
sql: ${TABLE}.sale_price
aggregate_type: sum
filters: { status: { is: Complete } }
order_count:
sql: ${TABLE}.order_id
aggregate_type: count_distinct# order_items.topic
topic:
base_view: order_items
label: Order Analysis
ai_context: |
Order-item level revenue and fulfillment. Use total_revenue for GMV and
completed_revenue for recognized revenue; join users for customer demographics.
joins:
users:
# a removable, query-time default — not baked into the model
filters:
order_items.status:
is: Completesource: order_items is conn.table('analytics.public.order_items') extend {
primary_key: order_item_id
join_one: users is conn.table('analytics.public.users') on user_id = users.id
dimension:
#(doc) Order item status
#(index)
status is order_status
#(doc) Sale-price value bucket
value_tier is
pick 'High' when sale_price >= 100
pick 'Medium' when sale_price >= 25
else 'Low'
measure:
#(doc) Gross merchandise value across all order items
# currency
total_revenue is sum(sale_price)
#(doc) Recognized revenue from completed items
# currency
completed_revenue is sum(sale_price) { where: status = 'Complete' }
#(doc) Distinct orders
order_count is count(order_id)
#(doc) Average order value
# currency
avg_order_value is total_revenue / order_count
view:
#(doc) Revenue by month
revenue_by_month is {
group_by: created_at.month
aggregate: total_revenue
}
}The topic's ai_context becomes #(doc) intent on the source and its views; the same physical view joined multiple ways in a topic becomes multiple named joins in Malloy.
More than a reformat. Definitions once split across shared, branch, and workbook layers collapse into one canonical, AI-discoverable model that composes into new questions. See what you gain →