Key Takeaways
- An AI coding agent can help you fix a broken report, if permitted. We show how it might with two demos.
- Today’s agents can be cautious, meticulous, and effective. These traits are not guaranteed: we observed them in an agent operating in a sandbox environment, with curated context, wielding purpose-built tools (CLIs), to fix a well-scoped problem. Letting agents loose in production without guardrails in place is not a good idea.
- There are different CLIs for the different surfaces of the Power BI and Fabric stack, and the lineup keeps growing; CLIs are having a moment well beyond Power BI. What an agent does through a CLI comes out as commands you can read back and run yourself, or use in a script when you want a repeatable process.
This summary is produced by the author, and not by AI.
Imagine you were just pinged by one of your users informing you that one of their essential reports is just straight up broken. They can’t open it anymore. The report owner has left the organization, and it’s now your problem to solve. You can’t open the report yourself either. An increasingly popular response is to just point an AI coding agent at it to “pls fix”.
So that’s what we did and recorded the whole thing end to end. This blog is a walkthrough of how that went: how the agent worked, what it struggled with and what went well. It is not an endorsement of using AI coding agents on your production tenant without guardrails. They can and will cause damage if you do.
The tools: different surfaces, different CLIs
Before diving into the demos, some background on CLIs. A Command-Line Interface (CLI) is a text-based interface to interact with software via commands. By typing te connect Sandbox SpaceParts and hitting enter, you are instructing the Tabular Editor CLI (te) to establish a connection with the SpaceParts semantic model in the Sandbox workspace. You can follow up with another command like te refresh --table Regions, which will request a refresh of the Regions table in the connected semantic model. You also could’ve chained it to the original te connect Sandbox SpaceParts command with &&, like so: te connect Sandbox SpaceParts && te refresh --table Regions. This command would first connect, and if successful, request the refresh. CLIs are a no-frills way to send instructions to systems and let them respond back.
CLIs have traditionally been associated with programming, and seen as tools mostly wielded by professional coders in dark-themed terminals. They have staying power for a practical reason: a command can be chained, saved to a script, and rerun the next time the same job comes up. Many of the oldest ones, like grep, were built to do one small thing and pass their output to the next tool, and that composability still pays off today. You could run te ls -s MyWorkspace -d MyModel | grep Orders to list a model’s objects and keep only the lines mentioning Orders. The same property makes CLIs easy to automate: a CI/CD pipeline in GitHub Actions or Azure DevOps can run the exact commands you validated by hand, unattended, and read their output back.
An agent already works in text, so a CLI’s typed commands and plain responses suit it better than clicking through a graphical interface would, and it tends to reach for one when it can. So you no longer have to live in a terminal to get a terminal’s benefits: you say what you want in plain language, the agent runs the commands, and you read back what it did.
Each surface can have specific CLIs: te for the model, pbir for the report, and fab, the Fabric CLI, for the workspace and service around it. This list is by no means exhaustive or exclusive, these are just the ones we have used here. Since the fixes here live in the report and service, the demos run on pbir and fab; te is one you would use when the problem is in the model itself. We’ll show the te CLI in action soon, in a future blog.

We stay on CLIs in these demos because what the agent runs comes back as commands you can read and rerun yourself. Another path is the Model Context Protocol (MCP), gaining ground including in the Microsoft stack. MCP exposes a tool’s capabilities to the agent through a structured protocol rather than as text commands. There’s also familiarity: the training data for LLMs includes many more examples of CLI interaction than use of the much newer MCP protocol, so results tend to be better with CLIs. Each suits different work: MCP can be cleaner when a capability does not map neatly to a text command, while a CLI’s plain-text trail is handy when the work must be reviewable, as a repair usually does. On to the demos.
The report that won’t open
You try to open the report, but are greeted with a generic ‘Unable to load report’ error. When you close the dialog, the spinner pretends that it’s doing something, but it’s in fact stuck. There’s no button to try and download it to file either. What do? You could try whether it’s downloadable to file through API, or… What if you just pointed your agent at it? The video below shows how that went for us, with some parts sped up for demonstration purposes:
We kept the prompt deliberately bare. We told it the symptom and which CLI to reach for, and left the approach to it:
The ‘V012 - Interactive Data Visualization’ report in the V011 workspace throws a generic “Unable to load report” error when I try to open it in the PBI service. Use pbir CLI to figure out what’s wrong and fix it.
It opened with the obvious check, pbir validate --all, and everything passed. A clean validation only means the report’s JSON is well-formed, though, not that the service will load it. The break showed up only under stricter checking: running validation with --strict against the published copy returned a cluster of errors flagged ORPHAN_PARENT_GROUP, child visuals pointing at parent group containers that were no longer there. To find which containers, the agent diffed the broken published report against a local copy and found three visual groups the local copy still had and the published version had lost.
The fix was a restore rather than a rebuild. The local copy was intact, so once we cleared it, the agent backed the report up with pbir backup, rebound it from a file path to the live model with pbir report rebind, and republished over the broken version with pbir publish -f. Re-exporting and validating again with --strict came back at zero errors.
The path there was not straight. pbir filters list crashed and pbir bpa run failed (beta tooling, both since reported to the authors), the in-browser check found no Chrome connected, and the agent briefly ran with a wrong “the local model is empty” assumption before recursive file discovery corrected it. The stricter validation is what finally pointed at the groups. The full command trail is in the action logs below.
Getting the report to open in the service turns out to be only half the job. Where before we’d have to theorize about ways into a broken thing we’re locked out of, now we gave the agent some tools in the form of CLIs and let it go ham to try to find a way in. There was no guarantee it would’ve found that way in, but it wasn’t us that had to spend time trying to crack the problem and potentially wasting our time.
The report loads now, but a lot of its visuals are still broken. Let’s load up another prompt.
NOTE
The two videos are from two recorded sessions against the same report. The demo that now follows was actually recorded before the demo above. The sanitized action logs are published alongside the article, so you can read the command trail.
Openable, but still broken
Some visuals are broken, evident by the gray boxes. A report can be valid, publishable and openable, but still have expressions returning errors or which point at fields that no longer exist in the visuals. To fix these we again send in the agent.
This time the prompt carried more direction. We told it to pull a local copy first, fix what it safely could, and hand back the harder calls:
The ‘V012 - Interactive Data Visualization’ report in the V011 workspace has grayboxed visuals on the Profitability page. Use fabric cli to export a local working copy, then do a first diagnostic pass and fix the stuff you can on the fly. Report back with harder stuff.
The instruction to export a local copy first was ours, and it mattered. An agent will not always think to do that on its own, and you do not want it editing the live report in place; a working copy is what keeps a fix reversible.
It exported both the report and its semantic model with fab export. It needs both: the report shows which fields it asks for, the model shows which of those fields still exist. pbir validate --fields --qa then returned about 125 warnings, which it cross-checked against the model’s TMDL.
The judgment call was splitting those warnings in two. Two were genuine model renames (Gross Margin % vs PY pp to Margin Delta YoY pp, and Customer Sold-To Name to Customer Name). The rest were stale query aliases left behind by Power BI Desktop that still resolve to a valid field underneath. Getting that split right matters: “fixing” an alias that already works would break a visual that currently renders. It backed the report up, previewed each rename with pbir fields replace --dry-run, then applied only the two real ones. After that it hand-patched the places a bulk replace does not reach: bookmark snapshots, a page binding, and a saved drill-state in the decomposition tree.
Before publishing, it paused and reported what it had fixed, what it had left alone, and what it needed us to decide. The report opened fine in Power BI Desktop, so we approved the publish with fab import -f, and let it leave a few non-blocking warnings be: a tooltip visual that would not render, a stacked bar missing a category role, and a couple of visuals on a newer schema than the local validator fully reads. We checked those and decided they were inconsequential here.
So, two repairs in two sessions. The first got the report to open again and the second fixed the visuals. The agent did the heavy lifting from problem to solution. Not in a straight line, granted, but it did get there with seemingly limited effort from us: just a few prompts.
Our role and the map we gave
The agent did not start from nothing. Part of the outcome came from the context it was given, not from raw model capability alone. It had access to Claude Code marketplace skills for PBIR and Fabric CLI work, the installed tools (CLIs), and our global Claude configuration. The demo repo’s own CLAUDE.md (a file with general instructions for Anthropic’s Claude Code agent) also nudges the agent towards the CLI companion skills. The ask-before-publishing caution came from the global config, not that repo file, so installing the skills alone would not reproduce it. We put the relevant context within reach beforehand, provisioned the tools, and most importantly: we came up with the idea and formulated the intent in a prompt. Agents can do the heavy lifting and dig up findings, but they shouldn’t make judgment calls like whether overwriting a live report from a local copy is acceptable, or whether to ignore a warning (we verified and decided they were inconsequential).
A well-scoped agent with the right local knowledge and tools turns a hard-to-start repair into an inspectable sequence of steps, but you still own the decisions.
Before you try this or something similar
We encourage you to try out agents to see what they can do for you, with an important caveat. This demo postmortem is not an endorsement of letting AI coding agents loose on production tenants without guardrails. It’s an experiment to show how it could go if you task an agent with a scoped task, not a showcase of good development practice. These demos were only safe to run because we ran them in a sandbox tenant without sensitive data.
When you leave the sandbox and/or introduce sensitive data, the stakes change dramatically.
- Reading and exporting. Report definitions carry names, paths, measures, filters (actual data) and so on; that’s all now in the agent’s context and wherever that context travels. Other local file contents the agent read or screenshots you pasted into the interface; this is data your organization might consider public or sensitive; the line can get blurry fast and that’s where the danger lives. Enterprise plans with LLM providers or running local organizational LLMs can be ways to mitigate the data privacy risk.
- Editing and publishing. Publishing may overwrite a live report your users depend on. Backups and solid CI/CD practices are ever more important with agents: their blast radius is only limited by hard access boundaries; they can and will ignore some of your instructions. Relying on asking agents to please create backups before touching anything is not a sound backup strategy. A good backup is one the agent cannot reach to overwrite or delete.
There is a more controlled way to get value from this in production. Let the agent do its exploring in a sandbox, where it can run commands freely until it lands on the sequence that actually fixes the problem. Because that sequence is just CLI commands, you can then run the same steps yourself against production, reading each one before you do. The agent does the exploring and builds the playbook where mistakes are cheap, and you keep control of every command that reaches live data.
Further recommended reading
- Introducing the Tabular Editor CLI. The model-side CLI on the diagram.
- AI readiness and best practices for semantic models. The model under the report.
- maxanatsko/pbir.tools.
pbir, by Kurt Buhler and Maxim Anatsko. - data-goblin/power-bi-agentic-development. The skills marketplace.
In conclusion
The broken report that opened this piece, the one you couldn’t even download from the graphical interface, went from a dead end to something you could again open, interact with, and give back to users. The specific CLIs may change and the agents will keep getting better at reaching for them, but the skill underneath holds: know which surface a problem lives on, scope it there, and keep the judgment calls for yourself. Get that right, and the next “pls fix” directed at you is one you could tag team with an agent, with respect for your organization’s policies.
Appendix
Below are the action logs for each of the two demo sessions.
Restore broken report
# V012 Unable To Load Report - Action Log
Source transcript: `2026-05-26-v012-unable-to-load.transcript.sanitized.md`
## Goal
Diagnose and fix the generic Power BI service error `Unable to load report` for `V012 - Interactive Data Visualization` in the `V011` workspace.
## Actions
1. Used `reports:pbir-cli` to follow PBIR report inspection, validation, rebind, and publish workflows.
2. Used `pbir ls` to list the local report contents and confirm the active report.
3. Used `pbir validate "V012 - Interactive Data Visualization.Report" --all` to run a full validation pass.
4. Used `pbir validate ... --all --json` to get machine-readable validation output.
5. Used `grep -i "error|critical|fail"` on the JSON validation output to confirm basic validation reported no blocking errors.
6. Used `pbir model` to inspect the local model binding and confirm the local report was a thick report bound by path.
7. Used `pbir tree` to inspect report structure, page counts, visual counts, filters, and bookmarks.
8. Used `pbir filters list --json` to inspect filters; the command failed on an advanced Date Hierarchy filter, which became a diagnostic lead.
9. Used `pbir cat "V012 - Interactive Data Visualization.Report/report"` to inspect report-level JSON, including theme collection, report filter config, resource packages, and settings.
10. Used local file listings and globbing to inspect static resources and confirm referenced theme, shape map, image, and base theme files.
11. Used `pbir find` and `pbir cat` to inspect shapeMap visuals and verify their custom map resource references.
12. Used direct file reads to inspect the custom `DeepReachTheme` JSON after `pbir cat` could not read static-resource files.
13. Tried `pbir bpa run` with several path forms; the command failed with a report-loading argument error, so BPA was not usable for this investigation.
14. Checked `.platform`, `definition.pbism`, `definition.pbir`, and the `.pbip` file to understand the PBIP and report/model binding shape.
15. Used `fab ls` to list Fabric workspaces and confirm `V011.Workspace` existed.
16. Used `fab ls "V011.Workspace"` to confirm the service workspace contained the target report and semantic model.
17. Used `fab get ... -q displayName` and related queries to confirm workspace and semantic model details.
18. Used `fab export "V011.Workspace/V012 - Interactive Data Visualization.SemanticModel"` to export the service semantic model for comparison.
19. Used globbing on the service semantic model export to confirm the service model had a full TMDL definition.
20. Used `fab export "V011.Workspace/V012 - Interactive Data Visualization.Report"` to export the published service report for comparison.
21. Used `pbir tree` and `pbir validate --all` against the service-exported report to compare service structure and validation state with the local copy.
22. Used schema searches to inventory PBIR schema versions and confirm the report mixed `visualContainer` 2.7.0 and 2.8.0 visuals.
23. Compared service and local report JSON, pages metadata, resource references, bookmark metadata, visual types, page bindings, and Date table fields.
24. Corrected an early wrong hypothesis that the local semantic model was empty by using recursive file discovery to confirm the local model did contain TMDL files.
25. Used `pbir model ... -q "EVALUATE ROW(\"x\", 1)"` against the local report and service-exported report to confirm only the service model could execute queries through PBIR.
26. Used Microsoft Learn search for PBIR service load and `definition.pbir` `byConnection` details to check known format pitfalls.
27. Used Chrome MCP discovery to try to inspect the service error directly; no connected Chrome browser was available.
28. Used `fab get` to obtain the service semantic model ID and report ID.
29. Inspected suspicious Profitability 3 visual JSON and counted `'minColor'` literals, then confirmed the same literals existed both locally and in the service export, so they were not the service-only load cause.
30. Used `pbir validate "/tmp/svc-export/V012 - Interactive Data Visualization.Report" --fields --strict` to reveal blocking strict-validation errors in the service export.
31. Identified 73 strict service errors, including 15 `ORPHAN_PARENT_GROUP` errors where child visuals referenced missing parent group visuals.
32. Compared local and service definitions for parent group IDs and confirmed the local report had the missing `visualGroup` containers while the service export did not.
33. Inspected the local parent group visual files for `77ad533f206603abeb57`, `5d3d165def12367496b3`, and `dc585e427a7b7c059049`.
34. Reported the diagnosis and asked the user to choose the fix path because publishing to the shared workspace was required.
35. Proceeded with the user-approved path: republish report only, leaving the service semantic model untouched.
36. Used `pbir --help`, `pbir report rebind --help`, and `pbir publish --help` to confirm the exact rebind and publish command shapes.
37. Used `pbir backup` to back up the local report before changing the binding.
38. Used `pbir report rebind "V012 - Interactive Data Visualization.Report" "V011.Workspace/V012 - Interactive Data Visualization.SemanticModel"` to convert the local report from `byPath` to `byConnection`.
39. Read `definition.pbir` to confirm it now referenced the service semantic model through a `byConnection` connection string with the semantic model ID.
40. Used `pbir validate "V012 - Interactive Data Visualization.Report" --strict` to confirm the rebound report was structurally valid enough to publish.
41. Used `pbir publish "V012 - Interactive Data Visualization.Report" "V011.Workspace/V012 - Interactive Data Visualization.Report" -f` to overwrite the broken service report.
42. Re-exported the service report with `fab export` after publishing.
43. Used `pbir validate` with strict JSON parsing on the re-exported service report to confirm `total errors: 0` and `orphan_parent_group errors: 0`.
44. Used `find ... -exec grep -l "visualGroup"` to confirm all service `visualGroup` containers were present, including the three missing parent groups.
## Result
Published a repaired thin report to `V011.Workspace/V012 - Interactive Data Visualization.Report`.
The service load failure was caused by missing parent `visualGroup` containers in the published report. The repaired service copy re-exported cleanly and strict validation reported:
- `total errors: 0`
- `orphan_parent_group errors: 0`
Separate latent issue noted:
- Field-reference drift remains in some visuals, especially around `Shipments[Gross Margin % vs PY pp]`. Those errors affect individual visuals but were not the generic report-loader failure.
Fix broken visuals
# V012 Profitability Graybox Fix - Action Log
Source transcript: `2026-05-05-v012-profitability-graybox-fix.transcript.sanitized.md`
## Goal
Diagnose grayboxed visuals on the `Profitability` page of `V012 - Interactive Data Visualization`, fix clear local PBIR issues, and publish back only after user approval.
## Actions
1. Used `fabric-cli:fabric-cli` to work with the Fabric workspace and report items.
2. Used `pbir-tools` to inspect, validate, back up, edit, and publish the PBIR report definition.
3. Used `fab auth status` to confirm Fabric CLI was authenticated.
4. Used `fab ls | grep -i V011` to find the `V011.Workspace`.
5. Used `fab ls "V011.Workspace" -l` to confirm the workspace contained the target report and semantic model.
6. Used `fab export "V011.Workspace/V012 - Interactive Data Visualization.Report"` to export a local working copy of the report.
7. Used `fab export "V011.Workspace/V012 - Interactive Data Visualization.SemanticModel"` to export the matching semantic model for field validation.
8. Used `pbir ls` to list report contents and identify the Profitability pages, bookmarks, theme, and filters.
9. Used `pbir validate "V012 - Interactive Data Visualization.Report"` to run a first structural validation pass.
10. Used `pbir validate "V012 - Interactive Data Visualization.Report" --fields --qa` to find missing field and table references behind the grayboxed visuals.
11. Used model TMDL searches on `Shipments.tmdl` and `Customer.tmdl` to map old report references to current model names.
12. Used `pbir tree "V012 - Interactive Data Visualization.Report/Profitability.Page" -v` to inspect visual field bindings on the Profitability page.
13. Used targeted `grep` and file reads on `visual.json` files to separate real broken `Property` references from stale `queryRef` aliases.
14. Identified `Shipments[Gross Margin % vs PY pp]` as a real broken reference and mapped it to `Shipments[Margin Delta YoY pp]`.
15. Identified `Customer[Customer Sold-To Name]` as a real broken reference and mapped it to `Customer[Customer Name]`.
16. Confirmed several warnings were alias-only and not direct graybox causes, including `Shipments.Units`, `Shipments.ee`, `CF - Subtitle...`, and `ScatterChartXAxis` / `ScatterChartYAxis` query aliases.
17. Used `pbir fields replace --help` to confirm the right command for bulk field-reference replacement.
18. Used `pbir backup` to create a local report backup before applying changes.
19. Used `pbir fields replace --dry-run` for `Shipments.Gross Margin % vs PY pp -> Shipments.Margin Delta YoY pp` to preview affected visuals and locations.
20. Used `pbir fields replace --dry-run` for `Customer.Customer Sold-To Name -> Customer.Customer Name` to preview affected visuals, page filters, and report locations.
21. Used `pbir fields replace` to apply the `Gross Margin % vs PY pp` rename across visuals, sort definitions, selectors, and conditional formatting.
22. Used `pbir fields replace` to apply the `Customer Sold-To Name` rename across slicers, scatter charts, decomposition tree, table visual, and page filters.
23. Used `pbir validate --fields` after each replacement to confirm the two target missing-field warnings were gone.
24. Used `grep` on bookmark definitions to find stale `Customer Sold-To Name` and `Gross Margin % vs PY pp` references inside bookmark snapshots.
25. Used a targeted text replacement in bookmark JSON to update bookmark `Property` references that `pbir fields replace` did not traverse.
26. Used targeted edits on the Decomposition page `pageBindings` and decomposition tree collapsed `queryRefs` to update remaining direct `Customer Sold-To Name` references.
27. Used `pbir validate --fields` for a final local validation pass.
28. Reported the local backup path, local report path, fixed field mappings, alias-only warnings left alone, and harder remaining issues.
29. Paused before publishing because updating the shared Fabric workspace required user approval.
30. After user approval, used `fab import "V011.Workspace/V012 - Interactive Data Visualization.Report" -i ... -f` to publish the fixed report back to the `V011` workspace.
## Result
Published the updated report to `V011.Workspace/V012 - Interactive Data Visualization.Report`.
The main graybox causes fixed were:
- `Shipments[Gross Margin % vs PY pp]` -> `Shipments[Margin Delta YoY pp]`
- `Customer[Customer Sold-To Name]` -> `Customer[Customer Name]`
Remaining non-blocking or separate issues noted:
- Alias-only validation warnings from stale `queryRef` / `nativeQueryRef` values.
- TT page `hundredPercentStackedBarChart` missing a `Category` role.
- Profitability 3 visuals using newer `visualContainer 2.8.0` schema than the local validator fully supports.


