platform-custom-setting-generate
Use this skill when users need to create, generate, or validate Salesforce Custom Setting metadata. Trigger when users mention custom settings (hier…
它会碰到什么
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
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.
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:
<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 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:
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:
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:
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:
- Warn prominently and first — before generating anything — that a custom setting is the wrong place
for a credential and the value will be readable.
- Recommend the right component — a Named Credential with an External Credential for callout
auth. Say plainly that this skill does not generate those.
- 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:
- Generate the object and field XML as normal.
- State the limitation in one line: setting values are data, not metadata, so they are not deployed.
- 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.
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).
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.
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:
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 |
|---|---|---|
| Admin-editable per profile/user, or a small keyed table that stays in one org | Custom Setting (this skill) | Values are data; they do not travel with a deploy |
| Reference data that must deploy between orgs with its records | platform-custom-metadata-type-generate | CMDT records are metadata and are deployable |
| Business records users create and edit at runtime | platform-custom-object-generate | Custom settings are configuration, not transactional data |
| Translatable UI text | Custom Label — this skill does not generate it | Labels are the supported translation surface |
| Credentials, API keys, tokens, endpoints with auth | Named Credential / External Credential — this skill does not generate them | See Section 5 |
| A permission check in Apex or a flow | Custom Permission — this skill does not generate it | Boolean access checks belong in the permission model |
The distinction that matters most: CMDT records deploy, custom setting values do not. If the user says
"and it should ship with these values" or "the same in every org," that is a CMDT request.
8. Common Deployment Errors
| Error Message | Cause | Fix |
|---|---|---|
| Must specify a non-empty plural label for the CustomObject | <customSettingsType> is missing, so this is being validated as a regular custom object | Add <customSettingsType>. Do NOT add <pluralLabel> (Section 2) |
| Cannot specify: pluralLabel for CustomSettings | <pluralLabel> present | Remove it — required on custom objects, forbidden here |
| Cannot specify: <element> for CustomSettings (<element> = nameField, sharingModel, deploymentStatus, validationRules, recordTypes, or compactLayouts) | A custom-object-only element is present | Remove it (enforce validation logic in Apex instead) |
| Invalid data type. | Unsupported field type (Section 4) | Read componentFailures[].fullName to find the field; switch to a supported type |
| Field manageability cannot be set on this entity. | <fieldManageability> on a setting field | Remove it — CMDT only |
| You can't set the visibility for a Custom Setting to Protected unless you are in a developer, sandbox, or scratch org. | Protected in a production-like org | Report to the user; never silently switch to Public (Section 5) |
The Cannot specify: suffix is for CustomSettings (one word) versus CMDT's for Custom Metadata Type,
and the visibility error uses for a Custom Setting (spaced, singular). Do not assume a shared template
when matching these strings.
9. Verification Checklist
Before generating custom setting XML, verify:
Component Identity Checks CRITICAL
- [ ] Is
<customSettingsType>present and set toHierarchyorList? - [ ] Is the choice between Hierarchy and List justified by the request (overridable vs keyed table)?
- [ ] If a deploy reported
Must specify a non-empty plural label for the CustomObject, was it fixed by adding<customSettingsType>rather than by adding<pluralLabel>? - [ ] After a successful deploy of a new setting, was it confirmed to actually be a custom setting? Inspecting the XML cannot catch this failure, because the wrong-component outcome deploys green. Run
sf sobject describe --sobject <Name>__c --target-org <alias>and verifycustomSettingistrue.
Syntactic Checks
- [ ] Are
<label>and<visibility>present? - [ ] Is
<description>present and specific about what the setting controls? - [ ] Is
<pluralLabel>ABSENT? - [ ] Are
<nameField>,<sharingModel>, and<deploymentStatus>ABSENT? - [ ] Are
<enableActivities>,<enableReports>,<enableHistory>, and<enableSearch>ABSENT? - [ ] Are
<validationRules>,<recordTypes>, and<compactLayouts>ABSENT? - [ ] Does the filename match the intended API name, ending in
__c?
Field Checks
- [ ] Is every field type in the supported list (Section 4)?
- [ ] Is
Picklistabsent? (unsupported — useText, or route to CMDT) - [ ] Is every
<formula>element absent? (formulas are unsupported) - [ ] Is
<fieldManageability>ABSENT on every field? - [ ] Do generic field attributes follow
platform-custom-field-generate?
Values Checks
- [ ] If the user asked for values, was the data-not-metadata limitation stated explicitly?
- [ ] Were
sfcommands given inline in the response, fully substituted with real API names and real values — not written to a file, not left as a template? - [ ] For a Hierarchy org default, is
SetupOwnerIdomitted rather than guessed? - [ ] For a List row, is
Namesupplied?
Consumption Checks
- [ ] If the user asked how to read the setting, was an Apex snippet given using the generated accessors (
getInstance/getOrgDefaultsfor Hierarchy,getValues/getAllfor List)? - [ ] Was the in-transaction DML rule stated — writes are DML that count against limits (bulkify, hoist out of loops), reads are free, and cross-transaction cache propagation lags?
Security Checks CRITICAL
- [ ] If the request involves a secret, key, token, or password, was the warning given before generating, with a Named Credential recommended?
- [ ] Was
Protectedleft intact rather than silently downgraded toPublicon an org-type failure?
Component-Choice Checks
- [ ] If the values must deploy between orgs, was
platform-custom-metadata-type-generaterecommended instead? - [ ] If the request is really business records, was
platform-custom-object-generaterecommended instead?
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。
它属于哪个仓库
同一个仓库里的其他技能
- commerce-b2b-open-code-components-integrate
- commerce-b2b-open-code-components-replace
- dx-devops-conflict-resolve
- dx-devops-pipeline-manage
- dx-devops-test-failures-analyze
- dx-devops-test-pipeline-configure
- dx-devops-test-suite-assignments-configure
- dx-devops-test-suite-run
- dx-devops-work-item-manage
- dx-app-analytics-query
- platform-agentexchange-partner-offers-configure
- automation-sandbox-post-copy-config-generate