| name | field-service-voice-to-form-configure |
| description | Set up Voice to Form on Field Service Mobile end-to-end against a Salesforce org, covering both variants: Voice to Record Edit (voice-fills any record-edit screen) and Voice to Form Data Capture (voice-fills Discovery Framework / Data Capture forms). Discovers existing DC forms and asks which to enable, hands off to fs-data-capture-form-deployer to create them if none exist, assigns every permission a mobile user needs, and walks the admin through the Einstein generative AI base setup. TRIGGER when the user asks to enable, configure, install, or set up Voice to Form, V2F, Voice to Record Edit, V2RE, the microphone on the mobile app, or voice-fill on Field Service Mobile. DO NOT TRIGGER when the user wants Pre-Work Brief, wants to author a brand-new Data Capture form, or wants to build a generic Agentforce agent. |
| user-invocable | false |
| metadata | {"version":"1.0","domains":["Field Service"],"cliTools":[{"tool":"[Truncated]","semver":">=2.0.0"}]} |
Setting up Voice to Form
Configure Voice to Form on Field Service Mobile from a fresh Field Service org. Voice to Form lets a mobile worker tap the microphone on a form or a record edit screen and dictate the contents. Einstein generative AI parses the speech and fills the matching fields.
There are two variants. They share a permission backbone but enable through different switches:
| Variant | What it does | Where it shows up | Underlying switch |
|---|
| Voice to Record Edit (V2RE) | Voice-fills the standard record edit screen on objects mobile workers can edit (Work Order, Service Appointment, Asset, Contact, Account, custom objects, etc.) | Mic icon on the Record Edit screen | FieldServiceMobileSettings.IsShowEditFullRecord = true (org-level row) + FieldServiceVoiceToRecordEdit system permission |
| Voice to Form Data Capture (V2F, Beta) | Voice-fills Discovery Framework / Data Capture flows the admin built in Flow Builder | Mic icon on a Data Capture form | FieldServiceVoiceToForm system permission + per-form LLM Targetable flag (UI toggle only) |
This skill walks the complete setup for both, in the order Salesforce documents them at:
help.salesforce.com/s/articleView?id=service.mfs_voice_to_form_setup.htm (V2F Data Capture)
help.salesforce.com/s/articleView?id=service.mfs_voice_to_record_edit_setup.htm (V2 Record Edit)
The skill is idempotent. Re-running on an already-configured org applies zero changes.
Runtime contract: every org interaction in this skill is a REST call
dispatched through the Codey runtime (dispatch locally / the hosted
Headless 360 MCP in shared surfaces). This skill has no dependency on the
execution environment — no sf CLI, no shell scripts, no local Python, no
jq, no temp files, no metadata deploy, no Apex. Detection is a set of REST
GETs; the LDS toggle is a Tooling FieldServiceSettings.Metadata PATCH; the
V2RE org switch is an sObject PATCH; the voice permset is a single sObject
POST; entitlement grants are association-object POSTs. The one step with no
callable API — the per-form LLM Targetable flag — is driven by the
agent-native browser MCP or handed to the admin as a Setup deeplink (a
click-through, not a shell step). Do not shell out.
Platform Notes
- All API paths use
vXX.0 — pin to the org's current API version (v62.0 or later; the V2F Beta assumes a recent release).
- Endpoints marked Tooling dispatch to
/services/data/vXX.0/tooling/...; the rest are the core Data API (/services/data/vXX.0/...).
- The Codey runtime resolves and refreshes the connected org and mints tokens on demand — this skill never manages org aliases, instance URLs, or access tokens.
- A few setup steps are genuinely clicks-only in Setup (the Einstein base-setup wizard org pref, the per-form LLM Targetable flag). For those the skill surfaces the exact Setup deeplink for the admin to click; it never tries to script them.
- Every SOQL below is dispatched as
GET /services/data/vXX.0/query?q=<soql> (Data API) or GET /services/data/vXX.0/tooling/query?q=<soql> (Tooling). Reads that return records are handled inline by the agent — there is no shell parsing.
Editions and licensing
- Edition. Field Service core features, managed package, and the mobile app are available in Enterprise, Unlimited, and Developer editions in Lightning Experience.
- Mobile entitlement. Every mobile worker needs the Field Service Mobile PSL (
FieldServiceMobilePsl) to log into the app. In modern Field Service orgs this is a permission-set license layered on top of any standard user license — there is NOT a separate "Field Service Mobile" user license SKU. (Earlier docs said otherwise; trust the live PermissionSetLicense query in Step 0.)
- V2RE entitlement. Mobile workers who use Voice to Record Edit need the Einstein for Field Service PSL (
EinsteinFieldServicePsl).
- V2F (Beta) entitlement. Mobile workers who use Voice to Form on Data Capture need the Agentforce for Field Service PSL. The Voice to Form Beta also requires the V2F and V2RE system permissions on a custom permset (see Step 4 — a thin custom permset, NOT a clone). Confirm license entitlement with your account exec before assigning, to avoid unanticipated fees.
- App version. V2RE requires Summer '25 or later of the Field Service Mobile App. V2F requires the latest version.
Prerequisites
Before running the setup sequence, confirm all of the following:
- Edition + add-on. The org has Einstein for Field Service (V2RE) and/or Agentforce for Field Service (V2F).
- Einstein generative AI is fully ON, not just provisioned. The Step 1.5 probe flags this. The
EinsteinLlm runtime entitlement must be active (live LLM call returns 200, not FUNCTIONALITY_NOT_ENABLED). Trial and SDO orgs commonly have the PSLs assigned but the runtime never turned on — this is the single most common cause of "We couldn't recommend any updates" on the mobile app.
- Data Cloud is provisioned and enabled if you also use Prompt Builder against grounded data. Required by the V2F help article. V2RE works without Data Cloud activation in practice.
- For V2F only: Data Capture is set up per
help.salesforce.com/s/articleView?id=service.mfs_data_capture_setup.htm. The skill detects DC forms in Step 5 and, if none exist, hands off to the fs-data-capture-form-deployer skill in this repo to create them.
- Admin user has the right permissions:
Customize Application, Manage Profiles and Permission Sets, and Manage Flows.
Setup Sequence
Run steps in order. Each step reads the org state before it writes; if a precondition fails, the step surfaces the failure and stops without mutating the org. Every read and write below is a single dispatch call.
Step 0: Detect provisioning state and route
Run six detection reads to classify the org. Several queries that look intuitive (FlowDefinitionView, Tooling FieldServiceMobileSettings, Flow.DeveloperName) DO NOT WORK — the field names and surfaces below are the verified ones.
1. Einstein / Agentforce / Mobile Field Service PSLs — GET /services/data/vXX.0/query:
SELECT DeveloperName, MasterLabel, TotalLicenses, UsedLicenses
FROM PermissionSetLicense
WHERE DeveloperName IN ('EinsteinFieldServicePsl','FieldServiceMobilePsl','AgentforceForFieldServicePsl')
EinsteinFieldServicePsl + FieldServiceMobilePsl are required for a V2F demo; AgentforceForFieldServicePsl is optional. Only assign in Step 7 the PSLs that come back here.
2. Shipped EinsteinFieldServiceUser permset (read-only clone source reference) — GET /services/data/vXX.0/query:
SELECT Id, Name, Label FROM PermissionSet WHERE Name = 'EinsteinFieldServiceUser'
Present → the FSL package is installed at a V2F-capable version. This permset is shipped read-only; the skill never edits it (and does NOT clone it — see Step 4).
3. Lightning Data Service mode (LDS) — Tooling GET /services/data/vXX.0/tooling/query:
SELECT FullName, Metadata FROM FieldServiceSettings
Read Metadata.enableLsdkMode. true → LDS on, proceed. false → Step 1 flips it. LDS is needed for V2F-DC, optional for V2RE.
4. V2RE org switch — regular sObject GET /services/data/vXX.0/query (NOT Tooling):
SELECT Id, MasterLabel, IsDefault, IsShowEditFullRecord FROM FieldServiceMobileSettings
Capture the Id of the IsDefault = true row (or the sole row) — Step 2's PATCH targets it.
5. Active Data Capture forms — Tooling GET /services/data/vXX.0/tooling/query (NOT FlowDefinitionView):
SELECT Id, MasterLabel, ProcessType, Status, DefinitionId
FROM Flow
WHERE ProcessType IN ('DataCaptureFlow','DiscoveryFrameworkDataCaptureFlow') AND Status = 'Active'
Use MasterLabel for display — Flow has no DeveloperName column (querying it 400s INVALID_FIELD); follow Definition.DeveloperName for the API name. Zero rows → Step 5 hands off to fs-data-capture-form-deployer.
6. Existing V2F custom permset — GET /services/data/vXX.0/query:
SELECT Id, Name, Label FROM PermissionSet WHERE IsCustom = true AND Name LIKE '%V2F%'
One row → a prior run created it; skip Step 4 and reuse its Id. Zero rows → Step 4 creates it.
Interpret the results to classify the org:
| Diagnostic 1 (PSL) | Diagnostic 2 (permset) | Diagnostic 5 (forms) | Action |
|---|
| MISSING | any | any | Stop. Contact Salesforce AE to purchase Einstein/Agentforce for Field Service. The skill cannot continue. |
| PRESENT | MISSING | any | Continue to Step 1.5. Einstein base setup is incomplete; run the wizard before anything else. |
| PRESENT | PRESENT | MISSING | Continue. V2RE will set up cleanly. V2F-DC will hand off to the DC skill in Step 5. |
| PRESENT | PRESENT | PRESENT | Continue. Both variants will set up cleanly. |
Step 0.5: Choose the target technician user
Voice to Form is a per-user feature: each technician needs the Field Service Mobile PSL, the Einstein for Field Service PSL, the V2F/V2RE permset, and an active ServiceResource row. The skill targets one technician at a time so the admin can pilot before broad rollout.
Ask the admin: "Do you have a specific technician user you want to enable Voice to Form for?"
If yes: the admin supplies a username or User Id. Validate that the user is active and has a ServiceResource record — two GET /services/data/vXX.0/query reads (substitute the supplied value into the bound WHERE):
SELECT Id, Name, Username, IsActive, Profile.Name FROM User
WHERE (Username = :tech OR Id = :tech) AND IsActive = true
SELECT Id, Name, ResourceType FROM ServiceResource
WHERE RelatedRecordId IN (SELECT Id FROM User WHERE Username = :tech OR Id = :tech)
AND IsActive = true
If no: auto-pick a candidate — the first active ResourceType='T' technician on a non-administrator profile — and surface the choice for confirmation, GET /services/data/vXX.0/query:
SELECT Id, Name, RelatedRecord.Id, RelatedRecord.Username, RelatedRecord.Name, RelatedRecord.Profile.Name
FROM ServiceResource
WHERE IsActive = true AND ResourceType = 'T'
AND RelatedRecordId != null AND RelatedRecord.IsActive = true
AND RelatedRecord.Profile.Name NOT IN ('System Administrator')
AND (NOT RelatedRecord.Profile.Name LIKE '%Customer Community%')
AND (NOT RelatedRecord.Profile.Name LIKE '%Partner Community%')
ORDER BY Name LIMIT 1
Capture the technician's User.Id (call it TECH_USER_ID) and Username for the assignment steps. The running admin's User Id is resolved the same way when needed (SELECT Id, Username FROM User WHERE ...) — the Codey runtime already knows the connected identity, so no org display call is required.
Step 1: Enable Lightning Data Service for the Field Service Mobile app
Voice to Form on Discovery Framework forms (V2F-DC) renders inside the LDS-aware mobile container. V2RE works without LDS, but enabling it is harmless and required for V2F-DC, so do it once up front.
LDS is enabled by default for new orgs from Winter '25; all orgs auto-migrate by Spring '26.
FieldServiceSettings is a Tooling sObject whose config lives in a JSON Metadata field — the same shape Step 0 diagnostic 3 reads back. So enabling LDS is a Tooling read-modify-write PATCH, not a metadata-file deploy. There is no .settings-meta.xml, no SFDX project, and no sf project deploy start — that path was never necessary; the Tooling Metadata surface is the real REST path (same pattern the sibling fs-data-capture-form-deployer skill uses for the FieldServiceSettings sharing prefs).
1a. Read the settings singleton (already done in Step 0 diagnostic 3, but re-read to get the full Metadata object and its row Id) — Tooling GET /services/data/vXX.0/tooling/query:
SELECT Id, FullName, Metadata FROM FieldServiceSettings
If Metadata.enableLsdkMode is already true, LDS is on — skip to Step 1.5. Otherwise capture the row Id (a base64-encoded singleton Tooling id) and the full Metadata object.
1b. PATCH the full Metadata back with enableLsdkMode: true — PATCH /services/data/vXX.0/tooling/sobjects/FieldServiceSettings/{Id}:
{ "Metadata": { "...all sibling keys from the GET...", "enableLsdkMode": true } }
Send the entire Metadata object read in 1a with only enableLsdkMode flipped — a partial body nulls the omitted org prefs (fieldServiceOrgPref, enableWorkOrders, the search-field arrays, etc.). A 204 is success.
1c. Verify it actually flipped — re-run the 1a Tooling read and confirm Metadata.enableLsdkMode == true. This guards the rare SDO/trial-org case where a write reports success but the flag stays false. If it did not flip, surface the Setup deeplink for the admin to toggle it by hand:
LDS Setup UI (fallback — only if the PATCH did not persist):
<instanceUrl>/lightning/setup/FieldServiceSettings/home
Enable 'Lightning SDK for Field Service Mobile' under the Lightning SDK section.
(The Codey runtime knows the instance URL; the skill just names the relative Setup path for the admin.)
Step 1.5: Confirm the Einstein generative AI runtime is ON
This is the step that most often goes missed. Without it the mic icon WILL render on-device, transcription WILL work, but every voice attempt fails with "We couldn't recommend any updates. Try again." — the LLM runtime returning FUNCTIONALITY_NOT_ENABLED: [EinsteinLlm] because the enableEinsteinGPT org pref was never flipped.
1.5a. Probe the runtime live. This is the only honest test — Tooling queries on Einstein settings are unreliable across releases. Dispatch GET /services/data/vXX.0/einstein/prompt-templates?pageSize=5:
- 200 with a
promptRecords array (at least one row, e.g. Salesforce-managed defaults like einstein_gpt__summarizeContact) → the LLM runtime is ON. Continue to Step 2.
- 400
FUNCTIONALITY_NOT_ENABLED: [EinsteinLlm] → the runtime is OFF. Walk 1.5b.
1.5b. If the probe failed, surface the wizard deeplinks for the admin. The wizard is genuinely UI-only — the skill cannot click through it and does not try. Name the relative Setup paths (the runtime resolves the instance URL):
Einstein LLM runtime is OFF. Walk the wizard end-to-end.
PRIMARY (start here):
/lightning/setup/EinsteinSetup/home
Wizard sub-pages:
Generative AI: /lightning/setup/EinsteinGPTSetupHome/home
Trust Layer: /lightning/setup/EinsteinTrustSetup/home
Data Cloud: /lightning/setup/DataCloudSetup/home
Prompt Builder: /lightning/setup/EinsteinPromptStudio/home
Models config: /lightning/setup/EinsteinModelsConfiguration/home
In order:
1. Open the PRIMARY link. Toggle 'Turn On Einstein' -> accept terms.
2. Open the Generative AI sub-page. Step through each numbered stage
(enable the org pref, set up Trust Layer, acknowledge data usage,
enable Prompt Builder).
3. If the wizard prompts for Data Cloud, open Data Cloud Setup and activate.
If it's not visible, refresh or re-login; if still missing, the org needs
a Data Cloud SKU (a CRT to Salesforce Support).
4. Re-run the 1.5a probe. If it now returns promptRecords, continue to Step 2.
Most common SDO/trial-org symptom: PSLs all assigned, EinsteinSetup page exists,
but the runtime entitlement was never turned on. 'Turn On Einstein' flips it.
1.5c. Re-probe after the admin completes the wizard. Re-run the 1.5a dispatch call. Do not move on until it returns promptRecords.
Step 2: Enable the Voice to Record Edit org switch
V2RE's org-level switch lives on FieldServiceMobileSettings, a regular sObject (not a Tooling Settings type — earlier docs were wrong about this). The relevant field is IsShowEditFullRecord (label "Enable full edit on records"). The settings record is named ("Field Service Mobile Settings" by default) and has an IsDefault flag controlling which profiles inherit it.
2a. Find the default settings row (from Step 0 diagnostic 4), or create one — if diagnostic 4 returned no row, create the default with POST /services/data/vXX.0/sobjects/FieldServiceMobileSettings:
{
"MasterLabel": "Field Service Mobile Settings",
"DeveloperName": "Field_Service_Mobile_Settings",
"IsDefault": true,
"IsShowEditFullRecord": true
}
A 201 returns the new row Id (which already satisfies Step 2b — skip the PATCH).
2b. Flip IsShowEditFullRecord (and IsDefault) to true on the existing row — PATCH /services/data/vXX.0/sobjects/FieldServiceMobileSettings/{Id}:
{ "IsShowEditFullRecord": true, "IsDefault": true }
A 204 is success. Re-read the row (Step 0 diagnostic 4) to confirm both fields are true. Without IsDefault = true, the toggle takes effect only on profiles explicitly mapped to this settings row via MobileSettingsAssignment — IsDefault = true is the simplest path for a pilot. The PATCH is idempotent: re-sending the same values returns 204 and changes nothing.
What the user sees on-device. Per Salesforce help (mfs_actions_order.xml): once IsShowEditFullRecord = true and the user has Edit access to the object, Edit Work Order, Edit Work Order Line Item, and Edit Service Appointment appear in the Actions launcher on the Work Order Overview screen, after Quick Actions. The mobile app caches the settings — the technician must log out and back in for the new actions to appear.
Step 3: Confirm the V2F + V2RE system-permission columns exist
Salesforce ships two distinct system perms — one per variant. They are enabled on a custom permset (Step 4). Their PermissionSet describe columns are:
- V2F (Beta):
FieldServiceVoiceToForm — column PermissionsFieldServiceVoiceToForm
- V2RE:
FieldServiceVoiceToRecordEdit — column PermissionsFieldServiceVoiceToRecordEdit
Column presence in the describe IS the org-level feature-flag test. Dispatch GET /services/data/vXX.0/sobjects/PermissionSet/describe and filter fields[].name for PermissionsFieldServiceVoiceTo*:
- Both columns present → V2F Beta and V2RE are both licensed on the org.
- Only
PermissionsFieldServiceVoiceToRecordEdit → V2F Beta isn't enabled for this org. Per the help article: "Your Customer Org ID needs to be identified, and the feature flag must be turned on for your respective sandbox or production organization." File a CRT with Salesforce Support quoting the org ID, then continue with V2RE-only setup.
- Neither present → the feature is not licensed. Stop.
The describe also confirms both columns are createable = true and updateable = true — which is why Step 4 can be a single POST (see below).
Step 4: Create the V2F/V2RE permset with both system perms
Create a thin custom permset that enables the voice system perms via a single sObject POST. PermissionSet is a REST-createable sObject and every Permissions* system-perm column is writable at create time (confirmed by the Step 3 describe: all 474 Permissions* columns are createable+updateable), so the permset is born with the voice perms already on — no XML, no SFDX project, no sf project deploy start.
Do NOT "clone" EinsteinFieldServiceUser. The shipped permset grants zero object permissions and only two unrelated system perms (ShowPreWorkBriefGA, FieldServiceCopilotActions); its only real payload is the Einstein license link, which Step 7 already delivers via the EinsteinFieldServicePsl PSL. A thin custom permset carrying just the voice system-perm booleans is correct and sufficient — replicating the shipped permset would add nothing.