Source Preview
Metadata
- name
omni-model-builder- description
Create and edit Omni Analytics semantic model definitions — views, topics, dimensions, measures, relationships, and query views — using YAML through the Omni REST API. Use this skill whenever someone wants to add a field, create a new dimension or measure, define a topic, set up joins between tables, modify the data model, build a new view, add a calculated field, create a relationship, edit YAML, work on a branch, promote model changes, or any variant of "model this data", "add this metric", "create a view for", or "set up a join between". Also use for migrating modeling patterns since Omni's YAML is conceptually similar to other semantic layer definitions.
Omni Model Builder
Create and modify Omni's semantic model through the YAML API — views, topics, dimensions, measures, relationships, and query views.
Tip: Always use
omni-model-explorerfirst to understand the existing model.
Prerequisites
export OMNI_BASE_URL="https://yourorg.omniapp.co"
export OMNI_API_KEY="your-api-key"
You need Modeler or Connection Admin permissions.
API Discovery
When unsure whether an endpoint or parameter exists, fetch the OpenAPI spec:
curl -L "$OMNI_BASE_URL/openapi.json" \
-H "Authorization: Bearer $OMNI_API_KEY"
Use this to verify endpoints, available parameters, and request/response schemas before making calls.
Safe Development Workflow
Always work in a branch. Never write directly to production.
Step 1: Write YAML to a Branch
curl -L -X POST "$OMNI_BASE_URL/api/v1/models/{modelId}/yaml" \
-H "Authorization: Bearer $OMNI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileName": "my_new_view.view",
"yaml": "dimensions:\n order_id:\n primary_key: true\n status:\n label: Order Status\nmeasures:\n count:\n aggregate_type: count",
"mode": "extension",
"branchId": "{branchId}",
"commitMessage": "Add my_new_view with status dimension and count measure"
}'
branchId is a UUID — retrieve it from the List Models endpoint with ?include=activeBranches. If the branch doesn't exist yet, Omni creates it.
Step 2: Validate
curl -L "$OMNI_BASE_URL/api/v1/models/{modelId}/validate?branchId={branchId}" \
-H "Authorization: Bearer $OMNI_API_KEY"
Returns validation errors and warnings with message, yaml_path, and sometimes auto_fix.
Step 3: Merge the Branch
Important: Always ask the user for confirmation before merging. Merging applies changes to the production model and cannot be easily undone.
curl -L -X POST "$OMNI_BASE_URL/api/v1/models/{modelId}/branch/{branchName}/merge" \
-H "Authorization: Bearer $OMNI_API_KEY"
If git with required PRs is configured, merge through your git workflow instead.
YAML File Types
| Type | Extension | Purpose |
|---|---|---|
| View | .view | Dimensions, measures, filters for a table |
| Topic | .topic | Joins views into a queryable unit |
| Relationships | (special) | Global join definitions |
Write with mode: "extension" (shared model layer). To delete a file, send empty yaml.
Writing Views
Basic View
dimensions:
order_id:
primary_key: true
status:
label: Order Status
created_at:
label: Created Date
measures:
count:
aggregate_type: count
total_revenue:
sql: ${sale_price}
aggregate_type: sum
format: currency_2
Dimension Parameters
See references/modelParameters.md for the complete list of 35+ dimension parameters, format values, and timeframes.
Most common parameters:
sql— SQL expression using${field_name}referenceslabel— display name ·description— help text (also used by Blobby)primary_key: true— unique key (critical for aggregations)hidden: true— hides from picker, still usable in SQLformat—number_2,currency_2,percent_2,idgroup_label— groups fields in the pickersynonyms— alternative names for AI matching (e.g.,[client, account, buyer])
Measure Parameters
See references/modelParameters.md for the complete list of 24+ measure parameters and all 13 aggregate types.
Measure filters restrict rows before aggregation:
measures:
completed_orders:
aggregate_type: count
filters:
status:
is: complete
california_revenue:
sql: ${sale_price}
aggregate_type: sum
filters:
state:
is: California
Filter conditions: is, is_not, greater_than, less_than, contains, starts_with, ends_with
Writing Topics
See Topics setup for complete YAML examples with joins, fields, and ai_context, and Topic parameters for all available options.
Key topic elements:
base_view— the primary view for this topicjoins— nested structure for join chains (e.g.,users: {}orinventory_items: { products: {} })ai_context— guides Blobby's field mapping (e.g., "Map 'revenue' → total_revenue")default_filters— applied to all queries unless removedalways_where_sql— non-removable filtersfields— field curation:[order_items.*, users.name, -users.internal_id]
Writing Relationships
- join_from_view: order_items
join_to_view: users
on_sql: ${order_items.user_id} = ${users.id}
relationship_type: many_to_one
join_type: always_left
| Type | When to Use |
|---|---|
many_to_one | Orders → Users |
one_to_many | Users → Orders |
one_to_one | Users → User Settings |
many_to_many | Tags ↔ Products (rare) |
Getting relationship_type right prevents fanout and symmetric aggregate errors.
Query Views
Virtual tables defined by a saved query:
schema: PUBLIC
query:
fields:
order_items.user_id: user_id
order_items.count: order_count
order_items.total_revenue: lifetime_value
base_view: order_items
topic: order_items
dimensions:
user_id:
primary_key: true
order_count: {}
lifetime_value:
format: currency_2
Or with raw SQL:
schema: PUBLIC
sql: |
SELECT user_id, COUNT(*) as order_count, SUM(sale_price) as lifetime_value
FROM order_items GROUP BY 1
Common Validation Errors
| Error | Fix |
|---|---|
| "No view X" | Check view name spelling |
| "No join path from X to Y" | Add a relationship |
| "Duplicate field name" | Remove duplicate or rename |
| "Invalid YAML syntax" | Check indentation (2 spaces, no tabs) |
Docs Reference
- Model YAML API · Views · Topics · Dimensions · Measures · Relationships · Query Views · Branch Mode
Related Skills
- omni-model-explorer — understand the model before modifying
- omni-ai-optimizer — add AI context after building topics
- omni-query — test new fields