
Platform Flexipage Generate
- 2.2k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
Creates, modifies, and troubleshoots Salesforce Lightning pages (FlexiPages) with CLI-bootstrapped templates, deployment, and XML validation to prevent common errors.
About
platform-flexipage-generate is a Salesforce sf-skills entry for creating, modifying, and troubleshooting Lightning pages (FlexiPages). It mandates starting from a CLI template, then validates XML structure and deploys record, app, and home pages so metadata stays valid. A Salesforce developer or admin reaches for it to build Lightning pages correctly instead of hitting common FlexiPage XML errors.
- Generate Lightning FlexiPages
- CLI template bootstrap required
- XML structure validation
- Deploy record, app, and home pages
Platform Flexipage Generate by the numbers
- 2,239 all-time installs (skills.sh)
- +566 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #227 of 4,386 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/forcedotcom/sf-skills --skill platform-flexipage-generateAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.2k |
|---|---|
| repo stars | ★ 763 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 24, 2026 |
| Repository | forcedotcom/sf-skills ↗ |
What it does
Creates, modifies, and troubleshoots Salesforce Lightning pages (FlexiPages) with CLI-bootstrapped templates, deployment, and XML validation to prevent common errors.
Who is it for?
Salesforce devs generating Lightning FlexiPages
Skip if: Non-Salesforce projects
Files
When to Use This Skill
Use this skill when you need to:
- Create Lightning pages (RecordPage, AppPage, HomePage)
- Generate FlexiPage metadata XML
- Add components to existing FlexiPages
- Troubleshoot FlexiPage deployment errors
- 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.
sf template generate flexipage \
--name <PageName> \
--template <RecordPage|AppPage|HomePage> \
--sobject <SObject> \
--primary-field <Field1> \
--secondary-fields <Field2,Field3> \
--detail-fields <Field4,Field5,Field6,Field7> \
--output-dir <packageDirectory>/main/default/flexipagesCRITICAL: If the sf template generate flexipage command fails, STOP.
1. Install the templates plugin:
sf plugins install templates2. Retry the sf template generate flexipage command 3. Verify the FlexiPage XML file was created
Do NOT continue to Step 2 until the template command succeeds. The generated XML is required for the entire workflow.
Template-specific requirements
RecordPage:
- Requires
--sobject(e.g., Account, Custom_Object__c) - Requires field parameters:
--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(notFirstName/LastName),BillingAddress(notBillingStreet/BillingCity/BillingState),MailingAddress, etc. when available - Include required fields in detail-fields: Always include object required fields (like
Name) in the--detail-fieldsparameter, even if they're also used in--primary-fieldor--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):
sf project deploy start --dry-run -d "<packageDirectory>/main/default" --test-level NoTestRun --wait 10 --jsonCritical: Fix any deployment errors before proceeding. The page must validate successfully.
Step 3: Add Components Dynamically (if requested)
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}(neverObject.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}
---
Required Metadata Structure
<FlexiPage xmlns="http://soap.sforce.com/2006/04/metadata">
<flexiPageRegions>
<!-- Regions and components here -->
</flexiPageRegions>
<masterLabel>Page Label</masterLabel>
<template>
<name>flexipage:recordHomeTemplateDesktop</name>
</template>
<type>RecordPage</type>
<sobjectType>Object__c</sobjectType> <!-- RecordPage only -->
</FlexiPage>Page Types:
RecordPage- requires<sobjectType>AppPage- no sobjectTypeHomePage- 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
fieldInstancePropertieswithuiBehavior - [ ] 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
__csuffix 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:
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
5. Validate → check identifiers, regions, property completenessKey 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 3. Resolve remaining — Smart defaults → LLM inference → user prompts (last resort)
See Hybrid Property Inference Strategy below for full details.
Step 4: Generate XML
What you CANNOT do:
- Modify top level structure in the XML file
- Add any components from memory which is not resolved from 3-Tier Component Discovery
- Make any enhancements
Read `references/xml_rules.md` before writing any XML. Follow all element naming and structure rules defined there.
Produce <itemInstances> XML for all resolved components:
- Use
<componentInstanceProperties>for every property (NOT<properties>) - Assign unique identifiers across the full set (see references/identifiers_and_regions.md)
- Insert into appropriate regions (header, main, sidebar, or facets)
- Follow each component's XML structure from its instructions file or schema
Step 5: Validate
Check the complete FlexiPage for:
- Identifier uniqueness (no duplicates across entire file)
- Region validity (components in correct regions)
- Property completeness (all required properties populated)
- XML encoding (HTML values entity-encoded)
- Element name correctness (see references/xml_rules.md §6)
Deploy with dry-run (use default package directory from sfdx-project.json):
sf project deploy start --dry-run -d "<packageDirectory>/main/default" --test-level NoTestRun --wait 10 --json---
MCP Action Integration
Read `references/mcp_action_examples.md` for full input/output examples and parameter tables.
Two MCP actions via execute_metadata_action:
| Action | Purpose | When |
|---|---|---|
DISCOVER_UI_COMPONENTS | Find components for a page type | Tier 2 discovery — single call for all unresolved components |
GET_UI_COMPONENT_SCHEMAS | Get property schemas | Property inference Step 1 (Tier 2 org components only) |
Key conventions:
- Component definition format:
namespace/blockName(forward-slash) in MCP calls,namespace:blockName(colon) in XML pageContextwithentityNameis required for RECORD_PAGEgetUiComponentSchemassupports partial failures — check each component'ssuccessboolean
---
Local Workspace Scanner
Scans the local SFDX project for custom LWC components before making any MCP calls (Tier 1 discovery).
Algorithm
Run the scanner for each component query (local scan — no network calls):
scripts/scan-lwc-components.sh "<query>" [packageDirectory]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, proceed to Tier 2
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
@apiproperties from the component's.jssource file - Tier 3 (generated): Skip — you just created the source, so properties are already known
Step 2: Apply Component Instructions (if present)
Run scripts/resolve-component-instructions.sh <namespace:component> — it returns the instructions file path if it exists, or empty string.
Examples:
record_flexipage:dynamicHighlights→references/record_flexipage_dynamicHighlights.mdflexipage:fieldSection→references/flexipage_fieldSection.mdc:expenseTracker→ (empty — no file)
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.
Tier-Specific Behavior
| Tier | Extra Step | Schema Call | Instructions |
|---|---|---|---|
| Tier 1 (local) | Extract @api props from source | No (use source) | If exists |
| Tier 2 (org) | — | Yes | If exists |
| Tier 3 (generated) | Extract @api from just-generated source | No (just created) | No |
---
New LWC Generation (Tier 3)
When no component is found locally (Tier 1) or in the org (Tier 2), offer to generate a new LWC.
Trigger Conditions
- Tier 1 and Tier 2 both miss or user rejected all candidates
- User has not explicitly said "skip" or "don't create"
Confirmation
Always confirm before creating. Explain: component name. If user declines: skip, continue with other components.
Post-Generation
After creating the LWC bundle: 1. Treat as a Tier 1 local component immediately 2. Extract @api properties from the generated source 3. Apply smart defaults for recordId and objectApiName 4. Generate FlexiPage XML with c:{componentName} as the componentName
Naming Convention
- Derive from user intent: "customer health score" →
customerHealthScore - camelCase, no hyphens, no underscores in the JS class name
- Folder name matches class name (lowercase first letter):
customerHealthScore/
---
Reference File Index
| File | When to read |
|---|---|
references/xml_rules.md | Before writing or editing any FlexiPage XML — encoding, field refs, identifiers, deployment errors |
references/identifiers_and_regions.md | When adding components — identifier algorithm, facet naming, region selection, container pattern |
references/cli_commands.md | When bootstrapping new pages — full CLI examples for RecordPage, AppPage, HomePage |
references/mcp_action_examples.md | When calling MCP actions — full input/output JSON for discoverUiComponents and getUiComponentSchemas |
references/flexipage_fieldSection.md | When adding a Field Section with columns |
references/record_flexipage_dynamicHighlights.md | When adding a Dynamic Highlights panel |
references/flexipage_richText.md | When adding a Rich Text component |
scripts/scan-lwc-components.sh | Tier 1 local workspace scan — tokenizes and scores LWC component names against user query |
scripts/resolve-component-instructions.sh | Property inference Step 2 — resolves component definition to instructions file path |
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→headeronlyflexipage:fieldSection→mainor tab facetsflexipage: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
CLI Command Reference
RecordPage with fields
sf template generate flexipage \
--name Account_Custom_Page \
--template RecordPage \
--sobject Account \
--primary-field Name \
--secondary-fields Phone,Industry,AnnualRevenue \
--detail-fields Street,City,State,Name,Phone,EmailAppPage
sf template generate flexipage \
--name Sales_Dashboard \
--template AppPage \
--label "Sales Dashboard"HomePage
sf template generate flexipage \
--name Custom_Home \
--template HomePage \
--description "Custom home for sales team"Common Options
All templates support:
--output-dir(default: current directory)--api-version(default: latest)--label(default: page name)--description
flexipage:fieldSection — Field Section
Purpose
Displays fields in a column layout under a labeled section heading.
Supported Page Types
- RecordPage (
mainregion or detail tab facets)
Structure
Three-level nesting: 1. Template Region (Region type) — contains the fieldSection component 2. Column Facets (Facet type) — contains flexipage:column components pointing to field facets 3. Field Facets (Facet type) — contains fieldInstance elements for each column
Critical: The columns property value must match the <name> of the facet where the flexipage:column components are defined. It is not a number.
Property Table
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| columns | String (Facet ref) | Yes | — | Reference to the Facet containing flexipage:column components |
| label | String | Yes | — | Section heading displayed to users |
| horizontalAlignment | Boolean | No | false | Align fields horizontally within columns |
Property Inference Rules
| User Intent | Inferred Properties |
|---|---|
| "add a field section with {fields}" | Split fields evenly across 2 columns |
| "section labeled {name}" | label = {name} |
XML Example
<!-- Field facet for first column -->
<flexiPageRegions>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>required</value>
</fieldInstanceProperties>
<fieldItem>Record.Field0</fieldItem>
<identifier>RecordColumn1Field0</identifier>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.Field1</fieldItem>
<identifier>RecordColumn1Field1</identifier>
</fieldInstance>
</itemInstances>
<name>Facet-FieldSection-Column1</name>
<type>Facet</type>
</flexiPageRegions>
<!-- Field facet for second column -->
<flexiPageRegions>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.Field2</fieldItem>
<identifier>RecordColumn2Field0</identifier>
</fieldInstance>
</itemInstances>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.Type</fieldItem>
<identifier>RecordColumn2Field1</identifier>
</fieldInstance>
</itemInstances>
<name>Facet-FieldSection-Column2</name>
<type>Facet</type>
</flexiPageRegions>
<!-- Columns facet -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>body</name>
<value>Facet-FieldSection-Column1</value>
</componentInstanceProperties>
<componentName>flexipage:column</componentName>
<identifier>flexipage_column1</identifier>
</componentInstance>
</itemInstances>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>body</name>
<value>Facet-FieldSection-Column2</value>
</componentInstanceProperties>
<componentName>flexipage:column</componentName>
<identifier>flexipage_column2</identifier>
</componentInstance>
</itemInstances>
<name>Facet-FieldSection-Columns</name>
<type>Facet</type>
</flexiPageRegions>
<!-- Template region with fieldSection component -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>columns</name>
<value>Facet-FieldSection-Columns</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>horizontalAlignment</name>
<value>false</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>label</name>
<value>Information</value>
</componentInstanceProperties>
<componentName>flexipage:fieldSection</componentName>
<identifier>flexipage_fieldSection</identifier>
</componentInstance>
</itemInstances>
<name>main</name>
<type>Region</type>
</flexiPageRegions>uiBehavior Attribute
Every fieldInstance requires a uiBehavior property that controls field editability on the page.
| Value | Meaning | When to use |
|---|---|---|
none | Field respects standard editability settings (default) | Standard fields — uses object/layout-level permissions |
required | Field is required — must be filled before save | Fields that must have a value for the record to be valid |
readonly | Field is read-only — displayed but not editable | Formula fields, system fields, or fields locked by business rules |
Inference rules:
- Default to
noneunless the user specifies otherwise - If user says "required" or "mandatory" → use
required - If user says "read-only", "display only", or "locked" → use
readonly - Formula fields and auto-number fields should always be
readonly
Edge Cases
columnsproperty is a Facet name, not a count — common mistake- Split fields roughly evenly across columns
- Identifiers:
flexipage_fieldSection,flexipage_fieldSection2; columns:flexipage_column1,flexipage_column2 - Second fieldSection on same page: all facet names and identifiers must be unique
flexipage:richText — Rich Text
Purpose
Displays HTML-formatted rich text content on a page. Supports text formatting, headings, lists, links, and inline styles. Content is static (not data-bound).
Supported Page Types
- RecordPage
- AppPage
- HomePage
Property Table
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| richTextValue | String (HTML-encoded) | Yes | — | HTML content, entity-encoded for XML |
| decorate | Boolean | No | true | Show card-style border/decoration around the content |
Property Inference Rules
| User Intent | Inferred Properties |
|---|---|
| "add rich text with {content}" | richTextValue = HTML-encoded version of content |
| "add a heading {text}" | richTextValue = <p><b style="font-size: 16px;">{text}</b></p> |
| "add a link to {url}" | richTextValue = <p><a href="{url}" rel="noopener noreferrer" target="_blank">{text}</a></p> |
| "no border" or "borderless" | decorate = false |
| "with card border" or "in a card" | decorate = true |
HTML Encoding Rules
CRITICAL: The richTextValue must be double-encoded for XML: 1. Write the desired HTML content 2. Entity-encode ALL HTML characters:
&->&(encode FIRST)<-><>->>"->"
Example: To display <b>Hello</b>, the value must be <b>Hello</b>
Supported HTML tags:
<p>— paragraphs (required wrapper for all content)<b>— bold<u>— underline<i>— italic<a href="..." rel="noopener noreferrer" target="_blank">— links<span style="...">— inline styling<br>or<br />— line breaks
Supported inline styles:
font-size: Npx(e.g.,12px,14px,16px,18px)color: #hexorcolor: colornametext-align: left|center|rightbackground-color: #hex
XML Example
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>richTextValue</name>
<value><p style="text-align: center;"><b style="font-size: 16px;">Welcome to the Account Page</b></p><p>Use this page to manage account details and related records.</p></value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>decorate</name>
<value>true</value>
</componentInstanceProperties>
<componentName>flexipage:richText</componentName>
<identifier>flexipage_richText</identifier>
</componentInstance>
</itemInstances>Edge Cases
- Never put raw HTML in
<value>tags — always entity-encode - Encode
&FIRST before encoding<and>to avoid double-encoding&lt; - Multiple rich text components on same page: increment identifier (
flexipage_richText,flexipage_richText2) - Empty content is invalid — always include at least one
<p>element - Links must include
rel="noopener noreferrer" target="_blank"for security - Can be placed in any region
- Keep content concise — rich text is for static labels/instructions, not data display
Identifiers, Regions, and Container Facets
Generating Unique Identifiers
Before generating ANY new identifier or facet name, read the existing XML and extract all `<identifier>` and `<name>` values first.
Identifier Generation Algorithm:
1. Extract ALL existing <identifier> AND <name> values from XML
2. Generate base name: {namespace}_{componentType}_{context}
Examples: "lst_relatedList_contacts", "flexipage_richText_header"
3. Find first available number:
- Try "{base}_1"
- If exists, try "{base}_2", "{base}_3", etc.
- Use first availableExamples:
- First related list:
lst_relatedList_contacts - Second related list:
lst_relatedList_contacts_2 - First rich text:
flexipage_richText_header - Second rich text:
flexipage_richText_header_2 - Field section:
flexipage_fieldSection
Facet Naming - Two Patterns:
1. Named facets (for major content areas):
detailTabContent(detail tab content)maintabs(main tab container)sidebartabs(sidebar tab container)- Use when facet represents meaningful content area
2. UUID facets (for internal structure):
- Format:
Facet-{8hex}-{4hex}-{4hex}-{4hex}-{12hex} - Example:
Facet-66d5a4b3-bf14-4665-ba75-1ceaa71b2cde - Use for field section columns, nested containers, anonymous slots
When adding components to existing files:
- Check if target facet name already exists
- If exists: Add new
<itemInstances>to that existing region (see xml_rules.md section 5 for details) - If doesn't exist: Create new region with unique name
---
Region Selection
Parse regions from file - don't hardcode names. Templates vary:
flexipage:recordHomeTemplateDesktop→header,main,sidebarruntime_service_fieldservice:...→header,main,footer- Others may have different region names
Default placement: End of target region (after last <itemInstances>)
Insertion pattern:
<flexiPageRegions>
<name>main</name> <!-- or whatever region name exists -->
<type>Region</type>
<itemInstances><!-- Existing component 1 --></itemInstances>
<itemInstances><!-- Existing component 2 --></itemInstances>
<itemInstances>
<!-- INSERT NEW COMPONENT HERE -->
</itemInstances>
</flexiPageRegions>---
Container Components with Facets
Components like tabs, accordions, and field sections require a 3-layer facet pattern. There is NO single "tabs" component — you must use flexipage:tabset + flexipage:tab + content facets.
The 3-layer tab pattern:
<!-- LAYER 1: Content facets — one per tab's body -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentName>force:detailPanel</componentName>
<identifier>force_detailPanel1</identifier>
</componentInstance>
</itemInstances>
<name>detailTabContent</name>
<type>Facet</type>
</flexiPageRegions>
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>relatedListComponentOverride</name>
<value>NONE</value>
</componentInstanceProperties>
<componentName>force:relatedListContainer</componentName>
<identifier>force_relatedListContainer1</identifier>
</componentInstance>
</itemInstances>
<name>relatedTabContent</name>
<type>Facet</type>
</flexiPageRegions>
<!-- LAYER 2: Tab definitions facet — each flexipage:tab points to a content facet via "body" -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>active</name>
<value>true</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>body</name>
<value>detailTabContent</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>title</name>
<value>Standard.Tab.detail</value>
</componentInstanceProperties>
<componentName>flexipage:tab</componentName>
<identifier>flexipage_tab1</identifier>
</componentInstance>
</itemInstances>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>active</name>
<value>false</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>body</name>
<value>relatedTabContent</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>title</name>
<value>Standard.Tab.relatedLists</value>
</componentInstanceProperties>
<componentName>flexipage:tab</componentName>
<identifier>flexipage_tab2</identifier>
</componentInstance>
</itemInstances>
<name>maintabs</name>
<type>Facet</type>
</flexiPageRegions>
<!-- LAYER 3: Tabset in the template region — references the tabs facet -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>tabs</name>
<value>maintabs</value>
</componentInstanceProperties>
<componentName>flexipage:tabset</componentName>
<identifier>flexipage_tabset1</identifier>
</componentInstance>
</itemInstances>
<name>main</name>
<type>Region</type>
</flexiPageRegions>Critical rules:
- Facet regions are siblings of template regions (same level), NEVER nested inside them
- Each
flexipage:tabhasbodypointing to a content facet name,titlefor the label, andactive(true/false) - The
flexipage:tabsethas a singletabsproperty pointing to the tabs facet name - Standard tab titles:
Standard.Tab.detail,Standard.Tab.relatedLists,Standard.Tab.activity,Standard.Tab.news - The component is
flexipage:tabset— NOTflexipage:tabs,flexipage:tabset2, orlightning:tabset
MCP Action Integration — Examples & Reference
Two MCP actions provide component discovery and schema retrieval. Call them via execute_metadata_action.
discoverUiComponents
Discovers components available for a page type in the user's org.
When to call: Tier 2 discovery — after local scan finds no match.
Input:
execute_metadata_action({
"actionName": "DISCOVER_UI_COMPONENTS",
"metadataType": "FLEXI_PAGE",
"parameters": {
"pageType": "RECORD_PAGE",
"pageContext": { "entityName": "Account" },
"searchQuery": "related list"
}
})Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
| pageType | String | Yes | RECORD_PAGE, APP_PAGE, or HOME_PAGE |
| pageContext | JSON | Conditional | Required for RECORD_PAGE: {"entityName": "ObjectApiName"} |
| searchQuery | String | No | Natural language search from user intent |
Output:
{
"componentDefinitions": [
{
"definition": "lst/dynamicRelatedList",
"label": "Dynamic Related List",
"description": "Shows related records...",
"attributes": [{"name": "parentFieldApiName", "description": "..."}]
}
]
}Notes:
- Output uses forward-slash delimiter (
namespace/blockName), but XML uses colon (namespace:blockName) - Only returns components compatible with the page type and accessible in the org
- May return empty list if no match — proceed to Tier 3
When multiple components are returned: 1. Best-match selection: If one component clearly matches user intent (label/description aligns with the request), auto-select it 2. Ambiguous results: If multiple components could satisfy the request, present the top candidates to the user with their labels and descriptions, and ask which one to use 3. Refinement: If results are too broad, refine the searchQuery parameter with more specific keywords from user intent and retry once before prompting the user
getUiComponentSchemas
Retrieves the full property schema for one or more components.
When to call: Tier 2 (org-discovered) components only — skip for Tier 1 (local) and Tier 3 (generated) components; read @api properties from source instead.
Input:
execute_metadata_action({
"actionName": "GET_UI_COMPONENT_SCHEMAS",
"metadataType": "FLEXI_PAGE",
"parameters": {
"pageType": "RECORD_PAGE",
"pageContext": { "entityName": "Account" },
"componentDefinitions": ["lst/dynamicRelatedList", "flexipage/richText"],
"includeKnowledge": true
}
})Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
| pageType | String | Yes | RECORD_PAGE, APP_PAGE, or HOME_PAGE |
| pageContext | JSON | Conditional | Required for RECORD_PAGE |
| componentDefinitions | List | Yes | Component FQNs (forward-slash format) |
| includeKnowledge | Boolean | No | Include component guidance text (default: true) |
Output:
{
"componentSchemas": [
{
"definition": "lst/dynamicRelatedList",
"success": true,
"schema": "{...JSON Schema string...}",
"knowledge": "Optional guidance text for this component"
}
]
}Notes:
- Supports partial failures — each component has its own
successboolean - On failure:
{"definition": "...", "success": false, "error": "reason"} - When a component schema fails, fall through to Step 3 (smart defaults + LLM inference)
knowledgeprovides platform-curated guidance — use it alongside instructions files- Component definition format: always
namespace/blockName(forward-slash)
record_flexipage:dynamicHighlights — Dynamic Highlights Panel
Purpose
Displays the record highlights panel at the top of a record page with a primary identifying field, secondary summary fields, and configurable actions. Replaces the older static force:highlightsPanel.
Supported Page Types
- RecordPage only (always in
headerregion)
Property Table
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| primaryField | String (Facet ref) | Yes | — | Reference to a Facet containing the primary field (typically Record.Name) |
| secondaryFields | String (Facet ref) | No | — | Reference to a Facet containing secondary highlight fields |
| actionNames | valueList | No | — | Actions in the highlights panel: Edit, Delete, ChangeOwnerOne, Share, RecordShareHierarchy |
| numVisibleActions | Integer | No | 3 | Number of actions shown before overflow menu |
Structural Pattern
This component uses an indirect Facet reference pattern. The primaryField and secondaryFields properties point to Facet regions that contain fieldInstance elements — they are NOT direct field API names.
Required supporting structure: 1. A Facet region for primaryField containing one fieldInstance (the identifying field) 2. A Facet region for secondaryFields containing multiple fieldInstance elements (summary fields)
Property Inference Rules
| User Intent | Inferred Properties |
|---|---|
| "highlights with {fields}" | Create secondaryFields facet with those fields as fieldInstances |
| "show actions: Edit, Delete" | actionNames = valueList with Edit, Delete |
| "show {N} actions" | numVisibleActions = {N} |
Field selection: Primary = Record.Name (or object's identifying field). Secondary = 4-6 useful fields (max 12). Prefer CLI --secondary-fields values if available.
XML Example
<!-- Component in header region -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<componentInstanceProperties>
<name>actionNames</name>
<valueList>
<valueListItems>
<value>Edit</value>
</valueListItems>
<valueListItems>
<value>Delete</value>
</valueListItems>
<valueListItems>
<value>ChangeOwnerOne</value>
</valueListItems>
</valueList>
</componentInstanceProperties>
<componentInstanceProperties>
<name>numVisibleActions</name>
<value>3</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>primaryField</name>
<value>Facet-primary-field-001</value>
</componentInstanceProperties>
<componentInstanceProperties>
<name>secondaryFields</name>
<value>Facet-secondary-fields-001</value>
</componentInstanceProperties>
<componentName>record_flexipage:dynamicHighlights</componentName>
<identifier>record_flexipage_dynamicHighlights</identifier>
</componentInstance>
</itemInstances>
<name>header</name>
<type>Region</type>
</flexiPageRegions>
<!-- Primary field Facet -->
<flexiPageRegions>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.Name</fieldItem>
<identifier>RecordNameField</identifier>
</fieldInstance>
</itemInstances>
<name>Facet-primary-field-001</name>
<type>Facet</type>
</flexiPageRegions>
<!-- Secondary fields Facet (same structure as primary, multiple fieldInstances) -->
<flexiPageRegions>
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value>
</fieldInstanceProperties>
<fieldItem>Record.Phone</fieldItem>
<identifier>RecordPhoneField</identifier>
</fieldInstance>
</itemInstances>
<name>Facet-secondary-fields-001</name>
<type>Facet</type>
</flexiPageRegions>Edge Cases
- Only ONE per page — never multiple instances
- Always in
headerregion — never inmainor sidebar - Facet names must be unique UUIDs or descriptive names
- Primary field
uiBehaviorisnone; secondary fields also usenone - If CLI already generated highlights, modify existing — do not add a duplicate
- Identifier is always
record_flexipage_dynamicHighlights(singular, never numbered)
Critical XML Rules & Deployment Errors
Contents
0. STOP — Read Before Writing ANY componentInstance 1. Property Value Encoding 2. Field References 3. Region vs Facet Types 4. itemInstances — ONE Child Per Wrapper 5. Unique Identifiers and Region Names 6. Correct Element Names 7. Common Deployment Errors
---
STOP — Read Before Writing ANY componentInstance
The element name is `<componentInstanceProperties>`, NEVER `<properties>`.
<!-- WRONG — WILL FAIL DEPLOYMENT -->
<componentInstance>
<properties>
<name>label</name>
<value>Hello</value>
</properties>
<componentName>flexipage:fieldSection</componentName>
<identifier>id1</identifier>
</componentInstance>
<!-- CORRECT — the ONLY valid element name -->
<componentInstance>
<componentInstanceProperties>
<name>label</name>
<value>Hello</value>
</componentInstanceProperties>
<componentName>flexipage:fieldSection</componentName>
<identifier>id1</identifier>
</componentInstance>There is no `<properties>` element in FlexiPage XML. It does not exist. Every time you write a property inside `<componentInstance>`, you MUST write `<componentInstanceProperties>`. If you find yourself typing `<properties>`, STOP and correct it to `<componentInstanceProperties>`.
---
1. Property Value Encoding (MOST COMMON ERROR)
Any property value with HTML/XML characters MUST be manually encoded in the following order (wrong order causes double-encoding corruption):
1. & → & (FIRST! Encode this before others)
2. < → <
3. > → >
4. " → "
5. ' → 'Wrong:
<value><b>Important</b> text</value>Correct:
<value><b>Important</b> text</value>Check your XML: Search for <value> tags - they should never contain raw < or > characters.
2. Field References
Use Record.{FieldApiName} — never {ObjectName}.{FieldApiName} (Salesforce resolves from Record, not object name).
<!-- Correct -->
<fieldItem>Record.Name</fieldItem>
<!-- Wrong -->
<fieldItem>Account.Name</fieldItem>3. Region vs Facet Types
Template Regions (header, main, sidebar):
<name>header</name>
<type>Region</type>Component Facets (internal slots like fieldSection columns):
<name>Facet-12345</name>
<type>Facet</type>Rule: If it's a template region name → Region. If it's a component slot → Facet.
4. itemInstances — ONE Child Per Wrapper (CRITICAL)
Each `<itemInstances>` can contain exactly ONE child element — either one <componentInstance> OR one <fieldInstance>. Never put multiple children inside a single <itemInstances>.
<!-- WRONG — multiple componentInstance in one itemInstances -->
<itemInstances>
<componentInstance>
<componentName>flexipage:field</componentName>
<identifier>field1</identifier>
</componentInstance>
<componentInstance>
<componentName>flexipage:field</componentName>
<identifier>field2</identifier>
</componentInstance>
</itemInstances>
<!-- CORRECT — each componentInstance in its own itemInstances -->
<itemInstances>
<componentInstance>
<componentName>flexipage:field</componentName>
<identifier>field1</identifier>
</componentInstance>
</itemInstances>
<itemInstances>
<componentInstance>
<componentName>flexipage:field</componentName>
<identifier>field2</identifier>
</componentInstance>
</itemInstances>fieldInstance Structure
Every fieldInstance requires:
<itemInstances>
<fieldInstance>
<fieldInstanceProperties>
<name>uiBehavior</name>
<value>none</value> <!-- none|readonly|required -->
</fieldInstanceProperties>
<fieldItem>Record.FieldName__c</fieldItem>
<identifier>RecordFieldName_cField</identifier>
</fieldInstance>
</itemInstances>Valid `uiBehavior` values (lowercase only):
| Value | Meaning |
|---|---|
none | Field respects standard editability settings (default) |
readonly | Field is permanently locked on this page |
required | Field must be filled out before saving on this page |
Rules:
- Each
<itemInstances>gets exactly ONE child (<componentInstance>or<fieldInstance>) - fieldInstance must have
fieldInstancePropertieswithuiBehavior - Use
Record.{Field}format - There is NO
editvalue — usenonefor standard editable fields
5. Unique Identifiers and Region Names (CRITICAL - PREVENTS DUPLICATE ERRORS)
EVERY identifier and region/facet name MUST be unique across the entire FlexiPage file.
- NEVER create two `<flexiPageRegions>` blocks with the same `<name>`
- If multiple components belong to same facet, combine them in ONE region with multiple `<itemInstances>`
- NEVER reuse the same `<identifier>` value
- Always read entire file first and extract ALL existing identifiers and names
- Element order inside `<flexiPageRegions>`:
<itemInstances>FIRST, then<mode>(if needed), then<name>, then<type>— NEVER put<name>/<type>before<itemInstances>
Wrong - This WILL FAIL with duplicate name error:
<!-- First field section in detail tab -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<identifier>flexipage_property_details_fieldSection</identifier>
...
</componentInstance>
</itemInstances>
<name>detailTabContent</name> <!-- WRONG: DUPLICATE NAME -->
<type>Facet</type>
</flexiPageRegions>
<!-- Second field section in detail tab -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<identifier>flexipage_pricing_fieldSection</identifier>
...
</componentInstance>
</itemInstances>
<name>detailTabContent</name> <!-- WRONG: DUPLICATE NAME - DEPLOYMENT FAILS -->
<type>Facet</type>
</flexiPageRegions>Correct - Combine itemInstances in ONE region:
<!-- Both field sections in same detail tab facet -->
<flexiPageRegions>
<itemInstances>
<componentInstance>
<identifier>flexipage_property_details_fieldSection</identifier>
...
</componentInstance>
</itemInstances>
<itemInstances>
<componentInstance>
<identifier>flexipage_pricing_fieldSection</identifier>
...
</componentInstance>
</itemInstances>
<name>detailTabContent</name> <!-- CORRECT: ONE REGION, MULTIPLE COMPONENTS -->
<type>Facet</type>
</flexiPageRegions>When to combine vs separate:
- Combine: Components that logically belong to same tab/section (e.g., multiple field sections in detail tab)
- Separate: Components that belong to different tabs/sections (e.g.,
detailTabContentvsrelatedTabContent)
---
6. Correct Element Names (CRITICAL — PREVENTS INVALID XML ERRORS)
FlexiPage XML uses specific element names. Common LLM hallucinations use WRONG names that cause deployment failures.
| WRONG (do NOT use) | CORRECT |
|---|---|
<entityType> | <sobjectType> |
<properties> | <componentInstanceProperties> |
<regions> | <flexiPageRegions> |
<components> | <itemInstances> |
<innerComponents> | (does not exist — use facets for nesting) |
<fieldItems> | <itemInstances> containing <fieldInstance> |
<template>value</template> | <template><name>value</name></template> |
<parentFlexiPage>flexipage:templateName</parentFlexiPage> | <parentFlexiPage>flexipage__default_rec_L</parentFlexiPage> |
Do NOT invent elements or component names:
Only use component names discovered through the 3-tier discovery process or present in the template from CLI. Do NOT add any XML element that is not present in the template structure from the CLI template. If a component name did not come from discovery or the CLI template.
| WRONG (do NOT use) | Why / What to use instead |
|---|---|
<apiVersion> | Not a FlexiPage element — API version lives in sfdx-project.json |
<description> | Not a FlexiPage element — use <masterLabel> for the page name |
flexipage:tabs | Does not exist — use flexipage:tabset + flexipage:tab in facets |
flexipage:tabset2 | Does not exist — correct name is flexipage:tabset |
flexipage:facet | Does not exist — use flexipage:column with body property |
flexipage:fields | Does not exist — use individual fieldInstance elements in a field facet |
<type>String</type> inside componentInstanceProperties | Remove — only valid <type> value is decorator, and only for UtilityBar pages |
Correct top-level FlexiPage structure (element order):
<?xml version="1.0" encoding="UTF-8"?>
<FlexiPage xmlns="http://soap.sforce.com/2006/04/metadata">
<flexiPageRegions>...</flexiPageRegions>
<masterLabel>Page Name</masterLabel>
<parentFlexiPage>flexipage__default_rec_L</parentFlexiPage>
<sobjectType>Account</sobjectType>
<template>
<name>flexipage:recordHomeTemplateDesktop</name>
</template>
<type>RecordPage</type>
</FlexiPage>Correct componentInstance structure:
<componentInstance>
<componentInstanceProperties>
<name>propertyName</name>
<value>propertyValue</value>
</componentInstanceProperties>
<componentName>lightning:card</componentName>
<identifier>unique_id_1</identifier>
</componentInstance>`<componentInstanceProperties>` children — `<name>`, `<value>`, and optionally `<type>`:
<!-- WRONG — "String", "Facet", etc. are NOT valid <type> values -->
<componentInstanceProperties>
<name>fieldApiName</name>
<type>String</type>
<value>Record.Name</value>
</componentInstanceProperties>
<!-- CORRECT — omit <type> for standard properties (most cases) -->
<componentInstanceProperties>
<name>fieldApiName</name>
<value>Record.Name</value>
</componentInstanceProperties>
<!-- CORRECT — <type>decorator</type> ONLY for UtilityBar component decorators -->
<componentInstanceProperties>
<name>panelHeight</name>
<type>decorator</type>
<value>480</value>
</componentInstanceProperties>`<type>` rules:
- If omitted (default): the property applies to the Lightning component itself
- If
decorator: the property applies to the component decorator (a wrapper that adds capabilities like height/width when opened) - The ONLY valid value is
decorator— neverString,Facet,Integer, etc. - Component decorators are ONLY supported on UtilityBar page types — do NOT use
<type>decorator</type>on RecordPage, AppPage, or HomePage
Nesting is done via facets, NOT via inner elements. Components that contain other components reference a facet name in their properties; the facet is a sibling <flexiPageRegions> with <type>Facet</type>.
| Error | Cause | Fix |
|---|---|---|
| "Element regions invalid in FlexiPage" | Used <regions> instead of <flexiPageRegions> | Replace with <flexiPageRegions> |
| "Element components invalid in FlexiPageRegion" | Used <components> instead of <itemInstances> | Replace with <itemInstances> |
| "couldn't retrieve design time component information" | Used hallucinated component name (flexipage:tabs, flexipage:tabset2) | Use flexipage:tabset — see identifiers_and_regions.md for the full 3-layer tab pattern |
---
Common Deployment Errors
| Error | Cause | Fix |
|---|---|---|
| "We couldn't retrieve or load the information on the field" | Invalid field API name — field doesn't exist or has incorrect spelling | Use MCP tools or describe commands to discover valid fields |
| "Invalid field reference" | Used ObjectName.Field instead of Record.Field | Change to Record.{FieldApiName} |
| "Element componentInstance is duplicated at this location in type ItemInstance" | Multiple <componentInstance> in one <itemInstances> | Each <componentInstance> needs its own <itemInstances> wrapper |
| "Element fieldInstance is duplicated" | Multiple fieldInstances in one <itemInstances> | Each fieldInstance needs its own <itemInstances> wrapper |
| "Missing fieldInstanceProperties" | No uiBehavior specified | Add fieldInstanceProperties with uiBehavior |
| "Unused Facet" | Facet defined but not referenced by any component | Remove Facet or reference it in a component property |
| "XML parsing error" | Unencoded HTML/XML in property values | Encode <, >, &, ", ' in all <value> tags |
| "Cannot create component with namespace" | Invalid page name (used __c suffix) | Use Volunteer_Record_Page not Volunteer__c_Record_Page |
| "Region specifies mode that parent doesn't support" | Added <mode> to a region that doesn't support it | Only use <mode> where required (e.g., <mode>Replace</mode> in detailTabContent for Dynamic Forms) |
| "We couldn't retrieve the design time component information for component X" | Hallucinated component name (e.g., flexipage:tabs, flexipage:tabset2) | Use correct component name — see Section 6 table and identifiers_and_regions.md for valid patterns |
| "'String' is not a valid value for the enum 'ComponentInstancePropertyTypeEnum'" | Used invalid <type> value (e.g., String, Facet, Integer) inside <componentInstanceProperties> | Remove <type> entirely — the only valid value is decorator, and only for UtilityBar page types |
| "Element apiVersion invalid at this location in type FlexiPage" | Added <apiVersion> to FlexiPage XML | Remove — API version belongs in sfdx-project.json, not in FlexiPage metadata |
#!/bin/bash
# resolve-component-instructions.sh — Resolve the instructions file path for a component.
#
# Usage: scripts/resolve-component-instructions.sh <componentDefinition>
#
# Arguments:
# componentDefinition — Component FQN in colon format (e.g., "flexipage:fieldSection")
#
# Output: The path to the instructions file if it exists, or empty string if not found.
#
# Examples:
# scripts/resolve-component-instructions.sh "record_flexipage:dynamicHighlights"
# → references/record_flexipage_dynamicHighlights.md
#
# scripts/resolve-component-instructions.sh "flexipage:fieldSection"
# → references/flexipage_fieldSection.md
#
# scripts/resolve-component-instructions.sh "c:expenseTracker"
# → (empty — file does not exist)
set -euo pipefail
COMPONENT="${1:-}"
if [ -z "$COMPONENT" ]; then
echo "Usage: $0 <componentDefinition>" >&2
exit 1
fi
# Derive filename: replace ':' with '_', append .md
FILENAME=$(echo "$COMPONENT" | sed 's/:/_/g').md
# Resolve path relative to the skill directory
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
FILEPATH="$SKILL_DIR/references/$FILENAME"
if [ -f "$FILEPATH" ]; then
echo "references/$FILENAME"
else
echo ""
fi
#!/bin/bash
# scan-lwc-components.sh — Scan local SFDX project for LWC components matching a query.
#
# Usage: scripts/scan-lwc-components.sh <query> [packageDirectory]
#
# Arguments:
# query — User intent keywords (e.g., "expense tracker")
# packageDirectory — SFDX package directory path (default: read from sfdx-project.json)
#
# Output: Ranked JSON array of matches with confidence scores.
# [{"name": "expenseTracker", "score": 75, "confidence": "high"}]
#
# Confidence tiers:
# high (≥70%): auto-select, confirm with user
# medium (40-69%): present ranked list for user selection
# low (<40%): skip, proceed to Tier 2
set -euo pipefail
QUERY="${1:-}"
PKG_DIR="${2:-}"
if [ -z "$QUERY" ]; then
echo "Usage: $0 <query> [packageDirectory]" >&2
exit 1
fi
# Resolve package directory from sfdx-project.json if not provided
if [ -z "$PKG_DIR" ]; then
if [ -f "sfdx-project.json" ]; then
PKG_DIR=$(python3 -c "
import json, sys
with open('sfdx-project.json') as f:
data = json.load(f)
dirs = data.get('packageDirectories', [])
if dirs:
print(dirs[0].get('path', 'force-app'))
else:
print('force-app')
" 2>/dev/null || echo "force-app")
else
PKG_DIR="force-app"
fi
fi
# Check if package directory exists
if [ ! -d "$PKG_DIR" ]; then
echo "[]"
exit 0
fi
# Tokenize query: lowercase, split on spaces
IFS=' ' read -ra QUERY_TOKENS <<< "$(echo "$QUERY" | tr '[:upper:]' '[:lower:]')"
# Find all LWC component directories
RESULTS="["
FIRST=true
while IFS= read -r dir; do
COMP_NAME=$(basename "$dir")
# Tokenize camelCase component name: split on uppercase boundaries → lowercase
COMP_TOKENS=$(echo "$COMP_NAME" | sed 's/\([a-z]\)\([A-Z]\)/\1 \2/g' | tr '[:upper:]' '[:lower:]')
IFS=' ' read -ra TOKENS <<< "$COMP_TOKENS"
TOTAL=${#TOKENS[@]}
if [ "$TOTAL" -eq 0 ]; then
continue
fi
# Count matched tokens
MATCHED=0
for qt in "${QUERY_TOKENS[@]}"; do
for ct in "${TOKENS[@]}"; do
if [ "$qt" = "$ct" ]; then
MATCHED=$((MATCHED + 1))
break
fi
done
done
# Calculate score
SCORE=$(( (MATCHED * 100) / TOTAL ))
# Determine confidence tier
if [ "$SCORE" -ge 70 ]; then
CONFIDENCE="high"
elif [ "$SCORE" -ge 40 ]; then
CONFIDENCE="medium"
else
CONFIDENCE="low"
fi
# Only include medium and high confidence matches
if [ "$SCORE" -ge 40 ]; then
if [ "$FIRST" = true ]; then
FIRST=false
else
RESULTS+=","
fi
RESULTS+="{\"name\":\"$COMP_NAME\",\"score\":$SCORE,\"confidence\":\"$CONFIDENCE\"}"
fi
done < <(find "$PKG_DIR" -path "*/lwc/*" -type d -maxdepth 5 | grep -v "__tests__")
RESULTS+="]"
# Sort by score descending (using python for JSON sorting)
echo "$RESULTS" | python3 -c "
import json, sys
data = json.load(sys.stdin)
data.sort(key=lambda x: x['score'], reverse=True)
print(json.dumps(data, indent=2))
" 2>/dev/null || echo "$RESULTS"
Related skills
FAQ
Is Platform Flexipage Generate safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.