Pbir report workflow
Skill wardawgmalvicious/claude-config/skills/pbir-report-workflow
Personal Claude Code config — skills, subagents, hooks, and rules for Microsoft Fabric and Power BI workflows on Windows. Cherry-pickable, no semver.
npx -y skills add wardawgmalvicious/claude-config --skill pbir-report-workflowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when scaffolding or building a new Power BI report end-to-end from a published semantic model using the pbir CLI. Covers the 10-step workflow — KPI / filter / granularity requirements, model field discovery via pbir model, pbir new report scaffold, renaming the default Page 1 instead of adding a new one, 3-30-300 visual hierarchy for three viewing distances (glance / scan / investigate), layout math with margin/gap constants (always inspect the scaffolded page first), row-by-row visual placement with explicit coordinates, explicit sort after bind, report vs page filters, extension-measure conditional formatting with theme tokens like good/bad, time-granularity inference from the active date filter, pbir validate + publish. Invoke when user says 'build a report', 'scaffold a dashboard', or 'lay out a KPI page'.
SKILL.md
12.6 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it
PBIR Report Workflow
End-to-end workflow for building Power BI reports from a published semantic model using pbir CLI. Requires the model to already exist in a Fabric/Power BI workspace.
Workflow Steps
- Gather requirements (KPIs, filters, granularity, audience)
- Discover model fields and data types
- Create project folder + scaffold report
- Rename default page (do not add a new one)
- Measure the scaffold (existing visuals, theme, canvas size) before computing layout
- Plan layout arithmetic from the measured scaffold
- Add visuals row-by-row with explicit coordinates
- Bind fields and set sort direction explicitly
- Add report-level and page-level filters
- Apply bespoke formatting only when theme is insufficient
- Validate, then publish
Rules
- Visuals must NOT overlap
- Favor theme changes over per-visual overrides
- Favor extension measures (
_Fmt) with theme tokens (good/bad) for conditional formatting - Always create reports inside a named project folder
- Run
pbir validateafter every mutation - Use PascalCase for project / report / page / visual names
- Edit PBIR JSON directly via Claude Code or
pbir set— do NOT use Tabular Editor - Do NOT add
PBI_*annotations manually
Step 1 — Requirements & Model Discovery
pbir model # List reports + models
pbir model "Sales.Report" -d # Model definition
pbir model "Sales.Report" -d -t Sales # Filter to table
pbir model "Sales.Report" -q "EVALUATE VALUES('Date'[Year])" # Query for filter values
Ask the user (via AskUserQuestion) to confirm:
- Which KPIs to surface (measures + targets)
- Trend granularity (daily / weekly / monthly / quarterly)
- Categorical breakdowns
- Detail table/matrix hierarchies
- Report-level vs page-level filters
Step 2 — Scaffold Report
mkdir -p SalesDashboard && cd SalesDashboard
pbir new report "Sales.Report" -c "MyWorkspace/Sales.SemanticModel"
pbir pages rename "Sales.Report/Page 1.Page" "Overview"
pbir pages active-page "Sales.Report" "Overview"
Resulting layout:
SalesDashboard/
Sales.pbip
Sales.Report/
definition.pbir
definition/
version.json
report.json
pages/
pages.json
Overview/
page.json
visuals/Title.Visual/visual.json
StaticResources/
Step 3 — Measure the Scaffold Before Laying Out
pbir new report produces a default page with some combination of a pre-placed title textbox, a baked-in theme, and canvas defaults. Exact coordinates, theme name, and visual positions depend on the CLI version and the chosen --from-template. Before planning anything, read the actual scaffold instead of assuming:
pbir cat "Sales.Report/Overview.Page" # Full page.json (width, height, displayOption)
pbir ls "Sales.Report/Overview.Page" # Existing visuals on the page
pbir tree "Sales.Report" -v # Every visual + bindings
pbir cat "Sales.Report/theme" # Active theme name + palette
From the output, record:
- Canvas
width/heightfrompage.json(often1280 x 720but templates may override). - Every existing visual's
position.x,position.y,position.width,position.height. For bulk reads usejq '.position' <path>/visual.jsonacross thevisuals/folder. - The tallest
y + heightamong existing visuals — the first safeyfor a new row you add. - Active base and custom theme names — so you don't accidentally re-apply a default over meaningful styling.
All subsequent coordinates should be derived from those measured values, not hardcoded from this doc.
Step 4 — Layout Math (3-30-300)
Every layout starts from four constants: (page_width, page_height, margin, gap).
Example (1280 x 720 canvas with margin=24, gap=16):
usable_width = page_width - (2 * margin) = 1232
usable_height = page_height - (2 * margin) = 672
3 equal columns = (usable_width - 2*gap) / 3 = 400
2 equal columns = (usable_width - gap) / 2 = 608
Substitute your measured page_width / page_height — do not hardcode 1280/720.
3-30-300 visual hierarchy — design for three viewing distances:
| Distance | View | Payload |
|---|---|---|
| 3 seconds | Glance | Headline KPIs + target delta |
| 30 seconds | Scan | Trend direction + top-1 breakdown |
| 300 seconds | Investigate | Detail table with hierarchies + conditional formatting |
Standard 3-row composition — compute each row from the measured scaffold:
| Row | Content |
|---|---|
| Top region | Existing title / header visuals already in the scaffold |
| Row 1 | 3 KPI visuals side-by-side |
| Row 2 | Line chart + bar chart (2 columns) |
| Row 3 | Full-width tableEx detail |
Row heights, the gap between rows, and y offsets all come from the measured scaffold plus your chosen margin / gap. Verify the total fits inside page_height before placing any visual.
Step 5 — Add Visuals (Coordinates Explicit)
The coordinates below are illustrative — computed from a measured 1280x720 scaffold with a ~90 px header region, margin=24, gap=16. Substitute values from your actual measurement before running these commands.
# Row 1: KPIs
pbir add visual kpi "Sales.Report/Overview.Page" --title "Revenue" \
-d "Indicator:Invoices.Turnover" -d "Goal:Invoices.Turnover 1YP" \
-d "TrendLine:Date.Calendar Month (ie Jan)" \
--x 24 --y 120 --width 400 --height 140
pbir add visual kpi "Sales.Report/Overview.Page" --title "OrderLines" \
-d "Indicator:Orders.Order Lines" -d "Goal:Orders.Order Lines 1YP" \
--x 440 --y 120 --width 400 --height 140
pbir add visual kpi "Sales.Report/Overview.Page" --title "MarginPct" \
-d "Indicator:Invoices.Selling Margin (%)" -d "Goal:Invoices.Selling Margin (%) 1YP" \
--x 856 --y 120 --width 400 --height 140
# Row 2: Trend + Breakdown
pbir add visual lineChart "Sales.Report/Overview.Page" --title "MonthlyTrend" \
--x 24 --y 276 --width 608 --height 208
pbir visuals bind "Sales.Report/Overview.Page/MonthlyTrend.Visual" \
-a "Category:Date.Calendar Month (ie Jan)" -a "Y:Invoices.Turnover"
pbir add visual barChart "Sales.Report/Overview.Page" --title "ByRegion" \
-d "Category:Regions.Territory" -d "Y:Invoices.Turnover" \
--x 648 --y 276 --width 608 --height 208
# Row 3: Detail
pbir add visual tableEx "Sales.Report/Overview.Page" --title "DetailByAccount" \
--x 24 --y 500 --width 1232 --height 196
pbir visuals bind "Sales.Report/Overview.Page/DetailByAccount.Visual" \
-a "Values:Customers.Key Account Name" -a "Values:Invoices.Turnover" -a "Values:Orders.Order Lines"
Step 6 — Spacing Sanity-Check
After placing visuals, verify the arithmetic yourself:
left_margin + usable_width + right_margin == page_width
top_region + Σ(row_heights) + (n-1) * gap + bottom_margin == page_height
If either equation fails, adjust before saving. pbir tree "Sales.Report" -v lists every visual's position in one command.
Step 7 — Sort, Filters, Theme Overrides
# Charts auto-sort descending by first measure. Set explicitly after bind.
pbir visuals sort "Sales.Report/Overview.Page/ByRegion.Visual" \
-f "Invoices.Turnover" -d Descending
# Report-level filters (apply to all pages)
pbir add filter Date Year -r "Sales.Report" --values 2025
pbir add filter Geography Region -r "Sales.Report"
# Page-level filters
pbir add filter Products Category -p "Sales.Report/Overview.Page"
Step 8 — Title Hierarchy
Distribute meaning across the title hierarchy — never say the same thing twice.
| Level | Content |
|---|---|
| Page title (textbox) | The subject — "OrderLines" |
| Visual titles | The differentiator — "byKeyAccount", "MonthlyTrend" |
| Subtitles | Hide — almost always redundant |
pbir visuals subtitle "Sales.Report/Overview.Page/MonthlyTrend.Visual" --no-show
Hide axis titles when the axis is self-evident (month names on x-axis). Hide category labels on cards when the visual title describes the metric.
Step 9 — Conditional Formatting via Extension Measures
Prefer extension measures returning theme tokens ("good", "bad") over hex strings so the theme can be rebranded centrally.
pbir dax measures add "Sales.Report" -t _Fmt -n "RevenueStatusColor" \
-e 'IF([Turnover] >= [Turnover 1YP], "good", "bad")' --data-type Text
pbir visuals cf "Sales.Report/Overview.Page/ByRegion.Visual" \
--measure "dataPoint.fill _Fmt.RevenueStatusColor"
Step 10 — Inferring Time Granularity from Filter Context
| Active Filter | Trend Granularity | Date Column |
|---|---|---|
| Year (e.g., 2025) | Monthly | Date.Calendar Month (ie Jan) |
| Quarter | Monthly or Weekly | Date.Calendar Month (ie Jan) / Date.Calendar Week EU |
| Month | Daily or Weekly | Date.Date / Date.Calendar Week EU |
| No date filter | Monthly or Quarterly | Date.Calendar Month Year / Date.Calendar Quarter Year |
Default to monthly when unsure.
Step 11 — Validate, Publish, Open
pbir validate "Sales.Report"
pbir tree "Sales.Report" -v
pbir publish "Sales.Report" "MyWorkspace.Workspace/Sales.Report" -o # Publish + open
pbir open "Sales.Report" # Local in Desktop
Common Page Sizes
| Type | Width x Height | Use Case |
|---|---|---|
| Default (16:9) | 1280 x 720 | Screen dashboards |
| Large (16:9) | 1920 x 1080 | High-density executive dashboards |
| Letter portrait | 816 x 1056 | Print/PDF reports |
| Tooltip | 320 x 240 | Hover tooltip pages |
| Custom tall | 1280 x 2400 | Scrollable operational pages |
KPI Target Measures
Use prior-year measures as targets when available. Add via TMDL if missing:
measure 'Turnover 1YP' = CALCULATE([Turnover], DATEADD('Date'[Date], -1, YEAR))
Gotchas
| Issue | Cause | Fix |
|---|---|---|
| Visual overlaps existing scaffold element | Placed y before measuring scaffold | Run pbir ls + inspect position of every pre-existing visual first |
| Extra blank page on report open | pbir add page called instead of rename | pbir pages rename "Page 1.Page" "Overview" |
| Charts show wrong sort order | Default auto-sort not set after bind | pbir visuals sort -f ... -d Descending |
| Theme overridden by visual formatting | Inline formatting applied | pbir visuals clear-formatting --only-containers -f |
| Publish 401 | Wrong Fabric token audience | az account get-access-token --resource https://api.fabric.microsoft.com |
| Page doesn't fit canvas | displayOption set to integer | Must be string: "FitToPage" etc. |
| Extension measure CF not rendering | references.measures missing a dep | Every measure used in DAX must appear in references.measures |
| Trend chart has wrong granularity | Granularity not matched to filter | Consult granularity table |
| Right margin looks off | Layout math not verified | Print spacing verification (left + usable + right = width) |
Reference
- Microsoft Learn: Power BI reports overview
- Microsoft Learn: Tips for designing a great Power BI report
- Microsoft Learn: Design reports for accessibility
- Comprehensive MS Learn link bundle (design principles / layout / field discovery / filters / CF / publish / time-granularity): references/REFERENCE.md
See also
pbip-project-structure— project file layoutpbir-cli— CLI command referencepbir-pages— page JSON structurefabric-tmdl— TMDL measure authoring
What ships with it: 1 file
5.5 KB alongside SKILL.md
references/
- REFERENCE.md5.5 KB