Moving an Agentforce agent from sandbox to production fails in two predictable places: a missing metadata type that passes deployment validation but breaks activation, and an Einstein provisioning state that nobody checked. Both are fixable with a correct manifest and the right pipeline steps.
DevOps complexity is one of the top two reported barriers to Agentforce adoption in 2026. The other is pricing. Unlike pricing, deployment complexity is fully solvable with the right structure. This is the guide that should exist in the official docs but doesn't.
Why standard Salesforce DevOps tooling breaks for Agentforce
A typical Salesforce deployment pipeline handles Apex, Flows, custom objects, and permission sets without much ceremony. Agentforce introduces a new dependency that breaks the standard approach: the agent cannot activate until Einstein generative AI features are provisioned at the platform level in the target org.
This provisioning is asynchronous and happens on Salesforce's infrastructure side. You cannot trigger it via API or CLI. The result: a deployment that passes validation and completes with status Succeeded — but an agent that sits inert with the message "agents are still being provisioned" when you try to activate it.
The fix is a pre-deployment check, not a different deployment tool. More on that in the checklist section.
The complete metadata manifest
A full Agentforce agent spans at minimum five metadata types. Missing any one of them produces a deployment that looks successful but cannot activate:
- GenAiPlanner — the agent definition: its name, description, system instructions, and the full topic routing configuration. This is the master record of what the agent is.
- BotVersion — the conversation model version associated with the agent. This is the record that triggers Einstein activation checks in the target org. It must be deployed last.
- GenAiFunction — one record per action: the action name, description, input/output parameter schema, and the Flow or Apex it invokes. Every action referenced by your topics needs its own
GenAiFunctionentry. - MlDomain — the Einstein AI feature binding. This record connects the agent to the underlying LLM configuration. Omitting it causes silent activation failure.
- PermissionSet — the permission set that grants the agent user access to the actions, objects, and fields it needs. If the agent user lacks FLS on a field an action writes to, the action will silently succeed at the HTTP layer and write nothing.
Beyond these five, include any Flow, Apex class, or PromptTemplate records that your GenAiFunction actions reference. A clean package.xml structure:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>MyServiceAgent</members>
<name>GenAiPlanner</name>
</types>
<types>
<members>MyServiceAgent.v1</members>
<name>BotVersion</name>
</types>
<types>
<members>GetCaseStatus</members>
<members>UpdateCaseStatus</members>
<name>GenAiFunction</name>
</types>
<types>
<members>MyServiceAgentDomain</members>
<name>MlDomain</name>
</types>
<types>
<members>AgentServiceUser</members>
<name>PermissionSet</name>
</types>
<version>62.0</version>
</Package>
Deployment order matters
Deploy in this sequence — deviating causes activation failures that are hard to diagnose because the error messages are generic:
- MlDomain — Einstein feature binding must exist in the target before anything references it
- PermissionSet — must exist before the agent user can be assigned it post-deploy
- Flows and Apex — referenced actions must exist before GenAiFunction records that point to them
- PromptTemplates — if any actions use grounded prompts, deploy these before GenAiFunction
- GenAiFunction — action definitions deploy once their referenced components exist
- GenAiPlanner — the agent definition deploys once its actions exist
- BotVersion — always last; this is the record that triggers the Einstein activation check
Deactivate the agent in the target org before deploying a new BotVersion. Redeploying BotVersion to an active agent fails. Add this as a pre-deployment step in your pipeline.
Pre-deployment checklist
Run these checks before the deployment pipeline fires:
- Einstein provisioning state — in Setup → Einstein → Einstein Features, confirm the status shows "Active" with a green indicator. If it shows "Provisioning" or is absent, do not deploy. Wait for the provisioning confirmation email from Salesforce.
- Agent deactivation — if updating an existing agent, deactivate it in Agentforce Builder before the pipeline runs. An active BotVersion blocks redeployment.
- Named Credentials — if your actions call external systems, confirm Named Credentials and External Credentials exist in the target with the same API names. They are not deployable via standard metadata — they must be configured manually in each org or via a separate secrets management process.
- Connected App permissions — if your deployment uses JWT auth, confirm the Connected App in production has the correct OAuth scopes and the certificate is still valid.
GitHub Actions workflow
A working workflow that handles the provisioning check and deployment order:
name: Deploy Agentforce to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Salesforce CLI
run: npm install -g @salesforce/cli
- name: Authenticate production org
run: |
echo "${{ secrets.SF_PROD_JWT_KEY }}" > server.key
sf org login jwt \
--client-id ${{ secrets.SF_PROD_CLIENT_ID }} \
--jwt-key-file server.key \
--username ${{ secrets.SF_PROD_USERNAME }} \
--alias prod
- name: Check Einstein provisioning state
run: |
STATUS=$(sf data query \
--query "SELECT Status FROM EinsteinFeatureUsage LIMIT 1" \
--target-org prod --json | jq -r '.result.records[0].Status')
if [ "$STATUS" != "Active" ]; then
echo "Einstein not provisioned in prod. Aborting."
exit 1
fi
- name: Deactivate agent before redeploy
run: |
sf agent disable --name MyServiceAgent --target-org prod || true
- name: Deploy metadata (ordered)
run: |
sf project deploy start \
--manifest manifest/package.xml \
--target-org prod \
--wait 30
- name: Assign permission set to agent user
run: |
sf org assign permset \
--name AgentServiceUser \
--on-behalf-of agentuser@myorg.com \
--target-org prod
- name: Activate agent
run: |
sf agent enable --name MyServiceAgent --target-org prod
- name: Run smoke test in Simulate Mode
run: |
sf agent test run \
--agent-name MyServiceAgent \
--test-set agent-smoke-tests.json \
--target-org prod
When to use Copado vs. bare sf CLI
Copado is worth the overhead if your team has three or more developers committing to the same org, you need approval gates before production deploys, or you require automated rollback on failed activations. For smaller teams or orgs where a single architect owns the Agentforce configuration, bare sf CLI with GitHub Actions covers everything Copado handles for Agentforce specifically — the deployment mechanics are identical, Copado just wraps them in a UI with change tracking.
Frequently Asked Questions
What metadata types does an Agentforce deployment require?
At minimum: GenAiPlanner (agent definition), BotVersion (conversation model — always deploy last), GenAiFunction (one per action), MlDomain (Einstein feature binding), and PermissionSet. Also include any Flow, Apex, or PromptTemplate records your actions reference. Missing any of these produces a deployment that passes validation but cannot activate in the target org.
Why does my agent work in sandbox but fail to activate in production?
Most likely cause: Einstein generative AI features aren't fully provisioned in production yet. This is an async process on Salesforce's side that you can't trigger via API. Check Setup → Einstein → Einstein Features for "Active" status. If it shows "Provisioning," wait for the confirmation email before running your deployment pipeline. Also check that the agent is deactivated before redeploying a BotVersion — deploying to an active agent fails.
Can I deploy Agentforce with sfdx or sf CLI without Copado?
Yes. Use the sf CLI (the current tool — sfdx is deprecated). Handle manually: (1) deploy BotVersion last after Einstein provisioning is confirmed, (2) deactivate the agent in target before redeploying BotVersion, (3) assign the PermissionSet to the agent user post-deploy, and (4) re-activate. These four steps are what Copado automates. The GitHub Actions workflow in this post covers all of them.
Moving Agentforce into production?
We architect and deploy Agentforce agents for enterprise orgs — from metadata structure and CI/CD setup to post-deployment observability. One call, concrete answers.
Book a strategy call →