npx skills add ...
npx skills add forcedotcom/sf-skills --skill service-itsm-agentic-setup-uel-user-create
Provision and enable a Unified Employee License (UEL) user in Salesforce with the full entity chain — User, Person Account, PersonContact, and Employee2 — through the Salesforce-hosted headless-360 MCP server. Use when the user asks to create a UEL user, set up a Unified Employee user account, enable an employee under the Unified Employee license, provision an employee with Person Account and Employee2 record, or onboard a new employee onto the Unified Employee profile. Triggers on: create UEL user, set up unified employee, provision unified employee, enable UEL employee, onboard employee user, create person account for employee. DO NOT TRIGGER when: the user asks to create a standard user without UEL, clone an existing user, manage existing user permissions only, assign incident permissions only, reset passwords only, or look up existing users without creation intent.
npx skills add forcedotcom/sf-skills --skill service-itsm-agentic-setup-uel-user-create
Provision an employee under the Unified Employee License (UEL) by creating and linking a User
on the Unified Employee license/profile, a Person Account (with an auto-generated Contact), and
an Employee2 record, then assigning the required permission sets. Every operation runs through
the Salesforce-hosted headless-360 MCP server (server key headless-360) via its four
meta-tools (discover, describe, dispatch_readonly, dispatch). The org is derived from the
OAuth JWT bound to the current MCP session — the skill never handles an org id, alias, or
credentials — so the flow behaves identically against production and sandbox with no per-user
MCP install.
Reads dispatch through mcp__headless-360__dispatch_readonly; writes through
mcp__headless-360__dispatch. Both take raw HTTP:
{"url": "<path>", "method": "GET|POST", "body"?: {...}, "queryParams"?: {...}}. Full URL paths and
request/response bodies for every row live in references/mcp-invocation.md; this table lists only
the operation and HTTP method.
| Concern | Method + operation | Notes |
|---|---|---|
| Unified Employee license | GET /query (UserLicense) | Zero rows → stop |
| Unified Employee profile | GET /query (Profile) | Zero rows → stop |
| Person Account record type | GET /query (RecordType, IsPersonType) | Zero rows → stop |
| Employee Hub perm set | GET /query (PermissionSet) | Mandatory; zero rows → stop |
| Employee2 accessible | GET /sobjects/Employee2/describe | 200 = HR module enabled |
| Resolve manager | GET /query (User by Username/Name) | Active users only |
| Create user | POST /sobjects/User | Profile = Unified Employee |
| Assign Employee Hub set | POST /sobjects/PermissionSetAssignment | Mandatory |
| Create Person Account | POST /sobjects/Account | PersonEmail required |
| Read PersonContact | GET /query (Account) | Capture PersonContactId |
| Create Employee2 | POST /sobjects/Employee2 | Use UserId/ContactId field names |
| Verify chain | GET /query | User + Account + Employee2 + perm sets |
Response envelope: describe, /query, and /sobjects/… are all standard REST — the
dispatch* tool returns the HTTP status plus the parsed body: { "status_code": 200, "body": <REST response> }. Read body. A create returns body.id and body.success == true; a query returns
body.records[]. Status codes: 200/201 success; 400 bad body (re-check schema via describe);
401/auth error the MCP session needs re-auth; 404 the endpoint/impl is not present on this org;
500 a downstream dependency issue.
Collect from the user (ask only what is not already in conversation context):
| Field | Description |
|---|---|
FirstName | Employee first name |
LastName | Employee last name |
Email | Employee email address |
| Field | Description | Example |
|---|---|---|
Username | Email-formatted, globally unique | jane.doe@company.uel.com |
Alias | Max 8 chars | jdoe |
TimeZoneSidKey | Timezone | America/Los_Angeles |
LocaleSidKey | Locale | en_US |
LanguageLocaleKey | Language | en_US |
EmailEncodingKey | Email encoding | UTF-8 |
| Field | Description |
|---|---|
ManagerName or ManagerUsername | Resolve to ManagerId via SOQL |
| Field | Description |
|---|---|
Department | Employee department |
Location | Employee location |
EmployeeNumber | HR employee number |
Title | Job title |
HireDate | Date format: YYYY-MM-DD |
Employee Hub Unified Employee User (EmployeeHubEmployeeUser) is always assigned — no other
permission sets belong on a UEL user. If the caller asks for extras (Incident Fulfiller, Case
Agent, or any other fulfiller/agent-role set), decline: those are for fulfillers on the Service
Cloud side, not for requesters who log into the Employee Hub. Point the caller at the
appropriate fulfiller user-create flow instead of extending this one.
All steps are sequential. Always read before you write. Every call goes through
mcp__headless-360__* tools. Stop and report if any step fails.
On any 401 / 403 / 404 from a discover / describe / dispatch / dispatch_readonly call below, halt and surface the raw error — the org or client is not configured correctly. 401 → headless-360 MCP client not authenticated to CORE_ORG_ALIAS (session expired). 403 → executing user is missing one of the required perms (ManageUsers, ManageProfilesPermissionsets, CustomizeApplication, AssignPermissionSets) OR the org lacks the Unified Employee License. 404 → the target sObject / route is not available (HR module / UEL not provisioned — surfaces separately as the five prerequisite checks in step 2).
Discover the operations — mcp__headless-360__discover(query="create User Account Employee2 sObject")
and mcp__headless-360__describe(id=<operation_id>) for the POST /sobjects/User,
POST /sobjects/Account, and POST /sobjects/Employee2 operations to confirm they are indexed
and pull the input schema. A discover miss does not mean the route is absent — the
/sobjects/… REST endpoints are core Data API paths and can be invoked directly with
dispatch_readonly / dispatch against the exact URL (see references/mcp-invocation.md). If a
direct dispatch_readonly probe at the documented path also fails (404), direct the user to the
Setup UI.
Verify all five UEL prerequisites (all read-only /query or describe). If any fails,
stop and report exactly which prerequisite is missing:
Capture: UnifiedEmployeeProfileId, PersonAccountRecordTypeId, EmployeeHubPermSetId.
ManagerId. When no manager was supplied, skip this step.User by Username; any record → stop, username taken.POST /sobjects/User with identity, locale, ProfileId =
UnifiedEmployeeProfileId, and ManagerId (omit ManagerId when none). Capture NewUserId.POST /sobjects/PermissionSetAssignment
with {AssigneeId: NewUserId, PermissionSetId: EmployeeHubPermSetId}. If this fails, stop and
report the exact error — the set exists (verified) but may be incompatible with the license.POST /sobjects/Account with FirstName, LastName,
PersonEmail (required), and RecordTypeId = PersonAccountRecordTypeId. Capture
NewAccountId. PersonEmail must be set: the Employee2 validation hook rejects the record when
the linked PersonContact is missing Email or LastName.IsPersonAccount and PersonContactId.
Confirm IsPersonAccount = true and capture PersonContactId. If it is null, stop and
report failure to generate the PersonContact.POST /sobjects/Employee2 with UserId = NewUserId,
ContactId = PersonContactId, and the HR attributes. Use the foreign-key field names
UserId/ContactId (not the relationship names User/Contact). Capture NewEmployee2Id.| Constraint | Rationale |
|---|---|
| Verify all five prerequisites before any mutation | Prevents partial state when the org is not configured for UEL |
Always describe before a POST | You need the exact input schema for each sObject |
| Confirm the plan with the user before creating records | Prevents unintended record creation |
PersonEmail is required on Person Account create | The Employee2 validation hook rejects a PersonContact with no Email |
Use UserId/ContactId field names on Employee2 | The API rejects bare IDs under the relationship names |
Employee Hub Unified Employee User is the ONLY permset assigned | UEL users are Employee Hub requesters, not fulfillers/agents — no other permsets are compatible |
| Omit null/empty foreign keys from create bodies | The API rejects an explicit empty ManagerId |
Display the exact error from dispatch* on failure | Helps diagnose issues |
| Never show Salesforce record IDs to the user | Use human-readable names only |
The executing admin user (the identity behind CORE_ORG_ALIAS) must have:
| Permission | Purpose |
|---|---|
| Manage Internal Users | Create User records |
| Manage Profiles and Permission Sets | Assign permission sets |
| Customize Application | Create Employee2 and Person Account records |
| Assign Permission Sets | Create PermissionSetAssignment records |
discover + describe(id) (or, on a discover miss, a direct dispatch_readonly probe at the documented /sobjects/… path) confirm the User / Account / Employee2 create operations?Account.IsPersonAccount = true with a non-null PersonContactId?User.IsActive = true on the Unified Employee profile (and manager, if provided)?Employee2 link UserId and ContactId correctly?Employee Hub Unified Employee User the only permission set assigned (no fulfiller-side extras)?On failure, display the error from dispatch* exactly as returned.
On success:
No record IDs in user-facing output — use human-readable names only.
| File | When to read |
|---|---|
references/mcp-invocation.md | Every phase — exact mcp__headless-360__* call shapes, the five prerequisite queries, the create bodies for the full chain, response envelope, discovery, and gotchas |
This skill provisions a Unified Employee License (UEL) user with the full entity chain. Two adjacent flows are out of scope: creating a standard (non-UEL) user, and cloning an existing user's full access configuration. Handle those requests separately — this skill does not cover them.