| name | report-implementation |
| description | Use when generating physical PBIR JSON files (pages, visuals) from a report blueprint. Triggers: "implement PBIR", "generate visual JSON", "create page.json", "visual binding", "PBIR template", "implement report from blueprint", "add visual to page", "visual.json structure", "report.json", "pages.json". |
| user-invocable | true |
Skill: Report Implementation (PBIR Visual Generation)
Purpose
Generate the physical Power BI Report (PBIR) files from the report design blueprint (report_blueprint.json) produced in Step 8. This step creates the actual page folders, page.json files, visual folders, and visual.json files inside the PBIP Report definition.
This step must implement the strategy already decided in the blueprint. It must not silently redesign mockup translation decisions or feasibility constraints.
Prerequisites — MANDATORY
Before starting report implementation:
- ✅ Step 8 completed and approved —
<ProjectName>/spec/report_blueprint.json exists on disk.
- ✅ Semantic Model exists —
<ProjectName>/PBIP/<ProjectName>.SemanticModel/definition/ contains valid TMDL files.
- ✅ PBIP Report scaffold exists —
<ProjectName>/PBIP/<ProjectName>.Report/definition/ folder exists (created in Step 00).
- ✅ Empty-canvas report baseline is intact before adding visuals:
definition/report.json uses the current baseline schema and theme resources.
definition/version.json and definition/pages/pages.json exist.
- At least one page folder exists and is referenced by
pages.json.
StaticResources/SharedResources/BaseThemes/ProjectDefault.json exists.
<ProjectName>.Report/report.json at report root does NOT exist.
Input / Output
| |
|---|
| Input | <ProjectName>/spec/report_blueprint.json, all TMDL files (model object registry) |
| Output | PBIR files in <ProjectName>/PBIP/<ProjectName>.Report/definition/pages/ + updated pages/pages.json |
References — MANDATORY
Before generating ANY PBIR JSON:
- READ
.github/skills/report-implementation/references/pbir-visual-templates.md for validated visual JSON templates.
- READ
.github/references/pbip-folder-structure.md for correct folder hierarchy.
- READ
.github/references/pbir-cli-integration.md before using the local pbir CLI for any packaged report operation.
- READ on demand (load only when needed for the specific task):
references/fields-and-bindings.md — Field types (Column/Measure/Extension), data roles by visual type, queryState structure
references/filters.md — Filter types (Categorical, TopN, Advanced, RelativeDate), scope, JSON structure
references/conditional-formatting.md — CF types, container.property mapping, measure-driven patterns
references/extension-measures.md — reportExtensions.json structure, common patterns, DAX verification
references/visual-formatting-properties.md — Universal containers, property catalogue, formatting hierarchy
- VERIFY all PBIR visual structures against the official Microsoft documentation:
- If uncertain about any PBIR schema, use
microsoft_docs_search MCP tool with queries like:
"Power BI PBIR page definition schema"
"Power BI PBIR visual container schema"
"Power BI report definition JSON format"
- Use
microsoft_docs_fetch for full documentation pages when search results are insufficient.
- If the step uncovers a new reusable PBIR rule about schema, folder structure, serialization, payload stability, or visual-role mapping, update the relevant reference file before ending the step. Do not leave recurring guidance only in chat output.
PBIR CLI Mutation Policy (Mandatory for Existing Artifacts)
When the local pbir CLI is available, this skill must use it as the mutation backend for existing local PBIR report artifacts.
Use it for:
- report inspection:
pbir ls, pbir tree, pbir model, pbir get, pbir cat
- schema/property discovery:
pbir schema types, pbir schema containers, pbir schema describe
- targeted local edits:
pbir add, pbir pages, pbir visuals, pbir set, pbir fields, pbir filters, pbir dax, pbir theme
- local safety loop:
pbir backup, pbir validate, pbir open
Rules:
- Do NOT run
pbir setup from this skill.
- Do NOT let CLI behavior replace blueprint-driven design or repository templates.
- Use the CLI for existing-report mutations that map cleanly to the requested change.
- Before any CLI read or write command, clear or replace any existing active
pbir connection and reconnect it to the current project report under <ProjectName>/PBIP/<PbipBaseName>.Report.
- Never assume the active
pbir session already points to the current project; verify with pbir connect or reconnect explicitly.
- Before bulk or structurally risky commands, run
pbir backup.
- After every CLI mutation, run
pbir validate (prefer --all when available), then still satisfy the repository validation gate below.
- If the CLI is unavailable or unsupported for a requested mutation, stop and request explicit approval before falling back to direct JSON edits.
- Do not use
pbir download or pbir publish in Step 9 unless the user explicitly requests Fabric-edge operations.
Direct JSON edit prohibition (existing artifacts):
- Do not hand-edit
visual.json, page.json, pages.json, or theme JSON for routine report mutations.
- Use CLI commands (
pbir set, pbir visuals, pbir fields, pbir filters, pbir theme) as the default path.
- If fallback is approved, record rationale and run dual validation before completion.
Mandatory Implementation Safety Gate
Before marking implementation complete, run this exact sequence:
pbir connect --clear
pbir connect "<PbipBaseName>.Report"
pbir validate "<PbipBaseName>.Report" --all
python .github/skills/report-quality-validation/scripts/validate_pbir_report.py <ProjectName>
Gate rules:
- If either validation fails, implementation is NOT complete.
- Fix errors first, rerun both commands, then update workflow state.
- Treat Desktop
AdditionalProperties failures as schema-blocking defects.
Schema red flags to check explicitly:
visualContainerObjects must be inside visual.
drillFilterOtherVisuals must be inside visual.
- Visual filters must be in top-level
filterConfig.filters, never in visual.filters.
- Top-level keys in
visual.json must stay within the schema surface ($schema, name, position, visual|visualGroup, optional filterConfig).
Canonical pbir Command Patterns
Use these examples only when they match the requested local report task.
- Inspect an existing report before edits:
pbir connect --clear
pbir connect "Sales.Report"
pbir tree "Sales.Report" -v
pbir model "Sales.Report" -d
- Create a backup before risky local changes:
pbir connect --clear
pbir connect "Sales.Report"
pbir backup "Sales.Report" -m "Before report implementation changes"
- Add a native visual with explicit binding:
pbir connect --clear
pbir connect "Sales.Report"
pbir add visual card "Sales.Report/Overview.Page" --title "Revenue" -d "Values:Sales.Revenue"
- Apply a narrow formatting or layout change:
pbir connect --clear
pbir connect "Sales.Report"
pbir visuals title "Sales.Report/Overview.Page/Revenue.Visual" --text "Net Revenue" --bold
pbir visuals position "Sales.Report/Overview.Page/Revenue.Visual" --x 40 --y 32 --width 260 --height 120
- Apply a safe theme-first formatting change:
pbir connect --clear
pbir connect "Sales.Report"
pbir theme set-colors "Sales.Report" --primary "#2B579A" --secondary "#217346"
pbir theme set-formatting "Sales.Report" "card.*.border.show" --value true
- Validate after mutation:
pbir connect --clear
pbir connect "Sales.Report"
pbir validate "Sales.Report"
Fallback:
- if any of these commands cannot express the blueprint requirement cleanly, return to the repository templates and direct file generation flow
- if a command requires broader destructive scope than requested, stop and keep the change in the repository-managed workflow instead
- if
pbir cat fails with a packaged runtime error but pbir ls or pbir get still work, treat cat as unavailable for the current environment and continue with repository-managed file inspection instead of blocking Step 9
CRITICAL: NEVER invent or guess PBIR JSON structures. Always validate against Microsoft official documentation or the template reference file. In the current baseline, drillFilterOtherVisuals belongs to visual, cards use visualType: cardVisual with queryState.Data, page navigation is governed by definition/pages/pages.json, and PBIR JSON must be written as UTF-8 without BOM.
CRITICAL: Schema lookup findings belong in repository knowledge, not in ad-hoc local scratch files. Temporary inspection artifacts may be used while working, but any durable conclusion must be normalized into a reference file and temporary files must not remain as project artifacts.
Anti-Hallucination Protocol
CRITICAL: PBIR JSON is verbose and deeply nested. The agent MUST NOT guess JSON structures.
- Use templates: Every visual MUST be generated from a template in
.github/skills/report-implementation/references/pbir-visual-templates.md.
- Validate field names: Every
Entity and Property in visual queries MUST match exactly the TMDL table and column/measure names.
- No invented visuals: Only generate visuals defined in
report_blueprint.json.
- Schema compliance: All JSON files MUST reference the correct Microsoft
$schema URLs.
- Physical ID discipline: Page and visual runtime ids used in PBIR folders and
name properties MUST be generated explicitly and kept synchronized across all referencing files.
- Encoding discipline: Write every generated PBIR JSON file as UTF-8 without BOM.
- Knowledge-base discipline: If a new rule is discovered that is not specific to the current report, persist it in the corresponding reference before closing the step.
Step 9 Procedure
9.1 Read Inputs
- READ
<ProjectName>/spec/report_blueprint.json — Parse the complete blueprint.
- READ TMDL files — Build a Model Object Registry (same as Step 7, Step B.0):
- All table names
- All column names per table (PascalCase)
- All measure names from
_Measures.tmdl (natural language with spaces)
- CROSS-VALIDATE: Verify that every field referenced in
report_blueprint.json exists in the Model Object Registry. If any field is missing, STOP and report the discrepancy.
- READ strategy metadata: If a visual declares
implementationStrategy, honor the selected mode (native, composite-native, svg, deneb, approximation, not-feasible) during generation.
- LOAD custom-visual skills on demand:
- If
implementationStrategy.mode = svg, load the svg-visuals skill before implementation.
- If
implementationStrategy.mode = deneb, load the deneb-visuals skill before implementation.
- If
implementationStrategy.mode = approximation, implement only the documented approximation. Do not invent a new strategy.
- If
implementationStrategy.mode = not-feasible, STOP and report the blueprint conflict instead of generating a fake equivalent.
9.2 Clean Up Existing Report Pages
Before generating new pages:
- CHECK if
<ProjectName>/PBIP/<ProjectName>.Report/definition/pages/ already contains page folders.
- If the folder contains only the default
Page1/ from Step 00 initialization, remove it (it will be replaced by the blueprint pages).
- If the folder contains pages from a previous Step 9 execution, ask the user whether to overwrite or skip.
- CHECK
definition/pages/pages.json before deletion or creation. Folder cleanup is invalid unless the metadata file is updated in the same operation.
9.3 Derive Physical PBIR IDs (MANDATORY)
The blueprint provides canonical logical identifiers for design intent. Step 09 must translate them into physical PBIR runtime ids.
For each page and visual:
- Generate a runtime-safe id following the repository-safe baseline observed from Desktop output:
- 20 lowercase alphanumeric characters
- Keep a deterministic mapping:
blueprint pageId -> pageRuntimeId
blueprint visualId -> visualRuntimeId
- Use the runtime id for:
- page folder names
page.json.name
pages/pages.json.pageOrder[]
pages/pages.json.activePageName
- visual folder names
visual.json.name
CRITICAL: Do NOT use user-facing labels like Page1, Page2, or visual_01 as final PBIR folder names. They are blueprint identifiers, not the physical PBIR object names.
9.4 Generate Page Folders and Files
For each page defined in report_blueprint.json:
A) Create Page Folder
<ProjectName>/PBIP/<ProjectName>.Report/definition/pages/<pageRuntimeId>/
Where <pageRuntimeId> is the generated PBIR runtime id for the page.
B) Create page.json
Use the page template from .github/skills/report-implementation/references/pbir-visual-templates.md:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/page/2.0.0/schema.json",
"name": "<pageRuntimeId>",
"displayName": "<displayName from blueprint>",
"displayOption": "FitToPage",
"height": <height from blueprint>,
"width": <width from blueprint>
}
CRITICAL: The PBIR page schema 2.0.0 does NOT allow additional properties. Only use the 6 properties shown above. Do NOT add ordinal or any other custom property — Power BI Desktop enforces strict schema validation and rejects unknown properties with AdditionalProperties error.
File location: <ProjectName>/PBIP/<ProjectName>.Report/definition/pages/<pageRuntimeId>/page.json
C) Create visuals/ Folder
<ProjectName>/PBIP/<ProjectName>.Report/definition/pages/<pageRuntimeId>/visuals/
D) Update pages/pages.json
Generate or update:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/pagesMetadata/1.0.0/schema.json",
"pageOrder": ["<pageRuntimeId1>", "<pageRuntimeId2>"],
"activePageName": "<firstPageRuntimeId>"
}
Guardrails:
pageOrder must reflect blueprint navigation order.
activePageName must point to a generated page.
- Page folders on disk and entries in
pageOrder must match exactly.
9.5 Generate Visual Files
For each visual defined in a page's visuals array in the blueprint:
A) Create Visual Folder
<ProjectName>/PBIP/<ProjectName>.Report/definition/pages/<pageRuntimeId>/visuals/<visualRuntimeId>/
Where <visualRuntimeId> is the generated PBIR runtime id for the visual.
B) Create visual.json
- Identify the visual type from the blueprint's
visualType field.
- Look up the corresponding template in
.github/skills/report-implementation/references/pbir-visual-templates.md (use the Visual Type Mapping table).
- Populate the template with:
name: The visualRuntimeId generated for the visual.
position: Map x, y, width, height from the blueprint's position object. Set z and tabOrder as deterministic monotonic integers based on visual order. Do NOT assume that increments of 1000 are required.
- usability sizing guardrails:
- top-row dropdown slicers should default to about
width = 180, height = 64-66
- grouped KPI bands should default to about
height = 120
- gauges should default to a primary analytical tile size above
300 x 130
- azure maps and treemaps should default to large analytical surfaces and should not be compressed into small tiles
- operational token guardrails:
- consume
designSystem.pagePadding, visualGap, sectionGap, gridUnit, and per-visual renderTokens from the blueprint when present
- if tokens are absent, use repository-safe fallback defaults
- treat overlap as forbidden unless a visual explicitly sets
renderTokens.allowOverlap = true
visual.visualType: The PBIR visual type (from mapping table).
visual.query.queryState: Map measures and fields from the blueprint to the correct PBIR query structure:
- Card measures →
Data projections with Measure field type, Entity = _Measures.