| name | aem-init |
| description | Configure AEM-specific settings for the dx workflow. Detects AEM project structure, component paths, and brands. Appends aem section to .ai/config.yaml. Run after /dx-init. |
| when_to_use | Use when setting up AEM-specific dx configuration for the first time, after /dx-init, when the user says 'configure AEM', 'set up AEM workflow', or 'initialize AEM settings'. |
| argument-hint | (no arguments — interactive) |
| allowed-tools | ["read","edit","search","write","agent","AEM/*","playwright/*"] |
You configure AEM-specific settings by detecting the project structure and appending an aem: section to .ai/config.yaml.
Re-run Validation Protocol
CRITICAL: When aem-init is re-run, EVERY step MUST execute. NEVER stop early. If the user chooses "Keep as-is" for config, skip to step 6 and continue through ALL remaining steps (6→7→8→9). Each step validates:
| File Category | Re-run Behavior |
|---|
| Config (aem: section in config.yaml) | Ask: keep / modify / regenerate |
| Component index (.ai/project/component-index.md) | Offer to re-scan if stale |
| Component discovery (.ai/project/component-discovery.md) | Offer to re-scan if stale (AEM dialog changes on QA) |
| Shared rule extensions (pr-review.md, pr-answer.md AEM sections) | Validate sections exist, re-append if missing |
| Rule templates (.claude/rules/be-.md, fe-.md) | Compare against plugin template → if template changed and user hasn't customized: update. If user customized: show diff, ask |
| Copilot instructions | Read from .claude/rules/ via COPILOT_CUSTOM_INSTRUCTIONS_DIRS — no copies needed |
| Copilot agents (.github/agents/AEM*.md) | Compare against plugin template → update silently if changed |
Inline execution from dx-init: When this skill is run inline from /dx-init step 7 (AEM auto-chain), skip Copilot-related steps: 8a (Copilot question), 8e (AEM Copilot agent templates), and 8f (copilot-instructions.md update). Also skip step 9 (Confirm). These are handled by dx-init steps 9 and 10 instead. Set COPILOT_ENABLED=false as default — dx-init handles Copilot output separately.
1. Check Prerequisites
Check if .ai/config.yaml exists. If not: "Run /dx-init first to set up the base project config."
Check if .ai/config.yaml already has an aem: section:
- If it exists: Display current AEM config and ask: "AEM config already exists. (A) Keep as-is, (B) Modify, or (C) Regenerate?"
- If A: Say "Config kept. Validating all AEM files..." — then CONTINUE to step 6 to validate component index, rules, and templates. DO NOT stop or exit.
- If B/C: Continue to step 2
- If it doesn't exist: Continue to step 2.
2. Detect AEM Structure
2a. Find Component Path
Search for AEM component definitions using Glob (no Bash needed):
Glob: "**/jcr_root/apps/*/components/*/.content.xml"
From the results, extract:
- Component namespace — e.g.,
/apps/myproject/components/content/
- Component prefix — e.g.,
myproject from path patterns
- Component group — from
componentGroup in .content.xml files
2b. Detect Module Structure
Look for AEM Maven modules:
| Check | Module Type |
|---|
*-core/pom.xml with bundle packaging | Java/OSGi bundle |
*-apps/pom.xml with content-package | HTL + dialogs |
*-clientlibs*/pom.xml or frontend/ | Frontend build |
*-config*/pom.xml | Configuration |
*-all*/pom.xml | Deployable container |
2c. Detect Frontend Structure
Look for frontend source locations using Glob (no Bash needed):
Glob: "*/frontend/"
Glob: "**/ui.frontend/"
Glob: "**/clientlib.config.js"
Glob: "**/clientlibs/**/.content.xml"
2d. Detect Brands (multi-brand)
Look for brand directories using Glob (no Bash needed):
Glob: "**/brands/clientlibs/*/"
3. Ask AEM URLs
Ask all four URLs. Author = content editing and dialog testing. Publisher = user-facing website rendering. These are always different instances.
**AEM Author URL (local dev)?** Content editing, dialog testing, component configuration. (default: http://localhost:4502)
**AEM Publisher URL (local dev)?** User-facing website rendering. (default: http://localhost:4503)
**Remote Author URL (QA/stage)?** For clickable author links in research output. (leave blank to use dev URL)
**Remote Publisher URL (QA/stage)?** For user-facing verification on QA environment. (leave blank to use dev URL)
4. Confirm
Present detected values:
## Detected AEM Configuration
| Property | Value |
|----------|-------|
| Component Path | `/apps/<prefix>/components/content/` |
| Component Prefix | `<prefix>` |
| Component Group | `<group>` |
| Resource Type Pattern | `<prefix>/components/content/<name>` |
| Java Package | `<package>` (if detected) |
| Frontend Dir | `<path>` |
| Brands | <list or "single-brand"> |
| AEM Author (Dev) | `http://localhost:4502` |
| AEM Publisher (Dev) | `http://localhost:4503` |
| AEM Author (QA) | `<url or "same as dev">` |
| AEM Publisher (QA) | `<url or "same as dev">` |
**Correct?** Type "yes" or tell me what to change.
5. Append to Config
Append aem: section to .ai/config.yaml:
aem:
component-path: "/apps/<prefix>/components/content"
component-prefix: "<prefix>"
component-group: "<group>"
resource-type-pattern: "<prefix>/components/content/<name>"
java-package: "<package>"
frontend-dir: "<path>"
brands: [<list>]
author-url: "http://localhost:4502"
author-url-qa: "<url>"
publish-url: "http://localhost:4503"
publish-url-qa: "<url>"
demo-parent-path: "<path>"
6. Component Discovery
6a. Glob-based Component Index (structural)
Ask: "Scan for existing components and generate .ai/project/component-index.md? This helps /aem-component and /dx-ticket-analyze find files faster."
If yes:
- Glob for all component
.content.xml files under the component path
- Extract: name, title, group, resource type, resourceSuperType
- Write
.ai/project/component-index.md as a lookup table (create .ai/project/ if needed)
6b. AEM MCP Component Discovery (semantic)
Ask: "Query AEM QA for component dialog fields, variants, and pages? This creates .ai/project/component-discovery.md for richer AI planning. Requires AEM QA to be reachable."
If yes:
Prerequisites check:
aem.author-url-qa must be configured. If not: warn "Set aem.author-url-qa in config to enable component discovery." and skip.
- Test AEM QA reachability:
mcp__plugin_dx-aem_AEM__getNodeContent on the component root path. If unreachable: warn "AEM QA not reachable — component-discovery.md skipped. Run /aem-init again when QA is available." and skip.
Discovery logic:
For each component found by Step 6a's Glob scan (scoped to this repo's aem.component-path):
-
Dialog fields — mcp__plugin_dx-aem_AEM__getNodeContent on <component-path>/<name>/_cq_dialog with depth 6. Extract: field name, sling:resourceType (maps to field type), fieldLabel, fieldDescription, required flag.
-
Variants in this repo — Glob sibling directories with same name suffix under the component path. E.g., if component is productcard, check for *-productcard or productcard-* siblings.
-
Variants in other repos — mcp__plugin_dx-aem_AEM__searchContent for components whose sling:resourceSuperType equals this component's resourceType. Cross-reference with repos: section in config.yaml to note owning repo.
-
Pages using component — mcp__plugin_dx-aem_AEM__searchContent by sling:resourceType under the content roots from content-paths.yaml or aem.demo-parent-path parent. Limit to 5 pages.
-
Authored values — For the first page found, mcp__plugin_dx-aem_AEM__getNodeContent on the component instance (depth 4). Extract actual field values to reveal semantic meaning.
Parallelism: Dispatch one Explore agent per ~10 components. Each agent receives the component list, AEM QA URL, and query instructions. Agents use mcp__plugin_dx-aem_AEM__* tools directly.
Output: Write .ai/project/component-discovery.md with format:
# AEM Component Discovery
**Generated:** <date>
**Instance:** <aem.author-url-qa> (QA)
**Repo:** <scm.repo or project name>
**Scope:** <aem.resource-type-pattern>* (<count> components)
## <component-name>
**Resource Type:** <full resource type>
**Owner:** <repo name> (this repo)
**Variants (this repo):** <comma-separated list or "none">
**Variants (other repos):**
- `<variant-name>` → <repo-name> (superType: <this component's resourceType>)
### Dialog Fields
| Field | Type | Label | Description | Required |
|-------|------|-------|-------------|----------|
| <name> | <type> | <fieldLabel> | <fieldDescription> | <yes/no> |
### Sample Authored Values (from <page-path>)
| Field | Value |
|-------|-------|
| <name> | <value or "(empty)"> |
### Pages (<count>)
- <page-path-1>
- <page-path-2>
...
### Cross-Repo Dependencies
- **superType:** <superType resource type> → <repo name> (base)
For brand-override repos: dialog fields note inherited from <base> vs LOCAL (this repo).
Re-run behavior: If .ai/project/component-discovery.md already exists, ask "Re-scan component discovery? (recommended after dialog changes on QA)". If no: keep existing, report "validated (kept existing)".
7. Extend Shared Rules with AEM Patterns
Append AEM-specific focus areas to the shared rules in .ai/rules/ (installed by dx-init). This ensures both local dx skills and automation agents apply AEM review criteria.
Idempotent: check if the section already exists before appending.
7a. Extend pr-review.md
If .ai/rules/pr-review.md exists:
- Read the file and check if it contains
## AEM/Sling Patterns (use Grep tool, not Bash)
- If NOT found, append:
## AEM/Sling Patterns
- Verify Sling Model annotations: correct adaptables, resource types, injection strategies
- Check @Self @Via(ResourceSuperType) delegation patterns
- Validate OSGi service references use proper injection
- Ensure ResourceResolver lifecycle is respected (no leaked resolvers)
## Frontend Patterns
- Check component-loader registration matches class name
- Verify config files externalize DOM selectors and CSS classes
- Check PubSub event usage matches constants from commons/constants/events.js
- Validate SCSS uses @use/@forward (not @import)
7b. Extend pr-answer.md
If .ai/rules/pr-answer.md exists:
- Read the file and check if it contains
## AEM/Sling Patterns (use Grep tool, not Bash)
- If NOT found, append:
## AEM/Sling Patterns
- Understand @Self @Via(ResourceSuperType) delegation
- Understand Sling Model injection strategies
- Know when OSGi service patterns are intentional
## Frontend Patterns
- Understand component-loader registration
- Know config externalization patterns
- Understand PubSub event communication
- SCSS uses @use/@forward (not @import)
If .ai/rules/pr-review.md or .ai/rules/pr-answer.md does not exist, skip and note: "Shared rules not found — run /dx-init first."
8. Copy Convention Templates
Unified convention templates (templates/rules/) contain dual frontmatter (paths: for Claude Code, applyTo: for Copilot CLI). Each template is copied to .claude/rules/. Copilot CLI reads rules from this same location via COPILOT_CUSTOM_INSTRUCTIONS_DIRS env var (set by /dx-init step 9a-bis) — no .github/instructions/ copies needed.
8a. Ask about Copilot support
**Support GitHub Copilot CLI?** (default: yes)
If yes:
- AEM Copilot agent definitions are generated in `.github/agents/`
If no:
- No Copilot agents generated
Set COPILOT_ENABLED=true or COPILOT_ENABLED=false based on the answer.
8b. Create target directories
Ensure .claude/rules/ exists. The Write tool creates parent directories automatically, so no explicit mkdir is needed.
8c. Copy rule templates to .claude/rules/
- Read
project.role from .ai/config.yaml
- Determine which template directories to install:
project.role | Directories |
|---|
frontend | shared/ + fe/ |
backend | shared/ + be/ |
fullstack | shared/ + be/ + fe/ |
config | shared/ only |
| (not set) | All directories (backward compatibility) |
- For each selected directory, Glob template files (no Bash needed):
Glob: "<plugin-path>/templates/rules/<dir>/*.md.template"
- For each template file found:
Derive target filename by stripping the .template suffix (e.g., be-sling-models.md.template → be-sling-models.md).
If .claude/rules/<target> already exists:
Read both the existing file and the plugin template. Compare content:
- Identical: Report "validated (up to date)", skip.
- Template changed, file matches old template: Update silently — the user hasn't customized it.
- User has customized (content differs from template): Show the diff summary and ask: (A) Keep existing, (B) Replace with updated template, (C) Write updated as
.template (user can diff manually).
Check for topic overlap (new files only):
Scan existing .claude/rules/*.md — read their frontmatter (description and paths fields). Compare against the template's paths glob and topic (filename prefix: fe- or be-). If a file with overlapping paths and similar topic exists:
- Show both filenames and their descriptions side-by-side
- Ask: (A) Skip (keep existing), (B) Replace (overwrite with template), (C) Write as
.template (user can diff manually)
No conflict:
Copy the file to .claude/rules/<target>, stripping the .template extension.
- Resolve template variables before writing:
Read from .ai/config.yaml:
| Variable | Config source |
|---|
{{COMPONENT_PREFIX}} | aem.component-prefix |
{{DAM_PATH}} | aem.dam-path |
{{CSS_PREFIX}} | aem.component-prefix (fallback: project.prefix) |
{{BUILD_TOOL}} | toolchain.build-tool |
{{CSS_COMPILER}} | toolchain.css-compiler |
{{NODE_VERSION}} | toolchain.node |
{{COMPONENT_BASE_CLASS}} | toolchain.component-base-class |
{{RESOURCE_TYPE_PATTERN}} | aem.resource-type-pattern |
For each variable, if the config value is empty or missing, leave the placeholder as-is (consumer will fill in or the value is not relevant for this project).
Note: .github/instructions/ copies are no longer generated. Copilot CLI reads rules directly from .claude/rules/ via COPILOT_CUSTOM_INSTRUCTIONS_DIRS env var. Rules with dual frontmatter (paths: + applyTo:) work in both tools from a single source.
8d. (Removed — instruction templates merged into rule templates)
Instruction templates no longer exist as separate files. The unified rule templates in templates/rules/ contain both paths: (Claude Code) and applyTo: (Copilot CLI) frontmatter. Step 8c handles both outputs.
8e. Copy AEM Copilot agent templates (if Copilot enabled)
Only if the user answered "yes" to Copilot support in step 7a.
Use Glob to find agent template files (no Bash needed):
Glob: "<plugin-path>/templates/agents/*.agent.md.template"
For each result:
- Read the template
- Strip the
.template suffix from the filename
- Write to
.github/agents/<AgentName>.agent.md
On re-run: If .github/agents/<target> already exists, compare against the plugin template. Update silently if the template has changed (Copilot agents are not user-customized). Report "validated" or "updated".
8f. Update copilot-instructions.md (if Copilot enabled and file exists)
If .github/copilot-instructions.md exists (generated by /dx-init), append an AEM agents section:
## AEM Agents
| Agent | Purpose | Invoke |
|-------|---------|--------|
| AEMBefore | Pre-development baseline snapshot | `@AEMBefore <component>` |
| AEMAfter | Post-deployment verification | `@AEMAfter <component>` |
| AEMSnapshot | Component inspection | `@AEMSnapshot <component>` |
| AEMDemo | Dialog screenshot + authoring guide | `@AEMDemo <component>` |
| AEMComponent | Find pages using a component | `@AEMComponent <component>` |
| AEMVerify | Bug verification on AEM | `@AEMVerify <component>` |
If the file doesn't exist, skip this step (it means /dx-init didn't generate Copilot files).
8g. Install AEM browser-auth helper (Playwright)
Copy the reusable auth helper so browser agents can authenticate to AEM without the password ever entering the model's context.
- Copy
${CLAUDE_PLUGIN_ROOT}/data/lib/aem-playwright-auth.sh → .ai/lib/aem-playwright-auth.sh (create .ai/lib/ if missing; chmod +x). On re-run, overwrite silently if the plugin version changed.
- Ensure the consumer
.gitignore contains .ai/playwright/ (the helper writes the session cookie + Basic Auth creds there — must never be committed). Append it under the runtime-output block if absent.
- Install the Playwright browser (one-time): the dx-aem
playwright MCP server drives a real Chromium that is NOT bundled — without it, every browser skill (/aem-verify, /aem-qa, /aem-fe-verify, /aem-editorial-guide) fails at first navigation. Run:
npx playwright install chromium
It's idempotent (no-op if already present). If it fails (offline/restricted), tell the user to run it manually before any browser verification.
What it provides (two independent auth layers — see the qa-basic-auth rule):
- AEM author login →
bash .ai/lib/aem-playwright-auth.sh author <local|qa> writes .ai/playwright/aem-author-state.json (a Playwright storageState with the login-token cookie). Browser agents load it via browser_set_storage_state before navigating to the author — no form-fill, no password in context.
- Publisher Basic Auth (opt-in) →
bash .ai/lib/aem-playwright-auth.sh config writes .ai/playwright/config.json with httpCredentials from QA_BASIC_AUTH_*. To use it browser-natively, add "--config", ".ai/playwright/config.json" to the playwright server args in .mcp.json. (Default skills use URL-embedded Basic Auth, which needs no config.)
8h. Report results
### Convention Files
**Rules** (`.claude/rules/`): <N> written, <N> skipped
<If Copilot enabled:>
**Copilot instructions**: read from `.claude/rules/` via `COPILOT_CUSTOM_INSTRUCTIONS_DIRS` (no copies needed)
**Copilot Agents** (`.github/agents/`): <N> written, <N> skipped
9. Confirm
## AEM Initialized
**Component Path:** `<path>`
**Brands:** <list>
**Config:** `.ai/config.yaml` (aem section appended)
### Next Steps
- `/aem-component <name>` — look up a component's files and pages
- `/aem-snapshot <name>` — capture baseline before development
- `/aem-verify <name>` — verify after deployment
10. Project Setup (if seed data exists)
Check if .ai/project/project.yaml exists. If not, print: "No project.yaml found. To add project knowledge, create .ai/project/project.yaml. See docs/authoring/seed-data-guide.md for format." Then skip to step 11.
If project.yaml exists:
10a. Brand/Market Selection
- Read
project.yaml → brands[] list
- For each brand:
- If
single-market: true: auto-confirm this brand and its single market. Report "Auto-confirmed: ()"
- Otherwise: Ask via AskUserQuestion: "Which markets are active for ? Options: . Enter comma-separated codes or 'all'."
- Store selected brands and market codes
10b. Repo Local Paths
- Read existing
repos: from .ai/config.yaml (written by /dx-init)
- Read
repos[] from .ai/project/project.yaml for platform and ado-project data
- For each repo in project.yaml NOT already in config
repos:, add it with name and path (ask: "Local path for ? (default: ../<name>)")
- For each repo in config
repos:, enrich with fields from project.yaml: platform, ado-project
- If
path is missing on any entry, ask: "Local path for ? (default: ../<name>)"
- Ask for
base-branch if not set (default: same as scm.base-branch)
- For each repo in
repos:, if role: is missing or capabilities: is present:
- Ask via AskUserQuestion: "What is 's role? (frontend / backend / fullstack / config)"
- Write
role: to the repo's entry in config.yaml
- If
capabilities: exists on that entry, remove it
10c. Preferences
Ask via AskUserQuestion (one at a time):
- "Auto-commit after each plan step? (y/n, default: n)"
- "Auto-create PR when all steps complete? (y/n, default: n)"
- "Docs repo URL for seed data refresh? (ADO URL or blank)"
10d. Read Defaults
From project.yaml → defaults:
qa-author-url → write to aem.author-url-qa
qa-publish-url → write to aem.publish-url-qa (if present)
10e. Write Project Config
Update top-level repos: section (NOT under aem:):
For each repo, ensure these fields are present:
repos:
- name: <repo>
path: <relative-path>
role: <role>
platform: <platform>
ado-project: <project>
base-branch: <branch>
Remove aem.repos if present (migrated to top-level repos:).
Remove aem.current-repo (redundant — current repo is implicit).
Keep aem.platform (quick self-identification for the current repo).
Append/update these fields in the aem: section of .ai/config.yaml:
aem:
platform: <derived from project.yaml>
active-brands: [<brands>]
active-markets: [<market codes>]
author-url-qa: <url from defaults>
publish-url-qa: <url from defaults>
docs-repo: <url>
auto-commit: <bool>
auto-pr: <bool>
10f. Re-run Behavior
If aem: section already has project config (active-brands, active-markets):
- Ask: "Project config already exists. (A) Keep existing, (B) Update?"
- If A: Skip 10a-10e, continue to step 11
- If B: Run 10a-10e (overwrites project config, preserves other aem: fields)
Migration from aem.repos: On re-run, if .ai/config.yaml has aem.repos: but top-level repos: is missing or incomplete, migrate: copy entries from aem.repos to top-level repos:, mapping local-path → path. Then remove the aem.repos section. Report what was migrated.
11. AEM Rule Template Installation
Copy rule templates from the plugin templates/rules/ directory to .claude/rules/:
audit.md.template → .claude/rules/audit.md (remote change audit rules)
qa-basic-auth.md.template → .claude/rules/qa-basic-auth.md (QA/stage auth credentials)
For qa-basic-auth: the rule now reads credentials from env vars first (QA_BASIC_AUTH_USER etc.), with .ai/config.yaml as legacy fallback. If project.yaml defines defaults.qa-basic-auth, still substitute into the rule template for backward compatibility.
On re-run: Compare existing file against template. If identical: skip. If template changed and user hasn't customized: update silently. If user customized: show diff, ask.
11a. Check AEM Environment Variable
Check if AEM_INSTANCES is already set in the shell environment:
echo "$AEM_INSTANCES"
-
If set: Report: "AEM_INSTANCES detected in shell environment — AEM MCP will use it." Skip to step 12.
-
If not set: Print setup instructions:
AEM MCP requires the AEM_INSTANCES environment variable.
Add to your shell profile (~/.bashrc or ~/.zshrc):
export AEM_INSTANCES="local:http://localhost:4502:admin:admin"
Format: name:url:user:pass (comma-separated for multiple instances).
Then restart your terminal or run: source ~/.zshrc
Alternative: add to .claude/settings.local.json under "env" (Claude Code only, not Copilot CLI).
-
Also update .claude/settings.local.json — add the AEM_INSTANCES key as a placeholder. Do NOT overwrite existing values:
a. If file exists: Merge AEM_INSTANCES into the existing "env" object.
b. If file does not exist: Create it with both base dx env vars and AEM env vars:
{
"env": {
"QA_BASIC_AUTH_USER": "",
"QA_BASIC_AUTH_PASS": "",
"QA_BASIC_AUTH_FALLBACK_USER": "",
"QA_BASIC_AUTH_FALLBACK_PASS": "",
"AXE_API_KEY": "",
"AEM_INSTANCES": "local:http://localhost:4502:admin:admin"
}
}
Report: "Updated .claude/settings.local.json with AEM_INSTANCES. Preferred: set in shell profile for both Claude Code and Copilot CLI."
12. Summary
Run component discovery for best results: The component-discovery.md file (generated in Step 6b) provides dialog field semantics, component variants, and page locations to all downstream skills (/dx-req, /dx-plan, /dx-step). Without it, these skills rely on Glob/Grep only and may miss field meanings and brand-specific variants. Re-run /aem-init after major dialog changes on QA.
## AEM Initialized
**Component Path:** `<path>`
**Brands:** <list>
**Active Markets:** <codes>
**Repos:** <count> configured (<count> with local paths)
**Config:** `.ai/config.yaml` (aem section updated)
### Seed Data Status
| File | Status |
|------|--------|
| component-index.md | <generated / exists / skipped> |
| component-discovery.md | <generated / exists / skipped / QA unreachable> |
| project.yaml | <found / not found> |
| file-patterns.yaml | <found / not found> |
| content-paths.yaml | <found / not found> |
| architecture.md | <found / not found> |
| features.md | <found / not found> |
| component-index-project.md | <found / not found> |
### Next Steps
- `/aem-component <name>` — look up a component's files and pages
- `/aem-refresh` — refresh seed data from docs repo
- `/aem-snapshot <name>` — capture baseline before development
- `/aem-verify <name>` — verify after deployment
Examples
-
/aem-init — First run after /dx-init. Detects ui.frontend/src/core/components/ and ui.frontend/src/brand/components/ directories, identifies brands from the project's component directories, and appends aem: section to .ai/config.yaml with author URL, publisher URL, component paths, and active markets.
-
/aem-init (re-run to update markets) — Detects existing aem: section in config. Asks whether to re-detect or update specific values. User updates active-markets from [gb, de] to [gb, de, fr]. Refreshes seed data files in .ai/project/.
-
/aem-init (with component index scan) — After detecting project structure, asks "Scan AEM for component index?" User confirms. Queries AEM author instance for all components under /apps/, builds component-index-project.md with component names, resource types, and dialog field counts.
Troubleshooting
-
".ai/config.yaml not found — run /dx-init first"
Cause: /aem-init requires the base config created by /dx-init.
Fix: Run /dx-init first to create .ai/config.yaml, then run /aem-init to add the AEM section.
-
Component index scan fails or returns empty
Cause: AEM author instance is not running or not reachable at the configured URL.
Fix: Start AEM locally or verify aem.author-url in .ai/config.yaml. The component index is optional — skip it and run /aem-init again later when AEM is available.
-
Seed data files missing after init
Cause: The plugin's data/ directory doesn't contain seed files for this project, or the copy step was skipped.
Fix: Run /aem-refresh to pull seed data from the docs repo or a local path. Check that .ai/project/ contains project.yaml, file-patterns.yaml, content-paths.yaml, and architecture.md.
Rules
- Interactive — use AskUserQuestion — Every question, confirmation, or choice in this skill MUST use the
AskUserQuestion tool to pause and wait for the user's response. Never proceed past a question without receiving the user's answer first. Present numbered options in the question text, then STOP and wait. Do not batch multiple questions into one message — ask one, wait for the answer, then continue.
- dx-init required first —
.ai/config.yaml must exist before adding AEM config
- Detect first, ask second — auto-detect everything possible
- Append, don't overwrite — add
aem: section to existing config
- Validate on re-run — every step executes on re-run; validate existing files against plugin templates, smart-update what's outdated, ask when in doubt
- Component index is optional — ask before scanning (can be slow for large projects)
- No hardcoded paths — detect from the actual project structure