Install
$ agentstack add skill-wardawgmalvicious-claude-config-fabric-tmdl ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
TMDL Authoring Rules
Syntax Rules (MUST follow)
- TMDL uses tab indentation — every nesting level is exactly one tab (
\t), NOT spaces. Spaces cause validation errors. - PowerShell: use `
t `` - Bash: use
$'\t'or literal tabs - Objects declared by type + name:
table Customer,column ProductId,measure 'Total Sales' - Names with spaces or special chars (
.,=,:,') must be in single quotes:column 'Order Date' - Descriptions use
///placed ABOVE the object — do NOT use thedescriptionproperty //comments are NOT supported in TMDL- Do NOT add
lineageTagon new objects — it is auto-generated - Multi-line DAX must be enclosed in triple backticks (
`) - Place measures before columns in table definitions
formatStringis required on every measure- Never set
dataTypeon measures — it is inferred from DAX
Naming Conventions
- Tables: business-friendly, no
Fact/Dimprefixes. Plural for facts (Sales), singular for dimensions (Product) - Columns: readable with spaces (
Order Date,Unit Price) - Measures: clear patterns (
Total Sales,# Customers). Time intelligence:[measure],[measure (ly)],[measure (ytd)])
Column Rules
| Property | Rule | |---|---| | dataType | Required. Use int64, decimal, string, dateTime, boolean. Avoid double | | sourceColumn | Must match partition source column name exactly | | isHidden | Set for ID columns, foreign keys, system columns | | summarizeBy | none for non-aggregatable numerics (IDs, postal codes, year numbers) | | isAvailableInMdx | false for hidden columns not used in sort-by or hierarchies | | sortByColumn | For text needing non-alphabetical sort (month names → month number) |
Measure & DAX Rules
- Always set
formatString— Currency:$#,##0.00| Percentage:0.00%| Integer:#,##0| Decimal:#,##0.00 - Use
DIVIDE()instead of/for safe division - Never use
IFERROR— causes performance degradation - Prefix
VARnames with_:VAR _totalSales = ... - Use
displayFolderto organize measures into logical groups - Add
///descriptions to explain business logic
Relationship Rules
fromColumn:= many-side (fact);toColumn:= one-side (dimension)- Create relationships BEFORE measures that depend on them
- Default:
crossFilteringBehavior: oneDirection; addbothDirectionsonly when needed isActive: falsefor role-playing dimensions; useUSERELATIONSHIP()in DAX- Both sides must have matching
dataType - Set
isKey: trueon dimension primary key columns - Hide foreign keys on fact tables (
isHidden: true) - No composite keys — use a single surrogate integer key
Calculation Groups
table 'Time Intelligence'
calculationGroup
calculationItem Current = SELECTEDMEASURE()
calculationItem YTD = CALCULATE(SELECTEDMEASURE(), DATESYTD('Date'[Date]))
column 'Time Intelligence'
dataType: string
partition 'Partition_Time Intelligence' = calculationGroup
calculationGroupkeyword has NO name — just the keyword indented under the table- Partition type must be
= calculationGroup(not= mor= calculated) - Use
formatStringDefinition(notformatString) for calc items that override measure format
Security Roles
role RegionalManager
modelPermission: read
tablePermission Sales = [Region] = "East"
modelPermission:required — usereadorreadRefresh- Assign users via Power BI REST API, not TMDL:
POST .../datasets/{id}/userswithrolesarray - Do NOT use
INFO.ROLES()/INFO.ROLEMEMBERSHIPS()via DAX — unreliable. Use the REST API.
Annotations
- Do NOT add
PBI_*annotations manually — they are Power BI internal metadata - Custom annotations are fine for documentation/tooling
- Syntax: blank line before the first annotation; blank line between annotations; same indent as peer properties
column 'Product Name'
dataType: string
sourceColumn: Product Name
annotation MyTool_Owner = analytics-team
model.tmdl Required Properties
model.tmdl is the root of the definition/ folder alongside database.tmdl, expressions.tmdl, functions.tmdl, relationships.tmdl, roles/, perspectives/, cultures/, and tables/.
model Model
culture: en-US
defaultPowerBIDataSourceVersion: powerBI_V3
discourageImplicitMeasures
sourceQueryCulture: en-US
dataAccessOptions
legacyRedirects
returnErrorValuesAsNull
defaultPowerBIDataSourceVersion: powerBI_V3 is required for Import-mode models — without it, Import from JSON supported for V3 models only.
Direct Lake Configuration
- ALL partitions must use
EntityPartitionSource— no M/Power Query - A named expression pointing to the Lakehouse/Warehouse must be defined before tables:
``tmdl expression DL_Lakehouse = let Source = AzureStorage.DataLake("https://onelake.dfs.fabric.microsoft.com//", [HierarchicalNavigation=true]) in Source ``
- Each table partition references the expression:
``tmdl partition Sales = entity mode: directLake source entityName: Sales schemaName: dbo expressionSource: DL_Lakehouse ``
dataType: binarycolumns are NOT supported in Direct Lake- Columns map directly via
sourceColumn— no transforms
Gotchas
| Issue | Cause | Fix | |---|---|---| | InvalidLineType: Property! in database.tmdl | Bare compatibilityLevel: without database declaration | Start the file with database on line 1 | | Import from JSON supported for V3 models only | Missing defaultPowerBIDataSourceVersion | Add powerBI_V3 to model.tmdl | | Spaces-for-tabs validation errors | Editor converted tabs | Force literal tabs; configure editor not to expand | | // comment ignored or invalid | Not supported | Use /// on line above the object (descriptions only) | | Measure has wrong inferred type | dataType was set manually | Remove dataType from measures — always inferred | | Missing formatString errors | Measure without formatString | Always set per measure; use formatStringDefinition for dynamic | | Calc item format ignored | Used formatString instead of formatStringDefinition | formatStringDefinition is DAX-based; only it overrides the selected measure's format | | Broken report binding after column rename | Stale lineageTag left in place | Never edit lineageTag; let Power BI regenerate only on creation | | Role members ignored | Authored member statically | Assign via Power BI REST API (POST datasets/{id}/users) | | INFO.ROLES() returns stale/missing data | Known DAX surface unreliability | Query membership via REST API | | Calendar name collision | Name unique per-table but not per-model | Calendar names must be globally unique across the model | | Direct Lake partition errors | binary column in source | Cast away in upstream Lakehouse/Warehouse; drop the column | | Perspective appears empty in Power BI | No perspectiveTable children | Add at least one table + column/measure, or includeAll on a table | | model.bim and definition/ both present | Forgot to delete .bim after TMDL conversion | Remove model.bim; they are mutually exclusive | | TMDL conversion fails | Old Microsoft.AnalysisServices.retail.amd64 | Upgrade NuGet package for TmdlSerializer | | Hierarchy level references missing column | Column removed or renamed without updating level | level.column: must reference an existing same-table column | | PBI_* annotation edits revert | Power BI rewrites on save | Do not hand-author PBI internal annotations |
Additional reference
- Microsoft Learn: TMDL language overview
- Microsoft Learn: TMDL view in Power BI Desktop
- Microsoft Learn: Power BI Desktop project semantic model folder (PBIP)
- Companion [references/REFERENCE.md](references/REFERENCE.md): per-object property tables (
database,model,table,column,measure,relationship,hierarchy,partition,calculationGroup,role,perspective,cultureInfo,expression,function,dataSource,refreshPolicy,calendar,queryGroup), BIM ↔ TMDL conversion procedure, enum value lists, and a comprehensive MS Learn link bundle (TMDL syntax / TMDL view / PBIP folder / calculation groups / Direct Lake / DAX / TMSL / TOM).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wardawgmalvicious
- Source: wardawgmalvicious/claude-config
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.