description: "Use this skill when users need to create, generate, or validate Salesforce Custom Field metadata. Trigger when users mention custom fields, field types, Roll-up Summary fields, Master-Detail relationships, Lookup relationships, formula fields, picklists, dependent (controlling) picklists, referencing a value set from a field, or scoping/limiting picklist values for a specific record type. Also use when users encounter field deployment errors, especially around Roll-up Summary format, Master-Detail constraints, formula issues, or a record type that won't deploy without a business process. Use this skill for custom field metadata work, field generation, and field troubleshooting. DO NOT TRIGGER for creating or customizing the value set itself — defining a new GlobalValueSet, or modifying a StandardValueSet catalog like Industry or Lead Source — use platform-value-set-generate instead; this skill covers the field that references a value set, not the value set definition."
Generates and validates Salesforce CustomField metadata XML, with special handling for the **highest-failure-rate types** — Roll-Up Summary and Master-Detail. The agent must verify the constraints below before outputting XML to prevent Metadata API deployment errors.
| `<fullName>` | Required | **Field** name only: derive from `<label>` — capitalize each word, replace spaces with `_`, append `__c`. Must start with a letter. E.g., label `Total Contract Value` → `Total_Contract_Value__c`. This rule is for the FIELD name. **Picklist VALUE `<fullName>` is different — keep it exactly as the user spelled it, spaces and all, no `__c`** (e.g. `Closed Won`, NOT `Closed_Won`). See [`references/advanced-picklists.md`](references/advanced-picklists.md) (ref §3). |
| `<description>` | Always include | Explain the business reason *why* this field exists. |
| `<inlineHelpText>` | Always include | Actionable end-user guidance that adds value beyond the label (e.g., "Enter the value in USD including tax", not "The amount"). |
`<description>` and `<inlineHelpText>` are mandatory outputs even though the Metadata API does not enforce them — omitting them produces low-quality metadata.
**File path (SFDX source format):** save each field as `force-app/main/default/objects/<Object>/fields/<FieldName>__c.field-meta.xml`, where `<Object>` is the object's API name (`Account`, `Opportunity`, or a custom `Inventory_Item__c`). A correct XML at the wrong path is never seen by the Metadata API.
**Trigger:** If the user mentions "integration," "importing data," "external system ID," or "unique key from [System Name]," set `<externalId>true</externalId>`.
**TextArea: do NOT include `<length>`** — the Metadata API fixes the length at 255 implicitly and **rejects an explicit `<length>` value** with "Can not specify 'length' for a CustomField of type TextArea". Omit `<length>` entirely; the field only needs `<fullName>`, `<label>`, and `<type>TextArea</type>`.
**Always set `<restricted>true</restricted>`** inside `<valueSet>` unless the user explicitly says the picklist should accept custom values not in the admin-defined list (e.g. "unrestricted"/"open"). Restricted sets are capped at 1,000 total values (active + inactive). Minimal inline shape:
**Errors:** `Master-Detail Relationship Fields Cannot be Optional or Required` · `Can not specify 'deleteConstraint' for a CustomField of type MasterDetail` · `Lookup filters are only supported on Lookup Relationship Fields`
**COUNT:** identical structure to SUM but **omit `<summarizedField>` entirely** (and keep `<summaryForeignKey>`). **MIN / MAX:** identical to SUM — just `<summaryOperation>min</summaryOperation>` or `max`, with `<summarizedField>` pointing at the field to find the minimum/maximum of. The Quick Reference table below covers all four.
- The contents of the `<formula>` tag MUST be wrapped in a `<![CDATA[ ... ]]>` section. This prevents the XML parser from interpreting formula operators (like `&`, `<`, `>`) as XML markup.
- If the formula text itself contains the literal sequence `]]>`, escape it by breaking the CDATA block: e.g., `<![CDATA[Text_Field__c & "]]]]><![CDATA[>"]]>`
- NEVER use an attribute or tag named `returnType`. This does not exist in the Metadata API. The `<type>` tag defines the return data type of the formula result.
### formulaTreatBlanksAs Rule
**Decision Logic:**
- IF formula result type = `Number`, `Currency`, or `Percent` → set `<formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>`
- IF formula result type = `Text`, `Date`, or `DateTime` → set `<formulaTreatBlanksAs>BlankAsBlank</formulaTreatBlanksAs>`
- Formula fields that reference other fields fail deployment if the referenced field doesn't exist or hasn't deployed yet — deploy referenced fields first.
- Use `ISPICKVAL()` (not `==`) for picklist comparisons.
- For the full formula-function reference (TEXT/VALUE/CASE/DAY/MONTH/DATEVALUE/ISCHANGED type rules), defer to the `platform-validation-rule-generate` skill, which owns formula-function correctness.
| `ConversionError: Invalid XML tags or unable to find matching parent xml file for CustomField` | XML comments placed before the root `<CustomField>` element | Remove XML comments (`<!-- ... -->`) that appear before `<CustomField>` in the `.field-meta.xml` file |
| `Field [FieldName] does not exist. Check spelling.` | Referenced field does not exist or has not been deployed yet | Verify the referenced field exists and is deployed before this field |
| `DUPLICATE_DEVELOPER_NAME` | Field fullName already exists on the object | Use a unique business-driven name |
| `MAX_RELATIONSHIPS_EXCEEDED` | More than 2 Master-Detail or 15 Lookup fields on the object | Use Lookup for 3rd+ Master-Detail; review Lookup count |
| Reserved keyword error | Using `Order__c`, `Group__c`, etc. | Rename to `Status_Order__c`, etc. |
| `Value set must reference a value set name or define a value set, but not both` | `<valueSet>` has both `<valueSetName>` and `<valueSetDefinition>` | Keep exactly one (see Section 3.4) |
| `duplicate value found: [X] is defined multiple times` | Two `<value>` entries share a `<fullName>` | Make every picklist value `<fullName>` unique |
| `Invalid fullName` on a picklist value | Value `<fullName>` starts with a digit or contains hyphens | Start with a letter; no hyphens, no leading digit. Spaces ARE allowed — do NOT underscore them (see §3.4 value-name fidelity) |
| `Element ...picklist is not allowed` | Deprecated ≤37.0 dependent-picklist syntax (`<picklist>`/`<picklistValues>`/`<controllingFieldValues>`) | Use the modern `valueSettings`/`controllingFieldValue`/`valueName` form (Section 3.4) |
- [ ] Does each `<valueSet>` contain EITHER `<valueSetName>` OR `<valueSetDefinition>` — never both?
- [ ] For a value-set reference: is `<restricted>true</restricted>` set?
- [ ] For a StandardValueSet reference: is the name the bare enum with NO `__c` (e.g. `Industry`)?
- [ ] For a GlobalValueSet reference: is the name the **bare** developer name with NO `__gvs` suffix?
- [ ] For dependent picklists: is `<controllingField>` set, with one `<valueSettings>` (`<controllingFieldValue>` + `<valueName>`) per pair?
- [ ] For dependent picklists: is the deprecated `<picklist>`/`<picklistValues>`/`<controllingFieldValues>` form ABSENT?
- [ ] Are all picklist value `<fullName>` values unique, start with a letter, and free of hyphens? (spaces are allowed — do NOT replace them with underscores, per the §3.4 value-name fidelity rule)