feat: dbt_sql_graph tool ā a model's CTEs, joins and filters as a graph
Issue for this PR
None
Type of change
- Bug fix
- New feature
- Refactor / code improvement
- Documentation
What does this PR do?
Adds the dbt_sql_graph { model } tool. It compiles the model with the project's dbt integration, reads its non-ephemeral parents' columns from the warehouse's metadata, and sends the compiled SQL to the Altimate backend's dbt/v3/sql_lineage endpoint (api/sql-lineage.ts). The backend's __final_select__ is renamed after the model and each relation node is tied to its dbt unique id by name, database and schema (a relation two parents could both be is tied to neither). The result is { nodes: [{ id, name, type, nodeId?, sql, columns }], edges: [[fromId, toId]] } (id is the backend's unique node key; name is only what is shown and can repeat; a join or filter's expression is its sql) plus a one-line-per-node text list. It is adapter-backed, so it needs write permission and an Altimate key; read-only calls get the foundation's refusal.
This branch contains the Power User foundation commits (feat/pu-mods-foundation); this PR's own change is tools/dbt-sql-graph.ts, api/sql-lineage.ts and test/altimate/dbt-sql-graph.test.ts.
How did you verify your code works?
bun test test/altimate/dbt-sql-graph.test.ts test/altimate/dbt-adapter-access.test.ts (44 tests, mocked endpoint and adapter) and bun typecheck, both from packages/opencode. Also run for real: altimate tool run dbt_sql_graph --allow-write on a built jaffle_shop copy against the Altimate backend (stg_customers: 4 nodes; orders: 9 nodes with a join and a group).
Cost side effects
One backend call and one warehouse metadata read (getBulkSchemaFromDB, parents only) per dbt_sql_graph call. Nothing runs per edit. The model's compile can run SQL only as the dbt integration already does for any compile.
Screenshots / recordings
Recorded run, real backend: /Users/harish/.quikim/artifacts/pu-mods/videos/P-01.mp4 (cast P-01.cast): the branch-built CLI's dbt_sql_graph output for orders, then /sql-graph orders in Claude Code (plugin PR AltimateAI/altimate-claude-plugin#29).
Review follow-ups (not changed here)
Credentials are checked after the adapter starts; the shared API client has a fixed 15 s timeout and no abort signal (cancel is raced in the tool instead); the client drops the backend's 400 detail, so a parse failure shows only the status; manifest description/meta are sent to the backend as Power User does. The backend's response shape was verified against a local backend checkout and a live call.
Checklist
- I have tested my changes locally
- I have not included unrelated changes in this PR
- I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"
Changelog:
- Added the
dbt_sql_graphtool: a dbt model's CTEs, joins and filters as a graph.
š¤ Generated with Claude Code
Summary by cubic
Adds the dbt_sql_graph { model } tool, which compiles a model with the dbt adapter and returns its CTEs, joins, and filters as a graph of nodes and edges, and lays the shared foundation for adapter-backed Altimate tools.
- The tool sends the compiled SQL to the Altimate backend's
dbt/v3/sql_lineageendpoint, names the final select after the model (<model> (final select)when the SQL already has a node by that name), and ties each relation to its dbt unique id by name, plus schema and database when both sides give one. Nodes keep an id apart from their on-screen name, so two relations can share one, and joins and filters keep the SQL they were built from. - The graph merges each parent's manifest columns with the warehouse's reported columns, keyed by the adapter's folding case, so the backend sees complete schemas.
- Only SQL models are accepted: seeds, snapshots, and Python models are refused before anything compiles.
dbtAdapterForis the single gate for adapter-backed tools: it refuses read-only calls, sessions in a different dbt project, and an adapter that didn't start, with a bounded wait that follows call aborts. Refusals return as tool failures, and an abort during the backend call ends it at once.AltimateApi.apiRequestposts to any backend endpoint with the stored credentials and a clear error naming the credentials file when missing.- Eight stubs (
dbt_run_results,dbt_defer_state,dbt_map_relations,docs_share_comments,dbt_cost_estimate,dbt_health,dbt_docs_coverage,dbt_cte_profile) are exposed through the tool allow-list as not-yet-implemented placeholders. - The tool needs write permission and an Altimate key; each call costs one backend request and one warehouse metadata read of the model's parents only.