platform-value-set-generate — скилл для Claude Code: value sets
Скилл собирает и проверяет метаданные Salesforce GlobalValueSet и StandardValueSet, чтобы деплой не падал на ошибках.
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a claude-codeЧто делает platform-value-set-generate
Скилл берёт на себя два типа метаданных с переиспользуемыми списками значений. GlobalValueSet — это набор, который заводится один раз и подключается к любому числу полей-списков. StandardValueSet — правка встроенного каталога вроде Industry или Lead Source: имя набора там фиксированное, но значения менять и добавлять можно.
Внутри — правила синтаксиса XML и разбор частых ошибок деплоя. Для GlobalValueSet имя берётся из имени файла, а не из тега <fullName>, обязательны <masterLabel>, <sorted> и хотя бы одно <customValue>. Суффикс __gvs в метаданных не пишется: и файл, и ссылка из поля идут с голым developer name. Поле подключается к набору через <valueSetName>.
Разовый список на одном поле без переиспользования — не сюда, для этого есть platform-custom-field-generate. Скиллу нужен sf версии 2.0.0 и выше, а также MCP-сервер metadata-grounding с инструментами query_metadata и search_metadata.
Какие задачи решает
- создать переиспользуемый набор значений для нескольких полей
- добавить значения во встроенный список вроде Industry
- починить ошибку деплоя при правке стандартного списка
- связать поле с набором через
<valueSetName> - проверить XML набора до выкладки в орг
Примеры запросов агенту
- Сделай GlobalValueSet с приоритетами: критичный, высокий, средний и низкий, средний по умолчанию
- Добавь в стандартный набор Industry новое значение и покажи готовый XML
- Проверь мой файл набора значений на ошибки перед деплоем
Как установить platform-value-set-generate
1Через Skills CLI (Vercel)
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a claude-code2Вручную: положить файлы
~/.claude/skills/platform-value-set-generate/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/platform-value-set-generate/
1Через Skills CLI (Vercel)
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a codex2Вручную: положить файлы
.agents/skills/platform-value-set-generate/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a cursor2Вручную: положить файлы
.cursor/skills/platform-value-set-generate/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install forcedotcom/sf-skills platform-value-set-generate2Вручную: положить файлы
.github/skills/platform-value-set-generate/SKILL.md1Через Skills CLI (Vercel)
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a gemini-cli2Командой платформы
gemini skills install https://github.com/forcedotcom/sf-skills --path skills/platform-value-set-generateВручную: положить файлы
.devin/skills/platform-value-set-generate/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о platform-value-set-generate
Как установить platform-value-set-generate в Claude Code?
Выполните npx skills add forcedotcom/sf-skills --skill platform-value-set-generate -a claude-code. Скилл окажется в ~/.claude/skills/platform-value-set-generate/SKILL.md.
Что делает platform-value-set-generate?
Генерирует и проверяет метаданные GlobalValueSet и StandardValueSet, а также подсказывает, как сослаться на набор из поля.
Чем GlobalValueSet отличается от StandardValueSet?
Первый лежит в globalValueSets/ и получает имя из файла, второй — в standardValueSets/, где <fullName> совпадает с фиксированным именем каталога. Новое имя для стандартного набора придумать нельзя.
Исходный текст
SKILL.md · Apache-2.0
---
name: platform-value-set-generate
description: "Use to create, generate, or validate a Salesforce GlobalValueSet (reusable picklist shared across fields) or customize a StandardValueSet (built-in picklists like Industry, Lead Source, Opportunity Stage). Trigger on global/standard value set, reusable picklist, .globalValueSet-meta.xml or .standardValueSet-meta.xml, or deploy errors adding values to a standard picklist. DO NOT TRIGGER for a one-off inline picklist on a single field with no reuse — use platform-custom-field-generate."
metadata:
version: "1.0"
domains: ["Platform"]
minApiVersion: "60.0"
relatedSkills:
- "platform-custom-field-generate"
- "platform-metadata-api-context-get"
cliTools:
- tool: ["sf"]
semver: ">=2.0.0"
mcpTools:
metadata-grounding:
tools: ["query_metadata", "search_metadata"]
semver: ">=1.0.0"
---
## Overview
Generates and validates the two reusable picklist value-set metadata types — **GlobalValueSet** (a new reusable set shared across fields) and **StandardValueSet** (customizing a built-in catalog picklist like Industry or Lead Source) — and wires a CustomField to one via `<valueSetName>`.
For authoritative Metadata API type, field, and enum details beyond this skill, use the `platform-metadata-api-context-get` skill.
### Scope
- **In scope:** creating a GlobalValueSet, customizing a StandardValueSet, referencing either from a field, and the related deployment errors.
- **Out of scope:** a one-off inline picklist on a single field with no reuse → use **`platform-custom-field-generate`** (inline `<valueSetDefinition>`). Generating the *field* that references a value set is also `platform-custom-field-generate`'s job; this skill produces the value set itself.
**Two different metadata types — do not confuse them:**
| Concern | GlobalValueSet | StandardValueSet |
|---------|----------------|------------------|
| Folder | `globalValueSets/` | `standardValueSets/` |
| File suffix | `.globalValueSet-meta.xml` | `.standardValueSet-meta.xml` |
| Root element | `<GlobalValueSet>` | `<StandardValueSet>` |
| Name source | filename (dev name) | `<fullName>` = fixed catalog name |
| Value element | `<customValue>` | `<standardValue>` |
| Can add NEW values? | Yes | Yes — copy the attribute pattern of an existing value |
| Can create a new NAME? | Yes | No — only the fixed catalog |
| `*` wildcard in package.xml | Supported | Not supported |
---
## Specification
### 1. Purpose
This document defines the mandatory constraints for generating value-set metadata XML. The agent must verify these constraints before outputting XML to prevent Metadata API deployment errors.
- **GlobalValueSet** — a reusable, named set of picklist values defined once and referenced by any number of picklist/multi-select fields. Use when the same value list is shared across multiple fields.
- **StandardValueSet** — the value list behind a Salesforce-defined standard picklist (Industry, Lead Source, etc.). You can only customize the fixed catalog of named sets, so you cannot invent a new set name, but you can modify existing values and add new ones.
---
### 2. GlobalValueSet — Syntactic Essentials
**File:** `globalValueSets/<DeveloperName>.globalValueSet-meta.xml`
The developer name comes from the **filename**, not a `<fullName>` tag.
#### Required Elements
| Element | Requirement | Notes |
|---------|-------------|-------|
| `<masterLabel>` | Required | UI label for the value set |
| `<sorted>` | Required | `true` = alphabetize values in the UI; `false` = preserve listed order |
| `<customValue>` | Required (≥1) | One per value (see below) |
#### `<customValue>` Sub-Elements
| Sub-element | Requirement | Notes |
|-------------|-------------|-------|
| `<fullName>` | Required | The value's API name. Use the value text **as the user spelled it** — spaces are allowed and must be preserved (e.g. `Closed Won`, not `Closed_Won`). Must start with a letter. This is a value name, NOT a field API name, so do not append `__c` or replace spaces with underscores. |
| `<default>` | Optional | At most one value `true`. Omit it (or use `false`) on the rest — it is not required on every value. |
| `<label>` | Required | UI label for the value |
| `<color>` | Optional | Hex color, e.g. `#FF0000` |
| `<isActive>` | Optional | Omit (active) or `false` to deactivate |
| `<description>` | Optional | Per-value description |
#### The `__gvs` Suffix — do NOT use it in metadata
**Rule: reference a GlobalValueSet by its bare developer name. Never add `__gvs`.**
In API 57.0+ orgs the platform *stores/displays* a GlobalValueSet's developer name with a `__gvs` suffix internally, but the **Metadata API (deploy and retrieve) always uses the bare name** — `<valueSetName>Priority_Levels</valueSetName>`, not `Priority_Levels__gvs`. The suffix was briefly emitted by a Winter '23 change that caused deploy failures and was patched out. So:
- The file is `globalValueSets/Priority_Levels.globalValueSet-meta.xml` — **no `__gvs`** in the filename.
- A field references it as `<valueSetName>Priority_Levels</valueSetName>` — **no `__gvs`**.
- If a retrieve shows `Priority_Levels__gvs` in the org or you see a "returned from org but not found in local project" warning, that's the expected org-storage display — keep your local metadata on the bare name.
#### CORRECT — GlobalValueSet
```xml
<?xml version="1.0" encoding="UTF-8"?>
<GlobalValueSet xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>Priority Levels</masterLabel>
<sorted>false</sorted>
<customValue>
<fullName>Critical</fullName>
<default>false</default>
<label>Critical</label>
</customValue>
<customValue>
<fullName>High</fullName>
<default>false</default>
<label>High</label>
</customValue>
<customValue>
<fullName>Medium</fullName>
<default>true</default>
<label>Medium</label>
</customValue>
<customValue>
<fullName>Low</fullName>
<default>false</default>
<label>Low</label>
</customValue>
</GlobalValueSet>
```
#### INCORRECT — GlobalValueSet
```xml
<GlobalValueSet xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Priority_Levels</fullName> <!-- WRONG: name comes from the filename -->
<masterLabel>Priority Levels</masterLabel>
<!-- WRONG: <sorted> is required and missing -->
<standardValue> <!-- WRONG: GVS uses <customValue>, not <standardValue> -->
<fullName>Critical</fullName>
</standardValue>
</GlobalValueSet>
```
**Errors:** missing required `sorted`; unknown element `standardValue`; root `fullName` is rejected because the name is derived from the filename.
---
### 3. StandardValueSet — Syntactic Essentials CRITICAL
**File:** `standardValueSets/<Name>.standardValueSet-meta.xml`
#### HARD CONSTRAINTS — read before generating
1. **A StandardValueSet name must come from the fixed catalog of named standard value sets.** You **cannot** create a new StandardValueSet name. You **can** add a new value to an existing standard set, but copy the full attribute pattern of an existing value in that set (for example `closed`, `forecastCategory`, `probability` and `won` on `OpportunityStage`), because omitted attributes are filled with platform defaults that can be wrong.
2. The root carries a `<fullName>` whose value is the **fixed enum name** (e.g. `Industry`), NOT a `masterLabel`. The filename must match this name.
3. Values are `<standardValue>` entries — **not** `<customValue>`.
4. **A StandardValueSet write REPLACES the whole set. Send every existing value and change only what the request names.** Read the current set first (grounding MCP or a retrieve), then include a `<standardValue>` block for every existing value, with the requested activations, deactivations, relabels or additions applied. A value you leave out is deactivated on the field: a deploy that named only `Web` in `CaseOrigin` left `Email`, `Phone` and `Agentforce` inactive. Never send only the named values, even when the set is large (for example all 30+ `Industry` entries). Request wording such as "keep *only* X active" means set X active and every other value inactive, so state that intent in the result. Verify by reading the set back and diffing it against the read taken before the write.
#### `<standardValue>` — Modifiable Sub-Elements
| Sub-element | Modifiable? | Notes |
|-------------|-------------|-------|
| `<fullName>` | Identifies the value | An existing value, or a new one you are adding |
| `<label>` | Yes | Relabel the value's UI text |
| `<isActive>` | Yes | `false` deactivates; omit or `true` keeps active |
| `<default>` | Yes | At most one value `true` |
| `<groupingString>` | Yes | Category grouping (used by some standard picklists) |
#### Canonical StandardValueSet Names (partial)
`Industry`, `LeadSource`, `OpportunityStage`, `OpportunityType`, `AccountType`, `AccountRating`, `LeadStatus`, `CaseStatus`, `CaseOrigin`, `CasePriority`, `CaseReason`, `TaskStatus`, `TaskPriority`, `QuoteStatus`, `Product2Family`, `Salutation`, `AccountOwnership`, `ContractStatus`, `OrderStatus`, `PartnerRole`.
> Full appendix: the complete list of valid standard value set names is at
> `https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/standardvalueset_names.htm`.
> If the name is not in that appendix, it is **not** a StandardValueSet — it is either a GlobalValueSet or an inline CustomField picklist.
#### CORRECT — StandardValueSet (the complete set, with the requested change applied)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<StandardValueSet xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Industry</fullName>
<standardValue>
<fullName>Technology</fullName>
<default>false</default>
<label>Technology</label>
<isActive>true</isActive>
</standardValue>
<standardValue>
<fullName>Agriculture</fullName>
<default>false</default>
<label>Agriculture</label>
<isActive>false</isActive> <!-- deactivated, but kept in the set -->
</standardValue>
<!-- ... every other existing standardValue entry repeated unchanged ... -->
</StandardValueSet>
```
#### INCORRECT — StandardValueSet
```xml
<StandardValueSet xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>Industry</masterLabel> <!-- WRONG: StandardValueSet uses <fullName>, not masterLabel -->
<customValue> <!-- WRONG: uses <standardValue>, not customValue -->
<fullName>Renewable Energy</fullName>
<label>Renewable Energy</label>
</customValue>
</StandardValueSet>
```
**Errors:** unknown element `masterLabel`/`customValue` for a StandardValueSet.
---
### 4. Never Invent Values — Verify, Don't Hallucinate CRITICAL
When customizing a **StandardValueSet** (or extending a shared GlobalValueSet), **never invent the existing value list of a standard picklist**. Existing values must be repeated exactly as the org has them, and a new value is added only when the request names it.
For well-known standard picklists you already know the canonical values (e.g. `Industry`, `LeadSource`, `OpportunityStage`). When you are unsure which values exist, you can confirm them against the live org — but treat lookup as a *confirmation* step, not a required first call:
- **Grounding MCP** (if available) exposes `search_metadata` and `query_metadata` to look up live metadata. Use them to read the complete current set, because a write must repeat every existing value with its exact `<fullName>`/`<label>`.
- **CLI fallback** — query the Tooling API directly:
```bash
sf data query --use-tooling-api \
--query "SELECT MasterLabel, Metadata FROM StandardValueSet WHERE MasterLabel = '<name>'"
```
> **The point is the output, not the lookup:** the written set must contain every existing value unchanged, plus only the changes the request names. Do not invent values the request did not ask for. (This pairs with rule 4 in §3: a write replaces the whole set.)
---
### 5. Referencing a Value Set from a CustomField
A picklist/multi-select CustomField references a value set via `<valueSetName>` inside `<valueSet>` (instead of an inline `<valueSetDefinition>`).
```xml
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Priority__c</fullName>
<label>Priority</label>
<type>Picklist</type>
<valueSet>
<restricted>true</restricted>
<valueSetName>Priority_Levels</valueSetName> <!-- bare developer name, NO __gvs; see §2 -->
</valueSet>
</CustomField>
```
- For a **GlobalValueSet**, `<valueSetName>` is the **bare developer name** (e.g. `Priority_Levels`) — **never** add `__gvs`. The suffix is an org-storage display artifact; the Metadata API uses the bare name for both deploy and retrieve (see §2).
- A field bound to a value set must **not** also declare an inline `<valueSetDefinition>` — choose one or the other.
---
### 6. Validation Rules
The agent must **reject** and explain — not silently "fix" by inventing metadata — the following:
| Violation | Action / Message |
|-----------|------------------|
| Create a NEW StandardValueSet name | Reject. The name must be in the standard catalog appendix. Otherwise it is a GlobalValueSet. |
| **Value set developer name** with spaces / invalid chars | Convert spaces to underscores; must start with a letter; alphanumeric + underscore only. `Priority Levels` → `Priority_Levels`. (This applies to the value SET name and the field API name — NOT to individual `<customValue><fullName>` values, which keep spaces as written.) |
| Duplicate value `fullName` within one set | Reject. Each `fullName` must be unique within the value set. |
| More than one `<default>true</default>` | Reject. At most one default value per set. |
#### Adding a value to a standard set
> "Add a `Cryptocurrency` value to the Industry picklist."
This is allowed. Read the complete current `Industry` set, then write it back with every existing value unchanged plus one new `<standardValue>` for `Cryptocurrency`. Copy the attribute pattern of an existing value in the set, because omitted attributes get platform defaults that can be wrong.
---
### 7. Deployment Ordering
A value set must deploy **before** any CustomField that references it.
- Deploy the `GlobalValueSet` / `StandardValueSet` first, then the CustomField whose `<valueSetName>` points at it.
- A field referencing a value set that does not yet exist fails with `valueSetName ... does not exist` (or a "not found" error).
- In `package.xml`: `GlobalValueSet` **supports** the `*` wildcard; `StandardValueSet` does **not** — list each standard set member explicitly.
---
### 8. Common Deployment Errors
| Error / Symptom | Cause | Fix |
|-----------------|-------|-----|
| Other values of a standard picklist became inactive after a deploy | The deploy listed only some values, and a write replaces the whole set | Resend the complete set with every existing value (§3 rule 4) |
| `Required field missing: sorted` | GlobalValueSet missing `<sorted>` | Add `<sorted>true</sorted>` or `<sorted>false</sorted>` |
| Unknown element `masterLabel` (StandardValueSet) | Used `masterLabel` instead of `fullName` | StandardValueSet root uses `<fullName>` = catalog name |
| Unknown element `customValue` (StandardValueSet) | Used `customValue` instead of `standardValue` | Use `<standardValue>` in standard sets |
| `valueSetName ... does not exist` | Field deployed before its value set, or `__gvs` wrongly added to the reference | Deploy the value set first; reference it by the **bare** developer name with NO `__gvs` (§2) |
| Duplicate value name | Two `<customValue>` entries share a `fullName` | Make each `fullName` unique within the set (spaces in a value name are allowed — do NOT underscore them) |
---
## Verification Checklist
Before generating value-set XML, verify:
### Type Selection
- [ ] Is this a reusable set shared across fields (GlobalValueSet) or a built-in standard picklist (StandardValueSet)?
- [ ] If StandardValueSet: is the name in the standard catalog appendix? If not, it must be a GlobalValueSet or inline picklist.
### GlobalValueSet Checks
- [ ] Is the root `<GlobalValueSet>` with namespace `http://soap.sforce.com/2006/04/metadata`?
- [ ] Is `<masterLabel>` present?
- [ ] Is `<sorted>` present (`true` or `false`)?
- [ ] Is there at least one `<customValue>`, each with `<fullName>` and `<label>` (at most one carrying `<default>true</default>`)?
- [ ] Is there NO root `<fullName>` (name comes from the filename)?
- [ ] When referencing from a field, is `<valueSetName>` the **bare** developer name with NO `__gvs` suffix?
### StandardValueSet Checks CRITICAL
- [ ] Did you read the complete current set (grounding `search_metadata`/`query_metadata` / Tooling API / retrieve) so every existing value is repeated exactly?
- [ ] Is the root `<StandardValueSet>` with the correct namespace?
- [ ] Does the root use `<fullName>` set to the fixed catalog name (NOT `masterLabel`)?
- [ ] Are values `<standardValue>` entries (NOT `customValue`)?
- [ ] Does the written set contain every existing value, with only the changes the request names applied?
- [ ] Did you avoid a new set name, and for any new value did you copy the attribute pattern of an existing value?
### Shared Checks
- [ ] At most one value has `<default>true</default>`?
- [ ] Are all value `fullName`s unique within the set? (Spaces in a value name are fine — preserve them as written; only the value-SET developer name and field API name use underscores.)
- [ ] Does the value set deploy BEFORE any CustomField that references it?
- [ ] Does the filename match the intended name?
© forcedotcom · Apache-2.0 · forcedotcom/sf-skills