Grounding an Agent in Your dbt Project: What It Reads, and What Changes
An agent pointed at your warehouse can already write SQL. The question is what it knows about the columns it writes against, and the honest answer is: the names, the types, and whatever free text happens to be in a description. Everything else it infers.
Grounding an Agent in Your dbt Project: What It Reads, and What Changes
An agent pointed at your warehouse can already write SQL. The question is what it knows about the columns it writes against, and the honest answer is: the names, the types, and whatever free text happens to be in a description. Everything else it infers.
This guide connects an agent to governed meaning instead, and shows the difference in the answers.
It assumes you have imported a dbt project — dbt parse, post the manifest — and nothing else.
What the agent actually connects to
Two endpoints, split by what they let an agent do:
| Endpoint | For | Role |
|---|---|---|
https://coremodels.example.com/mcp | Reading the governed model | Viewer |
https://coremodels.example.com/mcp-admin | Writing to it | Admin |
Use /mcp for grounding. It is the whole point. An agent should be able to look meaning up and
be unable to redefine it — a wrong answer is recoverable, a silently rewritten definition is not.
Nothing in this guide needs the admin surface.
Authenticate with OAuth2, or with an integration API key as a bearer token:
Authorization: Bearer <your CoreModels API key>
Issue the key from the recipe's third step, or from project settings later. It is scoped to the project, and a Viewer-scoped key cannot write regardless of which endpoint it is sent to.
The four questions worth wiring
Grounding is not "give the agent everything". A model context window filled with your whole estate is worse than a name, because it buries the relevant fact. These four cover the real cases.
1. What is in this project at all?
get_project_summary returns the shape — types, elements, taxonomies, counts. This is the cheap
orientation call that stops an agent inventing a table that does not exist.
2. What is this thing?
search_nodes finds a column, a model or a vocabulary by name or partial match, and returns the
governed node with its description and the mixin values attached to it. This is where the recipe's
Agent Guidance columns arrive: meaningNote, commonMistake, doNotUseFor. They are ordinary
mixin values, so they come back with the node — no special tool, no separate lookup.
3. What may this column contain?
The vocabulary behind the column. Because an accepted_values test became a governed taxonomy at
import, the permitted values arrive as a list with structure and descriptions rather than as a
string array — including, where you set it, that return_pending sits under returned rather
than beside it.
4. What else carries this concept?
analyze_concept_impact answers "what depends on this?" for a column, model or vocabulary: where it
is used inside the governed model, which estates carry it and by what path, and what it is bound to
externally. An agent asked to change something should call this before it proposes the change.
A grounded exchange, end to end
The prompt an analyst actually types:
"How many orders were returned last month?"
Ungrounded, the agent has one move: guess that status = 'returned' is the filter, because the
column is called status and returned is a word that appears in the question. It writes confident
SQL and undercounts by however many orders sat in return_pending.
Grounded, the sequence is:
search_nodes → the governed column `status` on `fct_orders`
description, and the Agent Guidance values you filled in
(vocabulary on it) → placed · shipped · completed · return_pending · returned
with return_pending nested under returned
Now the agent has the fact that changes the query: two values mean returned. If you filled in
commonMistake on that column — "return_pending is a return; filtering on returned alone
undercounts" — it reads that sentence directly.
The answer comes back citing the vocabulary rather than asserting from the column name. That is the whole difference: not a smarter model, a model that was told.
Which twenty columns to write
Do not describe the estate. Describe the columns that get answered wrong, and nothing else.
A practical way to find them: look at the questions your team asks the assistant repeatedly, and the
ones where somebody had to correct it. Those columns — usually status-like enums, date columns with
a business meaning (closed_at is not always when it closed), and identifiers that look
interchangeable and are not — are the twenty that matter. The recipe opens on a grid where you can
fill all three guidance columns inline.
The three columns and what belongs in each:
meaningNote— what the column means in business terms. Not a restatement of the name.commonMistake— the wrong assumption you have seen made. This is the highest-value field and the one people skip.doNotUseFor— the query this column looks right for and is wrong for.created_aton adim_customerthat is a slowly-changing dimension is the classic.
Verifying it worked
Take a question the assistant used to get wrong. Ask it again, with grounding connected.
The check is not that the answer changed — it is whether the agent cites something. A grounded answer names the vocabulary or quotes the guidance; an ungrounded one asserts. If the answer is right but uncited, the agent guessed correctly this time, which is not the same as knowing.
What this does not do
- It does not connect to your warehouse. The agent reads governed meaning from CoreModels and executes SQL wherever it already did. No credentials change hands here.
- It does not make the agent's SQL correct. It removes one class of error — inferred meaning — and leaves every other class exactly where it was.
- It does not update itself. The guidance columns are worth as much as the attention you put in them, and they go stale like any documentation. The review cadence on the ownership columns is there for that reason.
- Read-only means read-only. An agent on
/mcpcannot edit a definition, and should not be able to. Curating meaning is a human act with a role behind it.
Where to go next
The columns you just described want owners — the ownership guide covers making "who decides this?" answerable. The dbt quickstart that ships with the CoreModels integration docs covers the import this guide assumed.