We run Omni embedded inside our product (JustAsk, Simpro Group’s analytics layer). Our customers are embed users with the Restricted Querier role: they get dashboards, the workbook, the topic picker and Blobby chat, but nothing that explains the model. A list of raw field names tells a plumbing business owner very little about what they can actually ask. So the most common support question we got was some version of: “What can I actually ask this thing?”
Our fix was a Topic Reference page inside the embed app: a plain-English guide to every topic in our shared model, generated automatically from the model YAML. Omni folks saw it and told us to share, so here it is.
Quick tour: topic catalogue → lesson page → Ask straight into Blobby
What users see
The landing page is a searchable catalogue of all topics (55 today), grouped by business area (Jobs, Invoicing, Assets, Workforce, …). Each topic opens a “lesson” page with five sections:
- Questions you can ask — 5 to 7 suggested questions in business language. Each one has an “Ask” button that drops it straight into the embedded Blobby chat.
- What you can measure — cards for the topic’s measures, with a “verified” badge for measures our audit registry has signed off on.
- How the data connects — the topic’s joins rendered as plain-English sentences (“Each job belongs to one customer”), so users understand why a topic already has everything they need and they never have to join anything themselves.
- Browse all fields — every field grouped by view, with an “AI chat” marker on the ones exposed to Blobby via
ai_fields. The rest are labelled as dashboard/report-only. - Good to know — automatic filters (from
default_filters), access notes (fromaccess_filters), and the caveats we write inai_context.
On top of that we track light progress per user: “Continue where you left off”, an Updated pill on topics whose guide changed since their last visit, and a “What changed” panel listing added/removed fields, measures and questions.
How it is built
Zero hand-written docs. A single Node script walks the model repo and emits JSON the app ships with:
*.topic.yaml→ title, description, grain,ai_context,ai_fields,default_filters,access_filters,joins.*.view.yaml→ field labels, descriptions, types,hidden,aggregate_type.- dbt docs (
models.json) → fills in column descriptions and types where the view YAML is thin. - Our metric/relationship registries → verified flags and dates for measures and joins. (These are YAML files we keep in the model repo that track whether each measure has been independently checked. That is where the “verified” badge comes from.)
Output is one lightweight index (bundled) plus one JSON file per topic (loaded on demand). Each topic gets a content hash; diffing hashes between runs produces the “what changed” feed and the Updated pills.
A few details that mattered more than we expected:
ai_contextis written for the model, not for customers. We split it into two buckets: grain statements and human-readable caveats go into “Good to know”; anything smelling of SQL, Snowflake, YAML, or join mechanics is filtered out with a regex. Writeai_contextin short bullet-ish sentences and this works well.ai_fieldsis the single source of truth for the “AI chat” marker. Same rules, same evaluation, so the guide never claims Blobby can use a field it can’t.- Suggested questions are AI-generated, then frozen. A one-off pass fans out one agent per topic with the topic’s description, grain, caveats and top fields, and asks for exactly five specific business questions. A
questionsEnrichedflag means regenerating the docs never overwrites them; we re-run only for new topics. - Every field description in the model now has two readers: Blobby and a human on this page. That pushed us to keep descriptions as 1–3 user-facing sentences and move forensics (join mechanics, defect history) into comments and the registry. The Blobby answers got better as a side effect.
- Regenerate, then announce. We’re a small team, so we know when a model change merges. We re-run the generator by hand, and the diff it produces becomes a changelog entry in the app that deep-links to the affected topic. Users hear about new fields the same day, in language they understand, with a link to the page that explains them.
Questions welcome
Happy to go deeper on any part: the generator, the plain-English join rendering, or the registry behind the verified badges. And if you’ve solved this differently for your embed users, we’d like to hear it.