
Platform Custom Object Generate
- 2.3k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
Generates Salesforce custom object metadata so a solo builder can define new objects in the data model without hand-writing the object XML.
About
An official Salesforce skill that generates custom object metadata - the definition of a new object including its name, label, and settings on the platform. A solo builder reaches for it when modeling a Salesforce app's data and needs to create custom objects, letting the agent produce valid object metadata instead of crafting the XML by hand.
- Generates Salesforce custom object metadata
- Defines new objects in the data model
- Removes hand-editing of object XML
- Official forcedotcom skill set
Platform Custom Object Generate by the numbers
- 2,319 all-time installs (skills.sh)
- +594 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #222 of 4,386 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/forcedotcom/sf-skills --skill platform-custom-object-generateAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.3k |
|---|---|
| repo stars | ★ 763 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 24, 2026 |
| Repository | forcedotcom/sf-skills ↗ |
What it does
Generates Salesforce custom object metadata so a solo builder can define new objects in the data model without hand-writing the object XML.
Who is it for?
Defining new objects in a Salesforce data model
Skip if: Non-Salesforce schema work
What you get
- custom object metadata
Files
When to Use This Skill
Use this skill when you need to:
- Create new custom objects
- Generate custom object metadata XML
- Configure object sharing and security settings
- Set up object features and capabilities
- Troubleshoot deployment errors related to custom objects
- Add, update, or delete a field OR a validation rule on an existing object — any of these may make the object's
<description>stale, so you must refresh it (propose + confirm). This applies equally to validation-rule changes, not just fields. See Section 3.B.
Specification
1. Overview and Purpose
This document defines the mandatory constraints for generating CustomObject metadata XML (.object-meta.xml file). The agent must verify these constraints before outputting XML to prevent Metadata API deployment errors.
File extension: .object-meta.xml
🔔 Description freshness — applies to EVERY object change, fields AND validation rules: Whenever you add, update, or delete a field or a validation rule on an object, the <description> may now be stale. Before finishing, refresh it per Section 3.B (propose, confirm with the user, write). A validation-rule change counts exactly like a field change — the change is not done until the description has been reconciled. This is easy to forget on validation-rule edits/deletes — don't.---
2. Syntactic Essentials (Tier 1)
The following constraints must be true for the XML body to deploy successfully.
Note: The API Name (fullName) is NOT a tag; it is the filename (e.g., Vehicle__c.object-meta.xml).
Required Elements
| Element | Requirement | Notes |
|---|---|---|
<label> | Required | Singular UI name |
<pluralLabel> | Required | Plural UI name |
<sharingModel> | Required | See Sharing Model Rules below |
<deploymentStatus> | Required | Always set to Deployed |
<nameField> | Required | Primary record identifier (requires <label> and <type>) |
<visibility> | Required | Always set to Public |
Sharing Model Rules
Default: Set <sharingModel> to ReadWrite.
Exception: If this object contains a Master-Detail relationship field, <sharingModel> MUST be ControlledByParent.
Decision Logic:
- IF object has NO Master-Detail field → use
ReadWrite - IF object has Master-Detail field → use
ControlledByParent - IF a Master-Detail field is being added to an existing child object → that existing object's
<sharingModel>must also be updated toControlledByParent
❌ INCORRECT — Will cause error: Cannot set sharingModel to ReadWrite on a CustomObject with a MasterDetail relationship field
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Order Line Item</label>
<pluralLabel>Order Line Items</pluralLabel>
<sharingModel>ReadWrite</sharingModel> <!-- WRONG: Object has a M-D field -->
<deploymentStatus>Deployed</deploymentStatus>
</CustomObject>✅ CORRECT:
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Order Line Item</label>
<pluralLabel>Order Line Items</pluralLabel>
<sharingModel>ControlledByParent</sharingModel> <!-- CORRECT -->
<deploymentStatus>Deployed</deploymentStatus>
</CustomObject>---
3. Smart Defaults & Decision Logic (Tier 2)
The agent must choose which features to enable based on the object's intended use case.
A. The Name Field Decision
| Type | When to Use | Additional Requirements |
|---|---|---|
| Text | Default for human-named entities (Projects, Locations, Teams) | None |
| AutoNumber | Use for transactions, logs, or IDs (Invoices, Requests, Tickets) | Must include <displayFormat> (e.g., INV-{0000}) and <startingNumber>1</startingNumber> |
Text Name Field Example:
<nameField>
<label>Project Name</label>
<type>Text</type>
</nameField>AutoNumber Name Field Example:
<nameField>
<label>Invoice Number</label>
<type>AutoNumber</type>
<displayFormat>INV-{0000}</displayFormat>
<startingNumber>1</startingNumber>
</nameField>B. Object Description (Enrichment)
`<description>`: Mandatory — every Custom Object MUST have one. It must read like human-written documentation, never a generic template ("Object used to track and manage...") or a metadata dump ("Contains 8 fields including Project_Name__c...").
Always compose an enriched description — when creating the object, and again on any change to it: adding, updating, or deleting a field or a validation rule (so it never goes stale). The change — field or validation rule — is never "done" until you've refreshed the object's description. This is not optional; do not ask whether to add a description.
Confirm per change — every time. Propose and confirm on each field/rule change separately. A previous "keep current" applies only to that one change; it is never standing permission to skip the proposal on a later change. Do not infer a preference from an earlier answer — re-propose and re-ask for every new change.
Compose the description (steps below). If the object already has one, use it as a strong signal — preserve the business context it carries (domain, team, intent the schema can't reveal) and fold the new field/rule in rather than discarding it.
Then branch on whether a description already exists:
- No existing description (brand-new object): there is nothing to overwrite — just write the composed description. Do not prompt.
- An existing description (update, delete, or any re-enrichment): never overwrite it silently — you can't tell from the file whether it was hand-written by an admin or generated earlier. Show the proposal, ask, and STOP — wait for the user's reply before writing:
Proposed description for {Object}:<the enriched description>Current: <the existing description>Use this? (yes / keep current / edit)
You MUST NOT write the `<description>` until the user replies — showing the diff is not approval, even when the change looks obvious or minor. Then act: yes → write the proposed text · keep current → leave the existing one untouched (this applies to this change only — re-propose on the next one) · edit → use the user's wording.
Always end with a <description> written.
Composing the description:
1. Classify each field by how it appears in the description:
- Constrained (required, unique, externalId, restricted picklist) → selective parenthetical:
VIN (required, external ID),Color (Red/Green only) - Behavioral (formula, roll-up) → describe what it computes: "the Age Years field auto-calculates vehicle age"
- Relationship (master-detail, lookup) → woven context: "as a child of Account" (never "(Master-Detail to Account)")
- Standard → label only
2. Compose in this order, using field labels not API names:
Purpose → key fields → computed fields → validation rules (as business rules) → "Commonly used for {use cases}."
3. Count and trim before writing (required): count the words; aim ~45, hard ceiling 50. If over, tighten wording first, then drop whole sentences in priority order (use cases → rules → computed; never drop sentences 1–2). Recount. Do not write until ≤ 50.
Example (Car, 46 words):
<description>The Car object tracks vehicle inventory and maintenance. It captures Year, VIN (required, external ID), Color (Red/Green only), and Location; the Age Years field auto-calculates vehicle age. VIN is required and Black cars cannot be sold. Commonly used for fleet management, inventory tracking, and service scheduling.</description>→ For the full workflow and examples, read `references/description-enrichment.md`.
C. Junction Object Naming
If the object is a many-to-many link between two parents, name the object by combining the two parent entities to ensure the schema remains intuitive.
Examples:
Position_Candidate__c(links Position and Candidate)Job_Application__c(links Job and Application)
D. Feature Enablement (Clean XML)
To maintain "Clean XML," only include optional tags when deviating from the Salesforce platform default of false.
Scenario A: User-Facing Objects (Apps, Trackers, Business Entities)
- Trigger: The object is intended for direct user interaction
- Action: Set
<enableSearch>,<enableReports>,<enableActivities>, and<enableHistory>totrue
Scenario B: System-Facing Objects (Junctions, Background Logs)
- Trigger: The object exists for technical associations or background data
- Action: Omit these tags to keep the UI clean and the XML lean
---
4. Critical Constraints & Common Failures
Reserved Words
Never use reserved words as API names for Custom Objects or Custom Fields:
| Category | Reserved Words (Do Not Use as API Names) |
|---|---|
| SOQL/SQL | Select, From, Where, Limit, Order, Group |
| System | User, External, View, Type |
| Temporal | Date, Number |
Relationship Cap
Do not create more than 2 Master-Detail relationships for a single object. If a third relationship is required, use a Lookup instead.
XML Root Element
Do NOT include the <fullName> tag at the root of the .object-meta.xml file. The API name is derived from the filename.
❌ INCORRECT:
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Vehicle__c</fullName> <!-- WRONG: Remove this -->
<label>Vehicle</label>
</CustomObject>✅ CORRECT:
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Vehicle</label>
<!-- fullName comes from filename: Vehicle__c.object-meta.xml -->
</CustomObject>Validation Rule Naming Convention
Validation rule names follow different conventions than custom fields.
Rules:
- Must contain only alphanumeric characters and underscores
- Must begin with a letter
- Cannot end with an underscore
- Cannot contain two consecutive underscores
- Must NOT end with `__c` (unlike custom fields)
❌ INCORRECT:
<validationRules>
<fullName>Require_Start_Date__c</fullName> <!-- WRONG: Has __c suffix -->
<active>true</active>
<errorMessage>Start Date is required.</errorMessage>
<formula>ISBLANK(Start_Date__c)</formula>
</validationRules>Error: The validation name can only contain alphanumeric characters, must begin with a letter, cannot end with an underscore...
✅ CORRECT:
<validationRules>
<fullName>Require_Start_Date</fullName> <!-- CORRECT: No __c suffix -->
<active>true</active>
<errorMessage>Start Date is required.</errorMessage>
<formula>ISBLANK(Start_Date__c)</formula>
</validationRules>Naming Pattern Reference:
| Metadata Type | Naming Pattern | Example |
|---|---|---|
| Custom Fields | Ends with __c | Start_Date__c |
| Validation Rules | No suffix | Require_Start_Date |
| Custom Objects | Ends with __c | Vehicle__c |
---
5. Verification Checklist
Before generating the Custom Object XML, verify:
Syntactic Checks
- [ ] Are both
<label>and<pluralLabel>present? - [ ] Is
<deploymentStatus>set toDeployed? - [ ] Is
<visibility>set toPublic? - [ ] Does
<nameField>include both<label>and<type>? - [ ] If
<type>isAutoNumber, are<displayFormat>and<startingNumber>included?
Sharing Model Check (Critical)
- [ ] Does this object have a Master-Detail relationship field?
- If YES →
<sharingModel>MUST beControlledByParent - If NO →
<sharingModel>should beReadWrite
Constraint Checks
- [ ] Is the API name free of reserved words?
- [ ] Are there 2 or fewer Master-Detail relationships?
- [ ] Is
<fullName>absent from the XML root?
Validation Rule Checks (if applicable)
- [ ] Do validation rule names NOT end with
__c? - [ ] Do validation rule names follow alphanumeric + underscore pattern?
Description Enrichment Quality Checks
- [ ] Opens with "The {Object} object..." + business purpose (not "Object used to track and manage...")
- [ ] Uses field labels, never API names; no "Contains N fields including" dump
- [ ] Formulas/rollups described by behavior; validations stated as business rules; relationships as context
- [ ] Includes common use cases ("Commonly used for...") and is under 50 words
- [ ] Folded any current description's business context into the proposed one (didn't discard it)
- [ ] For an existing description (update/delete/re-enrich), STOPPED and waited for the user's reply before writing — did not treat showing the diff as approval
Architectural Checks
- [ ] Is
<description>present? (Enriched per Section B — proposed and confirmed with the user before writing.) - [ ] Are
<enableSearch>and<enableReports>set totrueif user-facing? - [ ] Does the filename match the intended API name?
---
Reference File Index
| File | When to read |
|---|---|
references/description-enrichment.md | Composing or refreshing an object's <description> (on create, or when a field/rule changes) — full enrichment workflow, field-prioritization tiers, junction/child handling, edge cases, and more examples |
<!-- Parent: platform-custom-object-generate/SKILL.md -->
Object Description Enrichment
The <description> on a Custom Object must read like human-written documentation.
---
When & How — always compose, confirm the text, write
A <description> is mandatory — always compose one. Do it when creating the object and again on any change: adding, updating, or deleting a field or a validation rule (keeps it from going stale). Validation-rule changes count exactly like field changes — the change isn't done until the description is refreshed. Never ask whether to add a description; the only thing to confirm is the wording.
Confirm per change. Propose and confirm on each change separately. A prior "keep current" applies to that one change only — it is never standing permission to skip the proposal on a later change.
Why confirm the wording: an existing description may be hand-authored by an admin (carrying context the schema can't reveal) or generated earlier — you can't tell which from the file, so don't overwrite it silently.
Compose the description (Steps 1–2 below). If one already exists, use it as a strong signal — preserve its business context and fold the new field/rule in; don't discard good prose. Then branch:
- No existing description (brand-new object): nothing to overwrite — just write the composed description. Do not prompt.
- An existing description (update / delete / any re-enrichment): never overwrite it silently. Show the proposal, ask, and STOP — wait for the user's reply before writing:
Proposed description for <Object>:
<enriched description>
Current: <existing description>
Use this? (yes / keep current / edit)Do NOT write the `<description>` until the user replies — showing the diff is not approval, even when the change looks obvious. Then act: yes → write proposed · keep current → leave untouched · edit → use the user's wording.
Always end with a <description> written.
---
Step 1 — Classify Description Signals
Each field is classified by how it should appear in the enriched description:
| Classification | Criteria | Enriched output |
|---|---|---|
| Constrained | required, unique, externalId, restricted picklist | Selective parenthetical: VIN (required, external ID), Color (Red/Green only) |
| Behavioral | formula / calculated, roll-up summary | Dedicated clause describing behavior: "the Age Years field auto-calculates vehicle age", "Total Service Cost summarizes related service records" — never formula syntax |
| Relationship | master-detail, lookup | Woven context: "as a child of Account", "links to User" — never "(Master-Detail to Account)" |
| Standard | everything else | Label only, no annotation |
When selecting which fields to surface, prioritize constrained > behavioral > relationship > standard.
Plus two non-field signals:
- Business purpose — from the user's words ("track projects", "manage inventory") or inferred from object name + key fields. Becomes the opening.
- Common use cases — infer 2-3 practical uses from purpose, fields, and relationships ("fleet management", "service scheduling");
helpTextand conversation context are hints.
---
Step 2 — Compose the Description
Compose in this order:
1 (Purpose): "The {Object_Label} object {verb_phrase}."
2 (Key fields): "It captures {labels with selective context}."
3 (Computed): "The {Label} field auto-calculates {what}, while {Label} summarizes {what}."
4 (Rules): "Validation rules enforce {human-readable constraints}."
5 (Use cases): "Commonly used for {use_case_1}, {use_case_2}, and {use_case_3}."Sentences 1 and 2 are always included. Apply these conditions to 3–5:
- Sentence 3 (Computed): include only if the object has formula or roll-up fields; omit if it has none.
- Sentence 4 (Rules): include only if the object has validation rules; omit if it has none.
- Sentence 5 (Use cases): always include — unless the description would exceed 50 words, in which case drop it first (it is the lowest-priority element).
Writing rules:
- Field labels, never API names (
Year, notYear__c) - Selective annotations only — annotate non-obvious attributes (required, external ID, restricted values); standard fields get label only
- Formulas/rollups → behavior, not syntax ("auto-calculates vehicle age", not
YEAR(TODAY()) - Year__c) - Validations → business rules ("require VIN"), not
ISBLANK(...) - Relationships → context ("as a child of Account"), not metadata notation
- Open in third person ("The X object..."), never "Tracks X" or "Object used to..."
- No "Contains N fields including"
- Clear professional prose; no markdown/backticks/special characters
- Hard ceiling: under 50 words. If over, tighten wording first; if still over, drop in priority order: sentence 5 (use cases) first, then sentence 4 (rules), then sentence 3 (computed); never drop sentences 1–2.
- The result must read like human-written documentation, comprehensible without the schema.
---
Field & Validation Prioritization
Large field lists: surface only the top 5-6 most notable by label + "along with additional tracking fields". Tier order when deciding what carries the most signal:
- Tier 1 — Structure & Logic: relationships, master-detail, roll-up summaries, formulas, picklists
- Tier 2 — Contextual: helpText, PII flag, externalId, trackHistory
- Tier 3 — Standard: everything else
Many validation rules: reference only active rules. If >20, prioritize complex/business-logic rules (compound conditions, cross-field comparisons) over trivial single-field null checks; summarize the 1-3 most important as business rules — never enumerate all.
---
Junction & Child Objects
- Junction: mention both parents in the opening — "The {Label} object connects {ParentA} and {ParentB}, enabling many-to-many tracking between them."
- Child: weave the parent into the purpose sentence — "The {Label} object tracks {purpose} as a child of {Parent}."
---
Examples
❌ Generic template — Object used to track and manage Projects within the organization. (no specifics)
❌ Mechanical metadata dump — Tracks customer projects. Contains 2 fields including Status__c (Picklist: Planning, Active, Complete), Account__c (Master-Detail to Account)... (API names, parenthetical type dump, "Contains N fields" boilerplate)
✅ Good (Project, 48 words):
<description>The Project object tracks customer projects through completion, as a child of Account. It captures Status, Budget, Actual Cost, Start Date, and Project Manager; the Budget Variance field auto-calculates planned-vs-actual spend. End Date must be after Start Date. Commonly used for project tracking, budget management, and resource planning.</description>✅ Excellent (Car, 46 words):
<description>The Car object tracks vehicle inventory and maintenance. It captures Year, VIN (required, external ID), Color (Red/Green only), and Location; the Age Years field auto-calculates vehicle age. VIN is required and Black cars cannot be sold. Commonly used for fleet management, inventory tracking, and service scheduling.</description>---
Edge Cases
| Scenario | Output |
|---|---|
| Bare object, no fields | The Vehicle object tracks vehicle information. |
| Junction object | The Position Candidate object connects Position and Candidate, enabling many-to-many tracking between them. |
| Only computed fields | Each formula/rollup gets a behavioral clause; no empty field list. |
Related skills
FAQ
Is Platform Custom Object Generate safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.