datagraph-core 0.8.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. datagraph_core-0.8.2/LICENSE +21 -0
  2. datagraph_core-0.8.2/PKG-INFO +427 -0
  3. datagraph_core-0.8.2/README.md +381 -0
  4. datagraph_core-0.8.2/pyproject.toml +61 -0
  5. datagraph_core-0.8.2/setup.cfg +4 -0
  6. datagraph_core-0.8.2/src/datagraph/__init__.py +59 -0
  7. datagraph_core-0.8.2/src/datagraph/ai/__init__.py +6 -0
  8. datagraph_core-0.8.2/src/datagraph/ai/explain.py +52 -0
  9. datagraph_core-0.8.2/src/datagraph/ai/lineage.py +162 -0
  10. datagraph_core-0.8.2/src/datagraph/ai/providers.py +197 -0
  11. datagraph_core-0.8.2/src/datagraph/analysis/__init__.py +5 -0
  12. datagraph_core-0.8.2/src/datagraph/analysis/impact.py +85 -0
  13. datagraph_core-0.8.2/src/datagraph/analysis/modeling.py +514 -0
  14. datagraph_core-0.8.2/src/datagraph/analysis/relationships.py +64 -0
  15. datagraph_core-0.8.2/src/datagraph/analysis/risk.py +70 -0
  16. datagraph_core-0.8.2/src/datagraph/analysis/tests_recommender.py +55 -0
  17. datagraph_core-0.8.2/src/datagraph/cli.py +831 -0
  18. datagraph_core-0.8.2/src/datagraph/extractors/__init__.py +31 -0
  19. datagraph_core-0.8.2/src/datagraph/extractors/airflow_extractor.py +223 -0
  20. datagraph_core-0.8.2/src/datagraph/extractors/base.py +21 -0
  21. datagraph_core-0.8.2/src/datagraph/extractors/datahub_extractor.py +162 -0
  22. datagraph_core-0.8.2/src/datagraph/extractors/dbt_extractor.py +321 -0
  23. datagraph_core-0.8.2/src/datagraph/extractors/git_extractor.py +118 -0
  24. datagraph_core-0.8.2/src/datagraph/extractors/js_extractor.py +146 -0
  25. datagraph_core-0.8.2/src/datagraph/extractors/lambda_extractor.py +215 -0
  26. datagraph_core-0.8.2/src/datagraph/extractors/lineage_file_extractor.py +138 -0
  27. datagraph_core-0.8.2/src/datagraph/extractors/openlineage_extractor.py +130 -0
  28. datagraph_core-0.8.2/src/datagraph/extractors/python_extractor.py +231 -0
  29. datagraph_core-0.8.2/src/datagraph/extractors/registry.py +94 -0
  30. datagraph_core-0.8.2/src/datagraph/extractors/sql_extractor.py +256 -0
  31. datagraph_core-0.8.2/src/datagraph/extractors/sql_in_code.py +88 -0
  32. datagraph_core-0.8.2/src/datagraph/extractors/warehouse_extractor.py +240 -0
  33. datagraph_core-0.8.2/src/datagraph/graph/__init__.py +16 -0
  34. datagraph_core-0.8.2/src/datagraph/graph/graph.py +546 -0
  35. datagraph_core-0.8.2/src/datagraph/graph/model.py +106 -0
  36. datagraph_core-0.8.2/src/datagraph/html_report.py +240 -0
  37. datagraph_core-0.8.2/src/datagraph/knowledge.py +210 -0
  38. datagraph_core-0.8.2/src/datagraph/maintenance.py +109 -0
  39. datagraph_core-0.8.2/src/datagraph/mcp_server.py +120 -0
  40. datagraph_core-0.8.2/src/datagraph/profiling.py +202 -0
  41. datagraph_core-0.8.2/src/datagraph/report.py +162 -0
  42. datagraph_core-0.8.2/src/datagraph/security.py +96 -0
  43. datagraph_core-0.8.2/src/datagraph_core.egg-info/PKG-INFO +427 -0
  44. datagraph_core-0.8.2/src/datagraph_core.egg-info/SOURCES.txt +80 -0
  45. datagraph_core-0.8.2/src/datagraph_core.egg-info/dependency_links.txt +1 -0
  46. datagraph_core-0.8.2/src/datagraph_core.egg-info/entry_points.txt +2 -0
  47. datagraph_core-0.8.2/src/datagraph_core.egg-info/requires.txt +33 -0
  48. datagraph_core-0.8.2/src/datagraph_core.egg-info/top_level.txt +1 -0
  49. datagraph_core-0.8.2/tests/test_ai_layer.py +101 -0
  50. datagraph_core-0.8.2/tests/test_airflow.py +67 -0
  51. datagraph_core-0.8.2/tests/test_analyze.py +67 -0
  52. datagraph_core-0.8.2/tests/test_bom_files.py +50 -0
  53. datagraph_core-0.8.2/tests/test_bridge_detection.py +65 -0
  54. datagraph_core-0.8.2/tests/test_cli.py +43 -0
  55. datagraph_core-0.8.2/tests/test_cli_v2.py +76 -0
  56. datagraph_core-0.8.2/tests/test_column_impact.py +43 -0
  57. datagraph_core-0.8.2/tests/test_datahub.py +57 -0
  58. datagraph_core-0.8.2/tests/test_dbt_compiled_lineage.py +86 -0
  59. datagraph_core-0.8.2/tests/test_dbt_extractor.py +53 -0
  60. datagraph_core-0.8.2/tests/test_git_extractor.py +82 -0
  61. datagraph_core-0.8.2/tests/test_graph.py +56 -0
  62. datagraph_core-0.8.2/tests/test_jaffle_shop.py +69 -0
  63. datagraph_core-0.8.2/tests/test_js.py +56 -0
  64. datagraph_core-0.8.2/tests/test_knowledge.py +80 -0
  65. datagraph_core-0.8.2/tests/test_lambda.py +84 -0
  66. datagraph_core-0.8.2/tests/test_lineage.py +63 -0
  67. datagraph_core-0.8.2/tests/test_lineage_file.py +57 -0
  68. datagraph_core-0.8.2/tests/test_llm_lineage.py +142 -0
  69. datagraph_core-0.8.2/tests/test_mcp_maintenance.py +62 -0
  70. datagraph_core-0.8.2/tests/test_modeling.py +122 -0
  71. datagraph_core-0.8.2/tests/test_openlineage.py +53 -0
  72. datagraph_core-0.8.2/tests/test_plugins.py +54 -0
  73. datagraph_core-0.8.2/tests/test_profiling.py +72 -0
  74. datagraph_core-0.8.2/tests/test_provenance_exports.py +60 -0
  75. datagraph_core-0.8.2/tests/test_providers.py +147 -0
  76. datagraph_core-0.8.2/tests/test_python_extractor.py +31 -0
  77. datagraph_core-0.8.2/tests/test_report.py +35 -0
  78. datagraph_core-0.8.2/tests/test_security.py +103 -0
  79. datagraph_core-0.8.2/tests/test_sql_column_lineage.py +64 -0
  80. datagraph_core-0.8.2/tests/test_sql_extractor.py +55 -0
  81. datagraph_core-0.8.2/tests/test_warehouse.py +61 -0
  82. datagraph_core-0.8.2/tests/test_warehouse_sqlite.py +91 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 impactgraph contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,427 @@
1
+ Metadata-Version: 2.4
2
+ Name: datagraph-core
3
+ Version: 0.8.2
4
+ Summary: AI-powered Change Impact Graph for data and code systems: answer 'if I change this, what can break?'
5
+ Author: Arati
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sumit-gupta03/datagraph
8
+ Keywords: change-impact,lineage,dbt,sql,openlineage,dependency-graph,data-engineering,impact-analysis,mcp
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Classifier: Topic :: Database
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: networkx>=3.0
24
+ Requires-Dist: rich>=13.0
25
+ Provides-Extra: sql
26
+ Requires-Dist: sqlglot>=20.0; extra == "sql"
27
+ Provides-Extra: ai
28
+ Requires-Dist: anthropic>=0.40.0; extra == "ai"
29
+ Provides-Extra: bedrock
30
+ Requires-Dist: boto3>=1.34; extra == "bedrock"
31
+ Provides-Extra: mcp
32
+ Requires-Dist: mcp>=1.0; python_version >= "3.10" and extra == "mcp"
33
+ Provides-Extra: yaml
34
+ Requires-Dist: pyyaml>=6.0; extra == "yaml"
35
+ Provides-Extra: all
36
+ Requires-Dist: sqlglot>=20.0; extra == "all"
37
+ Requires-Dist: anthropic>=0.40.0; extra == "all"
38
+ Requires-Dist: boto3>=1.34; extra == "all"
39
+ Requires-Dist: mcp>=1.0; python_version >= "3.10" and extra == "all"
40
+ Requires-Dist: pyyaml>=6.0; extra == "all"
41
+ Provides-Extra: dev
42
+ Requires-Dist: pytest>=7.0; extra == "dev"
43
+ Requires-Dist: sqlglot>=20.0; extra == "dev"
44
+ Requires-Dist: pyyaml>=6.0; extra == "dev"
45
+ Dynamic: license-file
46
+
47
+ # datagraph
48
+
49
+ **The data engine: lineage · relationships · data profiling · dimensional modelling · knowledge graph for AI assistants — built deterministically from your database, dbt project, SQL and code.**
50
+
51
+ Give datagraph a connection (and/or a dbt manifest, SQL, code) and it builds one graph of tables, columns, models, jobs and code,
52
+ then answers from that graph — locally, in seconds, with no LLM in the loop:
53
+
54
+ - **Where does this table / column come from and what does it feed?** (lineage, column level)
55
+ - **How are my tables related?** (foreign keys, view lineage, schema map)
56
+ - **What does the data look like?** (row counts, freshness, nulls, distincts — sensitive columns masked)
57
+ - **What is my dimensional model?** (Kimball facts / dimensions / bus matrix / SCD / issues, or a proposed star from a wide table)
58
+ - **Give my AI assistant the context.** (`context` packs, a Markdown wiki + `llms.txt`, an MCP server)
59
+ - **If I change this, what breaks?** (impact, risk, owners, tests — and the companion PR check
60
+ [impactgraph](https://github.com/sumit-gupta03/impactgraph) built on this engine)
61
+
62
+ ```
63
+ warehouse / dbt / SQL / Python / Airflow / Lambda / OpenLineage / DataHub ──► one deterministic graph
64
+ ──► lineage · relationships · profiles · dimensional model · impact ──► CLI · HTML · JSON · wiki · MCP
65
+ ```
66
+
67
+ <p align="center">
68
+ <img src="docs/images/lineage-jaffle-customers.png" alt="Lineage of the customers model in dbt's jaffle_shop project" width="900"><br>
69
+ <em><code>datagraph lineage customers --html</code> on dbt's public jaffle_shop project: upstream through staging models to seed files, downstream to the table and its columns.</em>
70
+ </p>
71
+
72
+ ## Contents
73
+
74
+ 1. [Install](#install)
75
+ 2. [The standard flow: connection in → lineage, profiling, model out](#the-standard-flow-connection-in--lineage-profiling-model-out)
76
+ 3. [What goes into the graph](#what-goes-into-the-graph)
77
+ 4. [Commands](#commands)
78
+ 5. [Dimensional modelling](#dimensional-modelling)
79
+ 6. [Data profiling](#data-profiling)
80
+ 7. [Knowledge base & MCP for AI assistants](#knowledge-base--mcp-for-ai-assistants)
81
+ 8. [Impact analysis & the impactgraph companion](#impact-analysis--the-impactgraph-companion)
82
+ 9. [Python API](#python-api)
83
+ 10. [Security](#security)
84
+ 11. [How it compares](#how-it-compares-graphify--datahub--openlineage--datagraph)
85
+ 12. [Node ids, provenance, propagation](#node-ids-provenance-propagation)
86
+ 13. [Development & roadmap](#development)
87
+
88
+ ## Install
89
+
90
+ ```bash
91
+ pip install datagraph-core # core: graph, warehouse/dbt/code extractors, lineage, profiling, modelling, wiki
92
+ pip install "datagraph-core[sql]" # + sqlglot: SQL files, view definitions, column-level lineage (recommended)
93
+ pip install "datagraph-core[mcp]" # + MCP server for Claude Code / Claude Desktop / Cursor
94
+ pip install "datagraph-core[ai]" # + Anthropic Claude for explanations / LLM lineage fallback
95
+ pip install "datagraph-core[bedrock]" # + Amazon Bedrock (Nova, Claude on Bedrock, Llama ...) for the same; OpenAI-compatible needs nothing extra
96
+ pip install "datagraph-core[all]" # everything (also PyYAML for YAML lineage files / serverless.yml)
97
+ ```
98
+
99
+ The PyPI distribution is **`datagraph-core`** (the bare name `datagraph` is not allowed on PyPI); the import name, CLI and MCP server are all `datagraph`:
100
+ `pip install datagraph-core` → `import datagraph` / `datagraph analyze …`.
101
+
102
+ Database drivers: SQLite and DuckDB files work out of the box; for Snowflake / Postgres / BigQuery / Redshift / MySQL / SQL Server
103
+ install SQLAlchemy plus the driver and pass a SQLAlchemy URL (or pass an open DB-API connection from Python).
104
+ From source: `pip install "datagraph-core[sql] @ git+https://github.com/sumit-gupta03/datagraph"`.
105
+
106
+ ## The standard flow: connection in → lineage, profiling, model out
107
+
108
+ ```bash
109
+ datagraph analyze --warehouse "snowflake://user:pw@account/db" --schemas analytics,raw -o out/
110
+ datagraph analyze --warehouse warehouse.db -o out/ # a SQLite / DuckDB file works too
111
+ ```
112
+
113
+ One command runs the standard sequence (use a **read-only** database role; the password is never stored or logged):
114
+
115
+ | Step | What datagraph does | Output in `out/` |
116
+ |---|---|---|
117
+ | connect | opens the connection (`sqlite` / `duckdb` file, or any SQLAlchemy URL) | — |
118
+ | schema | reads `information_schema`: tables, views, columns + types, primary & foreign keys, view definitions → graph | `datagraph.json` |
119
+ | relationships | table↔table and column↔column relationships (FKs, view lineage), per-table column lists | `relationships.json` |
120
+ | profiling | row count, freshness, per-column null %, distinct, min/max, top values (sampled); sensitive-looking columns masked | stored on the graph |
121
+ | dimensional model | Kimball: facts, dimensions, bridges, bus matrix, grain, measures & additivity, SCD types, conformed dimensions, issues | `MODEL.md`, `model.json`, `er-diagram.mmd` |
122
+ | lineage view | interactive HTML of the whole graph | `lineage.html` |
123
+ | knowledge base | `index.md`, one page per table, `GRAPH_REPORT.md`, `MODEL.md`, `llms.txt` | `wiki/` |
124
+
125
+ Then ask questions against the saved graph:
126
+
127
+ ```bash
128
+ datagraph lineage fact_sales --graph out/datagraph.json # upstream / downstream (add --html lineage.html)
129
+ datagraph relationships --graph out/datagraph.json --search customer
130
+ datagraph context dim_customer --graph out/datagraph.json # compact knowledge pack for an assistant
131
+ datagraph model --graph out/datagraph.json --from-table wide_orders
132
+ datagraph mcp --graph out/datagraph.json # MCP server for your coding assistant
133
+ ```
134
+
135
+ Options: `--schemas a,b` · `--database NAME` · `--dialect snowflake|postgres|bigquery|…` (for view SQL) · `--no-profile` (metadata only) ·
136
+ `--sample N` · `--no-top-values` · `--no-inferred` (declared foreign keys only) · `--json`.
137
+
138
+ ## What goes into the graph
139
+
140
+ `datagraph build` accepts any combination; fragments merge by shared node ids and table aliases (`analytics.orders` vs `prod.analytics.orders`) are linked automatically.
141
+
142
+ | Source | Flag | Contributes |
143
+ |---|---|---|
144
+ | Warehouse / database | `--warehouse DSN` (+ `--warehouse-schemas`, `--warehouse-database`) | tables, views, columns + types, primary keys, **foreign keys** (table and column level), view lineage |
145
+ | dbt project | `--dbt-manifest` (+ `--dbt-catalog`) | models, sources, seeds, snapshots, exposures, the DAG, materialized tables, columns + types, **owners**, **column-to-column lineage** from compiled SQL (expands `select *` with the catalog), compiled SQL and test names per model |
146
+ | Raw SQL files | `--sql DIR` | table/view lineage and column lineage (aliases, CTEs, renames) via sqlglot |
147
+ | Python | `--repo DIR` | files, functions, classes, imports, calls (*inferred*), and **SQL found inside code → table edges** |
148
+ | JavaScript / TypeScript | `--js DIR` | files, functions, imports, calls, SQL-in-code |
149
+ | Airflow | `--airflow DIR` | DAGs, tasks, dependencies (`>>`, lists, `chain`), `python_callable` links, SQL in operators |
150
+ | AWS Lambda | `--lambda FILE` | serverless.yml / SAM / CloudFormation: lambdas → handlers, HTTP APIs, S3/SQS/DynamoDB events, env-referenced tables |
151
+ | OpenLineage | `--openlineage FILE` | datasets, jobs, schema + `columnLineage` facets, ownership |
152
+ | DataHub | `--lineage-file FILE`, `--datahub URL` | curated lineage files, or a live GraphQL import of datasets, owners, table and column lineage |
153
+ | Git | `datagraph diff` | which files **and which functions** changed |
154
+ | Your own tool | `--<plugin>` | any package exposing a `datagraph.extractors` entry point (see Python API) |
155
+
156
+ ## Commands
157
+
158
+ | Command | Purpose |
159
+ |---|---|
160
+ | `analyze --warehouse DSN -o DIR` | the standard flow above, in one go |
161
+ | `build [inputs] -o datagraph.json` | build / refresh the graph from any inputs (`--update` skips when inputs are unchanged) |
162
+ | `lineage NODE [--html F] [--json]` | upstream (where it comes from) and downstream (what it feeds) |
163
+ | `relationships [--search X] [--json]` | schema map: every table with columns, foreign keys, lineage relationships, profiles |
164
+ | `profile --warehouse DSN [--tables a,b]` | data profiling stored on the graph |
165
+ | `model [--from-table T] [--mermaid F] [--markdown F] [--json]` | dimensional model / proposed star schema |
166
+ | `context NODE` | compact knowledge pack for one node |
167
+ | `wiki -o DIR` | Markdown knowledge base + `GRAPH_REPORT.md` + `MODEL.md` + `llms.txt` |
168
+ | `impact NODE` · `diff --repo .` · `paths A B` · `hotspots` | change impact: blast radius, risk, owners, tests; propagation paths; riskiest nodes |
169
+ | `html NODE -o F` · `html --all -o F` · `export --format graphml\|dot\|cypher\|json` | pictures and exports |
170
+ | `nodes --search X` | find node ids |
171
+ | `graph-diff old.json new.json` | schema / dependency drift between two graphs |
172
+ | `watch` · `hook-install` | keep the graph fresh (file watcher, git pre-commit hook) |
173
+ | `enrich [--dry-run]` · `explain NODE` | optional LLM lineage fallback / plain-language explanation (`[ai]`) |
174
+ | `mcp --graph F` | MCP server (`[mcp]`) |
175
+ | `plugins` | list installed extractor plugins |
176
+
177
+ Every command takes `--graph PATH` (default `datagraph.json`), most take `--json` and `--no-inferred`.
178
+
179
+ ## Dimensional modelling
180
+
181
+ ```bash
182
+ datagraph model # classify + star schema + issues + Mermaid ER diagram (Markdown to stdout)
183
+ datagraph model --markdown MODEL.md --mermaid er.mmd --json
184
+ datagraph model --from-table wide_orders # propose fact + dimensions from one flat / wide table
185
+ datagraph model --no-inferred # declared foreign keys only
186
+ ```
187
+
188
+ Standard Kimball approach, computed deterministically and **explained** (every classification lists its reasons):
189
+
190
+ - **Column roles** — pk / fk / date / measure / flag / attribute from names, declared types (warehouse or dbt catalog) and profiles.
191
+ - **Table roles** — fact / dimension / bridge / lookup / derived (views without key links) with a confidence and reasons: foreign keys
192
+ out/in, measures, dates, attributes, naming conventions, row counts.
193
+ - **Key links** — declared foreign keys (`extracted`) plus name inference such as `orders.customer_id → customers` (`inferred`, flagged to verify).
194
+ - **Star schema** — per fact: business process → **grain** → dimensions → facts (the four-step design), measures with additivity;
195
+ per dimension: key, attributes, used-by, **SCD type** (2 when `valid_from/valid_to/is_current` exist, 1 when `updated_at`, else
196
+ undecided with a recommendation); **bus matrix** (facts × dimensions) and **conformed dimensions**; snowflake chains.
197
+ - **Issues** — fact without a time grain, key with no dimension, fact-to-fact links, measures sitting in a dimension, unused
198
+ dimensions, natural/text keys (surrogate key advice), missing `dim_date`, high-null keys (late-arriving dimensions).
199
+ - **Propose from a wide table** — groups low-cardinality attributes by prefix into dimensions (`customer_name`, `customer_country` →
200
+ `dim_customer`), numeric columns into measures, dates into `dim_date`; near-unique text stays as degenerate dimensions.
201
+
202
+ `MODEL.md` is part of the wiki, `model` is an MCP tool, and the role shows up in `context` packs.
203
+
204
+ ## Data profiling
205
+
206
+ ```bash
207
+ datagraph profile --warehouse prod.db [--tables customers,orders] [--sample 100000] [--no-top-values]
208
+ ```
209
+
210
+ Per table: row count, freshness (max of date-like columns); per column: null %, distinct, min/max, top values (sampled). Results are
211
+ stored on the graph nodes and surface in `relationships`, `context`, lineage HTML tooltips and the wiki. Columns whose names look
212
+ sensitive (email, phone, name, address, card, token, …) keep counts only — no sample values. Profiles also make the risk score
213
+ data-aware (empty tables count half, >1M-row tables 1.5×) and feed the optional LLM lineage fallback.
214
+
215
+ ## Knowledge base & MCP for AI assistants
216
+
217
+ ```bash
218
+ datagraph context dim_customer # description, owner, columns (+type, pk, profile, where each column comes from),
219
+ # upstream, downstream, relationships, dbt tests, modelling role,
220
+ # risk-if-changed + test plan, and the SQL that builds it
221
+ datagraph wiki -o kb/ # index.md, nodes/*.md (cross-linked), GRAPH_REPORT.md, MODEL.md, llms.txt
222
+ ```
223
+
224
+ `GRAPH_REPORT.md` lists hotspots, high-impact dbt models without tests, ownerless nodes, roots and leaves. Everything is generated
225
+ from the graph, so an assistant explains rather than guesses.
226
+
227
+ **MCP** (Claude Code, Claude Desktop, Cursor — any MCP client), after `pip install "datagraph-core[mcp]"` and one `analyze`/`build`:
228
+
229
+ ```json
230
+ {
231
+ "mcpServers": {
232
+ "datagraph": {
233
+ "command": "python",
234
+ "args": ["-m", "datagraph.cli", "mcp", "--graph", "/path/to/out/datagraph.json"]
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ (`examples/mcp/claude-mcp.json`; for Claude Code put it in `.mcp.json` or run
241
+ `claude mcp add datagraph -- python -m datagraph.cli mcp --graph /path/to/datagraph.json`.) Tools: `impact`, `diff`, `find_nodes`,
242
+ `paths`, `hotspots`, `lineage`, `relationships`, `context`, `model`. The server is stdio-only, read-only over the graph file you pass,
243
+ and never receives connection strings.
244
+
245
+ **Claude Code skill:** copy `skills/datagraph/` to `.claude/skills/datagraph/` (or `~/.claude/skills/`) and ask *"where does
246
+ fact_booking come from?"*, *"how are these tables related?"*, *"what is the dimensional model?"*, *"what breaks if I change dim_customer?"*.
247
+
248
+ ## Impact analysis & the impactgraph companion
249
+
250
+ ```bash
251
+ datagraph impact dbt:customer # a model / table / column / function / task
252
+ datagraph diff --repo . --graph datagraph.json # what my uncommitted change can break
253
+ datagraph paths dbt:customer exposure:revenue_report
254
+ datagraph hotspots
255
+ ```
256
+
257
+ ```
258
+ ⚠ Change Impact Changed: customer Risk: HIGH (score 24.5)
259
+
260
+ ⬢ customer (dbt_model)
261
+ ├── ⬢ dim_customer (dbt_model) via depends_on
262
+ │ └── ⬢ fact_booking (dbt_model) via depends_on
263
+ │ ├── 📊 revenue_report (dashboard) via exposes
264
+ │ └── 📊 customer_dashboard (dashboard) via exposes
265
+ └── ▤ prod.analytics.customer (view) via writes_to
266
+
267
+ Affected: 3 dbt model(s) · 2 dashboard(s) · 2 table(s)
268
+ Notify (owners of affected artifacts): finance: revenue_report · growth: customer_dashboard
269
+ Recommended tests:
270
+ ✓ dbt build --select customer+ dim_customer+ fact_booking+
271
+ ✓ Run a schema/contract check on prod.analytics.fact_booking
272
+ ✓ Manually validate 'revenue_report' after deploy (numbers & filters)
273
+ ```
274
+
275
+ <p align="center">
276
+ <img src="docs/images/impact-demo.png" alt="Interactive blast-radius view" width="900"><br>
277
+ <em><code>datagraph html models/customer.sql</code> — one SQL file → models → tables → dashboards and the Python API, with risk, owners and the test plan.</em>
278
+ </p>
279
+
280
+ The **pull-request product** — `impactgraph check` / `pr`, a GitHub Action that comments the blast radius on every PR, `--fail-on`
281
+ gating — lives in **[impactgraph](https://github.com/sumit-gupta03/impactgraph)**, a thin layer over this engine that re-exports its
282
+ whole API. datagraph = everything data-related; impactgraph = "what breaks if I merge this?".
283
+
284
+ ## Python API
285
+
286
+ ```python
287
+ from datagraph import (ImpactGraph, WarehouseExtractor, DbtExtractor, SqlExtractor, PythonExtractor,
288
+ AirflowExtractor, LambdaExtractor, JsExtractor, OpenLineageExtractor,
289
+ LineageFileExtractor, DataHubExtractor, analyze_impact,
290
+ profile_warehouse, star_schema, propose_from_table, classify_tables,
291
+ context, build_wiki, ExtractorPlugin, register)
292
+
293
+ # 1. build (any combination; a DSN, a file path or an open DB-API connection)
294
+ graph = ImpactGraph()
295
+ graph.merge(WarehouseExtractor("snowflake://...", schemas=["analytics"]).extract())
296
+ graph.merge(DbtExtractor("target/manifest.json", catalog_path="target/catalog.json").extract())
297
+ graph.merge(PythonExtractor("./src").extract())
298
+ graph.link_table_aliases()
299
+
300
+ # 2. lineage & relationships
301
+ graph.lineage("table:analytics.dim_customer") # {'upstream': {...}, 'downstream': {...}}
302
+ from datagraph.analysis.relationships import relationships
303
+ relationships(graph)["table_relationships"] # foreign keys + lineage between tables
304
+
305
+ # 3. profiling, dimensional model, knowledge base
306
+ profile_warehouse("snowflake://...", graph) # stores node.meta["profile"] (sensitive columns masked)
307
+ model = star_schema(graph) # facts, dimensions, bus_matrix, scd, issues
308
+ from datagraph.analysis.modeling import to_markdown, to_mermaid
309
+ print(to_markdown(model)); print(to_mermaid(model))
310
+ propose_from_table(graph, "wide_orders") # star from a flat table
311
+ print(context(graph, "dim_customer")) # compact text pack
312
+ build_wiki(graph, "kb/")
313
+
314
+ # 4. impact
315
+ analysis = analyze_impact(graph, ["dbt:customer"])
316
+ analysis.risk, analysis.owners, analysis.recommended_tests, analysis.trees
317
+
318
+ # 5. your own extractor (BI tool, orchestrator, catalog ...) -> also becomes `datagraph build --mytool X`
319
+ register(ExtractorPlugin(name="mytool", factory=MyToolExtractor, help="...", options={"token": "API token"}))
320
+ # or in your package's pyproject: [project.entry-points."datagraph.extractors"] mytool = "my_pkg:MyToolExtractor"
321
+
322
+ # 6. optional AI (pip install datagraph-core[ai])
323
+ from datagraph.ai import explain_impact, suggest_lineage, apply_suggestions
324
+ print(explain_impact(analysis)) # explains; never changes the graph
325
+ apply_suggestions(graph, suggest_lineage(graph), min_confidence=0.7) # tagged provenance=llm, excludable
326
+ ```
327
+
328
+ ## Optional AI layer and LLM providers
329
+
330
+ The AI layer is optional and never builds the graph: `datagraph explain` narrates an impact analysis, `datagraph enrich` /
331
+ `build --llm-fallback` asks for relationship *suggestions* (schema-validated, must reference existing nodes, tagged `llm`,
332
+ confidence-gated). Three interchangeable providers; pick with `--provider` or `DATAGRAPH_LLM_PROVIDER`, model with `--model` or
333
+ `DATAGRAPH_LLM_MODEL`; credentials always come from the environment / cloud SDK, never from the graph:
334
+
335
+ | Provider | Install | Credentials | Default model | Example |
336
+ |---|---|---|---|---|
337
+ | `anthropic` (default) | `datagraph-core[ai]` | `ANTHROPIC_API_KEY` | `claude-opus-5` | `datagraph explain dbt:customer` |
338
+ | `bedrock` — Amazon Nova, Claude on Bedrock, Llama, Mistral … | `datagraph-core[bedrock]` | standard AWS chain (`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`/`AWS_REGION`, profile, SSO, instance role) | `amazon.nova-pro-v1:0` | `datagraph explain dbt:customer --provider bedrock --model amazon.nova-pro-v1:0` |
339
+ | `openai` — any OpenAI-compatible endpoint (OpenAI, Azure, Ollama, vLLM, Groq …) | nothing extra | `DATAGRAPH_LLM_API_KEY` (+ `DATAGRAPH_LLM_BASE_URL`, e.g. `http://localhost:11434/v1` for Ollama) | `gpt-4o-mini` | `DATAGRAPH_LLM_PROVIDER=openai DATAGRAPH_LLM_BASE_URL=http://localhost:11434/v1 datagraph enrich --model llama3 --dry-run` |
340
+
341
+ ```python
342
+ from datagraph.ai import explain_impact, suggest_lineage, BedrockProvider
343
+ print(explain_impact(analysis, provider="bedrock", model="amazon.nova-pro-v1:0"))
344
+ suggest_lineage(graph, provider=BedrockProvider(model="anthropic.claude-3-5-sonnet-20241022-v2:0", region="us-east-1"))
345
+ ```
346
+
347
+ Tested live on Amazon Bedrock with `amazon.nova-lite-v1:0` (explain + enrich). Bedrock per-model output caps are handled automatically (`DATAGRAPH_LLM_MAX_TOKENS` to override).
348
+
349
+ Everything else — lineage, relationships, profiling, dimensional modelling, wiki, MCP — needs no LLM at all.
350
+
351
+ ## Security
352
+
353
+ - **Deterministic core, no LLM in the loop.** Graph, lineage, profiling and the dimensional model are computed from artifacts; an LLM
354
+ is optional and only *explains* or *suggests* (suggestions are schema-validated, must reference existing nodes, are tagged `llm`
355
+ and gated by confidence). Nothing an LLM returns is executed.
356
+ - **Prompt injection.** Names, descriptions, docs and SQL are data from your repos and warehouses. Every LLM prompt wraps them in
357
+ `<data>` tags with an instruction to never follow instructions found inside; text is stripped of control/bidi characters and
358
+ truncated; wiki/context output and the MCP server instructions carry the same "untrusted text" notice for downstream assistants.
359
+ - **Secrets.** Connection strings are used only to open a connection; they are never written to the graph, the cache or outputs,
360
+ and passwords are redacted wherever a DSN is printed. Prefer environment variables / key-pair / SSO auth from your driver.
361
+ - **Personal data.** Profiling keeps counts but masks sample values (min/max/top values) for sensitive-looking columns;
362
+ `--no-top-values` disables value sampling; `--no-profile` skips data access entirely.
363
+ - **SQL / HTML injection.** Identifiers are quoted and literals escaped in every generated query; HTML reports escape embedded JSON.
364
+ - **MCP server.** stdio-only local process (no network port), read-only over the graph file you pass, accepts no connection strings.
365
+ - **Access.** Use a read-only database role; datagraph only issues `SELECT`s against `information_schema` and the tables you profile.
366
+ - **Plugins** are Python entry points — install only extractor packages you trust (same trust level as any pip package).
367
+
368
+ ## How it compares: Graphify · DataHub · OpenLineage · datagraph
369
+
370
+ | | Graphify | DataHub | OpenLineage | datagraph |
371
+ |---|---|---|---|---|
372
+ | What it is | A skill that turns a folder into a knowledge graph for AI assistants | A deployed metadata platform / catalog | An open standard for emitting lineage events (Marquez as reference server) | A pip library + CLI + MCP for lineage, relationships, profiling, dimensional modelling and impact |
373
+ | Question answered | "Help my AI assistant understand this repo" | "What data exists, who owns it, how is it connected, is it healthy?" | "What did this job read and write at run time?" | "Where does this come from, how is it related, what does it look like, what is the model, what breaks if I change it?" |
374
+ | Inputs | 13 languages via tree-sitter, docs, PDFs, images | 50+ connectors, OpenLineage events | Emitters in Airflow, Spark, dbt, Flink… | warehouse information_schema (FKs, views), dbt manifest + catalog, SQL, Python/JS, git diff, Airflow, Lambda, OpenLineage, DataHub, plugins |
375
+ | Graph built by | AST + Claude for non-code | ingestion connectors | the emitting jobs | deterministic extractors; optional `llm` fallback clearly tagged |
376
+ | Knows application code | yes (structure) | no | no | yes — functions, calls, SQL-in-code, Lambda handlers, Airflow callables |
377
+ | Column-level lineage | no | yes (connectors) | yes (facet) | yes (sqlglot, catalog-aware; imports OL/DataHub column lineage) |
378
+ | Foreign keys / schema relationships | no | yes | no | yes |
379
+ | Data profiling | no | yes (ingestion recipes) | no | yes (light, masked, feeds risk & modelling) |
380
+ | Dimensional modelling | no | no | no | yes (Kimball: facts/dims/bus matrix/SCD/issues, wide-table proposals) |
381
+ | Direction-aware impact + risk + test plan | no | impact view only | no | yes, across code and data (and impactgraph for PRs) |
382
+ | AI assistant integration | skill + MCP | MCP / API | via a backend | skill, MCP, context packs, wiki + llms.txt |
383
+ | Infrastructure | none | platform (DB, search, Kafka) | events need a backend | none — pip, a JSON file; runs in CI |
384
+
385
+ **Positioning:** OpenLineage is the *wire format* lineage travels in; DataHub is the *catalog* it lands in; Graphify is the *repo map*
386
+ for an assistant; datagraph is the *local data engine* that reads your warehouse, dbt and code, and **imports** OpenLineage / DataHub
387
+ rather than competing with them. It is deliberately not a catalog (no search UI, glossary, governance or monitoring).
388
+
389
+ **Known limits:** code languages are Python and JS/TS (regex-based for JS); call edges are name-resolved (tagged *inferred*); column
390
+ lineage needs SQL or a catalog — otherwise a same-name heuristic (tagged *inferred*) or the opt-in `llm` fallback applies; dimensional
391
+ classification is heuristic and always shows its reasons and confidence.
392
+
393
+ ## Node ids, provenance, propagation
394
+
395
+ ```
396
+ table:prod.analytics.customer column:dim_customer.customer_key dbt:dim_customer source:raw.customers
397
+ file:models/customer.sql func:src/api.py::customers_endpoint class:src/models.py::Customer
398
+ exposure:revenue_report job:airflow/load_dim_customer dag:nightly task:nightly/build_dim lambda:GetBookings api:GET /bookings
399
+ ```
400
+
401
+ Every edge carries a provenance — `extracted` (from an artifact), `inferred` (heuristic: name-resolved call, same-name column,
402
+ name-inferred foreign key) or `llm` (accepted suggestion); `--no-inferred` keeps only `extracted`. Edges are typed and each type knows
403
+ which way change flows (`contains`, `writes_to`, `exposes` forward; `calls`, `imports`, `depends_on` reverse): `impact()` walks forward,
404
+ `upstream()` backward, `lineage()` both.
405
+
406
+ ## Development
407
+
408
+ ```bash
409
+ git clone https://github.com/sumit-gupta03/datagraph && cd datagraph
410
+ pip install -e ".[dev]"
411
+ pytest # 140 tests, offline, ~20 s — includes dbt's real jaffle_shop project as a fixture
412
+ ```
413
+
414
+ Docs: `docs/datagraph-documentation.pdf` (how it was built, A to Z) and `docs/datagraph-learning-guide.pdf` (graphs and lineage from
415
+ zero). Tagging `vX.Y.Z` builds wheels, creates a GitHub Release and publishes `datagraph-core` to PyPI via trusted publishing
416
+ (`.github/workflows/publish.yml`).
417
+
418
+ ## Roadmap
419
+
420
+ - Plugin packages for Looker / Tableau / Power BI / Dagster / Prefect / Kafka (the `datagraph.extractors` entry point is ready)
421
+ - Tree-sitter parsers for Java / Scala / Go (today: Python via ast, JS/TS via regex)
422
+ - Data-quality rule suggestions from profiles + model (uniqueness of keys, referential integrity, freshness SLAs)
423
+ - Incremental per-file rebuilds (today `--update` skips unchanged inputs)
424
+
425
+ ## License
426
+
427
+ MIT