@salesforce/afv-skills 1.37.0 → 1.38.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 (247) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-generate/README.md +20 -3
  3. package/skills/agentforce-generate/SKILL.md +253 -440
  4. package/skills/agentforce-generate/assets/agent-spec-template.md +6 -2
  5. package/skills/agentforce-generate/assets/agents/order-service.agent +16 -12
  6. package/skills/agentforce-generate/assets/agents/production-faq.agent +4 -4
  7. package/skills/agentforce-generate/assets/agents/router-first.agent +5 -5
  8. package/skills/agentforce-generate/assets/agents/template-single-subagent.agent +4 -4
  9. package/skills/agentforce-generate/assets/agents/verification-gate.agent +8 -6
  10. package/skills/agentforce-generate/assets/agents/voice-knowledge-grounded.agent +9 -9
  11. package/skills/agentforce-generate/assets/agents/voice-service-agent.agent +7 -7
  12. package/skills/agentforce-generate/assets/patterns/README.md +3 -3
  13. package/skills/agentforce-generate/assets/patterns/action-callbacks.agent +5 -5
  14. package/skills/agentforce-generate/assets/patterns/advanced-input-bindings.agent +6 -8
  15. package/skills/agentforce-generate/assets/patterns/bidirectional-routing.agent +11 -13
  16. package/skills/agentforce-generate/assets/patterns/critical-input-collection.agent +11 -16
  17. package/skills/agentforce-generate/assets/patterns/lifecycle-events.agent +2 -3
  18. package/skills/agentforce-generate/assets/patterns/llm-controlled-actions.agent +6 -7
  19. package/skills/agentforce-generate/assets/patterns/open-gate-routing.agent +3 -3
  20. package/skills/agentforce-generate/assets/patterns/prompt-template-action.agent +14 -19
  21. package/skills/agentforce-generate/assets/patterns/system-instruction-overrides.agent +11 -20
  22. package/skills/agentforce-generate/references/actions-reference.md +2 -2
  23. package/skills/agentforce-generate/references/agent-audit-and-repair.md +135 -0
  24. package/skills/agentforce-generate/references/agent-audit-candidate-verification.md +160 -0
  25. package/skills/agentforce-generate/references/agent-audit-diagnostic-catalog.md +156 -0
  26. package/skills/agentforce-generate/references/agent-audit-diagnostics-actions-state.md +176 -0
  27. package/skills/agentforce-generate/references/agent-audit-diagnostics-architecture-evaluation.md +68 -0
  28. package/skills/agentforce-generate/references/agent-audit-diagnostics-instructions-routing.md +283 -0
  29. package/skills/agentforce-generate/references/agent-audit-evaluation-loop.md +191 -0
  30. package/skills/agentforce-generate/references/agent-audit-repair-report.md +143 -0
  31. package/skills/agentforce-generate/references/agent-audit-scope-path-review.md +180 -0
  32. package/skills/agentforce-generate/references/agent-design-and-spec-creation.md +105 -59
  33. package/skills/agentforce-generate/references/agent-script-core-language.md +144 -61
  34. package/skills/agentforce-generate/references/agent-subagent-map-diagrams.md +33 -23
  35. package/skills/agentforce-generate/references/agent-validation-and-debugging.md +37 -11
  36. package/skills/agentforce-generate/references/agentscript-toolchain.md +112 -0
  37. package/skills/agentforce-generate/references/architecture-patterns.md +81 -18
  38. package/skills/agentforce-generate/references/common-control-flow-pitfalls.md +255 -0
  39. package/skills/agentforce-generate/references/control-flow-actions-sequencing.md +198 -0
  40. package/skills/agentforce-generate/references/control-flow-lifecycle-side-effects.md +87 -0
  41. package/skills/agentforce-generate/references/examples.md +22 -22
  42. package/skills/agentforce-generate/references/instruction-resolution.md +123 -83
  43. package/skills/agentforce-generate/references/known-issues.md +1 -2
  44. package/skills/agentforce-generate/references/optimization-pattern-1-data-flow.md +4 -0
  45. package/skills/agentforce-generate/references/optimization-pattern-2-deterministic-logic.md +33 -0
  46. package/skills/agentforce-generate/references/optimization-pattern-3-reference-syntax.md +32 -3
  47. package/skills/agentforce-generate/references/optimization-pattern-4-escalation.md +2 -2
  48. package/skills/agentforce-generate/references/patterns-by-requirement.md +3 -1
  49. package/skills/agentforce-generate/references/posture-and-determinism.md +103 -22
  50. package/skills/agentforce-generate/references/reference-map.md +19 -3
  51. package/skills/agentforce-generate/references/scoring-rubric.md +1 -1
  52. package/skills/agentforce-generate/references/voice-latency-heuristics.md +4 -0
  53. package/skills/agentforce-generate/references/voice-modality-reference.md +4 -4
  54. package/skills/agentforce-generate/references/zen-of-agentscript.md +139 -23
  55. package/skills/agentforce-generate/scripts/agentscript-sdk-loader.mjs +133 -0
  56. package/skills/agentforce-generate/scripts/index-agent.mjs +141 -0
  57. package/skills/agentforce-generate/scripts/setup-agentscript-sdk.mjs +337 -0
  58. package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +1 -1
  59. package/skills/automation-sandbox-post-copy-configure/SKILL.md +433 -0
  60. package/skills/automation-sandbox-post-copy-configure/assets/api_request_templates.json +89 -0
  61. package/skills/automation-sandbox-post-copy-configure/examples/sample_config_input.json +40 -0
  62. package/skills/automation-sandbox-post-copy-configure/examples/sample_execution_summary.md +79 -0
  63. package/skills/automation-sandbox-post-copy-configure/references/api_endpoints.md +273 -0
  64. package/skills/automation-sandbox-post-copy-configure/references/authentication.md +94 -0
  65. package/skills/automation-sandbox-post-copy-configure/references/execution_phasing.md +93 -0
  66. package/skills/automation-sandbox-post-copy-configure/references/rules_gotchas.md +35 -0
  67. package/skills/automation-sandbox-post-copy-configure/scripts/classify-patch-result.mjs +88 -0
  68. package/skills/automation-sandbox-post-copy-configure/scripts/map-metadata-key.mjs +98 -0
  69. package/skills/automation-sandbox-post-copy-configure/scripts/plan-phases.mjs +98 -0
  70. package/skills/automation-sandbox-post-copy-configure/scripts/resolve-target-org.mjs +56 -0
  71. package/skills/design-systems-slds-validate/SKILL.md +14 -13
  72. package/skills/dx-code-analyzer-custom-rule-create/examples/xpath-examples.md +1 -1
  73. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-security.md +1 -1
  74. package/skills/dx-org-devhub-configure/SKILL.md +268 -0
  75. package/skills/dx-org-devhub-configure/examples/status-output.md +39 -0
  76. package/skills/dx-org-devhub-configure/scripts/devhub.sh +650 -0
  77. package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +116 -0
  78. package/skills/dx-org-manage/SKILL.md +135 -42
  79. package/skills/dx-org-manage/assets/derive-alias.sh +95 -0
  80. package/skills/dx-org-manage/assets/scratch-def.seed.json +6 -0
  81. package/skills/dx-org-manage/examples/README.md +1 -1
  82. package/skills/dx-org-manage/examples/scratch-orgs/delete_output.json +8 -0
  83. package/skills/dx-org-manage/examples/scratch-orgs/display_output.json +23 -0
  84. package/skills/dx-org-manage/examples/scratch-orgs/list_output.json +58 -0
  85. package/skills/dx-org-manage/examples/scratch-orgs/resume_output.json +38 -0
  86. package/skills/dx-org-manage/examples/scratch-orgs/success_definition_file.json +1 -1
  87. package/skills/dx-org-manage/examples/scratch-orgs/success_edition.json +1 -1
  88. package/skills/dx-org-manage/examples/scratch-orgs/success_shape.json +41 -0
  89. package/skills/dx-org-manage/examples/scratch-orgs/success_snapshot.json +1 -1
  90. package/skills/dx-org-manage/examples/snapshots/error_output.json +3 -3
  91. package/skills/dx-org-manage/references/creating-scratch-org.md +2 -2
  92. package/skills/dx-org-manage/references/creating-snapshot.md +1 -2
  93. package/skills/dx-org-manage/references/definition_file_options.md +24 -0
  94. package/skills/dx-org-manage/references/edition_types.md +10 -8
  95. package/skills/dx-org-manage/references/opening-org.md +11 -12
  96. package/skills/dx-org-manage/references/scratch-org-create.md +303 -0
  97. package/skills/dx-org-manage/references/scratch-org-operations.md +135 -0
  98. package/skills/experience-aura-lwc-migrate/SKILL.md +120 -0
  99. package/skills/experience-aura-lwc-migrate/references/aura-api-expert.md +170 -0
  100. package/skills/experience-aura-lwc-migrate/references/aura-data-expert.md +172 -0
  101. package/skills/experience-aura-lwc-migrate/references/aura-migration-guidelines.md +299 -0
  102. package/skills/experience-aura-lwc-migrate/references/aura-prd-framework.md +79 -0
  103. package/skills/experience-aura-lwc-migrate/references/aura-redundant-code-expert.md +24 -0
  104. package/skills/experience-aura-lwc-migrate/references/aura-reference-expert.md +140 -0
  105. package/skills/experience-aura-lwc-migrate/references/aura-resolver-expert.md +115 -0
  106. package/skills/experience-aura-lwc-migrate/references/aura-slots-expert.md +67 -0
  107. package/skills/experience-aura-lwc-migrate/references/aura-style-expert.md +62 -0
  108. package/skills/experience-aura-lwc-migrate/references/aura-to-lwc-completeness-checklist.md +188 -0
  109. package/skills/experience-aura-lwc-migrate/references/aura-values-expert.md +67 -0
  110. package/skills/experience-content-media-search/SKILL.md +17 -12
  111. package/skills/experience-content-media-stock-image-search/SKILL.md +192 -0
  112. package/skills/experience-content-media-stock-image-search/scripts/download-stock-image.py +102 -0
  113. package/skills/experience-lds-best-practices-apply/SKILL.md +245 -0
  114. package/skills/experience-lds-best-practices-apply/references/adapter-apis.md +1640 -0
  115. package/skills/experience-lds-best-practices-apply/references/lds-data-consistency.md +126 -0
  116. package/skills/experience-lds-best-practices-apply/references/lds-expert.md +429 -0
  117. package/skills/experience-lds-best-practices-apply/references/lds-referential-integrity.md +322 -0
  118. package/skills/experience-lds-best-practices-apply/references/wire-adapter-types.md +1511 -0
  119. package/skills/experience-lds-graphql-generate/SKILL.md +222 -0
  120. package/skills/experience-lds-graphql-generate/references/generation-guide.md +236 -0
  121. package/skills/experience-lds-graphql-generate/references/generation-mutation.md +277 -0
  122. package/skills/experience-lds-graphql-generate/references/generation-query.md +237 -0
  123. package/skills/experience-lds-graphql-generate/scripts/fetch-lds-graphql-schema.sh +230 -0
  124. package/skills/experience-lds-graphql-generate/scripts/test-lds-graphql-query.sh +128 -0
  125. package/skills/experience-lwc-accessibility-validate/SKILL.md +112 -0
  126. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +88 -0
  127. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +52 -0
  128. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +106 -0
  129. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +78 -0
  130. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +26 -0
  131. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +66 -0
  132. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +70 -0
  133. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +115 -0
  134. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +47 -0
  135. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +39 -0
  136. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +50 -0
  137. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +54 -0
  138. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +49 -0
  139. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +77 -0
  140. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +45 -0
  141. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +55 -0
  142. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +51 -0
  143. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +84 -0
  144. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +50 -0
  145. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +64 -0
  146. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +105 -0
  147. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +99 -0
  148. package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +97 -0
  149. package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-1-1-non-text-content.md +83 -0
  150. package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-1-use-of-color.md +62 -0
  151. package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-10-resize-reflow.md +18 -0
  152. package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-11-non-text-contrast.md +43 -0
  153. package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-3-contrast.md +25 -0
  154. package/skills/experience-lwc-accessibility-validate/scripts/contrast-ratio.py +153 -0
  155. package/skills/experience-lwc-design-generate/SKILL.md +261 -0
  156. package/skills/experience-lwc-design-generate/references/figma-to-prd-blueprint.md +66 -0
  157. package/skills/experience-lwc-design-generate/references/prd-analysis-template.md +17 -0
  158. package/skills/experience-lwc-design-generate/scripts/check-component-name.sh +75 -0
  159. package/skills/experience-lwc-design-generate/scripts/detect-project-tools.sh +97 -0
  160. package/skills/experience-lwc-runtime-observe/SKILL.md +244 -0
  161. package/skills/experience-lwc-runtime-observe/examples/component-preview-and-dom.md +41 -0
  162. package/skills/experience-lwc-runtime-observe/scripts/extract-dom.sh +79 -0
  163. package/skills/experience-lwc-runtime-observe/scripts/open-frontdoor.sh +46 -0
  164. package/skills/experience-lwc-runtime-observe/scripts/verify-toolchain.sh +48 -0
  165. package/skills/experience-lwc-security-validate/SKILL.md +151 -0
  166. package/skills/experience-lwc-security-validate/examples/review-report.md +6 -0
  167. package/skills/experience-lwc-security-validate/examples/score-report.sarif.json +32 -0
  168. package/skills/experience-lwc-security-validate/references/lws-security-expert.md +986 -0
  169. package/skills/experience-lwc-security-validate/references/security-analysis.md +611 -0
  170. package/skills/experience-lwc-security-validate/scripts/check-lwc-import.sh +166 -0
  171. package/skills/experience-lwc-security-validate/scripts/validate-sarif.sh +131 -0
  172. package/skills/experience-ui-bundle-2gp-deploy/SKILL.md +454 -0
  173. package/skills/experience-ui-bundle-2gp-deploy/assets/CustomApplication.app-meta.xml +12 -0
  174. package/skills/experience-ui-bundle-2gp-deploy/assets/PermissionSet.permissionset-meta.xml +9 -0
  175. package/skills/experience-ui-bundle-2gp-deploy/scripts/find-bundle-package-dir.sh +53 -0
  176. package/skills/experience-ui-bundle-agentforce-client-generate/SKILL.md +104 -26
  177. package/skills/experience-ui-bundle-agentforce-client-generate/references/constraints.md +35 -24
  178. package/skills/experience-ui-bundle-agentforce-client-generate/references/examples.md +92 -1
  179. package/skills/experience-ui-bundle-agentforce-client-generate/references/style-tokens.md +2 -0
  180. package/skills/experience-ui-bundle-agentforce-client-generate/references/troubleshooting.md +14 -1
  181. package/skills/experience-ui-bundle-agentforce-client-generate/scripts/detect-framework.sh +67 -0
  182. package/skills/experience-ui-bundle-deploy/SKILL.md +83 -14
  183. package/skills/experience-ui-bundle-deploy/assets/Communities.settings-meta.xml +19 -0
  184. package/skills/experience-ui-bundle-deploy/assets/org-setup.config.template.json +5 -0
  185. package/skills/experience-ui-bundle-deploy/assets/social-login-auth-providers.apex +158 -0
  186. package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +13 -1
  187. package/skills/experience-ui-bundle-deploy/references/social-login.md +179 -0
  188. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +14 -0
  189. package/skills/experience-ui-bundle-mfa-configure/SKILL.md +6 -5
  190. package/skills/experience-ui-bundle-mfa-configure/references/social-login.md +15 -7
  191. package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +41 -5
  192. package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +10 -22
  193. package/skills/experience-ui-bundle-salesforce-data-access/references/graphql-hand-authoring.md +4 -19
  194. package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +5 -0
  195. package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +33 -150
  196. package/skills/mobile-platform-native-capabilities-integrate/references/nfc.md +35 -0
  197. package/skills/platform-apex-generate/SKILL.md +8 -7
  198. package/skills/platform-apex-test-generate/SKILL.md +3 -1
  199. package/skills/platform-apex-test-run/SKILL.md +9 -8
  200. package/skills/platform-lightning-type-widget-coordinate/SKILL.md +1 -1
  201. package/skills/platform-lightning-type-widget-coordinate/examples/existing-lightning-type-with-widget-prompt.md +1 -1
  202. package/skills/platform-lightning-type-widget-coordinate/examples/new-lightning-type-with-widget-prompt.md +1 -1
  203. package/skills/platform-lightning-type-widget-coordinate/references/validation-gates.md +3 -3
  204. package/skills/platform-mcp-tool-widget-coordinate/SKILL.md +43 -67
  205. package/skills/platform-mcp-tool-widget-coordinate/examples/action-name-source-prompt.md +1 -2
  206. package/skills/platform-mcp-tool-widget-coordinate/examples/apex-invocable-source-prompt.md +2 -3
  207. package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-list-source-prompt.md +163 -0
  208. package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-single-source-prompt.md +198 -0
  209. package/skills/platform-mcp-tool-widget-coordinate/examples/pasted-tool-output-prompt.md +0 -1
  210. package/skills/platform-mcp-tool-widget-coordinate/references/build-plan-format.md +17 -11
  211. package/skills/platform-mcp-tool-widget-coordinate/references/mcp-tool-output-discovery.md +48 -15
  212. package/skills/platform-mcp-tool-widget-coordinate/references/two-clt-modeling.md +73 -10
  213. package/skills/platform-mcp-tool-widget-coordinate/references/validation-gates.md +48 -8
  214. package/skills/platform-policy-rule-generate/SKILL.md +22 -12
  215. package/skills/platform-policy-rule-generate/references/deploy-errors.md +1 -1
  216. package/skills/platform-policy-rule-generate/references/policy-schema-full.md +8 -29
  217. package/skills/platform-policy-rule-generate/references/templates-advanced.md +1 -1
  218. package/skills/platform-sharing-owd-configure/SKILL.md +20 -8
  219. package/skills/platform-sharing-owd-configure/references/access_levels.md +14 -1
  220. package/skills/platform-sharing-rules-generate/SKILL.md +67 -35
  221. package/skills/platform-sharing-rules-generate/examples/create-cases.md +16 -17
  222. package/skills/platform-sharing-rules-generate/examples/delete-cases.md +34 -79
  223. package/skills/platform-sharing-rules-generate/examples/edit-cases.md +13 -26
  224. package/skills/platform-sharing-rules-generate/scripts/count-remaining-rules.sh +33 -0
  225. package/skills/platform-widget-generate/SKILL.md +3 -5
  226. package/skills/platform-widget-generate/examples/conditional.json +18 -13
  227. package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
  228. package/skills/platform-widget-generate/examples/single-object.json +2 -2
  229. package/skills/platform-widget-generate/references/schema-from-lightning-type.md +27 -6
  230. package/skills/platform-widget-generate/references/widget-bundle-layout.md +4 -3
  231. package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +287 -0
  232. package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +260 -0
  233. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +252 -0
  234. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/references/mcp-invocation.md +204 -0
  235. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +259 -0
  236. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +188 -0
  237. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +197 -0
  238. package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +77 -0
  239. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +316 -0
  240. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/references/mcp-invocation.md +221 -0
  241. package/skills/service-itsm-incident-priority-configure/SKILL.md +168 -0
  242. package/skills/service-itsm-incident-priority-configure/examples/matrix-operations.md +200 -0
  243. package/skills/service-itsm-incident-priority-configure/examples/render-matrix.md +54 -0
  244. package/skills/service-itsm-incident-priority-configure/examples/seed-full-matrix.md +52 -0
  245. package/skills/service-itsm-incident-priority-configure/references/sf-cli-invocation.md +264 -0
  246. package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-source-prompt.md +0 -191
  247. package/skills/platform-policy-rule-generate/references/fixtures-index.md +0 -29
@@ -0,0 +1,198 @@
1
+ # Example: single nested-object payload field, discovered from the IA describe
2
+
3
+ A complete walkthrough for the case where an Invocable Action output is itself **another Apex class** —
4
+ a **single nested object** (`maxOccurs: 1`). **The Invocable Action (IA) describe is the source of
5
+ truth**; the Apex class is read only to enumerate the referenced class's own leaf fields. This is the
6
+ second, additive payload shape alongside the flat-primitive shape in `apex-invocable-source-prompt.md` —
7
+ read `references/mcp-tool-output-discovery.md` ("Nested-object and list payload fields") and
8
+ `references/two-clt-modeling.md` ("Nested-object and list payload fields") first. The **list** shapes
9
+ (top-level list, list-inside-wrapper) are in the companion example `nested-object-list-source-prompt.md`.
10
+
11
+ > **The skill never modifies the Apex.** The describe's `apexClass` + `maxOccurs` tell you the shape;
12
+ > reading the referenced class is a read-only enumeration step, not a reshape.
13
+
14
+ ---
15
+
16
+ ## Single nested object (`maxOccurs: 1`)
17
+
18
+ ### The prompt
19
+
20
+ > I have an MCP server tool backed by the `GetFlightDetailsAction` Apex invocable action. Build a
21
+ > widget that renders its output as a flight details card.
22
+
23
+ ### Phase 1 — Input selection
24
+
25
+ - Source: `action` — the prompt names an Apex Invocable, so describe it through the Actions REST API
26
+ (`/services/data/v<APIVER>/actions/custom/apex/GetFlightDetailsAction`). This is the source of truth
27
+ for the output shape; the `.cls` is read later only to enumerate the referenced class's leaves.
28
+ - Tool API name: `getFlightDetails` (from the class name `GetFlightDetailsAction`, stripping the
29
+ trailing `Action` suffix and lower-camelCasing — see the naming convention in
30
+ `references/two-clt-modeling.md`).
31
+
32
+ ### Phase 2 — Payload discovery (from the describe)
33
+
34
+ The Actions describe returns a scalar sibling alongside the single nested-object output:
35
+
36
+ ```jsonc
37
+ // GET /services/data/v67.0/actions/custom/apex/GetFlightDetailsAction → .outputs[]
38
+ [
39
+ { "name": "searchStatus", "type": "STRING", "maxOccurs": 1 },
40
+ { "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }
41
+ ]
42
+ ```
43
+
44
+ - `searchStatus` is a **flat primitive** (`STRING`) → `lightning__textType`, bound two segments deep. Flat scalars and a single nested object coexist in one response; handle each per its own branch.
45
+ - `flightInfo`: `type: null` + `apexClass` set + `maxOccurs: 1` = a **single nested object** (not a describe gap, not a list).
46
+ - The nested output's own leaf fields are **not** in the describe. Read the named class
47
+ (`SearchFlightsAction.Flight`) and enumerate its **public / `@AuraEnabled`** members — an
48
+ inner/referenced class is not gated by `@InvocableVariable` (that gates only the top-level response
49
+ class). These become the widget's flat leaf properties. **Never ignore any property.**
50
+
51
+ ```apex
52
+ public class Flight {
53
+ @InvocableVariable public String flightId;
54
+ @InvocableVariable public String origin;
55
+ @InvocableVariable public String destination;
56
+ @InvocableVariable public String departureTime;
57
+ @InvocableVariable public String arrivalTime;
58
+ @InvocableVariable public Long price;
59
+ }
60
+ ```
61
+
62
+ | Leaf field | Apex type | widget `lightning:type` |
63
+ |---|---|---|
64
+ | flightId | String | `lightning__textType` |
65
+ | origin | String | `lightning__textType` |
66
+ | destination | String | `lightning__textType` |
67
+ | departureTime | String | `lightning__textType` |
68
+ | arrivalTime | String | `lightning__textType` |
69
+ | price | Long | `lightning__numberType` |
70
+
71
+ `payloadFields` (from describe) = 2 fields: `searchStatus` (flat `STRING`) + `flightInfo` (Apex-class-typed → nested-object branch).
72
+ `payloadFields` (flattened, for the widget) = `searchStatus` + the 6 leaf rows above (7 total).
73
+
74
+ ### Phase 3 — Build plan (abridged)
75
+
76
+ ```text
77
+ MCP Tool Widget Build Plan: getFlightDetailsWidget
78
+
79
+ PLAN: Render the GetFlightDetails MCP tool output as a flight-details card.
80
+
81
+ TOOL / SOURCE:
82
+ Tool API name: getFlightDetails
83
+ Payload source: Actions describe of Apex Invocable GetFlightDetailsAction
84
+ Outputs: searchStatus (STRING, maxOccurs 1 → flat scalar) + flightInfo (apexClass SearchFlightsAction$Flight, maxOccurs 1 → single nested object)
85
+
86
+ LIGHTNING TYPES:
87
+ Response CLT: getFlightDetailsResponse
88
+ Properties: searchStatus → "lightning__textType"; flightInfo → "@apexClassType/c__SearchFlightsAction$Flight" # nested-object field, NOT {"type":"object"}
89
+ Envelope CLT: getFlightDetails
90
+ Renderer (default, bundle root): .../lightningTypes/getFlightDetails/renderer.json
91
+ Envelope: actionName (text), isSuccess (boolean), outputValues (c__getFlightDetailsResponse)
92
+
93
+ WIDGET: getFlightDetailsWidget
94
+ Schema: searchStatus (flat scalar) + flightInfo's 6 leaf fields (flightId, origin, destination, departureTime, arrivalTime, price)
95
+ Renderer binding: searchStatus → {!$attrs.outputValues.searchStatus} (two segments); each flightInfo leaf → {!$attrs.outputValues.flightInfo.<leaf>} (three segments)
96
+
97
+ GENERATION ORDER: response CLT → widget → envelope CLT
98
+ ```
99
+
100
+ Proceed unless the next reply pushes back.
101
+
102
+ ### Phase 4 — Generation order
103
+
104
+ 1. **Response CLT** `getFlightDetailsResponse`:
105
+
106
+ ```json
107
+ {
108
+ "title": "Get Flight Details Response",
109
+ "description": "Response fields from the GetFlightDetailsAction invocable-action (FlightDetailsResponse)",
110
+ "type": "object",
111
+ "lightning:type": "lightning__objectType",
112
+ "lightning:tags": ["mcp"],
113
+ "unevaluatedProperties": false,
114
+ "properties": {
115
+ "searchStatus": {
116
+ "title": "Search Status",
117
+ "lightning:type": "lightning__textType"
118
+ },
119
+ "flightInfo": {
120
+ "title": "Flight Info",
121
+ "lightning:type": "@apexClassType/c__SearchFlightsAction$Flight"
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ 2. **Widget** `getFlightDetailsWidget` — flat schema over `searchStatus` + the 6 leaf fields (not the
128
+ single `flightInfo` field); body binds `{!$attrs.searchStatus}`, `{!$attrs.flightId}`,
129
+ `{!$attrs.origin}`, etc.
130
+
131
+ 3. **Envelope CLT** `getFlightDetails`:
132
+
133
+ ```json
134
+ {
135
+ "title": "Get Flight Details",
136
+ "description": "Invocable-action result envelope for the GetFlightDetailsAction MCP tool",
137
+ "type": "object",
138
+ "lightning:type": "lightning__objectType",
139
+ "lightning:tags": ["mcp"],
140
+ "unevaluatedProperties": false,
141
+ "properties": {
142
+ "actionName": { "title": "Action Name", "lightning:type": "lightning__textType" },
143
+ "isSuccess": { "title": "Is Success", "lightning:type": "lightning__booleanType" },
144
+ "outputValues": { "title": "Output Values", "lightning:type": "c__getFlightDetailsResponse" }
145
+ }
146
+ }
147
+ ```
148
+
149
+ 4. **Default renderer** at `lightningTypes/getFlightDetails/renderer.json` —
150
+ `definition: @widget/c/getFlightDetailsWidget`, each attribute bound three segments deep through
151
+ the nested object:
152
+
153
+ ```json
154
+ {
155
+ "renderer": {
156
+ "componentOverrides": {
157
+ "$": {
158
+ "definition": "@widget/c/getFlightDetailsWidget",
159
+ "attributes": {
160
+ "searchStatus": "{!$attrs.outputValues.searchStatus}",
161
+ "flightId": "{!$attrs.outputValues.flightInfo.flightId}",
162
+ "origin": "{!$attrs.outputValues.flightInfo.origin}",
163
+ "destination": "{!$attrs.outputValues.flightInfo.destination}",
164
+ "departureTime": "{!$attrs.outputValues.flightInfo.departureTime}",
165
+ "arrivalTime": "{!$attrs.outputValues.flightInfo.arrivalTime}",
166
+ "price": "{!$attrs.outputValues.flightInfo.price}"
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Phase 5 — Validation
175
+
176
+ - `clt-reference-integrity`: envelope `outputValues` → `c__getFlightDetailsResponse`, response CLT
177
+ exists, `searchStatus` is a primitive `lightning__textType`, `flightInfo` uses
178
+ `@apexClassType/c__SearchFlightsAction$Flight` (not a bare `{"type":"object"}`, not an inlined
179
+ `lightning__objectType`), no `$schema`/`items` → **pass**. PROP_GROUNDING: both trace to describe outputs → **ok**.
180
+ - `renderer-wires-widget`: bundle-root renderer present, definition `@widget/c/getFlightDetailsWidget`,
181
+ `searchStatus` bound two segments, every `flightInfo` leaf bound three segments as
182
+ `{!$attrs.outputValues.flightInfo.<property>}` (not two, which would bind to an unresolvable object) → **pass**.
183
+ - `field-trace`: `searchStatus` (primitive) compares directly; `flightInfo` resolves to
184
+ `@apexClassType/...` and expands to its class's leaves before comparing. INVOCABLE_FIELDS (expanded)
185
+ = `searchStatus, flightId, origin, destination, departureTime, arrivalTime, price`. Widget properties
186
+ match exactly; INVENTED empty; OMITTED empty → **pass**.
187
+
188
+ ---
189
+
190
+ ## Notes
191
+
192
+ - **Why not a single-level opaque object.** Typing an Apex-class-typed field as `{"type":"object"}`
193
+ produces an opaque blob with no leaf fields — not renderable. The
194
+ `@apexClassType/<ns>__<OuterClass>$<InnerClass>` reference is what actually deploys.
195
+ - **This is additive, not a replacement.** A response of all primitives still uses the flat mapping
196
+ tables unchanged. Check each field independently — outputs can mix primitive and Apex-class-typed fields.
197
+ - **List shapes are separate.** A top-level list output or a list nested inside a wrapper is covered in
198
+ `nested-object-list-source-prompt.md`.
@@ -64,7 +64,6 @@ LIGHTNING TYPES:
64
64
 
65
65
  WIDGET: getOrderStatusWidget
66
66
  Renderer binding: each attribute → {!$attrs.outputValues.<field>}
67
- Properties omitted: none
68
67
 
69
68
  GENERATION ORDER: response CLT → widget → envelope CLT
70
69
  ```
@@ -20,11 +20,14 @@ LIGHTNING TYPES (two object-based CLTs of equal standing — named for what each
20
20
  Name: <responseCLT> # convention: <toolApiName>Response
21
21
  Path: <pkgDir>/lightningTypes/<responseCLT>/schema.json
22
22
  Properties: <field: lightning:type, ...> # 1:1 with response @InvocableVariable fields
23
+ Nested/list fields: <objectField: @apexClassType/c__<Outer>$<Inner>, ... — or "none">
24
+ # A single nested object is one @apexClassType property; a List<ApexClass> rides INSIDE an
25
+ # @apexClassType object (the CLT carries no lightning__listType — the list surfaces in the widget schema).
23
26
  Envelope CLT:
24
27
  Name: <toolCLT> # convention: <toolApiName>
25
28
  Path: <pkgDir>/lightningTypes/<toolCLT>/schema.json
26
29
  Renderer (default, at bundle root — wires the widget): <pkgDir>/lightningTypes/<toolCLT>/renderer.json
27
- Envelope properties: actionName (text), isSuccess (boolean), outputValues (c__<responseCLT>), <plus any others>
30
+ Envelope properties: actionName (text), isSuccess (boolean), outputValues (c__<responseCLT>) # exactly these three — no others
28
31
 
29
32
  WIDGET:
30
33
  Name: <widgetName> # convention: <toolApiName>Widget
@@ -33,12 +36,11 @@ WIDGET:
33
36
  <pkgDir>/uiWidgets/<widgetName>/schema.json
34
37
  <pkgDir>/uiWidgets/<widgetName>/<widgetName>.uiwidget-meta.xml
35
38
  Schema source: derived from the response field list (name + primitive type) — a standalone contract, not tied to any Lightning Type
36
- Renderer binding: each widget attribute maps to {!$attrs.outputValues.<field>}
37
- Layout intent: <one-line description of the widget composition>
38
- Properties omitted: <response fields the widget intentionally drops, with rationale — or "none">
39
- # actionName/isSuccess never appear here — they are envelope-only and never candidates for the widget.
40
- # Default omissions to declare when present in the response: isSuccess, errorMessage, status, message
41
- # (operational/status indicators, not display data) — each needs its own one-line rationale, not just the field name.
39
+ List fields: <listField: element class @apexClassType/c__<Outer>$<Inner> — or "none"> # widget schema/body authored by platform-widget-generate
40
+ Renderer binding: primitive → {!$attrs.outputValues.<field>}; nested-object leaf → {!$attrs.outputValues.<objectField>.<leaf>};
41
+ list → {!$attrs.outputValues.<listField>} (top-level) or {!$attrs.outputValues.<wrapperField>.<listField>} (list inside wrapper)
42
+ Layout intent: <one-line description of the widget composition, incl. how lists are rendered>
43
+ # actionName/isSuccess are envelope-only fields (on the envelope CLT) and never widget candidates.
42
44
 
43
45
  SUB-SKILLS THAT WILL RUN:
44
46
  platform-custom-lightning-type-generate (response CLT, then envelope CLT)
@@ -52,11 +54,16 @@ VALIDATIONS THAT WILL RUN AFTER GENERATION:
52
54
  - every {!$attrs.X} resolves to a widget schema property
53
55
  - <name>.uiwidget-meta.xml is well-formed, root <UiWidgetBundle>, declares <widgetType>JSON</widgetType>
54
56
  Cross-skill checks (run by this orchestrator):
55
- - clt-reference-integrity: envelope CLT outputValues → c__<responseCLT>; response CLT exists; no $schema/items
57
+ - clt-reference-integrity: envelope CLT outputValues → c__<responseCLT>; response CLT exists; no $schema/items;
58
+ non-primitive response fields typed @apexClassType (no CLT-level lightning__listType — lists ride inside the object)
56
59
  - renderer-wires-widget: envelope CLT renderer.json (bundle root) references the widget via @widget/c/<widgetName>,
57
- binding every widget property as {!$attrs.outputValues.<property>}
60
+ binding every widget property under outputValues ({!$attrs.outputValues.<property>}, or
61
+ {!$attrs.outputValues.<objectField>.<leaf|listField>} for nested/list fields)
62
+ - nested-list-coverage: every nested-object and list field discovered in Phase 2 is rendered by the widget
63
+ (authored by platform-widget-generate) and bound in the renderer at the correct depth. A discovered
64
+ nested/list field that is absent FAILS ("out of scope" / "beta single-response" are not valid drop rationales).
58
65
  - field-trace (advisory): print response @InvocableVariable fields and widget schema properties; print the diff.
59
- Invented widget fields fail; omissions not declared above warn.
66
+ Invented widget fields fail; a response data field absent from the widget warns.
60
67
 
61
68
  GENERATION ORDER: response CLT → widget → envelope CLT (response CLT must exist before the envelope CLT references it).
62
69
 
@@ -70,5 +77,4 @@ Proceeding unless you push back (reply "no", "stop", "change X"). The plan above
70
77
 
71
78
  - If the user replies with edits or declines, revise the plan and reprint. Do not assume which sections changed.
72
79
  - Approval applies only to the plan as printed. A later request for another tool starts a new planning cycle.
73
- - "Properties omitted" makes intentional drops explicit — e.g. `status`, `message`, internal IDs that do not belong on the render surface.
74
80
  - If the payload source is a pasted sample that nests under `outputValues.data`, record that extra level here — it changes the response CLT and every renderer binding to `{!$attrs.outputValues.data.<field>}`.
@@ -55,8 +55,8 @@ The describe response has an `outputs` array. Each entry describes one payload f
55
55
 
56
56
  - **Use `outputs` only.** `inputs` is the tool input (the request wrapper) — exclude it, exactly as `apex` excludes the request class.
57
57
  - `name` → the CLT/widget property key. `label` → the property `title`.
58
- - A field with `maxOccurs > 1` is a **collection** (list). For the beta, surface it to the user in the build plan — the widget renders a single response, and list payloads need a nested item CLT (out of scope for the default flow).
59
- - An entry with **`"type": null` and an `"apexClass"` key instead** (e.g. `{ "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }`) is **not missing data to default to text** — it is the describe's encoding for a field typed as another Apex class. `$` separates the outer class from the inner class, matching the `@apexClassType/<ns>__<OuterClass>$<InnerClass>` convention used elsewhere in this skill. This is the same case as a `List<ApexClass>`/nested-object field from the other two sources — see "Nested-object payload fields" below; the Actions REST API describe never exposes that class's own leaf fields, so retrieving/reading the Apex class named in `apexClass` (via `apex` §1/§3) is the correct next step, not a fallback away from `action`.
58
+ - A field with `maxOccurs > 1` is a **collection** (list) — it is in scope, not out of scope. If its `apexClass` is set (a list of nested objects) or its `type` is a primitive (a list of scalars), render it as a collection per "Nested-object and list payload fields" below; never drop it silently. (The `content[]` beta single-response limit is about rendering one tool *result*, not about list *fields* inside that result.)
59
+ - An entry with **`"type": null` and an `"apexClass"` key instead** (e.g. `{ "name": "flightInfo", "type": null, "apexClass": "SearchFlightsAction$Flight", "maxOccurs": 1 }`) is **not missing data to default to text** — it is the describe's encoding for a field typed as another Apex class. `$` separates the outer class from the inner class, matching the `@apexClassType/<ns>__<OuterClass>$<InnerClass>` convention used elsewhere in this skill. This is the same nested-object / list-of-objects case as from the other two sources — see "Nested-object and list payload fields" below (`maxOccurs: 1` → single object; `maxOccurs > 1` → list of that object); the Actions REST API describe never exposes that class's own leaf fields, so retrieving/reading the Apex class named in `apexClass` (via `apex` §1/§3) is the correct next step, not a fallback away from `action`.
60
60
 
61
61
  Extract the field list with `jq` (do NOT wrap in `$()`):
62
62
 
@@ -156,29 +156,62 @@ If the grep misses multi-line annotations, read the `.cls` with the Read tool an
156
156
 
157
157
  ---
158
158
 
159
- ## Nested-object payload fields (applies to every source above)
159
+ ## Nested-object and list payload fields (applies to every source above)
160
160
 
161
- The mapping tables above (Actions-API `type`, Apex type, JSON value/schema `type`) cover **primitive** fields. A field can also be typed as **another Apex class** instead of a primitive — e.g. `GetFlightDetailsAction.FlightDetailsResponse.flightInfo`, typed `SearchFlightsAction.Flight`. This is a second, additive branch — check every payload field against it, regardless of which of the three sources produced the field list:
161
+ The mapping tables above (Actions-API `type`, Apex type, JSON value/schema `type`) cover **primitive** fields. A field can also be typed as **another Apex class** — as a single object or as a list of them. Both are in scope; check every payload field against both branches, regardless of which of the three sources produced the field list. Detect a nested/list field by source:
162
162
 
163
- - **Actions API**: an output entry with `"type": null` and an `"apexClass": "<OuterClass>$<InnerClass>"` key, rather than a primitive `STRING`/`INTEGER`/etc. `type` (see step 3 above).
164
- - **`apex`**: an `@InvocableVariable` field whose declared type is not `String`/`Id`/`Integer`/`Long`/`Decimal`/`Double`/`Boolean`/`Date`/`Datetime` but another Apex class.
165
- - **`sample`**: a property whose JSON value/schema `type` is `"object"` (not a primitive).
163
+ - **Actions API**: an output entry with `"type": null` and an `"apexClass": "<OuterClass>$<InnerClass>"` key, rather than a primitive `STRING`/`INTEGER`/etc. `type` (see step 3 above). `maxOccurs: 1` → single object; `maxOccurs > 1` → list of that object.
164
+ - **`apex`**: an `@InvocableVariable` field whose declared type is not `String`/`Id`/`Integer`/`Long`/`Decimal`/`Double`/`Boolean`/`Date`/`Datetime` — either another Apex class (single object) or `List<ApexClass>` (list of objects).
165
+ - **`sample`**: a property whose JSON value/schema `type` is `"object"` (single object) or `"array"` of objects (list).
166
166
 
167
- **Never** model such a field as `{"type":"object"}` (opaque, unrenderable) or inline it as a nested `lightning__objectType` (rejected by the CLT metaschema — same rule as the envelope↔response relationship). Instead:
167
+ **Never** model such a field as `{"type":"object"}` (opaque, unrenderable) or inline it as a nested `lightning__objectType` (rejected by the CLT metaschema — same rule as the envelope↔response relationship).
168
+
169
+ > **Enumerating a referenced/inner Apex class — use its public/`@AuraEnabled` members, not `@InvocableVariable`** (SKILL.md Hard Rule 6: the invocable annotation gates only the top-level response class; an inner class's leaves are never in the describe, so grepping it for `@InvocableVariable` enumerates zero leaves). The grep:
170
+ >
171
+ > ```bash
172
+ > # Inner/referenced class leaves — public/@AuraEnabled members (NOT @InvocableVariable).
173
+ > echo "INNER_FIELDS:"
174
+ > grep -oE '(public|global)\s+[A-Za-z0-9_<>,\s]+\s+[a-zA-Z_][a-zA-Z0-9_]*\s*;' \
175
+ > <pkgDir>/classes/<OuterClass>.cls \
176
+ > | sed -E 's/.*\s([a-zA-Z_][a-zA-Z0-9_]*)\s*;/\1/' \
177
+ > | sort -u
178
+ > # Scope to the inner class block; @AuraEnabled fields have no @InvocableVariable line above them.
179
+ > # If the grep misses multi-line declarations, Read the .cls and list the inner class fields manually.
180
+ > ```
181
+
182
+ ### Single nested object (`maxOccurs: 1`)
183
+
184
+ `<objectField>` throughout this section is the output entry's own `name` from the describe (e.g. `flightInfo`) — the property key that carries the object, used verbatim in the response CLT property name and the renderer binding path. It is never an invented label.
168
185
 
169
186
  1. Type the response CLT property as `"@apexClassType/<ns>__<OuterClass>$<InnerClass>"` (e.g. `"@apexClassType/c__SearchFlightsAction$Flight"`) — the same convention `platform-custom-lightning-type-generate` documents for Apex-backed CLTs.
170
- 2. Enumerate the referenced Apex class's own fields (its own `@InvocableVariable`/public members) — these become the widget's leaf properties. The object field itself never appears on the widget.
187
+ 2. Enumerate the referenced Apex class's own fields by its **public / `@AuraEnabled`** members (see the callout above — inner classes are *not* gated by `@InvocableVariable`) — these become the widget's leaf properties. The object field itself never appears on the widget.
171
188
  3. Bind the renderer one level deeper: `{!$attrs.outputValues.<objectField>.<leaf>}` (e.g. `{!$attrs.outputValues.flightInfo.flightId}`), not `{!$attrs.outputValues.<objectField>}`.
172
- 4. A field typed `List<ApexClass>` (a list of nested objects, not a single one) is out of scope for the beta single-response flow — surface it in the build plan like a `maxOccurs > 1` scalar rather than emitting a schema for it.
173
189
 
174
- See `references/two-clt-modeling.md` ("Nested-object payload fields") for the worked JSON, and `examples/nested-object-source-prompt.md` for the full end-to-end walkthrough.
190
+ ### List of nested objects (`List<ApexClass>` / `maxOccurs > 1` with an `apexClass`)
191
+
192
+ A list of nested objects is **in scope** — a real, boundary-crossing, renderable field. Do **not** declare it "out of scope" and do **not** drop it silently. In a response CLT the list is **always a plain `@apexClassType/...` reference** (the CLT metaschema forbids `lightning__listType`/`items` on a response-CLT property — `unevaluatedProperties: false`); the list-ness surfaces in the *widget* schema. **Never touch the Apex to make a list renderable** — both list positions below bind directly, no wrapper reshape.
193
+
194
+ > **The binding depth equals the list's position in the describe — read it off the describe, never apply a transform.** Two positions, both directly bindable:
195
+ > - **Top-level list output** — the describe surfaces the list itself as an output entry: `apexClass` set + `maxOccurs > 1` (e.g. `GetLeadsList` → `leads`, `apexClass: GetLeadsList$LeadSummary`, `maxOccurs: 2000`), often alongside scalar sibling outputs (`leadCount`, `status`). Type the response CLT property **directly** as `@apexClassType/c__<Outer>$<ElementClass>` (the element/summary class) and bind the renderer at **two segments**: `{!$attrs.outputValues.<listField>}` (e.g. `{!$attrs.outputValues.leads}`). *No Apex change, no wrapper.*
196
+ > - **List inside a wrapper object** — the describe returns exactly ONE `apexClass` output with `maxOccurs: 1` (e.g. `GetShipmentDetails` → `shipmentDetailsResponse`), and the list is a field *inside* that class that the describe **does not surface**. Read the inner Apex class (via the `apex` source / apex describe) and enumerate its **public / `@AuraEnabled`** members — not `@InvocableVariable` (see the referenced/inner-class callout above) — to discover the list field, type the response CLT property as the wrapper class `@apexClassType/c__<Outer>$<ResponseClass>`, and bind the renderer at **three segments**: `{!$attrs.outputValues.<wrapperField>.<listField>}` (e.g. `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`).
197
+ >
198
+ > Whichever position, the response CLT property is a single `@apexClassType/...` reference — the extra binding depth for the wrapper case comes from the wrapper level in the describe, not from any reshape. See `references/two-clt-modeling.md` ("Top-level list vs list-inside-wrapper") for the worked JSON.
199
+
200
+ 1. **Response CLT:** type the list as a plain `@apexClassType/...` reference — `c__<Outer>$<ElementClass>` for a top-level list output, or `c__<Outer>$<ResponseClass>` (the wrapper class, whose interior list field you found by reading the class) for a list-inside-wrapper. Do NOT add a `lightning__listType` property to the CLT.
201
+ 2. **Renderer:** bind the list at the depth its describe position dictates — **two segments** `{!$attrs.outputValues.<listField>}` for a top-level list output, or **three segments** `{!$attrs.outputValues.<wrapperField>.<listField>}` for a list inside a wrapper object (never `.<leaf>`).
202
+
203
+ The **widget bundle** (schema + body) that surfaces and iterates the list is authored and validated by `platform-widget-generate` — this skill does not specify the widget's `lightning__listType`/`items` schema property or its iteration mechanism.
204
+
205
+ A `List<InnerClass>` collection is never omitted — it is domain data and is always rendered.
206
+
207
+ See `references/two-clt-modeling.md` ("Nested-object and list payload fields") for the worked JSON, and `examples/nested-object-single-source-prompt.md` (single object) / `examples/nested-object-list-source-prompt.md` (lists) for the full end-to-end walkthroughs.
175
208
 
176
209
  ## Output of Phase 2
177
210
 
178
- `payloadFields` — an ordered list of `{ name, title, lightning:type }` describing the response payload (primitive fields), plus any nested-object fields resolved to `@apexClassType/...` per above. This drives:
211
+ `payloadFields` — an ordered list of `{ name, title, lightning:type }` describing the response payload (primitive fields), plus any nested-object or list-of-object fields resolved to `@apexClassType/...` per above. A list-of-object field rides inside an `@apexClassType` object (it is not a CLT-level `lightning__listType`); it surfaces as a `lightning__listType` with an `items` element type in the **widget** schema. This drives:
179
212
 
180
- - the **response CLT** `properties` (CLT type vocabulary, `lightning__integerType` allowed, `@apexClassType/...` for nested-object fields),
181
- - the **widget schema** `properties.attributes.properties` (widget type vocabulary, numerics → `lightning__numberType`; nested-object fields flattened to their leaf properties),
182
- - the **renderer** attribute bindings (`{!$attrs.outputValues.<name>}` for primitives, `{!$attrs.outputValues.<objectField>.<leaf>}` for nested-object leaves).
213
+ - the **response CLT** `properties` (CLT type vocabulary, `lightning__integerType` allowed, `@apexClassType/...` for single nested-object fields and for the object a list rides inside — never `lightning__listType`/`items` in the CLT),
214
+ - the **widget schema** (authored by `platform-widget-generate` — flat leaf properties for single nested-object fields, and a list property for list-of-object fields; this skill supplies the field list and element typing, not the widget schema/body shape),
215
+ - the **renderer** attribute bindings (`{!$attrs.outputValues.<name>}` for primitives, `{!$attrs.outputValues.<objectField>.<leaf>}` for single nested-object leaves, `{!$attrs.outputValues.<listField>}` / `{!$attrs.outputValues.<wrapperField>.<listField>}` for list fields at the depth the describe dictates).
183
216
 
184
217
  Whichever source produced the fields, record it in the build plan so the reviewer knows whether the schema came from the live org (`action`), source (`apex`), or an example (`sample`).
@@ -1,6 +1,6 @@
1
1
  # Two-CLT Modeling for an MCP Tool Output
2
2
 
3
- A custom MCP server tool backed by an Apex Invocable Action returns the platform's **invocable-action result envelope**. The real payload the tool consumer cares about lives under `outputValues`; the surrounding fields (`actionName`, `isSuccess`, `errors`, `sortOrder`, `version`, …) are envelope metadata.
3
+ A custom MCP server tool backed by an Apex Invocable Action returns the platform's **invocable-action result envelope**. The real payload the tool consumer cares about lives under `outputValues`; the surrounding fields (`errors`, `sortOrder`, `version`, …) are envelope metadata and are not modeled — the envelope CLT declares only `actionName`, `isSuccess`, `outputValues`.
4
4
 
5
5
  To render this with an HXL widget we model it as **two object-based CLTs** and wire them with a renderer that bridges the nesting. Both are ordinary CLTs of equal standing — nothing in the platform or the metaschema distinguishes an "envelope type" from a "response type." The only reason two files exist is that one CLT (the envelope) must reference the other (the response) by name via `c__<name>`, and a CLT cannot reference itself — so the two need distinct deployed names, nothing more. Don't invent a role-label pair for the two CLTs themselves ("Payload CLT"/"Envelope CLT", "Outer CLT"/"Inner CLT") — name and describe each by what it actually models (see below), and in prose refer to them by that same identifier: "the `<toolApiName>` envelope" / "the `<toolApiName>Response`". ("Payload" and "response" remain fine as ordinary words for the data itself — e.g. "response fields", "the payload the tool consumer cares about" — the rule is about not naming or labeling the *CLTs* by an invented role.)
6
6
 
@@ -20,8 +20,6 @@ To render this with an HXL widget we model it as **two object-based CLTs** and w
20
20
  - Both CLT names are derived from the **same single `<toolApiName>`** — there is no separate naming decision to make per artifact, and no free-standing role word (no "Result", "OutputValues", "Payload", "Envelope", and no `_CLT` suffix either — a Lightning Type is identified by living under `lightningTypes/`, not by a suffix on its name). `Response` is not a role label; it is literally what the class is (the Invocable Action's declared `List<...Response>` return-element type) — the same word the Apex source itself already uses (e.g. `GetAccountSummaryResponse`, `FlightDetailsResponse`).
21
21
  - The envelope CLT is *structurally* generic but **cannot be a single shared CLT** — its `outputValues` must be typed to a tool-specific response CLT via `c__<responseCLT>`. One envelope CLT per tool.
22
22
 
23
- > **Naming convention supersedes the earlier hand-verified prototype.** Two bundles were manually fixed and successfully deployed during development using an older `<toolApiName>Result` / `<toolApiName>OutputValues` naming pair — that proved the *structural* pattern (two object-based CLTs, `@apexClassType` for nested fields, two-level renderer bindings) deploys correctly. The naming convention above replaces those two suffixes; every other structural rule in this file (root keys, `unevaluatedProperties`, the `c__` reference, nested-object typing, renderer bindings) is unchanged and still matches what was verified.
24
-
25
23
  ## Response CLT
26
24
 
27
25
  Object-based CLT whose `properties` are exactly the response `@InvocableVariable` fields (1:1). Root `lightning:type` is `lightning__objectType`. `platform-custom-lightning-type-generate` injects and enforces `"unevaluatedProperties": false` on every object-based CLT (its metaschema rejects a CLT without it) — this orchestrator does not fight that, it matches it in every example and every generated file. Give both CLTs a real, tool-specific `description` (never `""`) — it is what a consumer sees when picking a referenced CLT. Both CLTs also carry a root-level `"lightning:tags": ["mcp"]` — it marks the type as MCP-tool-generated per `platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md`.
@@ -43,14 +41,18 @@ Object-based CLT whose `properties` are exactly the response `@InvocableVariable
43
41
  }
44
42
  ```
45
43
 
46
- ### Nested-object payload fields (a second, additive case)
44
+ > **Response CLT properties are 1:1 with the describe outputs — never an invented wrapper.** The response CLT's top-level property names equal the describe's `outputs[].name` set (for `apex`/`sample`, the response class's `@InvocableVariable` field names). A describe with **N sibling outputs** → **N flat properties** (the `GetAccountSummary` example above; `GetLeadsList` → `leadCount`, `leads`, `message`, `status`); a describe with **one output** → **one property named after it** (`GetShipmentDetails` → `shipmentDetailsResponse`, `GetFlightDetails` → `flightInfo`). Do **not** collapse several sibling outputs into one lone property such as `leadsListResponse` — that key appears in no describe output and is unresolvable under `action` (the response-class name is never in `outputs[]`). A single-property response CLT is correct only when the describe itself returns a single output. This is enforced by `clt-reference-integrity` check 5 (`PROP_GROUNDING`).
45
+
46
+ ### Nested-object and list payload fields (a second, additive case)
47
+
48
+ The example above covers a **flat** payload — every `@InvocableVariable` field is a primitive. Some invocable responses instead have a field whose type is **itself an Apex class** — either a single object (e.g. `GetFlightDetailsAction.FlightDetailsResponse.flightInfo`, typed `SearchFlightsAction.Flight`) or a **list** of them (e.g. the `GetShipmentDetails` wrapper's `shipmentDetailsResponse.statusUpdates`, typed `List<StatusUpdateResponse>`). All three shapes — flat, single-object, list-of-objects — are in scope; pick the branch per field. In every case:
47
49
 
48
- The example above covers a **flat** payload — every `@InvocableVariable` field is a primitive. Some invocable responses instead have a field whose type is **itself an Apex class** (e.g. `GetFlightDetailsAction.FlightDetailsResponse.flightInfo`, typed `SearchFlightsAction.Flight`). Both shapes are in scope; pick the branch per field:
50
+ - **Never** type the property as a bare `{"type":"object"}` (opaque, unrenderable, and not what deploys) and **never** inline it as a nested `lightning__objectType` (rejected by the CLT metaschema, same as the envelope↔response relationship below).
51
+
52
+ #### Single nested object
49
53
 
50
- - **Never** type that property as a bare `{"type":"object"}` (opaque, unrenderable, and not what deploys) and **never** inline it as a nested `lightning__objectType` (rejected by the CLT metaschema, same as the envelope↔response relationship below).
51
54
  - **Do** type it as `"@apexClassType/<ns>__<OuterClass>$<InnerClass>"` — e.g. `"lightning:type": "@apexClassType/c__SearchFlightsAction$Flight"` — exactly the Apex-backed-CLT convention `platform-custom-lightning-type-generate` already documents for `@apexClassType/namespace__ClassName$InnerClass`.
52
- - The **widget** and **renderer** then flatten through it — see the nested-binding note at the end of the "Default renderer" section below, and the full walkthrough in `examples/nested-object-source-prompt.md`.
53
- - A field typed `List<ApexClass>` (a list of nested objects) is out of scope for the beta single-response flow — surface it in the build plan rather than emitting a schema for it, the same way a `maxOccurs > 1` scalar is surfaced.
55
+ - The **widget** and **renderer** then flatten through it — see the nested-binding note at the end of the "Default renderer" section below, and the full walkthroughs in `examples/nested-object-single-source-prompt.md` (single object) and `examples/nested-object-list-source-prompt.md` (lists).
54
56
 
55
57
  ```json
56
58
  {
@@ -69,6 +71,61 @@ The example above covers a **flat** payload — every `@InvocableVariable` field
69
71
  }
70
72
  ```
71
73
 
74
+ #### List of nested objects
75
+
76
+ A `List<ApexClass>` field (an Actions-API output with `apexClass` set and `maxOccurs > 1`, or an `@InvocableVariable List<Inner>` in source) is **in scope** — a real, renderable, boundary-crossing field. It is NOT out of scope for the beta: the `content[]` single-response limit governs how many tool *results* render (one), not list *fields* inside that one result. Render it as a collection; never drop it silently.
77
+
78
+ > **A list is bindable in whichever position the describe returns it — never reshape the Apex to move it.** Two positions occur, and both bind directly: (a) a **top-level list output** — the describe returns the list as its own output entry (`apexClass` set, `maxOccurs > 1`, e.g. a flat `GetLeadsList` whose `leads` output is `maxOccurs: 2000`); the response CLT types that property **directly** as `@apexClassType/c__<Outer>$<ElementClass>` and the renderer binds it at two segments, `{!$attrs.outputValues.<listField>}`. (b) a **list inside a single wrapper object** — the describe returns ONE output (`apexClass`, `maxOccurs: 1`, e.g. `GetShipmentDetails` → `shipmentDetailsResponse`) whose class *contains* the list (`statusUpdates`); the renderer binds it at three segments, `{!$attrs.outputValues.<wrapper>.<listField>}`. See "Top-level list vs list-inside-wrapper" below. In neither case does the CLT declare a `lightning__listType`/`items` — the list-typed property is always a plain `@apexClassType/...` reference.
79
+
80
+ The rule is that **a list-typed CLT property is always a plain `@apexClassType/...` reference — the object-based response CLT never declares the list as a `lightning__listType` property itself.** The `@apexClassType` describe layer resolves the list and its element type; the list surfaces as a `lightning__listType` in the *widget* schema, not the CLT. Which class the reference names, and how deep the renderer binds, depend on the list's **position in the describe** (see "Top-level list vs list-inside-wrapper" below). Concretely:
81
+
82
+ - **Response CLT:** the list-typed property is a plain `@apexClassType` reference (never a `lightning__listType`, never `items`). For a **top-level list output** (flat `GetLeadsList` → `leads`, `maxOccurs: 2000`) the property names the **element** class directly — `leads → @apexClassType/c__GetLeadsList$LeadSummary` — and the CLT carries that property itself. For a **list inside a wrapper** (`GetShipmentDetails` → `shipmentDetailsResponse`) the CLT carries the **wrapper** property — `shipmentDetailsResponse → @apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse` — and the `List<StatusUpdateResponse>` lives inside that class (discovered by reading it, not from the describe). Either way the CLT gets **no** `lightning__listType` property.
83
+ - **Renderer:** bind the list at the depth its position dictates (NOT `.<leaf>` in either case): `{!$attrs.outputValues.<listField>}` (two segments) for a **top-level list output** (e.g. `{!$attrs.outputValues.leads}`), or `{!$attrs.outputValues.<objectField>.<listField>}` (three segments) for a **list inside a wrapper** (e.g. `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`). This bridges the envelope to the widget's flat `{!$attrs.<listField>}`.
84
+
85
+ How the widget bundle surfaces the list (its `lightning__listType` + `items` schema property) and iterates the items is authored and validated by `platform-widget-generate` — not by this skill.
86
+
87
+ Deployed response CLT (the list is NOT here — it rides inside the `@apexClassType` object):
88
+
89
+ ```json
90
+ {
91
+ "title": "Get Shipment Details Response",
92
+ "description": "Payload fields returned by the GetShipmentDetails invocable action",
93
+ "type": "object",
94
+ "lightning:type": "lightning__objectType",
95
+ "lightning:tags": ["mcp"],
96
+ "unevaluatedProperties": false,
97
+ "properties": {
98
+ "shipmentDetailsResponse": {
99
+ "title": "Shipment Details Response",
100
+ "lightning:type": "@apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse"
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ Deployed renderer binding (list bound one level through the object; the widget iterates the items):
107
+
108
+ ```json
109
+ { "statusUpdates": "{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}" }
110
+ ```
111
+
112
+ The widget schema property for the list (`lightning__listType` + `items`) and the widget body that iterates it are authored by `platform-widget-generate`.
113
+
114
+ #### Top-level list vs list-inside-wrapper (which position the describe returns the list in)
115
+
116
+ **The describe is the source of truth, and the list is renderable in whichever position it returns — never touch the Apex to move it.** Two positions occur in practice. They differ ONLY in renderer binding depth:
117
+
118
+ | Position | Actions describe `outputs` | Response CLT list property | Renderer binding |
119
+ |---|---|---|---|
120
+ | **Top-level list output** (e.g. flat `GetLeadsList`) | The list is its **own** output entry — `apexClass` set, `maxOccurs > 1` (e.g. `leads` → `apexClass: GetLeadsList$LeadSummary`, `maxOccurs: 2000`), beside sibling scalars | `leads` → `@apexClassType/c__GetLeadsList$LeadSummary` (the **element** class) | **Two segments:** `{!$attrs.outputValues.leads}` |
121
+ | **List inside a wrapper** (e.g. `GetShipmentDetails`) | ONE output — `shipmentDetailsResponse` · `apexClass` set · `maxOccurs: 1`; the list is a field **inside** that class (`statusUpdates`), which the describe does NOT surface | `shipmentDetailsResponse` → `@apexClassType/c__GetShipmentDetails$GetShipmentDetailsResponse` (the **wrapper** class; the list is discovered by reading it) | **Three segments:** `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}` |
122
+
123
+ **A top-level `@apexClassType` list binds directly.** A response CLT that types a top-level list property directly as `@apexClassType/c__<Outer>$<ElementClass>`, with an envelope whose renderer binds `{!$attrs.outputValues.<listField>}` (two segments, no wrapper hop), is a valid, deployable shape. There is no need for — and the skill must not perform — any Apex reshaping (no wrapper class, no `List<Wrapper>` return-type change) to render a top-level list. The Apex is never modified by this skill.
124
+
125
+ **Typing facts:**
126
+ - A response CLT list property **must** be a plain `@apexClassType/c__<Outer>$<ElementClass>` reference. Typing it as `lightning__listType` with an `items` element type is **rejected** by the CLT metaschema (*"You can't add the items property … because the `unevaluatedProperties` keyword value is set to false"*). `items`/`lightning__listType` belong to the **widget** schema only.
127
+ - The binding depth is dictated purely by the list's position in the describe (two segments for a top-level output, three for a list inside a wrapper) — not by any transform you apply.
128
+
72
129
  ## Envelope CLT
73
130
 
74
131
  Object-based CLT that mimics the tool-result envelope. `outputValues` is typed to the response CLT via the referenced-CLT pattern `c__<responseCLT>` — **not** inlined as a nested `lightning__objectType` (nested object typing is rejected by the CLT metaschema; see `platform-custom-lightning-type-generate`).
@@ -91,7 +148,7 @@ Object-based CLT that mimics the tool-result envelope. `outputValues` is typed t
91
148
 
92
149
  - The `c__<responseCLT>` string is the referenced type's **registered identifier / FQN**, not its `title`. It must match the response CLT's deployed name.
93
150
  - The response CLT must be deployed **before** the envelope CLT.
94
- - Include only the envelope scalars the widget or the platform needs (`actionName`, `isSuccess`, and `outputValues` at minimum). Add `message` etc. only when rendered.
151
+ - Include only the envelope scalars the widget or the platform needs (`actionName`, `isSuccess`, and `outputValues` only). Add `message` etc. only when rendered. `outputValues` is the load-bearing field the renderer bridges through; the widget renders the payload under it, never the envelope metadata (`actionName`/`isSuccess`).
95
152
 
96
153
  ## Default renderer (in the ENVELOPE CLT)
97
154
 
@@ -117,7 +174,13 @@ The renderer is the **default `renderer.json` at the envelope CLT bundle root**,
117
174
 
118
175
  **The binding path is the crux:** each widget attribute (left, flat) maps to the response field nested under the envelope's `outputValues` node (right) via `{!$attrs.outputValues.<field>}`. Because the envelope CLT's `outputValues` is typed to the response CLT, the runtime can resolve `outputValues.<field>` against the response CLT's `properties`.
119
176
 
120
- **Nested-object response fields bind one level deeper.** When a response field is itself an Apex-class reference (the `flightInfo` case above), the widget flattens to that class's own leaf fields, and the renderer binding goes two levels deep: `{!$attrs.outputValues.flightInfo.flightId}`, `{!$attrs.outputValues.flightInfo.origin}`, etc. — `outputValues.<objectField>.<leaf>`, not `outputValues.<objectField>` alone (which would bind the widget to an unresolvable object, not a renderable leaf).
177
+ **Nested-object response fields bind one level deeper.** When a response field is itself a single Apex-class reference (the `flightInfo` case above), the widget flattens to that class's own leaf fields, and the renderer binding goes two levels deep: `{!$attrs.outputValues.flightInfo.flightId}`, `{!$attrs.outputValues.flightInfo.origin}`, etc. — `outputValues.<objectField>.<leaf>`, not `outputValues.<objectField>` alone (which would bind the widget to an unresolvable object, not a renderable leaf).
178
+
179
+ **List-of-object response fields bind the list, not the leaves — at a depth set by the list's position.** A `List<ApexClass>` returned as a **top-level output** (flat `GetLeadsList` → `leads`) binds at two segments — `{!$attrs.outputValues.leads}`. A `List<ApexClass>` that lives **inside a wrapper object** (`GetShipmentDetails` → `shipmentDetailsResponse.statusUpdates`) binds at three — `{!$attrs.outputValues.shipmentDetailsResponse.statusUpdates}`. Do NOT append `.<leaf>` to the list binding in the renderer — there is no single leaf to bind at the list level; the widget (authored by `platform-widget-generate`) iterates the list and renders each item's leaves. The renderer binding depth is set by the describe position.
180
+
181
+ > **The list binding must still go through the renderer's `outputValues` path.** A common failure is a widget that iterates the list correctly but whose *renderer* binds the list flat — `"leads": "{!$attrs.leads}"` instead of `"leads": "{!$attrs.outputValues.<wrapper>.leads}"`. The flat renderer binding resolves against the envelope root, where the payload does not live, so the widget renders "No data available" even though the widget body is correct. Every list is wired through the `outputValues` bridge.
182
+
183
+ > **A renderer attribute CAN bind a top-level `@apexClassType` list directly.** The bindable right-hand paths are: a primitive (`outputValues.<field>`), a **top-level `@apexClassType` list** (`outputValues.<listField>`, e.g. `outputValues.leads` — two segments), or a leaf/list reached *through* one `@apexClassType` wrapper (`outputValues.<wrapper>.<leaf>` / `outputValues.<wrapper>.<listField>` — three segments). There is no "top-level `@apexClassType` list is unbindable" constraint, and the skill must never reshape the Apex to a wrapper to render a top-level list. Bind at the depth the describe's position dictates and leave the Apex untouched.
121
184
 
122
185
  ## Why two CLTs and not one
123
186