Soql Lib Query Builder
beyond-the-cloud-dev/soql-lib
Builds Salesforce SOQL queries using the SOQL Lib fluent builder API (SOQL.cls).
Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms.
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configure --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .claude/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .claude/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configureType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configure --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .agents/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .agents/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configure --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .cursor/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .cursor/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/forcedotcom/sf-skills.git --path skills/field-service-data-capture-reference-configure--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configure --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .gemini/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .gemini/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configureInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .github/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .github/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install forcedotcom/sf-skills field-service-data-capture-reference-configure --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/forcedotcom/sf-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/field-service-data-capture-reference-configure .opencode/skills/field-service-data-capture-reference-configure && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "field-service-data-capture-reference-configure" agent skill from https://github.com/forcedotcom/sf-skills/tree/main/skills/field-service-data-capture-reference-configure into .opencode/skills/field-service-data-capture-reference-configure/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "field-service-data-capture-reference-configure", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
field-service-data-capture-reference-configureBuild, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms.
Field Service Data Capture Reference Configure is an agent skill from forcedotcom/sf-skills. Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtimeservicefieldservice:dc components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD +…
Its SKILL.md is about 9.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files.
It sits in Sales & Support, covering CRM management. It works with Salesforce. The repository describes itself as: Salesforce's curated collection of agent skills for building applications. Optimized for Agentforce Vibes, compatible with all AI tools. The licence is Apache-2.0.
4 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit e5164d9. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
sfpython3From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
soap.sforce.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Field Service Data Capture Reference Configure loads about 9.9k tokens when it runs. Until then it costs about 151 tokens; SKILL.md has 2,886 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from forcedotcom/sf-skills at commit e5164d9, republished under its Apache-2.0 licence (© forcedotcom). 2,886 words, ~9,881 tokens.
.claude/skills/field-service-data-capture-reference-configure/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites).
Build, edit, and deploy Salesforce Flows with processType: DataCaptureFlow (Field Service mobile / offline forms).
<processType>DataCaptureFlow</processType>
<areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
<environments>Offline</environments>
<!-- NO <apiVersion> tag -->Optional IsLlmTargetable custom property — if you include it, it must be a JSON string, not a boolean:
<customProperties>
<name>IsLlmTargetable</name>
<value><stringValue>{"value":"false"}</stringValue></value>
</customProperties>The <booleanValue>false</booleanValue> form deploys but blocks activation — error: The value of the IsLlmTargetable custom property's value field must be a string in JSON format. Omitting the property entirely is also fine.
Salesforce's Flow schema enforces grouping — all elements of the same type must appear in a single contiguous block. Deploy fails with Element X is duplicated at this location when violated.
Group order doesn't matter, but within each group elements must be adjacent:
<choices> together<dynamicChoiceSets> together<screens> together<decisions> together<recordLookups> together<recordCreates> together<recordUpdates> together<loops> together<assignments> together<variables> togetherConnector references determine execution order, not XML order.
All extensions: prefix runtime_service_fieldservice:
| Component | Extension | fieldType |
|---|---|---|
| Short Text | dcTextInput | ComponentInstance |
| Long Text | dcLongText | ComponentInstance |
dcEmail | ComponentInstance | |
| Phone | dcPhone | ComponentInstance |
| Name | dcName | ComponentInstance |
| Numeric | dcNumeric | ComponentInstance |
| Counter | dcCounter | ComponentInstance |
| Date | dcDate | ComponentInstance |
| Date & Time | dcDateTime | ComponentInstance |
| Checkbox | dcCheckbox | ComponentInstance |
| Toggle | dcToggle | ComponentInstance |
| Address / GPS | dcAddress | ComponentInstance |
| Lookup | dcLookup | ComponentInstance |
| Static image | dcFileView | ComponentInstance |
| Upload image (mobile) | dcUpImage | ComponentInstance |
| Upload file (mobile) | dcUpFile | ComponentInstance |
| Signature (mobile) | dcSignature | ComponentInstance |
| Picklist single | dcPicklist | ComponentChoice |
| Picklist multi | dcPicklist | ComponentMultiChoice |
| Radio buttons | dcRbGroup | ComponentChoice |
| Checkbox group | dcCbGroup | ComponentMultiChoice |
| Matrix | dcMatrix | ComponentMultiChoice |
| Display text | (none) | DisplayText |
| Section | (none) | RegionContainer + Region |
| Repeater | (none) | Repeater |
Note: <fieldType>Range</fieldType> is NOT a valid slider fieldType in DataCaptureFlow (despite "Range/Slider" appearing in Builder UI lists). Sliders aren't available as pure metadata in this process type — use dcNumeric or dcCounter. forceContent:repeater (Lightning generic) ≠ <fieldType>Repeater</fieldType> (FSL offline). They share a concept, not XML.
| fieldType | How |
|---|---|
ComponentInstance | <inputParameters><name>label</name><value><stringValue>…</stringValue></value></inputParameters> |
ComponentChoice / ComponentMultiChoice | <fieldText>Label</fieldText> |
DisplayText | <fieldText>HTML</fieldText> |
All ComponentInstance extensions (including dcAddress and dcToggle) accept the label inputParameter — no wrapping DisplayText needed.
Every input field needs <isRequired>true/false</isRequired> at field level. That single flag is sufficient for every dc* component — no extra required / isRequired inputParameter is needed.
dcLookup additionally accepts an isRequired inputParameter (boolean), but the field-level <isRequired> drives enforcement.
dcCheckbox and dcToggle accept <isRequired>true</isRequired> syntactically but don't enforce it at runtime.
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<storeOutputAutomatically>true</storeOutputAutomatically>
<styleProperties>
<verticalAlignment><stringValue>top</stringValue></verticalAlignment>
<width><stringValue>12</stringValue></width>
</styleProperties>Exception: <fieldType>Repeater</fieldType> explicitly rejects storeOutputAutomatically ("the storeOutputAutomatically field isn't supported"). Repeater output is always available as .AllItems — no opt-in needed.
Every screen needs ALL THREE of these or the Next/Finish button won't render:
<allowFinish>true</allowFinish> (even on non-final screens)<showFooter>true</showFooter><nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>Plus:
<start> must always be a <screens> element<screens> elements must be grouped together in the XMLThe Repeater's output collection is exposed as .AllItems. Confirmed working on API v66.
<!-- On the screen: -->
<fields>
<name>MyRepeater</name>
<fieldType>Repeater</fieldType>
<!-- NO storeOutputAutomatically on the Repeater itself -->
<fields>
<name>Row_PartName</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
<!-- … -->
</fields>
<fields>
<name>Row_PartQty</name>
<extensionName>runtime_service_fieldservice:dcCounter</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
<!-- … -->
</fields>
<isRequired>false</isRequired>
</fields>
<!-- At end of flow: -->
<loops>
<name>Loop_Parts</name>
<collectionReference>MyRepeater.AllItems</collectionReference> <!-- ← THE KEY -->
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Create_Part</targetReference>
</nextValueConnector>
</loops>
<recordCreates>
<name>Create_Part</name>
<object>CustomFormPart__c</object>
<connector>
<targetReference>Loop_Parts</targetReference> <!-- loops back -->
</connector>
<inputAssignments>
<field>PartName__c</field>
<value>
<elementReference>Loop_Parts.Row_PartName.value</elementReference>
<!-- ↑ LOOP name + nested field name + .value -->
</value>
</inputAssignments>
<inputAssignments>
<field>Quantity__c</field>
<value>
<elementReference>Loop_Parts.Row_PartQty.value</elementReference>
</value>
</inputAssignments>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>Don'ts:
<collectionReference>MyRepeater</collectionReference> → Element "MyRepeater" doesn't exist<collectionReference>MyRepeater.items</collectionReference> → generic server error<collectionReference>MyRepeater.data</collectionReference> → generic server errorMyRepeater.Row_PartName.value won't work — must use the loop's name, not the repeater's name.Cross-row validation does NOT compile. Formula refs like r_GR4.AllItems[$Items].field.value and r_GR4.AllItems[$Items - 1].field.value fail with Syntax error. Per-row validation works via plain fieldName.value inside the nested field's own validationRule. For cross-row rules, use a post-screen loops + decisions.
Other Repeater accessors don't resolve today. Only .AllItems works. AddedItems, PrepopulatedItems, RemovedItems all fail deploy with doesn't exist.
Bind an existing SObject collection to the Repeater so it renders one pre-filled row per source record. The user can then edit, add, or remove rows before submit.
Pattern: recordLookups (get source collection, getFirstRecordOnly=false, storeOutputAutomatically=true) → screen with Repeater bound via the collection inputParameter → nested fields use SourceCollection[$EachItem].FieldApiName as their value default.
<recordLookups>
<name>Get_Source</name>
<object>ServiceResource</object>
<getFirstRecordOnly>false</getFirstRecordOnly>
<storeOutputAutomatically>true</storeOutputAutomatically>
<connector><targetReference>Screen_Repeater</targetReference></connector>
<!-- optional <limit>, <filters> … -->
</recordLookups>
<!-- On the screen: -->
<fields>
<name>accountRepeater</name>
<fieldType>Repeater</fieldType>
<inputParameters>
<name>collection</name> <!-- ← binds source rows -->
<value><elementReference>Get_Source</elementReference></value>
</inputParameters>
<fields>
<name>account_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Id: {!Get_Source[$EachItem].Id}</p></fieldText>
<!-- DisplayText inside the Repeater merges via SourceCollection[$EachItem].Field -->
</fields>
<fields>
<name>name</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<inputParameters>
<name>label</name>
<value><stringValue>Name</stringValue></value>
</inputParameters>
<inputParameters>
<name>value</name>
<value><elementReference>Get_Source[$EachItem].Name</elementReference></value>
<!-- ↑ prepopulates the editable field with the source record's value -->
</inputParameters>
<isRequired>true</isRequired>
<storeOutputAutomatically>true</storeOutputAutomatically>
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<styleProperties>…</styleProperties>
</fields>
<isRequired>false</isRequired>
<styleProperties>…</styleProperties>
</fields>Key points:
collection, not value or source.SourceCollectionName[$EachItem].FieldApiName — use the record-lookup's name, not the Repeater's name. Works in both DisplayText.fieldText (as {!Get_Source[$EachItem].Id}) and in component value defaults (as <elementReference>Get_Source[$EachItem].Name</elementReference>).$EachItem is the per-row iterator Salesforce injects while rendering the Repeater. It only resolves inside Repeater-nested fields.Repeater_Name.AllItems as normal — prepopulation changes the input, not the output accessor..AllItems entries after submit; there is no PrepopulatedItems / AddedItems split (those accessors fail deploy).To show the user what they captured (e.g. review / confirmation / per-row detail), put a Loop after the Repeater screen whose body connects to a display screen; the display screen then connects back to the Loop. The end connector of the Loop moves on to the next step.
<loops>
<name>Loop_Through_Repeater</name>
<collectionReference>accountRepeater.AllItems</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Repeater_Output_Screen</targetReference> <!-- body = display screen -->
</nextValueConnector>
<!-- <noMoreValuesConnector> → next step after the review is done -->
</loops>
<screens>
<name>Repeater_Output_Screen</name>
<connector><targetReference>Loop_Through_Repeater</targetReference></connector> <!-- back to loop -->
<fields>
<name>display_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Source Id: {!Loop_Through_Repeater.UniqueField__Id}</p>
<p>Name: {!Loop_Through_Repeater.name.value}</p>
<p>Type: {!Loop_Through_Repeater.description.value}</p></fieldText>
<styleProperties>…</styleProperties>
</fields>
<allowFinish>true</allowFinish>
<showFooter>true</showFooter>
<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
</screens>Accessor rules inside the loop body:
{!LoopName.nestedFieldName.value} (same .value / .selectedChoiceValues / .isActive / etc. accessors as elsewhere).{!LoopName.UniqueField__Id}. This is a synthetic field the Repeater exposes on each iteration; it only carries a value for rows that came from the bound collection (new rows the user added will be blank)..AllItems + Create pattern above.This loop-over-.AllItems display pattern composes with the Create/Update patterns: one loop for rendering a review screen, a later loop (or the same one, if ordering permits) for CUD. Remember the CUD rule — nothing (screens, gets, decisions) may sit between sequential CUD nodes, so any review loop must fully complete before the CUD chain starts.
Append multiple Create, Update, or Delete operations only at the end of the flow, in any order.<inputParameters><name>min</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>max</name><value><numberValue>10.0</numberValue></value></inputParameters>
<inputParameters><name>step</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>minCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
<inputParameters><name>maxCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters><inputParameters><name>minDate</name><value><elementReference>$Flow.CurrentDate</elementReference></value></inputParameters>
<inputParameters><name>maxDate</name><value><dateValue>2027-12-31</dateValue></value></inputParameters>Only use isCompact=true when ALL labels ≤8 characters AND ≤5 options.
<inputParameters><name>objectApiName</name><value><stringValue>Asset</stringValue></value></inputParameters>
<inputParameters><name>searchedFields</name><value><stringValue>Name, SerialNumber</stringValue></value></inputParameters>
<inputParameters><name>isMultiSelection</name><value><booleanValue>true</booleanValue></value></inputParameters>
<inputParameters><name>recordIdCollection</name><value><elementReference>v_Ids</elementReference></value></inputParameters>recordIdCollection — scoping the searchable setrecordIdCollection (singular recordId + Collection suffix). recordIds fails deploy with We can't find this input attribute: "recordIds".isMultiSelection=true. In single-select mode it is silently ignored — the user sees the full unfiltered object.recordLookups (scoped subset) → loops + assignments (build String collection of Ids) → screen with dcLookup recordIdCollection=v_Ids. Works offline against Briefcase-primed data; target < 1s over ~60k records.{!Lookup.recordIds} (String collection); visibility rules and DML that previously used {!Lookup.recordId} (singular) must iterate the collection or take the first element.dcLookup displayed labeldcLookup has no input parameter for the displayed field (no displayField/primaryField). The label in search results and the selected chip is driven by the object's Primary Compact Layout — first field in that layout wins. To change it: Setup → Object Manager → Object → Compact Layouts → reorder → assign as Primary (org-wide change). searchedFields controls matching, not display.
Flow-local alternative: swap dcLookup for dcPicklist backed by a dynamicChoiceSets with <displayField> / <valueField>.
<inputParameters><name>useCoordinates</name><value><booleanValue>true</booleanValue></value></inputParameters><inputParameters><name>questions</name><value><stringValue>["Q1","Q2","Q3"]</stringValue></value></inputParameters>Escape & as & inside the JSON string.
<fields>
<name>MySection</name>
<fieldText>Section Header</fieldText>
<fieldType>RegionContainer</fieldType>
<fields>
<name>MySection_Col1</name>
<fieldType>Region</fieldType>
<fields><!-- components here --></fields>
<inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
<isRequired>false</isRequired>
</fields>
<fields>
<name>MySection_Col2</name>
<fieldType>Region</fieldType>
<fields><!-- components here --></fields>
<inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
<isRequired>false</isRequired>
</fields>
<isRequired>false</isRequired>
<regionContainerType>SectionWithHeader</regionContainerType>
…styleProperties…
</fields><visibilityRule>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>componentName.value</leftValueReference>
<operator>GreaterThan</operator>
<rightValue><numberValue>0.0</numberValue></rightValue>
</conditions>
</visibilityRule>Property accessors: .value (input components, including dcCheckbox), .selectedChoiceValues (choice components), .isActive (toggle), .firstName / .lastName (Name component), .recordId / .recordIds (Lookup single / multi).
The same accessors are also used inside recordCreates / recordUpdates inputAssignments — e.g. <elementReference>new_Reading.value</elementReference>.
validationRule, not isRequiredIF(TriggerField.selectedChoiceValues = "Yes",
AND(NOT(ISBLANK(value)), value >= 0, value <= 100000),
TRUE)IsNull takes a booleanValue on the right, NOT a null literal:
<conditions>
<leftValueReference>v_ParentId</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue> <!-- true = is null, false = is not null -->
</rightValue>
</conditions>Calculated values cannot display on the same screen that collects the inputs — calculations run only after the user taps Next. Pattern:
Screen N (collect inputs) → recordLookups / assignments / decisions → Screen N+1 (display results)Screen N's connector must point to the calculation element, NOT to Screen N+1. All decision branches must eventually converge on Screen N+1.
DisplayText in DataCaptureFlow has severely limited formula support compared to standard flows — complex formulas deploy fine and preview in Builder but fail at runtime with Error while resolving default value reference.
Fails at runtime:
IF(Toggle.isActive, "YES", "NO") — any IF/CASE on component propertiesTEXT(CASE(...)), ADDMONTHS(...), nested date mathfieldTextWorks:
{!var_RiskScore}{!MyPicklist.selectedChoiceValues}, {!MyNumeric.value}{!$Flow.CurrentDate}, {!$User.FirstName}Pattern: pre-calculate in an <assignments> element → store in a variable → reference that variable in DisplayText.
value defaults| Default binding | Variable | Works? |
|---|---|---|
dcTextInput | $User.Username | ✅ |
dcTextInput | $User.Name | ❌ type mismatch error |
dcDateTime | $Flow.InterviewStartTime | ✅ |
dcDate | $Flow.CurrentDate | ✅ |
dynamicChoiceSets) — mobile offline gotcha<outputAssignments> inside a dynamicChoiceSets deploys fine but does NOT reliably populate the target variables at runtime in mobile offline DataCaptureFlow. Downstream screens render blank.
Correct pattern: keep the choice set minimal (displayField, valueField, filters, object, dataType). After the selection screen, route through a recordLookups filtered by Id = {!picklistName.selectedChoiceValues} and put extra fields into variables via the lookup's outputAssignments. Fits calculation-timing rule naturally (lookup sits between selection screen and display screen).
<recordLookups>
<name>gr_SelectedChild</name>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value><elementReference>pl_Child.selectedChoiceValues</elementReference></value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>Child__c</object>
<outputAssignments>
<assignToReference>v_SelectedValue</assignToReference>
<field>Reading_Value__c</field>
</outputAssignments>
</recordLookups>Colors from the Lightning Design System: #2E844A (green), #0176D3 (blue), #FE9339 (orange), #C9C7C5 (neutral).
<div style="background: linear-gradient(135deg, #2E844A 0%, #0176D3 100%); color: white; padding: 20px; border-radius: 10px; text-align: center;">
<p style="margin: 0; font-size: 22px;"><strong>🔧 Site Visit Report</strong></p>
<p style="margin: 4px 0 0 0; font-size: 13px;">Subtitle</p>
</div><p><b>Step X of N – 📍 Section Title</b></p>
<div style="width: 100%; height: 8px; background-color: #C9C7C5; border-radius: 4px; margin: 5px 0;">
<div style="width: PERCENT%; height: 100%; background: linear-gradient(90deg, #2E844A 0%, #0176D3 100%); border-radius: 4px;"></div>
</div>Separator between counter and title MUST be en dash – (U+2013), not hyphen.
<!-- Info (blue) -->
<div style="background-color: #EAF5FE; border-left: 4px solid #0176D3; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #014486; font-size: 13px;"><b>ℹ️ Info:</b> …</p>
</div>
<!-- Warning (orange) -->
<div style="background-color: #FFF4E6; border-left: 4px solid #FE9339; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #704D00; font-size: 13px;"><b>⚠️ Heads up:</b> …</p>
</div>
<!-- Success (green) -->
<div style="background-color: #E8F5E9; border-left: 4px solid #2E844A; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #1B5E20; font-size: 13px;"><b>✅ Ready:</b> …</p>
</div><div style="border: 1px solid #DDDBDA; border-radius: 8px; padding: 14px 16px; background-color: #FAFAF9;">
<p style="margin: 0 0 8px 0; color: #0176D3; font-size: 14px;"><b>📍 Section</b></p>
<p style="margin: 2px 0;"><b>Name:</b> {!Input_SiteName.value}</p>
<p style="margin: 2px 0;"><b>Contact:</b> {!Input_Contact.firstName} {!Input_Contact.lastName}</p>
<p style="margin: 2px 0;"><b>Priority:</b> {!Input_Priority.selectedChoiceValues}</p>
<p style="margin: 2px 0;"><b>After-hours:</b> {!Input_Toggle.isActive}</p>
</div>All HTML must be XML-escaped in <fieldText>: & → &, " → ", < → <, > → >.
Custom object + field deploys do not auto-grant FLS/CRUD on the System Administrator profile. Flows running as the admin still can't read/write the new fields. Ship a PermissionSet and assign it:
<!-- MyObject_Access.permissionset-meta.xml -->
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<label>My Object Access</label>
<license>Salesforce</license>
<hasActivationRequired>false</hasActivationRequired>
<objectPermissions>
<allowCreate>true</allowCreate><allowDelete>true</allowDelete>
<allowEdit>true</allowEdit><allowRead>true</allowRead>
<modifyAllRecords>true</modifyAllRecords><viewAllRecords>true</viewAllRecords>
<object>MyObject__c</object>
</objectPermissions>
<fieldPermissions><field>MyObject__c.MyField__c</field><editable>true</editable><readable>true</readable></fieldPermissions>
<tabSettings><tab>MyObject__c</tab><visibility>Visible</visibility></tabSettings>
</PermissionSet>Assign after deploy: sf org assign permset --name MyObject_Access --target-org <alias>
<sharingModel>ControlledByParent</sharingModel>, else Must specify a sharing model value.actionOverrides for actions that aren't standard (Automation, Details). Strip them before re-deploy, else X is not a standard action and cannot be overridden.<type>LongTextArea</type>. Text max length is 255.required=true field deploys cleanly, but if FLS is set in a separate file, You cannot deploy to a required field fires. Flip the field to required=false or handle required-ness in the flow instead.Lets users list records from the App Launcher:
<!-- MyObject__c.tab-meta.xml -->
<CustomTab xmlns="http://soap.sforce.com/2006/04/metadata">
<customObject>true</customObject>
<motif>Custom53: Form</motif>
</CustomTab>Then add <tabSettings> to the permset (as shown above).
A flow that deploys cleanly and shows up on desktop will silently fail on FSL Mobile with "No forms available. Try Again" if the org isn't set up to share DDC + WorkPlan records with the assigned technician. Verified 2026-05-28: a fully-validated form (Sewerage Further Work Request) was invisible on iOS Field Service for the assigned tech until all four fixes below were in place. The same blocker hid the SDO's pre-shipped Job Safety Assessment form.
Why it's silent: FSL Mobile uses the UI API endpoint /services/data/v67.0/ui-api/related-list-records/{woId}/DynamicDataCaptures, which enforces sharing rules. SOQL queries as a sysadmin bypass sharing, so desktop validation never surfaces the issue. The endpoint returns INSUFFICIENT_ACCESS to the tech, the iOS app catches the error, and renders an empty state with a "Try Again" button.
Default platform OWD is Private for both objects. Override in object metadata:
<!-- objects/DynamicDataCapture/DynamicDataCapture.object-meta.xml -->
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<sharingModel>ReadWrite</sharingModel>
<externalSharingModel>ReadWrite</externalSharingModel>
</CustomObject><!-- objects/WorkPlan/WorkPlan.object-meta.xml -->
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<sharingModel>ReadWrite</sharingModel>
<externalSharingModel>ReadWrite</externalSharingModel>
</CustomObject>WorkStep inherits via ControlledByParent and doesn't need a separate change.
Many SDO orgs ship with these false. Without them, the AssignedResource never gets shared access to the WO, even though they show on the SA's resource list.
<!-- settings/FieldService.settings-meta.xml -->
<FieldServiceSettings xmlns="http://soap.sforce.com/2006/04/metadata">
<doesShareSaWithAr>true</doesShareSaWithAr>
<doesShareSaParentWoWithAr>true</doesShareSaParentWoWithAr>
</FieldServiceSettings>The settings change only applies to new AssignedResource rows. Existing rows need a touch-update to trigger sharing recalc:
sf apex run --target-org <alias> <<'APEX'
List<AssignedResource> ars = [
SELECT Id FROM AssignedResource
WHERE ServiceResource.RelatedRecord.Username = :techUsername
];
update ars;
APEX<relatedList>DynamicDataCapture</relatedList> (singular) is the correct XML form. The UI API uses plural DynamicDataCaptures separately. Don't try to align them.PausedFlowInterviewId — granted by default to all profiles.SDO_SFS_All_Permissions (or any equivalent FSL permset) is sufficient. No extra permset needed for the Forms tab.v67.0; only DEBUG builds dynamically discover.| Wrong | Correct | Deploy error (exact) |
|---|---|---|
dcRadioButtons | dcRbGroup | extension not found |
dcSection | RegionContainer | extension not found |
minimumDate / maximumDate | minDate / maxDate | input attribute not found |
multiSelection on Lookup | isMultiSelection | input attribute not found |
disabled / readOnly on Lookup | isDisabled / isReadonly (lowercase o) | input attribute not found |
<apiVersion> tag on flow | Omit entirely | You can't specify the field API Version |
extensionName on Repeater itself | Only on nested fields | extensionName isn't supported |
InputField fieldType | ComponentInstance + extensionName | Field type rejected |
<fieldText> on ComponentInstance | Use label inputParameter | A required input parameter is missing: 'label' |
placeholder inputParameter on dc* | Not supported — bake into label text | We can't find this input attribute: "placeholder" |
min/max on dcNumeric | Valid only on dcCounter | We can't find this input attribute: "min" |
<fieldType>Range</fieldType> (slider) | Not valid in DataCaptureFlow | 'Range' is not a valid value for the enum 'FlowScreenFieldType' |
storeOutputAutomatically on Repeater | Omit (collection is always .AllItems) | the storeOutputAutomatically field isn't supported |
collectionReference=Repeater_Name in loop | Repeater_Name.AllItems | Element "X" doesn't exist. Specify an existing collection element |
Loop body: Repeater_Name.field.value | Loop_Name.field.value (loop's name, not repeater's) | Invalid reference |
Cross-row validation: AllItems[$Items - 1] | Use post-screen loops + decisions | Formula Syntax error |
| Decision between CUD nodes | Sequential CUDs, no branches | Append multiple Create, Update, or Delete operations only at the end of the flow |
| Get Records after CUD | Move gets to before CUD | Flow structure rejected |
Step X of Y - Topic (hyphen) | Step X of Y – Topic (en dash U+2013) | Validator counts 0 progress indicators |
<start> → recordLookups / decisions | <start> → <screens> (intro screen first) | Mobile offline fails to render |
<actionCalls> | Remove; use DisplayText for notifications | Action elements not allowed |
helpText inputParameter | Bake into label text | input attribute not found |
IsLlmTargetable as <booleanValue> (optional property, but if present) | <stringValue>{"value":"false"}</stringValue> or omit the property entirely | Activation error: The value of the IsLlmTargetable custom property's value field must be a string in JSON format |
recordIds inputParameter on Lookup | recordIdCollection (singular Id + Collection) | We can't find this input attribute: "recordIds" |
recordIdCollection with single-select Lookup | Set isMultiSelection=true (scoping ignored otherwise) | No error — silently unfiltered at runtime |
<outputAssignments> inside dynamicChoiceSets | Post-selection recordLookups with outputAssignments | No deploy error — variables stay blank on downstream screens |
IF/CASE/date math in DisplayText | Pre-calculate in Assignment, reference simple variable | Error while resolving default value reference at runtime |
$User.Name as value default on dcTextInput | $User.Username | field integrity exception… type for input parameter "Value" doesn't match |
Missing nextOrFinishButtonLabel on screen | Add <nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel> | Next/Finish button not visible |
| Calling AutoLaunched subflow from DataCaptureFlow | Inline the logic, or call only another DataCaptureFlow | This flow can't reference [FlowName] because the referenced flow type is Autolaunched Flow |
isRequired=true on field behind visibilityRule | Set isRequired=false; use validationRule IF(trigger, rule, TRUE) | User blocked from proceeding on hidden field |
# Single file
sf project deploy start -d force-app/main/default/flows/MyFlow.flow-meta.xml \
--target-org <alias> --wait 60 --json
# Multi-dir (use repeated -d, NOT comma-separated)
sf project deploy start \
-d force-app/main/default/objects \
-d force-app/main/default/permissionsets \
-d force-app/main/default/tabs \
--target-org <alias> --wait 60 --jsonExtract errors:
... --json 2>&1 | python3 -c "
import sys, json
d = json.load(sys.stdin)
r = d.get('result', {})
print('Status:', r.get('status'))
for f in r.get('details', {}).get('componentFailures', []):
print('ERROR:', f.get('fullName'), '-', f.get('problem'))
"Bundled alongside this skill at examples/ (in this skill):
Data_Capture_All_Components.flow-meta.xml — every component in deployment-ready XMLDataCapture_Showcase.flow-meta.xml — full end-to-end flow: multi-screen form, continue-editing recordLookup, Repeater → Loop → child records via .AllItems, Create-or-Update CUD chain driven by a Decision, visual polish (banner, progress, callouts, review cards). This is the canonical "truth" for XML format — when skill rules conflict with this file, the file wins.Repeater_with_prepopulation.flow-meta.xml — canonical prepopulated-Repeater pattern: recordLookups (ServiceResource) → Repeater bound via collection inputParameter with nested field value defaults using SourceCollection[$EachItem].FieldApiName → post-Repeater Loop over .AllItems feeding a display screen that reads {!LoopName.nestedField.value} and {!LoopName.UniqueField__Id}. Validated example — treat as ground truth for prepopulation and post-Repeater display XML.DataCapture_Repeater_with_data_showcase.flow (in the org, not committed) — canonical .AllItems loop spike; also documents non-working cross-row validation formula syntaxes─────
Runtime context (Headless 360 / agentic): When this skill runs in the Headless 360 / agentic context, prefer the platform dispatch tool (dispatch in the hosted Headless 360 MCP; dispatch in the local-dev MCP) 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. Call the dispatch tool against the canonical paths. CLI fallback is acceptable only when no API path exists for a given capability.
Operational rules:
<variables><name>recordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
<variables><name>parentRecordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
<variables><name>parentObjectType</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>isRequired=true if it's behind a visibilityRule. The required check still fires while the field is hidden, so users can't proceed. Instead, set the field isRequired=false and wrap the rule:© forcedotcom, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 3 other files in skills/field-service-data-capture-reference-configure of forcedotcom/sf-skills.
Open the folder on GitHubat commit e5164d9
Field Service Data Capture Reference Configure next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Field Service Data Capture Reference Configure this skillforcedotcom/sf-skills | 1.1k | — | ~9.9k | Automated safety check: Pass | Apache-2.0 | |
| Soql Lib Query Builderbeyond-the-cloud-dev/soql-lib | 154 | — | ~4.3k | Automated safety check: Pass | MIT | |
| Sf DatacloudJaganpro/sf-skills | 424 | — | ~2.7k | Automated safety check: Pass | MIT | |
| Soql Lib Selectorbeyond-the-cloud-dev/soql-lib | 154 | — | ~2k | Automated safety check: Pass | MIT | |
| Dev SetupPortwood-Global-Solutions/Portwood | 126 | — | ~1.1k | Automated safety check: Pass | Apache-2.0 | |
| Sf FlowJaganpro/sf-skills | 424 | — | ~1.8k | Automated safety check: Pass | MIT |
beyond-the-cloud-dev/soql-lib
Builds Salesforce SOQL queries using the SOQL Lib fluent builder API (SOQL.cls).
Jaganpro/sf-skills
Salesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows.
beyond-the-cloud-dev/soql-lib
Creates Salesforce Apex selector classes using the SOQL Lib selector pattern.
Portwood-Global-Solutions/Portwood
Get from a fresh clone of Portwood to a working, fully-tested Salesforce org.
Jaganpro/sf-skills
Creates and validates Salesforce Flows with 110-point scoring.
gmapsscraper/google-maps-agent-skills
Export Google Maps business data to CSV, JSON, or CRM format (HubSpot, Pipedrive, Salesforce).
forcedotcom/sf-skills
Declared architecture snapshot for one Agentforce agent: planner, topics, actions, flows, Apex, prompt templates, and NGA plugins.
forcedotcom/sf-skills
Data Cloud 360° view of a single Agentforce session. An agent skill from forcedotcom/sf-skills.
forcedotcom/sf-skills
Apply a Salesforce sandbox post-copy automation JSON config against a target org.
forcedotcom/sf-skills
Apply a Salesforce sandbox post-copy automation JSON config against a target org.
forcedotcom/sf-skills
Apply SLDS-compliant UI using the correct blueprints, styling hooks, utility classes, and icons.
forcedotcom/sf-skills
Lightning Web Components with PICKLES methodology and 165-point scoring.
Works with
Categories
Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Field Service Data Capture Reference Configure is an agent skill from forcedotcom/sf-skills. Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms.
Field Service Data Capture Reference Configure fits situations like: authoring flow-meta.xml with runtimeservicefieldservice:dc components; repeater loops (.AllItems); master-detail child record persistence; visual polish (gradient banners.
Run `npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a claude-code`. Or copy the skill folder (skills/field-service-data-capture-reference-configure in forcedotcom/sf-skills) into .claude/skills/field-service-data-capture-reference-configure in your project. Claude Code loads it when a task matches its description.
Run `npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a codex`. Or copy the skill folder (skills/field-service-data-capture-reference-configure in forcedotcom/sf-skills) into .agents/skills/field-service-data-capture-reference-configure in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add forcedotcom/sf-skills --skill field-service-data-capture-reference-configure -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/field-service-data-capture-reference-configure, .gemini/skills/field-service-data-capture-reference-configure, .github/skills/field-service-data-capture-reference-configure and .opencode/skills/field-service-data-capture-reference-configure in your project.
Going by SKILL.md and its folder, Field Service Data Capture Reference Configure needs the command-line tools its instructions call (sf and python3).
SKILL.md names 1 domain. In commands or code: soap.sforce.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Field Service Data Capture Reference Configure is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 9.9k tokens (SKILL.md is roughly 40k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Field Service Data Capture Reference Configure: Soql Lib Query Builder (beyond-the-cloud-dev/soql-lib, 154 stars), Sf Datacloud (Jaganpro/sf-skills, 424 stars), Soql Lib Selector (beyond-the-cloud-dev/soql-lib, 154 stars) and Dev Setup (Portwood-Global-Solutions/Portwood, 126 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
forcedotcom (a GitHub organization) maintains it in forcedotcom/sf-skills, which has 1,065 GitHub stars. The repository holds 251 skills in this directory. The repository was last updated on October 7, 2026.
Source: forcedotcom/sf-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.