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