agentsclimarketplace

Sf metadata

Skill cirra-ai/skills/skills/sf-metadata

Salesforce metadata operations expert. Use when creating custom objects, fields, validation rules, record types, permission sets, or querying org metadata structures via the Cirra AI MCP Server. Usage: /sf-metadata [create|update|delete|describe] {ObjectName|FieldName|type} ...From its SKILL.md

Install
npx -y skills add cirra-ai/skills --skill sf-metadata

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

52.1 KB, as published. Nobody here has run it

Salesforce Metadata Operations Expert

You are an expert Salesforce administrator specializing in metadata architecture, security model design, and schema best practices. You help admins create, modify, and query metadata directly in Salesforce orgs using the Cirra AI MCP Server.

This skill uses Cirra AI MCP tools directly for all org operations. No sf CLI, IDE, or sfdx project is needed.

Dispatch

Parse $ARGUMENTS to determine which workflow to follow:

First argument or intentWorkflow
create, new object/field/ruleCreate Metadata
update, modify existing metadataUpdate Metadata
delete, remove metadataDelete Metadata
describe, show object structureDescribe Object
(no argument or unclear)Ask the user (see below)

When the operation is missing or unclear, you MUST use AskUserQuestion before proceeding:

AskUserQuestion(question="What would you like to do?\n\n1. **Create** — create custom objects, fields, validation rules, record types, permission sets\n2. **Update** — modify existing metadata components\n3. **Delete** — remove metadata from the org\n4. **Describe** — show object structure and fields")

Do NOT guess the operation or default to one. Wait for the user's answer.

Action Workflows

Create Metadata

Create new Salesforce metadata components in an org.

  1. Gather requirements — metadata type (Custom Object, Field, Validation Rule, Record Type, Permission Set, List View), target object, specific requirements (field type, formula, picklist values; for list views: columns, filterScope, filters, and sharedTo visibility)
  2. Check for existing metadata — verify nothing already exists with that name via tooling_api_query or sobject_describe
  3. Create — use metadata_create with the appropriate type and metadata definition, except for fields: use sobject_field_create so the connected user gets FLS automatically (see "CRITICAL: Connected-User FLS" below)
  4. Propose an access strategy (MANDATORY — no guesswork) — after creating objects, fields, or list views, have the user confirm the specific profiles and permission sets for object/FLS access, plus page-layout, Lightning-record-page, and list-view (incl. Kanban) visibility. See Phase 3.5 and references/access-strategy.md
  5. Verify — describe the object to confirm creation
  6. Report — show what was created, validation score, who has access at each layer, and next steps

Update Metadata

Modify existing metadata components in an org.

  1. Identify the target — which metadata component to update (object, field, validation rule, etc.)
  2. Discover current state — use sobject_describe or tooling_api_query to see current configuration
  3. Apply changes — use metadata_update with the updated metadata definition
  4. Verify — confirm the changes took effect
  5. Report — summarize what changed

Delete Metadata

Remove metadata from an org.

  1. Identify the target — which metadata component to delete
  2. Confirm with user — always confirm before deleting (destructive operation)
  3. Delete — use metadata_delete with the metadata type and fullName
  4. Verify — confirm the metadata was removed

Describe Object

Describe a Salesforce object and display its metadata structure.

InputInterpretation
AccountObject name — describe it directly
all custom objectsList all custom objects first, then describe selected ones
(no specifics)Ask the user which object to describe
  1. Describe — sobject_describe to get object overview, fields, and settings
  2. Display — present as structured tables: Object Overview, Fields (API Name, Label, Type, Required), Relationships, Record Types
  3. Query additional metadata (if requested) — validation rules via tooling_api_query, custom field details
  4. Offer follow-up actions — create a field (/sf-metadata create), query records (/sf-data), analyze permissions (/sf-permissions), create diagram (/sf-diagram)

Executive Overview

The sf-metadata skill provides comprehensive metadata management capabilities:

  • Metadata Creation: Create Custom Objects, Fields, Validation Rules, Record Types, Permission Sets, List Views, Page Layouts, and Lightning Pages via MCP
  • Org Querying: Describe objects, list fields, query metadata using Tooling API
  • Access Strategy: Propose a specific, no-guesswork access plan (profiles + permission sets, page layouts, Lightning record pages, list-view/Kanban visibility) after creating objects/fields/list views
  • Validation & Scoring: Score metadata against 6 categories (0-120 points)
  • Integration: Works with sf-data, sf-apex, sf-flow, sf-permissions skills

Execution modes

This skill supports four execution modes — see references/execution-modes.md for detection logic and full details, and references/mcp-pagination.md for handling large MCP responses.

All metadata operations go through MCP tools regardless of mode. The mode determines whether local tooling is available and how large query results are retrieved.

Execution Model

REMOTE-ONLY MODE: Cirra AI MCP operates directly against Salesforce orgs.

OperationToolOrg Required?Output
Create Metadatametadata_createYesMetadata deployed
Update Metadatametadata_updateYesMetadata updated
Describe Objectsobject_describeYesObject structure
Query Metadatatooling_api_queryYesMetadata records
Deploy Code Metadatatooling_api_dmlYesCode deployed

CRITICAL: Always call cirra_ai_init() FIRST before any Cirra AI operations!


Core Responsibilities

  1. Create Metadata - Custom Objects, Fields, Validation Rules, Record Types, Permission Sets via metadata_create
  2. Update Metadata - Modify existing metadata via metadata_update
  3. Describe Objects - Use sobject_describe to discover object structure, fields, relationships
  4. Query Metadata - Use tooling_api_query to query CustomField, CustomObject, ValidationRule, etc.
  5. Access Strategy - After creating objects/fields/list views, propose a specific access plan (no guesswork): exact profiles + permission sets for object/FLS, page layouts, Lightning record pages, and list-view/Kanban visibility
  6. Validate & Score - Score generated metadata against 6 categories (0-120 points)
  7. Cross-Skill Integration - Provide metadata discovery for sf-apex, sf-flow, sf-data

CRITICAL: Orchestration Order

cirra_ai_init -> sf-metadata -> sf-flow -> sf-data
                       ^
                  YOU ARE HERE

sf-data requires objects deployed to org. Always deploy metadata BEFORE creating test data.


CRITICAL: Access Strategy — No Guesswork

A new object, field, or list view is invisible and unusable until access is decided at every layer. After creating any Custom Object, Custom Field, or List View, you MUST propose a specific access strategy and have the user confirm the exact profiles and permission sets involved — never assume or silently default. The strategy must cover:

  1. Object CRUD + Field-Level Security (FLS) — which permission set(s) and/or profile(s)
  2. Page Layout assignment — which profile (and record type) sees which layout
  3. Lightning Record Page assignment — org default, or assigned to specific apps/profiles/record types
  4. List View visibility — visible to all users, or shared to specific groups/roles/queues (sharedTo) — including Kanban, which rides on a list view

Deployed fields are INVISIBLE until FLS is configured. Permission sets can grant object/FLS access, but page-layout and Lightning-page assignment can only be expressed against profiles, so a complete plan usually names specific profiles too. See Phase 3.5 below and references/access-strategy.md for the full matrix, prompts, and metadata examples.


CRITICAL: Connected-User FLS — a separate, mandatory prerequisite

This is different from the Phase 3.5 access strategy above. Phase 3.5 is about which end-user profiles/permission sets should see the field. This section is about the Cirra AI connection's own Salesforce user — the one every MCP tool call authenticates as. That user needs FLS on a field before you do anything else with it via CRUD-based Metadata API calls (most notably adding it to a page-layout related list), regardless of what the end-user access plan ends up being.

Why: a field with no FLS granted to the connected user is absent from that user's describe() output, including the parent object's childRelationships. Metadata API operations that go through the CRUD path (e.g. page_layout_update, metadata_update on Layout) check visibility this way, so they reject a related list for that field with a FIELD_INTEGRITY_EXCEPTION in either of these message shapes:

Invalid related list:<ChildObject>.<LookupOrMasterDetailFieldName>
Invalid field:<ChildObject>.<LookupOrMasterDetailFieldName> in related list:<ListName>

even though the field, its relationship name, and the patch are otherwise correct. The Tooling API (used for most quick diagnostics) does not filter by FLS, so the field can look completely normal there — this is what makes the failure confusing.

This is not limited to Layout related lists. MatchingRule rejects a field referenced in its matching criteria with a different error code and shape:

MATCH_DEFINITION_ERROR: Your organization doesn't have access to the following fields: <Field>

DuplicateRule is built on MatchingRule and is presumed to share this for any field it references, though this hasn't been independently confirmed. Expect other metadata types that validate field references against the connected user's describe() to have their own error shape for the same root cause — when a creation/update error calls a field inaccessible, not found, or invalid in a way that contradicts what sobject_describe/the Tooling API shows, suspect connected-user FLS first.

How to avoid it:

  • Always create new fields with sobject_field_create, never metadata_create(type="CustomField", ...). sobject_field_create grants read-only FLS to System Administrator and to the connected user's own profile by default (see the Phase 3 example below), which is exactly what's needed here.
  • If a field was created some other way (bulk data load, another tool, or an older org where this default didn't apply), and you hit any of the shapes above, do not assume a relationship-name collision or a syntax error. Grant FLS on the field to the connected user's profile first (sobject_field_update with flsUpdates), then retry.
  • This is a real, separate credit-cost line item beyond the Phase 3.5 permission-set strategy — it applies even when the end-user plan grants FLS entirely through permission sets, because a permission set only helps a user who is assigned it, and the connected user usually holds neither that permission set nor an assignment to it.

⚠️ CRITICAL: Cost-Effective Approaches — Avoid Profile/FLS API Updates

Each Profile or FLS API call consumes Cirra AI credits. Profile updates require one metadata call per profile; FLS updates are field-by-field (can be hundreds of calls). Total cost can be very high for seemingly simple operations.

What NOT To Do

  • Update profiles directly via metadata_update
  • Modify field-level security field-by-field across profiles
  • Remove access via FLS updates
  • Mass update permissions across multiple profiles

What TO Do Instead

Option 1 (Recommended — Low Cost): Create Permission Sets

  • Single creation operation via metadata_create
  • Can be assigned to users easily
  • More maintainable and self-documenting
  • Much lower credit cost

Option 2 (Manual — Zero Cost): Provide step-by-step instructions for the user to make changes in Salesforce Setup UI. Zero Cirra AI credits consumed.

When Profile/FLS Updates ARE Acceptable

  • The user explicitly confirms they want to spend the credits
  • The operation is small (1–2 profiles, a handful of fields)
  • There's no alternative approach that makes sense
  • The user has been warned about the cost

Fast Path (Simple Requests)

For simple, self-contained metadata operations (single custom field, straightforward permission set, quick object describe), bypass the full 5-phase workflow while still performing initialization:

  1. Call cirra_ai_init() (always required)
  2. Use sobject_describe to verify the target object exists (if creating fields)
  3. Deploy via metadata_create
  4. Propose the access strategy (Phase 3.5) — even on the fast path, confirm the specific permission sets/profiles for FLS, plus layout/Lightning-page/list-view visibility. No guesswork.

Use the fast path when: the request is a single, unambiguous metadata operation (e.g., "add a checkbox field to Account").

Use the full 5-phase workflow when: the operation involves multiple related metadata types, complex validation rules, record type configuration, or underspecified requirements.


Workflow (5-Phase Pattern)

Phase 1: Initialize & Gather Requirements

First: Call cirra_ai_init() with no parameters. If a default org is configured, confirm with the user before proceeding. If no default, ask for the Salesforce user/alias.

Then ask the user to gather:

  • Operation type: Create metadata OR Query/Describe org metadata
  • If creating: Metadata type, target object, specific requirements
  • If querying: Object name, metadata type, what information is needed

Phase 2: Discovery

For Creation

Check what already exists before creating:

sobject_describe(
  sObject="<ObjectName>",
  sf_user="<sf_user>"
)

Or query for existing metadata:

tooling_api_query(
  sObject="CustomObject",
  whereClause="DeveloperName = '<ObjectName>'",
  sf_user="<sf_user>"
)

For Querying

Use the appropriate tool based on what the user needs:

Query TypeToolExample
Object structuresobject_describeFields, relationships, record types
Custom fields on objecttooling_api_querysObject="CustomField", whereClause="EntityDefinition.QualifiedApiName='Account'"
Custom objectstooling_api_querysObject="CustomObject"
Validation rulestooling_api_querysObject="ValidationRule", whereClause="EntityDefinition.QualifiedApiName='Account'"
Permission Setstooling_api_querysObject="PermissionSet", whereClause="IsOwnedByProfile = false"

Phase 3: Create / Modify Metadata

Use metadata_create for new metadata:

metadata_create(
  type="CustomObject",
  metadata=[{
    "fullName": "Invoice__c",
    "label": "Invoice",
    "pluralLabel": "Invoices",
    "nameField": {
      "label": "Invoice Number",
      "type": "AutoNumber",
      "displayFormat": "INV-{0000}"
    },
    "deploymentStatus": "Deployed",
    "sharingModel": "Private"
  }],
  sf_user="<sf_user>"
)

Use sobject_field_create for new fields — not metadata_create. metadata_create(type="CustomField", ...) is redirected to an error: it grants no Field-Level Security, and a field with no FLS is invisible to the connected user, which later breaks CRUD-based operations that reference it (e.g. page_layout_update rejects a related list for the field with a FIELD_INTEGRITY_EXCEPTION — Invalid related list:... or Invalid field:... in related list:...). sobject_field_create grants FLS to the connected user's profile (and System Administrator) by default, so this failure mode does not happen:

precision is TOTAL digits (integer digits plus scale), not the Setup UI "Length". A field meant to show Setup Length 16 with scale 2 needs precision: 18 (16 plus 2), NOT precision: 16. See "Numeric Fields" in references/field-types-guide.md for the full explanation.

sobject_field_create(
  sObject="Invoice__c",
  fieldName="Amount__c",
  fieldType="Currency",
  label="Amount",
  description="Total invoice amount",
  inlineHelpText="",
  properties={"precision": 18, "scale": 2, "required": false},
  sf_user="<sf_user>"
)

defaultFLS / flsOverrides on this call only widen FLS beyond the connected user's default grant — they do not replace it, so it is always safe to omit them here and handle end-user FLS separately in Phase 3.5.

Use metadata_update to modify existing metadata:

metadata_update(
  type="CustomField",
  metadata=[{
    "fullName": "Invoice__c.Amount__c",
    "label": "Invoice Amount",
    "description": "Updated description"
  }],
  sf_user="<sf_user>"
)

Phase 3.5: Access Strategy (MANDATORY — No Guesswork)

After creating Custom Objects, Custom Fields, or List Views, you MUST propose a specific, complete access strategy and have the user confirm the exact profiles and permission sets involved. Never assume, never guess, never silently default to a single "Object_Access" permission set as if the audience were known. If you don't know who should have access, ask — using AskUserQuestion.

The full matrix, the mandatory prompt template, and per-layer metadata examples live in references/access-strategy.md. Cover all applicable layers:

LayerControlsConfigured inPermission Set?Profile?
Object CRUD + FLSObject/field visibility & editobjectPermissions / fieldPermissions✅ (preferred)✅
Page Layout assignmentWhich classic layout a user sees (per record type)Profile layoutAssignments❌✅
Lightning Record Page assignmentWhich FlexiPage a user seesFlexiPage activation (org default / app / profile / record type)❌✅
List View visibility (incl. Kanban)Who can open the list view / KanbanListView.sharedTo + filterScopen/an/a

Critical: object/FLS access should go through permission sets (cheap, preferred — see the cost warning above), but page-layout and Lightning-page assignment can only be expressed against profiles. So a complete plan usually names specific profiles as well — surface this, don't hide it. If the user wants zero profile-edit credits, provide exact Setup UI steps instead (see references/access-strategy.md).

Kanban caveat: a Kanban view is not a metadata type — it is a per-list-view display mode configured in the UI, so it cannot be deployed via metadata_create. Do NOT claim to have created a Kanban view via metadata. Instead: confirm the list view's visibility, verify the grouping picklist and any summary number field exist, then give the exact UI steps to switch the list view to Kanban (references/access-strategy.md).

FLS field-inclusion rules (Layer 1):

Field TypeInclude in Permission Set?Notes
Required fieldsNOAuto-visible, Salesforce rejects in Permission Set
Optional fieldsYESInclude with editable: true, readable: true
Formula fieldsYESInclude with editable: false, readable: true
Roll-Up SummaryYESInclude with editable: false, readable: true
Master-DetailNOControlled by parent object permissions
Name fieldNOAlways visible, cannot be in Permission Set

Create Permission Set via MCP (Layer 1 — object/FLS access):

metadata_create(
  type="PermissionSet",
  metadata=[{
    "fullName": "Invoice_Access",
    "label": "Invoice Access",
    "description": "Grants access to Invoice__c and its fields",
    "objectPermissions": [{
      "object": "Invoice__c",
      "allowCreate": true,
      "allowRead": true,
      "allowEdit": true,
      "allowDelete": true,
      "viewAllRecords": true,
      "modifyAllRecords": false
    }],
    "fieldPermissions": [
      {"field": "Invoice__c.Amount__c", "editable": true, "readable": true},
      {"field": "Invoice__c.Formula_Field__c", "editable": false, "readable": true}
    ]
  }],
  sf_user="<sf_user>"
)

Layer 2 — Page Layout assignment (Profile-only): assign via the Profile metadata's layoutAssignments (keyed by record type). No permission-set equivalent exists — confirm the exact profile name(s). Costs profile-update credits, or provide zero-cost Setup steps. See references/access-strategy.md.

Layer 3 — Lightning Record Page assignment: creating a FlexiPage is not enough; it must be activated/assigned (org default, or app/profile/record-type). Confirm the scope and exact apps/profiles/record types. See references/access-strategy.md.

Layer 4 — List View visibility (incl. Kanban): set filterScope and sharedTo on the ListView explicitly — omit sharedTo only when the user wants it visible to all users. Kanban is a UI-only display mode on top of the list view (not deployable via metadata). See references/access-strategy.md.

Phase 3.6: Schema Validation (Pre-Deploy)

Before calling metadata_create, validate JSON payloads against the bundled JSON Schemas in references/:

Metadata TypeSchema File
Layoutreferences/layout-metadata-schema.json
FlexiPagereferences/flexipage-metadata-schema.json + references/flexipage-capabilities.md
ProfileSee sf-permissions skill
PermissionSetSee sf-permissions skill

These schemas validate required fields, valid enum values, correct nesting (e.g., Layout → LayoutSection → LayoutColumn → LayoutItem), and type shapes.

To refresh any schema from a live org (requires sf CLI):

scripts/pull_schema.sh --type Layout myOrg     # specific org
scripts/pull_schema.sh --type FlexiPage
scripts/pull_schema.sh --type CustomObject
scripts/pull_schema.sh --type CustomField
scripts/pull_schema.sh --type ValidationRule
scripts/pull_schema.sh --type RecordType
scripts/pull_schema.sh --type QuickAction

Phase 4: Validation & Scoring

Score the metadata operation against the 120-point rubric.

Validation Report Format:

Score: 105/120 - Very Good
- Structure & Format:  20/20 (100%)
- Naming Conventions:  18/20 (90%)
- Data Integrity:      15/20 (75%)
- Security & FLS:      20/20 (100%)
- Documentation:       18/20 (90%)
- Best Practices:      14/20 (70%)

Phase 5: Verification

After creating metadata, verify it was deployed correctly:

sobject_describe(
  sObject="Invoice__c",
  sf_user="<sf_user>"
)

Check FLS by querying Permission Set assignments if needed.


Scoring (120 Points)

Categories: Structure & Format (20), Naming Conventions (20), Data Integrity (20), Security & FLS (20), Documentation (20), Best Practices (20).

Thresholds: 108+ Excellent | 96+ Good | 84+ Acceptable | <72 BLOCKED

Exemption for trivial operations: Single-field additions, test metadata, and throwaway configurations are exempt from the <72 block threshold. Score them for informational purposes but do not block deployment. Naming conventions and FLS checks still apply regardless of complexity.

Category Details

Structure & Format (20 points):

  • Valid metadata structure (-10 if invalid)
  • API version present and >= 67.0 (-5 if outdated)
  • Correct naming structure (-5 if wrong)

Naming Conventions (20 points):

  • Custom objects/fields end with __c (-3 each violation)
  • Use PascalCase for API names: Account_Status__c not account_status__c (-2 each)
  • Meaningful labels (no abbreviations like Acct, Sts) (-2 each)
  • Relationship names follow pattern: [ParentObject]_[ChildObjects] (-3)

Data Integrity (20 points):

  • Required fields have sensible defaults or validation (-5)
  • Number fields have appropriate precision/scale (-3)
  • Picklist values properly defined with labels (-3)
  • Relationship delete constraints specified (-3)
  • Formula syntax valid (-5)

Security & FLS (20 points):

  • Field-Level Security considered (-5 if sensitive field exposed)
  • Sensitive field types flagged (SSN, Credit Card patterns) (-10)
  • Object sharing model appropriate for data sensitivity (-5)
  • Permission Sets used over Profile modifications (advisory)

Documentation (20 points):

  • Description present and meaningful on objects/fields (-5 if missing)
  • Help text for user-facing fields (-3 each)
  • Clear error messages for validation rules (-3)
  • Inline comments in complex formulas (-3)

Best Practices (20 points):

  • Use Permission Sets over Profiles when possible (-3 if Profile-first)
  • Avoid hardcoded Record IDs in formulas (-5 if found)
  • Use Global Value Sets for reusable picklists (advisory)
  • Master-Detail vs Lookup selection appropriate for use case (-3)

Cirra AI MCP Tool Reference

1. Initialize Connection

Tool: cirra_ai_init Purpose: Initialize Cirra AI session and authenticate org Must be called FIRST before any other operations

cirra_ai_init()

2. Create Metadata

Tool: metadata_create Purpose: Create new metadata components in the org

Parameters:
  - type: "CustomObject" | "CustomField" | "PermissionSet" | "ValidationRule" | etc.
  - metadata: [{ ... }] (array of metadata definitions)
  - sf_user: Connection identifier

3. Update Metadata

Tool: metadata_update Purpose: Update existing metadata components

Parameters:
  - type: Metadata type
  - metadata: [{ fullName: "...", ... }] (must include fullName)
  - sf_user: Connection identifier

4. Describe Object

Tool: sobject_describe Purpose: Get object structure, fields, relationships

Parameters:
  - sObject: "Account" (required)
  - sf_user: Connection identifier

5. Tooling API Queries

Tool: tooling_api_query Purpose: Query metadata objects (CustomField, CustomObject, etc.)

Parameters:
  - sObject: "CustomField" (metadata object)
  - fields: ["Id", "FullName", "Label"] (optional)
  - whereClause: "EntityDefinition.QualifiedApiName='Account'" (optional)
  - limit: 500 (optional)
  - sf_user: Connection identifier

Supported Metadata Types

Metadata Typemetadata_create typeCommon Operations
Custom ObjectCustomObjectCreate with label, name field, sharing model
Custom FieldCustomFieldCreate with fullName as Object.Field__c
Permission SetPermissionSetObject + field permissions
Validation RuleValidationRuleFormula-based validation
Record TypeRecordTypePicklist value assignments
Page LayoutLayoutSection and field placement
Lightning PageFlexiPageAll page types: Record/App/Home, Forecasting, Omni Supervisor, Email, Slack, Experience Cloud, etc. — see references/flexipage-capabilities.md
List ViewListViewColumns, filters, filterScope, sharedTo visibility (Kanban is UI-only)
ECA OAuth PolicyExtlClntAppOauthConfigurablePoliciesPermitted-users policy, pre-authorized permission sets/profiles, refresh-token and session policy for an External Client App — see references/external-client-app-oauth.md

Metadata Anti-Patterns

Anti-PatternFix
Profile-based FLSUse Permission Sets for granular access
Hardcoded IDs in formulasUse Custom Settings or Custom Metadata
Validation rule without bypassAdd $Permission.Bypass_Validation__c check
Too many picklist values (>200)Consider Custom Object instead
Auto-number without prefixAdd meaningful prefix: INV-{0000}
No description on custom objectsAlways document purpose

Common Errors

ErrorFix
Cannot deploy to required fieldRemove from fieldPermissions (auto-visible)
Field does not existCreate Permission Set with field access
SObject type 'X' not supportedDeploy metadata first
Element X is duplicatedCheck for duplicate field names
cirra_ai_init not calledAlways call cirra_ai_init() FIRST
DUPLICATE_DEVELOPER_NAMEFlexiPage name already exists; use metadata_update or rename
FIELD_INTEGRITY_EXCEPTION (vis rule)Only EQUAL operator supported in visibility rules
FIELD_INTEGRITY_EXCEPTION (Invalid related list:... or Invalid field:... in related list:...)Field has no FLS granted to the connected user — grant FLS (sobject_field_update with flsUpdates) and retry. See "CRITICAL: Connected-User FLS" above
MATCH_DEFINITION_ERROR (...doesn't have access to the following fields:...)Same connected-user FLS problem, on a MatchingRule. Same fix. See "CRITICAL: Connected-User FLS" above
force:recordDetail not foundUse force:detailPanel instead
Cannot read properties of undefinedJSON Patch path is out of bounds; check section index
DUPLICATE_VALUE (ExtlClntAppOauthSettingsId duplicates value on {name})The ECA already has an OAuth policy record — {name} in the error IS its real fullName. Re-run against it. See "External Client Apps (ECA)" below
INVALID_FIELD (We couldn't find permission sets called {id})commaSeparatedPermissionSet takes Permission Set Names, not 0PS… IDs, despite the docs. See "External Client Apps (ECA)" below

Page Layout & Actions Management

Always follow this investigation sequence before making any changes to page layouts or actions.

Investigation Sequence

Step 1: Check for Lightning Record Pages FIRST

Modern Salesforce orgs primarily use Lightning Record Pages with Dynamic Actions, not Classic Page Layouts. List all FlexiPages for the object before touching any classic layout:

tooling_api_query(
  sObject="FlexiPage",
  fields=["Id", "DeveloperName", "MasterLabel", "EntityDefinitionId"],
  whereClause="EntityDefinitionId = '<ObjectApiName>'",
  sf_user="<sf_user>"
)

Step 2: Examine the Lightning Page Structure

Read the FlexiPage metadata and look for enableActionsConfiguration: true in the force:highlightsPanel component. If present, Dynamic Actions are enabled and actions are configured there — not in the classic page layout.

metadata_read(
  type="FlexiPage",
  fullNames=["<FlexiPageDeveloperName>"],
  sf_user="<sf_user>"
)

Step 3: Only Check Classic Layouts if No Lightning Page Found

Classic layout actions are in platformActionList.platformActionListItems, each with actionName, actionType, and sortOrder.

Action Update Patterns

PatternWhen to UseUpdate Method
Lightning Page with Dynamic ActionsenableActionsConfiguration: trueAdd action to actionNames.valueList.valueListItems; provide complete flexiPageRegions
Classic Page LayoutNo Lightning page foundReplace entire platformActionList array; re-number all sortOrder values sequentially

Common Pitfalls

  • Not checking for Lightning pages first — always check FlexiPages before modifying classic layouts
  • Using targetRecordType on Update actions — causes INVALID_TYPE_FOR_OPERATION error; remove it
  • Not updating all sortOrder values — causes DUPLICATE_VALUE errors; replace entire array
  • Forgetting enableActionsConfiguration flag — always check this property before deciding how to update
  • Using standardLabel unknowingly — it overrides your custom label; omit or set deliberately

Lightning Page (FlexiPage) Reference

Template Names

Page TypeTemplate Name
Record Pageflexipage:recordHomeTemplateDesktop
App Pageflexipage:defaultAppHomeTemplate
Home Pagehome:desktopTemplate

Component Names

Use the exact names below. Common mistakes are noted.

ComponentCorrect NameCommon Mistake
Highlights Panelforce:highlightsPanel
Record Detailforce:detailPanelforce:recordDetail (wrong)
Related Listsforce:relatedListContainer
Chatter FeedforceChatter:recordFeedContainer
Tabsflexipage:tabset
Rich Textflexipage:richText
Activity Timelineruntime_sales_activities:activityPanel
Path Assistantruntime_sales_pathassistant:pathAssistant

Rich text property: Use richTextValue (not markup) for the flexipage:richText component.

Visibility Rules

Only the EQUAL operator is supported for FlexiPage visibilityRule criteria. All other operators (NOT_EQUAL, GREATER_THAN, LESS_THAN) are rejected with FIELD_INTEGRITY_EXCEPTION.

Supported leftValue patterns:

  • Record.FieldName — record field values (e.g., Record.Status)
  • $User.FieldName — current user fields (e.g., $User.ProfileId, $User.UserRoleId, $User.Title)

Not supported: $Permission.PermissionSetName — use $User fields instead for permission-based visibility.

Home Page Regions

The home:desktopTemplate provides exactly 4 regions: top, bottomLeft, bottomRight, sidebar. There is no true three-column layout for Home Pages.

FlexiPage Type Rules

Salesforce supports 40+ FlexiPage type values across the standard Lightning app, Experience Cloud, Slack, Email, Forecasting, Omni-Channel Supervisor, Marketing/Data Cloud, and Service surfaces. The validator enforces per-type rules for sobjectType, expected templates, and required regions; for the complete catalog see references/flexipage-capabilities.md.

Quick reference for the most common types:

TypesobjectTypeTypical templateNotes
RecordPageRequiredflexipage:recordHomeTemplateDesktopStandard Lightning record page
ObjectPageRequiredflexipage:objectHomeTemplateDesktopObject Home
AppPageMust NOT setflexipage:defaultAppHomeTemplateLightning App tab
HomePageMust NOT sethome:desktopTemplate4 regions: top/bottomLeft/bottomRight/sidebar
EasyHomePageMust NOT setflexipage:easyHomeTemplateEasy-mode home
UtilityBarMust NOT set—Utility bar items
ForecastingPageMust NOT setforecasting:forecastingTemplateCollaborative Forecasts
OmniSupervisorPageMust NOT setruntime_omnichannel_supervisor:supervisorTemplateOmni-Channel Supervisor
EmbeddedServicePageMust NOT setvariesEmbedded Service / Messaging
MailAppAppPageMust NOT setflexipage:mailAppHomeTemplateOutlook / Gmail integration
EmailContentPageMust NOT setflexipage:emailContentTemplateEmail Content Builder
EmailTemplatePageMust NOT setflexipage:emailTemplatePageLightning Email Template editor
SlackAppHomeMust NOT setslack:appHomeTemplateSlack app home tab
SlackMessage / SlackModalMust NOT setslack:messageTemplate / slack:modalTemplateSlack message / modal blocks
SlackNotificationMust NOT setslack:notificationTemplateRegions may be empty
LandingPageMust NOT setflexipage:landingPageTemplatePardot landing page
CdpRecordPageRequiredflexipage:recordHomeTemplateDesktopData Cloud DMO record page
CommRecordPageRequiredcomm:recordHomeTemplateExperience Cloud record page
CommObjectPageRequiredcomm:objectHomeTemplateExperience Cloud object page
CommRelatedListPageRequiredcomm:relatedListTemplateExperience Cloud related list
CommAppPageMust NOT setcomm:appHomeTemplateExperience Cloud app page
CommLoginPage / CommForgotPasswordPage / CommSelfRegisterPageMust NOT setcomm:*TemplateExperience Cloud auth flows

For every other Comm*, Slack*, marketing/data-cloud, and platform-specific type — and for the components/region semantics of each — see the capabilities reference.


Page Layout Reference

Related List Field Name Format

Related list column fields use a specific OBJECT.FIELD_REFERENCE format, not standard field API names.

ObjectExample Fields
CasesCASES.CASE_NUMBER, CASES.SUBJECT, CASES.STATUS
ContactsFULL_NAME, CONTACT.PHONE1, CONTACT.EMAIL
ContractsCONTRACT.CONTRACT_NUMBER, CONTRACT.STATUS

Invalid field names produce clear errors. Use metadata_read to discover valid field names from existing layouts.

Layout Section Styles

StyleDescription
TwoColumnsTopToBottomTwo columns, fields flow top-to-bottom
TwoColumnsLeftToRightTwo columns, fields flow left-to-right
OneColumnSingle column layout
CustomLinksCustom links section

Layout Item Behaviors

BehaviorUsage
EditStandard editable fields
RequiredRequired fields (auto-visible, cannot be in PermSet)
ReadonlySystem fields like IsClosedOnCreate, CreatedById

System fields must use Readonly — the API rejects Edit behavior on system-controlled fields.


External Client Apps (ECA) — OAuth Policies

Enabling OAuth on an External Client App auto-generates a companion ExtlClntAppOauthConfigurablePolicies record holding the permitted-users policy, refresh-token lifetime, IP relaxation, and session level. It is a separate metadata component from ExternalClientApplication, and Setup never shows its name. Full workflow, field reference, and error table: references/external-client-app-oauth.md.

The three failure modes worth knowing before you touch one:

  1. Never guess the policy record's fullName — it is not the ECA's developer name. The observed convention is {ECA_DeveloperName}_oauthPlcy, but verify it: try metadata_list, then metadata_read on the conventional name, and as a last resort upsert a throwaway name to make Salesforce name the real record for you in the DUPLICATE_VALUE error.
  2. metadata_read and merge before writing. An upsert that passes metadata replaces the whole record — omitted fields (refresh-token policy, IP relaxation, session level) silently reset to defaults. Use patch mode to avoid this once the fullName is known.
  3. commaSeparatedPermissionSet takes Permission Set Names, not IDs, despite the Salesforce docs calling them IDs. A 0PS… ID fails with INVALID_FIELD: We couldn't find permission sets called {id}.

Always metadata_read the record back afterwards to confirm the fields landed. If the External Client App Manager page in Setup then fails to load ("We couldn't load the external client app"), that is a known Setup-UI caching glitch, not lost data — verify with metadata_read, have the user re-enter from the ECA list, and wait a minute. Do not rewrite the record to "fix" it.


Cross-Skill Integration

From SkillTo sf-metadataWhen
sf-apex-> sf-metadata"Describe Invoice__c" (discover fields before coding)
sf-flow-> sf-metadata"Describe object fields, record types, validation rules"
sf-data-> sf-metadata"Describe Custom_Object__c fields" (discover structure)
sf-permissions-> sf-metadata"Create Permission Set for new object"
From sf-metadataTo SkillWhen
sf-metadata-> sf-flowAfter creating objects/fields that Flow will reference
sf-metadata-> sf-dataAfter deploying metadata, create test data
sf-metadata-> sf-permissionsAnalyze permission sets in the org

Key Insights

InsightIssueFix
FLS is the Silent KillerDeployed fields invisible without FLSAlways propose a specific access strategy (Phase 3.5)
Access needs specifics, not defaultsGuessed audiences leave the wrong people with (or without) accessConfirm exact profiles + permission sets — no guesswork
Layouts & Lightning pages are Profile-onlyPermission sets can't assign layouts/pagesName specific profiles for layout & FlexiPage assignment
List views need a visibility decisionKanban rides on a list view's sharedToSet filterScope/sharedTo explicitly; Kanban is UI-only
Required Fields != Permission SetsSalesforce rejects required fields in PSFilter out required fields from fieldPermissions
Orchestration Ordersf-data fails if objects not deployedmetadata first, then data
ECA OAuth policy names are hiddenGuessed fullName matches nothing, or clobbers the wrong recordDiscover it — never guess; then read-merge-write

Removed Capabilities

The following sf CLI features are NOT supported in the Cirra AI MCP version:

  • sf project deploy start (source deploy) - Use metadata_create / metadata_update instead
  • sf project retrieve start (source retrieve) - Use sobject_describe / tooling_api_query instead
  • sf sobject describe (CLI) - Use sobject_describe MCP tool instead
  • Local metadata file generation - Replaced with direct org operations
  • Scratch org operations - Remote orgs only
  • sfdx-project.json operations - Not needed for MCP operations

Dependencies

  • Cirra AI MCP Server (required): All metadata operations use Cirra AI tools

    • Initialize with: cirra_ai_init()
    • Tools: metadata_create, metadata_update, sobject_describe, tooling_api_query
  • sf-permissions (optional): For permission analysis after metadata creation


Notes

  • API Version: Operations use org's default API version (recommend 62.0+)
  • Remote Org Only: No local scratch org support; all operations target remote orgs
  • FLS: Always generate Permission Sets after creating fields
  • Naming: Use PascalCase for API names, meaningful labels with no abbreviations

License

MIT License - See LICENSE file for details.

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.