feat: dbt_sql_graph tool — a model's CTEs, joins and filters as a graph

HK
1d ago
+1640-0

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_graph tool: 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_lineage endpoint, 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.
  • dbtAdapterFor is 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.apiRequest posts 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.