Imported from easingthemes/dx-aem-flow (
plugins/dx-core/skills/dx-step/SKILL.md). Install upstream withnpx skills add easingthemes/dx-aem-flow --skill dx-step. Copyright stays with the author.
You execute the next pending step from implement.md — implement the changes, verify compilation, run tests, review against plan and conventions, commit, and mark the step done.
Progress Tracking
Before creating tasks, use TaskList to check for existing tasks from a previous run. If stale tasks exist, cancel them first with TaskUpdate (status: cancelled). Then create a task for the current step using TaskCreate (e.g., "Step 3: Add dropdown field"). Mark in_progress when starting, completed when committed. On phase failures, update the task subject (e.g., "Step 3: Add dropdown field (test failed)").
Flow
digraph step {
"Locate spec directory" [shape=box];
"Hub mode check" [shape=diamond];
"Find next step" [shape=diamond];
"All done" [shape=doublecircle];
"Step status?" [shape=diamond];
"Mark in-progress" [shape=box];
"AEM MCP Pre-Check" [shape=box];
"Execute the step" [shape=box];
"Verify compilation" [shape=box];
"Verification passed?" [shape=diamond];
"Classify error" [shape=diamond];
"TRANSIENT: Retry" [shape=box];
"Retry passed?" [shape=diamond];
"VALIDATION: Auto-fix" [shape=box];
"Auto-fix passed?" [shape=diamond];
"Run tests" [shape=box];
"Tests passed?" [shape=diamond];
"Review against plan" [shape=box];
"Review passed?" [shape=diamond];
"Stage and commit" [shape=box];
"Commit succeeded?" [shape=diamond];
"Mark done + present summary" [shape=doublecircle];
"Mark blocked + present summary" [shape=doublecircle];
"Locate spec directory" -> "Hub mode check";
"Hub mode check" -> "Find next step" [label="not hub mode"];
"Hub mode check" -> "All done" [label="hub dispatched"];
"Find next step" -> "All done" [label="none pending"];
"Find next step" -> "Step status?" [label="found"];
"Step status?" -> "Mark in-progress" [label="pending"];
"Step status?" -> "AEM MCP Pre-Check" [label="in-progress (resume)"];
"Step status?" -> "Find next step" [label="blocked (skip)"];
"Mark in-progress" -> "AEM MCP Pre-Check";
"AEM MCP Pre-Check" -> "Execute the step";
"Execute the step" -> "Verify compilation";
"Verify compilation" -> "Verification passed?";
"Verification passed?" -> "Run tests" [label="yes"];
"Verification passed?" -> "Classify error" [label="no"];
"Classify error" -> "TRANSIENT: Retry" [label="TRANSIENT"];
"Classify error" -> "VALIDATION: Auto-fix" [label="VALIDATION"];
"Classify error" -> "Mark blocked + present summary" [label="PERMANENT"];
"TRANSIENT: Retry" -> "Retry passed?";
"Retry passed?" -> "Run tests" [label="yes"];
"Retry passed?" -> "Mark blocked + present summary" [label="no"];
"VALIDATION: Auto-fix" -> "Auto-fix passed?";
"Auto-fix passed?" -> "Run tests" [label="yes"];
"Auto-fix passed?" -> "Mark blocked + present summary" [label="no"];
"Run tests" -> "Tests passed?";
"Tests passed?" -> "Review against plan" [label="yes"];
"Tests passed?" -> "Mark blocked + present summary" [label="no"];
"Review against plan" -> "Review passed?";
"Review passed?" -> "Stage and commit" [label="yes"];
"Review passed?" -> "Mark blocked + present summary" [label="no"];
"Stage and commit" -> "Commit succeeded?";
"Commit succeeded?" -> "Mark done + present summary" [label="yes"];
"Commit succeeded?" -> "Mark blocked + present summary" [label="no"];
}
Node Details
Locate spec directory
SPEC_DIR=$(bash .ai/lib/dx-common.sh find-spec-dir $ARGUMENTS)
Read implement.md from $SPEC_DIR.
Hub mode check
Read shared/hub-dispatch.md for hub detection logic.
If hub mode is active (hub.enabled: true AND cwd is .hub/):
- Determine which repo owns this step:
- Read
implement.mdstep instructions for file paths - Match file paths to repo capabilities from config
- Or: if step specifies a repo tag (from cross-repo plan), use that
- Read
- Dispatch to the correct repo:
cd <repo.path> && claude -p "/dx-step <ticket-id>" --output-format json --allowedTools "Bash,Read,Edit,Write,Glob,Grep" --permission-mode bypassPermissions - Collect result, write state
- Print:
✓ <repo> — step <N> <status> - Go to → "All done" (step executed in target repo)
If hub mode is not active: continue to "Find next step" (normal flow).
Find next step
Parse implement.md and find the first step with **Status:** pending.
If a step has **Status:** in-progress, it was interrupted — route to "Step status?" with in-progress.
If a step has **Status:** blocked, skip it and find the next pending step. Print: "Skipping Step N (blocked). Executing Step M instead."
All done
- Check if implement.md has an
**Other repos required:**line. If so, print:> Cross-repo: This plan covers <current repo> only. Switch to <other repo(s)> and run `/dx-req <id>` there. - Print: "All steps are done. Run
/dx-prto create a pull request." - STOP.
Step status?
Route based on the step's current status:
- pending → go to "Mark in-progress"
- in-progress → go to "AEM MCP Pre-Check" (resume interrupted step — pre-check is idempotent)
- blocked → go back to "Find next step" (skip and find next pending)
Mark in-progress
Update the step's status in implement.md:
**Status:** in-progress
Note: When updating status in implement.md, preserve the provenance frontmatter block at the top of the file unchanged.
AEM MCP Pre-Check
Trigger: Only runs when the current step modifies files under aem.component-path or frontend component paths from config. Skip for pure Java, config, test-only, or non-component steps.
Prerequisite: aem.author-url-qa configured in .ai/config.yaml. If not configured, skip pre-check silently.
Three quick validation queries against AEM QA:
-
Component exists —
mcp__plugin_dx-aem_AEM__getNodeContenton the component definition path. If not found: warn "Component<name>not found on QA. May be new or not yet deployed. Skipping AEM pre-check." and skip remaining queries. -
Field exists —
mcp__plugin_dx-aem_AEM__getNodeContenton<component-path>/<name>/_cq_dialog(depth 6). Check that every dialog field referenced in the plan step actually exists in the dialog. If a referenced field is missing: warn "Plan references field<field>but it's not in the QA dialog. Possible: not yet deployed or field name is wrong." -
Field semantic check —
mcp__plugin_dx-aem_AEM__getNodeContenton a component instance from a known page (use pages fromresearch.mdAEM Component Intelligence, or query for one). Compare the plan's assumption about the field's purpose against the actualfieldLabeland authored value. If mismatch: warn "Plan says<field>is<plan assumption>, but QA shows label<actual label>with value<actual value>. Review the step."
All results are warnings — never block execution. The agent uses warnings to adjust its implementation approach if needed. Pre-check informs, does not gate.
What this does NOT do: No page scanning (init territory), no variant discovery (planning territory), no content comparison (aem-verify territory), no full dialog walk (aem-snapshot territory). This is a focused 3-query sanity check.
Execute the step
Incremental Implementation Principles
Before writing code, apply these guardrails:
- Vertical slices — implement the smallest complete piece of functionality. Each change should leave the system in a working state.
- Safe defaults — new code opts into behavior conservatively. New features default to OFF.
- Rollback-friendly — prefer additive changes (new files, new methods) over modifications. Additive changes are independently revertable.
- Scope discipline — touch only files listed in the step's Files: section. Note adjacent improvements in a comment, don't fix them.
- No premature abstraction — three similar lines of code beat a premature helper. Only abstract when the third use appears.
Read the step's full instructions:
- Files — which files to modify or create
- What — specific instructions for changes
- Why — requirement being addressed (for context)
Implement the changes:
- Read each file listed in Files before modifying it
- Follow the What instructions precisely
- Before creating any new utility, helper, or abstraction: search the codebase (
commons/,utils/,shared/,lib/,scripts/libs/,mixins/) for existing implementations. If one exists, use it instead of creating new code. Ifresearch.mdexists in the spec directory, check its "Existing Implementation Check" section for reusable code. - Use Edit tool for modifications, Write tool for new files
- Follow project conventions — read
.claude/rules/for rules matching the file types being modified (e.g.,fe-javascript.mdfor JS,fe-styles.mdfor SCSS). If.github/instructions/exists, also read the relevant instruction file for framework-specific patterns. For AEM frontend work involving modals, overlays, or focus traps, check ifshared/aem-dom-rules.mdexists (dx-aem plugin) and follow its DOM constraints.
Test-first approach:
If the step has a Test: line and superpowers:test-driven-development is available, invoke it to guide the RED-GREEN-REFACTOR cycle.
Fallback (if superpowers not installed): Follow the Red-Green-Refactor cycle from shared/testing-patterns.md:
- RED: Write/locate the test first. Run it — confirm it fails (proves the test validates something).
- GREEN: Write the minimal implementation to pass the test. No extras (YAGNI).
- REFACTOR: Clean up only after green — duplication, naming, structure — while staying green.
If a test passes immediately before any code change, the test isn't validating new behavior — fix it.
Verify compilation
Run the step's Test command if specified. Otherwise, read the build command from .ai/config.yaml build.command and run a compile check (not full build):
If the project uses Maven: mvn compile -pl <module> -q
If the project uses npm: npm run build
Otherwise: use whatever compile/typecheck command is configured.
Verification passed?
- yes — compilation/test exits 0 → go to "Run tests"
- no — error detected → go to "Classify error"
Classify error
Classify the error against the taxonomy in shared/error-handling.md:
- TRANSIENT → go to "TRANSIENT: Retry"
- VALIDATION → go to "VALIDATION: Auto-fix"
- PERMANENT → go to "Mark blocked + present summary"
TRANSIENT: Retry
Retry the command (up to 2 times). If still failing, go to "Mark blocked + present summary".
Retry passed?
- yes — retry succeeded → go to "Run tests"
- no — still failing after retries → go to "Mark blocked + present summary"
VALIDATION: Auto-fix
Attempt ONE auto-fix (syntax fix, missing import, lint fix). Re-run verification. Do NOT attempt more than one auto-fix.
Auto-fix passed?
- yes — fix + verify passes → go to "Run tests"
- no — fix fails or verify still fails → go to "Mark blocked + present summary"
Run tests
Determine the test command:
- Check the current step's Test: line
- Fall back to
build.testfrom.ai/config.yaml - Fall back to common patterns: Maven →
mvn test -pl <module>, npm →npm test
Execute with a 5-minute timeout. Parse output:
- Tests run / Passed / Failed / Errors / Skipped / Time elapsed
- For each failure: extract test name and assertion message (max 10 lines per failure)
Tests passed?
- yes — all tests pass (zero failures, zero errors) → go to "Review against plan"
- no — any test failure or error → go to "Mark blocked + present summary" with
{ status: "blocked", phase: "test", error: "<failure summary>" }
Review against plan
Use ultrathink for deep reasoning about correctness.
Get the diff: git diff for uncommitted changes, or git diff HEAD~1 if already committed. Read modified files in full for context.
Plan compliance: Do changes match the step's instructions? Are all Files: modified? Any extra files changed?
Convention check: Read .claude/rules/ and .github/instructions/ for relevant file types. Check naming, framework patterns, interface separation, template patterns, test patterns.
Bug check: Null pointer risks, resource leaks, hardcoded values that should be configurable, missing imports, property name mismatches.
Verdict: APPROVED, APPROVED WITH NOTES, or CHANGES REQUESTED.
Review passed?
- yes — verdict is APPROVED or APPROVED WITH NOTES → go to "Stage and commit"
- no — verdict is CHANGES REQUESTED → go to "Mark blocked + present summary" with
{ status: "blocked", phase: "review", error: "<list of required changes>" }
Stage and commit
Before anything else, read shared/git-rules.md — all git/SCM conventions.
Branch check: Verify on feature/* or bugfix/* branch. If not, run bash .ai/lib/ensure-feature-branch.sh $SPEC_DIR.
Determine files: From the step's Files: list + git status for files clearly part of this step. Never stage unrelated files, .env, credentials, or secrets.
Stage specifically (never git add -A):
git add <file1> <file2> ... <implement.md>
Always include implement.md to capture the status update.
Commit message: Extract work item ID from spec directory name. Format: #<ID> <imperative description>. Use HEREDOC:
git commit -m "$(cat <<'EOF'
#<ID> <description>
EOF
)"
If nothing to stage, report "Nothing to stage — no commit created" and go to "Mark blocked + present summary" with { status: "blocked", phase: "commit", error: "nothing to stage" }.
Commit succeeded?
- yes — commit created with valid hash → go to "Mark done + present summary"
- no — commit failed → go to "Mark blocked + present summary" with
{ status: "blocked", phase: "commit", error: "<message>" }
Mark done + present summary
Update implement.md:
**Status:** done
Print:
## Step N complete: <step title>
**Files modified:** <list>
**Compilation:** passed
**Tests:** passed (<N> tests, <time>)
**Review:** <verdict>
**Commit:** `<short hash>` — `<commit message>`
**Next:** Step <N+1> — <title> (or "All steps done — run `/dx-pr`")
Run `/dx-step` for the next step, or `/dx-step-all` to continue autonomously.
Mark blocked + present summary
Update implement.md:
**Status:** blocked
Include the phase, error category, message, and suggested action:
{ status: "blocked", phase: "compile|test|review|commit", error: "<message>" }
Print the summary with the failure details. The coordinator (dx-step-all) uses this to decide whether to call dx-step-fix.
Success Criteria
- Target step status updated: pending → done (or blocked with reason)
- If done: compilation/build command exits 0
- If done: tests pass (zero failures)
- If done: review verdict is APPROVED or APPROVED WITH NOTES
- If done: commit created with work item ID in message
- If done: files modified match step's
**Files:**list - implement.md updated in-place (no corruption of other steps)
Examples
Execute next step (full pipeline)
/dx-step 2435084
Finds the first pending step in implement.md, marks it in-progress, implements code, verifies compilation, runs tests, reviews against plan and conventions, commits, and marks done.
Resume interrupted step
/dx-step 2435084
If a step is in-progress (from a previous interrupted run), resumes it instead of starting the next pending step.
All steps complete
/dx-step 2435084
If no pending steps remain, prints "All steps are done. Run /dx-pr to create a pull request."
Troubleshooting
Step marked blocked after compilation failure
Cause: The implemented code doesn't compile, and the one auto-fix attempt also failed.
Fix: Run /dx-step-fix to diagnose and fix the error, or manually fix and reset the status to pending in implement.md.
Step marked blocked after test failure
Cause: Tests fail after implementation.
Fix: Run /dx-step-fix to diagnose and fix failures, then reset status to pending.
Step marked blocked after review
Cause: Code review found issues (convention violations, bugs, plan deviations).
Fix: Run /dx-step-fix to address the required changes, then reset status to pending.
Step creates a new helper instead of reusing existing one
Cause: The step instructions in implement.md say "create new" when an existing utility would work.
Fix: Fix implement.md first — update the step's What instructions to reference the existing code. Then re-run /dx-step.
"No implement.md found"
Cause: Planning hasn't been done yet.
Fix: Run /dx-plan <id> to generate the implementation plan first.
"Not on a feature branch"
Cause: Working on development, main, or another protected branch.
Fix: The skill auto-runs ensure-feature-branch.sh. If that fails, manually create: git checkout -b feature/<id>-<slug>.
Decision Examples
Fixable Error (VALIDATION)
Error: error TS2304: Cannot find name 'HeroProps'
Classification: VALIDATION / SYNTAX — missing import
Action: Add import { HeroProps } from './hero.types', re-run compilation
Outcome: Fixed. Proceed to tests.
Unfixable Error (PERMANENT)
Error: bash: mvn: command not found
Classification: PERMANENT / MISSING_DEPENDENCY
Action: Do NOT attempt fix. Mark step blocked: "Maven not installed on this machine."
Ambiguous Error (needs classification)
Error: ECONNREFUSED 127.0.0.1:4502
Classification: TRANSIENT / TIMEOUT — AEM is not running
Action: Retry once (AEM may be starting). If still failing → mark blocked: "AEM instance not available."
Test Failure
Tests: 3 failed out of 47
Action: Mark blocked with { status: "blocked", phase: "test", error: "3 test failures: TestDialog#testDropdown, ..." }. Coordinator calls /dx-step-fix.
Review Rejection
Verdict: CHANGES REQUESTED — hardcoded color #FF0000 should use SCSS variable
Action: Mark blocked with { status: "blocked", phase: "review", error: "Convention violation: use $primary-color instead of #FF0000" }. Coordinator calls /dx-step-fix.
Anti-Rationalization
Common excuses for cutting corners during step execution — and why they're wrong:
| False Logic | Reality Check |
|---|---|
| "I'll test at the end" | Bugs cascade — a Step 1 error corrupts Steps 2-5. Test every step. |
| "This is too small to commit separately" | Small commits are costless; large ones hide problems and block bisection. |
| "I know what this file does, no need to read it" | Assumptions cause wrong edits. Reading is cheap, debugging is expensive. |
| "I'll skip the review — it compiled and tests pass" | Compilation proves syntax, not correctness. Reviews catch logic bugs. |
| "The plan is wrong, I'll improvise a better approach" | Mark the step blocked and let the user decide. Don't freelance. |
| "I'll refactor this adjacent code while I'm here" | Scope creep causes merge conflicts and breaks unrelated tests. Touch only what the step requires. |
| "Tests pass immediately, so they're fine" | A test that passes before implementation proves nothing — fix it. |
Rules
- One step at a time — execute exactly one step, then stop. Let the coordinator or user decide what's next.
- Read before writing — always read a file before editing it. Never blindly edit.
- Follow conventions — read
.claude/rules/and.github/instructions/(if it exists) for the relevant file types before writing code. For AEM modal/overlay work, also checkshared/aem-dom-rules.md. - Don't improvise — implement exactly what the step says. If instructions are unclear, mark the step blocked with a note rather than guessing.
- Update status immediately — mark in-progress before starting, done/blocked when finished. This is the state machine that coordinators rely on.
- Compile check is mandatory — never mark a step done without verifying compilation passes.
- Tests are mandatory — never mark a step done without running tests.
- Review is mandatory — never mark a step done without reviewing against the plan.
- Commit is mandatory — never mark a step done without committing changes.
- Follow git-rules.md — read
shared/git-rules.mdbefore committing. Stage specifically, nevergit add -A. - No empty commits — if nothing to stage, report and mark blocked.