
Platform Metadata Deploy
- 2.3k installs
- 763 repo stars
- Updated July 24, 2026
- forcedotcom/sf-skills
Deploys Salesforce platform metadata (objects, fields, permission sets, Apex) from a project to a target org so a solo builder can push changes without manual clicks.
About
An official Salesforce (forcedotcom) skill that deploys platform metadata - custom objects, fields, permission sets, Apex classes - from a local project into a target Salesforce org. A solo builder reaches for it when they need to ship configuration and code changes to a live org through the Salesforce CLI instead of clicking through the setup UI.
- Deploys Salesforce metadata to a target org
- Handles objects, fields, permission sets and Apex
- Automates the sf CLI deploy flow
- Official forcedotcom skill set
Platform Metadata Deploy by the numbers
- 2,341 all-time installs (skills.sh)
- +599 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #75 of 1,453 DevOps & CI/CD 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-metadata-deployAdd 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
Deploys Salesforce platform metadata (objects, fields, permission sets, Apex) from a project to a target org so a solo builder can push changes without manual clicks.
Who is it for?
Salesforce developers shipping metadata and Apex to an org
Skip if: Non-Salesforce projects
When should I use this skill?
You need to deploy Salesforce metadata to a live org
What you get
- deployed metadata in target org
Files
platform-metadata-deploy: Comprehensive Salesforce DevOps Automation
Use this skill when the user needs deployment orchestration: dry-run validation, targeted or manifest-based deploys, CI/CD workflow advice, scratch-org management, failure triage, or safe rollout sequencing for Salesforce metadata.
When This Skill Owns the Task
Use platform-metadata-deploy when the work involves:
sf project deploy start,quick,report, or retrieval workflows- release sequencing across objects, permission sets, Apex, and Flows
- CI/CD gates, test-level selection, or deployment reports
- troubleshooting deployment failures and dependency ordering
Delegate elsewhere when the user is:
- authoring Apex code → platform-apex-generate
- authoring LWC components → experience-lwc-generate
- creating custom objects or fields → platform-custom-object-generate, platform-custom-field-generate
- building Flows → automation-flow-generate
- doing org data operations → platform-data-manage
- authoring or testing Agentforce agents → agentforce-generate
---
Critical Operating Rules
- Use `sf` CLI v2 only.
- On non-source-tracking orgs, deploy/retrieve commands require an explicit scope such as
--source-dir,--metadata, or--manifest. - Prefer `--dry-run` first before real deploys.
- For Flows, deploy safely and activate only after validation.
- Keep test-data creation guidance delegated to `platform-data-manage` after metadata is validated or deployed.
Default deployment order
| Phase | Metadata |
|---|---|
| 1 | Custom objects / fields |
| 2 | Permission sets |
| 3 | Apex |
| 4 | Flows as Draft |
| 5 | Flow activation / post-verify |
This ordering prevents many dependency and FLS failures.
---
Required Context to Gather First
Ask for or infer:
- target org alias and environment type
- deployment scope: source-dir, metadata list, or manifest
- whether this is validate-only, deploy, quick deploy, retrieve, or CI/CD guidance
- required test level and rollback expectations
- whether special metadata types are involved (Flow, permission sets, agents, packages)
Preflight checks:
sf --version
sf org list
sf org display --target-org <alias> --json
test -f sfdx-project.json---
Recommended Workflow
1. Preflight
Confirm auth, repo shape, package directories, and target scope.
2. Validate first
sf project deploy start --dry-run --source-dir force-app --target-org <alias> --wait 30 --jsonUse manifest- or metadata-scoped validation when the change set is targeted.
3. If validation succeeds, offer the next safe workflow
After a successful validation, guide the user to the correct next action: 1. deploy now 2. assign permission sets 3. create test data via platform-data-manage 4. run tests / smoke checks 5. orchestrate multiple post-deploy steps in order
4. Deploy the smallest correct scope
# source-dir deploy
sf project deploy start --source-dir force-app --target-org <alias> --wait 30 --json
# manifest deploy
sf project deploy start --manifest manifest/package.xml --target-org <alias> --test-level RunLocalTests --wait 30 --json
# manifest deploy with Spring '26 relevant-test selection
sf project deploy start --manifest manifest/package.xml --target-org <alias> --test-level RunRelevantTests --wait 30 --json
# quick deploy after successful validation
sf project deploy quick --job-id <validation-job-id> --target-org <alias> --json5. Verify
sf project deploy report --job-id <job-id> --target-org <alias> --jsonThen verify tests, Flow state, permission assignments, and smoke-test behavior.
6. Report clearly
Summarize what deployed, what failed, what was skipped, and what the next safe action is.
Output template: references/deployment-report-template.md
---
High-Signal Failure Patterns
| Error / symptom | Likely cause | Default fix direction |
|---|---|---|
FIELD_CUSTOM_VALIDATION_EXCEPTION | validation rule or bad test data | adjust data or rule timing |
INVALID_CROSS_REFERENCE_KEY | missing dependency | include referenced metadata first |
CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY | trigger / Flow / validation side effect | inspect automation stack and failing logic |
| tests fail during deploy | broken code or fragile tests | run targeted tests, fix root cause, revalidate |
| field/object not found in permset | wrong order | deploy objects/fields before permission sets |
| Flow invalid / version conflict | dependency or activation problem | deploy as Draft, verify, then activate |
Full workflows: references/orchestration.md, references/trigger-deployment-safety.md
---
CI/CD Guidance
Default pipeline shape: 1. authenticate 2. validate repo / org state 3. static analysis 4. dry-run deploy 5. tests + coverage gates 6. deploy 7. verify + notify
- When org policy and release risk allow it, consider
--test-level RunRelevantTestsfor Apex-heavy deployments. - Pair this with modern Apex test annotations such as
@IsTest(testFor=...)and@IsTest(isCritical=true)— see platform-apex-generate for authoring guidance.
Static analysis now uses Code Analyzer v5 (sf code-analyzer), not retired sf scanner.
Deep reference: references/deployment-workflows.md
---
Agentforce Deployment Note
Use this skill to orchestrate deployment/publish sequencing around agents, but use the agent-specific skill for authoring decisions:
- agentforce-generate for
.agentauthoring, Agent Builder, Prompt Builder, and metadata config
For full agent DevOps details, including Agent: pseudo metadata, publish/activate, and sync-between-orgs, see:
- references/agent-deployment-guide.md
---
Cross-Skill Integration
| Need | Delegate to | Reason |
|---|---|---|
| custom object creation | platform-custom-object-generate | define objects before deploy |
| custom field creation | platform-custom-field-generate | define fields before deploy |
| Apex authoring / fixes | platform-apex-generate | code authoring and repair |
| Flow creation / repair | automation-flow-generate | Flow authoring and activation guidance |
| test data or seed records | platform-data-manage | describe-first data setup and cleanup |
| Agent authoring and publish readiness | agentforce-generate | agent-specific correctness |
---
Reference Map
Start here
- references/orchestration.md
- references/deployment-workflows.md
- references/deployment-report-template.md
Specialized deployment safety
- references/trigger-deployment-safety.md
- references/agent-deployment-guide.md
- references/deploy.sh
Asset templates
- assets/package.xml — manifest template covering common metadata types
- assets/destructiveChanges.xml — template for removing metadata from target orgs
---
Score Guide
| Score | Meaning |
|---|---|
| 90+ | strong deployment plan and execution guidance |
| 75–89 | good deploy guidance with minor review items |
| 60–74 | partial coverage of deployment risk |
| < 60 | insufficient confidence; tighten plan before rollout |
---
Completion Format
Deployment goal: <validate / deploy / retrieve / pipeline>
Target org: <alias>
Scope: <source-dir / metadata / manifest>
Result: <passed / failed / partial>
Key findings: <errors, ordering, tests, skipped items>
Next step: <safe follow-up action><?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<!--
Destructive Changes Template
Use this file to specify metadata components to delete from the target org.
This file should be used with --pre-destructive-changes or --post-destructive-changes
Example:
sf project deploy start \
--manifest manifest/package.xml \
--post-destructive-changes manifest/destructiveChanges.xml \
--target-org production
-->
<!-- Delete Apex Classes -->
<!--
<types>
<members>DeprecatedClass1</members>
<members>DeprecatedClass2</members>
<name>ApexClass</name>
</types>
-->
<!-- Delete Apex Triggers -->
<!--
<types>
<members>OldTrigger</members>
<name>ApexTrigger</name>
</types>
-->
<!-- Delete Custom Objects -->
<!--
<types>
<members>ObsoleteObject__c</members>
<name>CustomObject</name>
</types>
-->
<!-- Delete Custom Fields -->
<!--
<types>
<members>Account.DeprecatedField__c</members>
<members>Contact.OldField__c</members>
<name>CustomField</name>
</types>
-->
<!-- Delete Lightning Components -->
<!--
<types>
<members>oldComponent</members>
<name>LightningComponentBundle</name>
</types>
-->
<!-- Delete Aura Components -->
<!--
<types>
<members>deprecatedAuraComponent</members>
<name>AuraDefinitionBundle</name>
</types>
-->
<!-- Delete Validation Rules -->
<!--
<types>
<members>Account.OldValidationRule</members>
<name>ValidationRule</name>
</types>
-->
<!-- Delete Workflow Rules -->
<!--
<types>
<members>Account.OldWorkflowRule</members>
<name>WorkflowRule</name>
</types>
-->
<!-- Delete Flows -->
<!--
<types>
<members>Deprecated_Flow</members>
<name>Flow</name>
</types>
-->
<!-- Delete Permission Sets -->
<!--
<types>
<members>ObsoletePermissionSet</members>
<name>PermissionSet</name>
</types>
-->
<!-- Delete Static Resources -->
<!--
<types>
<members>oldStaticResource</members>
<name>StaticResource</name>
</types>
-->
<!-- API Version -->
<version>66.0</version>
</Package>
<!--
IMPORTANT NOTES:
1. Order of operations:
- Pre-destructive: Deleted BEFORE deployment (--pre-destructive-changes)
- Post-destructive: Deleted AFTER deployment (--post-destructive-changes)
2. Best practices:
- Test destructive changes in sandbox first
- Backup metadata before deletion
- Use --dry-run to validate before actual deployment
- Delete fields before objects
- Be careful with dependencies
3. Common destructive change scenarios:
- Removing deprecated features
- Cleaning up unused metadata
- Refactoring object structures
- Removing test/demo data objects
4. Example usage:
sf project deploy start \
--manifest manifest/package.xml \
--post-destructive-changes manifest/destructiveChanges.xml \
--target-org sandbox \
--dry-run \
--test-level RunLocalTests \
--wait 30
5. Rollback:
- Keep backup of deleted metadata in version control
- Tag the commit before destructive deployment
- Can redeploy from backup if needed
-->
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<!-- Apex Classes -->
<types>
<members>*</members>
<name>ApexClass</name>
</types>
<!-- Apex Triggers -->
<types>
<members>*</members>
<name>ApexTrigger</name>
</types>
<!-- Aura Components -->
<types>
<members>*</members>
<name>AuraDefinitionBundle</name>
</types>
<!-- Lightning Web Components -->
<types>
<members>*</members>
<name>LightningComponentBundle</name>
</types>
<!-- Custom Objects -->
<types>
<members>Account</members>
<members>Contact</members>
<members>Opportunity</members>
<!-- <members>CustomObject__c</members> -->
<name>CustomObject</name>
</types>
<!-- Custom Fields (if needed) -->
<!--
<types>
<members>Account.CustomField__c</members>
<name>CustomField</name>
</types>
-->
<!-- Layouts -->
<types>
<members>*</members>
<name>Layout</name>
</types>
<!-- Profiles (be careful with profiles) -->
<!--
<types>
<members>Admin</members>
<members>Standard User</members>
<name>Profile</name>
</types>
-->
<!-- Permission Sets -->
<types>
<members>*</members>
<name>PermissionSet</name>
</types>
<!-- Flows -->
<types>
<members>*</members>
<name>Flow</name>
</types>
<!-- Validation Rules -->
<types>
<members>*</members>
<name>ValidationRule</name>
</types>
<!-- Workflow Rules -->
<types>
<members>*</members>
<name>WorkflowRule</name>
</types>
<!-- Static Resources -->
<types>
<members>*</members>
<name>StaticResource</name>
</types>
<!-- Email Templates -->
<types>
<members>*</members>
<name>EmailTemplate</name>
</types>
<!-- Reports -->
<types>
<members>*</members>
<name>Report</name>
</types>
<!-- Dashboards -->
<types>
<members>*</members>
<name>Dashboard</name>
</types>
<!-- Custom Tabs -->
<types>
<members>*</members>
<name>CustomTab</name>
</types>
<!-- Applications -->
<types>
<members>*</members>
<name>CustomApplication</name>
</types>
<!-- API Version -->
<version>66.0</version>
</Package>
platform-metadata-deploy
Comprehensive Salesforce DevOps automation using sf CLI v2. Validate, deploy, verify, and hand off cleanly to post-deploy activities.
Features
- Deployment Management: Execute, validate, and monitor deployments
- DevOps Automation: CI/CD pipelines, automated testing workflows
- Org Management: Authentication, scratch orgs, environment management
- Quality Assurance: Dry-run validation, tests, code coverage, pre-production verification
- Post-Deploy Handoff: Guide users to the next safe step after validation or deployment
- Troubleshooting: Debug failures, analyze logs, provide solutions
Quick Start
1. Invoke the skill
Skill: platform-metadata-deploy
Request: "Deploy all changes to org dev with validation"2. Common operations
| Operation | Example Request |
|---|---|
| Deploy | "Deploy force-app to org dev" |
| Validate | "Dry-run deploy to check for errors" |
| Quick deploy | "Quick deploy validated changes" |
| Cancel | "Cancel the current deployment" |
| Status | "Check deployment status" |
Key Commands
# Validate before deploy (ALWAYS DO THIS)
sf project deploy start --dry-run --source-dir force-app --target-org [alias]
# Deploy with tests
sf project deploy start --source-dir force-app --test-level RunLocalTests --target-org [alias]
# Quick deploy (after validation)
sf project deploy quick --job-id [id] --target-org [alias]
# Check status
sf project deploy report --job-id [id] --target-org [alias]
# Cancel deployment
sf project deploy cancel --job-id [id] --target-org [alias]Recommended post-validation flow
After a successful dry run, guide the user to the next safe step: 1. deploy now 2. assign permission sets 3. create test data with platform-data-manage 4. run tests or smoke checks 5. combine multiple post-deploy steps in order
Orchestration Order
platform-custom-object-generate/automation-flow-generate → platform-metadata-deploy → platform-data-manageWithin platform-metadata-deploy: 1. Objects/Fields 2. Permission Sets 3. Apex 4. Flows (as Draft) 5. Activate Flows
Best Practices
| Rule | Details |
|---|---|
Always --dry-run first | Validate before actual deployment |
| Deploy order matters | Objects → Permissions → Code |
| Test levels | Use RunLocalTests for production |
| Flow activation | Deploy as Draft, activate manually |
| Post-deploy data | Hand off to platform-data-manage rather than mixing raw data creation into deploy logic |
Cross-Skill Integration
| Related Skill | When to Use |
|---|---|
| platform-custom-object-generate / platform-custom-field-generate | Create objects/fields BEFORE deploy |
| platform-apex-test-run | Run tests AFTER deployment |
| platform-data-manage | Create describe-validated test data AFTER deployment |
Documentation
- SKILL.md - Full workflow and orchestration guidance
- references/orchestration.md - Deployment sequencing
- references/deployment-workflows.md - CI/CD and workflow examples
- references/deploy.sh - Sample deployment script
Requirements
- sf CLI v2
- Target Salesforce org
- Proper permissions for deployment
<!-- Parent: platform-metadata-deploy/SKILL.md -->
Agentforce Agent Deployment Guide
Complete DevOps guide for deploying Agentforce agents using SF CLI
Overview
This guide covers the complete deployment lifecycle for Agentforce agents, including:
- Agent metadata types and pseudo metadata
- Sync operations (retrieve/deploy)
- Lifecycle management (activate/deactivate)
- Full deployment workflows
Related Skills:
agentforce-generate- Agent authoring, publishing, Agent Builder, and Prompt Builderplatform-metadata-deploy- This skill - deployment orchestration
---
Agent Metadata Types
Agentforce agents consist of multiple metadata components:
| Metadata Type | Description | Example API Name |
|---|---|---|
Bot | Top-level chatbot definition | Customer_Support_Agent |
BotVersion | Version configuration | Customer_Support_Agent.v1 |
GenAiPlannerBundle | Reasoning engine (LLM config) | Customer_Support_Agent_Planner |
GenAiPlugin | Topic definition | Order_Management_Plugin |
GenAiFunction | Action definition | Get_Order_Status_Function |
Metadata Hierarchy
Bot (Agent Definition)
└── BotVersion (Version Config)
└── GenAiPlannerBundle (Reasoning Engine)
├── GenAiPlugin (Topic 1)
│ ├── GenAiFunction (Action 1)
│ └── GenAiFunction (Action 2)
└── GenAiPlugin (Topic 2)
└── GenAiFunction (Action 3)---
Agent Pseudo Metadata Type
The Agent pseudo metadata type is a convenience wrapper that retrieves or deploys all agent-related components at once.
Using the Agent Pseudo Type
# Retrieve agent + all dependencies from org
sf project retrieve start --metadata Agent:[AgentName] --target-org [alias]
# Deploy agent metadata to org
sf project deploy start --metadata Agent:[AgentName] --target-org [alias]What Gets Synced
When using --metadata Agent:[Name]:
Retrieved/Deployed:
Bot- Top-level chatbotBotVersion- Version configurationGenAiPlannerBundle- Reasoning engineGenAiPlugin- All topicsGenAiFunction- All actions
NOT Included:
- Apex classes (deploy separately)
- Flows (deploy separately)
- Named Credentials (deploy separately)
---
Sync Operations
Retrieving Agents from Org
# Retrieve agent using pseudo metadata type
sf project retrieve start --metadata Agent:Customer_Support_Agent --target-org myorg
# Retrieve to specific output directory
sf project retrieve start --metadata Agent:Customer_Support_Agent --output-dir ./retrieved --target-org myorg
# Retrieve multiple agents
sf project retrieve start --metadata Agent:Support_Agent,Agent:Sales_Agent --target-org myorgRetrieving Specific Components
# Retrieve just the bot definition
sf project retrieve start --metadata Bot:Customer_Support_Agent --target-org myorg
# Retrieve a specific BotVersion along with the bot definition
sf project retrieve start \
--metadata Bot:Customer_Support_Agent \
--metadata BotVersion:Customer_Support_Agent.v3 \
--target-org myorg
# Retrieve just the planner bundle
sf project retrieve start --metadata GenAiPlannerBundle:Customer_Support_Agent_Planner --target-org myorg
# Retrieve all plugins (topics)
sf project retrieve start --metadata GenAiPlugin --target-org myorg
# Retrieve all functions (actions)
sf project retrieve start --metadata GenAiFunction --target-org myorgVersioned retrieve note: Current SF CLI releases correctly retrieve the specific BotVersion you request instead of always pulling only the latest version.Deploying Agents to Org
# Deploy agent using pseudo metadata type
sf project deploy start --metadata Agent:Customer_Support_Agent --target-org myorg
# Deploy with validation only (dry run)
sf project deploy start --metadata Agent:Customer_Support_Agent --dry-run --target-org myorg
# Deploy multiple agents
sf project deploy start --metadata Agent:Support_Agent,Agent:Sales_Agent --target-org myorg---
Agent Lifecycle Management
Activate Agent
Makes an agent available to users.
# Manual activation
sf agent activate --api-name [AgentName] --target-org [alias]
# CI / deterministic activation of a known BotVersion
sf agent activate --api-name [AgentName] --version [N] --target-org [alias] --jsonRequirements:
- Agent must be published first (
sf agent publish authoring-bundle) - All Apex classes and Flows must be deployed
default_agent_usermust be a valid org user with Agentforce permissions
Activation notes:
--version [N]maps to thevNsuffix inBotVersionmetadata- Omitting
--versiontriggers interactive version selection - Using
--jsonwithout--versionactivates the latest agent version - For CI/CD and reproducible rollouts, prefer
--version [N] --json
Post-Activation:
- Agent is immediately available to users
- Preview command can be used for testing
- Changes require deactivation first
Deactivate Agent
Deactivates an agent for modifications. Required before making changes.
# Manual deactivation
sf agent deactivate --api-name [AgentName] --target-org [alias]
# Script-friendly deactivation
sf agent deactivate --api-name [AgentName] --target-org [alias] --jsonWhen Deactivation is Required:
- Adding or removing topics
- Modifying action configurations
- Changing system instructions
- Updating variable definitions
Modification Workflow
# 1. Deactivate agent
sf agent deactivate --api-name Customer_Support_Agent --target-org myorg
# 2. Make changes to Agent Script
# 3. Re-publish
sf agent publish authoring-bundle --api-name Customer_Support_Agent --target-org myorg
# 4. Re-activate
sf agent activate --api-name Customer_Support_Agent --target-org myorg---
Agent Preview
Preview allows testing agent behavior before production deployment.
Preview Modes
| Mode | Command | Use When |
|---|---|---|
| Simulated | sf agent preview --api-name X | Testing logic, Apex/Flows not ready |
| Live | sf agent preview --api-name X --use-live-actions | Integration testing with real data |
Simulated Mode (Default)
sf agent preview --api-name Customer_Support_Agent --target-org myorg- LLM simulates action responses
- No actual Apex/Flow execution
- Safe for testing - no data changes
Live Mode
sf agent preview --api-name Customer_Support_Agent --use-live-actions --target-org myorgRequirements:
- Standard org auth (
sf org login web) - Apex classes and Flows deployed
- Agent must be active
Preview with Debug Output
sf agent preview --api-name Customer_Support_Agent --output-dir ./preview-logs --apex-debug --target-org myorgv2.121.7+: Live preview no longer requires a Connected App. Standard org auth (sf org login web) suffices.---
Full Deployment Workflows
New Agent Deployment
Complete workflow for deploying a new agent:
# 1. Deploy Apex classes (if any)
sf project deploy start --metadata ApexClass --target-org myorg
# 2. Deploy Flows
sf project deploy start --metadata Flow --target-org myorg
# 3. Validate Agent Script
sf agent validate authoring-bundle --api-name Customer_Support_Agent --target-org myorg
# 4. Publish agent
sf agent publish authoring-bundle --api-name Customer_Support_Agent --target-org myorg
# 5. Preview (simulated mode)
sf agent preview --api-name Customer_Support_Agent --target-org myorg
# 6. Activate
sf agent activate --api-name Customer_Support_Agent --target-org myorg
# 7. Preview (live mode - optional)
sf agent preview --api-name Customer_Support_Agent --use-live-actions --target-org myorgUpdate Existing Agent
# 1. Deactivate
sf agent deactivate --api-name Customer_Support_Agent --target-org myorg
# 2. Deploy updated dependencies (if any)
sf project deploy start --metadata ApexClass,Flow --target-org myorg
# 3. Validate
sf agent validate authoring-bundle --api-name Customer_Support_Agent --target-org myorg
# 4. Re-publish
sf agent publish authoring-bundle --api-name Customer_Support_Agent --target-org myorg
# 5. Preview
sf agent preview --api-name Customer_Support_Agent --target-org myorg
# 6. Re-activate
sf agent activate --api-name Customer_Support_Agent --target-org myorgSync Between Orgs
# 1. Retrieve from source org
sf project retrieve start --metadata Agent:Customer_Support_Agent --target-org source-org
# 2. Deploy dependencies to target org first
sf project deploy start --source-dir force-app/main/default/classes --target-org target-org
sf project deploy start --source-dir force-app/main/default/flows --target-org target-org
# 3. Deploy agent metadata
sf project deploy start --metadata Agent:Customer_Support_Agent --target-org target-org
# 4. Publish agent in target org
sf agent publish authoring-bundle --api-name Customer_Support_Agent --target-org target-org
# 5. Activate in target org
sf agent activate --api-name Customer_Support_Agent --target-org target-orgCI/CD Pipeline Integration
Example deployment script for CI/CD:
#!/bin/bash
# deploy-agent.sh
set -e # Exit on error
ORG_ALIAS=$1
AGENT_NAME=$2
AGENT_VERSION=$3
echo "🚀 Deploying agent: $AGENT_NAME to $ORG_ALIAS (version: $AGENT_VERSION)"
# Step 1: Deploy dependencies
echo "📦 Deploying Apex classes..."
sf project deploy start --metadata ApexClass --target-org $ORG_ALIAS --wait 10 --json
echo "📦 Deploying Flows..."
sf project deploy start --metadata Flow --target-org $ORG_ALIAS --wait 10 --json
# Step 2: Validate agent script
echo "✅ Validating Agent Script..."
sf agent validate authoring-bundle --api-name $AGENT_NAME --target-org $ORG_ALIAS --json
# Step 3: Check if agent exists (deactivate if needed)
echo "🔍 Checking agent status..."
if sf agent deactivate --api-name $AGENT_NAME --target-org $ORG_ALIAS --json 2>/dev/null; then
echo "⏸️ Agent deactivated for update"
fi
# Step 4: Publish agent (--skip-retrieve skips metadata retrieval, faster in CI)
echo "📤 Publishing agent..."
sf agent publish authoring-bundle --api-name $AGENT_NAME --target-org $ORG_ALIAS --skip-retrieve --json
# Step 5: Activate agent deterministically
echo "▶️ Activating agent..."
sf agent activate --api-name $AGENT_NAME --version $AGENT_VERSION --target-org $ORG_ALIAS --json
echo "✅ Agent deployment complete: $AGENT_NAME"Usage:
./deploy-agent.sh myorg Customer_Support_Agent 4Pass the BotVersion number you intend to activate as the third argument.
---
Dependency Deployment Order
Critical: Dependencies must be deployed BEFORE the agent.
1. Custom Objects/Fields (platform-custom-object-generate, platform-custom-field-generate)
↓
2. Apex Classes (platform-apex-generate)
↓
3. Flows (automation-flow-generate)
↓
4. Named Credentials (integration-connectivity-generate, if external APIs)
↓
5. Agent Metadata (agentforce-generate publish)
↓
6. Agent ActivationDeployment Commands by Order
# 1. Objects/Fields
sf project deploy start --metadata CustomObject,CustomField --target-org myorg
# 2. Apex
sf project deploy start --metadata ApexClass --target-org myorg
# 3. Flows
sf project deploy start --metadata Flow --target-org myorg
# 4. Named Credentials (if needed)
sf project deploy start --metadata NamedCredential --target-org myorg
# 5. Publish agent
sf agent publish authoring-bundle --api-name My_Agent --target-org myorg
# 6. Activate
sf agent activate --api-name My_Agent --target-org myorg---
Post-Deployment Validation for API Access
After deploying and activating an agent, verify it is accessible via the Agent Runtime API. Missing metadata causes silent 500 errors.
Validation Checklist
# 1. Verify GenAiPlannerBundle has plannerSurfaces
sf project retrieve start --metadata GenAiPlannerBundle --target-org myorg --output-dir ./check
grep -l "plannerSurfaces" ./check/**/*.xml
# If no results → add plannerSurfaces block (see below)
# 2. Verify BotVersion has surfacesEnabled=true
sf project retrieve start --metadata BotVersion --target-org myorg --output-dir ./check
grep "surfacesEnabled" ./check/**/*.xml
# Should show: <surfacesEnabled>true</surfacesEnabled>
# 3. Test API connectivity
curl -s -X POST "https://DOMAIN.my.salesforce.com/services/oauth2/token" \
-d "grant_type=client_credentials&client_id=KEY&client_secret=SECRET" | jq .access_tokenFix: Add Missing plannerSurfaces
If the GenAiPlannerBundle XML is missing the plannerSurfaces block, add CustomerWebClient:
<GenAiPlannerBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<!-- existing elements -->
<plannerSurfaces>
<adaptiveResponseAllowed>false</adaptiveResponseAllowed>
<callRecordingAllowed>false</callRecordingAllowed>
<surface>SurfaceAction__CustomerWebClient</surface>
<surfaceType>CustomerWebClient</surfaceType>
</plannerSurfaces>
</GenAiPlannerBundle>Note:EinsteinAgentApiChannelsurfaceType is NOT available on all orgs. UseCustomerWebClientinstead — it enables both Agent Builder Preview and Agent Runtime API access.
⚠️ Agent Script agents:connection messaging:in the.agentDSL ONLY generates aMessagingplannerSurface —CustomerWebClientis never auto-generated. You must manually patch it after EVERYsf agent publish authoring-bundle. See the post-publish workflow inagentforce-generate.
Fix: Add plannerSurfaces when agent is active
If the agent is active, you must deactivate before deploying:
# Deactivate → Deploy → Activate
sf agent deactivate --api-name AgentName -o TARGET_ORG --json
sf project deploy start --metadata "GenAiPlannerBundle:AgentName_vNN" -o TARGET_ORG --json
sf agent activate --api-name AgentName --version NN -o TARGET_ORG --jsonUse the same NN value from the planner bundle version you just patched so activation is deterministic.
Fix: Enable surfacesEnabled on BotVersion
<BotVersion xmlns="http://soap.sforce.com/2006/04/metadata">
<!-- existing elements -->
<surfacesEnabled>true</surfacesEnabled>
</BotVersion>Then redeploy:
sf project deploy start --metadata GenAiPlannerBundle,BotVersion --target-org myorgWhy this matters: WithoutCustomerWebClientplannerSurface, the Agent Builder Preview shows "Something went wrong" and the Agent Runtime API returns500 UNKNOWN_EXCEPTIONon session creation.
---
ISV Packaging (BotTemplate)
Use sf agent generate template to package an agent for distribution via managed packages on AppExchange.
Generate a BotTemplate
sf agent generate template \
--agent-file force-app/main/default/bots/My_Agent/My_Agent.bot-meta.xml \
--agent-version 1 \
--output-dir my-package \
--source-org my-scratch-org \
--jsonImportant: This command packages Bot / BotVersion-based agents. It does not package Agent Script .agent authoring bundles.What Gets Generated
The command generates a BotTemplate metadata type that wraps:
Bot— Top-level agent definitionBotVersion— Version configurationGenAiPlannerBundle— Reasoning engine and topic/action bindings
Packaging Workflow
1. Generate template: Run sf agent generate template as shown above 2. Include in package: Add the BotTemplate and GenAiPlannerBundle metadata to your managed package directory 3. Create package version: sf package version create --package <name> --installation-key <key> --wait 20 4. Install in subscriber org: sf package install --package <version-id> --target-org <alias> --wait 10 5. Publish agent in subscriber org: sf agent publish authoring-bundle --api-name <name> --target-org <alias>
Key Considerations
- The BotTemplate is designed for ISV distribution — it allows subscribers to install and customize the agent
- Subscribers can modify topics, actions, and instructions after installation
- The
--agent-versionflag specifies which BotVersion to template (typically1for new agents) - The
--agent-filemust point to the.bot-meta.xmlfile in your local project --source-orgmust be a namespaced scratch org that contains the source agent- Agent Script
.agentbundles currently need a different rollout path; use source-driven publish workflows instead ofsf agent generate template
---
Troubleshooting
"Internal Error, try again later"
Causes:
- Invalid
default_agent_user - Dependencies not deployed
- Flow/action variable name mismatch
Solutions:
# Verify user exists
sf data query --query "SELECT Id, Username FROM User WHERE Username = 'agent@example.com'" --target-org myorg
# Deploy dependencies first
sf project deploy start --metadata ApexClass,Flow --target-org myorg"No active agents found"
Cause: Agent not activated
Solution:
sf agent activate --api-name My_Agent --target-org myorg"Agent must be deactivated before changes"
Cause: Trying to modify active agent
Solution:
sf agent deactivate --api-name My_Agent --target-org myorg
# Make changes
sf agent publish authoring-bundle --api-name My_Agent --target-org myorg
sf agent activate --api-name My_Agent --target-org myorgDeployment Fails with Missing Dependencies
Cause: Apex/Flows not deployed before agent
Solution: Follow the dependency deployment order above.
---
Cross-Skill Integration
| From Skill | To Skill | Purpose |
|---|---|---|
| agentforce-generate | platform-metadata-deploy | Publish and activate agents |
| platform-apex-generate | platform-metadata-deploy | Deploy Apex before agent |
| automation-flow-generate | platform-metadata-deploy | Deploy Flows before agent |
| integration-connectivity-generate | platform-metadata-deploy | Deploy Named Credentials for external APIs |
Integration Pattern
# 1. platform-apex-generate creates InvocableMethod class
# 2. automation-flow-generate creates wrapper Flow
# 3. agentforce-generate creates agent with flow:// action
# 4. platform-metadata-deploy orchestrates deployment in correct order---
Command Reference
Agent-Specific Commands
| Command | Description |
|---|---|
sf agent publish authoring-bundle --api-name X | Publish authoring bundle |
sf agent publish authoring-bundle --api-name X --skip-retrieve | Publish without retrieving from org (CI/CD) |
sf agent activate --api-name X --version N --json | Activate a specific published BotVersion deterministically |
sf agent deactivate --api-name X --json | Deactivate agent for changes |
sf agent preview --api-name X | Preview agent behavior |
sf agent validate authoring-bundle --api-name X | Validate Agent Script syntax |
Metadata Commands with Agent Pseudo Type
| Command | Description |
|---|---|
sf project retrieve start --metadata Agent:X | Retrieve agent + components |
sf project deploy start --metadata Agent:X | Deploy agent metadata |
sf project retrieve start --metadata Bot:X | Retrieve bot definition only |
sf project retrieve start --metadata Bot:X --metadata BotVersion:X.vN | Retrieve a specific BotVersion |
sf project retrieve start --metadata GenAiPlannerBundle:X | Retrieve planner bundle |
sf project retrieve start --metadata GenAiPlugin | Retrieve all plugins |
sf project retrieve start --metadata GenAiFunction | Retrieve all functions |
Management Commands
| Command | Description |
|---|---|
sf org open agent --api-name X | Open agent in Agentforce Builder |
sf org open authoring-bundle | Open Agentforce Studio list view (v2.121.7+) |
sf org list metadata --metadata-type Bot | List bots in org |
sf org list metadata --metadata-type GenAiPlannerBundle | List planner bundles |
---
Related Documentation
- Agentforce Development Guide
- Agentforce Testing Guide
#!/bin/bash
#
# Multi-Step Deployment Script
# Generated by platform-metadata-deploy skill
#
# Usage: ./scripts/deploy.sh <target-org-alias>
set -e # Exit on error
TARGET_ORG=${1:-"myorg"}
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
echo "═══════════════════════════════════════════════════════════════════"
echo " DEPLOYMENT TO: $TARGET_ORG"
echo "═══════════════════════════════════════════════════════════════════"
# Step 0: Pre-flight checks
echo "📋 Pre-flight checks..."
sf --version || { echo "❌ sf CLI not found"; exit 1; }
sf org display --target-org "$TARGET_ORG" --json || { echo "❌ Cannot connect to org"; exit 1; }
# Step 0.5: Dry-run validation first
echo "🧪 Step 0.5: Running dry-run validation..."
sf project deploy start \
--dry-run \
--source-dir "$PROJECT_DIR/force-app/main/default" \
--target-org "$TARGET_ORG" \
--wait 30 \
--json
# Step 1: Deploy Custom Objects/Fields
echo "📦 Step 1: Deploying objects and fields..."
sf project deploy start \
--source-dir "$PROJECT_DIR/force-app/main/default/objects" \
--target-org "$TARGET_ORG" \
--wait 10 \
--json
# Step 2: Deploy Permission Sets
echo "📦 Step 2: Deploying permission sets..."
sf project deploy start \
--source-dir "$PROJECT_DIR/force-app/main/default/permissionsets" \
--target-org "$TARGET_ORG" \
--wait 10 \
--json
# Step 3: Deploy Apex (with tests)
echo "📦 Step 3: Deploying Apex..."
sf project deploy start \
--source-dir "$PROJECT_DIR/force-app/main/default/classes" \
--source-dir "$PROJECT_DIR/force-app/main/default/triggers" \
--target-org "$TARGET_ORG" \
--test-level RunLocalTests \
--wait 30 \
--json
# Step 4: Deploy Flows (Draft)
echo "📦 Step 4: Deploying flows..."
sf project deploy start \
--source-dir "$PROJECT_DIR/force-app/main/default/flows" \
--target-org "$TARGET_ORG" \
--wait 10 \
--json
echo "═══════════════════════════════════════════════════════════════════"
echo " ✅ DEPLOYMENT COMPLETE"
echo "═══════════════════════════════════════════════════════════════════"
echo ""
echo "Recommended Next Steps:"
echo " 1. Assign permission sets: sf org assign permset --name PermSetName --target-org $TARGET_ORG"
echo " 2. Activate flows after validation"
echo " 3. Create test data with platform-data-manage or describe-first sf data commands"
echo " 4. Run smoke tests / targeted verification"
<!-- Parent: platform-metadata-deploy/SKILL.md -->
Deployment Report Template
Standard output format for Salesforce deployment summaries.
Full Report Format
## Salesforce Deployment Report
### Pre-Deployment Checks
✓ Org authenticated: <org-alias> (<org-id>)
✓ Project validated: sfdx-project.json found
✓ Components identified: X classes, Y triggers, Z components
### Deployment Execution
→ Deployment initiated: <timestamp>
→ Job ID: <deployment-job-id>
→ Test Level: RunLocalTests
### Results
✓ Status: Succeeded
✓ Components Deployed: X/X
✓ Tests Passed: Y/Y (Z% coverage)
### Deployed Components
- ApexClass: AccountController, ContactTriggerHandler
- LightningComponentBundle: accountCard, contactList
- CustomObject: CustomObject__c
### Next Steps
1. Verify functionality in target org
2. Monitor for any post-deployment issues
3. Update documentation and changelogCompact Report Format
For quick summaries:
✓ Deployment: [org-alias] | Job: [job-id]
Components: X/X | Tests: Y/Y (Z% coverage)
Status: SucceededFailure Report Format
## Deployment Failed
### Error Summary
✗ Status: Failed
✗ Failed Components: 2/15
### Errors
1. ApexClass: MyController
- Line 45: Variable 'acc' does not exist
2. CustomField: Account.Custom__c
- Missing referenced field: Contact.Email
### Suggested Actions
1. Fix compilation error in MyController.cls:45
2. Deploy Contact.Email field before Account.Custom__c
3. Re-run deployment after fixesCI/CD Pipeline Output
For automated pipelines (GitHub Actions, GitLab CI):
deployment:
status: success|failure
job_id: "0Af..."
org: "<alias>"
components:
total: 15
deployed: 15
failed: 0
tests:
total: 45
passed: 45
failed: 0
coverage: 87.5
duration: "2m 34s"
errors: []<!-- Parent: platform-metadata-deploy/SKILL.md -->
Salesforce Deployment Workflow Examples
This file contains practical examples of common Salesforce deployment scenarios using the platform-metadata-deploy skill.
Example 1: Basic Production Deployment
User Request:
"Deploy my changes to production with full test coverage"Skill Execution:
1. Pre-deployment checks
sf org display --target-org production
sf project deploy start --dry-run --test-level RunLocalTests --target-org production --wait 302. Validation output
✓ Deployment validation succeeded
✓ Tests passed: 145/145 (92% coverage)
✓ Components validated: 233. Quick deploy (using validation ID)
sf project deploy quick --job-id 0Af5g00000XXXXX --target-org production4. Final output
## Salesforce Deployment Report
✓ Status: Succeeded
✓ Components Deployed: 23/23
✓ Tests Passed: 145/145 (92% coverage)
✓ Duration: 8m 32s
### Deployed Components:
- ApexClass: AccountController, ContactTriggerHandler, LeadProcessor
- ApexTrigger: AccountTrigger, ContactTrigger
- LightningComponentBundle: accountCard, contactList---
Example 2: Selective Component Deployment
User Request:
"Deploy only the new Lightning Web Components to sandbox"Skill Execution:
1. Identify LWC components
# Find all LWC components
ls -R force-app/main/default/lwc/2. Deploy specific directory
sf project deploy start \
--source-dir force-app/main/default/lwc \
--target-org dev-sandbox \
--test-level NoTestRun \
--wait 153. Output
✓ Deployment succeeded
✓ Components Deployed:
- accountCard (LWC)
- contactList (LWC)
- opportunityBoard (LWC)---
Example 3: Hotfix Deployment
User Request:
"I need to deploy an urgent bug fix in AccountController to production"Skill Execution:
1. Verify the specific file
cat force-app/main/default/classes/AccountController.cls2. Run targeted tests
sf apex run test \
--tests AccountControllerTest \
--target-org production \
--wait 53. Deploy single class
sf project deploy start \
--source-dir force-app/main/default/classes/AccountController.cls \
--target-org production \
--test-level RunSpecifiedTests \
--tests AccountControllerTest \
--wait 104. Verification
sf project deploy report --job-id <job-id> --target-org production---
Example 4: Manifest-Based Deployment
User Request:
"Deploy using the package.xml manifest for release v2.3"Skill Execution:
1. Read manifest file
cat manifest/package-v2.3.xml2. Validate deployment
sf project deploy start \
--manifest manifest/package-v2.3.xml \
--target-org production \
--dry-run \
--test-level RunLocalTests \
--wait 303. Quick deploy
sf project deploy quick --job-id 0Af5g00000XXXXX --target-org production---
Example 5: Scratch Org Development Workflow
User Request:
"Create a scratch org and deploy my feature branch"Skill Execution:
1. Create scratch org
sf org create scratch \
--definition-file config/project-scratch-def.json \
--alias feature-branch-123 \
--duration-days 7 \
--set-default2. Push source
sf project deploy start --target-org feature-branch-1233. Assign permission sets
sf org assign permset --name AdminPermSet --target-org feature-branch-1234. Import test data
sf data import tree --plan data/sample-data-plan.json --target-org feature-branch-1235. Open org
sf org open --target-org feature-branch-123---
Example 6: Deployment Rollback
User Request:
"The deployment failed, I need to rollback to the previous version"Skill Execution:
1. Retrieve current production metadata (if not backed up)
sf project retrieve start \
--manifest manifest/package-production.xml \
--target-org production2. Check out previous version from git
git checkout v2.2-stable3. Deploy previous version
sf project deploy start \
--manifest manifest/package-v2.2.xml \
--target-org production \
--test-level RunLocalTests \
--wait 304. Verify rollback
sf org open --target-org production---
Example 7: Destructive Changes
User Request:
"Remove the deprecated CustomObject__c and old Apex classes"Skill Execution:
1. Create destructiveChanges.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>DeprecatedClass1</members>
<members>DeprecatedClass2</members>
<name>ApexClass</name>
</types>
<types>
<members>CustomObject__c</members>
<name>CustomObject</name>
</types>
<version>66.0</version>
</Package>2. Deploy with destructive changes
sf project deploy start \
--manifest manifest/package.xml \
--post-destructive-changes manifest/destructiveChanges.xml \
--target-org production \
--test-level RunLocalTests \
--wait 30Current SF CLI releases support this combined pattern correctly, including runs where the manifest deploys one set of components while a destructive changes file deletes different components in the same operation.
---
Example 8: Multi-Environment Deployment
User Request:
"Deploy to dev, then staging, then production after each passes validation"Skill Execution:
1. Deploy to Dev
sf project deploy start --target-org dev --test-level NoTestRun --wait 102. Deploy to Staging
sf project deploy start --target-org staging --test-level RunLocalTests --wait 203. Validate Production
sf project deploy start --target-org production --dry-run --test-level RunLocalTests --wait 304. Deploy to Production (after manual approval)
sf project deploy quick --job-id <validation-job-id> --target-org production---
Example 9: Code Coverage Analysis
User Request:
"Check my code coverage and identify classes that need more tests"Skill Execution:
1. Run all tests
sf apex run test \
--test-level RunLocalTests \
--target-org dev \
--code-coverage \
--result-format human \
--wait 152. Analyze coverage report
Overall Code Coverage: 87%
Classes with <75% coverage:
- LeadProcessor: 62%
- OpportunityHelper: 71%
- AccountBatchProcessor: 45%
Recommendations:
1. Add test methods for LeadProcessor.processLeads()
2. Test error handling in OpportunityHelper
3. Create comprehensive tests for AccountBatchProcessor---
Example 10: Deployment Error Recovery
User Request:
"Deployment failed with 'INVALID_CROSS_REFERENCE_KEY' error"Skill Execution:
1. Analyze error
Error: INVALID_CROSS_REFERENCE_KEY
Component: CustomObject__c.SomeLookupField__c
Message: Field references non-existent object2. Identify dependency
grep -r "ReferencedObject__c" force-app/3. Solution provided
The error indicates that SomeLookupField__c references an object
that doesn't exist in the target org.
Solutions:
1. Deploy the referenced object first
2. Include both objects in the same deployment
3. Update the field to reference a different object
4. Check if the referenced object exists: sf org list metadata --metadata-type CustomObject4. Deploy with dependencies
# Include both in manifest
sf project deploy start \
--manifest manifest/package-with-dependencies.xml \
--target-org production---
Tips for Successful Deployments
1. Always validate first - Use --dry-run for production 2. Monitor test execution - Watch for test failures early 3. Check code coverage - Ensure >75% minimum 4. Deploy incrementally - Smaller deployments are easier to troubleshoot 5. Use version control - Tag releases for easy rollback 6. Document changes - Keep deployment logs 7. Test in sandbox - Never test directly in production 8. Handle dependencies - Deploy referenced metadata first
---
These examples demonstrate common patterns. The platform-metadata-deploy skill adapts to your specific use case and provides guided assistance.
<!-- Parent: platform-metadata-deploy/SKILL.md -->
Multi-Skill Orchestration: platform-metadata-deploy Perspective
This document details how platform-metadata-deploy fits into the multi-skill workflow for Salesforce development.
---
Standard Orchestration Order
┌─────────────────────────────────────────────────────────────────────────────┐
│ STANDARD MULTI-SKILL ORCHESTRATION ORDER │
├─────────────────────────────────────────────────────────────────────────────┤
│ 1. platform-custom-object-generate / platform-custom-field-generate │
│ └── Create object/field definitions (LOCAL files) │
│ │
│ 2. automation-flow-generate │
│ └── Create flow definitions (LOCAL files) │
│ │
│ 3. platform-metadata-deploy ◀── YOU ARE HERE │
│ └── Deploy all metadata (REMOTE) │
│ │
│ 4. platform-data-manage │
│ └── Create test data (REMOTE - objects must exist!) │
└─────────────────────────────────────────────────────────────────────────────┘---
Why platform-metadata-deploy Goes Third (Not Last)
platform-metadata-deploy is the bridge between local files and the org:
| Before platform-metadata-deploy | After platform-metadata-deploy |
|---|---|
| Metadata exists locally | Metadata exists in org |
| Flows reference objects | Flows can run |
| Data can't be created | platform-data-manage can create records |
platform-data-manage REQUIRES deployed objects. The error SObject type 'X' not supported means objects weren't deployed.
---
Deploy Order WITHIN platform-metadata-deploy
When deploying multiple metadata types:
┌─────────────────────────────────────────────────────────────────────────────┐
│ INTERNAL DEPLOY ORDER │
├─────────────────────────────────────────────────────────────────────────────┤
│ 1. Custom Objects & Fields │
│ └── Objects must exist before anything references them │
│ │
│ 2. Permission Sets │
│ └── Field-Level Security requires fields to exist │
│ │
│ 3. Apex Classes │
│ └── @InvocableMethod for Flow actions │
│ │
│ 4. Flows (as Draft) │
│ └── Flows reference fields and Apex │
│ │
│ 5. Activate Flows │
│ └── Change status Draft → Active │
└─────────────────────────────────────────────────────────────────────────────┘Why this order?
- Flows need fields to exist
- Users need Permission Sets for field visibility
- Triggers may depend on active flows
- Draft flows can be tested before activation
---
Integration + Agentforce Extended Order
When deploying agents with external API integrations:
┌─────────────────────────────────────────────────────────────────────────────┐
│ AGENTFORCE DEPLOYMENT ORDER │
├─────────────────────────────────────────────────────────────────────────────┤
│ 1. integration-connectivity-connected-app-configure → Create OAuth Connected App │
│ 2. integration-connectivity-generate → Create Named Credential + External Service │
│ 3. platform-apex-generate → Create @InvocableMethod (if needed) │
│ 4. automation-flow-generate → Create Flow wrapper │
│ │
│ 5. platform-metadata-deploy ◀── FIRST DEPLOYMENT │
│ └── Deploy: Objects, Fields, Permission Sets, Apex, Flows │
│ │
│ 6. agentforce-generate → Create agent with flow:// target │
│ │
│ 7. platform-metadata-deploy ◀── SECOND DEPLOYMENT (Agent Publish) │
│ └── sf agent publish authoring-bundle --api-name [AgentName] │
│ │
│ 8. platform-data-manage → Create test data │
└─────────────────────────────────────────────────────────────────────────────┘---
Common Deployment Errors from Wrong Order
| Error | Cause | Fix |
|---|---|---|
Invalid reference: Quote__c | Object not deployed | Deploy objects first |
Field does not exist: Status__c | Field not deployed | Deploy fields first |
no CustomObject named X found | Permission Set deployed before object | Deploy objects, then Permission Sets |
SObject type 'X' not supported | platform-data-manage ran before deploy | Deploy before creating data |
Flow is invalid | Flow references missing object | Deploy objects before flows |
Flow not found | Agent references undeploy flow | Deploy flows before agent publish |
---
Two-Step Deployment Pattern (Recommended)
Always validate before deploying:
# Step 1: Dry-run validation
sf project deploy start --dry-run --source-dir force-app --target-org alias
# Step 2: Actual deployment (only if validation passes)
sf project deploy start --source-dir force-app --target-org alias---
Cross-Skill Dependencies
Before deploying, verify these prerequisites:
| Dependency | Check Command | Required For |
|---|---|---|
| TAF Package | sf package installed list | TAF trigger pattern |
| Custom Objects | sf sobject describe | Apex/Flow field refs |
| Permission Sets | sf org list metadata --metadata-type PermissionSet | FLS for fields |
| Flows | sf org list metadata --metadata-type Flow | Agent actions |
---
agentforce-generate Integration
For agent deployments, use the specialized commands:
# Deploy dependencies first
sf project deploy start --metadata ApexClass,Flow --target-org alias
# Validate agent syntax
sf agent validate authoring-bundle --api-name AgentName --target-org alias --json
# Publish agent
sf agent publish authoring-bundle --api-name AgentName --target-org alias --json
# Activate a specific BotVersion deterministically in automation
sf agent activate --api-name AgentName --version N --target-org alias --jsonIf you omit--version, activation is interactive. For CI/CD and scripted orchestration, prefer--version N --json.
---
Invocation Patterns
| From Skill | To platform-metadata-deploy | When |
|---|---|---|
| platform-custom-object-generate | → platform-metadata-deploy | "Deploy objects to [org]" |
| automation-flow-generate | → platform-metadata-deploy | "Deploy flow with --dry-run" |
| platform-apex-generate | → platform-metadata-deploy | "Deploy classes with RunLocalTests" |
| agentforce-generate | → platform-metadata-deploy | "Deploy and publish agent" |
---
Related Documentation
| Topic | Location |
|---|---|
| Deployment workflows | platform-metadata-deploy/references/deployment-workflows.md |
| Agent deployment guide | platform-metadata-deploy/references/agent-deployment-guide.md |
| Deploy script template | platform-metadata-deploy/references/deploy.sh |
<!-- Parent: platform-metadata-deploy/SKILL.md -->
Trigger Deployment Safety Guide
Overview
This guide covers deployment considerations for triggers, focusing on cascade failures, atomicity patterns, and async decoupling strategies.
---
1. Understanding Cascade Failures
What Are Cascade Failures?
When an exception in one trigger causes rollback of operations from preceding triggers in the chain.
Account Insert → AccountTrigger → ContactTrigger → OpportunityTrigger
✓ ✓ ✗ (Exception)
All three operations ROLL BACKDefault Behavior
- Uncaught exceptions in triggers cause rollback of all operations in the transaction
- This includes operations from other triggers that fired successfully
- This behavior may or may not be desired depending on business requirements
When Cascade Failure is DESIRED
- All operations represent ONE atomic business process
- Example: Order with line items must be complete or not exist
- Same business unit/persona owns all the data
// DESIRED cascade: Order and OrderItems must both succeed
trigger OrderTrigger on Order__c (after insert) {
// If this fails, we WANT the Order insert to roll back
List<OrderItem__c> items = createDefaultLineItems(Trigger.new);
insert items; // Exception here rolls back Order insert - GOOD
}When Cascade Failure is PROBLEMATIC
- Operations represent INDEPENDENT business processes
- Example: Creating account + syncing to external CRM
- Different business units own different parts of the process
// PROBLEMATIC cascade: CRM sync failure shouldn't prevent Account creation
trigger AccountTrigger on Account (after insert) {
// If CRM sync fails, Account creation also fails - BAD
CRMService.syncNewAccounts(Trigger.new); // Exception here rolls back Account
}---
2. Atomicity Patterns
Explicit Savepoints
Use Database.setSavepoint() for explicit transaction control within a single process.
/**
* Demonstrates explicit atomicity control for cross-object operations
*/
public class AccountOwnership {
/**
* Reassigns all related records when account owner changes.
* This is an ATOMIC operation - all changes succeed or all roll back.
*/
public static void reassignRelatedRecords(
List<Account> accountsWithNewOwner,
Map<Id, Account> oldAccountsById
) {
// Create savepoint for atomic operation
Savepoint sp = Database.setSavepoint();
try {
Map<Id, Id> newOwnerByAccountId = buildOwnerMap(accountsWithNewOwner);
// Step 1: Reassign opportunities
reassignOpportunities(newOwnerByAccountId);
// Step 2: Reassign cases
reassignCases(newOwnerByAccountId);
// Step 3: Create transition tasks
createOwnerTransitionTasks(accountsWithNewOwner, oldAccountsById);
} catch (Exception e) {
// Rollback ALL changes if ANY step fails
Database.rollback(sp);
// Log the failure for investigation
ErrorLogger.log('AccountOwnership.reassignRelatedRecords', e);
// Re-throw to inform the caller
throw new AccountOwnershipException(
'Failed to reassign related records: ' + e.getMessage()
);
}
}
}When to Use Savepoints
| Scenario | Use Savepoint? | Reason |
|---|---|---|
| Multi-object update in same trigger | Yes | Ensures consistency |
| Order + OrderItems creation | Yes | Business atomicity required |
| Account + CRM sync | No | Use async decoupling instead |
| Validation that spans objects | Yes | All-or-nothing validation |
---
3. Async Decoupling Patterns
The Problem
After-trigger logic that represents an independent business process can cause cascade failures.
Solution: Queueable Jobs
/**
* Queueable job for processing that should not block the main transaction
*/
public class AccountSyncQueueable implements Queueable, Database.AllowsCallouts {
private Set<Id> accountIds;
private TriggerOperation operationType;
public AccountSyncQueueable(Set<Id> accountIds, TriggerOperation operationType) {
this.accountIds = accountIds;
this.operationType = operationType;
}
public void execute(QueueableContext context) {
try {
List<Account> accounts = [
SELECT Id, Name, Website, Industry, BillingAddress
FROM Account
WHERE Id IN :accountIds
];
switch on operationType {
when AFTER_INSERT {
ExternalCRM.createAccounts(accounts);
}
when AFTER_UPDATE {
ExternalCRM.updateAccounts(accounts);
}
when AFTER_DELETE {
ExternalCRM.deleteAccounts(accountIds);
}
}
} catch (Exception e) {
// Log error but don't fail - this is independent of main transaction
ErrorLogger.log('AccountSyncQueueable', e, accountIds);
}
}
}Usage in Trigger Handler
public void afterInsert(List<Account> newAccounts, Map<Id, Account> newAccountsById) {
// Synchronous operations that SHOULD block
AccountNotifications.notifySalesTeam(newAccounts);
// Async operations that should NOT block main transaction
if (canEnqueueJob()) {
System.enqueueJob(new AccountSyncQueueable(
newAccountsById.keySet(),
TriggerOperation.AFTER_INSERT
));
}
}
private Boolean canEnqueueJob() {
return !System.isBatch() &&
!System.isFuture() &&
Limits.getQueueableJobs() < Limits.getLimitQueueableJobs();
}Platform Events for Maximum Decoupling
// Publisher (in trigger)
EventBus.publish(new Account_Changed__e(
Account_Id__c = account.Id,
Change_Type__c = 'INSERT'
));
// Subscriber (separate trigger on platform event)
trigger AccountChangedSubscriber on Account_Changed__e (after insert) {
// Process events - failures here don't affect original transaction
List<Id> accountIds = new List<Id>();
for (Account_Changed__e event : Trigger.new) {
accountIds.add(event.Account_Id__c);
}
// Sync to external system
}Decoupling Decision Matrix
| Business Process | Same User Persona? | Failure Impact | Recommendation |
|---|---|---|---|
| Order + Line Items | Yes | Must be atomic | Synchronous + Savepoint |
| Account + Audit Log | Yes | Can retry | Queueable |
| Account + External CRM | No | Independent | Platform Event |
| Contact + Marketing Cloud | No | Independent | Platform Event |
| Record + Email Notification | Yes | Non-critical | @future |
---
4. Pre-Deployment Checklist
Trigger Cascade Analysis
Before deploying triggers, analyze the cascade impact:
CHECKLIST:
□ List all triggers that fire on the same transaction
□ Identify which operations are atomic (same business process)
□ Identify which operations are independent (different processes)
□ Verify exception handling in each trigger
□ Check for recursive trigger prevention
□ Review async job usage and limitsQuestions to Answer
1. What triggers will fire together?
- Map the full trigger chain for each DML operation
- Include triggers on related objects (parent-child)
2. What happens if each trigger fails?
- Which operations will roll back?
- Is that the desired behavior?
3. Are there external system calls?
- Should they be async?
- What happens if they fail?
4. What about governor limits?
- How many DML statements in the chain?
- How many SOQL queries?
- Can bulk operations stay within limits?
---
5. Testing Cascade Scenarios
Test Cascade Success
@IsTest
static void testTriggerChain_AllSucceed() {
Test.startTest();
Account acc = new Account(Name = 'Test');
insert acc; // Should fire AccountTrigger, create child records, etc.
Test.stopTest();
// Verify all expected records were created
Assert.areEqual(1, [SELECT COUNT() FROM Contact WHERE AccountId = :acc.Id]);
Assert.areEqual(1, [SELECT COUNT() FROM Task WHERE WhatId = :acc.Id]);
}Test Cascade Failure (Expected Rollback)
@IsTest
static void testTriggerChain_ChildFailure_RollsBack() {
// Configure scenario that will cause child trigger to fail
Test.startTest();
try {
Account acc = new Account(Name = 'Trigger Failure Test');
insert acc;
Assert.fail('Expected DmlException');
} catch (DmlException e) {
// Expected - verify Account was NOT created
Assert.areEqual(0, [SELECT COUNT() FROM Account WHERE Name = 'Trigger Failure Test']);
}
Test.stopTest();
}Test Async Decoupling
@IsTest
static void testAccountInsert_CRMSyncAsync_DoesNotBlock() {
// Even if CRM sync would fail, Account should be created
Test.startTest();
Account acc = new Account(Name = 'Async Test');
insert acc;
Test.stopTest();
// Account should exist regardless of async job outcome
Assert.areEqual(1, [SELECT COUNT() FROM Account WHERE Name = 'Async Test']);
// Verify async job was enqueued
Assert.areEqual(1, [SELECT COUNT() FROM AsyncApexJob WHERE JobType = 'Queueable']);
}---
6. Deployment Commands for Trigger Safety
Validate Before Deploying
# Always validate triggers before deploying
sf project deploy start --dry-run \
--source-dir force-app/main/default/triggers \
--source-dir force-app/main/default/classes \
--test-level RunLocalTests \
--target-org aliasDeploy with Test Coverage
# Deploy triggers with their test classes
sf project deploy start \
--source-dir force-app/main/default/triggers \
--source-dir force-app/main/default/classes \
--test-level RunSpecifiedTests \
--tests AccountTriggerTest,ContactTriggerTest \
--target-org aliasVerify Trigger Order
After deployment, verify trigger execution order if you have multiple triggers on the same object:
# Query trigger execution order (via Debug Logs)
sf apex tail log --target-org alias
# Or check in Setup: Object Manager → [Object] → Triggers---
Summary
| Pattern | Use Case | Trade-off |
|---|---|---|
| Default (Cascade) | Atomic business processes | Simple but all-or-nothing |
| Savepoint | Controlled rollback within handler | More code, explicit control |
| Queueable | Independent async processes | Decoupled but async limits |
| Platform Event | Maximum decoupling | More infrastructure |
| @future | Simple fire-and-forget | Limited parameters |
Key Principles
1. Make atomicity decisions explicit - Don't rely on default behavior accidentally 2. Decouple independent processes - Use async for cross-domain operations 3. Test cascade scenarios - Verify both success and failure paths 4. Document trigger chains - Future maintainers need to understand dependencies 5. Validate before deploying - Use --dry-run to catch issues early
Related skills
FAQ
Is Platform Metadata Deploy safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.