Using Dinorules to Control AI-Generated Code in dbt™ Projects
Feb 26, 2026
AI assistants write dbt™ code fast—but without guardrails, "fast" quickly turns into "chaotic." One model uses SELECT in uppercase, another in lowercase. A staging model is named stg_orders in one file and staging_orders in another. A generated query uses SELECT * that silently breaks when a source schema changes.
.dinorules solves this. It is a plain-text configuration file, committed to the root of your dbt™ repository, that tells DinoAI (Paradime's AI platform) exactly how to generate SQL, Jinja, and YAML. Every AI interaction—inline completions, agent-mode generation, prompt-based code creation—reads .dinorules first and constrains output to match your team's declared conventions. No linting after the fact. No post-processing. Standards are enforced at generation time.
This guide walks through what .dinorules is, how to set it up, what rules to start with, and how it compares to alternatives like CLAUDE.md and dbt™ Agent Skills.
Why AI-Generated dbt™ Code Drifts Without Explicit Rules
AI assistants like GitHub Copilot and Claude generate syntactically correct SQL. The code compiles. It runs. But syntactically correct is not the same as stylistically consistent.
Without explicit rules, every prompt is an isolated event. The AI has no memory of what your team decided about comma placement last Tuesday, or that staging models must start with stg_. The result is a codebase that works but is increasingly expensive to maintain—because every pull request becomes a formatting debate and every new team member encounters a different pattern in every file.
Formatting Churn in Pull Requests
Inconsistent formatting creates noisy diffs that slow code reviews and obscure meaningful logic changes:
Trailing vs. leading commas: AI may alternate between styles across files, making it impossible to see at a glance which columns were actually added or removed
Keyword casing: Uppercase
SELECTin one model, lowercaseselectin another—trivial differences that pollute diffs with irrelevant changesIndentation depth: Two spaces in one model, four in another—making side-by-side comparisons unreadable
These aren't bugs. They're friction. And friction compounds across hundreds of models.
Inconsistent Naming Conventions
AI has no opinion about your naming conventions unless you give it one. Without rules, you might get:
stg_ordersin one file andstaging_ordersin anotherdim_customersalongsidecustomer_dimensionfct_revenuenext tofact_revenue
This breaks discoverability. Analysts searching for the staging model of orders now need to check two patterns. Downstream models that depend on a consistent naming scheme break silently when a name changes. The dbt™ project evaluator explicitly warns against inconsistent prefixes for this reason.
Risky Patterns Like SELECT * and Implicit Joins
Some AI-generated patterns are not just inconsistent—they are dangerous:
SELECT *— Pulls every column from a source. When a source schema changes (a column is added, renamed, or removed), downstream models break without warning.Comma joins (implicit joins) —
FROM orders, customers WHERE orders.customer_id = customers.idis valid SQL but error-prone. Missing a join condition silently produces a Cartesian product.Missing
WHEREclauses onDELETEstatements — ADELETE FROM table_namewithout aWHEREclause wipes the entire table.
These patterns pass linting. They compile. They run. And they cause production incidents.
What Is .dinorules and How Does It Work
.dinorules is a plain-text configuration file that you commit to the root of your dbt™ repository. It contains natural language instructions—written in plain English using bullet points, sections, or numbered lists—that tell DinoAI exactly how to generate code. Think of it as a .cursorrules or .windsurfrules file, but purpose-built for analytics engineering workflows.
No special syntax is required. No YAML schemas to learn. You write rules in plain English, and DinoAI reads them.
Repo-Committed Rules for AI Governance
.dinorules lives alongside dbt_project.yml in the repository root, making standards:
Portable — Every team member who clones the repo gets the same rules. No IDE settings to sync, no Slack messages to remember.
Auditable — Changes go through pull requests. You can see exactly when a rule was added, who approved it, and why.
Version-controlled — Rules evolve with the codebase. When you adopt a new convention, you update
.dinorulesin the same PR that implements the change.
Unlike IDE-specific settings or team wikis, .dinorules travels with the code itself.
How DinoAI Reads and Applies Rules at Generation Time
When you interact with DinoAI—whether through inline suggestions, agent mode, or prompt-based generation—it automatically loads .dinorules as part of its context window. The mechanism is straightforward:
DinoAI detects
.dinorulesin the repository rootIt parses the rules before generating any SQL, Jinja, or YAML
Generated output is constrained to match declared conventions
Rules apply to every interaction: new models, updates, documentation, and tests
No additional configuration is needed. No plugins to install. The file's presence is sufficient.
DinoAI reads .dinorules before generating any code, ensuring output matches team conventions from the start.
Where to Place .dinorules in Your dbt™ Project
Place .dinorules in the root directory of your repository—at the same level as dbt_project.yml. DinoAI auto-detects the file; no additional configuration is needed.
Tip: While iterating on your rules locally, you can temporarily add
.dinorulesto.gitignore. Once the team agrees on the rules, remove it from.gitignore, commit, and share.
Starter .dinorules Template for dbt™ Style Guide Enforcement
Here is a copy-paste ready template covering the three pillars—SQL formatting, dbt™ conventions, and safety guardrails. Drop this into your repo root as .dinorules and customize as needed:
Each section maps directly to a category of problems described earlier: SQL style prevents formatting churn, dbt™ conventions prevent naming inconsistencies, and safety guardrails prevent production incidents.
SQL Formatting Rules for Consistent AI Output
SQL formatting rules eliminate the single largest source of pull request noise: style disagreements that have nothing to do with logic.
Lowercase or Uppercase SQL Keywords
The dbt™ Labs SQL style guide recommends lowercase for all keywords, field names, and function names. Most modern dbt™ teams follow this convention. In your .dinorules:
With this rule active, DinoAI will never generate SELECT order_id FROM orders. It will always produce:
Leading Commas vs Trailing Commas
Leading commas produce cleaner diffs when adding or removing columns. When a new column is added, only one line changes—the new line. With trailing commas, adding a column requires modifying the previous line to add a comma.
Before (trailing commas—noisier diffs):
After (leading commas—cleaner diffs):
Note: The dbt™ Labs style guide officially recommends trailing commas. Leading commas are a popular alternative favored by many teams for diff clarity. Choose whichever your team prefers and encode it in
.dinorules.
In your .dinorules:
Explicit Join Conditions
Implicit joins use comma-separated tables in the FROM clause:
Explicit joins make the relationship between tables clear:
In your .dinorules:
dbt™ Convention Rules for ref() source() and Staging Patterns
Beyond SQL formatting, .dinorules enforces dbt™-specific conventions that maintain lineage integrity, project structure, and model predictability.
Always Use ref() and source()
Hardcoded table names break dbt™'s lineage graph. If a model references raw.jaffle_shop.orders directly instead of using {{ source('jaffle_shop', 'orders') }}, dbt™ cannot track the dependency. Lineage becomes invisible, and dbt build cannot determine the correct execution order.
In your .dinorules:
With these rules, DinoAI will generate:
Enforce Staging Model Naming
The dbt™ staging best practices guide recommends the pattern stg_[source]__[entity]s—with a double underscore separating the source system from the entity name and a plural entity suffix.
In your .dinorules:
This prevents AI from generating staging_orders, stg_orders, or stg-jaffle-shop-orders. Every staging model follows the same pattern: stg_jaffle_shop__orders, stg_stripe__payments, stg_google_analytics__sessions.
Incremental Model Best Practices
Incremental models are one of the most powerful—and most error-prone—features in dbt™. Without explicit rules, AI might generate an incremental model that lacks a unique_key (causing duplicate rows) or omits the is_incremental() block (causing full-table scans on every run).
In your .dinorules:
With these rules, DinoAI generates incremental models that follow dbt™ best practices:
Safety Guardrails to Prevent Risky AI-Generated Code
Safety rules prevent the patterns that cause production incidents. They act as guardrails that catch problems before code review—because the problems never make it into the generated code.
Block SELECT * in All Models
SELECT * is the single most common source of silent breakage in dbt™ projects. When a source schema changes—a column is added, renamed, or removed—every model using SELECT * inherits the change without warning. Downstream models that expect specific columns fail. Dashboards break. Data contracts are violated.
In your .dinorules:
With this rule, DinoAI will always enumerate columns explicitly, functioning as a schema contract between your model and its dependencies.
Require WHERE Clauses on Deletes
A DELETE FROM table_name without a WHERE clause wipes every row in the table. This is catastrophic in production and trivially easy for AI to generate if not explicitly guarded against.
In your .dinorules:
Disallow Implicit Joins
Implicit joins—comma-separated tables in the FROM clause—are error-prone because a missing WHERE condition silently produces a Cartesian product. The result is a table with exponentially more rows than expected, often discovered only when storage costs spike or dashboards show inflated metrics.
In your .dinorules:
This reinforces the explicit JOIN...ON syntax described earlier, but framed as a safety requirement rather than a style preference.
How DinoAI Applies .dinorules Across Paradime Surfaces
.dinorules is not limited to a single interface. It works everywhere DinoAI operates, ensuring consistent standards regardless of how your team interacts with AI.
Copilot in the Paradime Code IDE
When you use DinoAI Copilot in the Paradime Code IDE, .dinorules applies to:
Inline code completions — Autocomplete suggestions follow your declared formatting and naming conventions
Chat suggestions — Responses to questions about how to build a model respect your team's patterns
Code generation prompts — Full model generation from natural language follows every rule in
.dinorules
Bolt AutoPilot for Self-Healing Pipelines
When Bolt AutoPilot detects a pipeline failure, DinoAI reads the failure logs, traces dependencies across repositories, and generates a fix. Because DinoAI loads .dinorules as part of its context, auto-generated fixes match your team's coding standards—the same formatting, the same naming conventions, the same safety patterns.
This means a 2 AM pipeline fix looks indistinguishable from code a team member wrote during business hours.
MCP Server for External AI Clients Like Claude and Cursor
Teams using external AI tools—Claude Desktop, Claude Code, Cursor, ChatGPT, GitHub Copilot—can connect via Paradime's MCP Server. The MCP Server provides DinoAI's full context graph (lineage, catalog, Bolt logs, and more) to any MCP-compatible client. Because .dinorules is part of the repository context, standards travel with the project regardless of which AI client the team uses.
.dinorules flows from the repository through DinoAI to every surface where AI generates code.
Advanced .dinorules for Team Maturity Levels
Not every team needs the same rules on day one. Start simple and add complexity as your team matures.
Maturity Level | Focus Areas | Example Rules |
|---|---|---|
Beginner | Formatting + safety | Keyword case, no |
Intermediate | Naming + macros |
|
Advanced | Performance | Partitioning, clustering, incremental strategies |
Beginner Rules for Formatting and Safety
Start here. These rules have the highest impact-to-effort ratio—they eliminate formatting noise in PRs and prevent the most dangerous AI defaults:
This set of 7 rules is enough to make AI-generated code consistently reviewable. Adoption friction is minimal because the rules align with widely accepted conventions.
Intermediate Rules for Naming Conventions and Macros
Once the team is comfortable with basic rules, add naming enforcement and macro usage patterns:
At this level, you might also add rules for custom macros your team uses frequently—for example, requiring a specific logging macro or a standard audit column pattern.
Advanced Rules for Partitioning and Performance
Advanced rules are warehouse-specific and require more context. They prevent costly query patterns that are easy for AI to generate:
Validate That Your .dinorules Are Working
After committing .dinorules, verify that rules are applied correctly before trusting them across the team.
Before and After Prompt Examples
Use the same prompt with and without .dinorules to see the difference.
Prompt: "Create a staging model for the orders table from the jaffle_shop source"
Without .dinorules (inconsistent output):
With .dinorules (standards-compliant output):
The second output follows your .dinorules: lowercase keywords, leading commas, source() macro, proper naming convention, CTE pattern.
PR Checklist and Code Review Heuristics
For the first few AI-generated pull requests, review closely against this checklist:
✅ Does keyword casing match the rule (all lowercase)?
✅ Are all table references wrapped in
ref()orsource()?✅ Are joins explicit (
inner join,left join) withONconditions?✅ Is
SELECT *absent from all models?✅ Do staging models follow the
stg_[source]__[entity]spattern?✅ Do incremental models include
unique_keyandis_incremental()?✅ Are primary key columns tested with
uniqueandnot_null?✅ Is the comma style consistent (leading or trailing, per your rule)?
If any items fail, refine your .dinorules wording—sometimes a rule needs to be more explicit for the AI to interpret it correctly.
Common .dinorules Pitfalls and How to Avoid Them
Over-Constraining AI Output
Rules that are too strict can make AI struggle to generate useful code. For example, specifying exact CTE names, exact comment formats on every line, and rigid column ordering simultaneously may cause DinoAI to produce stilted, overly verbose output.
Recommendation: Start with 10–15 rules maximum. Don't add rules that linters like SQLFluff can auto-fix—focus .dinorules on patterns that are hard to fix after generation (naming conventions, ref()/source() usage, safety patterns).
Conflicting Rule Definitions
What happens when .dinorules contains contradictory instructions—for example, requiring both uppercase AND lowercase keywords? DinoAI validates rules at parse time and surfaces conflicts in the IDE, allowing teams to resolve contradictions before they affect code generation.
Treat .dinorules as code: review it for logical consistency just as you would review a SQL model for correctness.
Failing to Update Rules as Standards Evolve
.dinorules is not a "set and forget" file. As dbt™ best practices evolve—new materialization strategies, new macro patterns, new warehouse features—your rules should evolve too.
Recommendation: Schedule a quarterly .dinorules review. Audit recent pull requests for recurring review comments that could be codified as rules. Remove rules that are no longer enforced or relevant. Update rules when adopting new dbt™ features.
How .dinorules Compares to CLAUDE.md and dbt™ Agent Skills
Teams evaluating AI governance for dbt™ projects often encounter three options. Here's how they compare:
Feature | .dinorules (Paradime) | CLAUDE.md | dbt™ Agent Skills |
|---|---|---|---|
Purpose | AI coding standards enforcement for dbt™ | General project context for Claude Code | Reusable skill definitions for AI agents working with dbt™ |
Scope | All DinoAI surfaces + MCP clients | Claude Code only | Any MCP-compatible agent (open-source) |
Version control | Native (repo-committed, git-tracked by default) | Manual (repo-committed but not auto-loaded by all tools) | Repo-committed (open-source on GitHub) |
dbt™-specific rules | Yes — | Generic — requires manual dbt™ context | Partial — provides dbt™ workflow skills, not formatting rules |
Enforcement mechanism | Rules applied at generation time; no post-processing | Context injection; no enforcement guarantee | Skill execution; focuses on capability, not style |
Multi-surface support | Paradime IDE, Bolt AutoPilot, MCP Server | Claude Code terminal only | Depends on client implementation |
Key distinction: .dinorules is purpose-built for dbt™ workflows. It enforces coding standards—how code should look and what patterns to follow. CLAUDE.md provides context—project descriptions, architecture notes, general instructions. dbt™ Agent Skills provide capabilities—the ability for AI to compile, test, and manage dbt™ projects. These tools serve different purposes and can complement each other.
Ship Consistent Standards-Compliant dbt™ Code with Paradime
.dinorules eliminates the guesswork from AI-generated dbt™ code. Instead of hoping that AI follows your team's conventions, you declare them once, commit the file, and every AI interaction—across every surface—produces standards-compliant output.
The implementation path is straightforward:
Create a
.dinorulesfile in your repo root (start with the template above)Commit and push
Every DinoAI interaction now follows your declared standards
No plugins to install. No settings to sync. No post-generation linting.
Paradime offers a free tier to try DinoAI and .dinorules immediately. Start for free →
FAQs About .dinorules in dbt™ Projects
Can .dinorules be scoped to specific folders or model types?
Currently, .dinorules applies globally across the entire dbt™ project. Folder-specific or model-type scoping is on the roadmap for teams that need varied conventions across different domains or layers.
Do .dinorules work alongside .dinoprompts for reusable prompts?
Yes. .dinorules enforces coding standards (how code should look), while .dinoprompts stores reusable prompt templates (what code to generate). Both are version-controlled in the same repository and work together for consistent AI behavior.
How should teams version-control and review changes to .dinorules?
Treat .dinorules like any production code—changes should go through pull requests with team review to ensure new rules don't conflict with existing ones or over-constrain AI output. This also creates an audit trail of when and why standards evolved.
What happens when DinoAI encounters conflicting rules in .dinorules?
DinoAI validates rules at parse time and surfaces conflicts in the IDE, so teams can resolve contradictions before they affect code generation. For example, if your file contains both "use uppercase keywords" and "use lowercase keywords," the conflict is flagged immediately.
Does .dinorules enforcement add latency to AI response time?
Rule parsing adds negligible overhead. .dinorules is read once per session and applied during generation, with no noticeable impact on response speed. The file is typically small (under 100 lines), making parsing near-instantaneous.