Hero-Godsway

Data Lab

UX DESIGNDATA & SQLAPPLIED AI

Dashboards bring clarity and excitement, but also follow-up questions that wait on an analyst for another chart. Generic AI chatbots return unreliable numbers without the right data setup for every user. So I designed and shipped Data Lab, a self-serve agent in Cato Analytics that lets non-technical teams explore their data through conversation, with reliable tracing, exports, and access guardrails.

Internal product · the real interface with invented data

Tools used for this project

  • BigQuery
  • dbt
  • SQL
  • Figma
  • Claude
  • Langfuse
Planned questionsOpen questionsUncheckedCheckedDashboardsText-to-SQL botGeneral chat assistantData Lab
BeforeNowEditorsEventsLeadershipOne analystby hand, in daysWarehouseEditorsEventsLeadershipData Labin secondsMartsreviews answers
Questionplain wordsCatalogyour access onlyPromptcached rulesClaudeplans, in passesAuditafter the answerAnswerphases · chartValidate specallowlist, fail closedComputeby referenceChart viewranked viewsBigQueryone martcode runsevery queryTraceevery step

Where Data Lab sits Diagram

Every chart sparks a next question.

Every chart on the teams’ dashboard is focused on a key metric. The Data Lab agent’s access to both the data and its sources allows for additional and contextual exploration of the underlying nuances, which supports all users in dissecting and exploring the data in the directions led by their curiosity.

Planned questionsOpen questionsUncheckedCheckedDashboardsText-to-SQL botGeneral chat assistantData Lab
BeforeNowEditorsEventsLeadershipOne analystby hand, in daysWarehouseEditorsEventsLeadershipData Labin secondsMartsreviews answers
Questionplain wordsCatalogyour access onlyPromptcached rulesClaudeplans, in passesAuditafter the answerAnswerphases · chartValidate specallowlist, fail closedComputeby referenceChart viewranked viewsBigQueryone martcode runsevery queryTraceevery step

Where Data Lab sits Diagram

Clean tables before clever prompts. Structuring BigQuery and dbt for AI.

Raw tables invite broken joins and double-counted rows, so I modeled clean, pre-joined marts in the database with dbt. Each mart’s schema carries an agent block—grain, measures, caveats—that generates the catalog the agent reads. This approach allows every change in definition to reach the agent the same day, with no prompt to rewrite.

In the warehouse · dbtIn the workbenchmodels/marts/ai_traffic.ymlmart_ai_traffic_monthly meta.agent:domain:ai-trafficgrain:monthtime_column:monthdimensions:[assistant]measures:[sessions, views]filterable:[assistant]pinnable_entity:assistantcaveats:[month is partial]charts:[trend, ranking]paid_ads · stub · not built yetShelf pillAI trafficClarify first“sessions or views?”Pin listone assistant, by codeCaveat footerunder every chartView rankingtrend first, then rankedDeclines, with a reasonpaid ads: not built yetThe catalog is generated from these blocks at build time.Nothing about a mart is written by hand.
Asked how many listeners there were last month, Data Lab asks one clarifying question: listeners can come from two podcast sources. The person answers “Apple Podcasts, as a bar chart by show”, and the answer and chart follow. Asked about paid ads, it declines and names the reason: that data is not in the warehouse yet.
Teach the agentthe warehouse✕Written by hand in the promptdrifts as the marts change✕Retrieval over docsfinds prose, not grain or columns✓Generated from dbt meta.agentgrain, measures, pins, caveats per mart;unbuilt domains stay as stubs with a reason

From dbt schema to live catalog Diagram

The AI translates; code calculates. Zero raw SQL and zero mental math.

The underlying language models are built to first clarify and decipher the user’s intent, so we can reliably turn the user’s prompt into a structured request against one mart; code validates it, runs the query, and computes every change (difference) by reference. An additional audit traces each provided figure the LLM shows to the user against the tool results obtained from the mart query.

A person asks how podcast downloads this year compare with last year, month by month. Claude queries one mart, answers with each month's change and a year-over-year chart, then, asked for the rows behind the chart, returns a CSV download link.

AI referrals have grown sharply this year — up from January ( sessions) to September (). October () is only a partial month.

1 query · 10 rows · 5 passes · Data from Jan 2026 to Oct 2026

compute · pct_change(src_1·r9, src_1·r1) = 0.646 → 65%

Rowmonthai_sessions
r12026-0117,753
r22026-0218,827
r32026-0320,343
r42026-0422,041
r52026-0523,126
r62026-0622,595
r72026-0724,262
r82026-0825,935
r92026-0929,227
r102026-1030,455
1The requestClaude writes a spec,never SQL.query_mart({ mart: "ai_traffic_monthly", select: ["month", "sessions"], filters: [month >= "2026-01"] })validated against the allowlist · fails closed2Query, computeCode runs the query;arithmetic by reference.SELECT month, sessionsFROM mart_ai_traffic_monthlyWHERE month >= @fromBigQuery · 10 rowscompute(pct_change, 29227, 17753) → 0.6463The auditAfter the answer, eachnumeral is traced.Misses count toward abadge earned under 2%.AI referrals are up 65% from January(17,753) to September (29,227).17,753 → row 1 · 29,227 → row 965% → compute · 3 of 3 matched
A finished Data Lab answer: the chat on the left, and on the stage a bar chart of 2026 pageviews by channel, values on the bars, with share and export above it and the thread's filmstrip below.
  1. A title for this answer
  2. The view it chose
  3. Values on the bars
  4. Caveats from the mart
  5. Queries · rows · passes
  6. Rate the answer
  7. Share with the org
  8. Export PNG or CSV
  9. The thread's filmstrip
  10. Every chart, kept

Year over year + CSV X-ray motion

A split canvas designed for charts.

Given that data exploration is a visual task, a split workspace provides an enhanced environment for users to visually engage with the chart while allowing room for threaded conversations in a single session.

A person asks “How did AI referrals change this year?” on the Data Lab welcome card. The status line runs Analyzing, Querying the AI traffic marts, Analyzing and Writing while Claude works; the answer streams in (up 65% from January to September, October a partial month) and a line chart of AI-referral sessions by month lands on the stage.
The first version · JuneThe workbench · JulyJa Fe Ma Ap Ma Ju Ju Au Se O4,1203,0152,2901,370The view the ranking picksTrendline, year marksComparisonthis year vs last4,1203,0152,2901,370Rankingbars with valuesSharedonut, as shares
A bar chart of the AI assistants that sent the most visits in September. The person asks to show it as a donut chart instead; the donut replaces it on the stage, and the person marks the answer as helpful.

The workbench in motion X-ray motion

What’s happening behind the scenes? Turning database wait time into trust.

Unmasking the system’s actions and real-time statuses keeps the users informed about the agent’s actions. This encourages a little more patience and grace from users when database pulls, calculations, and chart visualizations need a little more time. Using the brand colors, I designed animated agent marks that connect with live step readouts to encourage retention.

Close on the input box and the top of the chat: the agent mark at rest, then a question is sent; the mark folds into three dots and the status line steps through Analyzing, Querying the marts and Writing, then the answer begins.
  • Product · agentThe agent mark grows from the product mark
  • RestA slow orbit on the welcome card
  • ThinkingFolds into three dots
  • WritingStream dots above the answer
  • StagePixel grid and a timer
Idlemark at restThinkingmark → 3 dotsQueryingthe marts…Analyzingstep lineBuilding chartpixel grid, timerWritingstream dotsDonesource · dateAsks one questionan ambiguous termDeclines with a reasona stub's reasonBackup-model noticebefore the first tokenProblem statesLimit reached · cannot connect · switched off by an admin

One turn, close Motion

Guided conversations, guarded on access.

Data source pins and filters offer underlying context for agents when selected by the user. This allows faster, more nuanced analysis over longer threaded conversations. Filter and catalog implementations were scoped with data access in mind, which prevents users from choosing data not granted to them, allowing the agent to gracefully decline when prompted.

On the Podcasts shelf a person pins one show from the list, then asks how downloads trended this year; the answer covers that show only. Then a member of the podcast and video team asks about the website's client errors, which their access does not include, and Data Lab declines.
What a pin becomesShelf · PodcastsPin · Show BAsk about downloads…filters += { column: "display_name", value: "Show B" }added by code to every turn in the thread · never by proseWhat the shelf picker listsA podcast & video teammateWeb trafficAI trafficVideoPodcastsAn adminWeb trafficAI trafficArticlesSite searchClient errorsVideoPodcastsRegistrationsSignupsShelves outside your access are not greyed out. They are not listed.
WarehouseKill switchYour accessShelf pinClaude seesWeb trafficWeb trafficWeb trafficWeb trafficAI trafficAI trafficAI trafficAI trafficArticlesArticlesArticlesArticlesVideoVideoVideoVideoPodcastsPodcastsPodcastsPodcastsSocialSocialSocialSocialEventsEventsEventsNewslettersNewslettersNewslettersClient errorsClient errorsClient errorsRestrictedRestrictedRestricted2 not builtStubs: whyStubs: whyPodcastsshow =“Show B”Entity pin: a filteradded by code,never by proseEvery tool call checks access again, with the session's user id.

Pinned, then outside access X-ray motion

Data transparency, enhanced collaboration, and weekly evals.

Anyone can download the rows behind a chart as a CSV, or share a snapshot across the organization with a comment thread. Simple user feedback mechanisms like thumbs up/down provide quick opportunities for user feedback without interruption and allow the agent to document user-scoped preferences on chart types, while also serving as a key user feedback system for feature ideas and bug resolutions.

The share dialog over the workbench: “Most-watched videos, 2026 YTD” will be visible to everyone at the organisation with a comment thread, its data frozen as generated; an optional comment, then Share org-wide. Behind it, the ranked bar chart and the thread's filmstrip.
The workbench after a follow-up question: under the answer, thumbs up and down, and a one-line survey, “How's the assistant doing on this task?”, with Great, Okay and Not helpful. On the stage, the ranked bar chart of the most-watched videos.

Share across the org Laptop

Reflection

My most important takeaway is that the performance and efficiency of LLMs in applied data projects are influenced more by the design of the underlying database and its pipelines. Cleaner, more structured data tables and dbt models facilitated higher output quality than the choice of models used. Also, my prior ownership and understanding of the database, its design, and ELT processes facilitated quicker diagnosis and agent error detection as an added advantage.

Questions about this project?

Get in touch

More work