Install
$ agentstack add skill-wardawgmalvicious-claude-config-pbip-project-structure ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
PBIP Project Structure
Power BI Project (PBIP) is the text-based developer format for Power BI. Replaces the .pbix binary with a folder of UTF-8 text files (TMDL for semantic models, PBIR JSON for reports).
Folder Layout
/
+-- .pbip # Optional entry point
+-- .gitignore # Auto-generated
+-- .SemanticModel/
| +-- .pbi/
| | +-- localSettings.json # Gitignored
| | +-- cache.abf # Data cache, gitignored
| | +-- unappliedChanges.json # Pending PQ changes
| +-- definition.pbism # SM entry point
| +-- definition/ # TMDL files
| +-- model.bim # TMSL legacy (mutually exclusive)
| +-- diagramLayout.json
| +-- DAXQueries/ # .dax query view tabs
| +-- TMDLScripts/ # .tmdl script view tabs
| +-- .platform # Fabric identity
+-- .Report/
+-- .pbi/localSettings.json # Gitignored
+-- definition.pbir # Report entry point
+-- definition/ # PBIR JSON files
+-- report.json # PBIR-Legacy (legacy alt)
+-- mobileState.json # No external edit
+-- semanticModelDiagramLayout.json # Diagram node positions
+-- CustomVisuals/ # Private .pbiviz metadata
+-- StaticResources/RegisteredResources/ # Themes, images
+-- DAXQueries/ # Report-level .dax files
+-- .platform
Entry-Point Files
| File | Purpose | |---|---| | .pbip | Project entry point. Optional — definition.pbir can be opened directly | | .pbir | Report entry point. Points at semantic model via byPath or byConnection | | .pbism | Semantic model entry point. version: "4.2" for TMDL | | .platform | Fabric identity per item: displayName, type, logicalId | | version.json | Inside definition/ — PBIR schema version ("2.0.0") |
.pbip
{
"version": "1.0",
"artifacts": [{ "report": { "path": "MyReport.Report" } }],
"settings": { "enableAutoRecovery": true }
}
.platform
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/gitIntegration/platformProperties/2.0.0/schema.json",
"metadata": { "type": "Report", "displayName": "MyReport" },
"config": { "version": "2.0", "logicalId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
}
logicalIdis the Fabric identity — never change on an existing deployed item- When forking a project,
logicalIdMUST be regenerated to a new GUID typevalues:Report,SemanticModel
definition.pbir — byPath (Thick Project)
Report + model bundled in same project folder.
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byPath": { "path": "../MyModel.SemanticModel" }
}
}
definition.pbir — byConnection (Thin Report)
Report connects to a remote published semantic model. Preferred for managed/shared BI.
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byConnection": {
"connectionString": "Data Source=powerbi://api.powerbi.com/v1.0/myorg/WorkspaceName;Initial Catalog=ModelName"
}
}
}
For Fabric REST API deployments, use the id form: "connectionString": "semanticmodelid=[SemanticModelId]".
Do NOT use the legacy six-property form (pbiServiceModelId, pbiModelVirtualServerName, etc.) for new reports.
definition.pbism
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/semanticModel/definitionProperties/1.0.0/schema.json",
"version": "4.2",
"settings": {}
}
| version | Supported Format | |---|---| | 1.0 | TMSL only (model.bim) | | 4.0+ | TMSL or TMDL (definition/ folder) |
PBIX vs PBIP
| Aspect | PBIX | PBIP | |---|---|---| | Format | Single binary ZIP | Folder of text files | | Source control | Not diff-friendly | Git-ready | | External editing | Not supported | VS Code, pbir CLI, scripts | | Cached data | Embedded | cache.abf gitignored | | Conversion | File → Save As → PBIP in Desktop | File → Save As → PBIX in Desktop |
PBIX Extraction
A .pbix is a ZIP (OPC) archive. Thick PBIX contains a DataModel binary (opaque ABF); thin PBIX has a Connections file instead. Modern PBIX stores reports in Report/definition/ (PBIR); legacy PBIX uses a monolithic Report/Layout (UTF-16LE).
| PBIX Internal File | Encoding | |---|---| | Version, Settings, Metadata, Report/Layout | UTF-16LE | | Connections, Report/definition/* | UTF-8 | | [Content_Types].xml | UTF-8 with BOM | | DataModel, SecurityBindings | Binary |
import zipfile
with zipfile.ZipFile("MyReport.pbix") as z:
z.extractall("MyReport_extracted")
# Detect type
is_thick = Path("MyReport_extracted/DataModel").exists()
is_modern = Path("MyReport_extracted/Report/definition/report.json").exists()
Assembling a PBIP from an extracted thin PBIX: copy Report/definition/ into .Report/definition/, generate definition.pbir with byConnection, generate .platform with a new logicalId GUID.
Thick PBIX cannot be converted programmatically — the DataModel binary is opaque. Use PBI Desktop File → Save As.
Forking a Project
- Copy the entire project folder, rename the root
- Rename
.Report/and.SemanticModel/subfolders - Update
.pbip→artifacts[].report.path - Update
.pbir→datasetReference.byPath.path(if byPath) - Update each
.platform(Report and SemanticModel separately) → set the appropriatedisplayNameand regenerate a NEW uniquelogicalIdper file (the two.platformfiles get different GUIDs)
Rename Cascade
Renaming a table, measure, or column requires updates in every location that references it. Missing one causes broken visuals or DAX errors.
| Location | What to Update | |---|---| | TMDL table/measure/column declaration | The Name line | | TMDL partition name | Matches table name | | model.tmdl | ref table Name + PBI_QueryOrder annotation | | relationships.tmdl | fromColumn: / toColumn: table prefix | | All DAX expressions | Both Table[ and 'Table'[ forms | | visual.json query projections | SourceRef.Entity, queryRef | | visual.json filter/sort/CF blocks | Nested SourceRef.Entity, From[].Entity | | page.json filterConfig | From[].Entity | | Bookmark JSONs | filter.From[].Entity, expression.*.SourceRef.Entity, highlight.dataMap keys | | SparklineData metadata | Compact string SparklineData(Table.Measure_[...]) | | reportExtensions.json | Top-level entities[].name AND nested references.measures[].entity | | Culture .tmdl linguistic metadata | ConceptualEntity, ConceptualProperty | | semanticModelDiagramLayout.json | nodeIndex | | DAX query files | Both .SemanticModel/DAXQueries/ and .Report/DAXQueries/ |
Commonly missed: sortDefinition blocks, SparklineData compact strings, bookmark highlight.dataMap keys, the second DAX query location, references.measures[].entity nested inside reportExtensions.json.
Git-Friendly Organization
- Set
core.autocrlfor add* text=autoto.gitattributes— PBI Desktop writes CRLF - UTF-8 without BOM for all files — a BOM prefix causes parse errors
- Keep the root path short — 260-char Windows path limit; page/visual GUID folders can exceed it
- Rename PBIR GUID folders (
0c32c81b...) to human names (Overview,lineChart_Sales) for better diffs. Folder names are freely renamable;page.json/visual.jsonfilenames and internalnameproperties must NOT change - Multiple
.Report/and.SemanticModel/folders can coexist in one project - Fabric Git Integration only processes
definition.pbir— other.pbirfiles are ignored but can coexist
Gotchas
| Issue | Cause | Fix | |---|---|---| | Parse error on open | File saved with UTF-8 BOM | Re-save as UTF-8 without BOM | | 260-char path error on Git clone | Deep GUID folder nesting | Shorten root path; rename GUID folders | | PBI Desktop ignores external edits | Stale in-memory state | Close and reopen Desktop | | Broken visual after table rename | Missed cascade location | Grep for old name across .json, .tmdl, .dax (both DAXQueries folders) | | Empty reportExtensions.json crashes Desktop | "entities": [] is invalid | Delete the file instead of leaving empty | | Forked project shows as same Fabric item | logicalId not regenerated | New GUID per .platform on fork | | Thick PBIX cannot be converted to PBIP via script | DataModel binary is opaque | Use File → Save As in PBI Desktop | | Merge conflicts in diagramLayout.json | Auto-generated per user | Treat as binary or add to .gitignore |
Reference
- Microsoft Learn: Power BI Desktop project (PBIP) overview
- Microsoft Learn: Power BI Desktop project — semantic model folder
- Microsoft Learn: Introduction to Fabric Git integration
- Comprehensive MS Learn link bundle (PBIP docs / entry-point file shapes / Direct Lake live editing / Fabric Git / REST envelope / TMDL): [references/REFERENCE.md](references/REFERENCE.md)
See also
pbir-cli— pbir CLI command referencepbir-report-workflow— report creation workflowpbir-pages— page JSON structurefabric-tmdl— TMDL authoring rules
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wardawgmalvicious
- Source: wardawgmalvicious/claude-config
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.