description: "Use this skill when users need to create, generate, modify, or validate Salesforce Lightning pages (FlexiPages). Trigger when users mention RecordPage, AppPage, HomePage, Lightning pages, page layouts, adding components to pages, or page customization. Also use when users say things like 'create a Lightning page', 'add a component to a page', 'customize the record page', 'generate a FlexiPage', or when they're working with FlexiPage XML files and need help with components, regions, or deployment errors. Always use this skill for any FlexiPage-related work, even if they just mention 'page' in the context of Salesforce. DO NOT TRIGGER when users ask about Visualforce pages, Aura components without FlexiPage context, page layout assignments in the UI, or Lightning Web Component development that does not involve placing components on a FlexiPage."
- Understand FlexiPage structure and component configuration
- Work with page layouts or Lightning page customization
- Edit or update ANY *.flexipage-meta.xml file
## Specification
## Overview
**CRITICAL: When creating NEW FlexiPages, you MUST ALWAYS start with the CLI template command.** Never create FlexiPage XML from scratch - the CLI provides valid structure, proper regions, and correct component configuration that prevents deployment errors.
Generate Lightning pages (RecordPage, AppPage, HomePage) using CLI bootstrapping for component discovery and configuration.
---
## Quick Start Workflow
### Step 1: Bootstrap with CLI
**MANDATORY FOR NEW PAGES: This step is NOT optional.** Always use the CLI template command when creating a new FlexiPage. The CLI generates valid XML structure, proper regions, and correct metadata that prevents common deployment errors. Only skip this step if you're editing an existing FlexiPage file.
**`<packageDirectory>`** = the `path` value from `sfdx-project.json` → `packageDirectories[0]` (e.g., `force-app`). Read it from the project file before running commands.
-`--primary-field`: Most important identifying field (e.g., Name)
-`--secondary-fields`: Record summary (recommended 4-6, max 12)
-`--detail-fields`: Full record details, including required fields (e.g., Name)
**AppPage:**
- No additional requirements
**HomePage:**
- No additional requirements
#### **Field Selection Rules**
- **Validate fields exist**: Use MCP tools or describe commands to discover available fields for the object before specifying them in the command
- **Prefer compound fields**: Use `Name` (not `FirstName`/`LastName`), `BillingAddress` (not `BillingStreet`/`BillingCity`/`BillingState`), `MailingAddress`, etc. when available
- **Include required fields in detail-fields**: Always include object required fields (like `Name`) in the `--detail-fields` parameter, even if they're also used in `--primary-field` or `--secondary-fields`
#### **What you get**
- Valid FlexiPage XML with correct structure
- Pre-configured regions and basic components
- Proper field references and facet structure
- Ready to deploy as-is or enhance further
### Step 2: Deploy Base Page
Run a **dry-run** deployment to validate the page and dependencies (use the default package directory from `sfdx-project.json`):
After the base page deploys successfully, if the user wants additional components, follow the **Adding Components Dynamically** workflow below. All component additions MUST go through the discovery and inference pipeline — never write component XML from memory alone.
---
## Critical XML Rules
**Read `references/xml_rules.md`** for all XML encoding rules, field reference format, region/facet types, fieldInstance structure, unique identifier requirements, and common deployment error resolutions.
**Key rules (quick reminder):**
- Encode HTML in `<value>` tags: `&` first, then `<`, `>`, `"`, `'`
- Field references: `Record.{FieldApiName}` (never `Object.Field`)
- Every `<identifier>` and region `<name>` must be unique across the file
- Multiple components in same facet → combine in ONE region with multiple `<itemInstances>`
---
### Identifiers, Regions, and Containers
**Read `references/identifiers_and_regions.md`** for the identifier generation algorithm, facet naming patterns (named vs UUID), region selection rules, and container component facet structure.
---
## Component-Specific Tips
### dynamicHighlights (RecordPage Header)
**Location:** `header` region only. See `references/record_flexipage_dynamicHighlights.md` for full structure.
CLI generates Facets automatically from `--primary-field` and `--secondary-fields`.
### fieldSection
**Use for:** Displaying fields in columns. Three-level nesting: Region → Column Facets → Field Facets.
See `references/flexipage_fieldSection.md` for full structure and XML example.
**Critical:** The `columns` property value is a Facet name, not a number.
### richText
See `references/flexipage_richText.md` for encoding rules and XML structure.
Identifier: `flexipage_richText` or `flexipage_richText_{N}`
<sobjectType>Object__c</sobjectType><!-- RecordPage only -->
</FlexiPage>
```
**Page Types:**
-`RecordPage` - requires `<sobjectType>`
-`AppPage` - no sobjectType
-`HomePage` - no sobjectType
---
## Validation Checklist
### Structure (new pages)
- [ ] Used CLI to bootstrap — never create FlexiPage XML from scratch
### Identifiers & Regions
- [ ] All `<identifier>` values unique across entire file
- [ ] All region/facet `<name>` values unique across entire file
- [ ] Multiple components in same facet combined in ONE region with multiple `<itemInstances>`
### Field Instances
- [ ] All field references use `Record.{Field}` format
- [ ] Each fieldInstance has `fieldInstanceProperties` with `uiBehavior`
- [ ] Each fieldInstance in its own `<itemInstances>` wrapper
### Types & Encoding
- [ ] Template regions use `<type>Region</type>`; component facets use `<type>Facet</type>`
- [ ] Property values with HTML/XML are entity-encoded
- [ ] No unnecessary `<mode>` tags (only where component patterns require them)
- [ ] No `__c` suffix in page names
- [ ] Each Facet referenced by exactly one component property
---
## Quick Reference: CLI Command
**Read `references/cli_commands.md`** for full CLI examples (RecordPage, AppPage, HomePage) and available options.
---
## Adding Components Dynamically
> **MANDATORY WORKFLOW:** ALL component additions to a FlexiPage MUST follow this workflow. Do not write component XML from memory or skip discovery. This applies to standard OOTB components, custom LWC components, and any other component type.
### Overview
When the user requests components (e.g., "add a related list of contacts and a report"), follow this pipeline:
```text
1. Parse Intent → identify ALL requested components
2. Discover ALL → batch components through 3-tier discovery
3. Infer Properties → run 3-step inference for EACH discovered component
4. Generate XML → produce valid XML for all components together
**Key rule:** Discover ALL components as a batch first (one scan, one MCP call), THEN infer properties for each. Do not invoke discovery steps per-component or interleave discovery and inference.
### Step 1: Parse User Intent
Extract every component request from the user's utterance. Examples:
- "Create Account page with a report and related contacts" → 2 components: report, related list
- "Add activities, chatter, and a DRL of Cases" → 3 components: activities, chatter, dynamic related list
### Step 2: 3-Tier Component Discovery
Complete each tier for ALL components before moving to the next tier — do NOT run Tier 1→2→3 per component:
| Tier | Source | When | Calls |
|------|--------|------|-------|
| **1** | Local workspace scan | Always first — run for ALL components | 0 (local only) |
| **2** | `discoverUiComponents` MCP action | Single call for all components unresolved after Tier 1 | 1 |
| **3** | Generate new LWC bundle | Only for components still unresolved after Tier 2 + user confirms | 0 |
After Tier 1 completes for all components, collect only the unresolved ones and pass them to Tier 2 in a single MCP call. Only components still unresolved after Tier 2 proceed to Tier 3.
See **Local Workspace Scanner** and **MCP Action Integration** sections below for details.
### Step 3: Property Inference (per component)
For EACH discovered component, infer properties using the 3-step strategy:
1.**Fetch schema or read source** — For Tier 2 (org) components, call `getUiComponentSchemas`; for Tier 1 (local), extract `@api` props from source
2.**Apply component instructions** — If `references/<name>.md` exists, read and follow its inference rules
The script scans `<packageDirectory>/**/lwc/*/`, tokenizes camelCase component names, scores them against user intent keywords, and returns a JSON array of matches with confidence tiers:
- **High confidence (≥70%):** auto-select, confirm with user
- **Medium confidence (40-69%):** present ranked list for user selection
- **Low confidence (<40%):**skip,proceedtoTier2
Run Tier 1 for ALL components before moving any to Tier 2. Collect all unresolved components from Tier 1, then pass them to Tier 2 in a single MCP call.
### Disambiguation
For medium-confidence matches (40-69%) or multiple high-confidence matches:
1. Read each candidate's `.js-meta.xml` for `<description>` and `<targetConfigs>`
2. Present ranked list to user with component name + description
3. User selects or says "none of these" (→ proceed to Tier 2)
### When to Skip
Skip local scan when:
- User explicitly mentions an org-level component ("use the standard report component")
- User intent clearly maps to a known standard component (DRL, richText, etc.)
- No `<packageDirectory>` directory exists in the workspace
---
## Hybrid Property Inference Strategy
For EACH discovered component, populate its properties using this 3-step strategy in order:
### Step 1: Fetch Latest Schema (conditional)
Call `getUiComponentSchemas` only when the component does **not** exist on the local machine (i.e., Tier 2 org-discovered components). For local components (Tier 1), extract `@api` properties directly from the source code instead.
**When to call:**
- Tier 2 (org discovery): Always — the schema is the only source of property info
- Tier 1 (local): Skip — read `@api` properties from the component's `.js` source file
- Tier 3 (generated): Skip — you just created the source, so properties are already known
If a file is returned: read and follow its inference rules, XML patterns, and defaults.
If empty: skip directly to Step 3.
Instructions files augment the schema — they provide *how* to derive values from user intent. Any properties in the schema not covered by the instructions file are resolved in Step 3.
### Step 3: Resolve Remaining Properties
For any properties not yet resolved, apply in this priority order:
**3a. Smart Default Heuristics:**
| Property Pattern | Default Value |
|-----------------|---------------|
| `recordId` | `{!recordId}` |
| `objectApiName` / `sObjectName` | Page's `<sobjectType>` value |
| `show*` / `visible*` / `display*` | `true` |
| `hide*` / `hidden*` / `disabled*` | `false` |
| Boolean without prefix | `false` |
| Schema specifies `"default"` | Use schema default |
**3b. LLM Inference:**
Use the component schema + user intent + page context to infer reasonable values. Example: user says "report showing top opportunities" → infer `reportName` should reference an opportunities report.
**3c. User Prompts (last resort):**
Only prompt the user for critical required properties that cannot be inferred. If user says "skip", omit the component entirely.
**To add a new component pattern:** Create `references/<namespace>_<componentName>.md` following the structure in existing files. The skill automatically checks for the file during Step 2 of property inference.
---
## Validation Rules for Dynamic Components
After generating XML for dynamically added components, verify ALL of the following before deployment:
### Identifier Uniqueness
- Extract ALL `<identifier>` values from the entire FlexiPage file
- Confirm zero duplicates
- If conflict: auto-increment suffix (`_2`, `_3`, etc.)
### Region Validity
- Components placed in correct regions for their type:
-`record_flexipage:dynamicHighlights` → `header` only
-`flexipage:fieldSection` → `main` or tab facets
-`flexipage:richText` → any region
### Property Completeness
- All properties marked required in schema have values
- All values match expected types (String, Boolean, valueList, Integer)
- No raw HTML in `<value>` tags (must be entity-encoded)
### Structural Integrity
- Every Facet referenced by a component property exists as a `<flexiPageRegions>` block
- No orphan Facets (every Facet is referenced by exactly one component)
- Multiple components in same region use ONE `<flexiPageRegions>` block with multiple `<itemInstances>`
### Cross-Component Consistency
- For multi-component additions: identifiers are unique across ALL new components
- Facet UUIDs don't collide between components
- Components that require singleton placement (dynamicHighlights, recordDetailPanelMobile) are not duplicated