<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vincenzo Nudo</title>
    <description>The latest articles on DEV Community by Vincenzo Nudo (@vincenzo_nudo_842cddd9973).</description>
    <link>https://dev.to/vincenzo_nudo_842cddd9973</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3827170%2Fe09d1dcc-c40d-4fcf-bf16-f8ea0d1b6090.png</url>
      <title>DEV Community: Vincenzo Nudo</title>
      <link>https://dev.to/vincenzo_nudo_842cddd9973</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vincenzo_nudo_842cddd9973"/>
    <language>en</language>
    <item>
      <title>Schema catalogs for AI assistants: the layer nobody wants to maintain</title>
      <dc:creator>Vincenzo Nudo</dc:creator>
      <pubDate>Wed, 26 Aug 2026 03:41:52 +0000</pubDate>
      <link>https://dev.to/vincenzo_nudo_842cddd9973/schema-catalogs-for-ai-assistants-the-layer-nobody-wants-to-maintain-457k</link>
      <guid>https://dev.to/vincenzo_nudo_842cddd9973/schema-catalogs-for-ai-assistants-the-layer-nobody-wants-to-maintain-457k</guid>
      <description>&lt;p&gt;The schema catalog for an AI assistant is the artefact that answers the question "what does this database look like right now". Whether the database is Postgres, MySQL, SQL Server or Redshift, the shape of the problem is the same: the catalog carries table names, column names, types, keys, and enough relationships to let the assistant write a query that resolves. It lives somewhere between the database and the assistant, has to stay in sync with a database that changes underneath it, and is almost always built the same weekend the team decides they want an AI assistant reading their data. It runs fine for the first three tables. The problems start around the fourth week, and none of them look like the same problem twice.&lt;/p&gt;

&lt;p&gt;The distinction worth naming early is between the &lt;strong&gt;connection layer&lt;/strong&gt; (how the assistant reaches the database) and the &lt;strong&gt;knowledge layer&lt;/strong&gt; (what the assistant knows about the database's shape). The connection layer receives most of the attention, because credentials, network isolation and query cost are visible failure modes and easy to argue about. The knowledge layer is where most of the actual quality of the assistant lives, and it decays quietly. The &lt;a href="https://taavik.com/ai-database-context" rel="noopener noreferrer"&gt;AI database context&lt;/a&gt; page covers why this second layer matters at all when the first one exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just point the assistant at the database
&lt;/h2&gt;

&lt;p&gt;Connecting the AI directly to production is the shortest path and the one most teams reject after five minutes of thinking about it. The assistant would get read access on tables it should not see, its queries can be arbitrarily expensive, its credentials would live somewhere they should not, and the audit trail becomes hard to reason about. What most teams end up building is a layer in between: a representation of the database that the assistant can read cheaply and safely without ever touching production.&lt;/p&gt;

&lt;p&gt;That layer is what this article is about. It is not the connection. It is the catalog.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five recipes teams build
&lt;/h2&gt;

&lt;p&gt;Ask fifteen senior developers how to build that layer and you get roughly five recipes. Most teams end up combining two or three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe 1: the JSON catalog file.&lt;/strong&gt; A script dumps the schema (table names, column names, types) into a JSON file, committed to the same repo as the assistant's prompt config. The assistant reads the file at startup. The simplest thing that works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe 2: the nightly refresh.&lt;/strong&gt; Same as recipe 1, but a cron job regenerates the JSON every night from the running database. Sometimes on demand from a slash command in Slack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe 3: the custom MCP server.&lt;/strong&gt; A small Model Context Protocol server sits between the AI and the database, exposing a set of typed queries. The assistant calls these instead of writing raw SQL. The MCP process holds the credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe 4: the semantic layer.&lt;/strong&gt; The catalog is enriched with human notes: which column is a foreign key in disguise, what &lt;code&gt;status = 'C'&lt;/code&gt; actually means in this business, which tables are archived. This layer is typically a YAML file or rows in a table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recipe 5: the read-only replica.&lt;/strong&gt; A separate replica of the production database, sometimes with masked columns, that the assistant is allowed to query directly. Solves the credential problem. Does not solve the knowledge problem.&lt;/p&gt;

&lt;p&gt;None of these are bad. All of them ship. Most of them stop working around the same point in the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why all five recipes work in week one
&lt;/h2&gt;

&lt;p&gt;The recipes deliver the same thing on day one: the assistant answers a question about the database, correctly, in front of someone who wanted to see it work. The team walks away with the impression that the layer is done. The layer is not done. The layer is at day zero of a maintenance timeline that nobody has planned for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why all five recipes start breaking around week three
&lt;/h2&gt;

&lt;p&gt;Four failure modes, in the order teams usually hit them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A column gets renamed and nobody updates the catalog.&lt;/strong&gt; A developer renames &lt;code&gt;user_email&lt;/code&gt; to &lt;code&gt;contact_email&lt;/code&gt; in a migration. The migration ships. The catalog file still says &lt;code&gt;user_email&lt;/code&gt;. The assistant asks for &lt;code&gt;user_email&lt;/code&gt; and gets a "column does not exist" error, or worse, silently gets zero rows back and confidently reports "there are no users with an email".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A new column appears and the assistant never learns about it.&lt;/strong&gt; The nightly refresh (recipe 2) picks it up in fifteen hours. In those fifteen hours the assistant is asked something that would have needed the new column, and answers based on the old shape of the world. No error, no warning, just a wrong answer delivered with the same confidence as a right one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The semantic notes drift out of sync with reality.&lt;/strong&gt; The YAML file (recipe 4) said &lt;code&gt;status = 'C'&lt;/code&gt; means "cancelled". Someone changed it to mean "completed" six months ago as part of a business logic overhaul. The YAML was never updated. The assistant answers questions about cancelled orders with rows for completed ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The MCP typed queries stop matching the schema.&lt;/strong&gt; A typed query (recipe 3) was written for a table with three columns. The table now has five. The query still runs, still returns rows, and skips the two new columns entirely. The assistant works around a phantom limitation of the database that only exists in the code between the two.&lt;/p&gt;

&lt;p&gt;None of these failure modes are exotic. All of them show up on any database older than a year, staffed by more than three developers, without anyone doing anything wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a layer that survives looks like
&lt;/h2&gt;

&lt;p&gt;Three properties separate a catalog that ages well from one that goes stale in two weeks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is regenerated from the running database on a schedule, not from a file.&lt;/strong&gt; The source of truth for what the assistant sees has to be what the database currently is, not what someone wrote down when they built the layer. If the regeneration is not automated, it will not happen. This is the difference between "the catalog is code" (fragile) and "the catalog is a snapshot" (self healing). The mechanics of doing this well are discussed in more detail in the &lt;a href="https://taavik.com/blog/schema-drift-detection" rel="noopener noreferrer"&gt;schema drift detection&lt;/a&gt; piece.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It records structural changes as typed events, not as raw diffs.&lt;/strong&gt; When a column is renamed, someone needs to see "column &lt;code&gt;user_email&lt;/code&gt; was renamed to &lt;code&gt;contact_email&lt;/code&gt; on 2026-08-14" instead of two hundred lines of unified diff between two JSON files. This is what makes drift readable and reviewable rather than noise to scroll past. The &lt;a href="https://taavik.com/product/schema-changes" rel="noopener noreferrer"&gt;schema change history&lt;/a&gt; page shows what this looks like when the events are typed and severity-classified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It carries human annotations alongside the metadata, and versions them.&lt;/strong&gt; The semantic notes (which enum values mean what, which two column joins are load bearing, which tables are archived) live next to the raw catalog, versioned together, so that when the schema changes the annotations get flagged for review instead of quietly outliving their referent.&lt;/p&gt;

&lt;p&gt;A layer with these three properties is not built in a weekend. Which is why almost nobody has one, and why most teams are running a catalog file that was accurate three weeks ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Taavik fits
&lt;/h2&gt;

&lt;p&gt;Taavik is one implementation of the three properties above, packaged as a Model Context Protocol (MCP) server that AI assistants and coding agents consume directly. Recipe 3 up in the list (write your own MCP server) is the DIY version of what Taavik ships in the box: catalog scans on the team's cadence, typed rename events in the change history, and human annotations at the column and table level versioned alongside the metadata. Postgres, MySQL, SQL Server and Redshift are supported. Database credentials never leave the private network, which is the topic of a separate piece and not what this one is about.&lt;/p&gt;

&lt;p&gt;The choice is not Taavik versus nothing. The choice is whether those three properties end up in the stack, by any route, before the fourth week runs out. Building them in-house costs a few hundred lines of code and one person willing to own them for as long as the database lives. Buying them costs a subscription and one decision meeting. The right answer depends on how many databases are in scope and how many engineers can be pulled away from product work to look after a layer that is technically boring and operationally load bearing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://taavik.com/blog/schema-catalog-layer" rel="noopener noreferrer"&gt;Taavik blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>postgres</category>
      <category>database</category>
      <category>mcp</category>
    </item>
    <item>
      <title>How I turned approved SQL into governed business KPIs</title>
      <dc:creator>Vincenzo Nudo</dc:creator>
      <pubDate>Mon, 16 Mar 2026 15:36:32 +0000</pubDate>
      <link>https://dev.to/vincenzo_nudo_842cddd9973/how-i-turned-approved-sql-into-governed-business-kpis-4673</link>
      <guid>https://dev.to/vincenzo_nudo_842cddd9973/how-i-turned-approved-sql-into-governed-business-kpis-4673</guid>
      <description>&lt;p&gt;In a lot of companies, executives and business teams want answers from company data, but they do not know SQL.&lt;/p&gt;

&lt;p&gt;That part is obvious.&lt;/p&gt;

&lt;p&gt;What is less obvious is that SQL is not the real problem.&lt;/p&gt;

&lt;p&gt;The real problem is this:&lt;/p&gt;

&lt;p&gt;How do you let non-technical users ask business questions about company data without exposing raw SQL, direct database access, or completely uncontrolled AI generated queries?&lt;/p&gt;

&lt;p&gt;That was the problem I wanted to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naive solution looks attractive
&lt;/h2&gt;

&lt;p&gt;The first idea is always the same:&lt;/p&gt;

&lt;p&gt;Connect an AI assistant directly to the database and let people ask questions in natural language.&lt;/p&gt;

&lt;p&gt;At first, this sounds great.&lt;/p&gt;

&lt;p&gt;In practice, it creates a different set of problems:&lt;/p&gt;

&lt;p&gt;• the business definition of a metric is not stable&lt;br&gt;&lt;br&gt;
• different prompts may produce different SQL for the same question&lt;br&gt;&lt;br&gt;
• there is no strong boundary between approved and unapproved logic&lt;br&gt;&lt;br&gt;
• scheduling, monitoring, and delivery workflows are still missing&lt;br&gt;&lt;br&gt;
• auditability becomes weak very quickly&lt;br&gt;&lt;br&gt;
• private environments become painful to manage  &lt;/p&gt;

&lt;p&gt;In other words, query generation is only one small part of the problem.&lt;/p&gt;

&lt;p&gt;The harder part is making the answers reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern I ended up using
&lt;/h2&gt;

&lt;p&gt;Instead of letting AI write arbitrary SQL for business users, I flipped the model.&lt;/p&gt;

&lt;p&gt;The system starts from real SQL written and approved by analysts.&lt;/p&gt;

&lt;p&gt;The flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An analyst writes a real SQL query.&lt;/li&gt;
&lt;li&gt;They define only the minimal input parameters needed for the business question.&lt;/li&gt;
&lt;li&gt;That query becomes a governed KPI.&lt;/li&gt;
&lt;li&gt;The KPI can contain multiple query variants.&lt;/li&gt;
&lt;li&gt;Business users never see SQL.&lt;/li&gt;
&lt;li&gt;They only see KPI cards and ask follow-up questions in plain language.&lt;/li&gt;
&lt;li&gt;AI maps the question to the right KPI variant.&lt;/li&gt;
&lt;li&gt;The backend executes only approved query paths.&lt;/li&gt;
&lt;li&gt;The UI renders the result as a scalar, a short list, or a chart.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That design changes everything.&lt;/p&gt;

&lt;p&gt;The SQL remains controlled.&lt;/p&gt;

&lt;p&gt;The business experience becomes flexible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why query variants matter
&lt;/h2&gt;

&lt;p&gt;This was one of the most important parts of the design.&lt;/p&gt;

&lt;p&gt;A single KPI often needs more than one query behind it.&lt;/p&gt;

&lt;p&gt;For example, imagine a fintech KPI about money movement.&lt;/p&gt;

&lt;p&gt;The same KPI may need:&lt;/p&gt;

&lt;p&gt;• a default comparison variant for today versus yesterday&lt;br&gt;&lt;br&gt;
• a trend variant for a daily bar chart this week&lt;br&gt;&lt;br&gt;
• a breakdown variant for operational exceptions like refunds or failed payments  &lt;/p&gt;

&lt;p&gt;From the business user’s point of view, this still feels like one KPI.&lt;/p&gt;

&lt;p&gt;From the backend point of view, it is a governed set of approved query variants.&lt;/p&gt;

&lt;p&gt;That means the user can ask:&lt;/p&gt;

&lt;p&gt;• How are we doing versus yesterday&lt;br&gt;&lt;br&gt;
• Show the daily trend this week&lt;br&gt;&lt;br&gt;
• Are refunds rising  &lt;/p&gt;

&lt;p&gt;But the system is not improvising SQL every time.&lt;/p&gt;

&lt;p&gt;It is resolving the question to a predefined execution path.&lt;/p&gt;

&lt;p&gt;That is the difference between flexibility and chaos.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI actually does
&lt;/h2&gt;

&lt;p&gt;This is the part I think many teams get wrong.&lt;/p&gt;

&lt;p&gt;In my flow, AI does not generate arbitrary SQL against the database.&lt;/p&gt;

&lt;p&gt;Its role is narrower and much more useful:&lt;/p&gt;

&lt;p&gt;• interpret the user’s question&lt;br&gt;&lt;br&gt;
• map it to the correct KPI&lt;br&gt;&lt;br&gt;
• select the correct query variant&lt;br&gt;&lt;br&gt;
• resolve the right time context and parameters&lt;br&gt;&lt;br&gt;
• explain the result in business language  &lt;/p&gt;

&lt;p&gt;So the AI is acting as a language and intent layer, not as an unrestricted database operator.&lt;/p&gt;

&lt;p&gt;That matters because it gives business users a natural interface without giving up control, auditability, or execution safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works better for business users
&lt;/h2&gt;

&lt;p&gt;Business users do not want to think about joins, schemas, or prompt engineering.&lt;/p&gt;

&lt;p&gt;They want answers like:&lt;/p&gt;

&lt;p&gt;• How did onboarding perform last week&lt;br&gt;&lt;br&gt;
• Show daily wires and P2P transfers this week&lt;br&gt;&lt;br&gt;
• Are failed payments increasing  &lt;/p&gt;

&lt;p&gt;They also want charts, lists, and short explanations.&lt;/p&gt;

&lt;p&gt;If the underlying SQL is already approved and versioned, you can give them that experience safely.&lt;/p&gt;

&lt;p&gt;The UI becomes simple because the backend is strict.&lt;/p&gt;

&lt;p&gt;That is a much better tradeoff than giving everyone direct AI to database access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution still matters
&lt;/h2&gt;

&lt;p&gt;Even with this model, execution is still the real backbone.&lt;/p&gt;

&lt;p&gt;In my case, query execution, scheduling, and monitoring all follow the same deployment model.&lt;/p&gt;

&lt;p&gt;They can run:&lt;/p&gt;

&lt;p&gt;• in the cloud&lt;br&gt;&lt;br&gt;
• or on-prem through a dedicated installed agent  &lt;/p&gt;

&lt;p&gt;In general, on-prem is the preferable setup for sensitive environments, because the data never needs to be exposed outside the customer environment.&lt;/p&gt;

&lt;p&gt;The platform orchestrates the workflow, but execution stays close to the database.&lt;/p&gt;

&lt;p&gt;That turned out to be a very important distinction.&lt;/p&gt;

&lt;p&gt;A lot of teams do not just need answers.&lt;/p&gt;

&lt;p&gt;They need answers without opening up their data environment too much.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this unlocked
&lt;/h2&gt;

&lt;p&gt;This approach gave me a few things at the same time:&lt;/p&gt;

&lt;p&gt;• business users can ask follow-up questions in plain language&lt;br&gt;&lt;br&gt;
• analysts still control business logic&lt;br&gt;&lt;br&gt;
• the results stay tied to approved SQL&lt;br&gt;&lt;br&gt;
• charts and tables stay consistent with the same KPI definition&lt;br&gt;&lt;br&gt;
• scheduling and monitoring remain part of the same operational system&lt;br&gt;&lt;br&gt;
• cloud and on-prem execution both fit naturally into the model  &lt;/p&gt;

&lt;p&gt;So instead of treating natural language as a replacement for data workflows, I ended up using it as an access layer on top of governed workflows.&lt;/p&gt;

&lt;p&gt;That feels much more robust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;I think a lot of teams are focusing on the wrong question.&lt;/p&gt;

&lt;p&gt;The question is not:&lt;/p&gt;

&lt;p&gt;Can AI generate SQL&lt;/p&gt;

&lt;p&gt;The more important question is:&lt;/p&gt;

&lt;p&gt;How much execution freedom should AI have around company data&lt;/p&gt;

&lt;p&gt;For business-facing analytics, I have become convinced that natural language works best when the SQL underneath is already approved, versioned, and operationally controlled.&lt;/p&gt;

&lt;p&gt;The hard part is not letting AI write SQL.&lt;/p&gt;

&lt;p&gt;The hard part is making business answers reliable.&lt;/p&gt;

&lt;p&gt;I’m building this approach in DataPilot, where approved SQL becomes governed business KPIs and business users can ask follow-up questions without touching raw SQL.&lt;/p&gt;

&lt;p&gt;If you want to see the product context behind this model, it’s here:&lt;br&gt;
&lt;a href="https://getdatapilot.com/product/business-kpis" rel="noopener noreferrer"&gt;https://getdatapilot.com/product/business-kpis&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>analytics</category>
      <category>data</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
