| name | pbi-report-generator |
| description | Use when the operator wants to generate a complete Power BI report file as code — model tables, DAX measures, and report visuals — without opening Power BI Desktop. Covers both .pbit output (pbi-tools PbixProj compile, Desktop-free) and .pbip output (Desktop-native PBIR-Legacy + TMDL). Triggers include "generate a pbit", "generate a pbip", "power bi report as code", "compile a power bi file", "create a report file from my star schema", "pbit for databricks importBI", and the Portuguese variants "gerar pbit", "gerar pbip", "relatório power bi como código", "criar arquivo power bi por código". |
| license | MIT |
| metadata | {"author":"Gus Bavia","version":"0.1.2","category":"business-intelligence","tags":["power-bi","pbit","pbip","pbi-tools","pbixproj","tmdl","report-as-code","semantic-model","dax","databricks-importbi"],"companions":["pbi-aibi-migrator","pbi-lifecycle","pbi-theme","pbi-model-audit","pbi-model-doc"],"support":"https://linkedin.com/in/gusbavia"} |
Power BI Report Generator (as code) · v0.1.2
Generate a complete, working Power BI report file — semantic model (tables, columns, relationships, measures) AND report page (visuals) — entirely from code. No Power BI Desktop required to author. Two output routes:
| Route | Output | Toolchain | Best for |
|---|
| A — PBIT | .pbit (template, metadata-only) | PbixProj source → pbi-tools compile | Desktop-free pipelines, Databricks AI/BI /importBI, distributing templates, CI builds |
| B — PBIP | .pbip folder (PBIR-Legacy + TMDL) | Direct file generation | Ongoing development in Power BI Desktop, git-per-file diffs, integration with the pbi-lifecycle folder suite |
Generic positioning · MANDATORY
This skill ships to any Power BI practitioner. Do not use the operator's personal context, memory, or session history to invent defaults. All examples stay neutral (Client A, My Report, dim_customer). If the operator volunteers specifics, use them for that run only.
The questionnaire · ALWAYS the first action
Never start generating from assumptions. Collect the spec first (use AskUserQuestion when available, otherwise a numbered prompt). Ask only what the invocation didn't already answer:
- Format — PBIT (route A) or PBIP (route B)? If unsure, offer the table above.
- Model — tables with columns + data types (
int64, string, double, dateTime, boolean, decimal). Sources accepted: the operator types them; OR points to an existing schema (SQL DDL, a warehouse DESCRIBE, a CSV header, a measures.dax file). One table may be marked as the date table (which column is the date key?).
- Relationships — fact→dim pairs (from-column / to-column); flag inactive ones.
- Measures — name + DAX + format string, per home table. Accept an existing
.dax file and let the operator pick a subset.
- Report page(s) — for each visual: type (
card, clusteredBarChart, clusteredColumnChart, lineChart, pieChart, tableEx, slicer, textbox), fields (which column/measure in which role), and rough position (the skill defaults to a clean 1280×720 grid if the operator says "you lay it out").
- Output folder + project name.
- Theme (optional) — a theme.json to embed, or default.
Echo the collected spec back as a compact table and get a "go" before writing files.
Route A · PBIT via pbi-tools
REQUIRED READING: references/pbixproj-pbit.md (the PbixProj source format — what pbi-tools compile actually reads; it is NOT Desktop's PBIP/PBIR).
- Ensure
pbi-tools Core is available: pbi-tools.core.exe info. If missing, download the pbi-tools.core.<ver>_win-x64.zip self-contained release from github.com/pbi-tools/pbi-tools (no Desktop, no .NET SDK needed).
- Adapt
scripts/author_pbixproj.py — edit its TABLES / RELATIONSHIPS / visuals spec to the questionnaire answers, set the output folder. Run it → emits the full PbixProj source.
- Compile:
pbi-tools.core.exe compile <src-folder> <out>.pbit PBIT true (positional args, not flags).
- Validate — the
.pbit is a zip: extract, parse DataModelSchema (UTF-16 LE) and confirm tables/relationships/measures/partition mode; parse Report/Layout and confirm sections + visuals. Report the counts to the operator.
Route B · PBIP (PBIR-Legacy + TMDL)
REQUIRED READING: references/pbip-tmdl.md (folder anatomy, TMDL table syntax, locked recipe rules).
- Generate the PBIP tree:
<Name>.pbip + Report/ (.platform, definition.pbir, report.json at root, StaticResources/) + SemanticModel/ (.platform, definition.pbism, definition/*.tmdl including one tables/<Table>.tmdl per table with columns, partition, and measures).
- Honor every locked rule in the reference — the expensive ones: UTF-8 without BOM everywhere,
__PBI_TimeIntelligenceEnabled = 0, compatibilityLevel 1600, report.json at Report/ root (PBIR-Legacy, not modular), theme name ≤ 16 chars, MAX_PATH 256 headroom.
- Validate — JSON-parse every JSON artifact, BOM-sweep every file, path-budget check, then tell the operator to open the
.pbip in Desktop and load data.
Visual layout JSON (both routes)
REQUIRED READING: references/visual-layout.md — the classic Layout visualContainer config (singleVisual, projections, prototypeQuery, queryRef) used verbatim by route A's Report/sections/ files and route B's report.json sections.
Quick reference
| Task | Where |
|---|
| PbixProj source anatomy + compile gotchas | references/pbixproj-pbit.md |
| PBIP/TMDL anatomy + locked recipe | references/pbip-tmdl.md |
| Visual config JSON patterns (card, bar, line, table…) | references/visual-layout.md |
| Working PBIT generator to adapt | scripts/author_pbixproj.py |
Common mistakes
| Mistake | Fix |
|---|
Omitting DiagramLayout.json or leaving QueriesSettings empty (route A) | PBIT compiles but Desktop rejects it ("corrupted or unrecognized version", MashupValidationError). Both are REQUIRED — see references/pbixproj-pbit.md required-parts table. Verified 2026-06-12. |
Authoring Desktop PBIP/PBIR source and feeding it to pbi-tools compile | compile reads PbixProj (pbi-tools' own layout). Route A only. |
Measures inline in table.json (route A) | Measures live in measures/<Name>.dax + <Name>.xml; columns each in columns/<col>.json. |
| Table partition missing (route A) | Partition M comes from Model/queries/<table>.m — matched by filename. |
| M queries that need credentials | Use a typed empty #table partition — schema-complete, refresh-safe, credential-free. |
| BOM in any PBIP file (route B) | Power BI Desktop fails silently. Write UTF-8 without BOM. |
Lowercase theme enums ("left") | Must be CamelCase ("Left"); Power BI silently rejects the theme. |
| Forgetting the date table marking | Date table: dataCategory: "Time" (route A table.json) / dataCategory: Time (TMDL) + isKey: true on the date column. |
| Inventing visual types | Stick to the catalog in references/visual-layout.md; unknown types render as errors in Desktop. |
Companions
pbi-aibi-migrator (takes the compiled .pbit into Databricks AI/BI — the import workflow lives there, not here), pbi-lifecycle (folder bootstrap, git, env promotion — its Phase 2 scaffolds an empty PBIP; this skill generates a full report), pbi-theme (theme JSON generation), pbi-model-audit / pbi-model-doc (post-generation quality).