Platform Custom Lightning Type Generate
Use this skill when users need to create Custom Lightning Types (CLTs) for Einstein Agent actions or structured input/output schemas. Trigger when users mention CLT, Custom Lightning Types, JSON schemas for agents, type definitions, lightning__objectType, or editor/renderer configurations. For widget renditions that combine a CLT with a Widget bundle, use the platform-lightning-type-widget-coordinate orchestrator instead. This is complex - always use this skill for CLT work.
- Skill ID
- forcedotcom/sf-skills/platform-custom-lightning-type-generate
- Publisher
- forcedotcom
- Repository
- sf-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
forcedotcom/sf-skills/platform-custom-lightning-type-generateInstalls these files- SKILL.md
- assets/primitive-types-and-constraints.md
- references/widget-rendition.md
What this skill tells the agent
When to Use This Skill
Use this skill when you need to:
- Create Custom Lightning Types (CLTs) for structured inputs/outputs
- Generate JSON Schema-based type definitions for Lightning Platform
- Configure CLTs for Einstein Agent actions
- Set up editor and renderer configurations for custom UI
- Troubleshoot deployment errors related to Custom Lightning Types
Specification
CustomLightningType Metadata Specification
Overview & Purpose
Custom Lightning Types (CLTs) are JSON Schema-based type definitions used by the Lightning Platform (including Einstein Agent actions) to describe structured inputs/outputs and drive editor/renderer experiences.
Configuration
- Choose referenced CLT pattern for nested objects - When you need a reusable or separately deployed nested type, create a CLT for that shape and reference it with
"lightning:type": "c__<CLTName>". That string is the referenced type’s `lightning:type` value / FQN / registered identifier — not the JSON Schematitle. - Choose standard Lightning types when the structure is simple and can be expressed with properties and supported primitive
lightning:typeidentifiers. - Choose Apex class types (
@apexClassType/...) when the structure already exists server-side and you want the Apex class to define the shape. - Include editor/renderer config only when you need custom UI behavior (custom LWC input/output components). Otherwise, omit.
Critical Rules (Read First)
- CRITICAL: NEVER include the `"$schema"` field in schema.json
- Salesforce CLT validator WILL REJECT schemas with this field, even if it's a valid JSON Schema
$schemadeclaration. - Root object schemas MUST include:
"type": "object""title""lightning:type": "lightning__objectType""unevaluatedProperties": false"unevaluatedProperties"is enforced asfalseby the CLT metaschema. Do not set it totrue.- Root object schemas MUST NOT include
"examples"when"unevaluatedProperties": falseis set. - Nested objects (inside `properties`) MUST NOT set
"lightning:type": "lightning__objectType". - Nested objects can be: references to other CLTs using
c__<CLTName>syntax. - List/array properties are highly restricted by the CLT metaschema:
- CRITICAL LIMITATION: the CLT metaschema may reject the
itemskeyword entirely. Treatitemsas disallowed by default. - Root-level arrays (direct children of the root
properties): - MUST include
"lightning:type": "lightning__listType" - MUST NOT include
"items" - OPTIONAL
"type": "array" - Nested arrays (arrays inside nested objects) are the most common failure:
- MUST include
"type": "array" - MUST NOT include
"lightning:type": "lightning__listType" - MUST NOT include
"items" - When `"unevaluatedProperties": false` is set, any unknown keyword will fail validation. Prefer removing keywords over relaxing strictness.
- Apex class CLTs are minimal:
- Include only
title,description(optional), andlightning:typeset to@apexClassType/.... - Do not add
type,properties,required, orunevaluatedProperties. - Custom LWC renderers/editors on an Apex class CLT MUST NOT use `attributes` in the root override — this overrides any prompt wording to the contrary. Since the schema has no
propertiesblock, there is nothing for{!$attrs.<name>}to resolve against —unevaluatedProperties: falsewill reject any attribute key (e.g."You can't add the flightId property ... because the unevaluatedProperties keyword value is set to false"). Use"componentOverrides": { "$": { "definition": "c/<yourComponent>" } }with no `attributes` key at all. If the user's prompt explicitly asks for attribute mappings to specific fields (e.g. "with attribute mappings for fieldA, fieldB") on an Apex-class CLT renderer/editor, do NOT comply literally — omitattributesfrom the root override anyway, and say so in your response (e.g. "Note: attribute mappings were omitted because the backing type is an Apex-class CLT, which has nopropertiesblock to bind against"). - No shell metacharacters that trigger the Vibes safe-shell filter. In any Bash tool call emitted by this skill, do NOT use command substitution (
$(…)or backticks), process substitution (<(…),>(…)), brace expansion ({a,b,c}or{1..N}), oreval/exec. Vibes forces manual approval on these patterns even under Bypass mode and stalls the eval. Emit separate commands (mkdir -p a && mkdir -p b) or print each value with its own command and reason about the output rather than capturing it in a shell variable.
Additional CLT Metaschema Validations
- Org namespace validation: titles/descriptions and other string fields may be validated to ensure you are not using an org namespace in places that are disallowed.
- Lightning type validation: CLTs are validated to prevent referencing internal namespaces (for example, disallowing types from internal namespaces like
sfdc_cmswhere not permitted). - Object type validation: the CLT root is validated to ensure
lightning:typeis exactlylightning__objectType.
Primitive Types & Constraints
When you need the full list of supported primitive lightning:type identifiers, their constraints, and the allowed property-level keywords, read assets/primitive-types-and-constraints.md in this skill's directory.
Generation Workflow
- Confirm the CLT approach
- If referencing Apex: capture the exact class reference (@apexClassType/namespace__ClassName$InnerClass).
- If using standard primitives: list the fields, their Lightning primitive types, and which fields are required.
- Draft `schema.json`
- DO NOT include `"$schema"` at the top
- Start with the root object structure (required root fields).
- Add
propertiesusing valid primitivelightning:typeidentifiers. - For nested-object properties, use CLT Reference pattern:
"lightning:type": "c__<CLTName>"to reference another CLT- The referenced CLT must be deployed to the org before the parent CLT.
- For Apex-based nested objects: Use
@apexClassType/...when structure exists server-side. - If the prompt explicitly requires true nested object output, prefer an Apex-based CLT (
@apexClassType/...) for deploy-safe nested structures. - For arrays: follow the strict list rules (avoid
items; avoidlightning:typeon nested arrays). - Before deployment, verify exact
lightning:typespellings (for example, uselightning__richTextType, not misspelled variants).
- (Optional) Draft `editor.json` (only if custom UI is required)
- Supported shape: Top-level
editorobject witheditor.componentOverridesandeditor.layout. - Top-level
editorobject. - Use
editor.componentOverridesfor component overrides. - Use
editor.layoutfor layout. - DEPRECATED: Do NOT use
propertyRenderersorview— these are legacy keys. Always usecomponentOverridesandlayoutinstead. - Root override pattern (most common for fully custom editing UI):
editor.componentOverrides["$"] = { "definition": "c/<yourEditorComponent>", "attributes": { ... } }- When passing schema data into a custom LWC, use attribute mapping with the
{!$attrs.<name>}syntax: e.g."attributes": { "myField": "{!$attrs.value}" }so the runtime binds schema values to your component's attributes. - CRITICAL: The
<name>in{!$attrs.<name>}must be a property defined in your type schema. For example, if your schema has a property calledtemperature, use{!$attrs.temperature}, not{!$attrs.value}unlessvalueis an actual property. - Property-level override pattern (for individual fields):
editor.componentOverrides["<propertyName>"] = { "definition": "es_property_editors/<...>" }
More from forcedotcom
Use this skill in a project
Open any RiverX project, search the Skills panel for forcedotcom/sf-skills/platform-custom-lightning-type-generate, and install it in one click.
