Skip to content

Commit 9b91619

Browse files
npiccoloclaudehsinghbisht-sfdcshetzel
authored
feat: (developing-agentforce) use sf org create agent-user command (#234)
* feat(developing-agentforce): use sf org create agent-user command Replace the legacy multi-step Einstein Agent User creation flow (profile query + record creation + permset assignment) with the new unified `sf org create agent-user` command available in SF CLI 2.131.7+. The new command works across all org types and auto-assigns required permission sets. Closes W-22190552 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Update skills/developing-agentforce/references/agent-user-setup.md Co-authored-by: Steve Hetzel <shetzel@salesforce.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Hemant Singh Bisht <hsinghbisht@salesforce.com> Co-authored-by: Steve Hetzel <shetzel@salesforce.com>
1 parent 9edf77b commit 9b91619

3 files changed

Lines changed: 71 additions & 129 deletions

File tree

skills/developing-agentforce/references/agent-design-and-spec-creation.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Nam
122122

123123
**If results are returned:** Ask which username to use. Record choice in the Agent Spec Configuration section. Verify permissions per [Agent User Setup & Permissions](agent-user-setup.md).
124124

125-
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user, then read [Agent User Setup & Permissions](agent-user-setup.md) for user creation instructions.
125+
**If no results are returned:** STOP. Do NOT invent a username. Ask if you should create a new user. If yes, use:
126+
```bash
127+
sf org create agent-user --target-org TARGET_ORG --first-name <AgentName> --last-name Agent --json
128+
```
129+
Then read the generated username from `result.username`. See [Agent User Setup & Permissions](agent-user-setup.md) for the complete provisioning workflow.
126130

127131
**WRONG:** Fabricating a username when query returns nothing
128132
```

skills/developing-agentforce/references/agent-user-setup.md

Lines changed: 54 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,23 @@ sf data query --json \
3333
-o TARGET_ORG
3434

3535
# Step 2: Create Einstein Agent User (2 minutes)
36-
# Get Profile ID (read result.records[0].Id from JSON response)
37-
sf data query --json \
38-
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
39-
-o TARGET_ORG
36+
# Use the new dedicated command — works in all org types (scratch, sandbox, production)
37+
# Automatically assigns Einstein Agent User profile + AgentforceServiceAgentBase,
38+
# AgentforceServiceAgentUser, and EinsteinGPTPromptTemplateUser permission sets
39+
sf org create agent-user \
40+
--target-org TARGET_ORG \
41+
--first-name <AgentName> \
42+
--last-name Agent
4043

41-
# For Production/Sandbox (non-scratch org):
42-
# Use the ProfileId from the query above
43-
sf data create record --json --sobject User --values \
44-
"Username=<agent_name>_user@<orgId>.ext \
45-
LastName=<AgentName> \
46-
Email=admin@example.com \
47-
Alias=<alias> \
48-
TimeZoneSidKey=America/Los_Angeles \
49-
LocaleSidKey=en_US \
50-
EmailEncodingKey=UTF-8 \
51-
ProfileId=<PROFILE_ID> \
52-
LanguageLocaleKey=en_US" \
53-
-o TARGET_ORG
54-
55-
# For Scratch Orgs (use user definition file):
56-
# sf org create user --definition-file config/einstein-agent-user.json -o TARGET_ORG
44+
# Capture the username from the command output (result.username) — it is generated
45+
# with a unique GUID suffix, e.g. agent_agent@00Dxx.org.salesforce.com-abc123
5746

5847
# Step 3: Assign System Permission Set (1 minute)
48+
# NOTE: AgentforceServiceAgentUser is already assigned by sf org create agent-user.
49+
# This step is only needed if you created the user manually (legacy method).
5950
sf org assign permset --json \
6051
--name AgentforceServiceAgentUser \
61-
--on-behalf-of <agent_name>_user@<orgId>.ext \
52+
--on-behalf-of <agent_name_from_output> \
6253
-o TARGET_ORG
6354

6455
# Step 4: Deploy Custom Permission Set (3 minutes)
@@ -102,11 +93,12 @@ sf agent activate --json \
10293
```
10394

10495
Critical notes:
105-
- For **scratch orgs**, use `sf org create user --definition-file`
106-
- For **production/sandbox**, use `sf data create record` as shown above
107-
- `sf org create user` only works in scratch orgs — it will fail in production/sandbox
96+
- `sf org create agent-user` works in **all org types** (scratch, sandbox, production) — use it instead of the legacy `sf org create user` or `sf data create record` approach
97+
- The command auto-assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` — no separate permset assignment needed
98+
- The command may exit non-zero with `PermissionSetAssignmentError` if a permset license is exhausted, **even when the user was created successfully**. Always inspect `result.username` and `result.permissionSetErrors[]` from the JSON output. If the only failure is `EinsteinGPTPromptTemplateUser` and your agent has no Prompt Template actions, you can proceed. Otherwise, free a license (or use `--base-username` to retry against a different license pool) before continuing.
99+
- Capture the generated username from the command output (`result.username`) and use it for `default_agent_user`
108100
- Always test with preview BEFORE publishing to avoid version management overhead
109-
- Assign `AgentforceServiceAgentUser` BEFORE publishing to prevent "Internal Error"
101+
- Assign any custom permission sets (`{AgentName}_Access`) BEFORE publishing to prevent "Internal Error"
110102
- Publishing does NOT activate — you must run `sf agent activate` separately
111103

112104
---
@@ -117,90 +109,60 @@ Critical notes:
117109

118110
Service agents need a dedicated service account with consistent permissions.
119111

120-
**Get Org ID first** (needed for username format):
121-
```bash
122-
sf org display --json -o TARGET_ORG
123-
# Read result.id from the JSON response
124-
```
125-
126112
**Query existing Einstein Agent Users** (skip creation if one exists):
127113
```bash
128114
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true" -o TARGET_ORG
129115
```
130116

131117
**Create the user** (if none exists):
132118

133-
1. Get the Einstein Agent User profile ID:
134-
```bash
135-
sf data query --json --query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" -o TARGET_ORG
136-
```
137-
138-
2. Create a user definition file (`config/einstein-agent-user.json`):
139-
```json
140-
{
141-
"Username": "{agent_name}_agent@{orgId}.ext",
142-
"LastName": "{AgentName} Agent",
143-
"Email": "placeholder@example.com",
144-
"Alias": "agntuser",
145-
"ProfileId": "<profile-id-from-step-1>",
146-
"TimeZoneSidKey": "America/Los_Angeles",
147-
"LocaleSidKey": "en_US",
148-
"EmailEncodingKey": "UTF-8",
149-
"LanguageLocaleKey": "en_US",
150-
"UserPermissionsKnowledgeUser": true
151-
}
152-
```
153-
154-
3. Create the user:
155-
156-
**Option A: Scratch Org (Definition File)**
157-
```bash
158-
sf org create user --json \
159-
--definition-file config/einstein-agent-user.json \
160-
-o TARGET_ORG
161-
```
162-
163-
**Option B: Production/Sandbox (Direct Record Creation)**
164-
```bash
165-
# Get Profile ID first
166-
# Get Profile ID (read result.records[0].Id from JSON response)
167-
sf data query --json \
168-
--query "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'" \
169-
-o TARGET_ORG
170-
171-
# Create user directly (use ProfileId from query above)
172-
sf data create record --json --sobject User --values \
173-
"Username='{agent_name}_agent@{orgId}.ext' LastName='{AgentName} Agent' Email='placeholder@example.com' Alias='agntuser' ProfileId='<PROFILE_ID>' TimeZoneSidKey='America/Los_Angeles' LocaleSidKey='en_US' EmailEncodingKey='UTF-8' LanguageLocaleKey='en_US'" \
174-
-o TARGET_ORG
175-
```
176-
177-
**Note**: `sf org create user` only works in scratch orgs. For production/sandbox, use `sf data create record`. Attempting `sf org create user` in a non-scratch org fails with an authorization error.
178-
179-
4. Verify creation:
180-
```bash
181-
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Username = '{agent_name}_agent@{orgId}.ext'" -o TARGET_ORG
182-
```
183-
184-
**Username format**: `{agent_name}_agent@{orgId}.ext` (production) or `{agent_name}.{suffix}@{orgfarm}.salesforce.com` (dev/scratch). Always query the target org to confirm the exact format.
119+
Use the dedicated command — works in all org types (scratch, sandbox, production):
120+
121+
```bash
122+
sf org create agent-user \
123+
--target-org TARGET_ORG \
124+
--first-name <AgentName> \
125+
--last-name Agent
126+
```
127+
128+
This command:
129+
- Creates a user with the "Einstein Agent User" profile
130+
- Automatically assigns `AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, and `EinsteinGPTPromptTemplateUser` permission sets
131+
- Returns a unique generated username in `result.username` — record this for `default_agent_user`
132+
133+
Optional flags:
134+
- `--base-username <email>` — sets the base portion of the username (a unique suffix is always appended)
135+
- `--json` — output as JSON for scripting
136+
137+
**Verify creation:**
138+
```bash
139+
sf data query --json --query "SELECT Id, Username, IsActive FROM User WHERE Profile.Name = 'Einstein Agent User' AND IsActive = true ORDER BY CreatedDate DESC LIMIT 5" -o TARGET_ORG
140+
```
141+
142+
**Note**: The generated username has a GUID suffix for global uniqueness (e.g. `agentname_agent@orgid.salesforce.com-abc123`). Always read the username from command output rather than constructing it manually.
185143

186144
---
187145

188146
### Step 2: Assign System Permission Set (`AgentforceServiceAgentUser`)
189147

190148
Critical: Must be assigned BEFORE publishing the agent. Without it, publish fails with "Internal Error".
191149

150+
**If you used `sf org create agent-user` (recommended):** `AgentforceServiceAgentUser` is assigned automatically — skip to Step 3.
151+
152+
**If you created the user manually (legacy):**
153+
192154
Via Setup UI:
193155
1. Setup > Permission Sets > search "AgentforceServiceAgentUser"
194156
2. Manage Assignments > Add Assignments > select the Einstein Agent User > Save
195157

196158
Via CLI:
197159
```bash
198-
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name}_agent@{orgId}.ext" -o TARGET_ORG
160+
sf org assign permset --json --name AgentforceServiceAgentUser --on-behalf-of "{agent_name_from_output}" -o TARGET_ORG
199161
```
200162

201163
Verify assignment:
202164
```bash
203-
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name}_agent@{orgId}.ext' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
165+
sf data query --json --query "SELECT Id, PermissionSet.Name FROM PermissionSetAssignment WHERE Assignee.Username = '{agent_name_from_output}' AND PermissionSet.Name = 'AgentforceServiceAgentUser'" -o TARGET_ORG
204166
```
205167

206168
---
@@ -460,9 +422,9 @@ Checklist:
460422
- **Prevention:** Deploy → Test → Publish workflow (Step 6.1-6.3)
461423
- **Result:** No version management overhead during development
462424

463-
### 4. Wrong User Creation Command
464-
- **Cause:** Using `sf org create user` in non-scratch orgs
465-
- **Prevention:** Step 1 provides correct commands for each org type (Option A vs B)
425+
### 4. Wrong User Creation Command (Legacy)
426+
- **Cause:** Using `sf org create user` in non-scratch orgs, or manually constructing user records with `sf data create record`
427+
- **Prevention:** Use `sf org create agent-user --target-org TARGET_ORG` — works in all org types and auto-assigns required permission sets
466428
- **Result:** User created successfully without authorization errors
467429

468430
### 5. Auto-Generated Permission Set Gaps
@@ -486,7 +448,7 @@ Checklist:
486448
| "invocable action does not exist" | Apex class not in custom PS (auto-generated PS incomplete) | Create custom `{AgentName}_Access` with all `<classAccesses>` (Step 3) |
487449
| "Invalid default_agent_user" | Username typo or user not active | Query Einstein Agent Users, verify exact username + `IsActive = true` |
488450
| Agent runs but returns wrong data | Employee agent using wrong user context | Verify `agent_type` — Service agents use dedicated user, Employee agents use logged-in user |
489-
| `sf org create user` fails | Used in production/sandbox org | Use `sf data create record` instead (Step 1, Option B) |
451+
| `sf org create user` fails | Used in production/sandbox org | Use `sf org create agent-user --target-org TARGET_ORG` instead (Step 1) |
490452

491453
---
492454

@@ -526,4 +488,6 @@ Checklist:
526488

527489
---
528490

529-
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.*
491+
*Validated against: ORM1, ORM2, AutomotiveSupport, SalesforceProductAssistant agents. Last validated: 2026-03-07.
492+
Updated to use `sf org create agent-user` (SF CLI 2.131.7+)
493+
2026-04-30.*

skills/developing-agentforce/references/salesforce-cli-for-agents.md

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -331,53 +331,27 @@ If `TotalLicenses > UsedLicenses`, a license is available and a new Einstein Age
331331

332332
### Creating an Einstein Agent User
333333

334-
#### Step 1: Query for the Einstein Agent User profile ID
334+
Use the dedicated command — works in all org types (scratch, sandbox, production). It automatically assigns the Einstein Agent User profile and the required permission sets (`AgentforceServiceAgentBase`, `AgentforceServiceAgentUser`, `EinsteinGPTPromptTemplateUser`).
335335

336336
```bash
337-
sf data query --json -q "SELECT Id FROM Profile WHERE Name = 'Einstein Agent User'"
338-
```
339-
340-
#### Step 2: Create a User import JSON file (e.g., `data-import/User.json`)
341-
342-
```json
343-
{
344-
"records": [
345-
{
346-
"attributes": {
347-
"type": "User",
348-
"referenceId": "AgentUserRef1"
349-
},
350-
"ProfileId": "<PROFILE_ID_FROM_STEP_1>",
351-
"Username": "<UNIQUE_USERNAME>",
352-
"Alias": "AgntUsr",
353-
"CommunityNickname": "Agent User<UNIQUE_STRING>",
354-
"Email": "noreply@example.com",
355-
"FirstName": "Agent",
356-
"LastName": "User",
357-
"IsActive": true,
358-
"ForecastEnabled": false,
359-
"EmailEncodingKey": "UTF-8",
360-
"LanguageLocaleKey": "en_US",
361-
"LocaleSidKey": "en_US",
362-
"TimeZoneSidKey": "America/Los_Angeles"
363-
}
364-
]
365-
}
366-
```
367-
368-
#### Step 3: Import the user record
369-
370-
```bash
371-
sf data import tree --json --files data-import/User.json
337+
sf org create agent-user \
338+
--target-org <TARGET_ORG> \
339+
--first-name <AgentName> \
340+
--last-name Agent \
341+
--json
372342
```
373343

374-
#### Step 4: Verify the user was created
344+
Optional: `--base-username <email>` sets the base portion of the username (a unique suffix is always appended).
345+
346+
**Capture the generated username** from `result.username` in the output — use it as `default_agent_user` in the `.agent` config.
347+
348+
#### Verify the user was created
375349

376350
```bash
377351
sf data query --json -q "SELECT Username FROM User WHERE Profile.UserLicense.Name = 'Einstein Agent' AND IsActive = true LIMIT 5"
378352
```
379353

380-
After creating the user, continue with permission setup in [Agent User Setup & Permissions](agent-user-setup.md).
354+
After creating the user, continue with custom permission set setup in [Agent User Setup & Permissions](agent-user-setup.md).
381355

382356
---
383357

0 commit comments

Comments
 (0)