data-source-connector
Skill1 starsChanged 6 months agoMITView on GitHub
Source-agnostic adapter that introspects any data storage (SQL databases, cloud warehouses, Excel/CSV files, OData/REST APIs, SharePoint lists) and emits a normalized data-model.json describing tables, columns, types, and relationships. Use this skill at the start of the dashboard pipeline whenever the user has not provided a structured data model. It also emits a clarification question list when schema cannot be auto-discovered, and produces the source-specific M-Code / import block consumed by semantic-mapper.
In this repository8 other files it gives its agents.
- bi-dash-creatorSkill
- nlq-dashboard-orchestratorSkill
- project-packagerSkill
- query-to-pbipSkill
- semantic-mapperSkill
- theme-brandingSkill
- visual-generatorSkill
- visual-selectorSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 119
If schema cannot be fully discovered (missing credentials, ambiguous grain, no FK constraints), emit openQuestions[] for the orchestrator …
- Very specific: line 137
Run scripts/introspect_source.py (or the source-specific adapter) to:
- Distinctive: line 143
If the source supports FK constraints (SQL databases) → use them directly
- Very specific: line 158
If unsure, add to openQuestions[] and ask the user at Gate A.
- Distinctive: line 255
Every table has at least one column
- Very specific: line 256
Every relationship references existing {table, column} on both sides
- Very specific: line 257
Every column has both dataType and sourceProviderType
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Data Source Connector
Universal data-source adapter for the Power BI dashboard pipeline. This skill abstracts away the specifics of every supported source and produces a single, normalized artifact — data-model.json — that downstream skills (semantic-mapper, visual-selector, visual-generator) can consume without knowing where the data actually came from.
When to Use This Skill
- The orchestrator (or the user) has identified a source but no structured data model exists
- The agent needs to enumerate tables, columns, types, and relationships from any backend
- A Genie YAML metric view is not available (use this skill instead of
semantic-mapper's YAML path) - The agent needs the source-specific M-Code / connection block to embed in TMDL partitions
Supported Sources
| Source Type | type value | Required Inputs |
| Databricks | databricks | hostname, warehouse_id, catalog, schema |
| Snowflake | snowflake | account, warehouse, database, schema, role |
| BigQuery | bigquery | project, dataset |
| Azure Synapse | synapse | server, database |
| SQL Server | sqlserver | server, database |
| PostgreSQL | postgres | host, port, database, schema |
| MySQL | mysql | host, port, database |
| Oracle | oracle | host, port, service_name |
| Excel | excel | path (.xlsx file); each sheet becomes a table |
| CSV | csv | path or directory of CSVs; each file becomes a table |
| Parquet | parquet | path or directory |
| OData | odata | service_url |
| REST API | rest | base_url, endpoints[], auth |
| SharePoint Lists | sharepoint | site_url, list_names[] |
Inputs
- Source descriptor —
{ type, ...connection params }from the orchestrator or the user - Scope hint (optional) — which tables / sheets / endpoints to include (defaults to all)
- Sampling preference (optional) — number of sample rows to capture per table (default 5)
Outputs
Primary: data-model.json
Source-agnostic, normalized representation. Schema:
{
"source": {
"type": "excel",
"connection": { "path": "C:/data/sales.xlsx" },
"discoveredAt": "2026-05-13T11:00:00Z"
},
"tables": [
{
"name": "fact_sales",
"physicalName": "Orders",
"role": "fact",
"grain": "one row per order line",
"rowCountEstimate": 50000,
"columns": [
{
"name": "order_id",
"physicalName": "OrderID",
"dataType": "int64",
"sourceProviderType": "bigint",
"isPrimaryKey": true,
"nullable": false
},
{
"name": "customer_key",
"physicalName": "CustomerID",
"dataType": "int64",
"sourceProviderType": "bigint",
"isForeignKey": true,
"foreignKey": { "table": "dim_customer", "column": "customer_key" }
},
{
"name": "total_value",
"physicalName": "TotalValue",
"dataType": "double",
"sourceProviderType": "double",
"formatHint": "currency"
}
],
"sampleRows": [
{ "order_id": 1, "customer_key": 42, "total_value": 199.99 }
]
}
],
"relationships": [
{
"from": { "table": "fact_sales", "column": "customer_key" },
"to": { "table": "dim_customer", "column": "customer_key" },
"cardinality": "many-to-one",
"isActive": true,
"inferredFrom": "naming convention"
}
],
"mCodeAdapter": {
"mode": "import",
"templates": {
"fact_sales": "let Source = Excel.Workbook(File.Contents(\"C:/data/sales.xlsx\"), null, true), Orders_Sheet = Source{[Item=\"Orders\",Kind=\"Sheet\"]}[Data], #\"Promoted Headers\" = Table.PromoteHeaders(Orders_Sheet, [PromoteAllScalars=true]) in #\"Promoted Headers\""
}
},
"openQuestions": [
{
"id": "q1",
"scope": "relationship",
"question": "Is the relationship between fact_sales.customer_key and dim_customer.customer_key correct? It was inferred from column-name similarity, not from a foreign key constraint."
}
]
}Secondary: Clarification report
If schema cannot be fully discovered (missing credentials, ambiguous grain, no FK constraints), emit openQuestions[] for the orchestrator to surface to the user.
Workflow
Step 1: Validate Connection Inputs
For each source type, check that required inputs are present. If any are missing, emit a clarification question and stop.
Examples:
databricksmissingwarehouse_id→ ask: "What is the Databricks SQL warehouse ID?"excelmissingpath→ ask: "What is the full path to the Excel file?"sqlservermissing credentials → ask: "Is this a trusted-connection database, or do I need a username and password?"
See references/clarification-questions.md for the full question bank.
Step 2: Probe the Source
Run scripts/introspect_source.py (or the source-specific adapter) to:
- List tables / sheets / endpoints
- For each table: list columns with native types, nullability, primary key flags
- Sample rows: pull 5 sample rows per table (configurable)
- Foreign key discovery:
- If the source supports FK constraints (SQL databases) → use them directly
- Otherwise → infer from column-name patterns (
<table>_key,<table>_id, identical names across tables) and flag asinferredFrom: naming conventionfor user confirmation at Gate A
Step 3: Classify Tables (Fact vs. Dimension)
Heuristics:
| Signal | Likely Role |
| Has multiple FK columns + a numeric measure column | fact |
Name contains fact_, sales, orders, transactions, events | fact |
Name contains dim_, customers, products, dates, geography | dimension |
| Only one PK column + descriptive columns | dimension |
| Has a date column with daily continuity | date dimension |
If unsure, add to openQuestions[] and ask the user at Gate A.
Step 4: Normalize Types
Map source-native types to TMDL types (consumed by semantic-mapper):
| Source Type | dataType | sourceProviderType |
STRING, VARCHAR, NVARCHAR, TEXT | string | nvarchar(65535) |
INT, INTEGER, INT32 | int64 | int |
BIGINT, LONG | int64 | bigint |
DOUBLE, FLOAT, REAL, DECIMAL, NUMERIC | double | double |
DATE | dateTime | date |
DATETIME, TIMESTAMP, DATETIME2 | dateTime | datetime2 |
BOOLEAN, BIT | boolean | bit |
For Excel/CSV with no declared types, sniff from sample rows.
Step 5: Generate the M-Code Adapter Block
Each source has a different M-Code template. Per-source templates live in references/connection-patterns.md. Examples:
Databricks (DirectQuery):
let
Source = DatabricksMultiCloud.Catalogs("<hostname>", "/sql/1.0/warehouses/<warehouse_id>", [Catalog = "", Database = ""]),
<catalog>_Database = Source{[Name="<catalog>",Kind="Database"]}[Data],
<schema>_Schema = <catalog>_Database{[Name="<schema>",Kind="Schema"]}[Data],
<table>_Table = <schema>_Schema{[Name="<table>",Kind="Table"]}[Data]
in
<table>_TableExcel (Import):
let
Source = Excel.Workbook(File.Contents("<path>"), null, true),
<sheet>_Sheet = Source{[Item="<sheet>",Kind="Sheet"]}[Data],
#"Promoted Headers" = Table.PromoteHeaders(<sheet>_Sheet, [PromoteAllScalars=true])
in
#"Promoted Headers"CSV (Import):
let
Source = Csv.Document(File.Contents("<path>"), [Delimiter=",", Columns=<n>, Encoding=65001, QuoteStyle=QuoteStyle.Csv]),
#"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true])
in
#"Promoted Headers"SQL Server (DirectQuery):
let
Source = Sql.Database("<server>", "<database>"),
<schema>_<table> = Source{[Schema="<schema>",Item="<table>"]}[Data]
in
<schema>_<table>The connector emits one M-Code block per table into data-model.json → mCodeAdapter.templates.
Step 6: Mode Selection
Set mCodeAdapter.mode based on source:
| Source | Mode |
| Databricks, Snowflake, BigQuery, Synapse, SQL Server (large), Oracle | directQuery |
| Excel, CSV, Parquet, SharePoint List, REST API | import |
| Postgres, MySQL | directQuery if user opts in, otherwise import |
Step 7: Emit openQuestions
Append a question for every uncertainty:
- Ambiguous fact/dimension classification
- Inferred (not declared) foreign keys
- Multiple date columns (which is the primary date?)
- Tables with no measurable columns (skip or include?)
- Files with multiple sheets where some look like junk (e.g., metadata, instructions)
Outputs Handed to Downstream
| File | Consumer | Purpose |
data-model.json | semantic-mapper, visual-selector, nlq-dashboard-orchestrator | Normalized model |
data-model.json.openQuestions[] | nlq-dashboard-orchestrator (Gate A) | Drive clarification dialog |
data-model.json.mCodeAdapter | semantic-mapper | TMDL partition source blocks |
Validation Checklist
- Every table has at least one column
- Every relationship references existing
{table, column}on both sides - Every column has both
dataTypeandsourceProviderType - Exactly zero or one date-dimension table is flagged as
role: "date dimension"per date role - At least one table is classified as
fact mCodeAdapter.templateshas one entry per table intables[]openQuestionsis empty OR every entry has a uniqueidand a non-emptyquestion
Error Handling
| Error | Resolution |
| Cannot reach source | Surface error verbatim; ask user for corrected connection params |
| Authentication failed | Ask user for credentials; never store them in data-model.json |
| Empty schema (no tables found) | Stop and ask the user to verify scope |
| Table with zero columns | Skip and log a warning |
| Source type unsupported | Ask user to convert to a supported source (e.g., export DB query to CSV) |
Resources
scripts/introspect_source.py— Main connector entry point; routes to source-specific adaptersreferences/connection-patterns.md— Per-source connection recipes and M-Code templatesreferences/clarification-questions.md— Standard question bank for missing/ambiguous inputsreferences/data-model-schema.md— Full JSON schema fordata-model.json
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

