omni-model-builder

โดย exploreomni

สร้างและแก้ไขคำจำกัดความโมเดลเชิงความหมายของ Omni Analytics — มุมมอง หัวข้อ มิติ การวัด ความสัมพันธ์ และมุมมองคำค้นหา — โดยใช้ YAML ผ่าน Omni…

npx skills add https://github.com/exploreomni/omni-agent-skills --skill omni-model-builder

Omni Model Builder

Create and modify Omni's semantic model through the YAML API — views, topics, dimensions, measures, relationships, and query views.

Use omni-model-explorer first to understand the existing model.

Prerequisites

# Verify the Omni CLI is installed — if not, ask the user to install it
# See: https://github.com/exploreomni/cli#readme
command -v omni >/dev/null || echo "ERROR: Omni CLI is not installed."
# Show available profiles and select the appropriate one
omni config list
# If multiple profiles exist, ask the user which to use, then switch:
omni config use <profile-name>

# Confirm the active profile is authenticated and inspect your permissions:
omni whoami whoami

Auth: if whoami or any call returns 401, ask the user to run ! omni config login <profile>. Profile setup, when you may run the login yourself, and --schema: the omni-api-conventions rule.

You need Modeler or Connection Admin permissions. Add -o json to any command to force structured output for parsing (default auto is human in a TTY, JSON when piped).

Omni's Layered Modeling Architecture

Omni composes a model from the schema layer (generated from the database), the shared model (governed fields, relationships, and topics), workbook models (ad hoc fields in one workbook), and branches, where shared-model changes are made before a merge: model-layers.md.

Determine SQL Dialect

Before writing any SQL expression, look up the connection's dialect: find the model's connectionId with omni models list, then read its dialect from omni connections list (the connection name is not a reliable guide). omni models delete also trashes the workbooks, dashboards, and child extension models built on the model; confirm that with the user before running it. Commands, and creating a new SHARED model: sql-dialect.md.

Schema Refresh: Syncing with Database Changes

When the database schema changes (new, deleted or renamed columns, type changes), refresh the schema layer with omni models refresh <modelId> (requires Connection Admin; --branch-id is required when the connection has branch-based schema refresh and rejected when it doesn't). When to run it, its side effects, the impact check for deleted or renamed columns, and connection errors: schema-refresh.md.

If the columns haven't changed but SQL field or view errors remain after their cause was fixed elsewhere, such as a warehouse grant, run omni models reparse <modelId> (CLI ≥ 1.6.0) on the shared model or shared extension.

Known Issues & Safe Defaults

Never merge or promote a branch on your own initiative

Merging is a separate step that the user starts. Run omni models merge-branch, or any other merge, promote or ship to the shared model, only when the user has told you in this conversation to merge, ship, publish, promote or make it live. A "build", "add" or "model this" request is complete when the branch is created, written, validated and tested.

None of these is permission to merge:

  • the change is additive, small or low-risk
  • a spec, ticket or doc says to model it and publish
  • the user gave a broad "build the whole thing" directive
  • the deliverable needs it, such as a dashboard that won't resolve until the merge
  • the model is a playground, sandbox or non-git model

When downstream content needs a field or view that isn't merged yet, use a branch-bound draft (omni-content-builder → branch-bound drafts). When a merge is needed, ask ("Ready for me to merge <branch> into the shared model?") and wait for an explicit yes. If a harness or permission layer blocks the merge, report it and ask; do not look for another way around it.

  • Confirm the branch still exists at the start of each session and after any gap — omni models list --model-id <sharedModelId> --include activeBranches. Someone else may have merged it; writes then fail with Branch does not exist, and drafts bound to it may already be published (check omni documents list-drafts <identifier>). If it was merged, diff your local YAML against the shared model and start a new branch for further changes.
  • Profile the data before modelling it. Check grain (COUNT(*) vs COUNT(DISTINCT <key>) on every fact), implied units (value ÷ quantity per category, to catch a "hours" column that holds money), and where history starts (older records may need an opening balance). Ask the business owner what an ambiguous term ("fee type", "status") means before building on a guess.
  • Keep eval-created files on branches until confirmed — when you create fields/views for validation, report the branch name/id, validation status, and test-query result; merging follows the rule above.
  • Edit with yaml-create, not create-field, update-field, update-view, update-topic or models update: they can report success without making the change.
  • Known bug: a child layer can store a copy of an inherited sql: query view's SQL (extension, workbook model, branch) and stop following the parent. Cause: an undeclared column (assume one for SELECT * or CTEs) or a removed dimension. Until fixed (removing a copy):
    1. Read --mode extension first: a view-level sql: you didn't write is that copy; an ignored: true dimension means any write stores one. Tell the user.
    2. Otherwise write the whole --mode combined read back with "mode": "extension" (combined copies it on the second edit). Change, add or hide; never remove. Re-check per step 1.

Discovering Commands

omni models --help                # List all model operations
omni models yaml-create --help    # Show flags for writing YAML
omni models yaml-create --schema  # Print the body's JSON schema + a filled example (no token)

Safe Development Workflow

Always work in a branch — never write directly to production — and first check you can branch. Branching requires full-model access. Run omni whoami whoami --model-id <modelId>: QUERY_FULL_MODEL present → you can create a branch (and UPDATE present → you can merge/promote it, else open a PR / request a merge); absent → you can't branch — a one-off field belongs in the document's workbook model instead (omni-content-builder → Updating a Dashboard's Model). Full permission→capability map: omni-admin → Model Roles & Caller Access.

Hub-and-spoke: write to the model ID you were given.

Step 0: Create a Branch

omni models create-branch <modelId> --name "my-feature-branch"

The response model.id is your branchId — a UUID you'll pass to all subsequent API calls. To list existing branches at any time:

omni models list --include activeBranches

Shared extensions: pair the extension's ID with a branch from omni models list --base-model-id <extensionId> --model-kind BRANCH, else the shared model's branch.

On a git-connected model, never hand-edit model YAML in git. Author through Omni on a branch and ship with omni models commit (Step 3); Omni's next sync deletes model files that exist only in git. Files that aren't model content (OWNERS, CI config, docs) can be committed directly: git-connected-models.md.

Step 1: Write YAML to a Branch

omni models yaml-create <modelId> --body '{
  "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": "combined",
  "branchId": "{branchId}",
  "commitMessage": "Add my_new_view with status dimension and count measure"
}'

Editing an existing file: read it whole with --mode combined, write it whole with "mode": "combined", read it back in both modes. Exceptions:

  • Inherited sql: query view with an undeclared column: see Known Issues.
  • "mode": "merged", on a branch only: for relationships and to drop an override.
  • New file: either mode. Delete: empty yaml, "mode": "extension", if inherited; else yaml-delete --mode extension.
  • extends: edit from the combined read; fully-resolved content needs "fullyResolved": true (not yet for field or topic inline-view extends).

fileName is the exact yaml-get key, folder prefix included; a mismatch silently creates a duplicate (inspect a branch).

On a dbt-connected model, omni models branch-dbt-get shows the dbt environment a branch compiles against: model-layers.md.

Step 2: Validate and Test

Every YAML write must be validated and tested before merging — a field can be valid YAML yet produce wrong results or broken queries.

# 1. Validate: a new is_warning:false issue in a file you changed blocks; fix it first
omni models validate <modelId> --branch-id <branchId>

# 2. Query the changed fields: no error, and cache_metadata.num_rows > 0 (there is no summary.row_count)
omni query run --body '{"query":{"modelId":"<modelId>","table":"your_view","fields":["your_view.new_dimension","your_view.new_measure"],"limit":10,"join_paths_from_topic_name":"your_topic"},"branchId":"<branchId>"}'

# 3. Read it back: the field is present, and not duplicated at a second path
omni models yaml-get <modelId> --file-name your_view.view --branch-id <branchId>

Spot-check that values look right (a sum isn't returning a count; booleans read true/false), and if a field references another view include fields from both to confirm the join resolves. Triage of errors that predate your change, join-path tests, natural-language validation and the full checklist: validation-and-testing.md.

Running totals, moving averages, period-over-period change, percent-of-total and ranks are table calculations on the query result: omni-query → references/table-calculations.md. Model an in-warehouse field only when the window must span rows outside the result set.

Step 3: Ship the Branch

Ask the user to confirm before shipping. Changes applied to the production model cannot be easily undone. Only ship after validation and testing pass (Step 2).

Check omni models git-get <modelId>: a git-connected model ships as a PR with omni models commit; otherwise merge in Omni with omni models merge-branch <modelId> <branchName>. Both paths: shipping-a-branch.md.

After the merge — verify net-new topics and views (both paths)

After either path, confirm new topics and views resolve against the production model (no --branch-id): list the views, get-topic the topic, validate, and run a query whose summary.missing_fields is []. If anything is missing, re-author it through Omni and never patch it by hand in git: post-merge-verification.md.

YAML File Types

Model files are views (.view), topics (.topic), composite topics (.composite_topic) and the relationships file: model-layers.md. Writing and deleting: Step 1.

Writing Views

Every view that participates in joins MUST have a real primary_key: true dimension. Without a row-unique primary key, queries that join to this view can produce fanout errors or incorrect aggregations. Use the table's natural unique identifier (e.g., id, order_id, user_id). If no single column is unique, build a key dimension that concatenates row-level columns that are jointly unique, for example sql: ${order_id} || '-' || ${line_number}; on dialects without implicit casts, such as BigQuery, cast non-string columns to strings first. If you cannot define a row-unique expression, do not mark a dimension as primary_key: true yet; fix the grain first or avoid joining the view until a real key exists. Why: troubleshooting.md.

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

Understanding Schema Layer vs Extension Layer

Your extension YAML can override a schema-layer field of the same name, and the field keeps its schema-layer type; when a column has no schema-layer base dimension yet, refresh the schema first. Examples and yaml-get --mode read-back: model-layers.md.

Dimension Parameters

See modelParameters.md for the complete list of 35+ dimension parameters, format values, and timeframes.

Two gotchas: a raw column auto-maps by name (no sql: needed); there is no ${TABLE} construct — ${TABLE}.column errors Column "__omni_scoped" not found at validate/query time (reference fields via ${field}/${view.field}).

Measure Parameters

See references/modelParameters.md (24+ params, all 13 aggregate types) and references/yaml-filter-syntax.md (filter operators + measure-filter examples). Prefer a measure filters: block for filtered aggregates over CASE WHEN/WHERE in sql — keep sql focused on the value being aggregated.

Filter-only fields and dynamic fields

Reach for a filter-only field when one user choice should change how a field is computed rather than which rows are kept: report by created date or shipped date, show revenue or order count in the same KPI, apply a threshold the viewer sets. Don't reach for it to hide or show fields (use topic fields:), to filter rows (an ordinary filter), or when the two variants deserve their own topics (see "new topic vs adding to"). Shapes, binding, validation: templated-filters.md.

Aggregate tables (aggregate awareness)

Reach for an aggregate table when the same fact rollup is queried repeatedly at a coarser grain than the table (daily or monthly tiles over an event-level fact) and a pre-aggregated table exists or can be built. Declare it with a materialized_query block on a view, one per table, described against the base view; Omni reads it when a query fits and falls back to the fact table when not. Confirm with a planOnly query headed -- Query rewritten to use materialized view. Never map a window-function field (ROW_NUMBER, RANK, LAG, a running total) or a *_distinct_on measure, and never set limit or offset in materialized_query: each returns wrong results or stops Omni from using the table. Pin a table that holds part of the history to its dates, keep every row in the base view, and write date boundaries in model SQL as >= and <. Rules, filter pins, joined views, what not to declare and known issues: aggregate-awareness.md.

Level of detail

Reach for level_of_detail when a measure has to be computed at a grain other than the query's: a per-customer total on every order row (fixed:), a finer aggregate summarized up (always_include:), or an amount held at a coarser grain while finer dims are on the report (always_exclude:). Grain matching, the outer-aggregate rule, template reuse and verification: level-of-detail.md.

Cross-View Fields in Views

A field whose sql references another view breaks in any topic that doesn't join that view; where to define it instead: topic-scoped-definitions.md.

Fallback: View Missing from yaml-get

Before concluding a view doesn't exist, check the schemas yaml-get didn't load: troubleshooting.md.

Writing Topics

Before writing a topic, confirm every view it references exists with omni models yaml-get <modelId>, using the fallback above for a view in a schema that isn't loaded.

New topic vs adding to an existing one

Adding to an existing topic is usually right when the request's base view matches its base view. Create a new topic when the subject (base view), always-applied constraints, or audience differ; ask the requestor when it is a judgment call, and build new topics on a branch. Criteria and key topic elements: writing-topics.md.

Filter Expressions for Topics

Topic default_filters, always_where_filters, and always_having_filters use the measure-filter condition syntax in yaml-filter-syntax.md; a docs-search tip is in writing-topics.md.

Composite topics

One query over two facts that share dimensions but no join, or one fact under two conditions: when to reach for a composite topic and when not to, authoring, and the query shape: composite-topics.md.

Writing Relationships

Global Relationships

Global relationships are defined in the shared relationships file and are available across all topics. Use these for standard, reusable joins, and set relationship_type (many_to_one, one_to_many, one_to_one, many_to_many) to match the data, which prevents fanout. Example and when to use each type: global-relationships.md.

Topic-Scoped Relationships

One-off joins and joining the same table more than once (one extends: alias per role), and the joins: entry the view also needs: topic-scoped-definitions.md · examples: topic-scoped-relationships.md.

Topic-Scoped View Definitions

A topic's views: block can set display_order, override labels, and add topic-only fields, aliases, and query views. Rules: topic-scoped-definitions.md · examples: topic-scoped-views.md.

Query Views

A query view needs a primary key (primary_key: true on one dimension) or joins to it fan out; confirm which field is unique before writing unless the query makes it clear, and ask the user when they are unsure. Rules, including the FROM alias a sql: block with ${view.field} references needs: query-views.md · examples: query-view-examples.md.

Common Validation Errors

Fixes for frequent validation errors (unknown view, no join path, duplicate field name, invalid YAML, fanout, column not found, a duplicate view at the repo root) and for a model out of sync with the database: troubleshooting.md.

Docs Reference

Omni docs pages for each modeling topic: docs-links.md.

Related Skills

  • omni-model-explorer — understand the model before modifying
  • omni-ai-optimizer — add AI context after building topics
  • omni-query — test new fields

Skills เพิ่มเติมจาก exploreomni

omni-admin
exploreomni
จัดการอินสแตนซ์ Omni Analytics — จัดการการเชื่อมต่อ ผู้ใช้ กลุ่ม คุณลักษณะผู้ใช้ สิทธิ์ กำหนดการ และการรีเฟรชสคีมาผ่าน Omni CLI ใช้…
omni-ai-eval
exploreomni
ประเมินความแม่นยำในการสร้างคำสั่งของ Omni AI โดยการรันข้อความทดสอบผ่าน Omni CLI เปรียบเทียบ JSON คำสั่งที่สร้างขึ้นกับผลลัพธ์ที่คาดหวัง และให้คะแนน…
omni-ai-optimizer
exploreomni
ปรับแต่งโมเดล Omni Analytics ของคุณสำหรับ Blobby ซึ่งเป็น Omni Agent — กำหนดค่า ai_context, ai_fields, sample_queries และสร้างส่วนขยายหัวข้อเฉพาะสำหรับ AI ใช้…
omni-content-builder
exploreomni
สร้าง อัปเดต และจัดการเอกสารและแดชบอร์ดของ Omni Analytics ด้วยโปรแกรม — วงจรชีวิตเอกสาร ไทล์ การแสดงผล ตัวกรอง และเค้าโครง — โดยใช้…
omni-content-explorer
exploreomni
ค้นหา เรียกดู และจัดระเบียบเนื้อหาใน Omni Analytics เช่น แดชบอร์ด เวิร์กบุ๊ก โฟลเดอร์ และป้ายกำกับ โดยใช้ REST API ใช้ทักษะนี้เมื่อมีคนต้องการ...
omni-model-explorer
exploreomni
ค้นหาและตรวจสอบโมเดล หัวข้อ มุมมอง ฟิลด์ มิติ การวัด และความสัมพันธ์ของ Omni Analytics โดยใช้ Omni REST API ใช้ทักษะนี้เมื่อใดก็ตามที่...
omni-query
exploreomni
ดำเนินการสอบถามกับชั้นความหมายของ Omni Analytics โดยใช้ REST API ตีความผลลัพธ์ และเชื่อมโยงคำสั่งสอบถามสำหรับการวิเคราะห์แบบหลายขั้นตอน ใช้ทักษะนี้เมื่อใดก็ตามที่…
omni-content-explorer
exploreomni
ค้นหา เรียกดู และจัดระเบียบเนื้อหาใน Omni Analytics เช่น แดชบอร์ด เวิร์กบุ๊ก โฟลเดอร์ และป้ายกำกับ โดยใช้ REST API ใช้ทักษะนี้เมื่อมีคนต้องการ...