Managing Fs Prework Brief Deployer
SkillCloud & infraLets your agent set up Einstein Pre-Work Brief in a Salesforce Field Service org by deploying templates, licenses, and test data.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Managing Fs Prework Brief Deployer skill
About this capability
Deploy the deterministic half of Einstein Pre-Work Brief on Field Service Mobile to a target org, prompt template, Lightning Data Service, licenses and permission sets, the Work Order layout field, and a scheduled test Work Order. Use this skill when a user asks to deploy, set up, enable, or config
What this skill tells your AI
The instructions your AI receives, as published by forcedotcom/sf-skills in skills/field-service-prework-brief-deployer-configure/SKILL.md and read by ahel’s review.
When to Use This Skill
Deploy the deterministic half of Einstein Pre-Work Brief on Field Service Mobile to a target org via dispatch — prompt template, Lightning Data Service, licenses and permission sets, the Work Order layout field, and a scheduled test Work Order.
Workflow
Field Service Pre-Work Brief Deployer
Deploy the deterministic half of Einstein Pre-Work Brief on Field Service Mobile via dispatch.
This skill takes an org whose Einstein for Field Service add-on is already provisioned and performs every automatable step to stand up Pre-Work Brief: it deploys three metadata artifacts, assigns licenses and permission sets, exposes the Work Order field on the technician's layout, wires a test Work Order scheduled in today's window, and activates the prompt template via the Connect API. The workflow is fully automatable end-to-end — there are no irreducibly manual steps. On-device rendering verification (confirming grounding produces job-specific content) is owned by the coordinating Pre-Work Brief skill, not this deploy primitive.
This skill is the judgment-free deploy primitive. Org diagnosis / routing (STOP if unprovisioned), technician selection, and the fresh-vs-existing test-data decision are resolved by the coordinating skill and passed in as inputs / a choice point.
What it does
- Prompt template — deploys the
einstein_gpt__fieldServicePreWorkBriefGenAiPromptTemplate (Pre_Work_Brief) as Published. - Lightning Data Service — enables Lightning Data Service on the Field Service settings (the
lsdkForFieldServiceMobilePreforg preference; without LDS the brief renders blank on mobile). - Licenses + permission sets — assigns the Einstein for Field Service PSL + permission sets to an admin and a pilot technician.
- Field-level access — deploys
PreWorkBrief_Field_Accessand exposesWorkOrder.PreWorkBriefPromptTemplateon the technician's layout with FLS. - Test data — creates a test Work Order + Service Appointment + Assigned Resource scheduled in today's window, pointed at the deployed template (or points an existing Work Order at it).
Inputs
- Target org — an org whose Einstein for Field Service add-on is provisioned. If the add-on is absent the org is unprovisioned — STOP; the coordinating skill owns this routing.
- Pilot technician — username + user Id, selected by the coordinating skill, with an active
ServiceResource. - Test-data mode —
fresh(create a clean test Work Order chain) orexisting(point a supplied real Work Order at the template and move its Service Appointment into today's window). Defaultfresh.
Preconditions
- The Einstein for Field Service add-on is provisioned (the Einstein for Field Service permission-set license is present).
- The admin holds Customize Application + Manage Profiles and Permission Sets.
- Einstein generative AI base setup (including Data 360 grounding) is complete on the org.
- A pilot technician has been selected and has an active
ServiceResource.
Happy path (fresh test data)
Verify provisioning → assign licenses and permission sets → verify permset assignments → detect existing template → deploy prompt template → verify template deployed → read Field Service settings → deploy LDS setting → verify LDS enabled → deploy field-access permset → read Work Order layout → add field to layout → verify field on layout → create test Work Order → create Service Appointment → assign resource → verify test Work Order scheduled → resolve template version → activate prompt template (Connect API) → verify activation.
Existing-test-WO branch — when test-data-mode is existing, skip create-test-workorder / create-service-appointment / assign-resource and run point-existing-workorder instead: update a real Work Order's PreWorkBriefPromptTemplate and move its Service Appointment into today's window.
Every step is idempotent — it checks org state before it writes, so re-running applies zero changes.
Ordering is load-bearing
- Assign the admin permission sets (including
EinsteinGPTPromptTemplateManager) BEFORE deploying the prompt template. If the admin lacks it, the Pre-Work Brief template type silently vanishes from Prompt Builder and the deploy fails with no error message — just a missing dropdown option. - Enable LDS (
lsdkForFieldServiceMobilePref) before on-device use or the brief renders blank on mobile.
Gotchas
GenAiPromptTemplateis NOT SOQL/REST queryable. Detect it and resolve its0hf-prefixed Id via the Metadata deep-read by name (type=GenAiPromptTemplate,fullName=Pre_Work_Brief), not a query.- Send the template deploy bodies as JSON objects, not serialized strings.
- Whole-record write footguns — two different mechanisms, neither a raw MDAPI deploy.
deploy-lds-settingandadd-field-to-layoutboth write existing whole records, but differently. LDS goes through the Field Service settings controller (saveFieldServiceSettingsConfig): a per-fieldisChanged<Field>partial-patch whose body must be wrapped under a top-leveluserSettingskey —{"userSettings": {"lsdkForFieldServiceMobilePref": true, "isChangedLsdkForFieldServiceMobilePref": true}}. A flat body (fields at the top level) returns 500CONTROLLER_ERRORNullPointerException (userSettings is null). The Work Order layout is a Tooling APILayout.Metadataround-trip that IS full-replace: read the current Metadata first (a ToolingLayoutGET —read-workorder-layout'sdescribe/layoutsis only for checking placement), add only the new field, and PATCH the whole object back (omitted keys reset to default). On the write, null outfeedLayoutand drop theServiceReportRelatedListrelated list or the PATCH 400s (see the layout step's notes). This is NOT SOAP MDAPI and NOT/headless/metadata(unrouted) — it's Tooling REST over dispatch passthrough.
Activate the prompt template (Connect API)
The template deploys Published, not Active — until it is activated it does not appear in the runtime catalog and the mobile app fails with "We hit a snag." Activation IS programmatic via the Connect API (available since v65.0 / API 258):
PUT /services/data/v67.0/einstein/prompt-templates/{devName}/versions/{versionId}/status?action=activate&ignoreWarnings=false
Body: {}
- Resolve the
versionIdfirst. GET/services/data/v67.0/einstein/prompt-templates/{devName}and readchildRelationships.GenAiPromptTemplateVersions[].fields.Id.value(the3vN-prefixed version Id). This GET works even while the template is inactive/absent from the catalog. - On success the response is
isSuccessful:true,statusCode:"200", with anadditionalData.wrappedMap.summary.overallSeverityofSAFE. The template-levelIsActiveflips totrueandActiveVersionIdis populated (the version's ownStatusstaysPublished— "Published" at the version level is "Active" at the template level). - Not callable from Apex. The endpoint is
@ConnectHidden(from=Apex); call it throughdispatch(orsf api request rest --method PUT), notConnectApi. This is why the earlier ApexConnectApi.EinsteinLLMand Tooling/metadata attempts failed — along with a wrong URL shape (/activaterather than/versions/{id}/status?action=activate) and too-early API versions (v62–v66). verify-activation— a runtime prompt-template-catalog read (GET /einstein/prompt-templates?pageSize=200, confirmPre_Work_Briefnow appears) — is chained immediately after to confirm activation landed.
Live-verified against a non-prod org 2026-07-22: IsActive False→True, ActiveVersionId null→populated, and the template appeared in the runtime catalog on the same call.
Scope boundary — on-device rendering
On-device verification (the technician opening the Field Service mobile app and confirming the brief renders job-specific content in the Overview tab) is out of scope for this deploy primitive and owned by the coordinating Pre-Work Brief skill. Note that verify-activation confirms the template is Active, but only on-device rendering confirms Data 360 grounding is actually producing job-specific content — a distinct check the coordinating skill is responsible for. There is no headless surface that returns what the technician sees on the device.
Source
Authored from the sf-skills-internal coordinating skill field-service-prework-brief-configure (+ its references/ files) and Salesforce Help for Einstein Pre-Work Brief. Live-validated against a dispatcher org. The harness derives the ordered, typed SOR from this skill on each run.
─────
Runtime context (Headless 360 / agentic): When this skill runs in the Headless 360 / agentic context, prefer the dispatch tool over CLI tools (sf project deploy, sfdx, shell commands) when possible. The operations available to you are listed below in steps:; each has been verified against the live org. Use dispatch against the canonical paths. CLI fallback is acceptable only when no API path exists for a given capability.
Critical Constraints
Preconditions:
- EinsteinFieldServicePsl provisioned (check:
GET /services/data/v67.0/query?q=SELECT Id FROM PermissionSetLicense WHERE DeveloperName='EinsteinFieldServicePsl' returns totalSize>=1) - Admin holds Customize Application + Manage Profiles and Permission Sets (check:
session user is a Setup admin) - Einstein generative AI base setup complete (incl. Data 360 grounding) (check:
org-level Einstein Pref enabled; grounding sources reachable) - Pilot technician selected with an active ServiceResource (check:
GET /services/data/v67.0/query?q=SELECT Id, RelatedRecordId FROM ServiceResource WHERE IsActive=true AND RelatedRecordId='<pilot-user-id>' returns totalSize=1)
Verification Checklist
After every write operation, confirm the effect by re-reading state:
- After (write): call
verify-provisioning(GET /services/data/v67.0/query) - After
assign-perms-admin: callverify-permset-admin(GET /services/data/v67.0/query) - After
verify-showpreworkbrief-perm: calldetect-existing-template(GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}) - After
deploy-prompt-template-header: callverify-template-deployed(GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}) - After
deploy-lds-setting: callverify-lds-enabled(GET /headless/invoke/platform/document-builder) - After
add-field-to-layout: callverify-field-on-layout(GET /services/data/v67.0/sobjects/WorkOrder/describe/layouts) - After
assign-resource: callverify-workorder-scheduled(GET /services/data/v67.0/query) - After
activate-prompt-template: callverify-activation(GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}) - After
assign-fs-einstein-user-admin: callverify-showpreworkbrief-perm(GET /services/data/v67.0/query)
Operations Reference
Operations grouped by purpose. Use these as the building blocks for the workflows above.
Summary
| Operation | Purpose | Status | Call | Depends on |
|---|---|---|---|---|
verify-provisioning | verify | — | GET /services/data/v67.0/query | — |
assign-psl-admin | write | — | POST /services/data/v67.0/sobjects/PermissionSetLicenseAssign | verify-provisioning |
assign-perms-admin | write | — | POST /services/data/v67.0/sobjects/PermissionSetAssignment | assign-psl-admin |
verify-permset-admin | verify | — | GET /services/data/v67.0/query | assign-perms-admin |
detect-existing-template | verify | — | GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName} | verify-showpreworkbrief-perm |
deploy-prompt-template-header | write | — | PATCH /headless/invoke/platform/einstein-prompt-studio/insert-prompt-template | detect-existing-template |
verify-template-deployed | verify | — | GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName} | deploy-prompt-template-header |
read-fieldservice-settings | read | — | GET /headless/invoke/platform/document-builder | verify-template-deployed |
deploy-lds-setting | write | — | PATCH /headless/invoke/platform/document-builder-rlm/save-field-service-settings-config | read-fieldservice-settings |
verify-lds-enabled | verify | — | GET /headless/invoke/platform/document-builder | deploy-lds-setting |
deploy-field-access-permset | write | — | POST /services/data/v67.0/sobjects/PermissionSet | verify-lds-enabled |
assign-perms-technician | write | — | POST /services/data/v67.0/sobjects/PermissionSetAssignment | deploy-field-access-permset |
read-workorder-layout | read | — | GET /services/data/v67.0/sobjects/WorkOrder/describe/layouts | assign-perms-technician |
verify-field-on-layout | verify | — | GET /services/data/v67.0/sobjects/WorkOrder/describe/layouts | add-field-to-layout |
create-test-workorder | write | — | POST /services/data/v67.0/sobjects/WorkOrder | verify-field-on-layout |
create-service-appointment | write | — | POST /services/data/v67.0/sobjects/ServiceAppointment | create-test-workorder |
assign-resource | write | — | POST /services/data/v67.0/sobjects/AssignedResource | create-service-appointment |
verify-workorder-scheduled | verify | — | GET /services/data/v67.0/query | assign-resource |
point-existing-workorder | write | — | PATCH /services/data/v67.0/sobjects/WorkOrder/{Id} | verify-field-on-layout |
resolve-template-version | read | — | GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName} | verify-workorder-scheduled, point-existing-workorder |
activate-prompt-template | write | — | PUT /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}/versions/{versionId}/status?action=activate&ignoreWarnings=false | resolve-template-version |
verify-activation | verify | — | GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName} | activate-prompt-template |
assign-fs-einstein-psl-admin | write | — | POST /services/data/v67.0/sobjects/PermissionSetLicenseAssign | verify-permset-admin |
assign-fs-einstein-user-admin | write | — | POST /services/data/v67.0/sobjects/PermissionSetAssignment | assign-fs-einstein-psl-admin |
verify-showpreworkbrief-perm | verify | — | GET /services/data/v67.0/query | assign-fs-einstein-user-admin |
add-field-to-layout | write | — | PATCH /services/data/v67.0/tooling/sobjects/Layout/{layoutId} | read-workorder-layout |
Dependency graph
graph TD
verify_provisioning["verify-provisioning (verify)"]
assign_psl_admin["assign-psl-admin (write)"]
assign_perms_admin["assign-perms-admin (write)"]
verify_permset_admin["verify-permset-admin (verify)"]
detect_existing_template["detect-existing-template (verify)"]
deploy_prompt_template_header["deploy-prompt-template-header (write)"]
verify_template_deployed["verify-template-deployed (verify)"]
read_fieldservice_settings["read-fieldservice-settings (read)"]
deploy_lds_setting["deploy-lds-setting (write)"]
verify_lds_enabled["verify-lds-enabled (verify)"]
deploy_field_access_permset["deploy-field-access-permset (write)"]
assign_perms_technician["assign-perms-technician (write)"]
read_workorder_layout["read-workorder-layout (read)"]
verify_field_on_layout["verify-field-on-layout (verify)"]
create_test_workorder["create-test-workorder (write)"]
create_service_appointment["create-service-appointment (write)"]
assign_resource["assign-resource (write)"]
verify_workorder_scheduled["verify-workorder-scheduled (verify)"]
point_existing_workorder["point-existing-workorder (write)"]
resolve_template_version["resolve-template-version (read)"]
activate_prompt_template["activate-prompt-template (write)"]
verify_activation["verify-activation (verify)"]
assign_fs_einstein_psl_admin["assign-fs-einstein-psl-admin (write)"]
assign_fs_einstein_user_admin["assign-fs-einstein-user-admin (write)"]
verify_showpreworkbrief_perm["verify-showpreworkbrief-perm (verify)"]
add_field_to_layout["add-field-to-layout (write)"]
verify_provisioning --> assign_psl_admin
assign_psl_admin --> assign_perms_admin
assign_perms_admin --> verify_permset_admin
verify_showpreworkbrief_perm --> detect_existing_template
detect_existing_template --> deploy_prompt_template_header
deploy_prompt_template_header --> verify_template_deployed
verify_template_deployed --> read_fieldservice_settings
read_fieldservice_settings --> deploy_lds_setting
deploy_lds_setting --> verify_lds_enabled
verify_lds_enabled --> deploy_field_access_permset
deploy_field_access_permset --> assign_perms_technician
assign_perms_technician --> read_workorder_layout
add_field_to_layout --> verify_field_on_layout
verify_field_on_layout --> create_test_workorder
create_test_workorder --> create_service_appointment
create_service_appointment --> assign_resource
assign_resource --> verify_workorder_scheduled
verify_field_on_layout --> point_existing_workorder
verify_workorder_scheduled --> resolve_template_version
point_existing_workorder --> resolve_template_version
resolve_template_version --> activate_prompt_template
activate_prompt_template --> verify_activation
verify_permset_admin --> assign_fs_einstein_psl_admin
assign_fs_einstein_psl_admin --> assign_fs_einstein_user_admin
assign_fs_einstein_user_admin --> verify_showpreworkbrief_perm
read_workorder_layout --> add_field_to_layout
Read operations
read-fieldservice-settings
Read the Field Service settings singleton (userSettings map — lsdkForFieldServiceMobilePref for LDS on mobile, other prefs). Result is the pre-write snapshot for deploy-lds-setting's read-back contract in verify-lds-enabled. Reused from FieldServiceSettings SOR.
Call: GET /headless/invoke/platform/document-builder
Depends on: verify-template-deployed
Output: FieldServiceSettingsSerializer map at body.body. Load-bearing key: lsdkForFieldServiceMobilePref (Lightning Data Service for Field Service Mobile — without it, Pre-Work Brief renders blank on device). This step is a snapshot for verify-lds-enabled; deploy-lds-setting does NOT consume the full map (see its inputs — the controller uses isChanged partial-patch semantics).
read-workorder-layout
Enumerate WorkOrder page layouts + record types. Result feeds add-field-to-layout / verify-field-on-layout. Response is large (~200KB).
Call: GET /services/data/v67.0/sobjects/WorkOrder/describe/layouts
Depends on: assign-perms-technician
Output: layouts[] array with layoutSections/detailLayoutSections and buttonLayoutSection; recordTypeMappings[] mapping recordTypeId -> layoutId. Scan detailLayoutSections[].layoutRows[].layoutItems[].layoutComponents[].value for the technician's layout to check whether 'PreWorkBriefPromptTemplate' is present.
resolve-template-version
Extract the 3vN-prefix version Id from the deployed Pre_Work_Brief template. Same GET as detect-existing-template / verify-template-deployed — this step re-reads under a distinct id because activation consumes the version Id specifically. Read childRelationships.GenAiPromptTemplateVersions[].fields.Id.value; pick the entry whose fields.Status.value == 'Published' (the pre-active version).
Call: GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}
Inputs:
promptTemplateDevName(String) — Fixed 'Pre_Work_Brief' for this workflow.
Depends on: verify-workorder-scheduled, point-existing-workorder
Output: childRelationships.GenAiPromptTemplateVersions[].fields.Id.value — the 3vN-prefix version Id activate-prompt-template consumes. The GET works even while the template is inactive/absent from the runtime catalog.
Notes: branch_join: Join point for both test-data branches. verify-workorder-scheduled is the fresh-branch tail; point-existing-workorder is the existing-branch tail. The two are mutex, so exactly one predecessor runs — activation fires in either mode. Treat depends_on here as an OR-join, not a barrier.
Write operations
assign-psl-admin
Grant the Einstein-for-Field-Service PSL to the admin user via PermissionSetLicenseAssign create. Idempotent: swallow DUPLICATE_VALUE (STATUSCODE) as already-assigned success.
Call: POST /services/data/v67.0/sobjects/PermissionSetLicenseAssign
Inputs:
AssigneeId(String) — 18-char User Id (005-prefixed).PermissionSetLicenseId(String) — 0PL-prefixed PSL Id from verify-provisioning.- Source: output of
verify-provisioning
- Source: output of
Depends on: verify-provisioning
Rollback: DELETE /sobjects/PermissionSetLicenseAssign/{id}
Notes: idempotency: DUPLICATE_VALUE -> success (already assigned)
assign-perms-admin
Grant EinsteinGPTPromptTemplateManager to the admin — this provides Prompt Studio authoring access. NOTE (corrected 2026-08-25): this permset does NOT make the Pre-Work Brief template TYPE visible; the type is gated by UserPermission ShowPreWorkBriefGA (see assign-fs-einstein-user-admin). On a full FS eval org ShowPreWorkBriefGA is ambient so this permset alone appeared sufficient, but on a fresh org it is not. Idempotent: swallow DUPLICATE_VALUE as already-assigned.
Call: POST /services/data/v67.0/sobjects/PermissionSetAssignment
Inputs:
AssigneeId(String)PermissionSetId(String) — 0PS-prefixed PermissionSet Id. Resolve via SELECT Id FROM PermissionSet WHERE Name='EinsteinGPTPromptTemplateManager'.
Depends on: assign-psl-admin
Rollback: DELETE /sobjects/PermissionSetAssignment/{id}
Notes: idempotency: DUPLICATE_VALUE -> success; skill_gotcha: Skipping this before deploy-prompt-template-header produces silent failure (missing dropdown option, no error).
deploy-prompt-template-header
Create the Pre_Work_Brief GenAiPromptTemplate (type einstein_gpt__fieldServicePreWorkBrief) in ONE insertPromptTemplate call that carries the version + WorkOrder input + Flow DataProvider inline via childRelationships. insertPromptTemplate rejects a bare header ("Prompt Template[null] has no versions"), and createPromptTemplateVersion only adds versions to an already-existing template, so header + version + input + provider are created together in a single transaction. Skipped when detect-existing-template returned 200. Adjusted-from the skill's MDAPI-deploy assumption: /headless/metadata is not routed on this dispatcher; einstein-prompt-studio is the canonical replacement.
Call: PATCH /headless/invoke/platform/einstein-prompt-studio/insert-prompt-template
Inputs:
promptTemplate(object) — Complete GenAiPromptTemplate as a single-call insert, sent as a JSON object (NOT a serialized string). Exact nested shape (each node uses the wrapper form {apiName, id:null, isStandard:false, isOverridable:false, additionalFields:{}, fields:{...}, childRelationships:{...}}). apiName MUST be the node's ENTITY TYPE NAME (NOT null): 'GenAiPromptTemplate' for the top node, then 'GenAiPromptTemplateVersion', 'GenAiPromptTemplateInput', 'GenAiPromptTemplateDataProvider', 'GenAiPromptTemplateDataProviderParam' on the nested nodes. A null apiName throws CONTROLLER_ERROR ("Cannot invoke String.equals ... getApiName() is null"). The Flow reference (DataProvider Definition/ReferenceName and the version Content merge field) MUST use the fully-qualified namespaced flow name sfdc_fieldservice__ModifyPWB — the bare FlowDefinitionView.ApiName (ModifyPWB) fails flow-accessibility ("ModifyPWB is not accessible"):
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 1k
- Forks
- 342
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
field-service-prework-brief-deployer-configure- Source
- github.com/forcedotcom/sf-skills
github.com/forcedotcom/sf-skills