name: dx-doctor description: Check health of all dx workflow files — config, rules, scripts, seed data, MCP, settings. Detects installed plugins and checks each. Use after upgrading plugins or when something seems broken. when_to_use: "Use after upgrading plugins or when something seems broken. Trigger on 'check health', 'doctor', 'diagnose workflow', 'something is broken', 'verify dx setup', or 'what is wrong with my dx config'." argument-hint: "[dx|aem|auto|all]" allowed-tools: ["read", "edit", "search", "write", "agent"]
You are a diagnostic tool for the dx workflow setup in a consumer project. You check all init-generated files across all installed plugins, then print a status report with actionable remediation.
This skill is read-only. Never modify, fix, or create anything.
Tool Usage Rules
- File existence: Use
Globwith exact path patterns — never[ -f ],test -f, orlsin Bash - File content: Use
Readto read files — nevercat,head, ordiffin Bash - Content comparison: Read both files with
Read, compare in-context — never shelldiff - Bash is ONLY for:
git branch -a(step 6a) — nothing else in this skill needs Bash - Parallel checks: Call multiple
Glob/Readtools in a single response for efficiency — do not serialize into one Bash command with&&/||
0. Read Configuration & Detect Plugins
Read .ai/config.yaml. If it does not exist:
✗ FATAL: .ai/config.yaml not found. Run /dx-init first.
STOP.
Detect which plugins are configured:
- dx — always (config.yaml exists)
- aem —
aem:section present in config.yaml - seed-data —
.ai/project/directory exists with seed data files - auto —
.ai/automation/infra.jsonexists
Parse the argument:
dx— check dx core onlyaem— check AEM plugin onlyseed-dataordata— check seed data onlyauto— check automation plugin onlyallor no argument — check everything
If the user requests a specific plugin that is not configured, report: ⚠ <plugin> plugin not configured. Skipping.
1. dx Core Files
Check existence and validity of every file dx-init generates.
1a. Config Structure
Read .ai/config.yaml and verify these required keys exist and are non-empty:
project.nameproject.prefixscm.providerscm.orgscm.base-branchbuild.command
Report each: ✓ present or ✗ MISSING.
1a-ii. Config Version
Read dx.version from .ai/config.yaml:
- Missing →
⚠ dx.version not set — run /dx-upgrade to add version tracking - Older than current plugin version →
⚠ Config version <version> behind plugin <plugin-version> — run /dx-upgrade - Current →
✓ dx.version: <version>
To determine the current plugin version, read version from the dx-core plugin.json.
1b. Stale project.yaml check
Check for the deprecated adapt-generated profile file .ai/project.yaml (NOT .ai/project/project.yaml — that's seed data and is checked in section 8):
- Exists →
⚠ DEPRECATED: .ai/project.yaml found. Run /dx-upgrade to migrate fields to config.yaml. - Missing →
✓ not present (expected — fields are in config.yaml)
1c. Template-Generated Files
Check existence of:
.ai/README.md→✓ presentor✗ MISSINGagent.index.md(project root) →✓ presentor✗ MISSING.ai/me.md→✓ presentor⚠ missing (optional — created by /dx-init)
1d. Utility Scripts
Find the dx plugin directory by searching for this skill's own location:
Glob: "**/skills/dx-doctor/SKILL.md"
Navigate up 3 levels from the skill directory to get the dx plugin root.
Discovery (do NOT hardcode the file list — every new utility script in <dx-plugin>/data/lib/ must be picked up automatically). Glob <dx-plugin>/data/lib/*.sh and <dx-plugin>/data/lib/*.js. From the result set, exclude:
- Test files:
*.test.sh,*.test.js - Anything under
<dx-plugin>/data/lib/fixtures/
The remaining files form the utility manifest — each is expected to live at .ai/lib/<basename>.
Plus one fixed entry from a different plugin directory:
.ai/lib/<basename>←<dx-plugin>/data/lib/<basename>(one row per discovered file).claude/hooks/stop-guard.sh←<dx-plugin>/data/hooks/stop-guard.sh(always check)
For each:
- If installed file is missing →
✗ MISSING - If installed file exists, Read both files and compare content:
- Identical →
✓ up to date - Different only in comment lines (lines starting with
#for shell,//or/* */for JS) where the change is a genericized example name (e.g., plugin usesmyai-dedupebut project useskai-dedupe) →✓ up to date (project-specific examples). Plugin templates use generic placeholder names in code comments; consumer projects replace these with real infrastructure names. This is NOT staleness. - Different in functional code (non-comment lines) →
⚠ STALE (plugin version updated — run /dx-upgrade)
- Identical →
1e. (Removed — .ai/docs/ no longer managed by plugins)
Plugin documentation is public at https://easingthemes.github.io/dx-aem-flow/
If .ai/docs/ exists in the project, note: ℹ .ai/docs/ found — these are no longer synced from plugins. Safe to remove if not project-specific.
1f. Output Templates
Check .ai/templates/ directory structure and staleness against <dx-plugin>/data/templates/:
For each subdirectory (spec/, wiki/, ado-comments/):
- Check if
.ai/templates/<subdir>/exists → if not,✗ MISSING - For each
*.templatefile in the plugin source:- Check if
.ai/templates/<subdir>/<name>exists- Missing →
✗ MISSING
- Missing →
- If exists, Read both and compare:
- Identical →
✓ up to date - Different →
⚠ stale (plugin template updated — run /dx-upgrade)
- Identical →
- Check if
Report count: Output templates (<N> present, <M> stale, <K> missing out of <T> templates)
2. dx Rule Files
Compare installed rules against plugin templates. The dx plugin templates live at <dx-plugin>/templates/rules/.
2a. Shared Rules (.ai/rules/)
| Installed | Template |
|---|---|
.ai/rules/pr-review.md |
pr-review.md.template |
.ai/rules/pr-answer.md |
pr-answer.md.template |
.ai/rules/pragmatism.md |
pragmatism.md.template |
.ai/rules/plan-format.md |
plan-format.md.template |
Note: If AEM plugin is configured, pr-review.md and pr-answer.md will have AEM sections appended — this is expected. When comparing, check whether the dx template portion (before the AEM section) matches the template. If only the AEM section differs, report as up to date for dx purposes.
2b. Universal Rules (.claude/rules/)
| Installed | Template |
|---|---|
.claude/rules/reuse-first.md |
universal-reuse-first.md.template |
For each rule:
- Missing →
✗ MISSING - Read both files and compare:
- Identical (or template portion matches) →
✓ up to date - Different →
⚠ stale (plugin template updated — run /dx-upgrade)
- Identical (or template portion matches) →
3. MCP Configuration
Read scm.provider from config.yaml.
If ado:
- Check
.mcp.jsonexists →✓or✗ MISSING - If exists, read it and check:
- Has
mcpServers.adoentry →✓or✗ MISSING - The
argsarray contains the org fromscm.org→✓ matchesor⚠ org mismatch (config: <config-org>, .mcp.json: <mcp-org>)
- Has
If not ado: Report — Not ADO, MCP check skipped
Security: Never print credentials, tokens, or full args arrays. Only report structure and org name.
4. Settings
Check .claude/settings.json:
- Exists → check for
attributionkey withcommitandprsubkeys- Present →
✓ attribution configured - Missing attribution →
⚠ attribution settings missing (run /dx-upgrade)
- Present →
- File missing →
⚠ .claude/settings.json missing
5. .gitignore Coverage
Read .gitignore (if it exists). Check for these entries (exact or parent-covering pattern):
.ai/specs/→✓or⚠ NOT in .gitignore.ai/run-context/→✓or⚠ NOT in .gitignore.ai/research/→✓or⚠ NOT in .gitignore
If .gitignore does not exist → ⚠ no .gitignore found
6. References
Cross-check config values against the filesystem:
6a. Base Branch
Run:
git branch -a 2>/dev/null
Check if scm.base-branch value appears in the output:
- Found →
✓ branch exists - Not found →
⚠ branch '<name>' not found in local or remote branches
6b. Build Tool
Check that the build tool referenced in build.command has its config file:
- Contains
mvn→ checkpom.xmlexists - Contains
npmornpx→ checkpackage.jsonexists - Contains
gradle→ checkbuild.gradleorbuild.gradle.ktsexists - Contains
cargo→ checkCargo.tomlexists - Contains
go→ checkgo.modexists - Found →
✓ build config found - Not found →
⚠ build command uses <tool> but <config-file> not found
6.5. Copilot Files (conditional)
Skip if .github/agents/ doesn't exist — Copilot was never enabled.
If it exists, check:
6.5a. Copilot Agents
Compare installed agents in .github/agents/ against plugin templates in <dx-plugin>/templates/agents/:
For each *.agent.md.template in the plugin:
- Check if
.github/agents/<name>.agent.mdexists- Missing →
✗ MISSING
- Missing →
- If exists, Read both files and compare content:
- Identical →
✓ up to date - Different →
⚠ stale (plugin template updated — run /dx-upgrade)
- Identical →
Report count: Copilot agents (<N> present, <M> stale, <K> missing out of <T> templates)
6.5b. Stale Copilot CLI MCP workaround
Copilot CLI v1.0.12 (April 2026) closed github/copilot-cli#2198 — project .mcp.json is now auto-loaded. The previous --additional-mcp-config flag and global ~/.copilot/mcp-config.json are no longer required.
Warn if the user still has either:
# Check 1: project-level Copilot MCP override file
[ -f .mcp-copilot.json ] && echo "FOUND .mcp-copilot.json"
# Check 2: --additional-mcp-config flag in shell aliases or rc files
grep -l "additional-mcp-config" ~/.zshrc ~/.bashrc ~/.zprofile 2>/dev/null
Reporting:
- Neither present →
✓ Copilot CLI MCP config (using project .mcp.json — v1.0.12+ default) .mcp-copilot.jsonexists →⚠ stale workaround: .mcp-copilot.json present (no longer needed since Copilot CLI v1.0.12 — safe to delete or keep as personal override)--additional-mcp-configin shell rc →⚠ stale workaround: --additional-mcp-config alias in ~/.<shell>rc (Copilot CLI now reads project .mcp.json directly — alias is a no-op)
These are informational warnings, not blockers. The workaround still functions; it's just unnecessary.
6.5c. Copilot CLI v1.0.40+ prompt-mode env vars
Skip if Copilot CLI is not installed (which gh fails or gh copilot --version errors).
Check for the required env vars in the user's shell profile files (~/.zshrc, ~/.bashrc, ~/.zprofile):
REPOS_HOOKS=$(grep -rl "GITHUB_COPILOT_PROMPT_MODE_REPO_HOOKS" ~/.zshrc ~/.bashrc ~/.zprofile 2>/dev/null | head -1)
WORKSPACE_MCP=$(grep -rl "GITHUB_COPILOT_PROMPT_MODE_WORKSPACE_MCP" ~/.zshrc ~/.bashrc ~/.zprofile 2>/dev/null | head -1)
Also check if they are currently set in the environment:
[ -n "${GITHUB_COPILOT_PROMPT_MODE_REPO_HOOKS:-}" ] && HOOKS_ACTIVE=1 || HOOKS_ACTIVE=0
[ -n "${GITHUB_COPILOT_PROMPT_MODE_WORKSPACE_MCP:-}" ] && MCP_ACTIVE=1 || MCP_ACTIVE=0
Reporting:
- Both exported in current env →
✓ Copilot CLI v1.0.40+ prompt-mode env vars set (repo hooks + workspace MCP enabled) - Missing from current env but found in shell rc →
⚠ Copilot CLI prompt-mode env vars in shell rc but not active — restart shell or run: source ~/.zshrc - Missing entirely →
✗ MISSING: Copilot CLI v1.0.40+ requires GITHUB_COPILOT_PROMPT_MODE_REPO_HOOKS=1 and GITHUB_COPILOT_PROMPT_MODE_WORKSPACE_MCP=1 in your shell profile. Without them, repo hooks and workspace MCP are silently disabled. Run /dx-init to add them.
7. AEM Plugin (conditional)
Skip if aem plugin not configured or not in scope.
Find the aem plugin directory:
Glob: "**/skills/aem-init/SKILL.md"
Navigate up 3 levels to get the aem plugin root.
7a. Config Keys
Check these keys exist in the aem: section:
aem.component-path→✓or✗ MISSINGaem.author-url→✓or✗ MISSING
7b. AEM Rule Files
Check existence and staleness of AEM rules in .claude/rules/. Compare each against <aem-plugin>/templates/rules/*.template:
| Installed | Template |
|---|---|
.claude/rules/be-components.md |
be-components.md.template |
.claude/rules/be-sling-models.md |
be-sling-models.md.template |
.claude/rules/be-testing.md |
be-testing.md.template |
.claude/rules/fe-clientlibs.md |
fe-clientlibs.md.template |
.claude/rules/fe-javascript.md |
fe-javascript.md.template |
.claude/rules/fe-styles.md |
fe-styles.md.template |
.claude/rules/naming.md |
naming.md.template |
.claude/rules/accessibility.md |
accessibility.md.template |
For each: missing → ✗ MISSING, content matches → ✓ up to date, differs → ⚠ stale.
Note: Some rules may have been intentionally deleted by dx-init step 8a (project type filtering). If .ai/config.yaml has project.type: aem-frontend, expect be-*.md files to be absent — report as — filtered (aem-frontend) not as missing.
7c. AEM Sections in Shared Rules
Read .ai/rules/pr-review.md and .ai/rules/pr-answer.md. Check each contains an AEM-related section (grep for ## AEM or ## Sling):
- Found →
✓ AEM sections present - Not found →
⚠ AEM sections missing from <file> (run /dx-upgrade)
7d. Delegation
Print: → For component, OSGi, dispatcher, and instance checks, run /aem-doctor
7e. Config Migration Status
Check for legacy config patterns that need migration:
aem.repossection exists in config →⚠ MIGRATE: aem.repos should be merged into top-level repos:. Run /dx-upgrade or /dx-syncaem.current-repofield exists →⚠ MIGRATE: aem.current-repo is deprecated. Run /dx-upgrade or /dx-sync- Top-level
repos:entries exist but any entry lacks apathfield →⚠ repos entries missing path field. Run /dx-upgrade
8. Project Seed Data (conditional)
Skip if .ai/project/ directory does not exist or not in scope.
8a. Seed Data Inventory
Check which seed data files exist in .ai/project/ and report line counts:
| File | Purpose | Expected |
|---|---|---|
project.yaml |
Repos, brands, markets, platforms | yes |
file-patterns.yaml |
Source file path patterns | yes |
content-paths.yaml |
AEM content tree, language defaults | optional |
component-index-project.md |
Enriched component catalog | yes |
architecture.md |
Rendering pipelines, patterns | yes |
features.md |
Domain feature documentation | yes |
component-index.md |
Local repo component scan | generated by /aem-init |
For each: exists → ✓ present (<N> lines), missing (expected) → ✗ MISSING, missing (optional) → ⚠ not present (optional)
8b. YAML Validation
For each .yaml file in .ai/project/:
- Read the file
- Check for valid YAML syntax (balanced indentation, no duplicate keys visible, no bare tabs)
- For
project.yaml: verifyplatforms[].idvalues are referenced by at least one entry inrepos[]orbrands[].markets[] - Report:
✓ validor⚠ syntax issues: <details>
8c. AEM Rule Files (from aem plugin templates)
Check existence and staleness in .claude/rules/. Compare against <aem-plugin>/templates/rules/:
| Installed | Template |
|---|---|
.claude/rules/audit.md |
audit.md.template |
.claude/rules/qa-basic-auth.md |
qa-basic-auth.md.template |
9. Automation Plugin (conditional)
Skip if automation plugin not configured or not in scope.
9a. Infrastructure Config
.ai/automation/infra.jsonexists →✓or✗ MISSING- If exists, read it and check:
automationProfilevalue → report:Profile: <value>. If value isconsumer,pr-only, orpr-delegation(legacy):⚠ Legacy profile — re-run /auto-init to migrate to per-project model.If field absent:Profile: per-project (legacy — no profile field).{{placeholder remnants — report all unresolved{{...}}placeholders as⚠ unresolved.
9b. Supporting Files
.ai/automation/repos.jsonexists and is valid JSON →✓or✗.ai/automation/policy/pipeline-policy.yamlexists →✓or✗
9c. File Checks
Check files based on which agents are enabled (not disabled: true) in infra.json:
- If any Lambda-based agents enabled (DoD, QA, DevAgent, DOCAgent, Estimation, PR Answer): expect Lambda handlers in
.ai/automation/lambda/→ report missing as✗. - Always expect pipeline YAMLs for all enabled agents → report missing as
✗. - Legacy consumer installs will be missing Lambda files → the profile warning in 9a alerts user to re-run
/auto-init.
9d. Delegation
Print: → For pipeline, Lambda, and env var checks, run /auto-doctor
10. Print Results
Use this exact format with status indicators:
✓— check passed⚠— warning (works but attention needed)✗— error (broken or missing)—— skipped (not applicable)
=== dx Project Doctor ===
Plugins detected: dx, aem, seed-data
dx Core Files Status
─────────────────────────────────────────────────────────
.ai/config.yaml ✓ valid (6 required keys)
project.name ✓ present
scm.provider ✓ present
...
.ai/project.yaml (deprecated) ✓ not present
.ai/README.md ✓ present
agent.index.md ✓ present
.ai/me.md ⚠ missing (optional)
.ai/lib/audit.sh ✓ up to date
.ai/lib/dx-common.sh ✓ up to date
.ai/lib/pre-review-checks.sh ✓ up to date
.ai/lib/plan-metadata.sh ✓ up to date
.ai/lib/gather-context.sh ✓ up to date
.ai/lib/ensure-feature-branch.sh ✓ up to date
.ai/lib/queue-pipeline.sh ✓ up to date
.claude/hooks/stop-guard.sh ⚠ STALE
Plugin version updated — run /dx-upgrade
Docs (8 templates) ✓ 8 present, 0 stale
Output templates (11 templates) ✓ 11 present, 0 stale
dx Rule Files Status
─────────────────────────────────────────────────────────
.ai/rules/pr-review.md ✓ up to date
.ai/rules/pr-answer.md ⚠ stale
Template updated — run /dx-upgrade
.ai/rules/pragmatism.md ✓ up to date
.ai/rules/plan-format.md ✓ up to date
.claude/rules/reuse-first.md ✓ up to date
MCP Configuration Status
─────────────────────────────────────────────────────────
.mcp.json ✓ ADO MCP configured
Settings Status
─────────────────────────────────────────────────────────
.claude/settings.json ✓ attribution configured
.gitignore Coverage Status
─────────────────────────────────────────────────────────
.ai/specs/ ✓ in .gitignore
.ai/run-context/ ⚠ NOT in .gitignore
.ai/research/ ✓ in .gitignore
References Status
─────────────────────────────────────────────────────────
Base branch (develop) ✓ exists
Build tool (mvn) ✓ pom.xml found
Copilot Files Status
─────────────────────────────────────────────────────────
Copilot agents (14 templates) ✓ 14 present, 0 stale
Copilot skills (31 templates) ✓ 31 present, 0 stale
Shared files (7 files) ✓ 7 present, 0 stale
AEM Plugin Status
─────────────────────────────────────────────────────────
aem: config section ✓ valid
aem.component-path ✓ present
aem.author-url ✓ present
AEM rules (8 files) ✓ all present
be-components.md ⚠ stale
AEM sections in shared rules ✓ present
→ For component/OSGi/dispatcher/instance checks, run /aem-doctor
Project Seed Data Status
─────────────────────────────────────────────────────────
.ai/project/ ✓ 6 files present
project.yaml ✓ present (277 lines), valid
file-patterns.yaml ✓ present (119 lines), valid
content-paths.yaml ✓ present (58 lines), valid
component-index-project.md ✓ present (478 lines)
architecture.md ✓ present (100 lines)
features.md ✓ present (112 lines)
AEM rules ✓ all present
Automation Plugin Status
─────────────────────────────────────────────────────────
.ai/automation/infra.json ✓ valid
Profile consumer
Relevant placeholders ⚠ 3 unresolved
{{PR_REVIEW_PIPELINE_ID}}
{{PR_ANSWER_PIPELINE_ID}}
{{EVAL_PIPELINE_ID}}
Hub-only placeholders ℹ 8 ignored (hub-only)
.ai/automation/repos.json ✓ valid JSON
.ai/automation/policy/pipeline-policy.yaml ✓ present
→ For pipeline/Lambda/env checks, run /auto-doctor
Summary: 25 passed, 4 warnings, 0 errors
→ Run /dx-upgrade to fix 4 stale/missing items
For each warning/error, include a one-line remediation below the status.
Examples
Check everything
/dx-doctor
Detects installed plugins (dx, aem, seed-data, auto), runs all checks, prints status report with pass/warn/error counts.
Check specific plugin
/dx-doctor aem
Only checks AEM plugin files — config keys, rule files, AEM sections in shared rules.
After upgrade
/dx-doctor
Compares installed files against plugin templates. Reports stale files that need updating via /dx-upgrade.
Troubleshooting
"FATAL: .ai/config.yaml not found"
Cause: Project hasn't been initialized.
Fix: Run /dx-init to set up the project.
Many "STALE" warnings after plugin upgrade
Cause: Plugin templates have been updated but consumer project files haven't been refreshed.
Fix: Run /dx-upgrade to update stale files automatically.
Plugin directory not found
Cause: Plugin isn't installed or was installed to a different path.
Fix: Check that plugins are installed via /plugin install. The skill locates plugins by searching for their skill files.
Error Handling
- If a plugin directory cannot be found (Glob returns nothing), skip file comparison for that plugin:
⚠ <plugin> plugin directory not found. Cannot compare file versions. Checking existence only. - Never fail silently — always report what was skipped and why
- If
.gitignoredoesn't exist, report it but don't treat it as fatal
Rules
- Read-only — never modify, fix, or create anything
- Config-driven — read all paths from
.ai/config.yaml, never hardcode - Graceful degradation — skip checks when plugin is not configured or plugin dir not found
- Actionable output — every warning/error suggests a specific fix command
- Efficient — check file existence first, then content comparisons; no external service calls
- Delegate deep checks — do not duplicate aem-doctor or auto-doctor logic; point to them
- Compare by content — Read both files and compare; report "up to date" or "stale"
- Never expose secrets — never print credentials, tokens, or full MCP args