Semantic Model Cleaner analyzes Power BI PBIR + TMDL projects, shows which semantic model items appear to be unused across selected reports, and lets you apply cleanup actions locally.
It works directly in repositories containing TMDL and PBIR files; Power BI Desktop is not required. Core workflows are free under the MIT license, with no account or paid service required. Fabric integration is a future extension.
It is designed for local use against files on your machine. Version 0.4.0b10
is the public beta for Power BI practitioners who already work with PBIR
and TMDL.
Beta10 integrates format-string reference checks, whole-table dependencies, Broken-item deletion handling, nullable report bindings, Review explanations, and structural-unit retention. See the release notes.
Before applying changes: back up your Power BI Project or commit it to version control first. Apply writes to your TMDL and PBIR files; guarded restore recovers the original bytes from the plan, but a backup is your safety net.
Release candidate: publication and independent review are pending. Versioned download links below are release targets, not evidence of available artifacts.
AI agents can use the repository's SKILL.md for command discovery,
scope rules and the reviewed cleanup workflow. Maintainers regenerate it with
python scripts/generate_skill.py after installing the project; CI checks it
against smc capabilities with python scripts/generate_skill.py --check.
- Project maturity: public beta
0.4.0b10 - Runtime shape: Python package with a CLI, a local web UI, and Windows desktop packaging
- Stable entry points:
semantic-model-cleaner,semantic-model-cleaner-web,smc, andsmc-web - Windows entry points: packaged
Semantic Model Cleaner.exe,semantic-model-cleaner-desktop, andsmc-desktop - Release channel: beta is baked into this package and shown in the UI
- Scans exactly one
.SemanticModeland one or more.Reportfolders - Detects direct report usage plus supported indirect or model-backed usage
- Surfaces warnings for unresolved or ambiguous dynamic references
- Lets you review analysis results in a local web UI
- Supports local cleanup actions such as move to folder, hide/unhide, and delete
- Previews queued cleanup actions before writing TMDL files
- It does not host or publish reports for you
- It does not yet ship a signed installer or auto-update flow
- It does not yet cover every Power BI metadata edge case
- Windows ZIP: Windows x64; no Python installation required.
- CLI or source install: Python
3.11+.
The desktop VS Code extension preview is prepared
for an initial public pre-release as MrPerfectH.semantic-model-cleaner 0.1.4.
It wraps the existing Python/UI and requires a separately installed compatible
engine. Nothing is installed automatically; see the extension instructions
for engine setup, VSIX packaging and acceptance limits. Publication is a separate
maintainer action.
Runtime install:
python -m pip install .Development install:
python -m pip install -e .[dev]For terminal-free Windows use, download
semantic-model-cleaner-windows-x64-0.4.0b10.zip
and its
SHA-256 checksum
from the explicit beta prerelease. Extract the whole ZIP, then run
Semantic Model Cleaner.exe. Python, Power BI Desktop, Fabric, an account,
and paid services are not required.
Local launcher command:
semantic-model-cleaner-desktop .Short alias:
smc-desktop .Packaged runtime behavior:
- starts the local app on
127.0.0.1 - prefers port
5001and falls back to another free local port if needed - opens the default browser automatically
- can skip browser launch with
--no-open-browser
Open Try demo or Open Power BI Project, review the selected Semantic Model and connected Reports, then choose Analyze. Inspect one item’s Usage and dependencies before preparing changes. Review the exact file diff before apply. Changes & history provides file verification and guarded restore. See the Windows walkthrough.
Run smc --help for the complete command guide and smc --version for the
installed version. The CLI automation contract documents
JSON output, exit codes, path/filter differences, and a disposable reviewed-change workflow.
Ask focused questions with compact text output or versioned JSON for agents:
smc items . --search Revenue
smc usage . --table Sales --item Revenue
smc usage . --table Sales
smc summary .
smc review . --format json
smc capabilitiesSMC normally discovers one Semantic Model and its connected Reports. For explicit
selection, use --model-path Models/Sales.SemanticModel and repeatable
--report-path Reports/Executive.Report. These are exact paths relative to the
project argument (absolute paths also work) across project commands. Existing
selectors retain their behavior; see selection and migration.
These source-version commands explain direct and indirect usage by Report, page,
and visual, summarize each Report's model footprint, and group existing check
findings. They are read-only; use --model-only when Report usage cannot be
checked. See focused CLI queries and agent workflows.
Run the analyzer from a workspace root:
semantic-model-cleaner . --format fullExport JSON or Excel:
semantic-model-cleaner . --format json -o analysis.json
semantic-model-cleaner . --format xlsx -o analysis.xlsxShort alias:
smc . --format fullUse explicit paths when your model and report roots are separate:
semantic-model-cleaner \
--models-path /path/to/Model.SemanticModel \
--reports-path /path/to/Report.Report \
--format unusedModule entrypoint:
python3 -m semantic_model_cleaner . --format fullclean-stale previews dead PBIR metadata in bulk: stale visual selectors, stale bookmark projections and stale formatting rules. These are the warning issues the analyzer already marks with a high-confidence clean_stale suggestion, because the reference is not part of the live visual query. Broken references (missing_table, missing_column, missing_measure — severity error, i.e. rename fallout) are never touched.
smc clean-stale . # dry run: counts + full candidate list
smc clean-stale . --kind formatting selector # limit to some kinds
smc clean-stale . --format json # machine-readableBy default it analyzes only the reports whose definition.pbir binds them to the selected semantic model (by path, or by published name for live connections) — the same invariant the web UI's report finder applies; pass --all-reports to analyze every discovered report, and note that --report filters compose on top of the bound set.
The positional argument is project_path — the Power BI Project folder that holds one .SemanticModel and its .Report folders (default .). It takes the same selection flags as the analyzer (--models-path, --reports-path, --model, --report).
Exit codes (so CI can gate on a dry run):
| Code | Meaning |
|---|---|
| 0 | No cleanup candidates |
| 1 | Cleanup candidates found; nothing was written |
| 2 | Input/analysis error or a withheld direct-write request |
This command is read-only in the beta. The legacy --apply shortcut is withheld because it cannot apply a previously reviewed, saved plan. Use the app change review or a clean_stale operation through CLI plans, followed by smc diff, smc apply and smc verify. The reviewed workflow always records recovery data.
Start the web app:
semantic-model-cleaner-web .Short alias:
smc-web .Then open http://127.0.0.1:5001.
Optional flags:
semantic-model-cleaner-web . --port 8080
semantic-model-cleaner-web . --host localhost
semantic-model-cleaner-web . --debugModule entrypoint:
python3 -m semantic_model_cleaner.web .The web app is local-only: both launchers accept 127.0.0.1 or localhost, and
remote binding is disabled. The workspace handles the per-launch request token
automatically. Local scripted HTTP clients must first read /api/session, then
send its token in the X-SMC-Token header; use JSON for changes. CLI file-based
commands need no HTTP token. See local HTTP access
for the supported client protocol and browser boundary.
The app bundles a small synthetic demo workspace. In the web UI, click Try the demo workspace to copy it to ~/.semantic-model-cleaner/demo-workspace and analyze it — no Power BI Project files of your own are needed, and the bundled copy is never modified. The source lives under src/semantic_model_cleaner/demo_workspace and also supports screenshots, quick validation, and safe public examples.
A richer synthetic QA workspace is available under examples/product-qa-workspace. It exercises trust-critical flows such as Report Health, stale report metadata, broken references, Unsupported Metadata review downgrades, RLS-backed dependencies, and Report Extension Measures.
- CLI:
json,xlsx - Web UI:
Export JSON,Export Excel
Both web exports download the latest completed analysis without re-running it.
CLI exports (full, unused, json, and xlsx) must be saved outside Semantic
Model and Report artifact folders, including artifacts excluded from the analysis.
This also applies to Excel's default output in the current directory. Use
--output to choose an external directory; unsafe destinations return exit code 2
without writing project files. Resolved symlink/junction aliases are checked, and
existing files with multiple hard links are rejected; choose a new output file
instead. Ordinary external export files can still be overwritten.
- The workflow is intentionally
1 semantic model -> 1 or more reports - UI and CLI changes use saved plans with exact previews, validation, source fingerprints and guarded apply
- Every applied plan records a receipt and original bytes for guarded restore; legacy direct-write HTTP routes are withheld
- Field parameters backed by
NAMEOF(...)are supported - Calculation groups are recognized (type, items, selector column, retained parent-table DAX consumers); calculation item expressions remain Analysis limitations and keep unused items at Review
- Culture translations are read structurally as per-object Translation Membership (culture, file and line), shown as informational evidence that never changes the Cleanup Recommendation;
linguisticMetadataremains an Analysis Limitation owned by its culture - Auto-date tables (analysis summary): one group-level result for Power BI generated
LocalDateTable_*/DateTableTemplate_*tables. Either "N auto-date tables detected. All can be removed." with one Preview removal of all auto-date tables action, or "Cannot remove all: dependencies were found [or coverage could not be confirmed]. Nothing will be removed." with a short grouped reason. All or nothing: there is no per-table choice, and the server refuses table lists and older per-table plans. Every table must match the generated structure and have no use in the selected model and reports, including Q&A linguistic metadata (Q&A keys in a letter case other than Power BI Desktop's also block). Their relationships,ref tablelines and date-columnvariations go with them; the date columns stay. The Auto date/time setting is not changed - Delete and rename plans include dependent perspective members and culture translations in their file diffs and recovery data. Unrecognized or malformed perspective/culture structure blocks the plan with a file-specific explanation; expression payloads such as linguistic metadata remain unchecked
- Usage states: the web app separates Used, Indirect, Stale only (referenced only by stale report metadata) and Unused. The CLI
--format unusedlist and the JSONsummary.not_usedtotal include Stale only items, so they can exceed the web app's "Not used" count by exactly those items - Analysis limitations are listed separately from Report Health with distinct-limitation and affected-item counts; remaining caveats include broader metadata indirection and malformed or skipped JSON
Run tests:
python3 -m pytestRun lint:
python3 -m ruff check .Build distributions:
python3 -m buildBuild the Windows package locally:
pwsh -File packaging/windows/build.ps1- Version
0.4.0b10defaults to thebetarelease channel without an environment variable. - Developers can set
SMC_RELEASE_CHANNEL=stableto inspect the stable-gated UI during compatibility testing. - The public beta shows a
Betabanner. Experiments remain separately opt-in.
No experimental features are currently registered. See tests/test_experiments.py for release-channel logic.
See the five-minute repository quick start, CI check contract, and support matrix.
src/semantic_model_cleaner/analyzer.py: CLI analyzer and export logicsrc/semantic_model_cleaner/webapp.py: Flask app and APIsrc/semantic_model_cleaner/tmdl_writer.py: TMDL edit enginesrc/semantic_model_cleaner/templates/index_v2.html: single-page workspace UI templatesrc/semantic_model_cleaner/demo_workspace/: bundled synthetic demo workspaceexamples/product-qa-workspace/: richer synthetic QA workspacescripts/analyze_model_usage.py: compatibility wrapper for the packaged CLIscripts/app.py: compatibility wrapper for the packaged web apptests/: automated tests and fixtures
Contribution guidance is documented in CONTRIBUTING.md.
Planned follow-up work is tracked in BACKLOG.md.
Analyzer-specific usage and caveats are documented in scripts/analyze_model_usage.README.md.
- License: MIT
- Code of Conduct: CODE_OF_CONDUCT.md
- Security reporting: SECURITY.md
- Issues and discussions are monitored on the public GitHub repository.
The CLI and web UI share a staged change-plan engine for model cleanup, renames, measure moves, report extension measure deletion, report-measure promotion and report repairs. Prepare a plan from an operations JSON file, inspect its exact differences, then apply it with freshness checks and a recovery journal:
smc plan /path/to/project --operations operations.json -o review/change.plan.json
smc diff review/change.plan.json
smc apply review/change.plan.json
smc verify review/change.plan.jsonUse smc history to inspect receipts and smc restore review/change.plan.json for guarded recovery. Plans contain local metadata and must come from a trusted source. Static validation covers supported selected files; it does not evaluate Power BI runtime behavior. See CLI plans and recovery for operation examples, scope rules, exit codes and interrupted-operation recovery.
Read CI checks and baselines, supported workflows, and the beta quick start.
External/saved .dax queries (including developer scratch and DAXQueries files) are outside semantic-model and report cleanup scope. They are not analyzed, fingerprinted, staged, changed or restored. Query edits, additions and deletions do not invalidate a cleanup plan. Model TMDL expressions and report-extension DAX remain analyzed.
Scratch query scope includes the exact DAXQueries/.pbi/daxQueries.json editor index. Its contents, including unsupported or malformed state, do not affect cleanup eligibility, coverage or plan drift. Apply and restore preserve concurrent scratch edits, additions and deletions. Declared report resources and files in StaticResources keep their resource guards regardless of extension (including .dax); a declaration that collides with the editor-index path takes precedence. Other JSON and .pbi metadata remain guarded.