examples/AccountsCreatedThisYear.report-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns="http://soap.sforce.com/2006/04/metadata">
<name>Accounts Created This Year</name>
<reportType>AccountList</reportType>
<format>Summary</format>
<scope>organization</scope>
<description>Shows accounts created in the current fiscal year, grouped by industry. Demonstrates a filtered report with timeFrameFilter, row-level filter, and date-based scoping on a non-Opportunity report type.</description>
<showDetails>true</showDetails>
<showGrandTotal>true</showGrandTotal>
<showSubTotals>true</showSubTotals>
<columns>
<field>ACCOUNT_NAME</field>
</columns>
<columns>
<field>INDUSTRY</field>
</columns>
<columns>
<field>TYPE</field>
</columns>
<columns>
<field>ANNUAL_REVENUE</field>
<aggregateTypes>Sum</aggregateTypes>
<aggregateTypes>Average</aggregateTypes>
</columns>
<columns>
<field>CREATED_DATE</field>
</columns>
<columns>
<field>OWNER_FULL_NAME</field>
</columns>
<groupingsDown>
<field>INDUSTRY</field>
<dateGranularity>None</dateGranularity>
<sortOrder>Asc</sortOrder>
</groupingsDown>
<filter>
<criteriaItems>
<column>TYPE</column>
<isUnlocked>true</isUnlocked>
<operator>notEqual</operator>
<value>Analyst,Press</value>
</criteriaItems>
</filter>
<timeFrameFilter>
<dateColumn>CREATED_DATE</dateColumn>
<interval>INTERVAL_CURY</interval>
</timeFrameFilter>
</Report>
examples/OpportunitiesByStageAndQuarter.report-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns="http://soap.sforce.com/2006/04/metadata">
<name>Opportunities Stage x Quarter</name>
<reportType>Opportunity</reportType>
<format>Matrix</format>
<scope>organization</scope>
<description>Cross-tabulates opportunities by stage (rows) and close date quarter (columns) with sum of amount. Demonstrates a Matrix report with both row and column groupings and aggregates.</description>
<showDetails>false</showDetails>
<showGrandTotal>true</showGrandTotal>
<showSubTotals>true</showSubTotals>
<columns>
<field>OPPORTUNITY_NAME</field>
</columns>
<columns>
<field>ACCOUNT_NAME</field>
</columns>
<columns>
<field>STAGE_NAME</field>
</columns>
<columns>
<field>AMOUNT</field>
<aggregateTypes>Sum</aggregateTypes>
</columns>
<columns>
<field>CLOSE_DATE</field>
</columns>
<groupingsDown>
<field>STAGE_NAME</field>
<dateGranularity>None</dateGranularity>
<sortOrder>Asc</sortOrder>
</groupingsDown>
<groupingsAcross>
<field>CLOSE_DATE</field>
<dateGranularity>FiscalQuarter</dateGranularity>
<sortOrder>Asc</sortOrder>
</groupingsAcross>
<params>
<name>open</name>
<value>all</value>
</params>
<params>
<name>probability</name>
<value>>0</value>
</params>
<params>
<name>co</name>
<value>1</value>
</params>
<timeFrameFilter>
<dateColumn>CLOSE_DATE</dateColumn>
<interval>INTERVAL_CURY</interval>
</timeFrameFilter>
</Report>
examples/OpportunitiesByStageReport.report-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns="http://soap.sforce.com/2006/04/metadata">
<name>Opportunities by Stage</name>
<reportType>Opportunity</reportType>
<format>Summary</format>
<scope>organization</scope>
<description>Groups open opportunities by stage with a sum of amount, and includes a vertical bar chart. Demonstrates a Summary report with one grouping, an aggregate column, and an embedded chart.</description>
<showDetails>true</showDetails>
<showGrandTotal>true</showGrandTotal>
<showSubTotals>true</showSubTotals>
<columns>
<field>OPPORTUNITY_NAME</field>
</columns>
<columns>
<field>ACCOUNT_NAME</field>
</columns>
<columns>
<field>STAGE_NAME</field>
</columns>
<columns>
<field>AMOUNT</field>
<aggregateTypes>Sum</aggregateTypes>
</columns>
<columns>
<field>CLOSE_DATE</field>
</columns>
<columns>
<field>PROBABILITY</field>
<aggregateTypes>Average</aggregateTypes>
</columns>
<columns>
<field>FULL_NAME</field>
</columns>
<groupingsDown>
<field>STAGE_NAME</field>
<dateGranularity>None</dateGranularity>
<sortOrder>Asc</sortOrder>
</groupingsDown>
<filter>
<criteriaItems>
<column>STAGE_NAME</column>
<isUnlocked>true</isUnlocked>
<operator>notEqual</operator>
<value>Closed Won,Closed Lost</value>
</criteriaItems>
</filter>
<params>
<name>open</name>
<value>all</value>
</params>
<params>
<name>probability</name>
<value>>0</value>
</params>
<params>
<name>co</name>
<value>1</value>
</params>
<timeFrameFilter>
<dateColumn>CLOSE_DATE</dateColumn>
<interval>INTERVAL_CURY</interval>
</timeFrameFilter>
<chart>
<chartType>VerticalColumn</chartType>
<groupingColumn>STAGE_NAME</groupingColumn>
<chartSummaries>
<aggregate>Sum</aggregate>
<column>AMOUNT</column>
</chartSummaries>
<enableHoverLabels>true</enableHoverLabels>
<location>CHART_TOP</location>
<size>Medium</size>
<title>Pipeline by Stage</title>
</chart>
</Report>
examples/TabularOpportunitiesReport.report-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<Report xmlns="http://soap.sforce.com/2006/04/metadata">
<name>New Opportunities Report</name>
<reportType>Opportunity</reportType>
<format>Tabular</format>
<scope>organization</scope>
<description>Lists all new opportunities with key fields for pipeline review. Demonstrates a simple tabular report — no groupings, no chart.</description>
<showDetails>true</showDetails>
<columns>
<field>OPPORTUNITY_NAME</field>
</columns>
<columns>
<field>ACCOUNT_NAME</field>
</columns>
<columns>
<field>STAGE_NAME</field>
</columns>
<columns>
<field>AMOUNT</field>
</columns>
<columns>
<field>CLOSE_DATE</field>
</columns>
<columns>
<field>PROBABILITY</field>
</columns>
<columns>
<field>LEAD_SOURCE</field>
</columns>
<columns>
<field>FULL_NAME</field>
</columns>
<params>
<name>open</name>
<value>all</value>
</params>
<params>
<name>probability</name>
<value>>0</value>
</params>
<params>
<name>co</name>
<value>1</value>
</params>
<timeFrameFilter>
<dateColumn>CLOSE_DATE</dateColumn>
<interval>INTERVAL_CURRENT</interval>
</timeFrameFilter>
</Report>
references/chart-types.md
# Chart Types Reference
Charts can only be added to Summary or Matrix reports. A Tabular report with a `<chart>` element will fail deployment.
## Available Chart Types
| Chart Type | Category | Notes |
|-----------|----------|-------|
| `HorizontalBar` | Bar | Single-series horizontal bar |
| `HorizontalBarGrouped` | Bar | Grouped horizontal bars (requires secondaryGroupingColumn) |
| `HorizontalBarStacked` | Bar | Stacked horizontal bars |
| `HorizontalBarStackedTo100` | Bar | Stacked to 100% |
| `VerticalColumn` | Column | Single-series vertical column |
| `VerticalColumnGrouped` | Column | Grouped vertical columns |
| `VerticalColumnStacked` | Column | Stacked vertical columns |
| `VerticalColumnStackedTo100` | Column | Stacked to 100% |
| `Line` | Line | Single-series line |
| `LineGrouped` | Line | Grouped line chart |
| `LineCumulative` | Line | Cumulative line chart |
| `LineCumulativeGrouped` | Line | Grouped cumulative line |
| `Pie` | Circular | Pie chart |
| `Donut` | Circular | Donut chart |
| `Funnel` | Other | Funnel chart |
| `Scatter` | Other | Scatter chart |
| `ScatterGrouped` | Other | Grouped scatter chart |
## legendPosition
`legendPosition` is only accepted on some chart types. On the others, ANY value fails with `chart-legendPosition: Invalid value specified: Right` — omit the element.
| Chart types | Accepted `legendPosition` |
|-------------|---------------------------|
| Single-series `HorizontalBar`, `VerticalColumn`, `Line`, `LineCumulative` | None — omit it |
| Grouped/stacked (`VerticalColumnGrouped`, `HorizontalBarStacked`, …) | `Right`, `Bottom` (`OnChart` fails) |
| `Pie`, `Donut`, `Funnel`, `Scatter` | `Right`, `Bottom`, `OnChart` |
## Allowed `<chart>` Child Elements
Use only these elements inside `<chart>`. Anything else (e.g. `<summaryAxisManualRangeEnabled>`, `<showInlineChart>`) fails with `Element ... invalid at this location in type ReportChart`.
`backgroundColor1`, `backgroundColor2`, `backgroundFadeDir`, `chartSummaries` (`aggregate`, `axisBinding`, `column`), `chartType`, `enableHoverLabels`, `expandOthers`, `groupingColumn`, `legendPosition`, `location`, `secondaryGroupingColumn`, `showAxisLabels`, `showPercentage`, `showTotal`, `showValues`, `size`, `summaryAxisRange` (`Auto` or `Manual`), `textColor`, `textSize`, `title`, `titleColor`, `titleSize`.
A minimal chart needs only `chartType`, `groupingColumn`, `chartSummaries`, and `location`.
## Record Count Charts
To chart a record count, `<chartSummaries>` holds ONLY `<column>RowCount</column>` — no `<aggregate>`. `Sum` with `RowCount` fails with `aggregate type cannot be specified with RowCount summary`, and `Count` is not a valid aggregate at all.
```xml
<chartSummaries>
<column>RowCount</column>
</chartSummaries>
```
For any other column, `<aggregate>` is required and must be `Sum`, `Average`, `Maximum`, or `Minimum`.
references/column-names.md
# Column Names by Report Type
Report metadata uses **platform report column names**, NOT raw API field names. These names are report-type-specific — ALWAYS verify using MCP tools (`get_metadata_type_sections` or `get_metadata_type_context`).
## Standard Report Type API Names
Use the API name, never a name guessed from the UI label. There is NO `AccountContact` report type.
| UI label | `<reportType>` |
|----------|----------------|
| Accounts | `AccountList` |
| Accounts with Contacts / Accounts with Contact Roles | `AccountContactRole` |
| Contacts & Accounts | `ContactList` |
| Opportunities | `Opportunity` |
| Opportunities with Products | `OpportunityProduct` |
| Cases | `CaseList` |
| Leads | `LeadList` |
## Opportunity
| Object.Field | Report Column Name |
|-------------|-------------------|
| Opportunity.Name | `OPPORTUNITY_NAME` |
| Opportunity.Amount | `AMOUNT` |
| Opportunity.CloseDate | `CLOSE_DATE` |
| Opportunity.StageName | `STAGE_NAME` |
| Opportunity.Owner | `FULL_NAME` (NOT `OWNER_FULL_NAME` or `OWNER_NAME`) |
| Account.Name | `ACCOUNT_NAME` |
| Opportunity.CreatedDate | `CREATED_DATE` |
| Opportunity.Probability | `PROBABILITY` |
| Opportunity.Type | `TYPE` |
| Opportunity.LeadSource | `LEAD_SOURCE` |
## CaseList
| Object.Field | Report Column Name |
|-------------|-------------------|
| Case.CaseNumber | `CASE_NUMBER` |
| Case.Subject | `SUBJECT` |
| Case.Status | `STATUS` |
| Case.Priority | `PRIORITY` |
| Case.Owner | `OWNER` (NOT `OWNER_NAME` or `OWNER_FULL_NAME`) |
| Case.CreatedDate | `CREATED_DATE` |
## LeadList
| Object.Field | Report Column Name |
|-------------|-------------------|
| Lead.FirstName | `FIRST_NAME` |
| Lead.LastName | `LAST_NAME` |
| Lead.Company | `COMPANY` |
| Lead.Status | `STATUS` |
| Lead.LeadSource | `LEAD_SOURCE` |
| Lead.CreatedDate | `CREATED_DATE` |
## AccountList
| Object.Field | Report Column Name |
|-------------|-------------------|
| Account.Name | `ACCOUNT_NAME` |
| Account.Id | `ACCOUNT_ID` |
## AccountContactRole
| Object.Field | Report Column Name |
|-------------|-------------------|
| Contact.FirstName | `FIRST_NAME` (NOT `FULL_NAME` or `CONTACT_NAME`) |
| Contact.LastName | `LAST_NAME` |
| Contact.Title | `TITLE` (NOT `CONTACT_TITLE`) |
| Contact.Email | `EMAIL` (NOT `CONTACT_EMAIL`) |
| Contact.Phone | `PHONE1` (NOT `CONTACT_PHONE`) |
| Contact.MailingCity | `ADDRESS2_CITY` (NOT `CONTACT_MAILINGCITY`) |
| Account.Name | `ACCOUNT.NAME` (NOT `ACCOUNT_NAME` — uses dot notation) |
| AccountContactRole.Role | `ROLE` |
### AccountContactRole FILTER columns
Filter `<column>` values use plain names for Account fields — NOT dot notation:
- Use `INDUSTRY` (not `ACCOUNT.INDUSTRY`)
- Use `TYPE` (not `ACCOUNT.TYPE`)
- Use `ACCOUNT_ID` (not `ACCOUNT.ID`)
- Only `ACCOUNT.NAME` uses dot notation (for display columns and groupings only)
## Common Mistakes
- `RowCount` in `<columns><field>` → NEVER valid (fails with `columns-field: Invalid value specified: RowCount`). `RowCount` is valid only in `<chartSummaries><column>`, as a `<sortByName>` value, or inside a `<calculatedFormula>`; a Summary/Matrix report shows the record count per grouping without any column
- Bare `NAME` or `USERS.NAME` → NEVER valid on any standard report type (fails with `columns-field: Invalid value specified: NAME` / `Grouping: Invalid value specified: USERS.NAME`). Pick the name column for the report type from the tables above:
- Opportunity name → `OPPORTUNITY_NAME`; opportunity owner → `FULL_NAME`; account → `ACCOUNT_NAME`
- Case or Lead owner → `OWNER`
- Lead or contact person → `FIRST_NAME` + `LAST_NAME`
- Account (AccountList) → `ACCOUNT_NAME`; account on AccountContactRole → `ACCOUNT.NAME`
- `USERS.NAME` as the owner → `OWNER` (CaseList, LeadList) or `FULL_NAME` (Opportunity)
- `CASENUMBER` → `CASE_NUMBER` (CaseList)
- `ISCLOSED` filter → NOT a valid filter column; to exclude closed cases filter `STATUS` `notEqual` `Closed`
- `PHONE` → `PHONE1` (AccountContactRole)
- `MAILING_CITY` → `ADDRESS2_CITY` (AccountContactRole)
- `FULL_NAME`, `ACCOUNT_NAME` on AccountContactRole → `FIRST_NAME` + `LAST_NAME`, `ACCOUNT.NAME`
- Never derive a column from the field API name (`CaseNumber` → `CASENUMBER`, `IsClosed` → `ISCLOSED`); take it from the table for the report type
- `OWNER_FULL_NAME` → Use `FULL_NAME` (Opportunity) or `OWNER` (Case/Lead)
- `OWNER_NAME` → Use `OWNER` (CaseList) or `FULL_NAME` (Opportunity)
- `CONTACT_NAME` → Verify per report type; some use `FIRST_NAME` + `LAST_NAME`
- `ACCOUNT_NAME` → For AccountContactRole, use `ACCOUNT.NAME` (dot notation)
- `FULL_NAME` → NOT valid for AccountContactRole; use `FIRST_NAME` + `LAST_NAME`
## Custom Fields
Custom fields use the format `<ObjectApiName>.<FieldApiName__c>` (e.g., `Opportunity.Custom_Field__c`).
## Custom Report Types
A report built on a custom report type (`reportTypes/<Name>.reportType-meta.xml`) follows different naming than standard report types:
- `<reportType>` is the developer name **plus `__c`**: `Accounts_with_Projects__c`.
- Every column, grouping, filter, chart, and time-frame column is a `$` path built from the report type's section `<table>` and `<field>`: `<table>$<field>`.
- Only fields listed in the report type's `<sections>` are valid. Do not add a `<timeFrameFilter>` on a date field (e.g. `CreatedDate`) the layout does not include.
For a report type with `<baseObject>Account</baseObject>` joined through `<relationship>Projects__r</relationship>`:
| Section `<table>` | Section `<field>` | Report column |
|-------------------|-------------------|---------------|
| `Account` | `Name` | `Account$Name` (NOT `ACCOUNT_NAME`) |
| `Account.Projects__r` | `Name` | `Account.Projects__r$Name` (NOT `Project__c.Name`) |
| `Account.Projects__r` | `Budget_Amount__c` | `Account.Projects__r$Budget_Amount__c` |
references/date-intervals.md
# Date Intervals Reference
Only use values from this table. Do NOT invent interval names like `INTERVAL_CURQ` — they will cause deployment failures.
## Fiscal Intervals (use when org has fiscal year configured)
| Interval | Description |
|----------|-------------|
| `INTERVAL_CURRENT` | **Current fiscal quarter** — use this for "this quarter" or "current quarter" |
| `INTERVAL_CURNEXT1` | Current + next fiscal quarter |
| `INTERVAL_CURPREV1` | Previous + current fiscal quarter |
| `INTERVAL_NEXT1` | Next fiscal quarter |
| `INTERVAL_PREV1` | Previous fiscal quarter |
| `INTERVAL_CURNEXT3` | Current + next 3 fiscal quarters |
| `INTERVAL_CURFY` | Current fiscal year |
| `INTERVAL_PREVFY` | Previous fiscal year |
| `INTERVAL_NEXTFY` | Next fiscal year |
| `INTERVAL_PREVCURFY` | Previous + current fiscal year |
## Calendar Intervals
| Interval | Description |
|----------|-------------|
| `INTERVAL_CURRENTQ` | Current calendar quarter |
| `INTERVAL_NEXTQ` | Next calendar quarter |
| `INTERVAL_PREVQ` | Previous calendar quarter |
| `INTERVAL_CURY` | Current calendar year |
| `INTERVAL_PREVY` | Previous calendar year |
| `INTERVAL_NEXTY` | Next calendar year |
| `INTERVAL_PREVCURY` | Previous + current calendar year |
| `INTERVAL_THISMONTH` | This month |
| `INTERVAL_LASTMONTH` | Last month |
| `INTERVAL_NEXTMONTH` | Next month |
| `INTERVAL_THISWEEK` | This week |
| `INTERVAL_LASTWEEK` | Last week |
| `INTERVAL_NEXTWEEK` | Next week |
## Day-Based Intervals
| Interval | Description |
|----------|-------------|
| `INTERVAL_YESTERDAY` | Yesterday |
| `INTERVAL_TODAY` | Today |
| `INTERVAL_TOMORROW` | Tomorrow |
| `INTERVAL_LAST7` | Last 7 days |
| `INTERVAL_LAST30` | Last 30 days |
| `INTERVAL_LAST60` | Last 60 days |
| `INTERVAL_LAST90` | Last 90 days |
| `INTERVAL_LAST120` | Last 120 days |
| `INTERVAL_NEXT7` | Next 7 days |
| `INTERVAL_NEXT30` | Next 30 days |
| `INTERVAL_NEXT60` | Next 60 days |
| `INTERVAL_NEXT90` | Next 90 days |
| `INTERVAL_NEXT120` | Next 120 days |
## Custom
| Interval | Description |
|----------|-------------|
| `INTERVAL_CUSTOM` | Custom date range — requires `<startDate>` and `<endDate>` |
references/errors-and-troubleshooting.md
# Common Authoring Errors
Read this when a generated `.report-meta.xml` is rejected during deployment or fields don't appear in the report. Use these to validate the authored XML before handing it off; deployment itself is outside this skill's scope.
| Error | Cause | Fix |
|-------|-------|-----|
| `Invalid report type 'X'` | Report type doesn't exist or isn't deployed in the target org | Verify the report type API name. For custom report types, ensure `<deployed>true</deployed>` is set. Use `platform-custom-report-type-generate` skill to create if missing |
| `Invalid field 'X' for report type 'Y'` | Column name not recognized for the report type — used raw field API name instead of platform column name | Use platform column names (e.g. `ACCOUNT_NAME` not `Account.Name`). For custom fields, use `ObjectApiName.FieldApiName__c`. Use `get_metadata_type_shape` MCP tool to discover valid column names |
| `Grouping field 'X' not found in columns` | A `<groupingsDown>` or `<groupingsAcross>` field is not also listed as a `<columns>` entry | Add the grouping field as a `<columns>` block |
| `Chart not valid for Tabular format` | `<chart>` element present on a Tabular report | Remove the chart or change format to `Summary` or `Matrix` |
| `Summary report requires at least one grouping` | Format is `Summary` but no `<groupingsDown>` is defined | Add at least one `<groupingsDown>` block or change format to `Tabular` |
| `Matrix report requires row and column groupings` | Format is `Matrix` but `<groupingsDown>` or `<groupingsAcross>` is missing | Add both row and column groupings |
| `Tabular report cannot have groupings` | `<groupingsDown>` or `<groupingsAcross>` present on a Tabular report | Remove groupings or change format to `Summary`/`Matrix` |
| `Invalid filter operation 'X'` | Typo or unsupported operation value | Use a valid operation from `filter-operations.md` |
| `Filter logic references filter N but only M filters exist` | `<filterLogic>` references more filters than defined | Ensure filter numbers in the logic match the actual filter count |
| `Report folder not found` | Report file not inside a valid folder directory, or folder metadata file missing | Ensure the file is under `<sourceDir>/reports/<FolderName>/` (check sfdx-project.json for source path) and a `<FolderName>-meta.xml` exists |
| `Too many cross filters` | More than 3 `<crossFilters>` elements | Reduce to 3 or fewer cross-filters |
| `Joined report requires at least 2 blocks` | `<format>` is `Joined` but fewer than 2 `<block>` elements | Add at least 2 block elements |
| `Block format cannot be Tabular` | A `<block>` inside a Joined report has `<format>Tabular</format>` | Change block format to `Summary` or `Matrix` |
| `Aggregate types not valid for Tabular format` | `<aggregateTypes>` specified on a column in a Tabular report | Remove aggregates or change format to `Summary`/`Matrix` |
| `Invalid date interval 'X'` | Typo in `<interval>` value inside `<timeFrameFilter>` | Use a valid interval constant (e.g. `INTERVAL_CURRENT`, `INTERVAL_CURY`) |
| `Custom start/end date required for INTERVAL_CUSTOM` | Interval is `INTERVAL_CUSTOM` but `<startDate>` or `<endDate>` is missing | Add both `<startDate>` and `<endDate>` in `YYYY-MM-DD` format |
## Common Pitfalls
### Pitfall 1: Using API Field Names Instead of Platform Column Names
**Wrong:**
```xml
<columns>
<field>Account.Name</field> <!-- raw API name -->
</columns>
```
**Right:**
```xml
<columns>
<field>ACCOUNT_NAME</field> <!-- platform column name -->
</columns>
```
Standard fields have specific platform column names (e.g. `OPPORTUNITY_NAME`, `STAGE_NAME`, `CLOSE_DATE`). Custom fields use the format `ObjectApiName.FieldApiName__c`.
### Pitfall 2: Forgetting Grouping Fields in Columns
Every field used in `<groupingsDown>` or `<groupingsAcross>` must also be present as a `<columns>` entry. Missing the column causes the grouping to fail.
### Pitfall 3: Mismatched Format and Structure
| If you want... | Use format | Must have |
|----------------|------------|-----------|
| Flat list | `Tabular` | Only `<columns>`, NO groupings |
| Grouped rows | `Summary` | `<columns>` + `<groupingsDown>` |
| Cross-tab | `Matrix` | `<columns>` + `<groupingsDown>` + `<groupingsAcross>` |
| Multi-source | `Joined` | `<block>` elements (2-5), each with own columns/groupings |
### Pitfall 4: Chart Summary Column Syntax
The `<summaryColumn>` in a chart uses a special syntax for aggregate references:
- `s!AMOUNT` — Sum of Amount
- `a!AMOUNT` — Average of Amount
- `m!AMOUNT` — Max of Amount
- `x!AMOUNT` — Min of Amount
- `RowCount` — Record count (valid only here, in `<sortByName>`, and in a `<calculatedFormula>`; never as a `<columns><field>`)
### Pitfall 5: Joined Report Restrictions
- Joined reports do NOT support top-level `<chart>`, `<columns>`, or `<groupingsDown>` — everything goes inside `<block>` elements
- Each block must have its own `<reportType>` — blocks can use different report types
- Blocks align on common grouping fields for cross-block comparison
- Block format must be `Summary` or `Matrix`, never `Tabular`
references/filter-operations.md
# Filter Operations Reference
The `<operation>` element in a `<filter>` block determines how the field value is compared. Use these values exactly as shown.
## Text & Picklist Operations
| Operation | Description | `<value>` Required | Example |
|-----------|-------------|-------------------|---------|
| `equals` | Exact match (case-insensitive for text) | Yes | `<value>Closed Won</value>` |
| `notEqual` | Does not equal | Yes | `<value>Closed Lost</value>` |
| `contains` | Contains substring | Yes | `<value>Enterprise</value>` |
| `notContain` | Does not contain substring | Yes | `<value>Test</value>` |
| `startsWith` | Starts with prefix | Yes | `<value>Acme</value>` |
## Numeric & Currency Operations
| Operation | Description | `<value>` Required | Example |
|-----------|-------------|-------------------|---------|
| `equals` | Equal to | Yes | `<value>100000</value>` |
| `notEqual` | Not equal to | Yes | `<value>0</value>` |
| `lessThan` | Less than | Yes | `<value>50000</value>` |
| `greaterThan` | Greater than | Yes | `<value>100000</value>` |
| `lessOrEqual` | Less than or equal to | Yes | `<value>50000</value>` |
| `greaterOrEqual` | Greater than or equal to | Yes | `<value>100000</value>` |
## Multi-Select Picklist Operations
| Operation | Description | `<value>` Required | Example |
|-----------|-------------|-------------------|---------|
| `includes` | Includes any of the specified values | Yes | `<value>Web;Phone</value>` (semicolon-separated) |
| `excludes` | Excludes all of the specified values | Yes | `<value>Other;Unknown</value>` |
## Blank / Null Operations
| Operation | Description | `<value>` Required | Example |
|-----------|-------------|-------------------|---------|
| `isBlank` | Field is null or empty | No | (no `<value>` element needed) |
| `notBlank` | Field is not null and not empty | No | (no `<value>` element needed) |
```xml
<filter>
<field>ACCOUNT_NAME</field>
<operation>notBlank</operation>
</filter>
```
## Geolocation Operations
| Operation | Description | `<value>` Required | Example |
|-----------|-------------|-------------------|---------|
| `within` | Within specified distance | Yes | `<value>DISTANCE(BillingAddress, GEOLOCATION(37.7749,-122.4194), 'mi') < 50</value>` |
## Multiple Values in a Single Filter
For `equals` and `notEqual` operations on picklist fields, separate multiple values with commas:
```xml
<filter>
<field>STAGE_NAME</field>
<operation>notEqual</operation>
<value>Closed Won,Closed Lost</value>
</filter>
```
## Filter Logic
Use `<filterLogic>` to combine filters with AND/OR/NOT logic. Filters are numbered starting from 1 in the order they appear in the XML.
```xml
<filter>
<field>STAGE_NAME</field>
<operation>equals</operation>
<value>Prospecting</value>
</filter>
<filter>
<field>AMOUNT</field>
<operation>greaterThan</operation>
<value>10000</value>
</filter>
<filter>
<field>LEAD_SOURCE</field>
<operation>equals</operation>
<value>Web</value>
</filter>
<filterLogic>1 AND (2 OR 3)</filterLogic>
```
**Rules:**
- Every filter must be referenced in the logic expression
- Parentheses control evaluation order
- Supported operators: `AND`, `OR`, `NOT`
- Maximum 20 filters per report
- Without `<filterLogic>`, all filters are combined with AND
references/summary-formulas-sorting-limits.md
# Custom Summary Formulas, Sorting & Row Limits
Covers three report-metadata capabilities beyond the core columns/groupings/filters:
custom summary formulas (`<aggregates>`), report and grouping sort
(`<sortColumn>` / `<sortOrder>` / grouping `<sortType>`), and tabular row limit /
top-N (`<rowLimit>`). See Rules 16–18 in `SKILL.md`.
## Custom Summary Formulas (`<aggregates>`)
Custom summary formulas (CSFs) compute a value from a report's summaries. They are valid
**only** in `Summary`, `Matrix`, and `Joined` reports.
**Summary report** (no `<acrossGroupingContext>`):
```xml
<aggregates>
<calculatedFormula>AMOUNT:SUM / RowCount</calculatedFormula>
<datatype>currency</datatype>
<developerName>FORMULA1</developerName>
<downGroupingContext>GRAND_SUMMARY</downGroupingContext>
<isActive>true</isActive>
<isCrossBlock>false</isCrossBlock>
<masterLabel>Avg Deal Size</masterLabel>
<scale>2</scale>
</aggregates>
```
**Matrix report only**: add `<acrossGroupingContext>` next to `<downGroupingContext>`:
```xml
<acrossGroupingContext>GRAND_SUMMARY</acrossGroupingContext>
<downGroupingContext>GRAND_SUMMARY</downGroupingContext>
```
| Sub-element | Notes |
|-------------|-------|
| `<developerName>` | Unique per report (`FORMULA1`, `FORMULA2`, …). Referenced by charts and grouping sort (`<sortByName>` with `<sortType>CustomSummaryFormula</sortType>`). |
| `<calculatedFormula>` | Uses summary references such as `AMOUNT:SUM`, `AMOUNT:AVG`, and `RowCount`. |
| `<datatype>` | `number`, `currency`, or `percent`. |
| `<scale>` | Decimal places (0–18). |
| `<downGroupingContext>` | `GRAND_SUMMARY` or a 0-based grouping level (`0`, `1`, …). Required. |
| `<acrossGroupingContext>` | Matrix only; `GRAND_SUMMARY` or a 0-based across-grouping level. |
| `<isCrossBlock>` | `true` only for cross-block formulas in Joined reports. |
Include `<acrossGroupingContext>` **only** for Matrix reports. On a Summary report it fails
to deploy with `acrossBreakContext not allowed for summary reports, only for matrix reports`
— use `<downGroupingContext>` alone. A grouping context that references a level the report
does not have is also a deployment failure.
## Sorting (`<sortColumn>`, `<sortOrder>`, grouping `<sortType>`)
**Sort detail rows** (Tabular, or the detail area of Summary/Matrix):
```xml
<sortColumn>AMOUNT</sortColumn>
<sortOrder>Desc</sortOrder>
```
The `<sortColumn>` must be a platform column name that also appears in `<columns>`.
`<sortOrder>` is case-sensitive — `Asc` or `Desc`.
**Sort a grouping by its own value:**
```xml
<groupingsDown>
<field>STAGE_NAME</field>
<sortOrder>Asc</sortOrder>
</groupingsDown>
```
**Sort a grouping by a summary** (e.g. show the group with the biggest total first):
```xml
<groupingsDown>
<field>STAGE_NAME</field>
<sortType>Aggregate</sortType>
<sortByName>AMOUNT</sortByName>
<sortOrder>Desc</sortOrder>
</groupingsDown>
```
With `<sortType>Aggregate</sortType>`, `<sortByName>` = a summarized column name (e.g.
`AMOUNT`, which must carry an `<aggregateTypes>`, or `RowCount`). Do NOT use the Analytics
REST `s!` prefix here — in report metadata the plain column name is required. Default
`<sortType>` is `Column` (sort by the grouping's own value).
**Sort a grouping by a custom summary formula**: use `<sortType>CustomSummaryFormula</sortType>`
with the CSF's `<developerName>`:
```xml
<groupingsDown>
<field>STAGE_NAME</field>
<sortType>CustomSummaryFormula</sortType>
<sortByName>FORMULA1</sortByName>
<sortOrder>Desc</sortOrder>
</groupingsDown>
```
Do NOT pair `<sortType>Aggregate</sortType>` with a CSF name: it deploys without error but
the sort silently falls back to the grouping field.
## Row Limit / Top-N (`<rowLimit>`)
Row Limit restricts a **Tabular** report to the top or bottom N rows — commonly used for
"Top N" dashboard table components. It requires a sort column that defines the ranking.
```xml
<format>Tabular</format>
<rowLimit>10</rowLimit>
<sortColumn>AMOUNT</sortColumn>
<sortOrder>Desc</sortOrder>
```
- `Desc` → top N; `Asc` → bottom N.
- Valid only on `Tabular`; requires `<sortColumn>` + `<sortOrder>`.
- Value 1–99.
Setting `<rowLimit>` on a Summary/Matrix report, or without a sort column, fails to deploy.
references/verification-checklist.md
# Verification Checklist
Run through these checks before deploying any generated report metadata.
## Before Writing the XML
- [ ] Check every `<field>` in `<columns>`, `<groupingsDown>`, and `<groupingsAcross>`, every filter `<column>`, and the chart `<groupingColumn>` against the column table for the report type in `references/column-names.md` (or the MCP column list). No bare `NAME` or `USERS.NAME` — use the report type's name column (e.g. `OPPORTUNITY_NAME`, `FULL_NAME`, `OWNER`, `FIRST_NAME` + `LAST_NAME`)
## Universal Checks
- [ ] File extension is `.report-meta.xml`
- [ ] File is placed under `<sourceDir>/reports/<FolderName>/` (check sfdx-project.json for source path)
- [ ] Folder metadata file exists at `<sourceDir>/reports/<FolderName>-meta.xml`
- [ ] `<name>` is human-readable and under 40 characters
- [ ] `<reportType>` is a valid, deployed report type API name
- [ ] `<format>` is one of: `Tabular`, `Summary`, `Matrix`, `Joined`
- [ ] `<scope>` is set (default `organization`; LeadList uses `org`)
- [ ] `<description>` explains the business purpose (max 255 chars)
- [ ] All column `<field>` values use correct platform column names
- [ ] Custom field columns use `<ObjectApiName>.<FieldApiName__c>` format
- [ ] Each `<columns>` contains exactly one `<field>`
- [ ] Custom report type: `<reportType>` ends in `__c` and every column uses a `<table>$<field>` path from the report type's sections
## Format-Specific Checks
- [ ] Tabular: no `<groupingsDown>`, no `<groupingsAcross>`, no `<chart>`, no `<aggregateTypes>`
- [ ] Summary: at least 1 `<groupingsDown>` (max 3), no `<groupingsAcross>`
- [ ] Matrix: at least 1 `<groupingsDown>` AND at least 1 `<groupingsAcross>` (max 3 each)
- [ ] Joined: at least 2 `<block>` elements (max 5), no top-level columns/groupings
## Filter Checks
- [ ] Each `<filter>` contains `<criteriaItems>` with a valid `<operator>`
- [ ] Each `<criteriaItems>` has a `<column>` using the correct platform column name
- [ ] `<value>` is present when required by the operator
- [ ] `<filterLogic>` references all filters by number if used
- [ ] `<timeFrameFilter>` uses a valid `<interval>` value from `references/date-intervals.md`
- [ ] Date columns use platform column names (e.g. `CLOSE_DATE`, not `CloseDate`)
- [ ] Multi-value picklist uses ONE criteriaItem with comma-separated values
- [ ] No `<params>` the request didn't ask for; Opportunity `probability` param is only `>0`
## Grouping Checks
- [ ] `<dateGranularity>` is set for every grouping (use `None` for non-date fields)
- [ ] `<sortOrder>` is `Asc` or `Desc`
- [ ] Grouping fields do NOT also appear in `<columns>`
## Chart Checks (if applicable)
- [ ] Chart is only on Summary or Matrix report
- [ ] `<chartType>` is a valid type from `references/chart-types.md`
- [ ] `<groupingColumn>` matches a grouping field
- [ ] `<chartSummaries>` contains valid `<aggregate>` + `<column>`, or ONLY `<column>RowCount</column>` with no `<aggregate>`
- [ ] No `<columns><field>RowCount</field></columns>` — `RowCount` is only valid in `<chartSummaries><column>`, `<sortByName>`, or a `<calculatedFormula>`
- [ ] `legendPosition` omitted on single-series `HorizontalBar`/`VerticalColumn`/`Line`; on grouped/stacked charts only `Right` or `Bottom` (see `references/chart-types.md`)
- [ ] Every `<chart>` child element is in the allowed list in `references/chart-types.md`
## Cross-Filter Checks (if applicable)
- [ ] Maximum 3 cross-filters per report
- [ ] Maximum 5 criteria items per cross-filter
- [ ] `<operation>` is `with` or `without`
## Custom Summary Formula Checks (if applicable)
- [ ] `<aggregates>` only on Summary/Matrix/Joined (never Tabular)
- [ ] `<datatype>` is `number`, `currency`, or `percent`; `<scale>` is 0–18
- [ ] `<downGroupingContext>` (and `<acrossGroupingContext>` for Matrix) resolves to `GRAND_SUMMARY` or an existing grouping level
- [ ] `<developerName>` is unique within the report
## Sort & Row Limit Checks (if applicable)
- [ ] `<sortColumn>` (when present) names a column that appears in `<columns>`; `<sortOrder>` is exactly `Asc` or `Desc`
- [ ] Grouping `<sortType>Aggregate</sortType>` pairs with a summarized column name in `<sortByName>` (like `AMOUNT` or `RowCount` — NOT the Analytics-REST `s!` prefix)
- [ ] Grouping sorted by a CSF uses `<sortType>CustomSummaryFormula</sortType>` with the CSF `<developerName>` (like `FORMULA1`) — `Aggregate` + a CSF name deploys but silently sorts by the grouping field
- [ ] `<rowLimit>` only on `Tabular`, value 1–99, with `<sortColumn>` + `<sortOrder>` present
SKILL.md
---
name: platform-report-generate
description: "Use when users create, generate, or validate Salesforce Lightning Report metadata (.report-meta.xml) — tabular, summary, matrix, or joined reports with columns, groupings, filters, charts, cross-filters, buckets, formulas, or time-frame filters. Triggers on \"create a report\", \"build a report\", \"add a chart\", or .report-meta.xml deploy errors. Do NOT trigger for Custom Report Type metadata (use platform-custom-report-type-generate), dashboards, list views, running reports in the UI, or SOQL."
metadata:
version: "1.0"
domains: ["Platform"]
minApiVersion: "60.0"
relatedSkills:
- "platform-custom-report-type-generate"
mcpTools:
salesforce-api-context:
tools: ["get_metadata_type_context", "get_metadata_type_sections", "get_metadata_type_shape"]
semver: ">=1.0.0"
---
## Overview
Lightning Reports define how Salesforce data is queried, grouped, filtered, and displayed. Each report is a single `.report-meta.xml` file placed under `reports/<FolderName>/` within the project's source directory (check `sfdx-project.json` → `packageDirectories[].path` for the source root).
## Critical Rules (Read First)
**TOP DEPLOYMENT KILLERS — check these BEFORE generating any report:**
1. **Grouping fields in columns** — Fields in `<groupingsDown>` or `<groupingsAcross>` must NEVER also appear in `<columns>`
2. **Wrong column names (REQUIRED lookup)** — Before writing any `<columns>`, `<groupingsDown>`, `<groupingsAcross>`, filter `<column>`, or chart `<groupingColumn>`, take every name from the table for the chosen `<reportType>` in `references/column-names.md`, or confirm it with `get_metadata_type_sections`. NEVER derive a column name from the field's API name: `CASENUMBER`, `ISCLOSED`, `PHONE`, `MAILING_CITY` all fail (use `CASE_NUMBER`, a `STATUS` filter, `PHONE1`, `ADDRESS2_CITY`)
3. **Wrong scope** — LeadList uses `org`, not `organization`
4. **Filter column dot notation** — Filter `<column>` values use FLAT names (`INDUSTRY`, `TYPE`) NOT dot notation (`ACCOUNT.INDUSTRY` is INVALID)
5. **Multi-value picklist filters** — Use ONE `<criteriaItems>` with comma-separated `<value>` (e.g., `Technology,Financial Services`). Do NOT split into multiple criteriaItems with booleanFilter
6. **Report `<name>` over 40 characters** — Count the characters before writing. `Opportunities by Stage with Avg Deal Size` (41 characters) fails with `Value too long for field: Name maximum length is:40`; use something like `Opps by Stage - Avg Deal Size`
7. **Bare `NAME` / `USERS.NAME`** — Never use a bare `NAME` or `USERS.NAME` in columns or groupings; they are invalid on every standard report type. Look up the name column for the report type in `references/column-names.md` (e.g. `OPPORTUNITY_NAME`, `FULL_NAME` for the opportunity owner, `OWNER` for Case/Lead owner, `FIRST_NAME` + `LAST_NAME`)
8. **Unrequested or invalid `<params>`** — Do NOT add `<params>` the request didn't ask for. On Opportunity reports the only accepted `probability` value is `>0` (`0`, `all`, `>50` fail with `is not one of the picklist choices`); for a probability threshold, filter on `PROBABILITY` instead
9. **`RowCount` as a column** — `RowCount` is NOT a report column: `<columns><field>RowCount</field></columns>` fails with `columns-field: Invalid value specified: RowCount`. It is valid ONLY as `<chartSummaries><column>RowCount</column>`, as a `<sortByName>` value, or inside a custom summary formula's `<calculatedFormula>` (e.g. `AMOUNT:SUM / RowCount`). When the request asks for a record count, a Summary/Matrix report already shows the count per grouping — add no column; chart it with `RowCount` in `<chartSummaries>` if a chart is requested
### Rule 1: Format Determines Required Elements
| Format | `<groupingsDown>` | `<groupingsAcross>` | `<block>` |
|--------|-------------------|---------------------|-----------|
| `Tabular` | Not allowed | Not allowed | No |
| `Summary` | At least 1 (max 3) | Not allowed | No |
| `Matrix` | At least 1 (max 3) | At least 1 (max 3) | No |
| `Joined` | Not at top level | Not at top level | At least 2 (max 5) |
### Rule 2: Use Platform Column Names
Report metadata uses **platform report column names**, NOT raw API field names. **ALWAYS call `get_metadata_type_sections` or `get_metadata_type_context` to confirm valid column names.** See `references/column-names.md` for common mappings per report type.
### Rule 3: Valid Report Type Required
`<reportType>` must be a standard API name (e.g., `Opportunity`, `AccountList`, `CaseList`, `LeadList`, `AccountContactRole` for "Accounts with Contacts" — there is no `AccountContact`; see the label → API name table in `references/column-names.md`) or a deployed custom report type developer name **with a `__c` suffix** (`Accounts_with_Projects.reportType-meta.xml` → `<reportType>Accounts_with_Projects__c</reportType>`; without the suffix the deploy fails with `invalid report type`). Custom report type columns use `$` paths, not platform names: `Account$Name` for the base object, `Account.Projects__r$Budget_Amount__c` for a joined object. See the Custom Report Types section in `references/column-names.md`.
### Rule 4–5: Chart & Aggregates Require Summary/Matrix
Charts and `<aggregateTypes>` (Sum, Average, etc.) only work in Summary and Matrix reports. Use only the `<chart>` child elements listed in `references/chart-types.md` — invented elements such as `<summaryAxisManualRangeEnabled>` or `<showInlineChart>` fail parsing. Use `<legendPosition>` ONLY on grouped/stacked chart types (`Right` or `Bottom`) or on `Pie`, `Donut`, `Funnel`, `Scatter`; on a single-series `HorizontalBar`, `VerticalColumn`, `Line`, or `LineCumulative` any value fails with `chart-legendPosition: Invalid value specified: Right` — omit it. A record-count chart summary is `<chartSummaries><column>RowCount</column></chartSummaries>` with NO `<aggregate>` (`Sum`/`Count` with `RowCount` fails).
### Rule 6–8: Limits
- Max **3 cross-filters** per report, each with up to **5 criteria items**
- `<filterLogic>` must reference all filters sequentially (e.g., `1 AND (2 OR 3)`)
- Joined reports: 2–5 blocks, each block format must be Summary or Matrix (not Tabular)
### Rule 9: Folder Structure
Reports must live inside a folder with a corresponding folder metadata file:
```xml
<sourceDir>/reports/<FolderName>/<ReportName>.report-meta.xml
<sourceDir>/reports/<FolderName>-meta.xml
```
Determine `<sourceDir>` from `sfdx-project.json` (commonly `force-app/main/default`, but this is configurable).
### Rule 10–11: Date Columns & Scope
- Date columns use platform names (`CLOSE_DATE`, not `CloseDate`)
- LeadList scope is `org`; Opportunity/AccountList/CaseList use `organization`
### Rule 12–13: Description & Groupings
- `<description>` max **255 characters**
- Grouping fields must NOT appear in `<columns>` — automatic deployment failure
- Each `<columns>` element holds exactly ONE `<field>` — repeat `<columns>` per field (multiple `<field>`s fail with `Element field is duplicated`)
### Rule 14: Folder Metadata Requires `<sharedTo>`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<ReportFolder xmlns="http://soap.sforce.com/2006/04/metadata">
<folderShares>
<accessLevel>Manage</accessLevel>
<sharedTo>AllInternalUsers</sharedTo>
<sharedToType>Group</sharedToType>
</folderShares>
<name>My Report Folder</name>
</ReportFolder>
```
### Rule 15: Valid Date Intervals Only
Use `INTERVAL_CURRENT` for "this quarter", `INTERVAL_CURY` for "this year", `INTERVAL_LAST30` for last 30 days. Do NOT use `INTERVAL_CURQ` — it is not valid. See `references/date-intervals.md` for the full list.
### Rule 16: Custom Summary Formulas Need Summary/Matrix + a Grouping Context
`<aggregates>` (custom summary formulas, CSFs) evaluate **only** in `Summary`, `Matrix`, or `Joined` reports — never `Tabular`. Each CSF must declare where it is computed via `<downGroupingContext>` (and `<acrossGroupingContext>` for Matrix): use `GRAND_SUMMARY` for the report total, or a 0-based grouping level (`0`, `1`, …). A context that references a grouping level that does not exist is a deploy failure. See `references/summary-formulas-sorting-limits.md`.
### Rule 17: Report-Level Sort Is `<sortColumn>` + `<sortOrder>`; Group Sort Lives on the Grouping
- **Detail sort:** set top-level `<sortColumn>` (a platform column name that also appears in `<columns>`) plus `<sortOrder>` (`Asc` or `Desc`).
- **Grouping sort:** do NOT use `<sortColumn>` — set `<sortOrder>` on the `<groupingsDown>` / `<groupingsAcross>` element. To sort a grouping by a measure, match `<sortType>` to what `<sortByName>` names: `<sortType>Aggregate</sortType>` with a summarized column name (e.g. `AMOUNT`, which must carry an `<aggregateTypes>`, or `RowCount`); `<sortType>CustomSummaryFormula</sortType>` with a CSF `<developerName>` (e.g. `FORMULA1`). Pairing `Aggregate` with a CSF name deploys but silently sorts by the grouping field instead. Default `<sortType>` is `Column`.
- `<sortOrder>` is case-sensitive: `Asc` / `Desc` (not `ASC`/`Ascending`). See `references/summary-formulas-sorting-limits.md`.
### Rule 18: Row Limit / Top-N Is Tabular-Only and Requires a Sort
`<rowLimit>` (the "Row Limit" / top-N feature used for tabular dashboard components) is valid **only** on `Tabular` reports and **must** be paired with `<sortColumn>` + `<sortOrder>` that define what "top" means: `Desc` = top N, `Asc` = bottom N. Setting `<rowLimit>` on Summary/Matrix, or without a sort column, fails to deploy. Max 99. See `references/summary-formulas-sorting-limits.md`.
## Top-Level Elements
| Element | Required | Notes |
|---------|----------|-------|
| `<name>` | Yes | Report name (max 40 chars) |
| `<reportType>` | Yes | Report type API name |
| `<format>` | Yes | `Tabular`, `Summary`, `Matrix`, or `Joined` |
| `<scope>` | Recommended | `organization` (or `org` for LeadList) |
| `<columns>` | Yes | Field columns — each has `<field>` and optional `<aggregateTypes>` |
| `<filter>` | No | Contains `<criteriaItems>` with `<column>`, `<operator>`, `<value>` |
| `<groupingsDown>` | Conditional | Row groupings: `<field>`, `<dateGranularity>`, `<sortOrder>`, and `<sortType>`/`<sortByName>` for measure sort |
| `<groupingsAcross>` | Conditional | Column groupings (Matrix only) |
| `<aggregates>` | No | Custom summary formulas (Summary/Matrix/Joined only) — see Rule 16 |
| `<sortColumn>` | No | Platform column name to sort detail rows by; pair with `<sortOrder>`; required for `<rowLimit>` |
| `<sortOrder>` | No | `Asc` or `Desc` (case-sensitive) — used at report level and on each grouping |
| `<rowLimit>` | No | Tabular-only top-N (1–99); requires `<sortColumn>` + `<sortOrder>` — see Rule 18 |
| `<timeFrameFilter>` | Recommended | `<dateColumn>`, `<interval>`, optional `<startDate>`/`<endDate>` |
| `<chart>` | No | See `references/chart-types.md` |
| `<buckets>` | No | Bucket field definitions |
| `<crossFilters>` | No | Cross-object filters (`with`/`without`) |
| `<showDetails>` | Recommended | `true`/`false` |
| `<showGrandTotal>` | Recommended | `true`/`false` |
| `<showSubTotals>` | Recommended | `true`/`false` |
| `<description>` | Recommended | Business purpose (max 255 chars) |
| `<block>` | Conditional | Joined format blocks |
## Filter Syntax
```xml
<filter>
<criteriaItems>
<column>STAGE_NAME</column>
<operator>equals</operator>
<value>Closed Won</value>
</criteriaItems>
</filter>
```
**Multi-value picklist:** Use ONE criteriaItem with comma-separated values:
```xml
<criteriaItems>
<column>INDUSTRY</column>
<operator>equals</operator>
<value>Technology,Financial Services</value>
</criteriaItems>
```
Common operators: `equals`, `notEqual`, `lessThan`, `greaterThan`, `contains`, `startsWith`, `includes`, `excludes`, `isBlank`, `notBlank`. Full list in `references/filter-operations.md`.
## Generation Workflow
1. **Gather Requirements** — object, fields, groupings, filters, chart needs
2. **Determine Format** — no groupings → Tabular; row groupings → Summary; row + column → Matrix; multiple objects → Joined
3. **Look Up Every Column Name (required)** — list every field the report needs, then take each name from the `references/column-names.md` table for the chosen `<reportType>` or confirm it with `get_metadata_type_sections`. Do not write XML until every column, grouping, filter column, and chart grouping column is looked up
4. **Author Metadata** — start from closest example in `examples/` and adapt
5. **Create Folder** — generate folder directory + `<FolderName>-meta.xml` with `<folderShares>`
6. **Validate** — run through `references/verification-checklist.md`
## Reference File Index
| File | When to read |
|------|--------------|
| `references/column-names.md` | Step 3 — column name mappings per report type |
| `references/date-intervals.md` | When setting timeFrameFilter intervals |
| `references/chart-types.md` | When adding a chart — all 17 types + legendPosition rules |
| `references/filter-operations.md` | When building filters — complete operator reference |
| `references/verification-checklist.md` | Step 6 — pre-deploy validation |
| `references/errors-and-troubleshooting.md` | When fields are missing or deployment fails |
| `references/summary-formulas-sorting-limits.md` | When adding custom summary formulas, sorting, or a row limit / top-N (Rules 16–18) |
| `examples/TabularOpportunitiesReport.report-meta.xml` | Tabular report template |
| `examples/OpportunitiesByStageReport.report-meta.xml` | Summary report with chart |
| `examples/OpportunitiesByStageAndQuarter.report-meta.xml` | Matrix report template |
| `examples/AccountsCreatedThisYear.report-meta.xml` | Filtered report with time frame |