All AEM as a Cloud Service skills: component development, Workflow model design, development, triggering, launchers, debugging, and triaging, Dispatcher config authoring, advisory, incident response, performance tuning, and security hardening, Rapid Development Environment (RDE) deployment, log inspection, snapshots, and troubleshooting via `aio aem rde`, Jackrabbit Oak query/index tuning (property, Lucene index definitions), and extracting/inventorying JCR queries (XPath, SQL2, QueryBuilder) across a codebase.
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Converts dialog/ (jcr:primaryType=cq:Dialog) to _cq_dialog/. Design dialog: design_dialog/ → _cq_design_dialog/. Only for action: convert-extjs components from confirmed .migration/lui-dialog-context.yml.
existingBackup: false (or user confirmed re-conversion).needs-user-confirm resolved.hasListeners: true — read Listeners section first.hasOptionsProvider: true — read optionsProvider section first.Node names (JCR keys) are preserved — they are authored content property names.
| Classic xtype | Coral 3 sling:resourceType | Notes |
|---|---|---|
textfield / editfield | granite/ui/components/coral/foundation/form/textfield | defaultValue → value; emptyText same |
textarea | granite/ui/components/coral/foundation/form/textarea | rows direct |
htmleditor / richtext | cq/gui/components/authoring/dialog/richtext | Add useFixedInlineToolbar="{Boolean}true"; preserve RTE plugin config sub-nodes |
checkbox | granite/ui/components/coral/foundation/form/checkbox | inputValue → value; add uncheckedValue="false" if absent |
selection (type=select or omitted) | granite/ui/components/coral/foundation/form/select | <options> → <items>; each option: text+value; see optionsProvider section |
combobox | granite/ui/components/coral/foundation/form/autocomplete | If free-form input required: add forceSelection="{Boolean}false"; else use select — confirm with user |
selection (type=radio) | granite/ui/components/coral/foundation/form/radiogroup | Same <options> → <items> |
pathfield / browsefield | granite/ui/components/coral/foundation/form/pathfield | rootPath direct; default /content |
smartfile | cq/gui/components/authoring/dialog/fileupload | Add useHTML5="{Boolean}true", uploadUrl="${suffix.path}"; mimeTypes → [image/jpeg,...] |
numberfield | granite/ui/components/coral/foundation/form/numberfield | minValue → min, maxValue → max; drop allowDecimals/allowNegative |
datefield | granite/ui/components/coral/foundation/form/datepicker | Add displayedFormat="MMMM DD, YYYY" and valueFormat="YYYY-MM-DD[T]HH:mm:ss.000Z" |
multifield | granite/ui/components/coral/foundation/form/multifield | Single sub-field: simple; multiple sub-fields: composite="{Boolean}true" + child node named field with sling:resourceType="granite/ui/components/coral/foundation/container" containing an <items> node; see namePrefix section and composite template below |
dialogfieldset | granite/ui/components/coral/foundation/form/fieldset | Recurse into children |
tabpanel (root) | granite/ui/components/coral/foundation/tabs + maximized="{Boolean}true" | See structure templates |
panel (tab) | granite/ui/components/coral/foundation/container + margin="{Boolean}true" | title → jcr:title |
hidden | granite/ui/components/coral/foundation/form/hidden | value direct |
colorfield | granite/ui/components/coral/foundation/form/colorfield | defaultValue → value |
tags / tagsfield | cq/gui/components/coral/common/form/tagfield | rootPath direct |
label / static | granite/ui/components/coral/foundation/form/text | text → value |
userpicker | cq/gui/components/coral/common/form/userpicker | rootPath direct |
button | granite/ui/components/coral/foundation/form/button | text → text; drop handler |
dialogbuttons | — | Drop silently — Touch UI renders OK/Cancel automatically |
Unknown xtype: Stop. Report xtype and path. Ask user for Coral 3 equivalent. Never guess.
rootPath sanitization: When copying rootPath from a Classic widget to the Coral 3 field, apply before writing:
/libs/ prefix — /libs/foundation/... paths are internal AEM paths that are not valid picker roots in Touch UI. Replace with the correct project-relative path (ask user if unclear) or omit the property to use the default.// sequences with / (typos and concatenation artifacts in legacy configs cause broken picker navigation).Example: rootPath="/libs//content/dam" → rootPath="/content/dam".
| Classic jcr:primaryType | Coral 3 | Node name |
|---|---|---|
cq:Dialog | nt:unstructured | root (becomes _cq_dialog/.content.xml) |
cq:WidgetCollection | nt:unstructured | rename to items |
cq:Widget | nt:unstructured | preserve widget node name |
| Classic property | Coral 3 | Action |
|---|---|---|
fieldLabel | fieldLabel | Keep |
name | name | Keep exactly — maps to JCR property names on authored content |
fieldDescription | fieldDescription | Keep |
required | required | Keep; ensure {Boolean}true syntax |
disabled | disabled | Keep |
cls | granite:class | Rename |
xtype | — | Drop |
jcr:primaryType | nt:unstructured | Replace on all nodes |
hideLabel | — | Drop |
width / height | — | Drop |
vtype | — | Drop; see Validation Migration note |
allowBlank | — | String "false" → required="{Boolean}true"; else drop |
regex / regexText | — | Drop; see Validation Migration note |
handler | — | Drop; see Listeners section |
Validation Migration note: vtype, regex, regexText, allowBlank validation must be reimplemented via a Coral 3 dialog clientlib using the foundation-validation framework. Flag each dropped validation property in the report.
Classic UI <listeners jcr:primaryType="nt:unstructured"> nodes contain JavaScript callbacks with no Touch UI equivalent. Never copy into _cq_dialog.
listeners nodes from source dialog/.<componentRoot>/_cq_dialog.listeners-review.md — list each node path and event properties._cq_dialog.listeners-review.md. Migrate to Granite UI dialog clientlib."optionsProvider on a selection widget means options are loaded dynamically from a Sling servlet. Coral 3 uses a datasource child node.
select shell with empty <items>.sling:resourceType must point to a Sling component whose GET handler returns application/json items (the developer implements this). Do not use servletPath — it is not a standard Granite UI datasource property:<datasource
jcr:primaryType="nt:unstructured"
sling:resourceType="NEEDS-DEVELOPER-REVIEW"/>
<!-- Original optionsProvider value: <optionsProvider value> — use as reference when implementing the datasource servlet -->optionsProvider (original value recorded above). Datasource shell created — developer must implement a Sling datasource component at the sling:resourceType."Classic namePrefix="./foo/" → Coral 3 composite multifield name="./foo" on the field container. Child field names are preserved. Report the mapping for developer verification.
Use when the Classic multifield contains more than one sub-field. The child container must be named field:
<myMultifield jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
composite="{Boolean}true"
fieldLabel="<label>">
<field jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- converted sub-fields, each with their own name="./propName" -->
</items>
</field>
</myMultifield>For a single sub-field multifield, omit composite and place the sub-field directly as <field .../> with the appropriate sling:resourceType.
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="<from source cq:Dialog jcr:title>"
sling:resourceType="cq/gui/components/authoring/dialog">
<content jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- converted fields -->
</items>
</column>
</items>
</content>
</jcr:root><content jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<tabs jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs"
maximized="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<tab1 jcr:primaryType="nt:unstructured"
jcr:title="<panel title>"
sling:resourceType="granite/ui/components/coral/foundation/container"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<columns jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- converted fields -->
</items>
</column>
</items>
</columns>
</items>
</tab1>
</items>
</tabs>
</items>
</content>dialog/.content.xml. Collect and set aside listeners nodes — write sidecar.xtype=tabpanel → tabbed, else flat.cq:WidgetCollection → nt:unstructured items; apply widget + property mapping; convert <options> → <items>; apply namePrefix; handle optionsProvider; drop dialogbuttons. Sanitize path property values (rootPath, pickerSrc, or any property whose value starts with /): strip a leading /libs/ prefix and collapse any // double-slash sequences to /._cq_dialog/.content.xml. If _cq_dialog/ exists: rename to _cq_dialog.coral2/ first.dialog/ → dialog.bak/. For design dialog: design_dialog/ → design_dialog.bak/; write output to _cq_design_dialog/.content.xml. Skip design dialog if skipReason: editable-templates-in-use.filter.xml — add excludes:<exclude pattern=".*/dialog\.bak(/.*)?"/>
<exclude pattern=".*/_cq_dialog\.coral2(/.*)?"/>
<exclude pattern=".*/_cq_dialog\.listeners-review\.md"/>.bak, then exclude from filter.xml.listeners nodes — sidecar only.name values exactly._cq_dialog must be jcr:primaryType="nt:unstructured"._cq_design_dialog/ (not design_dialog/).dialogbuttons is always dropped silently — never treated as unknown..tessl-plugin
skills
aem-rde
aem-workflow
code-assessment
content-distribution
create-component
assets
references
dispatcher
incident-response
references
dispatcher-foundation
performance-tuning
references
dispatcher-foundation
security-hardening
references
dispatcher-foundation
technical-advisory
references
dispatcher-foundation
workflow-orchestrator
references
dispatcher-foundation
ensure-agents-md
references
migration
references
dispatcher
legacy-ui
template-modernization
validation
scripts
dispatcher-tool
validate-migration