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
The single, authoritative procedure for adding a new code-assessment pattern (a new expert skill).
Follow it top to bottom; every step is concrete. The parent ../SKILL.md and
../scripts/README.md point here — this file is the source of truth.
A detectable code issue with a deterministic detector and a remediation recipe. Each pattern is bound together by one kebab-case slug used identically in four places:
pattern() return value (registered in scripts/analyzer/Registry.all())<slug>/)patterns.md../SKILL.md)The harness [wiring] test fails if these drift apart — so keep the slug identical everywhere.
mechanical — a deterministic single edit (e.g. swap an annotation, bump a version literal).guided — judgment or multiple variants (e.g. the correct API differs by library).scripts/analyzer/detectors/)Create a new file scripts/analyzer/detectors/YourDetector.java implementing the Detector interface:
package analyzer.detectors;
import analyzer.Corpus;
import analyzer.Detector;
import analyzer.Finding;
import analyzer.JavaUnit;
public final class YourDetector implements Detector {
public String pattern() { return "<slug>"; }
// Override needsJava()/needsPoms() (both default true) to declare which corpus
// types this detector consumes — a single-pattern run then parses only what it needs.
// e.g.: public boolean needsPoms() { return false; } // Java-only detector
public void detect(Corpus c, List<Finding> out, List<String> warnings) {
for (JavaUnit u : c.java) {
new TreePathScanner<Void, Void>() {
// override the visit* methods for the node types you care about
// (visitClass, visitMethod, visitVariable, visitMethodInvocation, visitNewClass,
// visitForLoop, visitTry, visitSynchronized, ...)
}.scan(u.cu, null);
}
}
}needsJava() and/or needsPoms() (both default true)
to declare which corpus types this detector consumes. A single-pattern run parses only what
the enabled detectors need — a Java-only detector should return false from needsPoms(),
and a pom-only detector should return false from needsJava().hasAnnotation(mods, simple, fqn, u) (import-aware),
JavaUnit.lineOf(tree), JavaUnit.snippetOf(tree), simpleName(fqn). Need to inspect the
enclosing method/class (scope checks)? Add a small shared helper that walks getCurrentPath()
up to the enclosing MethodTree/ClassTree — promote it once, reuse across detectors.c.poms — each entry is a PomUnit (parsed Document + lines).
See OutdatedDependencies for the pattern (getElementsByTagName, childText, underAny, line
lookup). Reuse analyzer.util.Poms (childText/underAny/findLine/isReactorVersion);
do not re-parse the pom.out.add(new Finding(pattern(), u.rel, line, snippet)). The shape {pattern, file, line, snippet} is fixed — do not change it.Set<Long>).new YourDetector() to Registry.all() in scripts/analyzer/Registry.java.Verify in isolation (from repo root): bash plugins/aem/cloud-service/skills/code-assessment/scripts/analyze.sh plugins/aem/cloud-service/test/code-assessment/fixtures/<slug> --pattern <slug>.
plugins/aem/cloud-service/test/code-assessment/)fixtures/<slug>/ with at least: one antipattern file (must be flagged) and one
clean / negative file (must NOT be flagged). Add edge cases (import-aware collisions, scope
suppression, etc.) as needed.plugins/aem/cloud-service/test/code-assessment/run-tests.sh immediately before the echo "----" summary:echo "[<slug>] <what it checks>"
OUT="$(run "$FIX/<slug>")"
assert_contains "antipattern flagged" "$OUT" '"pattern":"<slug>"'
assert_contains "expected file present" "$OUT" 'Antipattern.java'
assert_absent "clean file not flagged" "$OUT" 'Clean.java'bash plugins/aem/cloud-service/test/code-assessment/run-tests.sh.references/patterns.md: flip the planned row (or add a new one) to:
| [`<slug>`](../<slug>/SKILL.md) | <one-line description> | high|medium|low | ready | analyzer | mechanical|guided |../SKILL.md Manual Pattern Hints: add a row mapping user phrasings → <slug>/SKILL.md.
Description: leave the parent description alone unless the pattern introduces a domain
keyword it does not already cover (see the note in ../SKILL.md "Adding a new pattern"). Triggering
scales via Hints + catalog rows, not description edits.
<slug>/SKILL.md + recipe.md)Author from _template.md:
<slug>/SKILL.md — Overview; Classification (confirm it applies); Discovery (state the analyzer
command + the detector's match criteria); Resolution contract (self-evident | user-supplied |
guided); Review checklist; Recipe pointer; Handoff (runbook reference).<slug>/recipe.md — locator from the finding; the edit(s); mechanical = one deterministic
edit, guided = per-variant remediation; Unlocatable / skip reasons (exact strings the runbook
records); before/after example; editing strategy (surgical, preserve formatting).bash plugins/aem/cloud-service/test/code-assessment/run-tests.sh # your block + [wiring] green
npm run validate # exit 0[wiring] confirms detector ↔ expert dir ↔ ready+analyzer catalog row are all in sync.
detector.pattern() == <slug>/ directory == patterns.md ready+analyzer row == Manual Pattern Hints rowIf any of these is missing or misnamed, [wiring] fails the test suite. That is the guardrail that
keeps a growing catalog consistent.
JavacTask.analyze()), no classpath, no network.
Match on written names, annotations, calls, keywords, structure. Patterns needing deep semantic
analysis are out of scope by design.*.java / pom.xml) — also extend collect() and the detector signature;
see ../scripts/README.md. For Java/pom patterns no engine change is needed.analyzer/detectors/; register it in
Registry.all(). analyze.sh recompiles the package automatically on source change (the
compile cache is keyed on a hash of all analyzer/ sources). No manual build step..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