Project Packager
Scaffold, assemble, validate, and zip a Power BI Desktop Project (PBIP). This skill takes the TMDL files from the semantic mapper and the report files from the visual generator and packages them into a complete PBIP directory structure that can be opened in Power BI Desktop.
When to Use This Skill
- Assembling TMDL and report files into a PBIP directory structure
- Creating pointer files (.pbip, .pbism, .pbir) and .platform files with correct cross-references
- Validating that all required PBIP files exist and references are consistent
- Zipping a PBIP project for distribution
- Packaging artifacts as part of the query-to-pbip pipeline (Stage 4)
Inputs
- TMDL files — From Stage 1 (database.tmdl, model.tmdl, relationships.tmdl, tables/*.tmdl)
- Report files — From Stage 3 (visual.json files, one per visual)
- Project name — Used for directory and pointer file naming
Outputs
- Complete PBIP directory structure on disk
- Zipped PBIP archive (
.zip) ready for distribution
PBIP Directory Structure
The official Microsoft PBIP format (with TMDL semantic model and PBIR report format):
<ProjectName>/
├── <ProjectName>.pbip # Project entry point
├── .gitignore # Excludes local settings and cache
├── <ProjectName>.SemanticModel/
│ ├── .platform # Fabric Git integration (type: SemanticModel)
│ ├── definition.pbism # Semantic model pointer (version 4.2 for TMDL)
│ ├── diagramLayout.json # Model diagram layout (optional)
│ ├── .pbi/
│ │ └── editorSettings.json # Editor configuration
│ └── definition/
│ ├── database.tmdl # Database name + compatibility level
│ ├── model.tmdl # Model configuration
│ ├── relationships.tmdl # Table relationships
│ ├── cultures/
│ │ └── en-US.tmdl # Culture/locale definition
│ └── tables/
│ ├── fact_sales.tmdl
│ ├── dim_customer.tmdl
│ └── ...
└── <ProjectName>.Report/
├── .platform # Fabric Git integration (type: Report)
├── definition.pbir # Report pointer (version 4.0, references SemanticModel)
├── StaticResources/
│ └── SharedResources/
│ └── BaseThemes/
│ └── CY25SU11.json # Default Power BI theme
└── definition/
├── report.json # Report-level configuration (schema 3.1.0)
├── version.json # Report format version metadata
└── pages/
├── pages.json # Page ordering and active page
└── <pageId>/ # 20-char hex page identifier
├── page.json # Page definition (schema 2.0.0)
└── visuals/
├── <visualId>/ # 20-char hex visual identifier
│ └── visual.json # Visual definition (schema 2.5.0)
└── <visualId>/
└── visual.json
Packaging Workflow
Step 1: Create Directory Structure
Create the full directory hierarchy. Use scripts/scaffold_pbip.py from the query-to-pbip skill:
python scaffold_pbip.py <ProjectName> --output <output-dir>
This generates all directories, pointer files, .platform files, and stub report files.
Step 2: Generate Pointer Files
<ProjectName>.pbip — Project entry point:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/pbip/pbipProperties/1.0.0/schema.json",
"version": "1.0",
"artifacts": [
{
"report": {
"path": "<ProjectName>.Report"
}
}
],
"settings": {
"enableAutoRecovery": true
}
}
definition.pbism — Semantic model pointer (in <ProjectName>.SemanticModel/):
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/semanticModel/definitionProperties/1.0.0/schema.json",
"version": "4.2",
"settings": {}
}
Version 4.2 indicates the semantic model definition is stored as TMDL in the definition/ folder.
definition.pbir — Report pointer (in <ProjectName>.Report/):
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byPath": {
"path": "../<ProjectName>.SemanticModel"
}
}
}
Version 4.0 indicates the report definition is stored in PBIR format in the definition/ folder.
Step 3: Generate .platform Files
Each item folder (SemanticModel and Report) requires a .platform file for Fabric Git integration:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/gitIntegration/platformProperties/2.0.0/schema.json",
"metadata": {
"type": "SemanticModel",
"displayName": "<ProjectName>"
},
"config": {
"version": "2.0",
"logicalId": "<generated-guid>"
}
}
The type field is "SemanticModel" or "Report" depending on the folder. The logicalId is a unique GUID.
Step 4: Generate Report Definition Files
definition/report.json — Report configuration:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/report/3.1.0/schema.json",
"themeCollection": {
"baseTheme": {
"name": "CY25SU11",
"reportVersionAtImport": {
"visual": "2.4.0",
"report": "3.0.0",
"page": "2.3.0"
},
"type": "SharedResources"
}
},
"resourcePackages": [
{
"name": "SharedResources",
"type": "SharedResources",
"items": [
{
"name": "CY25SU11",
"path": "BaseThemes/CY25SU11.json",
"type": "BaseTheme"
}
]
}
],
"settings": {
"useStylableVisualContainerHeader": true,
"exportDataMode": "AllowSummarized",
"defaultDrillFilterOtherVisuals": true,
"allowChangeFilterTypes": true,
"useEnhancedTooltips": true,
"useDefaultAggregateDisplayName": true
}
}
definition/version.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/versionMetadata/1.0.0/schema.json",
"version": "2.0.0"
}
definition/pages/pages.json — Page ordering:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/pagesMetadata/1.0.0/schema.json",
"pageOrder": ["<pageId>"],
"activePageName": "<pageId>"
}
Step 5: Place Artifact Files
Copy files from previous pipeline stages into the correct locations:
| Source | Destination |
|---|---|
database.tmdl |
<ProjectName>.SemanticModel/definition/database.tmdl |
model.tmdl |
<ProjectName>.SemanticModel/definition/model.tmdl |
relationships.tmdl |
<ProjectName>.SemanticModel/definition/relationships.tmdl |
tables/*.tmdl |
<ProjectName>.SemanticModel/definition/tables/ |
visual.json (per visual) |
<ProjectName>.Report/definition/pages/<pageId>/visuals/<visualId>/visual.json |
Step 6: Validate the Structure
Run validation to ensure project integrity:
python package_pbip.py <ProjectDir> --validate-only
Validation checks:
- File existence —
.pbip,.pbism,.pbir,database.tmdl,model.tmdlall exist - Pointer consistency —
.pbirreferences the correct.SemanticModelpath - PBISM version — Must be
4.xfor TMDL format - Platform files —
.platformexists in both SemanticModel and Report - Report definition —
definition/report.jsonanddefinition/version.jsonexist - Pages —
pages.jsonexists, at least one page directory withpage.json - Visuals — Each visual directory contains
visual.json - Table files — At least one
.tmdlfile intables/
Step 7: Create Zip Archive
Package the validated project into a zip archive:
python package_pbip.py <ProjectDir> --output <ProjectName>.zip
The zip excludes .pbi/localSettings.json and .pbi/cache.abf (local-only files).
File Format Requirements
| File Type | Encoding | Indentation | Line Endings |
|---|---|---|---|
.tmdl |
UTF-8 (no BOM) | Tab | LF |
.json |
UTF-8 (no BOM) | 2 spaces | LF |
.pbip, .pbism, .pbir, .platform |
UTF-8 (no BOM) | 2 spaces | LF |
Validation Checklist
Before delivering the PBIP:
- Project file exists —
<ProjectName>.pbipis present in root .gitignoreexists — Excludes.pbi/localSettings.jsonand.pbi/cache.abf- Semantic model complete —
.platform,definition.pbism(v4.2),database.tmdl,model.tmdlall exist - Tables present — At least one
.tmdlfile intables/ - Culture defined —
cultures/en-US.tmdlexists - Relationships file exists —
relationships.tmdlis present (even if empty) - Report complete —
.platform,definition.pbir(v4.0),definition/report.json,definition/version.json - Pages configured —
pages.jsonwith at least one page ID, matching page directory withpage.json - Visuals present — At least one
visual.jsonin a visual subdirectory - Pointer paths correct —
.pbir→../<ProjectName>.SemanticModel
Error Handling
| Error | Resolution |
|---|---|
| Missing TMDL files from Stage 1 | Report which files are missing; do not create zip |
| Missing visual.json files from Stage 3 | Report which files are missing; do not create zip |
| Pointer path mismatch | Auto-correct the path based on project name |
| Empty tables directory | Warn but allow packaging (model may have no dimensions) |
| Missing .platform files | Generate them with new GUIDs |
| PBISM version mismatch | Update to version 4.2 for TMDL format |
Opening the PBIP
To use the generated PBIP:
- Extract the zip archive
- Open
<ProjectName>.pbipin Power BI Desktop (June 2023 or later with PBIP preview enabled) - Power BI will load the semantic model and report definition
- If the Databricks connection is configured, visuals will render with live data