@salesforce/afv-skills 1.29.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/skills/agentforce-architecture-analyze/README.md +2 -8
  4. package/skills/agentforce-architecture-analyze/SKILL.md +2 -2
  5. package/skills/agentforce-architecture-analyze/references/contract.json +4 -4
  6. package/skills/agentforce-architecture-analyze/references/soql_fields.md +1 -1
  7. package/skills/data360-activate/README.md +0 -1
  8. package/skills/data360-activate/SKILL.md +0 -2
  9. package/skills/data360-code-extension-generate/SKILL.md +15 -2
  10. package/skills/data360-connect/README.md +0 -2
  11. package/skills/data360-connect/SKILL.md +0 -2
  12. package/skills/data360-harmonize/SKILL.md +0 -1
  13. package/skills/data360-orchestrate/README.md +0 -7
  14. package/skills/data360-orchestrate/SKILL.md +0 -2
  15. package/skills/data360-prepare/README.md +0 -1
  16. package/skills/data360-prepare/SKILL.md +0 -1
  17. package/skills/data360-query/README.md +0 -1
  18. package/skills/data360-query/SKILL.md +0 -1
  19. package/skills/data360-segment/README.md +0 -1
  20. package/skills/data360-segment/SKILL.md +0 -2
  21. package/skills/dx-pkg-post-install-configure/SKILL.md +184 -0
  22. package/skills/experience-cms-brand-apply/SKILL.md +47 -16
  23. package/skills/experience-lwc-generate/README.md +3 -2
  24. package/skills/experience-lwc-generate/references/async-notification-patterns.md +1 -1
  25. package/skills/experience-lwc-generate/references/component-patterns.md +3 -3
  26. package/skills/experience-lwc-generate/references/flow-integration-guide.md +1 -1
  27. package/skills/experience-lwc-generate/references/lwc-best-practices.md +4 -4
  28. package/skills/experience-lwc-generate/references/scoring-and-testing.md +1 -1
  29. package/skills/experience-lwc-generate/references/state-management.md +2 -2
  30. package/skills/experience-lwc-generate/references/triangle-pattern.md +3 -3
  31. package/skills/experience-lwc-generate/scripts/post-tool-validate.py +2 -2
  32. package/skills/experience-lwc-generate/scripts/template_validator.py +1 -1
  33. package/skills/experience-ui-bundle-app-coordinate/SKILL.md +198 -34
  34. package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +26 -0
  35. package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +15 -0
  36. package/skills/experience-ui-bundle-metadata-generate/SKILL.md +19 -8
  37. package/skills/experience-ui-bundle-metadata-generate/references/csp-metadata-format.md +2 -2
  38. package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +30 -0
  39. package/skills/external-diagram-mermaid-generate/README.md +2 -2
  40. package/skills/external-diagram-mermaid-generate/SKILL.md +1 -3
  41. package/skills/external-diagram-mermaid-generate/assets/agentforce/agent-flow.md +4 -4
  42. package/skills/external-diagram-mermaid-generate/assets/architecture/system-landscape.md +1 -1
  43. package/skills/external-diagram-mermaid-generate/assets/datamodel/b2b-commerce-erd.md +3 -3
  44. package/skills/external-diagram-mermaid-generate/assets/datamodel/campaigns-erd.md +1 -1
  45. package/skills/external-diagram-mermaid-generate/assets/datamodel/consent-erd.md +2 -2
  46. package/skills/external-diagram-mermaid-generate/assets/datamodel/files-erd.md +2 -2
  47. package/skills/external-diagram-mermaid-generate/assets/datamodel/forecasting-erd.md +2 -2
  48. package/skills/external-diagram-mermaid-generate/assets/datamodel/fsl-erd.md +2 -2
  49. package/skills/external-diagram-mermaid-generate/assets/datamodel/party-model-erd.md +1 -1
  50. package/skills/external-diagram-mermaid-generate/assets/datamodel/quote-order-erd.md +3 -3
  51. package/skills/external-diagram-mermaid-generate/assets/datamodel/revenue-cloud-erd.md +2 -2
  52. package/skills/external-diagram-mermaid-generate/assets/datamodel/sales-cloud-erd.md +1 -1
  53. package/skills/external-diagram-mermaid-generate/assets/datamodel/salesforce-erd.md +1 -1
  54. package/skills/external-diagram-mermaid-generate/assets/datamodel/scheduler-erd.md +2 -2
  55. package/skills/external-diagram-mermaid-generate/assets/datamodel/service-cloud-erd.md +3 -3
  56. package/skills/external-diagram-mermaid-generate/assets/datamodel/territory-management-erd.md +1 -1
  57. package/skills/external-diagram-mermaid-generate/assets/integration/api-sequence.md +1 -1
  58. package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code-pkce.md +1 -1
  59. package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code.md +1 -1
  60. package/skills/external-diagram-mermaid-generate/assets/oauth/client-credentials.md +1 -1
  61. package/skills/external-diagram-mermaid-generate/assets/oauth/device-authorization.md +2 -2
  62. package/skills/external-diagram-mermaid-generate/assets/oauth/jwt-bearer.md +2 -2
  63. package/skills/external-diagram-mermaid-generate/assets/oauth/refresh-token.md +1 -1
  64. package/skills/external-diagram-mermaid-generate/assets/oauth/user-agent-social-sign-on.md +2 -2
  65. package/skills/external-diagram-mermaid-generate/assets/role-hierarchy/user-hierarchy.md +1 -1
  66. package/skills/external-diagram-mermaid-generate/references/color-palette.md +13 -13
  67. package/skills/external-diagram-mermaid-generate/references/diagram-conventions.md +5 -5
  68. package/skills/external-diagram-mermaid-generate/references/erd-conventions.md +1 -1
  69. package/skills/external-diagram-mermaid-generate/references/mermaid-styling.md +2 -2
  70. package/skills/external-diagram-mermaid-generate/references/preview-guide.md +1 -1
  71. package/skills/external-diagram-mermaid-generate/references/usage-examples.md +9 -9
  72. package/skills/external-diagram-mermaid-generate/scripts/README.md +1 -1
  73. package/skills/integration-connectivity-connected-app-configure/README.md +4 -5
  74. package/skills/integration-connectivity-connected-app-configure/SKILL.md +2 -2
  75. package/skills/integration-connectivity-connected-app-configure/references/example-usage.md +7 -7
  76. package/skills/integration-connectivity-connected-app-configure/references/migration-guide.md +1 -1
  77. package/skills/integration-connectivity-connected-app-configure/references/oauth-flows-reference.md +1 -1
  78. package/skills/integration-connectivity-connected-app-configure/references/testing-validation-guide.md +3 -3
  79. package/skills/integration-connectivity-generate/README.md +1 -1
  80. package/skills/integration-connectivity-generate/SKILL.md +6 -0
  81. package/skills/integration-connectivity-generate/assets/callouts/rest-queueable-callout.cls +1 -1
  82. package/skills/integration-connectivity-generate/assets/external-services/external-service-operations.md +1 -1
  83. package/skills/integration-connectivity-generate/assets/soap/wsdl2apex-guide.md +1 -1
  84. package/skills/integration-connectivity-generate/references/callout-patterns.md +4 -0
  85. package/skills/integration-connectivity-generate/references/cdc-guide.md +2 -2
  86. package/skills/integration-connectivity-generate/references/event-driven-architecture-guide.md +5 -5
  87. package/skills/integration-connectivity-generate/references/event-patterns.md +3 -2
  88. package/skills/integration-connectivity-generate/references/external-services-guide.md +4 -1
  89. package/skills/integration-connectivity-generate/references/messaging-api-v2.md +2 -2
  90. package/skills/integration-connectivity-generate/references/named-credentials-automation.md +1 -1
  91. package/skills/integration-connectivity-generate/references/named-credentials-guide.md +12 -2
  92. package/skills/integration-connectivity-generate/references/platform-events-guide.md +3 -3
  93. package/skills/integration-connectivity-generate/references/rest-callout-patterns.md +1 -1
  94. package/skills/integration-connectivity-generate/references/scoring-rubric.md +1 -1
  95. package/skills/integration-connectivity-generate/references/security-best-practices.md +5 -2
  96. package/skills/integration-connectivity-generate/scripts/configure-named-credential.sh +16 -5
  97. package/skills/integration-connectivity-generate/scripts/set-api-credential.sh +11 -2
  98. package/skills/integration-connectivity-generate/scripts/suggest_credential_setup.py +4 -3
  99. package/skills/integration-connectivity-generate/scripts/validate_integration.py +1 -1
  100. package/skills/omnistudio-callable-apex-generate/README.md +1 -5
  101. package/skills/omnistudio-callable-apex-generate/SKILL.md +14 -4
  102. package/skills/omnistudio-callable-apex-generate/assets/pattern_callable_vanilla.cls +8 -1
  103. package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md +1 -1
  104. package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md +1 -1
  105. package/skills/omnistudio-datamapper-generate/SKILL.md +1 -1
  106. package/skills/omnistudio-datamapper-generate/assets/completion-summary-template.md +2 -2
  107. package/skills/omnistudio-datamapper-generate/references/best-practices.md +9 -9
  108. package/skills/omnistudio-datamapper-generate/references/naming-conventions.md +6 -6
  109. package/skills/omnistudio-datapacks-deploy/README.md +1 -1
  110. package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle/deploy-business-internet-plus-bundle.yaml +1 -1
  111. package/skills/omnistudio-dependencies-analyze/SKILL.md +12 -5
  112. package/skills/omnistudio-dependencies-analyze/references/dependency-patterns.md +9 -9
  113. package/skills/omnistudio-dependencies-analyze/references/namespace-guide.md +1 -1
  114. package/skills/omnistudio-epc-catalog-generate/README.md +1 -1
  115. package/skills/omnistudio-flexcard-generate/SKILL.md +11 -4
  116. package/skills/omnistudio-flexcard-generate/references/best-practices.md +6 -6
  117. package/skills/omnistudio-flexcard-generate/references/data-binding-guide.md +9 -9
  118. package/skills/omnistudio-integration-procedure-generate/SKILL.md +9 -1
  119. package/skills/omnistudio-integration-procedure-generate/references/element-types.md +3 -3
  120. package/skills/omnistudio-omniscript-generate/SKILL.md +2 -2
  121. package/skills/omnistudio-omniscript-generate/references/best-practices.md +1 -1
  122. package/skills/omnistudio-omniscript-generate/scripts/check-duplicate-omniscript.sh +8 -0
  123. package/skills/omnistudio-omniscript-generate/scripts/deploy-omniscript.sh +8 -0
  124. package/skills/platform-apex-logs-debug/README.md +2 -2
  125. package/skills/platform-apex-logs-debug/references/cli-commands.md +2 -2
  126. package/skills/platform-apex-logs-debug/references/debug-log-reference.md +16 -16
  127. package/skills/platform-apex-logs-debug/references/log-analysis-tools.md +2 -2
  128. package/skills/platform-apex-test-run/README.md +1 -1
  129. package/skills/platform-apex-test-run/references/test-fix-loop.md +2 -2
  130. package/skills/platform-apex-test-run/references/testing-best-practices.md +3 -3
  131. package/skills/platform-custom-field-generate/SKILL.md +12 -11
  132. package/skills/platform-custom-field-generate/references/advanced-picklists.md +17 -17
  133. package/skills/platform-custom-report-type-generate/SKILL.md +259 -0
  134. package/skills/platform-custom-report-type-generate/examples/AccountProjectsWithTasks.reportType-meta.xml +51 -0
  135. package/skills/platform-custom-report-type-generate/examples/AccountsWithIndustry.reportType-meta.xml +27 -0
  136. package/skills/platform-custom-report-type-generate/examples/AccountsWithProjects.reportType-meta.xml +44 -0
  137. package/skills/platform-custom-report-type-generate/references/category-values.md +32 -0
  138. package/skills/platform-custom-report-type-generate/references/errors-and-troubleshooting.md +24 -0
  139. package/skills/platform-data-manage/README.md +4 -4
  140. package/skills/platform-data-manage/references/bulk-testing-example.md +1 -1
  141. package/skills/platform-data-manage/references/crud-workflow-example.md +2 -2
  142. package/skills/platform-data-manage/references/orchestration.md +6 -6
  143. package/skills/platform-dataspace-access-configure/SKILL.md +318 -0
  144. package/skills/platform-docs-get/SKILL.md +4 -0
  145. package/skills/platform-docs-get/scripts/extract_salesforce_doc.py +78 -13
  146. package/skills/platform-encryption-configure/SKILL.md +122 -0
  147. package/skills/platform-encryption-configure/assets/EncryptionKey.settings-meta.xml +17 -0
  148. package/skills/platform-encryption-configure/assets/PlatformEncryption.settings-meta.xml +15 -0
  149. package/skills/platform-encryption-configure/assets/encrypted-field.field-meta.xml +22 -0
  150. package/skills/platform-encryption-configure/examples/cache-only-keys.settings-meta.xml +11 -0
  151. package/skills/platform-encryption-configure/references/encryption-schemes.md +34 -0
  152. package/skills/platform-encryption-configure/references/key-models.md +34 -0
  153. package/skills/platform-encryption-configure/references/tenant-secret-lifecycle.md +23 -0
  154. package/skills/platform-encryption-configure/scripts/validate-encryption-metadata.sh +54 -0
  155. package/skills/platform-flexipage-generate/SKILL.md +281 -346
  156. package/skills/platform-flexipage-generate/references/cli_commands.md +39 -0
  157. package/skills/platform-flexipage-generate/references/flexipage_fieldSection.md +162 -0
  158. package/skills/platform-flexipage-generate/references/flexipage_richText.md +84 -0
  159. package/skills/platform-flexipage-generate/references/identifiers_and_regions.md +167 -0
  160. package/skills/platform-flexipage-generate/references/mcp_action_examples.md +104 -0
  161. package/skills/platform-flexipage-generate/references/record_flexipage_dynamicHighlights.md +119 -0
  162. package/skills/platform-flexipage-generate/references/xml_rules.md +335 -0
  163. package/skills/platform-flexipage-generate/scripts/resolve-component-instructions.sh +42 -0
  164. package/skills/platform-flexipage-generate/scripts/scan-lwc-components.sh +113 -0
  165. package/skills/platform-metadata-api-context-get/SKILL.md +13 -10
  166. package/skills/platform-metadata-deploy/README.md +2 -2
  167. package/skills/platform-metadata-deploy/references/agent-deployment-guide.md +2 -2
  168. package/skills/platform-metadata-deploy/references/deployment-workflows.md +16 -16
  169. package/skills/platform-metadata-deploy/references/orchestration.md +3 -3
  170. package/skills/platform-metadata-deploy/references/trigger-deployment-safety.md +2 -2
  171. package/skills/platform-models-api-configure/SKILL.md +140 -0
  172. package/skills/platform-models-api-configure/scripts/get-orgjwt.sh +48 -0
  173. package/skills/platform-policy-rule-generate/SKILL.md +260 -0
  174. package/skills/platform-policy-rule-generate/references/deploy-errors.md +54 -0
  175. package/skills/platform-policy-rule-generate/references/fixtures-index.md +29 -0
  176. package/skills/platform-policy-rule-generate/references/policy-schema-full.md +250 -0
  177. package/skills/platform-policy-rule-generate/references/templates-access.md +132 -0
  178. package/skills/platform-policy-rule-generate/references/templates-advanced.md +58 -0
  179. package/skills/platform-policy-rule-generate/references/templates-record.md +75 -0
  180. package/skills/platform-policy-rule-generate/references/templates-transform.md +70 -0
  181. package/skills/platform-policy-rule-generate/references/templates.md +10 -0
  182. package/skills/platform-policy-rule-generate/references/ui-compatibility.md +142 -0
  183. package/skills/platform-soql-query/README.md +1 -1
  184. package/skills/platform-soql-query/SKILL.md +1 -1
  185. package/skills/platform-soql-query/references/anti-patterns.md +1 -1
  186. package/skills/platform-soql-query/references/field-coverage-rules.md +1 -1
  187. package/skills/platform-soql-query/references/query-optimization.md +1 -1
  188. package/skills/platform-soql-query/scripts/post-tool-validate.py +3 -3
  189. package/skills/data360-activate/CREDITS.md +0 -5
  190. package/skills/data360-connect/CREDITS.md +0 -5
  191. package/skills/data360-harmonize/CREDITS.md +0 -3
  192. package/skills/data360-orchestrate/CREDITS.md +0 -15
  193. package/skills/data360-orchestrate/UPSTREAM.md +0 -45
  194. package/skills/data360-prepare/CREDITS.md +0 -7
  195. package/skills/data360-query/CREDITS.md +0 -7
  196. package/skills/data360-segment/CREDITS.md +0 -3
  197. package/skills/experience-lwc-generate/CREDITS.md +0 -5
  198. package/skills/external-diagram-mermaid-generate/CREDITS.md +0 -46
  199. package/skills/external-diagram-visual-generate/CREDITS.md +0 -80
  200. package/skills/external-diagram-visual-generate/README.md +0 -83
  201. package/skills/external-diagram-visual-generate/SKILL.md +0 -207
  202. package/skills/external-diagram-visual-generate/assets/architecture/integration-flow.md +0 -55
  203. package/skills/external-diagram-visual-generate/assets/erd/core-objects.md +0 -131
  204. package/skills/external-diagram-visual-generate/assets/erd/custom-objects.md +0 -60
  205. package/skills/external-diagram-visual-generate/assets/lwc/dashboard-card.md +0 -45
  206. package/skills/external-diagram-visual-generate/assets/lwc/data-table.md +0 -57
  207. package/skills/external-diagram-visual-generate/assets/lwc/record-form.md +0 -60
  208. package/skills/external-diagram-visual-generate/assets/review/apex-review.md +0 -57
  209. package/skills/external-diagram-visual-generate/assets/review/lwc-review.md +0 -48
  210. package/skills/external-diagram-visual-generate/references/architect-aesthetic-guide.md +0 -257
  211. package/skills/external-diagram-visual-generate/references/examples-index.md +0 -35
  212. package/skills/external-diagram-visual-generate/references/gemini-cli-setup.md +0 -65
  213. package/skills/external-diagram-visual-generate/references/interview-questions.md +0 -529
  214. package/skills/external-diagram-visual-generate/references/iteration-workflow.md +0 -173
  215. package/skills/external-diagram-visual-generate/scripts/check-prerequisites.sh +0 -101
  216. package/skills/external-diagram-visual-generate/scripts/generate_image.py +0 -243
  217. package/skills/integration-connectivity-connected-app-configure/CREDITS.md +0 -3
  218. package/skills/integration-connectivity-generate/CREDITS.md +0 -5
  219. package/skills/omnistudio-callable-apex-generate/CREDITS.md +0 -9
  220. package/skills/omnistudio-datamapper-generate/CREDITS.md +0 -5
  221. package/skills/omnistudio-datapacks-deploy/CREDITS.md +0 -5
  222. package/skills/omnistudio-dependencies-analyze/CREDITS.md +0 -5
  223. package/skills/omnistudio-epc-catalog-generate/CREDITS.md +0 -14
  224. package/skills/omnistudio-flexcard-generate/CREDITS.md +0 -5
  225. package/skills/omnistudio-integration-procedure-generate/CREDITS.md +0 -5
  226. package/skills/omnistudio-omniscript-generate/CREDITS.md +0 -5
  227. package/skills/platform-apex-generate/CREDITS.md +0 -5
  228. package/skills/platform-apex-logs-debug/CREDITS.md +0 -22
  229. package/skills/platform-apex-test-generate/CREDITS.md +0 -5
  230. package/skills/platform-apex-test-run/CREDITS.md +0 -22
  231. package/skills/platform-data-manage/CREDITS.md +0 -5
  232. package/skills/platform-metadata-deploy/CREDITS.md +0 -25
  233. package/skills/platform-soql-query/CREDITS.md +0 -21
  234. /package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/{MyCustomVlocityOpenInterface2.cls → MyCustomClass.cls} +0 -0
@@ -7,7 +7,7 @@ This document details how platform-data-manage fits into the multi-skill workflo
7
7
 
8
8
  ## Standard Orchestration Order
9
9
 
10
- ```
10
+ ```text
11
11
  ┌─────────────────────────────────────────────────────────────────────────────┐
12
12
  │ STANDARD MULTI-SKILL ORCHESTRATION ORDER │
13
13
  ├─────────────────────────────────────────────────────────────────────────────┤
@@ -35,7 +35,7 @@ This document details how platform-data-manage fits into the multi-skill workflo
35
35
  - Run test factories
36
36
  - Generate bulk test data
37
37
 
38
- ```
38
+ ```text
39
39
  ERROR: "SObject type 'Quote__c' is not supported"
40
40
  CAUSE: Quote__c object was never deployed to the org
41
41
  FIX: Run platform-metadata-deploy BEFORE platform-data-manage
@@ -58,7 +58,7 @@ FIX: Run platform-metadata-deploy BEFORE platform-data-manage
58
58
 
59
59
  When testing triggers or flows, always create test data AFTER deployment:
60
60
 
61
- ```
61
+ ```text
62
62
  1. sf-apex → Create trigger handler class
63
63
  2. sf-flow → Create record-triggered flow
64
64
  3. platform-metadata-deploy → Deploy trigger + flow + objects
@@ -74,7 +74,7 @@ When testing triggers or flows, always create test data AFTER deployment:
74
74
 
75
75
  Always test with **251 records** to cross the 200-record batch boundary:
76
76
 
77
- ```
77
+ ```text
78
78
  ┌─────────────────────────────────────────────────────────────────────────────┐
79
79
  │ BATCH BOUNDARY TESTING │
80
80
  ├─────────────────────────────────────────────────────────────────────────────┤
@@ -129,7 +129,7 @@ sf data query --query "SELECT Id FROM FieldPermissions WHERE SobjectType='MyObje
129
129
 
130
130
  Test Data Factory classes work with platform-data-manage:
131
131
 
132
- ```
132
+ ```text
133
133
  sf-apex: Creates TestDataFactory_Account.cls
134
134
 
135
135
  platform-metadata-deploy: Deploys factory class
@@ -151,7 +151,7 @@ System.debug('Created ' + accounts.size() + ' accounts');
151
151
 
152
152
  After testing, clean up in reverse order:
153
153
 
154
- ```
154
+ ```text
155
155
  1. platform-data-manage → Delete test records
156
156
  2. platform-metadata-deploy → Deactivate flows (if needed)
157
157
  3. platform-metadata-deploy → Remove test metadata (if needed)
@@ -0,0 +1,318 @@
1
+ ---
2
+ name: platform-dataspace-access-configure
3
+ description: "Use this skill to configure Salesforce Data Cloud DataSpace access for permission sets. Grants dataspace-level access via MDAPI PermissionSet XML with dataspaceScopes elements, and optionally grants object-level access to specific DMO, DLO, or CIO objects via the Object Access Grants Connect API. TRIGGER when: user needs to create or update a permission set that includes DataSpace access, grant a permission set access to a specific dataspace, configure dataAccessLevel or objectAccessLevel for a dataspace scope, add RBAC object access grants for Data Cloud objects, or list or remove object access grants for a permission set and DataSpace pair. DO NOT TRIGGER when: the task is a generic permission set without any dataspace access (use platform-permission-set-generate), the request is about data ingestion or streams (use data360-prepare), or the work involves creating dataspaces themselves rather than granting access to them."
4
+ metadata:
5
+ version: "1.0"
6
+ minApiVersion: "67.0"
7
+ cliTools:
8
+ - tool: ["sf"]
9
+ semver: ">=2.0.0"
10
+ - tool: ["jq"]
11
+ semver: ">=1.6"
12
+ ---
13
+
14
+ # platform-dataspace-access-configure
15
+
16
+ Configure DataSpace access in Salesforce Data Cloud using a two-layer model:
17
+
18
+ 1. **DataSpace-level access** — grant a `PermissionSet` access to a DataSpace by embedding a `<dataspaceScopes>` element in the permission set XML and deploying via MDAPI.
19
+ 2. **Object-level access (optional)** — grant that permission set access to specific DMO / DLO / CIO objects within the DataSpace using the Object Access Grants Connect API.
20
+
21
+ The MDAPI layer is required to establish the PermissionSet → DataSpace linkage. The Connect API layer is optional and only needed when access should be scoped to specific objects rather than governed entirely by data governance policies.
22
+
23
+ ---
24
+
25
+ ## Decide the Case First
26
+
27
+ Pick exactly one case from the table below before writing any files. Each case has a different output shape.
28
+
29
+ | Case | User intent | Permission set state | Files to emit |
30
+ |---|---|---|---|
31
+ | **A. Create new permset with DS access** | "create a permission set called X with dataspace scope Y" | does NOT exist yet | `permissionsets/<Name>.permissionset-meta.xml` **and** `package.xml` |
32
+ | **B. Add DS access to existing permset** | "grant existing permission set X access to dataspace Y" | already deployed (may contain other permissions) | patched `permissionsets/<Name>.permissionset-meta.xml` **and** `package.xml` — see Case B workflow below |
33
+ | **C. Object-level grant only** | "grant permset X access to object Z (in dataspace Y)" — permset + scope already configured | already deployed with `dataspaceScopes` | `api-request.json` (Connect API body). NO permission set XML, NO `package.xml` |
34
+
35
+ Only emit the files listed for the case you picked. Emitting Case A/B files for a Case C prompt (or vice versa) is a correctness failure — extra files change the deployment shape.
36
+
37
+ > **Case B — critical:** PermissionSet MDAPI deploy is a **full metadata replace**. Every `<objectPermissions>`, `<fieldPermissions>`, `<userPermissions>`, `<tabSettings>`, `<applicationVisibilities>`, `<recordTypeVisibilities>`, `<customPermissions>`, `<pageAccesses>`, `<classAccesses>`, `<customMetadataTypeAccesses>`, `<customSettingAccesses>`, `<externalDataSourceAccesses>` element you omit from the redeploy is **deleted from the org**. Before adding `<dataspaceScopes>` to an existing permset, retrieve the current XML and patch it — do not hand-author from scratch.
38
+
39
+ ### Case B workflow
40
+
41
+ 1. Retrieve the existing permission set:
42
+ ```bash
43
+ sf project retrieve start --metadata PermissionSet:<Name> --target-org <alias>
44
+ ```
45
+ 2. Open the retrieved `permissionsets/<Name>.permissionset-meta.xml`. Keep every element already there.
46
+ 3. Insert the `<dataspaceScopes>` block for the target DataSpace (element order in the file does not matter for MDAPI). If the file already has a `<dataspaceScopes>` block **for this same DataSpace**, replace only that block. Leave every `<dataspaceScopes>` block for other DataSpaces untouched — one block per DataSpace, and removing a block revokes that DataSpace grant.
47
+ 4. Write `package.xml` listing the permset in `<members>`.
48
+ 5. Redeploy with `sf project deploy start`.
49
+
50
+ ---
51
+
52
+ ## When This Skill Owns the Task
53
+
54
+ Trigger this skill when the user wants to:
55
+ - Create a permission set that grants access to a Data Cloud DataSpace
56
+ - Add or modify `dataspaceScopes` on an existing permission set
57
+ - Grant a permission set access to specific DMO / DLO / CIO objects in a DataSpace
58
+ - Configure `dataAccessLevel` and `objectAccessLevel` for a DataSpace scope
59
+ - List or remove object access grants for a permission set + DataSpace pair
60
+
61
+ Delegate elsewhere when:
62
+ - The permission set has no DataSpace access at all → `platform-permission-set-generate`
63
+ - The task is creating the DataSpace itself → `data360-orchestrate`
64
+ - The task is ingesting data or configuring streams → `data360-prepare`
65
+
66
+ ---
67
+
68
+ ## Layer 1 — DataSpace-Level Access (MDAPI)
69
+
70
+ Embed a `<dataspaceScopes>` element inside the `PermissionSet` XML. Deploy with MDAPI.
71
+
72
+ ```xml
73
+ <?xml version="1.0" encoding="UTF-8"?>
74
+ <PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
75
+ <label>Data Cloud Analyst</label>
76
+ <description>Data cloud analyst access to the default dataspace</description>
77
+ <hasActivationRequired>false</hasActivationRequired>
78
+ <dataspaceScopes>
79
+ <dataspaceScope>default</dataspaceScope>
80
+ <dataAccessLevel>ALL</dataAccessLevel>
81
+ <objectAccessLevel>BY_POLICY</objectAccessLevel>
82
+ </dataspaceScopes>
83
+ </PermissionSet>
84
+ ```
85
+
86
+ ### Element Rules
87
+
88
+ | Element | Required | Valid Values | Purpose |
89
+ |---|---|---|---|
90
+ | `<dataspaceScopes>` | yes | parent element (plural) | Container for a single dataspace scope grant |
91
+ | `<dataspaceScope>` | yes | DataSpace API name (e.g. `default`) | Which DataSpace this grant is for |
92
+ | `<dataAccessLevel>` | yes | `NONE`, `CONTROLLED_BY_PARENT`, `ALL` | Row-level data access within the DataSpace |
93
+ | `<objectAccessLevel>` | yes | `BY_POLICY`, `ALL_IN_DATASPACE` | Object-level access. `BY_POLICY` defers to data governance policies. `ALL_IN_DATASPACE` is only allowed when `dataAccessLevel` is `CONTROLLED_BY_PARENT` |
94
+
95
+ ### Common Mistakes
96
+
97
+ - **Wrong parent name** — using `<dataspaceScopeAccess>` instead of `<dataspaceScopes>`. Deployment fails silently or with cryptic errors.
98
+ - **Wrong child name** — using `<dataspaceScopeName>` instead of `<dataspaceScope>`.
99
+ - **Wrong enum values** — `ViewAllRows` / `Read` / `OWNER` / `EDIT` are not valid. Use `NONE`, `CONTROLLED_BY_PARENT`, or `ALL` for `dataAccessLevel`; use `BY_POLICY` or `ALL_IN_DATASPACE` for `objectAccessLevel`. See Element Rules table for allowed combinations. Deployment error `-379999659` means invalid enum.
100
+ - **Multiple scopes in one element** — `<dataspaceScopes>` grants access to exactly one DataSpace. To grant access to multiple, add multiple `<dataspaceScopes>` blocks.
101
+
102
+ ### Package Layout (Case A and Case B)
103
+
104
+ A deployable bundle for Layer 1 always contains **both** files:
105
+
106
+ ```text
107
+ <output-root>/
108
+ package.xml
109
+ permissionsets/<Name>.permissionset-meta.xml
110
+ ```
111
+
112
+ `package.xml` (required — list every permission set being deployed in `<members>`):
113
+
114
+ ```xml
115
+ <?xml version="1.0" encoding="UTF-8"?>
116
+ <Package xmlns="http://soap.sforce.com/2006/04/metadata">
117
+ <types>
118
+ <members>Data_Cloud_Analyst</members>
119
+ <name>PermissionSet</name>
120
+ </types>
121
+ <version>67.0</version>
122
+ </Package>
123
+ ```
124
+
125
+ Deploy:
126
+
127
+ ```bash
128
+ sf project deploy start --source-dir force-app/main/default/permissionsets/ --target-org <alias>
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Layer 2 — Object-Level Access (Connect API) — Case C
134
+
135
+ Only needed when `objectAccessLevel` is not `BY_POLICY`, or when governance policies do not cover the target objects. Grants are runtime — **no MDAPI deploy, no `package.xml`, no permission set XML**. The only artifact for a Case C task is a single `api-request.json` describing the Connect API call.
136
+
137
+ ### Resolve the API version first
138
+
139
+ Every Connect API `endpoint` in this layer contains an `/services/data/v<apiVersion>/…` segment. **Do not hardcode `v67.0`.** Resolve the target org's actual API version before writing the envelope so the request matches the org's supported surface:
140
+
141
+ ```bash
142
+ sf org display --target-org <alias> --json | jq -r '.result.apiVersion'
143
+ ```
144
+
145
+ - Substitute the returned value (e.g. `67.0`, `68.0`) into the `endpoint` as `v<apiVersion>`.
146
+ - If the org can't be queried (offline authoring, no alias yet), fall back to the `minApiVersion` from this skill's frontmatter (`67.0`) — the endpoint was introduced there and any newer version accepts the same body.
147
+ - If the user explicitly specifies a version in the prompt, use that verbatim.
148
+
149
+ In the templates below, `{apiVersion}` is a placeholder. Replace it with the resolved API version (e.g., `67.0`, `68.0`) before emitting `api-request.json`.
150
+
151
+ ### `api-request.json` — canonical shape
152
+
153
+ Emit the request as a self-describing envelope with `method`, `endpoint`, `headers`, `body`, and `expectedResponse`. Do NOT emit only the body — reviewers and downstream tooling read the envelope.
154
+
155
+ ```json
156
+ {
157
+ "method": "POST",
158
+ "endpoint": "/services/data/v{apiVersion}/ssot/data-governance/object-access-grants",
159
+ "headers": {
160
+ "Content-Type": "application/json"
161
+ },
162
+ "body": {
163
+ "permissionSetName": "Data_Cloud_Analyst",
164
+ "dataSpaceName": "default",
165
+ "objectApiName": "Account__dlm"
166
+ },
167
+ "expectedResponse": {
168
+ "status": 201,
169
+ "body": {
170
+ "permissionSetName": "Data_Cloud_Analyst",
171
+ "dataSpaceName": "default",
172
+ "objectApiName": "Account__dlm"
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ ### Bulk Grant
179
+
180
+ Same `api-request.json` envelope shape. `endpoint` gains the `/actions/bulk-create` suffix, `body.objectApiName` is replaced by the list-valued `body.objectApiNames`, and `expectedResponse` omits the `body` field because bulk responses return per-object status entries rather than the flat request payload (see Gotchas below).
181
+
182
+ ```json
183
+ {
184
+ "method": "POST",
185
+ "endpoint": "/services/data/v{apiVersion}/ssot/data-governance/object-access-grants/actions/bulk-create",
186
+ "headers": {
187
+ "Content-Type": "application/json"
188
+ },
189
+ "body": {
190
+ "permissionSetName": "Data_Cloud_Analyst",
191
+ "dataSpaceName": "default",
192
+ "objectApiNames": ["Account__dlm", "Contact__dlm", "Opportunity__dlm"]
193
+ },
194
+ "expectedResponse": {
195
+ "status": 201
196
+ }
197
+ }
198
+ ```
199
+
200
+ ### List Grants
201
+
202
+ Same envelope shape with `method: "GET"`, query parameters on the `endpoint`, and no `body`.
203
+
204
+ ```json
205
+ {
206
+ "method": "GET",
207
+ "endpoint": "/services/data/v{apiVersion}/ssot/data-governance/object-access-grants?permissionSetName=Data_Cloud_Analyst&dataSpaceName=default",
208
+ "headers": {
209
+ "Accept": "application/json"
210
+ },
211
+ "expectedResponse": {
212
+ "status": 200
213
+ }
214
+ }
215
+ ```
216
+
217
+ ### Revoke Grant
218
+
219
+ Same envelope shape with `method: "DELETE"`, the object API name as a path segment, and `expectedResponse.status: 204` (No Content).
220
+
221
+ ```json
222
+ {
223
+ "method": "DELETE",
224
+ "endpoint": "/services/data/v{apiVersion}/ssot/data-governance/object-access-grants/Account__dlm?permissionSetName=Data_Cloud_Analyst&dataSpaceName=default",
225
+ "headers": {
226
+ "Accept": "application/json"
227
+ },
228
+ "expectedResponse": {
229
+ "status": 204
230
+ }
231
+ }
232
+ ```
233
+
234
+ ### Object Types
235
+
236
+ - **DMO** (Data Model Object) — unified profile objects, suffix `__dlm`
237
+ - **DLO** (Data Lake Object) — raw ingested data, suffix `__dll`
238
+ - **CIO** (Calculated Insight Object) — computed metrics, suffix `__cio`
239
+
240
+ ---
241
+
242
+ ## Combined Setup — Case A + Case C from a Cold Start
243
+
244
+ Use this section ONLY when the user is starting from nothing and asks for both the permset+scope AND per-object grants in a single request. If the user's prompt is only about the Connect API grant (Case C) — for example "grant Account__dlm access; the permset and dataspace scope already exist" — SKIP this section entirely and emit only `api-request.json` from Layer 2.
245
+
246
+ The commands below are operator-facing `sf` CLI invocations (a runnable cold-start walkthrough), NOT the artifact you emit. For a normal Case C task the artifact is a single `api-request.json` envelope as documented in Layer 2 above.
247
+
248
+ **Goal:** Grant `Data_Cloud_Analyst` permission set access to `Account__dlm` and `Contact__dlm` in the `default` DataSpace.
249
+
250
+ **Step 1 — Deploy PermissionSet with DataSpace scope (MDAPI):**
251
+
252
+ ```xml
253
+ <PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
254
+ <label>Data Cloud Analyst</label>
255
+ <description>Data cloud analyst access to the default dataspace</description>
256
+ <hasActivationRequired>false</hasActivationRequired>
257
+ <dataspaceScopes>
258
+ <dataspaceScope>default</dataspaceScope>
259
+ <dataAccessLevel>ALL</dataAccessLevel>
260
+ <objectAccessLevel>BY_POLICY</objectAccessLevel>
261
+ </dataspaceScopes>
262
+ </PermissionSet>
263
+ ```
264
+
265
+ ```bash
266
+ sf project deploy start --source-dir permissionsets/ --target-org <alias>
267
+ ```
268
+
269
+ **Step 2 — Grant object access (Connect API):**
270
+ *(Required here because the `default` DataSpace has no governance policies covering `Account__dlm` and `Contact__dlm`. Skip Step 2 when `BY_POLICY` policies already govern the target objects — Layer 1 alone is sufficient.)*
271
+
272
+ Resolve the org's API version first (see [Resolve the API version first](#resolve-the-api-version-first) above), then substitute it into the `--path` value:
273
+
274
+ ```bash
275
+ API_VERSION=$(sf org display --target-org <alias> --json | jq -r '.result.apiVersion')
276
+
277
+ sf org api rest --target-org <alias> \
278
+ --method POST \
279
+ --path "/services/data/v${API_VERSION}/ssot/data-governance/object-access-grants/actions/bulk-create" \
280
+ --body '{
281
+ "permissionSetName": "Data_Cloud_Analyst",
282
+ "dataSpaceName": "default",
283
+ "objectApiNames": ["Account__dlm", "Contact__dlm"]
284
+ }'
285
+ ```
286
+
287
+ **Step 3 — Verify:**
288
+
289
+ ```bash
290
+ sf org api rest --target-org <alias> \
291
+ --path "/services/data/v${API_VERSION}/ssot/data-governance/object-access-grants?permissionSetName=Data_Cloud_Analyst&dataSpaceName=default"
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Rules and Constraints
297
+
298
+ | Rule | Reason |
299
+ |---|---|
300
+ | Use `<dataspaceScopes>` (plural) as parent, `<dataspaceScope>` (singular) as child | XML schema requirement; other names deploy-fail |
301
+ | `dataAccessLevel` values: `NONE`, `CONTROLLED_BY_PARENT`, `ALL` only | Other values (e.g. `OWNER`, `ViewAllRows`) are rejected |
302
+ | `objectAccessLevel` values: `BY_POLICY`, `ALL_IN_DATASPACE` only | Other values (e.g. `READ`, `EDIT`, `Read`) are rejected. `ALL_IN_DATASPACE` requires `dataAccessLevel=CONTROLLED_BY_PARENT` |
303
+ | Prefer `BY_POLICY` when data governance policies exist | Delegates row/column filtering to central policy — no per-object grants needed |
304
+ | One `<dataspaceScopes>` block per DataSpace | Repeat the block for multiple DataSpaces on the same permission set |
305
+ | Org must have Data Cloud provisioned to deploy `<dataspaceScopes>` | On non-Data-Cloud orgs, the element is ignored or rejected |
306
+ | Do not query `DataspaceScope` / `DataspaceScopeAccess` via SOQL | Not queryable; use MDAPI retrieve to inspect existing grants |
307
+
308
+ ---
309
+
310
+ ## Gotchas
311
+
312
+ | Issue | Resolution |
313
+ |---|---|
314
+ | Deployment fails with error `-379999659` | Check enum values — `dataAccessLevel` must be `NONE`/`CONTROLLED_BY_PARENT`/`ALL`; `objectAccessLevel` must be `BY_POLICY`/`ALL_IN_DATASPACE` |
315
+ | Permission set deploys but users still can't query DataSpace data | Layer 2 not applied — objects need explicit grants if `objectAccessLevel != BY_POLICY` |
316
+ | Bulk-create returns `AlreadyExists` for some objects | Idempotent — safe to retry; response shows per-object status |
317
+ | Connect API returns 404 for object grants endpoint | Org lacks Data Cloud provisioning, or the resolved API version is below the minimum. The endpoint was introduced in `v67.0` — re-run `sf org display --json` to confirm the org's `apiVersion` field is `67.0` or later, and substitute that value into the `endpoint` path |
318
+ | Retrieved PermissionSet XML shows different element names than deployed | Metadata API sometimes echoes legacy names on retrieve — always author with current names |
@@ -3,6 +3,10 @@ name: platform-docs-get
3
3
  description: "Official Salesforce documentation retrieval skill. Use when you need authoritative Salesforce docs from developer.salesforce.com, help.salesforce.com, architect.salesforce.com, admin.salesforce.com, or lightningdesignsystem.com, especially when pages are JS-heavy, shell-rendered, or hard to extract with naive fetching. Use to ground answers in official Salesforce sources instead of third-party blogs or summaries. TRIGGER when: user asks for official Salesforce documentation, Apex or API reference, LWC docs, Agentforce docs, setup or help articles, or any doc from a Salesforce-owned domain. DO NOT TRIGGER when: user is asking for a code change, deployment task, or anything not requiring documentation retrieval — use the appropriate sf-* skill instead."
4
4
  metadata:
5
5
  version: "1.1"
6
+ relatedSkills: ["platform-soql-query"]
7
+ cliTools:
8
+ - tool: ["python3"]
9
+ semver: ">=3.8.0"
6
10
  ---
7
11
 
8
12
  # platform-docs-get
@@ -153,27 +153,53 @@ def extract_official_salesforce_doc(url: str, timeout_seconds: int, use_stealth:
153
153
  http_status = response.status if response else None
154
154
  page.wait_for_timeout(1500)
155
155
  try:
156
- page.wait_for_function(
157
- r"""
156
+ page.wait_for_load_state("networkidle", timeout=min(timeout_ms, 15000))
157
+ except PlaywrightTimeoutError:
158
+ pass
159
+
160
+ # Wait for content: check both light DOM and shadow DOM content
161
+ is_developer = "developer.salesforce.com" in host
162
+ wait_js = r"""
158
163
  () => {
164
+ // Light DOM check (works for most official sites)
159
165
  const el = document.querySelector('main, article, [role="main"]');
160
- const text = (el?.innerText || el?.textContent || '').trim();
161
- return text.length > 200;
166
+ const lightText = (el?.innerText || el?.textContent || '').trim();
167
+ if (lightText.length > 200) return true;
168
+
169
+ // Shadow DOM check (needed for developer.salesforce.com)
170
+ function findDeepText(root, depth) {
171
+ if (depth > 5 || !root) return '';
172
+ let best = '';
173
+ const els = root.querySelectorAll ? root.querySelectorAll('*') : [];
174
+ for (const child of els) {
175
+ if (child.shadowRoot) {
176
+ // Check direct children of shadow root for text
177
+ for (const sc of child.shadowRoot.children) {
178
+ const t = (sc.innerText || '').trim();
179
+ if (t.length > best.length) best = t;
180
+ }
181
+ const deeper = findDeepText(child.shadowRoot, depth + 1);
182
+ if (deeper.length > best.length) best = deeper;
183
+ }
184
+ }
185
+ return best;
186
+ }
187
+ const shadowText = findDeepText(document, 0);
188
+ return shadowText.length > 200;
162
189
  }
163
- """,
164
- timeout=min(timeout_ms, 15000),
165
- )
166
- except PlaywrightTimeoutError:
167
- pass
190
+ """
168
191
  try:
169
- page.wait_for_load_state("networkidle", timeout=min(timeout_ms, 15000))
192
+ page.wait_for_function(
193
+ wait_js,
194
+ timeout=min(timeout_ms, 20000 if is_developer else 15000),
195
+ )
170
196
  except PlaywrightTimeoutError:
171
197
  pass
172
198
  page.wait_for_timeout(500)
173
199
 
174
200
  payload = page.evaluate(
175
201
  r"""
176
- () => {
202
+ (host) => {
177
203
  function normalize(text) {
178
204
  return String(text || '')
179
205
  .replace(/\u00a0/g, ' ')
@@ -233,6 +259,14 @@ def extract_official_salesforce_doc(url: str, timeout_seconds: int, use_stealth:
233
259
  return Array.from(urls);
234
260
  }
235
261
 
262
+ // --- Noise removal: strip cookie/consent overlays before scoring ---
263
+ document.querySelectorAll(
264
+ '#onetrust-banner-sdk, #onetrust-consent-sdk, .onetrust-consent-sdk, ' +
265
+ '[class*="onetrust-pc"], #onetrust-pc-sdk, ' +
266
+ '[id*="cookie-consent"], [class*="cookie-banner"], ' +
267
+ '.evidon-consent-button, #evidon-banner'
268
+ ).forEach(function(el) { el.remove(); });
269
+
236
270
  const title = document.title || normalize(document.querySelector('title')?.innerText || 'Untitled');
237
271
  const childLinks = new Set();
238
272
  for (const root of allRoots()) {
@@ -258,12 +292,42 @@ def extract_official_salesforce_doc(url: str, timeout_seconds: int, use_stealth:
258
292
  { selector: 'main .content, article .content', strategy: 'nested-content', base: 140 },
259
293
  ];
260
294
 
295
+ // --- Host-aware selector overrides for developer.salesforce.com ---
296
+ if (host.includes('developer.salesforce.com')) {
297
+ selectorConfigs.unshift(
298
+ { selector: 'doc-content', strategy: 'dev-doc-content', base: 295 },
299
+ { selector: '#maincontent', strategy: 'dev-maincontent', base: 290 },
300
+ { selector: '.doc-body', strategy: 'dev-doc-body', base: 285 },
301
+ { selector: '#topic-content', strategy: 'dev-topic-content', base: 285 },
302
+ { selector: '.topicContent', strategy: 'dev-topic', base: 280 },
303
+ { selector: '[class*="docContent"]', strategy: 'dev-doc-content-class', base: 275 },
304
+ { selector: 'doc-xml-content .content', strategy: 'dev-xml-content', base: 270 },
305
+ );
306
+ }
307
+
308
+ // Extract text from an element, including shadow root content
309
+ function extractText(el) {
310
+ let text = (el.innerText || el.textContent || '').trim();
311
+ // If element is a shadow host with no slotted light DOM text,
312
+ // gather text from its shadow root's children
313
+ if (text.length < 200 && el.shadowRoot) {
314
+ let shadowText = '';
315
+ for (const child of el.shadowRoot.children) {
316
+ shadowText += (child.innerText || child.textContent || '') + '\n';
317
+ }
318
+ if (shadowText.trim().length > text.length) {
319
+ text = shadowText.trim();
320
+ }
321
+ }
322
+ return text;
323
+ }
324
+
261
325
  const candidates = [];
262
326
  for (const cfg of selectorConfigs) {
263
327
  const nodes = deepQueryAll(cfg.selector);
264
328
  for (const node of nodes) {
265
329
  if (!isVisible(node)) continue;
266
- const text = normalize(node.innerText || node.textContent || '');
330
+ const text = normalize(extractText(node));
267
331
  if (text.length < 200) continue;
268
332
  let score = cfg.base + Math.min(text.length, 5000) / 30;
269
333
  const lowered = text.toLowerCase();
@@ -306,7 +370,8 @@ def extract_official_salesforce_doc(url: str, timeout_seconds: int, use_stealth:
306
370
  candidateCount: candidates.length,
307
371
  };
308
372
  }
309
- """
373
+ """,
374
+ host,
310
375
  )
311
376
 
312
377
  text = normalize_text(payload.get("text", ""))
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: platform-encryption-configure
3
+ description: "Configure Salesforce Shield Platform Encryption — generate deployable encryption settings and encrypted-field metadata, and answer key-model and lifecycle questions. TRIGGER when: user wants to turn on deterministic encryption, encrypt a field, set up Cache-Only Keys, External Key Management, or replay detection, or mentions Shield Platform Encryption, encryption at rest, deterministic vs probabilistic encryption, encryptionScheme, PlatformEncryptionSettings, EncryptionKeySettings, BYOK, BYOKMS, tenant secrets, key rotation, or .settings-meta.xml / .field-meta.xml for encryption — even when they don't say 'Shield'. SKIP when: user needs a generic custom field with no encryption (use platform-custom-field-generate), needs the raw Metadata API type reference (use platform-metadata-api-context-get), or asks about Classic Encryption (encrypted text fields), which is a different feature. Use this skill for any Platform Encryption configuration, field-encryption, or key-model question."
4
+ metadata:
5
+ version: "1.0"
6
+ minApiVersion: "62.0"
7
+ relatedSkills:
8
+ - "platform-custom-field-generate"
9
+ - "platform-metadata-api-context-get"
10
+ ---
11
+
12
+ # Configure Platform Encryption
13
+
14
+ Configures Salesforce Shield Platform Encryption by generating the metadata that turns it on and choosing the right settings: which encryption scheme a field should use, which key-management model fits a requirement, and how the tenant-secret lifecycle works. This is a **hybrid** skill — it emits deployable `*.settings-meta.xml` / `*.field-meta.xml` where Platform Encryption exposes a real Metadata API surface, and returns grounded guidance where the operation is UI/REST-only.
15
+
16
+ ## Scope
17
+
18
+ - **In scope**: choosing and applying `encryptionScheme` on a field; enabling deterministic encryption, Cache-Only Keys, External Key Management, and replay detection via `PlatformEncryptionSettings` / `EncryptionKeySettings`; explaining BYOK / BYOKMS / EKM / Cache-Only key models; tenant-secret rotation and destruction semantics; the query behavior of encrypted fields.
19
+ - **Out of scope**: a plain custom field with no encryption (use `platform-custom-field-generate`); the raw Metadata API field reference (use `platform-metadata-api-context-get`); Classic Encryption (`EncryptedText` fields) — that is a separate, legacy feature; deploying/pushing metadata to an org (that belongs to a deploy lifecycle skill).
20
+
21
+ ---
22
+
23
+ ## Required Inputs
24
+
25
+ Gather or infer before proceeding:
26
+
27
+ - **Question type**: is the user asking for a *deployable artifact* (a settings file, an encrypted field) or *guidance* (which model, what happens when I rotate a key)? Deployable → generate XML from `assets/`. Guidance → answer from `references/`. **A question is guidance whenever the ask is to explain, confirm, or compare** — "is that right?", "what's the relationship?", "can we…?", "is there an ordering requirement?", **"explain the difference between X and Y", "which key model should we use?"** — **even if the user also says they are about to write, deploy, or author settings themselves.** The user writing settings is *their* action; it does not make the skill's deliverable a file. Only an explicit "generate / create / give me the file / here is my field, encrypt it" is an artifact request.
28
+ - **Key-model choice questions are guidance, not deployable metadata.** "Explain BYOK vs external key management / BYOKMS / EKM / Cache-Only", "which one keeps key material out of Salesforce?", "should we use BYOK or EKM?" → answer them in a **single markdown answer file** (the guidance write-up), not a deployable `*.settings-meta.xml`. **Naming the enabling setting in that answer (e.g. `canExternalKeyManagement`, `enableCacheOnlyKeys`) does NOT turn it into a settings artifact** — cite the field name inline in the answer file; do **not** emit an `EncryptionKey.settings-meta.xml` unless the user explicitly says "generate/create the settings file."
29
+ - **Field encryption target** (for field work): the object and field API name, and whether the user needs to *filter, sort, or group* on the field (drives deterministic vs probabilistic).
30
+ - **Key model** (for key work): whether keys are Salesforce-derived (default), customer-supplied (BYOK), stored in an external KMS (BYOKMS/EKM), or fetched on demand (Cache-Only).
31
+
32
+ If the request is clear, generate or answer immediately — do not interrogate the user.
33
+
34
+ ---
35
+
36
+ ## Workflow
37
+
38
+ 1. **Classify the request** — deployable artifact vs guidance, using the Required Inputs above. Then **scope the output to exactly what was asked**:
39
+ - A **guidance** question produces **exactly one markdown answer file** — a single file (e.g. `answer.md`) containing the full written diagnosis/explanation — and **nothing else**. Do not also emit a `*.settings-meta.xml`, a `*.field-meta.xml`, or a second helper doc. This covers every "what happens when…?", "how do I…?", "which model…?", "is X right…?", "can we…?", "what's the relationship / ordering…?" question, including query-behavior and Cache-Only/replay questions. **A clause like "before I write our settings" or "before I author the file" describes the *user's* next step and does NOT turn the question into a deployable-metadata request — write the answer file, not a settings file.**
40
+ - **Naming a metadata change in a guidance answer does NOT mean emitting the deployable file for it.** A remediation or diagnosis question — *"how do I make the field queryable?"*, *"why did my query fail and how do I fix it?"*, *"which key model keeps material out of Salesforce?"* — is answered **inside the one markdown answer file**, naming the relevant element/scheme inline (e.g. "switch to a `Deterministic*` scheme and enable `enableDeterministicEncryption`", or "use External Key Management — `canExternalKeyManagement`"). Do **not** additionally materialize a `*.field-meta.xml` or `*.settings-meta.xml` to *demonstrate* that change — mentioning the element in the answer is the complete deliverable. Produce a deployable metadata file **only** when the user explicitly says generate/create/give me the field or settings file.
41
+ - An **artifact** request gets **only** the specific metadata file(s) named — do not add a `DEPLOYMENT_GUIDE.md`, `README.md`, an `EXPLANATION.md`, an org-`settings` file, or any companion artifact the user did not ask for.
42
+ - If a deploy step or org setting is a prerequisite, state it **inside the one answer file** (for guidance) or **in a code comment inside the one artifact** (for an artifact request) — never as an extra file.
43
+
44
+ 2. **For field encryption** — read `references/encryption-schemes.md` to choose the scheme, then load `assets/encrypted-field.field-meta.xml` as the starting template. Set `encryptionScheme` to exactly one of the four valid enum values (see the reference). Only `Deterministic*` schemes are filterable.
45
+
46
+ > **Write the field file at the SFDX source path, not the root.** A `*.field-meta.xml` **must** live at `objects/<ObjectApiName>/fields/<FieldApiName>__c.field-meta.xml` (e.g. `objects/Patient__c/fields/Diagnosis_Notes__c.field-meta.xml`) — the object folder uses the object's API name (`Patient__c` for a custom object, `Contact` for a standard one) and the file is named after the field API name. Emitting the file at the repo root, in a flat directory, or under any other folder is a structural miss even when the XML itself is correct.
47
+
48
+ 3. **For org-level encryption settings** — load `assets/PlatformEncryption.settings-meta.xml` (deterministic encryption, field-history encryption, MEK permission) or `assets/EncryptionKey.settings-meta.xml` (Cache-Only, EKM, Data 360, transactional DB, replay detection). Read `references/key-models.md` before setting any key-model field.
49
+
50
+ > **Name the output file after the Settings *member*, not the root element, and write it under `settings/`.** A `Settings` file must be `settings/<member>.settings-meta.xml`, where `<member>` is the org's metadata member name — **`EncryptionKey`** (root `<EncryptionKeySettings>`) and **`PlatformEncryption`** (root `<PlatformEncryptionSettings>`). Put it in the `settings/` source folder (e.g. `settings/EncryptionKey.settings-meta.xml`), not the repo root. Naming the key-settings file `Encryption.settings-meta.xml` or `EncryptionKeySettings.settings-meta.xml` fails deployment with *"The object '…' of type Settings metadata does not exist."*
51
+
52
+ > **Cache-Only Keys and replay detection are a one-way dependency, not an auto-enable.** You may set `enableReplayDetection` only after `enableCacheOnlyKeys` is `true`; enabling Cache-Only does **not** turn replay detection on by itself. An org can validly run Cache-Only with replay detection off.
53
+
54
+ 4. **For tenant-secret operations** (rotate, destroy, BYOK upload, Cache-Only callout setup) — read `references/tenant-secret-lifecycle.md`. These are UI/REST-only; capture the guidance in the single markdown answer file, not a deployable metadata file.
55
+
56
+ 5. **Validate any generated settings XML** — run `scripts/validate-encryption-metadata.sh` with the file path as its argument, and fix anything it reports. It checks the replay-detection dependency and the `encryptionScheme` enum deterministically.
57
+
58
+ 6. **Compare against the worked example** — verify a generated `EncryptionKeySettings` file against `examples/cache-only-keys.settings-meta.xml`.
59
+
60
+ ---
61
+
62
+ ## Rules / Constraints
63
+
64
+ | Constraint | Rationale |
65
+ |-----------|-----------|
66
+ | `encryptionScheme` must be exactly one of `CaseInsensitiveDeterministicEncryption`, `CaseSensitiveDeterministicEncryption`, `None`, `ProbabilisticEncryption` | These are the only values the Metadata API accepts (`CustomField`, API 44.0+); any other string fails deployment. |
67
+ | Set `enableReplayDetection` only when `enableCacheOnlyKeys` is `true` | The contract is *"Requires enableCacheOnlyKeys=true before setting enableReplayDetection to true"* — a one-way dependency. |
68
+ | Use deterministic schemes only when the field must be filtered, sorted, or grouped | Probabilistic is stronger but non-filterable; deterministic trades some cryptographic strength for queryability. |
69
+ | Never claim a filter/sort/group on a probabilistically-encrypted field silently returns zero rows | The platform **rejects** the query with `INVALID_FIELD` (see gotchas); telling the user it "returns nothing" is factually wrong. |
70
+ | Do not emit `enableExternalKeyManagement` — the field is `canExternalKeyManagement` | The WSDL element is `canExternalKeyManagement`; the sample in some docs uses a non-existent element name. |
71
+ | Transactional-DB, EKM, and Data 360 key fields require API 63.0+ | `canEncryptTransactionalDatabase`, `canExternalKeyManagement`, `canManageDataCloudKeys` were introduced in 63.0. |
72
+ | A **guidance** question produces **exactly one markdown answer file** — never a deployable `*.settings-meta.xml` / `*.field-meta.xml`, and never a second doc | The answer file is the user's reference document — it persists in the workspace and can be shared or revised. Emitting a deployable metadata file for a guidance question is unsolicited configuration that could be accidentally applied; emitting no file leaves the user without a tangible deliverable. |
73
+ | An **artifact** request emits **only** the metadata file(s) asked for — no companion files | Adding a `DEPLOYMENT_GUIDE.md`/`README.md`/`EXPLANATION.md` or an extra `settings` file the user didn't request is noise. Prerequisites belong in a code comment inside the artifact, not a second file. |
74
+
75
+ ---
76
+
77
+ ## Gotchas
78
+
79
+ | Issue | Resolution |
80
+ |-------|------------|
81
+ | Filtering/sorting/grouping on a probabilistically-encrypted field | The query is rejected with `INVALID_FIELD`: *"field '<Name>' can not be sorted / filtered / grouped in a query call."* Switch the field to a deterministic scheme if queryability is required. |
82
+ | Assuming Cache-Only Keys auto-enables replay detection | It does not. Set `enableReplayDetection` explicitly, and only after `enableCacheOnlyKeys=true`. |
83
+ | Case sensitivity in deterministic matching | `CaseSensitiveDeterministicEncryption` matches exact case; `CaseInsensitiveDeterministicEncryption` normalizes case. Choosing wrong silently breaks equality filters. |
84
+ | Confusing BYOK with BYOKMS/EKM | BYOK = you upload key material Salesforce stores; BYOKMS/EKM = key material stays in your external KMS. See `references/key-models.md`. |
85
+ | Using `enableExternalKeyManagement` element name | Wrong element. The field is `canExternalKeyManagement`. |
86
+ | Classic Encryption vs Shield | `encryptionScheme` is Shield only. `EncryptedText` custom fields are the legacy Classic feature and out of scope. |
87
+
88
+ ---
89
+
90
+ ## Output Expectations
91
+
92
+ Deliverables depend on the request — produce **exactly** these and nothing more:
93
+
94
+ - **Guidance questions produce exactly ONE markdown answer file.** Any "what happens when…", "how do I…", "which model…", "is X right…" question — including encrypted-field query behavior, Cache-Only/replay-detection relationships, tenant-secret / BYOK / Cache-Only lifecycle, and key-model choices — is answered by writing a single markdown file (e.g. `answer.md`) that fully captures the diagnosis/explanation. Do **not** additionally emit a deployable `*.settings-meta.xml` / `*.field-meta.xml` or a second doc, and do **not** answer with no file at all — the answer file is the user's persistent reference document.
95
+ - **Field encryption artifact**: **only** the `*.field-meta.xml` with `encryptionScheme` set, written at `objects/<ObjectApiName>/fields/<FieldApiName>__c.field-meta.xml`. Not a settings file, not a deploy guide. Pick `<type>` to match the request: **`Text`** for a string field up to **255** chars; **`LongTextArea`** only when the field must exceed 255 chars (256+). "Long text … up to 255 characters" is a `Text` field, not `LongTextArea`. Strip the template's instructional comment block from the delivered file — ship clean metadata. **Keep the accompanying chat prose tight — one or two sentences naming the scheme chosen and why (e.g. "ProbabilisticEncryption — strongest at-rest protection; the field can't be filtered/sorted/grouped, which matches your no-query requirement"). Do not restate the whole prompt, enumerate every scheme, or add setup/deployment walkthroughs; the deliverable is the file, not an essay.**
96
+ - **Org settings artifact**: **only** the settings file the request needs, at `settings/<member>.settings-meta.xml` named after its Metadata API member — `settings/PlatformEncryption.settings-meta.xml` (root `<PlatformEncryptionSettings>`) and/or `settings/EncryptionKey.settings-meta.xml` (root `<EncryptionKeySettings>`). Do **not** name the file after the root element, and do **not** drop it at the repo root.
97
+
98
+ Do **not** add companion files (`DEPLOYMENT_GUIDE.md`, `README.md`, an extra org-settings file) that the user did not ask for — state prerequisites in a code comment inside the artifact, or inside the single answer file for guidance. File structure follows the templates in `assets/`.
99
+
100
+ ---
101
+
102
+ ## Cross-Skill Integration
103
+
104
+ | Need | Delegate to |
105
+ |------|-------------|
106
+ | A custom field with no encryption | `platform-custom-field-generate` |
107
+ | The raw Metadata API type/field reference | `platform-metadata-api-context-get` |
108
+
109
+ ---
110
+
111
+ ## Reference File Index
112
+
113
+ | File | When to read |
114
+ |------|-------------|
115
+ | `assets/encrypted-field.field-meta.xml` | Before generating an encrypted custom field |
116
+ | `assets/PlatformEncryption.settings-meta.xml` | Before generating org encryption-policy settings (member `PlatformEncryption`) |
117
+ | `assets/EncryptionKey.settings-meta.xml` | Before generating key-management settings — Cache-Only, EKM, Data 360 (member `EncryptionKey`) |
118
+ | `references/encryption-schemes.md` | When choosing deterministic vs probabilistic, or explaining encrypted-field query behavior |
119
+ | `references/key-models.md` | When configuring or explaining BYOK / BYOKMS / EKM / Cache-Only key models |
120
+ | `references/tenant-secret-lifecycle.md` | When the user asks about key rotation, destruction, or BYOK upload |
121
+ | `examples/cache-only-keys.settings-meta.xml` | To verify a generated Cache-Only key-settings file |
122
+ | `scripts/validate-encryption-metadata.sh` | After generating any settings XML — validates the replay dependency and scheme enum |