
Create Pbi Report
- 58 installs
- 836 repo stars
- Updated July 29, 2026
- data-goblin/power-bi-agentic-development
Create complete Power BI reports from scratch with the pbir CLI, covering page layout, theme setup, visual placement, field binding, and publishing.
About
A step-by-step workflow for scaffolding a full Power BI report from scratch using the pbir CLI, from model discovery through page layout, visuals, formatting, and validation. A developer uses it to build a new dashboard or executive report end to end.
- Scaffolds reports with pbir CLI (uv tool install pbir-cli)
- Covers layout, theme, visual binding, filtering, and publishing
Create Pbi Report by the numbers
- 58 all-time installs (skills.sh)
- Ranked #903 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/data-goblin/power-bi-agentic-development --skill create-pbi-reportAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 58 |
|---|---|
| repo stars | ★ 836 |
| Last updated | July 29, 2026 |
| Repository | data-goblin/power-bi-agentic-development ↗ |
What it does
Create complete Power BI reports from scratch with the pbir CLI, covering page layout, theme setup, visual placement, field binding, and publishing.
Files
Creating Power BI Reports
Create and scaffold Power BI reports using pbir CLI. Install with uv tool install pbir-cli or pip install pbir-cli. Load the pbir-cli and pbi-report-design skills alongside this one.
Vague or Underspecified Prompts
When the user's request lacks specific measures, audience context, structural preferences, or formatting direction (e.g., "make me a dashboard", "create something with KPIs"), consult `references/vague-prompts.md` before proceeding. Close the gap between intent and specification with targeted questions; then apply sensible defaults (sqlbi theme, executive dashboard pattern, model-driven KPI selection) for anything the user can't or won't specify.
Rules
- Visuals must not overlap one another
- Favor theme changes over visual overrides for static formatting
- Favor extension measures with theme colors (like "bad") for conditional formatting
- Always create reports inside a named project folder (e.g.,
sales-dashboard/Sales.Report) - Run
pbir validateafter every mutation - New reports already include the sqlbi theme -- do NOT run
pbir theme apply-templateunless the user explicitly asks for a different theme - New reports already include a default Page 1 with a textbox visual for the page title at position (20,20) with height 90 -- do NOT add a new textbox; rename the existing page with
pbir pages renameinstead. Place all visuals at y:120 or below to avoid overlapping the title textbox.
Quick Reference
1. Get the workspace and semantic model from the user. If the user wants to connect to Power BI Desktop or create a report with source data, explain that a published semantic model in Fabric or Power BI is required first. 2. Analyze the user's requirements. Consider missing information -- charts, filters, formatting, analyses. Use AskUserQuestion if something is unclear. 3. Assemble a design brief (audience, purpose, decision questions, page list with per-page intent, committed design identity, delivery target); get user approval before building; see references/design-brief.md. 4. Consider missing semantic model objects -- not just what the user asks for, but targets (1 year prior), baselines (avg for period), or trend aggregations (14-day rolling) that enrich visuals. 5. Create a project folder and report (default format is PBIP):
mkdir -p /path/to/report-name
cd /path/to/report-name
pbir new report "Name.Report" -c "Workspace/Model.SemanticModel"6. Rename the default page (do NOT add a new page unless the report needs multiple pages): pbir pages rename "Name.Report/Page 1.Page" "Overview" 7. Only if the user requests a custom theme: pbir theme apply-template "Name.Report" template-name (the sqlbi theme is already included by default) 8. Discover model fields: pbir model "Name.Report" -d 9. Query field values for filters or formatting: pbir model "Name.Report" -q "EVALUATE VALUES('Table'[Column])" 10. Inspect field data types: pbir model "Name.Report" -d -t Table 11. Add visuals (the page already has a textbox for the title): pbir add visual kpi "Name.Report/Overview.Page" --title "Revenue" 12. Configure query reduction (slicers + heavy visuals): see references/interactivity.md 13. Wire cross-filter overrides and page navigation: see references/interactivity.md 14. Add filters and slicers; configure slicer sync and reset: see references/interactivity.md 15. Validate: pbir validate "Name.Report" 16. Publish: pbir publish "Name.Report" "Workspace.Workspace/Name.Report" 17. Open in Fabric after publish: pbir publish "Name.Report" "Workspace.Workspace/Name.Report" -o 18. Or open locally in Power BI Desktop: pbir open "Name.Report"
Step-by-Step Process
Step 1: Understand the Business Process
Before creating visuals, explore the semantic model to understand the domain. Use pbir model "Report.Report" -d to inspect tables, columns, measures, and hierarchies. Consider:
- What domain does this model cover? (sales, finance, operations, logistics, etc.)
- What KPIs and measures matter most?
- What dimensions and hierarchies exist for slicing data?
- What time granularity makes sense? (daily, weekly, monthly, quarterly)
Present a concrete proposal via AskUserQuestion before building anything. The proposal should include:
- Which KPI cards to show and what measures they display
- What trend chart(s) to include and at what time granularity
- Which categorical breakdowns are most insightful
- What detail table/matrix to provide and with what hierarchies
- How filters should scope the data
Iterate on the design before executing -- revising a plan is cheaper than rebuilding visuals.
Step 1b: Assemble and Lock the Design Brief
Consolidate the Step 1 exploration and any vague-prompt findings into one design brief. This is not a second round of requirements gathering; it freezes what is already known into a single spec the build steps execute against. The brief names the audience, the purpose, the 2-5 decision questions a viewer must answer, a page list where each page carries one stated intent, the committed design identity (tone plus signature), and the delivery target. See `references/design-brief.md` for the copy-able template and how to fill each field.
Present the brief once via AskUserQuestion for explicit "yes" or "change X" approval. On approval, treat it as frozen: the build steps run against it without re-litigating scope, and any later scope change re-opens the brief rather than silently drifting the visuals.
The approved brief routes to the `pbi-report-design` skill (which owns the design canon: commit the identity there, and map each page intent to a concrete layout), then into the build steps below. Reference identity and page-intent-to-layout by concept; pbi-report-design is the home for that reasoning, so do not restate it here.
Step 2: Identify Location and Connection
Determine where to create the report and which model it connects to. Purpose, audience, and decision questions are already settled in the locked brief (Step 1b); do not re-elicit them here.
pbir model # List all known reports/models
pbir connect MyWorkspace MyReport # Set active connectionIf the user provides a workspace location, create the report locally in a project folder, then publish.
Step 3: Create the Report
Create a project folder first, then the report inside it. Default format is PBIP.
mkdir -p sales-dashboard && cd sales-dashboard
pbir new report "Sales.Report" -c "MyWorkspace/Sales.SemanticModel"The resulting structure:
sales-dashboard/
Sales.Report/
definition/
pages/
report.json
StaticResources/
definition.pbir
Sales.pbipStep 4: Rename Default Page and Add More Pages
The report comes with a default "Page 1" that already has a textbox for the page title. Rename it rather than creating a new page. Only add additional pages if needed.
pbir pages rename "Sales.Report/Page 1.Page" "Overview" # Rename default page
pbir add page "Sales.Report/Detail.Page" -n "Detail" # Add extra pages only if needed
pbir pages active-page "Sales.Report" "Overview"Step 5: Configure Theme (only if user requests)
The sqlbi theme is already included by default. Only modify the theme if the user explicitly asks for a different theme or custom colors.
# Only if user wants a different theme:
pbir theme apply-template "Sales.Report" custom-theme
# Or to customize specific colors:
pbir theme set-colors "Sales.Report" --good "#00B050" --bad "#FF0000"
pbir theme set-text-classes "Sales.Report" title --font-size 16
pbir theme set-formatting "Sales.Report" "card.*.border.radius" --value 8Step 6: Add Visuals to Pages
Check actual page dimensions first -- do not assume 1280x720. Use pbir pages json "Report.Report/Page.Page" to verify. The object model validates that visuals fit within page bounds.
Fill the canvas with a purposeful visual hierarchy. Standard composition for a 1280x720 page:
- Row 1 (y: 20-160): KPI visuals -- 2-3
kpivisuals showing headline metrics with targets and trend lines - Row 2 (y: 180-460): Trend + Breakdown -- Line/area chart (~60% width) + bar/column chart (~40% width)
- Row 3 (y: 480-700): Detail table/matrix -- Full-width
tableExormatrixwith hierarchies and conditional formatting
For a complete layout example with exact coordinates, spacing verification, and visual commands, consult `references/layout-example.md`.
Key principles:
- Consistent spacing: Calculate positions from
(margin, gap, page_width, page_height). For 1280x720 with margin=24, gap=16, usable width = 1232. Verify arithmetic before placing visuals. - No redundant titles: Page title = subject ("Order Lines"), visual titles = differentiator ("by Key Account", "Monthly Trend"). Hide subtitles:
pbir visuals subtitle "path" --no-show - Sorting: Charts auto-sort descending by first measure. After
pbir visuals bind, set sort explicitly:pbir visuals sort "path" -f "Table.Measure" -d Descending
For reports where users pick which measure or dimension to view, use field parameters to collapse N near-duplicate visuals into one. See `references/interactivity.md` (Field Parameters section).
Step 7: Configure Query Reduction
For any report with slicers or a busy page (matrices, maps, high-cardinality tables), apply query reduction at creation -- not after. Retrofitting leaves stale interaction pairs and the page may already have unintended cross-filtering wired in.
The three components (see `references/interactivity.md` for full detail):
1. Add NoFilter visualInteractions pairs from each slicer to heavy visuals 2. Enable the filter-pane Apply button: pbir filters pane-set 3. Enable per-slicer Apply buttons: pbir visuals format on each slicer
For Import-mode reports with cheap queries, evaluate whether disabling cross-highlight is worth the loss of interactivity before applying.
Step 8: Wire Interactions and Navigation
After placing visuals, set cross-filter overrides and build navigation. Default is everything cross-filters everything, so author only the exceptions. For multi-page reports, add a pageNavigator visual rather than individual buttons.
See `references/interactivity.md` (Wiring Interactions and Navigation section) for the step-by-step and pitfalls.
Step 9: Add Filters and Slicers
pbir add filter Date Year -r "Sales.Report" --values 2025
pbir add filter Geography Region -r "Sales.Report"
pbir add filter Products Category -p "Sales.Report/Detail.Page"For slicer type selection, sync groups, and reset/persist filter patterns, see `references/interactivity.md` (Slicer Type, Sync, and Reset section).
Step 10: Format Visuals
Most formatting should come from the theme (Step 5). Apply bespoke formatting only for genuinely one-off cases.
# Bulk formatting via glob (requires -f for glob patterns)
pbir set "Sales.Report/**/*.Visual.title.show" --value true -f
pbir set "Sales.Report/**/*.Visual.border.show" --value true -f
# Individual visual formatting
pbir visuals title "Sales.Report/Overview.Page/Revenue.Visual" --fontSize 14 --bold
pbir visuals background "Sales.Report/Overview.Page/Revenue.Visual" --color "#F8F9FA"For titles that react to slicer selections or change color with status, use a _Report extension measure:
# Author a selection-aware title measure
pbir dax measures add \
-n "Title_Sales" \
-e 'IF(ISFILTERED(Region[Region]), "Sales: " & SELECTEDVALUE(Region[Region], "multiple regions"), "Sales: all regions")' \
-t _Report
# Bind via title CF, or drive a textbox text run with the measureKey rules for dynamic titles:
SELECTEDVALUE(..., "<fallback>")is mandatory; without it the title disappears under multi-select- Keep the text measure and color measure separate (one returns the string, one returns a theme token like "good"/"bad"); each is independently testable
- A measure-driven title and a literal title cannot coexist; clear the literal first
- Test across no/single/multi selection by reasoning about
ISFILTERED/HASONEVALUE, then confirm via render
Step 11: Validate
pbir validate "Sales.Report"
pbir tree "Sales.Report" -vStep 12: Publish or Open
pbir publish "Sales.Report" "MyWorkspace.Workspace/Sales.Report" # Publish
pbir publish "Sales.Report" "MyWorkspace.Workspace/Sales.Report" -o # Publish and open in browser
pbir open "Sales.Report" # Open in Power BI DesktopCommon Report Patterns
Executive Dashboard
- 2-3 KPI cards at top (revenue, orders, margin)
- 1 trend line/area chart (monthly if yearly filter, daily/weekly if monthly)
- 1-2 breakdown charts (bar/column) by key categories
- 1 detail table or matrix with hierarchies and conditional formatting
- Page size: 1280x720 (16:9)
Detailed Analysis
- Slicer bar at top (date range, category filters)
- Large table or matrix as main content with conditional formatting
- Supporting KPI cards for context
- Page size: 1280x720 or 1920x1080
Tooltip Pages
- Small page (320x240 or similar)
- 2-3 focused visuals
- Set via
pbir pages type "path" --type tooltip
Reference Files
- `references/vague-prompts.md` -- Handling underspecified prompts: targeted questions, sensible defaults, propose-before-building workflow
- `references/design-brief.md` -- Locked design-brief template: decision questions, per-page intent, committed design identity (tone plus signature), delivery target, approval gate, routing to pbi-report-design
- `references/layout-example.md` -- Complete layout with coordinates, spacing verification, time granularity guidance
- `references/interactivity.md` -- Query reduction, cross-filter wiring, navigation, slicer type/sync/reset, field parameters
- `references/limitations.md` -- Agent limitations to communicate to users
The Design Brief: Lock and Hand Off
A design brief is one approved spec the flow emits and freezes before any pbir mutation. It does not re-elicit requirements; it consolidates what AskUserQuestion and references/vague-prompts.md already surfaced into a single reviewable object, then becomes the contract every build step executes against.
Think of the brief as a thin lock-and-handoff layer sitting on top of the requirements gathering this skill already does. Revising the brief is cheap; rebuilding bound visuals is not. So the brief exists to catch scope and identity decisions while they are still words, not visuals.
When to assemble the brief
After Step 1 (Understand the Business Process) and after any vague-prompt questioning from references/vague-prompts.md. By this point the audience, purpose, candidate measures, and any style direction are already on the table. The brief writes them down, fills the remaining fields, and presents the whole thing once for approval.
The brief template
Fill this single block, then present it for approval. Keep every field concrete; if a field is still a guess, mark it and flag the guess to the user.
audience: who reads this and what they already know
purpose: the one outcome this report exists to drive
decision_questions: # 2 to 5; the questions a viewer answers at a glance
- are we ahead of last year and where
- which accounts are dragging margin
- what changed since last week
pages: # one job per page
- name: Overview
intent: show whether we are on track this period and flag what is off
serves: [are we ahead of last year and where, what changed since last week]
- name: Margin Detail
intent: locate where margin is leaking by account and product
serves: [which accounts are dragging margin]
design_identity: # committed once here; propagates to every visual
tone: quiet analytical # the feeling and restraint stance
signature: # the few repeated, recognizable choices
accent: single accent reserved for the focus measure
kpi: value over target, variance shown as a small inline figure
titles: subject on the page, differentiator on the visual
spacing: equal gaps and margins arithmetically derived
delivery_target: # where and how it is consumed
surface: Fabric workspace app
page_size: 1280x720
mobile: not requiredHow to fill each field
Pull most of this straight from answers already collected; do not start a fresh interview.
audience and purpose
Lift these from the Step 1 exploration and the vague-prompt answers. Audience sets the detail level (a board wants summary, an analyst wants granularity). Purpose is the single outcome, stated in one line.
decision_questions
This operationalizes the existing "what decisions does this report support" prompt into a written, checkable list. Name 2 to 5 concrete questions a viewer should answer at a glance. Every page and visual must trace back to at least one; if a visual serves no decision question, it is decoration and gets cut. These questions also drive measure and chart choice downstream.
pages and page intent
Give each page one sentence naming the single job it does and which decision question(s) it serves. One job per page; this is what prevents a page that is just "more charts." Do not resolve layout here. How an intent maps to a concrete layout (the detail gradient, the 3-30-300 reasoning, visual count, spacing) is owned by the pbi-report-design skill. Route the page intent there when building.
design_identity (tone plus signature)
Commit the design identity once, in the brief, so it propagates to every visual instead of being decided ad hoc per chart.
- tone is the overall feeling and restraint stance; for example quiet-analytical versus high-contrast-executive
- signature is the small set of repeated, recognizable choices that make the report look deliberate: where the accent color is allowed, how KPIs are treated, the title pattern, the spacing rhythm
Set these by routing to the pbi-report-design skill for the identity concept. That skill owns the design canon (encoding hierarchy, color discipline, chart vocabulary, layout). Reference it by concept; do not restate the canon here.
delivery_target
Capture where and how the report is consumed before sizing any page: a Fabric workspace app, an embedded surface, a desktop review, or mobile. The surface constrains page size, the slicer-versus-filter-pane choice, and whether a mobile layout subset is needed. These are all cheaper to decide before building than after.
The approval gate (lock)
Present the assembled brief as text, then confirm it with a single AskUserQuestion carrying the decision only (approve, or name the field to change); its options stay short, the brief itself is the text above them. On approval, treat the brief as frozen.
Frozen means the build steps execute against it without re-litigating scope. If the user later changes scope, do not silently drift the visuals; re-open the brief, amend it, and re-confirm the changed fields. Re-opening the brief is the cheap path; rebuilding bound visuals is the expensive one. This is the same propose-before-building principle the skill already follows, made into an explicit lock.
Routing: what the approved brief hands off to
The approved brief is the handoff payload between the plan phase and the build phase. It flows:
locked brief
-> pbi-report-design # commit identity; map each page intent to a layout
-> build steps (this SKILL.md)
create report -> pages -> visuals -> bind -> format -> validate -> publishThe build steps already exist in SKILL.md and are not rewritten by the brief. The brief simply tells them what to build: which pages, each page's job, which decision questions each visual must answer, and the committed identity every visual inherits.
Interactivity: Slicers, Interactions, Field Parameters, and Filter Persistence
Query Reduction at Creation
The "Query reduction" preset bundles three settings that collapse unnecessary visual queries. Apply at report creation; retrofitting leaves stale interaction pairs.
The three components set directly in PBIR:
- Cross-interaction default: add
NoFilterpairs inpage.jsonvisualInteractions[]from each slicer to heavy visuals (matrices, maps, high-cardinality tables). There is no single report-wide off key; write per-pair overrides. - Filter-pane Apply button: set via
pbir filters pane-set; validate with--qaafter. - Slicer Apply button: set per-slicer via
pbir visuals format. TheslicerandadvancedSlicerVisualobject models differ; confirm the container key withpbir schema describefirst.
Microsoft's optimization guidance shows these three changes cutting a page's visual queries by a large factor, which is why the "fewer visuals / apply buttons" audit rules exist.
Pitfalls:
- A hard-coded
Highlightpair invisualInteractions[]survives the preset; audit per page after applying - Apply buttons are per-slicer/per-pane; five slicers need five configurations unless you also add page-level Apply-all/Clear-all button visuals
- Disabling cross-highlight is a visible design tradeoff (selecting a bar no longer dims others); flag this on Import-mode reports where query cost is already cheap
Wiring Interactions and Navigation
After placing and formatting visuals, set interaction overrides and build navigation before final validation. A page of correctly bound visuals still ships poorly if every selection cross-filters everything or if a multi-page report has no way to move between pages.
1. Decide the cross-filter graph per page before touching JSON. Default is everything cross-filters everything, so author only the exceptions: KPI cards that should stay stable when a detail chart is clicked; charts that should not filter a slicer back. 2. Write overrides as page-level visualInteractions entries ({source, target, type}) using the visual name, not the title. Use Highlight/Filter only when overriding a default (charts default to Highlight, line/scatter/map to Filter). 3. For multi-page reports, prefer a native pageNavigator visual over hand-built buttons. One navigator auto-syncs to the page list; N buttons are N blobs to re-point on every page add or rename. 4. Validate, then reload+screenshot to confirm a slicer click filters the intended visuals and leaves the cards alone.
# Example: set KPI card to NoFilter from bar chart clicks
pbir visuals interactions "Sales.Report/Overview.Page" \
--source "Bar Chart.Visual" --target "Revenue KPI.Visual" --type NoFilter
# Add a page navigator
pbir add visual pageNavigator "Sales.Report/Overview.Page" \
--x 24 --y 680 --width 400 --height 32Pitfalls:
visualInteractionspairs are directional (sourcefilterstarget, not the reverse)- Stale pairs referencing a renamed or regenerated visual
namesilently no-op; they do not error during validate - Override exceptions, keep the default elsewhere; do not over-suppress interactivity
Slicer Type, Sync, and Reset
Type and single-select
Map slicer intent to type and mode:
low cardinality, single pick -> slicer (data.mode=Dropdown) or advancedSlicerVisual with singleSelect
measure beside each option -> listSlicer (Values: Column/Hierarchy; Tooltips: Measure)
date window -> slicer (data.mode=Between) or relative-date modeForce single-select where the analysis assumes one value:
pbir set <page>/<slicer> 'visual.objects.selection[0].properties.singleSelect' true
pbir set <page>/<slicer> 'visual.objects.selection[0].properties.strictSingleSelect' true # removes clear-to-allDefault to strictSingleSelect for metric-swap slicers (field parameter pickers) and single-entity slicers. Multi-select on those is the most common silent break.
Sync groups
Sync is not a slicer property; it lives in report.json as a sync group keyed by name. A slicer joins a group by sharing the name. Two independent toggles:
- sync filter state: selection follows the reader page to page
- sync visibility: whether the slicer is drawn on each page
The common pattern is sync-state everywhere, show-on-one-page. After hand-editing sync groups, validate and reload (a silent group-name typo de-syncs with no error). Sync supports one field per slicer only; a two-field slicer opts out.
Reset and persist filters
Power BI has no native reset button; build it from a bookmark:
1. Set every slicer/filter to its intended default state 2. Capture a Data-scoped (not Display) bookmark: pbir bookmark add "Default View" 3. Bind a button to it via pbir visuals action
Use the same bookmark as the page launch bookmark so the report opens at the baseline regardless of persisted state.
The "Don't allow end users to save filters" report setting turns off per-reader persistence. Select it for shared/kiosk reports that must open clean; leave persistence on for personal analytical reports. Persistence-on plus a launch bookmark conflict; decide one model per report.
Pitfalls:
- A Display-scoped reset bookmark moves/shows/hides visuals unexpectedly; always use Data scope for filter resets
- The reset button only restores what the bookmark captured; re-capture when slicers change
- Sync group names must match exactly; a trailing space de-syncs silently
Field Parameters
A field parameter is a calculated table in the model whose rows each name a column or measure (NAMEOF) plus a sort order. Bind the table's value column to a visual drop zone and to a single-select slicer; readers pick which measure or dimension renders without bookmarks or visual stacking. It collapses N near-duplicate visuals into one.
The table is model work (define exactly three columns per row, all values unique, or the parameter produces unexpected results). In PBIR the parameter participates like any column:
# Add the chart bound to the parameter
pbir add visual barChart "Sales.Report/Overview.Page" \
--title "by Metric" \
-d "Category:Product.Category" \
-d "Y:Metric.Metric Fields" \
--x 24 --y 120 --width 600 --height 360
# Add the slicer to pick the metric
pbir add visual slicer "Sales.Report/Overview.Page" \
-d "Values:Metric.Metric" \
--x 24 --y 72 --width 200 --height 40
# Force single-select so the report never opens showing every measure at once
pbir set "Sales.Report/Overview.Page/<slicer-name>.Visual" \
'visual.objects.selection[0].properties.singleSelect' true
# Validate that the parameter field binding resolves
pbir validate "Sales.Report" --fieldsPBIR-side pitfalls
These are the parts that break after the model is correct:
- Blank/"none" selection means ALL, not nothing: there is no empty state; use strict single-select plus a default selection so the report never opens showing every measure collapsed together
- Top N filters break on the parameter: they rank alphabetically by display name, not by the measure value. Fix: author a helper measure reading the active row via
SELECTEDVALUEover the parameter's hidden column +SWITCH, then apply Top N on that helper - CF does not follow the swap: conditional formatting binds to a concrete field. Drive CF from the same
SELECTEDVALUE+SWITCHhelper measure - Implicit measures: an explicit measure must exist first; no implicit aggregation is created for the parameter column
- Drillthrough/tooltip link fields: not usable as drillthrough or tooltip link fields; link the underlying dimensions instead
- Live connection models: field parameters require a local model; a pure live connection cannot host one
- Matrix "Persist hierarchy level": turn this report setting off; otherwise the hierarchy level collapses on every parameter switch
Validate and render
Always validate with --fields after binding a field parameter; mismatched Column vs Measure types pass JSON validation but fail at query time.
Layout Example and Time Granularity
Executive Dashboard Layout (1280x720, margin=24, gap=16)
# Page title textbox
pbir add visual textbox "Sales.Report/Overview.Page" \
--x 24 --y 16 --width 1232 --height 56
# KPI visuals with targets and trend lines (y=88, h=160)
# 3 KPIs: each w=400, gaps: 24 + 400 + 16 + 400 + 16 + 400 + 24 = 1280
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 88 --width 400 --height 160
pbir add visual kpi "Sales.Report/Overview.Page" --title "Order Lines" \
-d "Indicator:Orders.Order Lines" -d "Goal:Orders.Order Lines 1YP" \
-d "TrendLine:Date.Calendar Month (ie Jan)" \
--x 440 --y 88 --width 400 --height 160
pbir add visual kpi "Sales.Report/Overview.Page" --title "Margin %" \
-d "Indicator:Invoices.Selling Margin (%)" -d "Goal:Invoices.Selling Margin (%) 1YP" \
-d "TrendLine:Date.Calendar Month (ie Jan)" \
--x 856 --y 88 --width 400 --height 160
# Trend chart (left, y=264, h=220)
pbir add visual lineChart "Sales.Report/Overview.Page" --title "Monthly Trend" \
--x 24 --y 264 --width 608 --height 220
pbir visuals bind "Sales.Report/Overview.Page/Monthly Trend.Visual" \
-a "Category:Date.Calendar Month (ie Jan)" -a "Y:Invoices.Turnover"
# Breakdown chart (right, y=264, h=220)
pbir add visual barChart "Sales.Report/Overview.Page" --title "by Region" \
-d "Category:Regions.Territory" -d "Y:Invoices.Turnover" \
--x 648 --y 264 --width 608 --height 220
# Detail table (full width, y=500, h=196)
pbir add visual tableEx "Sales.Report/Overview.Page" --title "Detail by Account" \
--x 24 --y 500 --width 1232 --height 196
pbir visuals bind "Sales.Report/Overview.Page/Detail by Account.Visual" \
-a "Values:Customers.Key Account Name" -a "Values:Products.Product Name" \
-a "Values:Invoices.Turnover" -a "Values:Orders.Order Lines"Spacing Verification
Title bottom: 16+56 = 72. Gap to KPIs: 88-72 = 16 [ok]
KPI bottom: 88+160 = 248. Gap to charts: 264-248 = 16 [ok]
Chart bottom: 264+220= 484. Gap to table: 500-484 = 16 [ok]
Table bottom: 500+196= 696. Bottom margin: 720-696 = 24 [ok]
Left margin: 24. Right edge: 24+1232=1256. Right margin: 1280-1256 = 24 [ok]KPI Targets
Use prior-year measures as targets when available. If none exist, add the measure to the semantic model via Tabular Editor or by editing the TMDL files directly:
# In the relevant table's .tmdl file, add:
measure 'Measure 1YP' = CALCULATE([Measure], DATEADD('Date'[Date], -1, YEAR))If no clear target exists, ask the user via AskUserQuestion.
Inferring Time Granularity from Filter Context
When adding trend visuals, infer the appropriate time axis from active filters:
Year (e.g. 2021): Monthly # Date.Calendar Month (ie Jan) or Date.Calendar Month Year (ie Jan 21)
Quarter: Monthly or Weekly # Date.Calendar Month or Date.Calendar Week EU (ie WK25)
Month: Daily or Weekly # Date.Date or Date.Calendar Week EU (ie WK25)
No date filter: Monthly or Quarterly # Date.Calendar Month Year or Date.Calendar Quarter YearIf unsure, default to monthly granularity -- it works well for most business reporting contexts.
Title Hierarchy
Distribute meaning across the title hierarchy to avoid redundancy:
- Page title (textbox): The subject/metric (e.g., "Order Lines")
- Visual titles: Additional context that differentiates the visual (e.g., "by Key Account", "Monthly Trend", "Detail by Account")
- Subtitles: Almost always redundant -- hide by default when
--titleis set
Bad: Page title "Order Lines by Key Account" + visual title "Order Lines by Key Account" + subtitle "Order Lines by Key Account Name" -- says the same thing three times.
Good: Page title "Order Lines" + visual titles "by Key Account", "Monthly Trend", "On-Time Delivery" -- each adds unique information.
Hide subtitles explicitly:
pbir visuals subtitle "Report.Report/Page.Page/Visual.Visual" --no-showHide axis titles when the axis label is self-evident (e.g., month names on x-axis don't need a "Month" axis title). Hide category labels on cards when the visual title already describes the metric.
Limitations of agents using pbir-cli
You should inform users of your limitations:
- Connecting to Power BI Desktop; you only work with Power BI report metadata
- Working on report.json or layout json files (legacy format) - users must open their reports and save them with the enhanced report metadata (PBIR). PBIP format is recommended but not necessary.
- Adding new custom visuals from AppSource without their ID. Offer instead to create something with your
svg-visual,Deneb-visual,r-visual, orpython-visualskills - Creating very detailed, bespoke visualizations with the core visuals
Handling Vague or Underspecified Prompts
Users naturally describe reports in vague, subjective terms; "make me a nice dashboard" or "create something with KPIs and charts." This is expected. Natural language is how people think about dataviz, and the gap between intent and specification is the whole reason agents are useful.
But vague prompts produce generic reports. A dashboard built from "make it look good" will look like every other default Power BI report; it won't answer the questions the user actually cares about or reflect the decisions they need to make. The agent's job is to close that gap before building anything.
When to use this reference
Route here when the user's prompt lacks two or more of:
- Specific measures or KPIs to show
- A target audience or decision context ("for the CFO", "for weekly ops review")
- Structural preferences (page count, visual types, layout)
- Formatting direction (colors, style, brand)
Prompts like "create a sales dashboard", "build me a report with some KPIs", or "make a fancy executive dashboard" all qualify.
What to do
1. Acknowledge and reframe
Do not lecture the user or refuse to work. Instead, explain briefly that a few specifics will dramatically improve the result, then ask targeted questions. Frame it as collaboration, not gatekeeping.
Example:
"I can build this; a few details will make it much better. What decisions should this report help someone make? And which 2-3 numbers matter most?"
2. Ask the minimum viable questions
Do not overwhelm with a long questionnaire. Three questions are enough to start:
1. What decisions does this report support? This reveals the audience, the KPIs that matter, and the appropriate level of detail. "Weekly ops review" implies trend lines and variance; "board presentation" implies summary KPIs and minimal detail. 2. Which 2-3 measures matter most? If the user can't name them, explore the semantic model together with pbir model "Report.Report" -d and propose candidates. 3. Any style or brand preferences? Colors, fonts, existing reports to match. If none, state that the sqlbi theme will be applied as a professional default.
If the user still deflects ("just make it look good"), proceed with sensible defaults (below) but flag that the result is a starting point to iterate on; not a finished product.
3. Apply sensible defaults
When specifics are missing, fall back to these rather than guessing:
Theme:
default: sqlbi (already applied to new reports)
reason: professional colors and typography out of the box
Layout:
default: executive dashboard pattern (KPI row, trend chart, breakdown, detail table)
reason: most broadly useful; follows 3-30-300
Page size:
default: 1280x720
reason: standard 16:9
KPI selection:
default: top measures by business importance from the model
reason: explore with `pbir model -d`; propose before building
Time granularity:
default: monthly if yearly filter context; weekly/daily if monthly
reason: match the grain to the decision cadence
Conditional formatting:
default: gap/variance columns only; theme sentiment colors ("good"/"bad")
reason: formatting everything means formatting nothing4. Propose before building
Always present a concrete proposal via AskUserQuestion before executing. The proposal should be specific enough that the user can say "yes" or "change X." Include:
- Which KPI cards and what measures they display
- What chart types and what dimensions they break down
- What detail table or matrix columns to include
- How filters should scope the data
- The theme and color approach
Revising a plan is cheap; rebuilding visuals is expensive.
What not to do
- Do not refuse to work because the prompt is vague
- Do not generate a 10-question interview; three targeted questions are enough
- Do not build a generic report and call it done; iterate toward specifics
- Do not assume the user's reluctance means they don't care; they likely care but don't know how to articulate it in report-design terms