AI and Intent
Rocky uses AI to help you write models. It does not use AI at run time. The
rocky-ai crate generates models, explains them, syncs them, and writes tests.
The compiler gates all four.
Nothing an LLM writes reaches the warehouse until it passes type checking and contract validation.
Three levels of AI
Section titled “Three levels of AI”Level 1: Generate from scratch
Section titled “Level 1: Generate from scratch”Describe what you want. Rocky writes the model, in the Rocky DSL or in SQL.
rocky ai "Calculate monthly revenue per customer from orders, joined with customer names"
The LLM gets context first: the models already in your project, the source tables, and the output format. It writes source code. Rocky compiles that code straight away. If compilation fails, Rocky feeds the diagnostics back and asks again. The limit is three attempts, and no flag or config key changes it.
That loop is the safety mechanism. An LLM can write SQL that parses but means the wrong thing. The compiler catches it before Rocky reports success.
Level 2: Compile-verify loop
Section titled “Level 2: Compile-verify loop”The loop is not only for generation. It runs whenever AI writes or edits code. Rocky compiles each result and feeds any diagnostics back until the code passes or hits the attempt limit. See The compile-verify safety net for the full flow.
Level 3: Intent as metadata
Section titled “Level 3: Intent as metadata”Store the intent, in plain English, in the model’s configuration. The compiler carries it through the semantic graph, where the maintenance commands read it.
name = "orders_summary"intent = "Monthly revenue and order count per customer, excluding cancelled orders"
[target]catalog = "warehouse"schema = "silver"table = "orders_summary"A stored intent lets Rocky do three things:
- Propose updates that keep the original intent as the model changes
- Write test assertions against the business requirement, not only the types
- Explain what a model does to someone who has never read it
Commands
Section titled “Commands”rocky ai “intent”
Section titled “rocky ai “intent””Writes a new model from a description:
# Generate in Rocky DSL (default)rocky ai "Top 10 customers by lifetime revenue"
# Generate in SQLrocky ai "Top 10 customers by lifetime revenue" --format sql
# Output as JSON for programmatic consumptionrocky ai "Top 10 customers by lifetime revenue" --output jsonThe output carries the generated source, the suggested model name, the format, and how many compile attempts it took.
rocky ai-explain
Section titled “rocky ai-explain”Reads models you already have and writes an intent description for each. Run this first when adopting intent on an existing project.
# Explain a specific modelrocky ai-explain --models models/ orders_summary
# Explain all models that don't have intent yetrocky ai-explain --models models/ --all
# Save the generated intent to each model's TOML configrocky ai-explain --models models/ --all --save--save writes the intent string into the model’s TOML sidecar. Once saved,
rocky ai-sync can use it.
rocky ai-sync
Section titled “rocky ai-sync”Proposes updates to models that carry intent:
# Show proposed changesrocky ai-sync --models models/
# Apply the proposed changesrocky ai-sync --models models/ --apply
# Sync a specific modelrocky ai-sync --models models/ --model orders_summaryThe sync runs in four steps:
- Compiles the project to build the current semantic graph and typed schemas
- Asks the LLM to propose an update for each model that carries intent, keeping that intent
- Puts the proposal through the compile-verify loop
- Prints the change as a diff;
--applywrites it to disk
Proposals today read the model’s declared intent and nothing else. Detecting
upstream schema changes (diffing added, removed, renamed, and type-changed
columns against a stored previous compilation) is designed but not wired up. The
state store does not yet snapshot prior compilation results, so rocky ai-sync
prints a note saying the proposals come from declared intent alone.
rocky ai-test
Section titled “rocky ai-test”Writes test assertions from a model’s intent and schema:
# Generate tests for a specific modelrocky ai-test --models models/ orders_summary
# Generate tests for all modelsrocky ai-test --models models/ --all
# Save generated tests to the tests/ directoryrocky ai-test --models models/ --all --saveThe LLM reads the intent, the column schema with types and nullability, and the target table. It produces SQL assertions. Each assertion is a query that returns 0 rows when the assertion holds. The Testing and Contracts page has the test format.
The compile-verify safety net
Section titled “The compile-verify safety net”Every AI feature runs through the compiler. That is a deliberate choice.
your intent generated code compile (English) ─────────► .rocky or .sql ───────► rocky-compiler ▲ │ │ ├─ no errors ─► shown │ │ to you └── diagnostics ───────┘ retry, up to the attempt limitThe compiler catches four kinds of mistake:
- Type mismatch. The LLM wrote
SUM(name)over a string column. - Missing column. It read a column the upstream model does not have.
- Contract violation. The model drops a required column, or gives it the wrong type.
- Broken lineage. It referenced a model that is not in the project.
Diagnostics carry a machine-readable code and a suggested fix, so the LLM usually corrects itself within one or two attempts.
Configuration
Section titled “Configuration”AI features need an API key:
export ANTHROPIC_API_KEY="sk-ant-..."Rocky sets the provider, the model, and the attempt limit internally. It uses
Claude by default. No AI feature runs on its own. You always call it through a
rocky ai subcommand.
Adopting intent on an existing project
Section titled “Adopting intent on an existing project”- Run
rocky ai-explain --all --saveto write an intent for every model. - Read the generated intents and edit them. They are plain English, so change anything that reads wrong.
- Run
rocky ai-test --all --saveto write a baseline set of assertions. - From here,
rocky ai-syncproposes updates from each model’s declared intent. It does not detect upstream schema changes yet.
Intent is optional. A model without intent still compiles, tests, and runs. Intent turns on the maintenance commands. It is never required.