Skip to main content

platform-custom-setting-generate

Use to create, generate, or validate Salesforce Custom Setting metadata. Trigger on custom settings (hierarchy/list), customSettingsType, SetupOwnerId, per-profile/per-user config overrides, feature flags/toggles, kill switches, or admin on/off switches (e.g. bypass triggers during a data load); also "create a custom setting" or a setting that silently deployed as a regular object. A kill switch is just a checkbox on a hierarchy setting — generate ONLY the setting, never an Apex trigger/handler. DO NOT TRIGGER for Custom Metadata Types (use platform-custom-metadata-type-generate), business-record objects (use platform-custom-object-generate), or secrets/tokens (use a Named Credential).

Datos de origen

Repositorio
forcedotcom/sf-skills
Última actividad en el origen
15 de octubre de 2026 a las 07:57
Idioma detectado de SKILL.md
inglés
Estrellas
1094
Forks
371

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
platform-custom-setting-generate
description
Use to create, generate, or validate Salesforce Custom Setting metadata. Trigger on custom settings (hierarchy/list), customSettingsType, SetupOwnerId, per-profile/per-user config overrides, feature flags/toggles, kill switches, or admin on/off switches (e.g. bypass triggers during a data load); also "create a custom setting" or a setting that silently deployed as a regular object. A kill switch is just a checkbox on a hierarchy setting — generate ONLY the setting, never an Apex trigger/handler. DO NOT TRIGGER for Custom Metadata Types (use platform-custom-metadata-type-generate), business-record objects (use platform-custom-object-generate), or secrets/tokens (use a Named Credential).
metadata
{"version":"1.0","minApiVersion":"60.0","domains":["Platform"],"relatedSkills":["platform-custom-field-generate","platform-custom-metadata-type-generate","platform-custom-object-generate","platform-metadata-api-context-get"],"cliTools":[{"tool":"[Truncated]","semver":">=2.136.8"}]}
# Salesforce Custom Setting Generator and Validator ## When to Use This Skill Use this skill when you need to: - Create a Hierarchy or List custom setting - Generate custom setting metadata XML - Add or validate fields on an existing custom setting - Populate custom setting **values** (these are data, not metadata — see Section 6) - Troubleshoot custom setting deployment errors > **A trigger bypass / kill switch is a Custom Setting — not Apex and not a `__mdt`.** When the user wants a > switch admins can flip to turn behavior on or off — "disable my Account triggers during a data load", a > feature toggle, a maintenance-mode flag — generate **only** a hierarchy custom setting with a `Checkbox` > field (e.g. `Disable_Triggers__c` / `Bypass__c`). Do **not** author the Apex trigger, handler, or test > that reads it, and do **not** model it as a Custom Metadata Type: the per-profile/per-user override a > bypass flag needs is exactly what a hierarchy custom setting gives you and a `__mdt` does not. The Apex > that checks the flag is the developer's to write — this skill generates the setting only. --- For authoritative Metadata API type, field, and enum details beyond this skill, use the `platform-metadata-api-context-get` skill. ## 1. Overview and Purpose This document defines the mandatory constraints for generating Custom Setting metadata. A custom setting is a `CustomObject` with `<customSettingsType>` set — it is **not** a distinct metadata type. **File extension:** `.object-meta.xml` **File path:** `force-app/main/default/objects/<Name>__c/<Name>__c.object-meta.xml` **API name suffix:** `__c` (identical to a regular custom object — the suffix does **not** distinguish them) > **Values are data, not metadata.** You can generate the setting's *definition* as XML, but you cannot > deploy its *values* that way. There is no source-format equivalent of `customMetadata/` for custom > settings. Never generate a file that claims to carry setting values — see **Section 6** for what to do > instead. --- ## 2. Syntactic Essentials (Tier 1) ### `<customSettingsType>` is mandatory — CRITICAL **This is the single highest-severity rule in this skill.** Omitting `<customSettingsType>` does not produce a "you forgot customSettingsType" error. The component silently stops being a custom setting and is validated as a plain custom object. The failure is dangerous because it is *recoverable in the wrong direction*: an agent that omits the element, then obediently fixes each error the platform reports, ends up with a **green deploy and completely the wrong kind of component**. | What you see | What it means | |---|---| | `Must specify a non-empty plural label for the CustomObject` | You are **NOT** building a custom setting. `customSettingsType` is missing. Add it — do **not** add `pluralLabel`. | | `Cannot specify: nameField for CustomSettings` | You **ARE** building a custom setting. Remove the named element. | These two strings are mutually exclusive tells. The giveaway in the first is the phrase **`for the CustomObject`** and the absence of any mention of custom settings. **If a deploy reports `Must specify a non-empty plural label for the CustomObject` on something the user asked to be a custom setting, never satisfy that error by adding `<pluralLabel>`.** Adding it (plus `nameField`, `deploymentStatus`, and `sharingModel`) makes the deploy succeed and creates a regular custom object that the user did not ask for. ### Required and Allowed Elements | Element | Requirement | Notes | |---------|-------------|-------| | `<customSettingsType>` | **Required** | `Hierarchy` or `List` — see Section 3 | | `<label>` | **Required** | Singular UI name | | `<visibility>` | Always include | `Public`, or `Protected` only in a dev/sandbox/scratch org (Section 5) | | `<description>` | Always include | Explain what the setting controls and who edits it | | `<enableFeeds>` | Optional | Accepted | | `<listViews>` | Optional | Accepted — permitted despite `recordTypes` and `compactLayouts` being forbidden | ### Forbidden Elements Every element below produces `Cannot specify: <element> for CustomSettings`: | Forbidden element | Note | |---|---| | `<pluralLabel>` | **Required on a regular custom object, forbidden here.** Exactly inverted. | | `<nameField>` | The `Name` field exists implicitly on List settings | | `<deploymentStatus>` | | | `<sharingModel>` | Custom settings are not shared records | | `<enableActivities>` `<enableReports>` `<enableHistory>` `<enableSearch>` | | | `<validationRules>` | Enforce these in Apex instead | | `<recordTypes>` | | | `<compactLayouts>` | | **INCORRECT** — carries a regular custom object's required elements: ```xml <CustomObject xmlns="http://soap.sforce.com/2006/04/metadata"> <customSettingsType>Hierarchy</customSettingsType> <label>Feature Flags</label> <pluralLabel>Feature Flags</pluralLabel> <!-- WRONG: forbidden on custom settings --> <sharingModel>ReadWrite</sharingModel> <!-- WRONG: forbidden --> <deploymentStatus>Deployed</deploymentStatus> <!-- WRONG: forbidden --> <nameField> <!-- WRONG: forbidden --> <label>Name</label> <type>Text</type> </nameField> <visibility>Public</visibility> </CustomObject> ``` **Errors:** `Cannot specify: pluralLabel for CustomSettings` · `Cannot specify: sharingModel for CustomSettings` · `Cannot specify: deploymentStatus for CustomSettings` · `Cannot specify: nameField for CustomSettings` **CORRECT** — minimum valid custom setting: ```xml <?xml version="1.0" encoding="UTF-8"?> <CustomObject xmlns="http://soap.sforce.com/2006/04/metadata"> <customSettingsType>Hierarchy</customSettingsType> <label>Feature Flags</label> <description>Per-profile and per-user toggles for beta features in the ordering app. Edited by admins in Setup.</description> <visibility>Public</visibility> </CustomObject> ``` Note there is no `<fullName>`. A root-level one is tolerated and ignored, but omit it — the API name comes from the directory and filename. `<customSettingsType>List</customSettingsType>` deployed without needing the "Manage List Custom Settings Type" toggle in Setup. That toggle exists in some orgs, so if a List setting is rejected on a `customSettingsType` grounds in a different org, check Schema Settings before assuming the XML is wrong. --- ## 3. List vs Hierarchy Decision (Tier 2) `<customSettingsType>` has exactly two values, and the choice changes how rows are addressed. | | `Hierarchy` | `List` | |---|---|---| | **Use when** | The value can vary per profile or per user, with an org-wide fallback | The setting is a small keyed reference table, the same for everyone | | **Row key** | `SetupOwnerId` (Organization, Profile, or User) | `Name` | | **Resolution** | User value → Profile value → org default | Look up by `Name` | | **Apex read** | `MySetting__c.getInstance()` / `getOrgDefaults()` | `MySetting__c.getValues('Key')` / `getAll()` | | **Typical case** | Feature flags, per-profile limits, debug toggles | Country codes, tax rates by region, integration endpoints by key | **Default to `Hierarchy`** when the user describes toggles, limits, or anything that "can be overridden." Choose `List` when they describe a lookup table with named rows. If the user asks for a keyed reference table that should be **deployable between orgs**, a List custom setting is usually the wrong answer — its rows are data and will not travel with the deploy. Route to `platform-custom-metadata-type-generate` instead (Section 7). --- ## 4. Field Rules Fields on a custom setting are ordinary `CustomField` components at `objects/<Name>__c/fields/<Field>__c.field-meta.xml`. **This skill owns the custom-setting-specific deltas only** — the supported-type allowlist and the `fieldManageability` prohibition below. For everything generic (`<fullName>` derivation, `<label>`, `<description>`, `<inlineHelpText>`, precision/scale, `<length>`, `externalId`), follow `platform-custom-field-generate`. ### Supported Field Types `Checkbox`, `Currency`, `Date`, `DateTime`, `Email`, `Number`, `Percent`, `Phone`, `Text`, `TextArea`, `Url` `required`, `unique`, `externalId`, and `defaultValue` are accepted on custom setting fields. Whether a given one applies to a given type is a generic field rule — defer to `platform-custom-field-generate`. ### Unsupported Field Types `Picklist`, `MultiselectPicklist`, `LongTextArea`, `Html`, `Lookup`, `MasterDetail`, `AutoNumber`, `Location`, `Time`, `EncryptedText`, and **Formula** (a `<formula>` element on any type). Every one of these fails with the same bare, uninformative string: ```text Invalid data type. ``` **This error names neither field nor type.** On a multi-field deploy, read `componentFailures[].fullName` from the `--json` output to find the culprit — do not guess. **Roll-up summary fields are structurally impossible here** — a `Summary` needs a master-detail child, and `MasterDetail` is itself rejected on a custom setting. Don't generate one; the error text varies, so don't match on a specific string. **Picklist is the common trap.** Users frequently ask for a picklist on a custom setting. It is not supported. Use `Text` and enforce the allowed values in Apex, or route the request to `platform-custom-metadata-type-generate` — CMDT *does* support Picklist. Near-inversion vs CMDT: `Currency` works here but not on CMDT; `Picklist`/`LongTextArea` work on CMDT but not here. Never carry field-type assumptions across the two families. ### `<fieldManageability>` is forbidden That element belongs to CMDT fields only. On a custom setting field it fails with: ```text Field manageability cannot be set on this entity. ``` --- ## 5. Visibility, Secrets, and the No-Silent-Downgrade Rule ### `Protected` is org-type dependent `<visibility>Protected</visibility>` deploys only in a developer, sandbox, or scratch org. Anywhere else: ```text You can't set the visibility for a Custom Setting to Protected unless you are in a developer, sandbox, or scratch org. ``` ### The no-silent-downgrade rule — CRITICAL **If `Protected` fails because of the org type, never "fix" it by switching to `Public`.** A silent downgrade turns a deliberate confidentiality choice into a world-readable component with no signal. Report it plainly: the org does not permit `Protected`, so the options are a dev/sandbox/scratch org or accepting `Public` — let the user decide. This applies to any visibility narrowing, not just this error. ### Secrets do not belong in a custom setting Custom settings are **not** a secret store. Values are readable by anyone who can query the object, and `Protected` does not change that for code in the same namespace. When a user asks to store an API key, password, token, client secret, or certificate in a custom setting: 1. **Warn prominently and first** — before generating anything — that a custom setting is the wrong place for a credential and the value will be readable. 2. **Recommend the right component** — a **Named Credential** with an **External Credential** for callout auth. Say plainly that this skill does not generate those. 3. **If the user still insists, comply** — generate the setting but keep the warning in the response. Do not silently refuse, and do not silently obey. Never route a secret to `Protected` visibility as a compromise: if `Protected` is unavailable (above), the no-silent-downgrade rule applies with full force, because the downgrade would publish the secret. --- ## 6. Setting Values Are Data, Not Metadata **A custom setting's rows cannot be deployed as XML.** There is no `customMetadata/`-style folder for them. Only the object definition and its fields are metadata. When a user asks to create a setting *with values* — "add a feature flag setting with Beta enabled for admins" — do all of the following: 1. Generate the object and field XML as normal. 2. **State the limitation in one line:** setting values are data, not metadata, so they are not deployed. 3. **Give ready-to-run commands inline in the chat response**, fully substituted with the real object and field API names and the actual values — not a placeholder template, and not written to a file. All three shapes below are verified working. ### Hierarchy — org-wide default row **Omit `SetupOwnerId`.** It defaults to the Organization Id, which is exactly the org-default row. No Id lookup is needed. ```bash sf data create record --sobject Feature_Flags__c \ --values "Enable_Beta__c=true Max_Retries__c=3" \ --target-org <alias> ``` ### Hierarchy — profile or user override This one **does** need an Id, so it is two steps. A user-level override uses the same shape with a `User` Id in place of the Profile Id (extrapolated from the profile case, not separately verified). ```bash sf data query --query "SELECT Id FROM Profile WHERE Name='System Administrator'" --target-org <alias> sf data create record --sobject Feature_Flags__c \ --values "SetupOwnerId=00eXXXXXXXXXXXXXXX Enable_Beta__c=false" \ --target-org <alias> ``` An override row coexists with the org-default row; it does not replace it. ### List — one row per key `Name` is the row key and is required. ```bash sf data create record --sobject Country_Codes__c \ --values "Name='US' Iso_Code__c='USA' Dial_Prefix__c='+1'" \ --target-org <alias> ``` ### Quoting Wrap the whole `--values` argument in double quotes; single-quote any value with a space or shell-special character (`Environment_Label__c='org default'`). Plain numbers, booleans, and Ids need no inner quotes. ### Consuming a setting in Apex Values are read through the generated typed class — cached, so reads cost **no SOQL** and are safe inside loops and triggers. For a **Hierarchy** setting: ```apex Feature_Flags__c cfg = Feature_Flags__c.getInstance(); // running user: user → profile → org default Feature_Flags__c org = Feature_Flags__c.getOrgDefaults(); // org-default row only, no hierarchy Feature_Flags__c forProfile = Feature_Flags__c.getInstance(profileId); // a User Id works too Boolean beta = cfg.Enable_Beta__c; ``` `getInstance()` and `getOrgDefaults()` **never return null** (API ≥ 22) — a missing record comes back as an empty row, so test `org.Id != null` when you need to know whether a real record actually exists. For a **List** setting, use `getValues('Key')` for one row or `getAll()` for the `Map<String, Feature_Flags__c>` of every row. ### The in-transaction DML rule Populating or changing values is **runtime DML** (Apex `insert`/`update`/`upsert`, or the `sf` commands above) — there is no metadata path. That is the operational face of "values are data," and it has two consequences worth stating to the user: - **Writes count against DML governor limits; reads do not.** In a trigger over 200 records, never `upsert` the setting once per record — hoist the write out of the loop and do it once. - **Cross-transaction propagation lags.** After a write, other transactions may briefly read the previous value while the org cache propagates; within the same transaction the new value is visible immediately. --- ## 7. Choosing the Right Component Before generating, confirm a custom setting is actually what the user needs. If it is not, say so and name the right skill rather than building the wrong thing. | If the config is… | Use | Why | |---|---|---|
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub