---
name: field-service-prework-brief-deployer-configure
description: "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 configure Einstein Pre-Work Brief on Field Service Mobile."
user-invocable: false
metadata:
  version: "1.0"
  domains: ["Field Service"]
  cliTools:
    - tool: ["sf"]
      semver: ">=2.0.0"
---

# Managing Fs Prework Brief Deployer

## 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__fieldServicePreWorkBrief` GenAiPromptTemplate (`Pre_Work_Brief`) as Published.
- **Lightning Data Service** — enables Lightning Data Service on the Field Service settings (the `lsdkForFieldServiceMobilePref` org 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_Access` and exposes `WorkOrder.PreWorkBriefPromptTemplate` on 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) or `existing` (point a supplied real Work Order at the template and move its Service Appointment into today's window). Default `fresh`.

## 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

- **`GenAiPromptTemplate` is NOT SOQL/REST queryable.** Detect it and resolve its `0hf`-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-setting` and `add-field-to-layout` both write existing whole records, but differently. **LDS** goes through the Field Service settings controller (`saveFieldServiceSettingsConfig`): a per-field `isChanged<Field>` partial-patch whose body **must be wrapped under a top-level `userSettings` key** — `{"userSettings": {"lsdkForFieldServiceMobilePref": true, "isChangedLsdkForFieldServiceMobilePref": true}}`. A flat body (fields at the top level) returns **500 `CONTROLLER_ERROR` NullPointerException (`userSettings is null`)**. **The Work Order layout** is a **Tooling API `Layout.Metadata` round-trip** that IS full-replace: read the current Metadata first (a Tooling `Layout` GET — `read-workorder-layout`'s `describe/layouts` is only for checking placement), add only the new field, and PATCH the whole object back (omitted keys reset to default). On the write, null out `feedLayout` and drop the `ServiceReportRelatedList` related 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):

```text
PUT /services/data/v67.0/einstein/prompt-templates/{devName}/versions/{versionId}/status?action=activate&ignoreWarnings=false
Body: {}
```

- **Resolve the `versionId` first.** GET `/services/data/v67.0/einstein/prompt-templates/{devName}` and read `childRelationships.GenAiPromptTemplateVersions[].fields.Id.value` (the `3vN`-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 an `additionalData.wrappedMap.summary.overallSeverity` of `SAFE`. The template-level `IsActive` flips to `true` and `ActiveVersionId` is populated (the version's own `Status` stays `Published` — "Published" at the version level *is* "Active" at the template level).
- **Not callable from Apex.** The endpoint is `@ConnectHidden(from=Apex)`; call it through `dispatch` (or `sf api request rest --method PUT`), not `ConnectApi`. This is why the earlier Apex `ConnectApi.EinsteinLLM` and Tooling/metadata attempts failed — along with a wrong URL shape (`/activate` rather 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`, confirm `Pre_Work_Brief` now 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`: call `verify-permset-admin` (`GET /services/data/v67.0/query`)
- After `verify-showpreworkbrief-perm`: call `detect-existing-template` (`GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}`)
- After `deploy-prompt-template-header`: call `verify-template-deployed` (`GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}`)
- After `deploy-lds-setting`: call `verify-lds-enabled` (`GET /headless/invoke/platform/document-builder`)
- After `add-field-to-layout`: call `verify-field-on-layout` (`GET /services/data/v67.0/sobjects/WorkOrder/describe/layouts`)
- After `assign-resource`: call `verify-workorder-scheduled` (`GET /services/data/v67.0/query`)
- After `activate-prompt-template`: call `verify-activation` (`GET /services/data/v67.0/einstein/prompt-templates/{promptTemplateDevName}`)
- After `assign-fs-einstein-user-admin`: call `verify-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

```mermaid
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<Field> 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 versio