dx-adapt

star 6

Auto-detect project type, structure, build commands, and AEM values. Updates .ai/config.yaml with project profile and substitutes real values into installed .claude/rules/. Run after /dx-init and /aem-init. Re-run anytime to refresh detected values.

easingthemes By easingthemes schedule Updated 6/16/2026

name: dx-adapt description: Auto-detect project type, structure, build commands, and AEM values. Updates .ai/config.yaml with project profile and substitutes real values into installed .claude/rules/. Run after /dx-init and /aem-init. Re-run anytime to refresh detected values. when_to_use: "Use when auto-detecting project structure and build commands, when refreshing detected values after restructuring, when the user says 'detect project type', 'update config from project', or 'adapt to this codebase'." argument-hint: "[aem-fullstack|aem-frontend|frontend] (optional — auto-detects if omitted)" disable-model-invocation: true allowed-tools: ["read", "edit", "search", "write", "agent"]

You detect the project's technical profile from source files and update .ai/config.yaml with the project:, toolchain:, and additional build: fields. Then you substitute the detected values into .claude/rules/ files (replacing generic placeholders with real project values).

Use ultrathink — project detection requires reading multiple source files and making accurate inferences.

0. Check Prerequisites

Read .ai/config.yaml. If it doesn't exist: "Run /dx-init first." STOP.

Check if .ai/config.yaml already has a project: section with type field:

  • If no project: section: Go directly to Phase 1. (This is normal on first run or when called from dx-init.)
  • If project: section exists: Display the current values and ask: (A) Keep as-is, (B) Re-detect (re-reads source files), (C) Edit (re-confirm with current values pre-loaded). If A: skip to Phase 4 (rule substitution only).

Phase 1: Detect Project Type

1a. Auto-detect (or use argument)

If the user provided an argument (aem-fullstack, aem-frontend, frontend), use it. Otherwise detect:

Check Type
pom.xml exists AND contains com.adobe.cq or AEM uber-jar dependency aem-fullstack
pom.xml exists AND contains content-package-maven-plugin AND no Java source in src/main/java/ aem-frontend
package.json exists AND contains aem-clientlib-generator or clientlib.config.js exists aem-frontend
package.json exists AND no AEM indicators frontend
Only pom.xml (no AEM) java

1b. Extract details per project type

For aem-fullstack:

# Find Java package root
find . -path "*/src/main/java/*.java" | head -1
# → extract package from first line of that file

# Find component namespace from filter.xml or .content.xml
grep -r "componentGroup" --include="*.xml" -l | head -5

# Find base branch
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'

# Find Maven modules
find . -maxdepth 3 -name "pom.xml" | grep -v "^./pom.xml"

Read 2-3 .content.xml files with componentGroup to extract:

  • componentGroup — the group name string (e.g., "MyProject General")
  • componentPath — derive from the file path (e.g., /apps/myproject/components)
  • componentSelector — from @Exporter annotation in any Java @Model class
  • serviceVendor — from @Component(property = "service.vendor=...") in any Java class
  • dialogPropertyPrefix — check if dialog XML uses ./data/ nesting or ./ directly
  • rteInheritancePath — search for sling:resourceSuperType containing rteConfigs
  • authorPort — from pom.xml properties (default 4502)

Extract build commands from pom.xml and package.json (if frontend submodule exists):

  • build.fullmvn clean install -PautoInstallPackage (with correct -pl if multi-module)
  • build.deploymvn clean install -PautoInstallPackage -DskipTests (quick deploy, no tests)
  • build.compile — frontend compile if package.json submodule exists
  • build.testmvn test -pl <core-module>
  • build.testSinglemvn test -pl <core-module> -Dtest={className}
  • build.lint — from package.json scripts if frontend submodule exists

Extract modules list from child pom.xml files:

find . -maxdepth 3 -name "pom.xml" ! -path "./pom.xml" \
  -exec grep -l "packaging" {} \; | sort

For each, read packaging type: bundle, content-package, jar.

Extract sourceRoots, testRoots, componentPaths from the module paths found.

For aem-frontend:

Read package.json scripts to extract build, lint, test commands. Read webpack/clientlib config to find component output paths. No Java extraction needed — omit aem.javaPackage, aem.componentSelector, etc.

For frontend:

Read package.json for framework, scripts (build, test, lint, dev). Read tsconfig.json if present for TypeScript confirmation. Read directory structure (src/, app/, pages/, components/) for source roots.

1c. Git and SCM details

# Base branch
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'

# Branch prefix from recent branches
git branch -r | grep -E "feature/|bugfix/" | head -5

Read scm.base-branch from .ai/config.yaml as fallback.

Phase 2: Confirm with User

Print all detected values as a table. Ask: "Correct? Type 'yes' or correct any values."

## Detected: <project type>

| Property | Value |
|---|---|
| Project Type | <type> |
| Name | <name from config.yaml> |
| Build (full) | `<command>` |
| Build (compile) | `<command or "—">` |
| Test | `<command>` |
| Test (single) | `<pattern>` |
| Lint | `<command or "none">` |
| Base Branch | <branch> |
| Source Roots | <list> |
| Test Roots | <list> |
| Component Paths | <list> |
<AEM-only rows:>
| Java Package | <package> |
| Component Path | <path> |
| Component Group | <group> |
| Selector | <selector or "—"> |
| Service Vendor | <vendor or "—"> |
| Dialog Property Prefix | <prefix> |
| AEM Author Port | <port> |

Phase 3: Update .ai/config.yaml with project profile

3a. Derive project role

Derive project.role from project.type:

project.type project.role
aem-fullstack fullstack
aem-frontend frontend
frontend frontend
java backend
(other) Ask user to confirm

Confirm with user: "Detected project role: {role}. Is this correct?"

3b. Read existing config.yaml

Read .ai/config.yaml in full. You will append/update sections — never overwrite the entire file.

3c. Update config.yaml sections

Add or update the following sections in .ai/config.yaml. Preserve all existing sections (dx:, scm:, build:, aem:, etc.) — only add/update the fields listed below.

Add project: section (add after dx: section, or update if it already exists):

project:
  type: "{{type}}"           # aem-fullstack | aem-frontend | frontend | java
  role: "{{role}}"           # fullstack | frontend | backend (derived above)

Add toolchain: section (add after project: section):

toolchain:
  node-version: "{{version}}"          # detected from .nvmrc, .node-version, or package.json engines
  build-tool: "{{tool}}"               # webpack | vite | maven | gradle | etc.
  css-compiler: "{{compiler}}"         # sass | less | postcss | none
  component-base-class: "{{class}}"    # e.g. "com.adobe.cq.export.json.ComponentExporter" (AEM only, omit if N/A)

Only include fields that were actually detected. Omit fields with no detected value.

Update build: section — append these granular fields to the existing build: section if detected:

build:
  # ... existing fields (command, test, etc.) stay as-is ...
  serve: "{{command}}"        # dev server command (e.g. "npm run dev")
  lint-js: "{{command}}"      # JS/TS linting (e.g. "npm run lint:js")
  lint-scss: "{{command}}"    # SCSS/CSS linting (e.g. "npm run lint:scss")
  lint-fix: "{{command}}"     # auto-fix linting (e.g. "npm run lint:fix")

Only add fields that were detected from package.json scripts or build configs. Do not add fields with empty values.

Update aem: section — if project type is aem-fullstack or aem-frontend and the aem: section already exists, add/update component-prefix if a prefix was detected (e.g., from component group or path convention). Do NOT duplicate fields that already exist in the aem: section (java-package, component-path, component-group are already managed by /aem-init).

Fields NOT written (derivable from filesystem, dropped per spec): modules, sourceRoots, testRoots, componentPaths, source, output, component.registration.

Print: Updated .ai/config.yaml with project profile

Phase 4: Update Template-Seeded Files

Re-generate files seeded from plugin templates. These are the plugin's responsibility (not user-customized), so they always reflect the latest template.

4a. Regenerate agent.index.md

Read templates/INDEX.md.template from the plugin directory. Replace {{PROJECT_NAME}} with dx.project-name from .ai/config.yaml. Write to agent.index.md (project root). Always overwrite.

4b. Regenerate .ai/README.md

Read templates/README.md.template from the plugin directory. Replace {{PROJECT_NAME}} with the project name. Write to .ai/README.md. Always overwrite.

4c. Re-run scaffold for new static files

Run scaffold.sh to pick up any new rule templates or utilities added since last init:

bash skills/dx-init/scripts/scaffold.sh

Each file is skipped if it already exists — only newly added templates are installed.

Phase 5: Filter and Verify .claude/rules/

5a. Filter rules by project type

Read project.type from .ai/config.yaml.

project.type Action
aem-fullstack Keep all rules. No deletions.
aem-frontend Delete all be-*.md rules in .claude/rules/. Keep fe-*.md, accessibility.md, naming.md.
frontend Delete all be-*.md and fe-clientlibs.md rules. Keep accessibility.md, naming.md.
java Delete all fe-*.md rules. Keep be-*.md, accessibility.md, naming.md.

Use Glob to list matching files, then delete those that don't apply. If no files match the deletion criteria, report "no rules to filter".

5b. Verify project values in rules

Read each .claude/rules/*.md file that was installed from an aem-init template. Verify that project-specific values from .ai/config.yaml are present — not generic placeholders. Check for:

  • Java package name (should match aem.java-package from config.yaml aem: section)
  • Component path (should match aem.component-path from config.yaml aem: section)
  • Component group (should match aem.component-group from config.yaml aem: section)

Other substitution values are read from .ai/config.yaml:

  • project.type, project.role — from the project: section
  • toolchain.* values — from the toolchain: section
  • build.* values — from the build: section

If any file still contains generic examples instead of real project values, substitute them with values from .ai/config.yaml. If a file already has correct project-specific values, skip it silently.

Phase 6: Report

## Project Adapted: <name>

**Type:** <type>
**Role:** <role>
**Config:** `.ai/config.yaml` updated (project + toolchain sections)

### Rules Updated
<list of .claude/rules/ files modified with substitutions made>
<list of files skipped (already customized)>

### Next Steps
- Review `project:` and `toolchain:` sections in `.ai/config.yaml` — edit and re-run `/dx-adapt` if any values need correction
- `/dx-init` — re-run if base config.yaml needs changes
- `/aem-init` — re-run if AEM rule templates need reinstalling

Examples

  1. /dx-adapt — First run after /dx-init. Scans the codebase to detect 3 brands, 45 components, Node 10 with Gulp build. Updates config.yaml with project: and toolchain: sections, then substitutes placeholders in .claude/rules/ files (e.g., {{BRANDS}} becomes the actual brand list, {{BUILD_COMMAND}} becomes npm run build:new).

  2. /dx-adapt (re-run after adding a new brand) — Detects existing project: section in config.yaml, asks whether to re-detect or keep existing values. User chooses re-detect. Finds the new brand directory, updates config.yaml, and re-runs Phase 4 substitution to update rules files with the expanded brand list.

  3. /dx-adapt (AEM project) — Detects AEM project structure during Phase 1. After Phase 3 (config.yaml updated), automatically chains to /aem-init to install AEM-specific rules before Phase 4 runs substitution on all rule files including AEM ones.

Troubleshooting

  • "project profile already exists — re-detect or keep?" Cause: /dx-adapt was run before and detection results are saved in config.yaml's project: section. Fix: Choose "re-detect" if the project structure changed (new components, new brands). Choose "keep" if you only want to re-run the substitution phase (Phase 4) with existing values.

  • Placeholders left in rule files after adaptation Cause: The value could not be extracted from the codebase (e.g., no brands found, build tool not recognized). Fix: Check project: and toolchain: sections in .ai/config.yaml for missing values. Fill them in manually and re-run /dx-adapt — Phase 4 will substitute using the updated values.

  • Rule file skipped during substitution Cause: The rule file has no remaining placeholders (already customized) or was manually edited. Fix: This is expected behavior — /dx-adapt never overwrites user customizations. If you want to re-apply the template, delete the rule file and run /dx-adapt again (it will reinstall from the plugin template first).

Rules

  • Read real source files — extract values from actual code, not defaults
  • Never overwrite user customizations — if a rule file has no matching placeholder, skip it
  • Idempotent — safe to re-run; Phase 0 check skips detection if config.yaml already has a project: section (unless user chooses re-detect)
  • Phase 4 is always run — even if project profile already exists in config.yaml, substitution runs on re-run (user may have reinstalled rules)
  • Graceful on missing data — if a value can't be extracted, leave the placeholder and note it in the report
Install via CLI
npx skills add https://github.com/easingthemes/dx-aem-flow --skill dx-adapt
Repository Details
star Stars 6
call_split Forks 3
navigation Branch main
article Path SKILL.md
More from Creator
easingthemes
easingthemes Explore all skills →