--- name: platform-flexipage-generate description: "Use when users create, generate, modify, or validate Salesforce Lightning pages (FlexiPages). Trigger on RecordPage, AppPage, HomePage, Lightning pages, adding components to a page, page customization (e.g. 'customize the record page'), or .flexipage-meta.xml files (regions, components, deployment errors). DO NOT TRIGGER for Visualforce pages, page layout assignments in the UI, UI Bundle/Experience Cloud site pages, or Aura/Lightning Web Component development without FlexiPage context." allowed-tools: Bash Read Write metadata: version: "1.1" domains: ["Platform"] minApiVersion: "60.0" cliTools: - tool: ["python3"] semver: ">=3.10.0" - tool: ["sf"] semver: ">=2.126.4" mcpTools: metadata-experts: tools: ["execute_metadata_action"] semver: ">=1.0.0" --- ## 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. **``** = the `path` value from `sfdx-project.json` → `packageDirectories[0]` (e.g., `force-app`). Read it from the project file before running commands. ```bash sf template generate flexipage \ --name \ --template \ --sobject \ --primary-field \ --secondary-fields \ --detail-fields \ --output-dir /main/default/flexipages ``` **CRITICAL:** If the `sf template generate flexipage` command fails, **STOP**. 1. Install the templates plugin: ```bash sf plugins install templates ``` 2. 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` (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`): ```bash sf project deploy start --dry-run -d "/main/default" --test-level NoTestRun --wait 10 --json ``` **Critical:** 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 `` tags: `&` first, then `<`, `>`, `"`, `'` - Field references: `Record.{FieldApiName}` (never `Object.Field`) - Every `` and region `` must be unique across the file - Multiple components in same facet → combine in ONE region with multiple `` --- ### 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 ```xml Page Label RecordPage Object__c ``` **Page Types:** - `RecordPage` - requires `` - `AppPage` - no sobjectType - `HomePage` - no sobjectType --- ## Validation Checklist ### Structure (new pages) - [ ] Used CLI to bootstrap — never create FlexiPage XML from scratch ### Identifiers & Regions - [ ] All `` values unique across entire file - [ ] All region/facet `` values unique across entire file - [ ] Multiple components in same facet combined in ONE region with multiple `` ### Field Instances - [ ] All field references use `Record.{Field}` format - [ ] Each fieldInstance has `fieldInstanceProperties` with `uiBehavior` - [ ] Each fieldInstance in its own `` wrapper ### Types & Encoding - [ ] Template regions use `Region`; component facets use `Facet` - [ ] Property values with HTML/XML are entity-encoded - [ ] No unnecessary `` 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 5. Validate → check identifiers, regions, property completeness ``` **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/.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 `` XML for all resolved components: - Use `` for every property (NOT ``) - 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`): ```bash sf project deploy start --dry-run -d "/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 - `pageContext` with `entityName` is required for RECORD_PAGE - `getUiComponentSchemas` supports partial failures — check each component's `success` boolean --- ## 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): ```bash scripts/scan-lwc-components.sh "" [packageDirectory] ``` The script scans `/**/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 `` and `` 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 `` 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 ### Step 2: Apply Component Instructions (if present) Run `scripts/resolve-component-instructions.sh ` — it returns the instructions file path if it exists, or empty string. Examples: - `record_flexipage:dynamicHighlights` → `references/record_flexipage_dynamicHighlights.md` - `flexipage:fieldSection` → `references/flexipage_fieldSection.md` - `c: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 `` 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/_.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 `` 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 `` tags (must be entity-encoded) ### Structural Integrity - Every Facet referenced by a component property exists as a `` block - No orphan Facets (every Facet is referenced by exactly one component) - Multiple components in same region use ONE `` block with multiple `` ### 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