platform-manifest-generate
Produce a Salesforce metadata manifest — package.xml (or one of the destructive variants) — from local source, an org, or an explicit component list. This skill is purely about authoring the manifest file. Hand off to platform-metadata-deploy or platform-destructive-deploy once the file exists.
Tool Restrictions
Use ONLY the Bash tool to run sf project generate manifest, and the Write tool for the hand-built fallback path. Do NOT use MCP tools.
When This Skill Owns the Task
Use platform-manifest-generate when the work involves any of:
- Building a
package.xmlfrom a source directory (e.g.force-app/main/default/classes/) - Building a manifest from an explicit list of components (e.g.
AccountService,ContactSelector,Account) - Building a manifest by introspecting an org via
--from-org - Producing
destructiveChanges.xml,destructiveChangesPre.xml, ordestructiveChangesPost.xmlfor a deletion - Producing both a
package.xmland a destructive manifest in one operation
Delegate elsewhere when the user is:
- Running the deploy itself →
platform-metadata-deploy - Validating before a prod release →
platform-deploy-validate - Executing the destructive deploy →
platform-destructive-deploy(that skill uses the manifest this skill generates) - Retrieving metadata to local →
platform-metadata-retrieve
Two Generation Paths
Path A — CLI-driven (recommended)
Wrap sf project generate manifest. Always prefer this path; it knows about every metadata type and produces canonical XML — and never emits *, sidestepping the wildcard hazard entirely.
The CLI offers three input modes (mutually exclusive):
You can specify either --source-dir or --metadata, not both. --from-org may be combined with --metadata (filter included types) or --excluded-metadata (filter out types).
Verified flags (do not invent flags — verify with sf project generate manifest --help if unsure):
Manifest filename by --type:
You can specify either --type or --name, not both.
Canonical CLI examples
If both a package.xml and a destructive manifest are needed, run the CLI twice — once with --type package (or default), once with --type destroy / pre / post.
Path B — Hand-built fallback
Use this only when the CLI cannot express the user's intent — e.g. they want "just the Apex classes I changed today" and the change set is derived from git diff rather than a clean directory or component list. In that case:
- Resolve the components yourself (e.g. parse
git diff --name-onlyand map paths back to metadata types). - Group by metadata type.
- Emit the XML inline using the schema below.
- Always cross-check by running
sf project deploy start --manifest <file> --dry-run(hand off toplatform-metadata-deploy).
Manifest XML schema
Root element is <Package> in the metadata namespace. Each metadata type gets one <types> block containing one <members> per component plus a single <name>. The trailing <version> declares the API version for the manifest.
Notes:
- For component-bound types like
CustomField,BusinessProcess,RecordType,Layout,ListView,ValidationRule,WebLink, members useObject.Namenotation. destructiveChanges.xml,destructiveChangesPre.xml, anddestructiveChangesPost.xmluse the same XML structure — only the filename and intent differ.- An empty manifest (no
<types>blocks) is legal and is sometimes paired with a destructive manifest:
API Version Handling
The <version> element at the bottom of every manifest must reflect the project's API version.
Resolution order:
- Read
sourceApiVersionfromsfdx-project.jsonat the project root. - If
--api-versionwas passed by the user, use that instead. - If neither is available, fall back to the value reported by
sf --version(the CLI's bundled API version) — but warn the user and recommend they setsourceApiVersioninsfdx-project.jsonfor reproducibility. - Never silently hardcode a value (e.g.
62.0) into output without surfacing the source.
When using the CLI path, omit --api-version unless the user explicitly overrides — the CLI already reads sourceApiVersion.
Wildcard Members (<members>*</members>)
A wildcard member matches every component of that metadata type. It is not legal for every type. Using * for a disallowed type causes deploy/retrieve errors like Wildcards are not supported for this metadata type.
Wildcard NOT allowed (must enumerate)
These types require explicit member names. Common examples: Profile, PermissionSet, PermissionSetGroup, CustomLabels, CustomObjectTranslation, Layout, Workflow (in some package configurations), SharingRules, StandardValueSet, ManagedTopics, and most "container" types whose contents are object-bound (CustomField, RecordType, BusinessProcess, ListView, ValidationRule, WebLink, CompactLayout).
For these, enumerate explicitly:
Wildcard generally allowed
Most "self-contained" component types accept *. Examples: ApexClass, ApexTrigger, ApexComponent, ApexPage, AuraDefinitionBundle, LightningComponentBundle, CustomApplication, CustomTab, StaticResource, EmailTemplate, Report, Dashboard, Flow, FlexiPage, CustomMetadata. See references/wildcard-allowlist.md [blocked] for the full enumeration and edge cases.
Rule of thumb: if you are not certain, list the components explicitly. The CLI path (--source-dir / --metadata) sidesteps this problem because it never emits *.
Examples
Example 1 — Build package.xml from a directory
"Generate package.xml from
force-app/main/default/classes/"
Result: manifest/package.xml listing every Apex class in that folder.
Example 2 — Build a manifest covering specific components
"Build a manifest covering AccountService, ContactSelector, and the Account custom object"
Result: manifest/package.xml containing exactly those three components.
Example 3 — Generate both package.xml and destructiveChanges.xml for deletions
"Create both package.xml and destructiveChanges.xml for these deletions:
Account.OldField__c,Account.OldStatus__c"
After generation, hand off to platform-destructive-deploy to validate and execute the deletion.

