name: "dan:unify" description: "Close the loop on a completed plan by writing SUMMARY.md and updating state" argument-hint: "[plan-path]" disable-model-invocation: true agent-skills:
- dan-workflow
dan:unify
Close the execution loop for a completed plan. Reads task commits, deviations, and verification results to produce a SUMMARY.md file. Updates STATE.md and ROADMAP.md.
What It Does
- Reads the target PLAN.md and its task commits
- Gathers deviations, decisions, and issues from execution
- Produces
{phase}-{plan}-SUMMARY.mdwith:- Frontmatter (dependency graph, tech-stack, key-files, decisions, metrics)
- Accomplishments, task commits, files created/modified
- Deviations from plan, issues encountered
- Updates STATE.md (advance plan counter, add decisions, record metrics)
- Updates ROADMAP.md (plan progress row)
Execution Mode
Runs in-session (no agent spawning). Reads git log and plan files to produce summary.
CLI Tools
State and roadmap operations use the DAN CLI:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd $PROJECT_DIR state set "Plan" "3 of 4 in current phase"
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd $PROJECT_DIR state get "Status"
<execution_flow>
<step name="identify_plan"> Determine which plan to unify (close the loop on).-
If a plan path argument was provided by the user, use it directly:
PLAN_FILE=$1 # e.g., ".planning/phases/02-core-loop/02-01-PLAN.md" -
Otherwise, read STATE.md for current phase and plan position:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state get "Phase" node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state get "Plan"Determine the phase directory and scan for unclosed plans.
-
Find the most recent PLAN.md without a matching SUMMARY.md:
PHASE_PATH="$PROJECT_DIR/.planning/phases/${PADDED_PHASE}-${PHASE_NAME}" for PLAN in $(ls "$PHASE_PATH"/*-PLAN.md 2>/dev/null); do PREFIX=$(basename "$PLAN" | sed 's/-PLAN.md//') SUMMARY="$PHASE_PATH/${PREFIX}-SUMMARY.md" [ ! -f "$SUMMARY" ] && PLAN_FILE="$PLAN" && break done -
Parse the plan frontmatter and verify status:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" frontmatter parse "$PLAN_FILE"- If status is
COMPLETED: proceed (summary is the missing piece) - If status is
IN_PROGRESS: warn "Plan is still IN_PROGRESS. Producing summary anyway -- verify all tasks are done." - If status is
DRAFTorAPPROVED: error "Plan has not been executed yet. Run/dan:applyfirst."
- If status is
-
If no unclosed plans found:
All plans in phase ${PADDED_PHASE} have summaries. Nothing to unify.
-
Read the PLAN.md file and extract:
- Objective (from
<objective>block) - Tasks (from
<task>elements): name, type, files, done criteria - Success criteria (from
<success_criteria>block) - Requirements covered (from frontmatter
requirements) - Files modified (from frontmatter
files_modified)
- Objective (from
-
Read git log for commits matching this plan's identifier:
git log --oneline --grep="(${PADDED_PHASE}-${PADDED_PLAN})" --allThis captures all task commits (e.g.,
feat(02-01): ...,test(02-01): ...). -
For each task in the plan, determine its status:
- Completed: A commit exists with the task's description or file changes
- Skipped: No matching commit and task was explicitly deferred
- Modified: Commit exists but files or scope differ from plan
-
Check the current state of planned files:
for FILE in ${FILES_MODIFIED}; do [ -f "$PROJECT_DIR/$FILE" ] && echo "EXISTS: $FILE" || echo "MISSING: $FILE" done -
Count actual files created/modified from the git diff:
git diff --name-only $(git log --oneline --grep="(${PADDED_PHASE}-${PADDED_PLAN})" --format="%H" | tail -1)^..$(git log --oneline --grep="(${PADDED_PHASE}-${PADDED_PLAN})" --format="%H" | head -1)
-
Check STATE.md decisions section for any qualification results:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state get "Decisions"Look for entries mentioning this plan's identifier or PASS_WITH_CONCERNS.
-
Check for deviation patterns in commit messages:
git log --oneline --grep="(${PADDED_PHASE}-${PADDED_PLAN})" --all | grep -iE "fix|deviat|missing|bug" -
Collect any PASS_WITH_CONCERNS notes -- these become items in the "Deviations" or "Deferred" sections.
-
Note any auto-fixed bugs, added missing functionality, or blocking issues resolved during execution. These map to deviation rules:
- Rule 1 (Bug fixes)
- Rule 2 (Missing critical functionality)
- Rule 3 (Blocking issues) </step>
-
Determine the summary file path:
SUMMARY_FILE="$PHASE_PATH/${PADDED_PHASE}-${PADDED_PLAN}-SUMMARY.md" -
Build the summary content following
bin/templates/summary.mdstructure:Frontmatter:
--- phase: {PADDED_PHASE} plan: {PADDED_PLAN} completed: {YYYY-MM-DD} ---Title:
# Phase {PHASE} Plan {PLAN}: [Name] SummaryOne-liner: Substantive description of what was built (not "X implemented" but "JWT auth with refresh rotation using jose library").
Sections:
- Objective: Copied from the plan's
<objective>block - What Was Built: List actual deliverables with file paths from git evidence
- Plan vs Actual: Table comparing:
Aspect Planned Actual Tasks {planned_count} {actual_count} Files {planned_files} {actual_files} Duration {estimated} {actual_duration} - Decisions Made: Any decisions logged during execution (from STATE.md or commit messages)
- Deviations from Plan: Differences between planned and actual work. If none: "None - plan executed exactly as written."
- Deferred Items: Anything planned but not completed. If none: "None."
- Objective: Copied from the plan's
-
Write the summary file: Use the Write tool to create
</step>$SUMMARY_FILEwith the assembled content.
-
Transition the plan status to COMPLETED:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" frontmatter set "$PLAN_FILE" status COMPLETEDThe lifecycle module validates the transition (IN_PROGRESS -> COMPLETED or COMPLETED -> COMPLETED is idempotent).
-
Update STATE.md -- advance the plan counter:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state set "Plan" "${NEXT_PLAN_NUM} of ${TOTAL_PLANS} in current phase" node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state set "Last activity" "$(date +%Y-%m-%d) -- Completed plan ${PADDED_PHASE}-${PADDED_PLAN}" -
Add any new decisions to STATE.md:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" state get "Decisions"Append new decisions from the execution if not already present.
-
Update ROADMAP.md -- mark the plan as complete: Find the plan's entry in ROADMAP.md and change
[ ]to[x]:# Read ROADMAP.md, find the line for this plan, mark complete # Use Edit tool to change "- [ ] Plan XX-NN" to "- [x] Plan XX-NN" -
Commit all changes:
node "$HOME/.claude/dan/bin/dan-tools.cjs" --cwd "$PROJECT_DIR" commit "unify(${PADDED_PHASE}-${PADDED_PLAN}): close loop with summary" --files "$SUMMARY_FILE" "$PROJECT_DIR/.planning/STATE.md" "$PROJECT_DIR/.planning/ROADMAP.md" "$PLAN_FILE"
-
Check if more plans exist in the current phase:
TOTAL_PLANS=$(ls "$PHASE_PATH"/*-PLAN.md 2>/dev/null | wc -l) COMPLETED_PLANS=$(ls "$PHASE_PATH"/*-SUMMARY.md 2>/dev/null | wc -l) -
If uncompleted plans remain:
Loop closed for plan ${PADDED_PHASE}-${PADDED_PLAN}. Next: Run `/dan:apply` on plan ${PADDED_PHASE}-${NEXT_PADDED_PLAN} to continue. -
If all plans in the phase are complete:
Phase ${PADDED_PHASE} complete -- all plans have summaries. Next: Run `/dan:verify` to validate phase deliverables, or `/dan:plan` for the next phase. -
Always confirm closure:
The loop is now closed for plan ${PADDED_PHASE}-${PADDED_PLAN}.
</execution_flow>