Claude Counted 22 Salesforce Accounts at Risk. The Team's Number Was 98.
Claude, pointed straight at a Salesforce warehouse, counted a checkbox and answered 22. The team's number was 98. The semantic model is where that definition lives, so the second answer matched.
Ask an AI agent a question about your Salesforce data in BigQuery and it will usually find the right column. This post is about the question where it can't, and what it takes to fix that.
The whole run in under three minutes: the wrong answer, the onboarding in Claude Code, and the right one.
The question
Maya runs Revenue Operations. The quarterly business review is on Friday, and her chief revenue officer wants one number: how many accounts are at risk?
Maya is illustrative. The Salesforce org behind her is one we run for exactly this kind of test, so no customer is named here. Every query, answer and count below comes from real runs on 11 November 2026.
Her team's Metabase dashboard is right. Total ARR, bookings, open pipeline and win rate all match the numbers the business reports. Behind each tile is SQL the team wrote and checked.
That's also its limit. The dashboard answers what someone built in advance, and nobody built a tile for accounts at risk.
What Claude answers on the bare warehouse
So Maya asks Claude, with only Google's BigQuery connector turned on. Claude lists the tables, reads the account schema, finds a boolean called churn_risk_c, and counts it.

Claude's answer and the SQL it sent, from a fresh incognito chat. The dataset name is blurred.
The answer is 22. It isn't a careless answer. Claude noted that 71 more accounts have a low health score without the flag, and offered to count those too.
We ran the same question in six fresh chats. All six answered 22, all six counted the same flag, and none asked which definition the team uses. BigQuery's job history confirms the SQL each time.
To be fair to the bare warehouse, we tried other questions too. It got total ARR right in two runs out of two, open pipeline by region in one out of one, and partner win rate in two out of two. Clear column names like arr_c and sales_region_c give most of the answer away. "At risk" is different.
Why the column can't carry the definition
The team's definition of at risk doesn't live in the schema. It lives in three documents that disagree:
- The KPI definitions sheet says: count of accounts with ARR above zero and Health Score below 50. The owner is the VP of Customer Success.
- The RevOps data FAQ in Slack says the threshold is unsettled. Customer Success recalibrated the score in August 2024, and the Churn Risk checkbox has used below 40 ever since. The KPI sheet and the QBR still use below 50. It says to ask before using either number.
- The Salesforce field guide says the checkbox is a formula. It's checked when an account is at risk and renews within 180 days.
So churn_risk_c isn't the team's definition of at risk. It's a narrower operational flag: low health, and a renewal coming up soon. A model that reads only the schema has no way to know that, and no reason to ask.
That's the gap a semantic model closes. It puts the definition, the disagreement and the owner where an agent can read them.
The onboarding, in Claude Code
Maya's team onboarded the same BigQuery dataset onto Agami from Claude Code. It took 2 hours and 7 minutes from the first message to the saved model. We estimate the team's own time at about 15 minutes, spent on roughly 85 decisions on cards.
The steps, in order:
- Read what the team already knows. Agami read the KPI sheet, the field guide, the question bank and the QBR snapshot from a Drive folder, and the FAQ from a Slack canvas. Where sources disagreed, like which region field to use, the newer source won. Where nobody knew, it said so.
- Pick the scope. The dataset has 248 tables. Agami suggested 21 that answer RevOps questions, and the team confirmed.
- Describe in parallel. Separate agents described sales, products, revenue and service tables at the same time.
- Check every join against the data. Of 106 joins, five were contradicted by the data and removed. One that was missing, invoices to orders, was added.
- Sign off. The team approved 12 metrics, 21 entities and 37 example questions. Annual recurring revenue comes from Finance's field, never from summed deal amounts. Region means Sales Region. At risk was marked unsettled, so Agami asks before it answers.
- Hide personal data. 117 personal-data columns were hidden before anyone could query them.
- Check itself against what the team trusts. All 21 QBR figures matched, and all 17 dashboard tiles matched to the cent.

The summary at the end of the onboarding. Elapsed time is measured; the 15 minutes of hands-on time is an estimate.
The same question, with Agami
Maya asks again, in a fresh chat with only Agami turned on. This time Claude stops before writing any SQL:
Your org defines "at risk" two ways for paying accounts. Which Health Score threshold should I use?
Below 50 is marked as the KPI sheet and QBR definition. Below 40 is marked as the Churn Risk definition since the August 2024 recalibration. Maya picks both.

The answer and its receipt. The approver's address is blurred.
The answer is 98 below 50, and 47 below 40. Under it, the receipt names the measure, who signed it off and when. It also says plainly that the below-40 count was worked out for this question, because the model has no approved measure for it.
98 is the number in the KPI sheet and the QBR. Maya can answer her chief revenue officer.
The two statements side by side
The difference is in one line of SQL.

Left: the counting line from the bare run, trimmed. Right: the statement Claude sent through Agami, with the receipt below it.
The bare statement counts a flag it found. The Agami statement counts the definition the team signed off, arr_c > 0 AND health_score_c < 50, and the receipt shows where that came from.
What this looks like in Agami
- Definitions live beside the schema. The KPI sheet's rule for at risk is a signed-off measure in the semantic model, with its owner and its sources, so an agent reads it instead of guessing from column names.
- Disagreement becomes a question. Because the FAQ marked the threshold unsettled, the model records an open choice. Claude asks which one before it runs SQL, and never picks silently.
- Every answer carries a receipt, so this is AI you can audit. The receipt names the measure used, who approved it and when, and anything the model had to work out for that one question.
- Accuracy you can measure, against numbers the team already trusts. Here that meant the QBR snapshot and the Metabase dashboard, figure by figure, before anyone asked a new question.
- Personal data is out of scope from the start. Columns flagged as personal were hidden before the first query, and a query that names one is refused.
What we can't claim from this: one onboarding on one Salesforce org isn't a benchmark. The bare warehouse got three of our four questions right, and a different schema could close or widen that gap. The 15 minutes of hands-on time is our estimate, not a measurement.
Frequently asked questions
Did bare Claude ever get it right? For accounts at risk, no: six runs, six answers of 22, and none asked first. On total ARR, open pipeline by region and partner win rate, yes. Those answers follow from well-named columns.
Why not just rename the column? Because the problem isn't the name. The team has two live definitions, and the right move is to ask which one. A renamed column would still pick one silently.
Does this need Claude Code? The onboarding ran in Claude Code. Once the model is saved, any agent that connects to Agami reads the same definitions. The questions in this post ran in Claude on claude.ai.
References
- Use the BigQuery MCP server, Google Cloud's documentation for the connector used on the bare side
- agami-core on GitHub, the source-available semantic model format behind the definitions shown here
Make your data AI-ready
Agami puts your team's definitions, sign-offs and open questions where any AI agent can read them, so the answer matches the number your team already trusts.