Skip to content

Commit a30e344

Browse files
suryaiyer95claude
andcommitted
feat: rewrite builder prompt with skills-first architecture and surface altimate_core tools
- Restructure `builder.txt` from flat tool list to skills-first architecture - Surface 6 `altimate_core` offline SQL analysis tools (validate, semantics, lint, column_lineage, correct, grade) - Add structured 5-phase workflow: Explore → Plan → Analyze → Execute → Validate - Add Common Pitfalls section from benchmark failure analysis - Fix dbt-tools CLI: improve error handling in `columns`, `init`, and main dispatch - Update dbt-develop and dbt-troubleshoot skills with `altimate-dbt` references Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ddf6edd commit a30e344

9 files changed

Lines changed: 210 additions & 141 deletions

File tree

.opencode/skills/dbt-develop/SKILL.md

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,48 @@ Before writing any SQL:
3333
- Read the task requirements carefully
3434
- Identify which layer this model belongs to (staging, intermediate, mart)
3535
- Check existing models for naming conventions and patterns
36+
- **Check dependencies:** If `packages.yml` exists, check for `dbt_packages/` or `package-lock.yml`. Only run `dbt deps` if packages are declared but not yet installed.
3637

3738
```bash
3839
altimate-dbt info # project name, adapter type
3940
altimate-dbt parents --model <upstream> # understand what feeds this model
4041
altimate-dbt children --model <downstream> # understand what consumes it
4142
```
4243

43-
### 2. Discover — Know Your Data
44+
### 2. Discover — Understand the Data Before Writing
4445

45-
Never write SQL without knowing the columns:
46+
**Never write SQL without deeply understanding your data first.** The #1 cause of wrong results is writing SQL blind — assuming grain, relationships, column names, or values without checking.
47+
48+
**Step 2a: Read all documentation and schema definitions**
49+
- Read `sources.yml`, `schema.yml`, and any YAML files that describe the source/parent models
50+
- These contain column descriptions, data types, tests, and business context
51+
- Pay special attention to: primary keys, unique constraints, relationships between tables, and what each column represents
52+
53+
**Step 2b: Understand the grain of each parent model/source**
54+
- What does one row represent? (one customer? one event? one day per customer?)
55+
- What are the primary/unique keys?
56+
- This is critical for JOINs — joining on the wrong grain causes fan-out (too many rows) or missing rows
4657

4758
```bash
4859
altimate-dbt columns --model <name> # existing model columns
4960
altimate-dbt columns-source --source <src> --table <tbl> # source table columns
50-
altimate-dbt column-values --model <name> --column <col> # sample values
61+
altimate-dbt execute --query "SELECT count(*) FROM {{ ref('model') }}" --limit 1
5162
altimate-dbt execute --query "SELECT * FROM {{ ref('model') }}" --limit 5
63+
altimate-dbt column-values --model <name> --column <col> # sample values for key columns
5264
```
5365

54-
Read existing models in the same directory to match patterns:
66+
**Step 2c: Query the actual data to verify your understanding**
67+
- Check row counts, NULLs, date ranges, cardinality of key columns
68+
- Verify foreign key relationships actually hold (do all IDs in child exist in parent?)
69+
- Check for duplicates in what you think are unique keys
70+
71+
**Step 2d: Read existing models that your new model will reference**
72+
- Read the actual SQL of parent models — understand their logic, filters, and transformations
73+
- Read 2-3 existing models in the same directory to match patterns and conventions
74+
5575
```bash
5676
glob models/**/*.sql # find all model files
57-
read <model_file> # understand existing patterns
77+
read <model_file> # understand existing patterns and logic
5878
```
5979

6080
### 3. Write — Follow Layer Patterns
@@ -64,20 +84,37 @@ See [references/medallion-architecture.md](references/medallion-architecture.md)
6484
See [references/incremental-strategies.md](references/incremental-strategies.md) for incremental materialization.
6585
See [references/yaml-generation.md](references/yaml-generation.md) for sources.yml and schema.yml.
6686

67-
### 4. Validate — Always Build After Writing
87+
### 4. Validate — Build, Verify, Check Impact
6888

6989
Never stop at writing the SQL. Always validate:
7090

91+
**Build it:**
7192
```bash
7293
altimate-dbt compile --model <name> # catch Jinja errors
7394
altimate-dbt build --model <name> # materialize + run tests
74-
altimate-dbt execute --query "SELECT * FROM {{ ref('<name>') }}" --limit 10 # spot-check
7595
```
7696

77-
If building downstream too:
97+
**Verify the output:**
98+
```bash
99+
altimate-dbt columns --model <name> # confirm expected columns exist
100+
altimate-dbt execute --query "SELECT count(*) FROM {{ ref('<name>') }}" --limit 1
101+
altimate-dbt execute --query "SELECT * FROM {{ ref('<name>') }}" --limit 10 # spot-check values
102+
```
103+
- Do the columns match what schema.yml or the task expects?
104+
- Does the row count make sense? (no fan-out from bad joins, no missing rows from wrong filters)
105+
- Are values correct? (spot-check NULLs, aggregations, date ranges)
106+
107+
**Check SQL quality** (on the compiled SQL from `altimate-dbt compile`):
108+
- `sql_analyze` — catches anti-patterns (SELECT *, cartesian products, missing filters)
109+
- `altimate_core_validate` — validates syntax and schema references
110+
- `altimate_core_column_lineage` — traces how source columns flow to output columns. Use this to verify your SELECT is pulling the right columns from the right sources, especially for complex JOINs or multi-CTE models.
111+
112+
**Check downstream impact** (when modifying an existing model):
78113
```bash
79-
altimate-dbt build --model <name> --downstream
114+
altimate-dbt children --model <name> # who depends on this?
115+
altimate-dbt build --model <name> --downstream # rebuild downstream to catch breakage
80116
```
117+
Use `altimate-dbt children` and `altimate-dbt parents` to verify the DAG is intact when changes could affect downstream models.
81118

82119
## Iron Rules
83120

.opencode/skills/dbt-troubleshoot/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ If `doctor` fails, fix the environment first. Common issues:
4040
- Python not found → reinstall or set `--python-path`
4141
- dbt-core not installed → `pip install dbt-core`
4242
- No `dbt_project.yml` → wrong directory
43+
- Missing packages → if `packages.yml` exists but `dbt_packages/` doesn't, run `dbt deps`
4344

4445
### Step 2: Classify the Error
4546

packages/dbt-tools/src/commands/columns.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,29 @@ import type { DBTProjectIntegrationAdapter } from "@altimateai/dbt-integration"
33
export async function columns(adapter: DBTProjectIntegrationAdapter, args: string[]) {
44
const model = flag(args, "model")
55
if (!model) return { error: "Missing --model" }
6-
return adapter.getColumnsOfModel(model)
6+
try {
7+
const result = await adapter.getColumnsOfModel(model)
8+
if (!result) return { error: `Model '${model}' not found in manifest. Try: altimate-dbt execute --query "SELECT * FROM ${model} LIMIT 1"` }
9+
return result
10+
} catch (e) {
11+
const msg = e instanceof Error ? e.message : String(e)
12+
return { error: `Failed to get columns for '${model}': ${msg}. Try: altimate-dbt execute --query "SELECT * FROM ${model} LIMIT 1"` }
13+
}
714
}
815

916
export async function source(adapter: DBTProjectIntegrationAdapter, args: string[]) {
1017
const name = flag(args, "source")
1118
const table = flag(args, "table")
1219
if (!name) return { error: "Missing --source" }
1320
if (!table) return { error: "Missing --table" }
14-
return adapter.getColumnsOfSource(name, table)
21+
try {
22+
const result = await adapter.getColumnsOfSource(name, table)
23+
if (!result) return { error: `Source '${name}.${table}' not found. Try: altimate-dbt execute --query "SELECT * FROM ${table} LIMIT 1"` }
24+
return result
25+
} catch (e) {
26+
const msg = e instanceof Error ? e.message : String(e)
27+
return { error: `Failed to get columns for source '${name}.${table}': ${msg}` }
28+
}
1529
}
1630

1731
export async function values(adapter: DBTProjectIntegrationAdapter, args: string[]) {

packages/dbt-tools/src/commands/init.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export async function init(args: string[]) {
3636
const cfg: Config = {
3737
projectRoot: project,
3838
pythonPath: py ?? python(),
39-
dbtIntegration: "core",
39+
dbtIntegration: "corecommand",
4040
queryLimit: 500,
4141
}
4242

packages/dbt-tools/src/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { read } from "./config"
1+
import { join, resolve } from "path"
2+
import { existsSync } from "fs"
3+
import { read, type Config } from "./config"
24
import { init } from "./commands/init"
35
import { validate } from "./check"
46

@@ -27,6 +29,11 @@ const USAGE = {
2729
const cmd = process.argv[2]
2830
const rest = process.argv.slice(3)
2931

32+
function flag(args: string[], name: string): string | undefined {
33+
const i = args.indexOf(`--${name}`)
34+
return i >= 0 ? args[i + 1] : undefined
35+
}
36+
3037
function diagnose(err: Error): { error: string; fix?: string } {
3138
const msg = err.message || String(err)
3239
if (msg.includes("private field") || msg.includes("#stdin") || msg.includes("#stdout")) {
@@ -102,6 +109,17 @@ async function main() {
102109
const cfg = await read()
103110
if (!cfg) return { error: "No config found. Run: altimate-dbt init" }
104111

112+
// Override projectRoot: --project-dir flag > cwd auto-detect > config
113+
const dirFlag = flag(rest, "project-dir")
114+
if (dirFlag) {
115+
cfg.projectRoot = resolve(dirFlag)
116+
} else {
117+
const cwdProject = join(process.cwd(), "dbt_project.yml")
118+
if (existsSync(cwdProject) && resolve(process.cwd()) !== resolve(cfg.projectRoot)) {
119+
cfg.projectRoot = resolve(process.cwd())
120+
}
121+
}
122+
105123
if (cmd === "doctor") return (await import("./commands/doctor")).doctor(cfg)
106124

107125
// Validate prerequisites before loading the heavy adapter

packages/opencode/src/altimate/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export * from "./tools/altimate-core-validate"
4545
export * from "./tools/dbt-lineage"
4646
export * from "./tools/dbt-manifest"
4747
export * from "./tools/dbt-profiles"
48-
export * from "./tools/dbt-run"
48+
4949
export * from "./tools/finops-analyze-credits"
5050
export * from "./tools/finops-expensive-queries"
5151
export * from "./tools/finops-query-history"

0 commit comments

Comments
 (0)