npx skills add ...
npx skills add forcedotcom/sf-skills --skill platform-manifest-generate
Use this skill to generate a package.xml (and optionally destructiveChanges.xml, destructiveChangesPre.xml, or destructiveChangesPost.xml) from a local source directory, an explicit component list, or org introspection. Trigger when the user says \"generate a package.xml from this folder\", \"create a manifest for these classes\", \"I need a deploy manifest\", \"build package.xml for the contacts changes\", or \"create both package.xml and destructiveChanges.xml for these deletions\". Encodes which metadata types accept a wildcard member and which must be enumerated, avoiding the common \"Wildcards are not supported for this metadata type\" deploy failure. DO NOT TRIGGER for executing a deploy (use platform-metadata-deploy), performing the deletion in destructiveChanges.xml (use platform-destructive-deploy), or retrieving metadata (use platform-metadata-retrieve).
npx skills add forcedotcom/sf-skills --skill 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.
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.
Use platform-manifest-generate when the work involves any of:
package.xml from a source directory (e.g. force-app/main/default/classes/)AccountService, ContactSelector, Account)--from-orgdestructiveChanges.xml, destructiveChangesPre.xml, or destructiveChangesPost.xml for a deletionpackage.xml and a destructive manifest in one operationDelegate elsewhere when the user is:
platform-metadata-deployplatform-deploy-validateplatform-destructive-deploy (that skill uses the manifest this skill generates)platform-metadata-retrieveWrap 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):
| Input | Flag | Use when |
|---|---|---|
| Source directory | --source-dir (-p) | User points to a folder containing already-on-disk metadata |
| Component list | --metadata (-m) | User names specific components, e.g. ApexClass:AccountService CustomObject:Account |
| Org introspection | --from-org | User wants every component currently in an org (or a filtered subset) |
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):
| Flag | Purpose |
|---|---|
--source-dir, -p | Local source paths to scan |
--metadata, -m | Component names to include (e.g. ApexClass:AccountService) |
--from-org | Username or alias of org to introspect |
--name, -n | Custom output filename (mutually exclusive with --type) |
--type, -t | Predefined manifest kind: package | pre | post | destroy |
--output-dir, -d | Directory to write the manifest into |
--api-version | Override the API version for the request |
--include-packages, -c | Include managed and/or unlocked package metadata when using --from-org |
--excluded-metadata | Types to exclude when using --from-org |
--json | Machine-readable output |
Manifest filename by --type:
--type | Output file |
|---|---|
package (default) | package.xml |
pre | destructiveChangesPre.xml |
post | destructiveChangesPost.xml |
destroy | destructiveChanges.xml |
You can specify either --type or --name, not both.
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.
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:
git diff --name-only and map paths back to metadata types).sf project deploy start --manifest <file> --dry-run (hand off to platform-metadata-deploy).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:
CustomField, BusinessProcess, RecordType, Layout, ListView, ValidationRule, WebLink, members use Object.Name notation.destructiveChanges.xml, destructiveChangesPre.xml, and destructiveChangesPost.xml use the same XML structure — only the filename and intent differ.<types> blocks) is legal and is sometimes paired with a destructive manifest:The <version> element at the bottom of every manifest must reflect the project's API version.
Resolution order:
sourceApiVersion from sfdx-project.json at the project root.--api-version was passed by the user, use that instead.sf --version (the CLI's bundled API version) — but warn the user and recommend they set sourceApiVersion in sfdx-project.json for reproducibility.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.
<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.
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:
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 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 *.
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.
"Build a manifest covering AccountService, ContactSelector, and the Account custom object"
Result: manifest/package.xml containing exactly those three components.
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.
| Symptom | Likely cause | Recovery |
|---|---|---|
Path does not exist: <dir> | --source-dir points at a missing folder | Confirm the path; use ls to verify; default to force-app/main/default if the user is vague |
| Generated manifest is empty | Source dir contained no recognizable metadata, or all files were ignored | Check .forceignore; verify the path actually contains metadata files (*.cls, *-meta.xml, etc.) |
Wildcards are not supported for this metadata type at deploy time | Hand-built manifest used * for a disallowed type | See the wildcard allowlist above; enumerate the components explicitly |
<version> missing or mismatched | sfdx-project.json lacks sourceApiVersion | Add sourceApiVersion to sfdx-project.json, or pass --api-version to the CLI |
You can specify either --type or --name, but not both | CLI invocation passed both flags | Drop one; use --type for predefined names, --name for a custom one |
You can specify either --source-dir or --metadata, but not both | CLI invocation passed both | Pick one input mode |
Components missing from --from-org output | Org introspection batched too aggressively, or the type is in a managed package | Set SF_LIST_METADATA_BATCH_SIZE lower; add --include-packages managed if intended |
| Need | Delegate to | Reason |
|---|---|---|
| Run a deploy with the generated manifest | platform-metadata-deploy | This skill stops at file generation |
| Validate before a prod release | platform-deploy-validate | Pre-flight test against prod |
| Actually delete the components in the destructive manifest | platform-destructive-deploy | That skill validates and executes the destructive deploy |
| Retrieve metadata listed in the manifest | platform-metadata-retrieve | Pulls org metadata to local |
| Author the metadata being listed in the manifest | Other platform-* generators (e.g. platform-custom-object-generate) | The manifest just lists what already exists on disk |