diff --git a/commands/gsd/milestone-summary.md b/commands/gsd/milestone-summary.md
new file mode 100644
index 000000000..e5210d6e9
--- /dev/null
+++ b/commands/gsd/milestone-summary.md
@@ -0,0 +1,51 @@
+---
+type: prompt
+name: gsd:milestone-summary
+description: Generate a comprehensive project summary from milestone artifacts for team onboarding and review
+argument-hint: "[version]"
+allowed-tools:
+ - Read
+ - Write
+ - Bash
+ - Grep
+ - Glob
+---
+
+
+Generate a structured milestone summary for team onboarding and project review. Reads completed milestone artifacts (ROADMAP, REQUIREMENTS, CONTEXT, SUMMARY, VERIFICATION files) and produces a human-friendly overview of what was built, how, and why.
+
+Purpose: Enable new team members to understand a completed project by reading one document and asking follow-up questions.
+Output: MILESTONE_SUMMARY written to `.planning/reports/`, presented inline, optional interactive Q&A.
+
+
+
+@~/.claude/get-shit-done/workflows/milestone-summary.md
+
+
+
+**Project files:**
+- `.planning/ROADMAP.md`
+- `.planning/PROJECT.md`
+- `.planning/STATE.md`
+- `.planning/RETROSPECTIVE.md`
+- `.planning/milestones/v{version}-ROADMAP.md` (if archived)
+- `.planning/milestones/v{version}-REQUIREMENTS.md` (if archived)
+- `.planning/phases/*-*/` (SUMMARY.md, VERIFICATION.md, CONTEXT.md, RESEARCH.md)
+
+**User input:**
+- Version: $ARGUMENTS (optional — defaults to current/latest milestone)
+
+
+
+Read and execute the milestone-summary workflow from @~/.claude/get-shit-done/workflows/milestone-summary.md end-to-end.
+
+
+
+- Milestone version resolved (from args, STATE.md, or archive scan)
+- All available artifacts read (ROADMAP, REQUIREMENTS, CONTEXT, SUMMARY, VERIFICATION, RESEARCH, RETROSPECTIVE)
+- Summary document written to `.planning/reports/MILESTONE_SUMMARY-v{version}.md`
+- All 7 sections generated (Overview, Architecture, Phases, Decisions, Requirements, Tech Debt, Getting Started)
+- Summary presented inline to user
+- Interactive Q&A offered
+- STATE.md updated
+
diff --git a/get-shit-done/workflows/milestone-summary.md b/get-shit-done/workflows/milestone-summary.md
new file mode 100644
index 000000000..e5ef4b37e
--- /dev/null
+++ b/get-shit-done/workflows/milestone-summary.md
@@ -0,0 +1,223 @@
+# Milestone Summary Workflow
+
+Generate a comprehensive, human-friendly project summary from completed milestone artifacts.
+Designed for team onboarding — a new contributor can read the output and understand the entire project.
+
+---
+
+## Step 1: Resolve Version
+
+```bash
+VERSION="$ARGUMENTS"
+```
+
+If `$ARGUMENTS` is empty:
+1. Check `.planning/STATE.md` for current milestone version
+2. Check `.planning/milestones/` for the latest archived version
+3. If neither found, check if `.planning/ROADMAP.md` exists (project may be mid-milestone)
+4. If nothing found: error "No milestone found. Run /gsd:new-project or /gsd:new-milestone first."
+
+Set `VERSION` to the resolved version (e.g., "1.0").
+
+## Step 2: Locate Artifacts
+
+Determine whether the milestone is **archived** or **current**:
+
+**Archived milestone** (`.planning/milestones/v{VERSION}-ROADMAP.md` exists):
+```
+ROADMAP_PATH=".planning/milestones/v${VERSION}-ROADMAP.md"
+REQUIREMENTS_PATH=".planning/milestones/v${VERSION}-REQUIREMENTS.md"
+AUDIT_PATH=".planning/milestones/v${VERSION}-MILESTONE-AUDIT.md"
+```
+
+**Current/in-progress milestone** (no archive yet):
+```
+ROADMAP_PATH=".planning/ROADMAP.md"
+REQUIREMENTS_PATH=".planning/REQUIREMENTS.md"
+AUDIT_PATH=".planning/v${VERSION}-MILESTONE-AUDIT.md"
+```
+
+Note: The audit file moves to `.planning/milestones/` on archive (per `complete-milestone` workflow). Check both locations as a fallback.
+
+**Always available:**
+```
+PROJECT_PATH=".planning/PROJECT.md"
+RETRO_PATH=".planning/RETROSPECTIVE.md"
+STATE_PATH=".planning/STATE.md"
+```
+
+Read all files that exist. Missing files are fine — the summary adapts to what's available.
+
+## Step 3: Discover Phase Artifacts
+
+Find all phase directories:
+
+```bash
+gsd-tools.cjs init progress
+```
+
+This returns phase metadata. For each phase in the milestone scope:
+
+- Read `{phase_dir}/{padded}-SUMMARY.md` if it exists — extract `one_liner`, `accomplishments`, `decisions`
+- Read `{phase_dir}/{padded}-VERIFICATION.md` if it exists — extract status, gaps, deferred items
+- Read `{phase_dir}/{padded}-CONTEXT.md` if it exists — extract key decisions from `` section
+- Read `{phase_dir}/{padded}-RESEARCH.md` if it exists — note what was researched
+
+Track which phases have which artifacts.
+
+**If no phase directories exist** (empty milestone or pre-build state): skip to Step 5 and generate a minimal summary noting "No phases have been executed yet." Do not error — the summary should still capture PROJECT.md and ROADMAP.md content.
+
+## Step 4: Gather Git Statistics
+
+Try each method in order until one succeeds:
+
+**Method 1 — Tagged milestone** (check first):
+```bash
+git tag -l "v${VERSION}" | head -1
+```
+If the tag exists:
+```bash
+git log v${VERSION} --oneline | wc -l
+git diff --stat $(git log --format=%H --reverse v${VERSION} | head -1)..v${VERSION}
+```
+
+**Method 2 — STATE.md date range** (if no tag):
+Read STATE.md and extract the `started_at` or earliest session date. Use it as the `--since` boundary:
+```bash
+git log --oneline --since="" | wc -l
+```
+
+**Method 3 — Earliest phase commit** (if STATE.md has no date):
+Find the earliest `.planning/phases/` commit:
+```bash
+git log --oneline --diff-filter=A -- ".planning/phases/" | tail -1
+```
+Use that commit's date as the start boundary.
+
+**Method 4 — Skip stats** (if none of the above work):
+Report "Git statistics unavailable — no tag or date range could be determined." This is not an error — the summary continues without the Stats section.
+
+Extract (when available):
+- Total commits in milestone
+- Files changed, insertions, deletions
+- Timeline (start date → end date)
+- Contributors (from git log authors)
+
+## Step 5: Generate Summary Document
+
+Write to `.planning/reports/MILESTONE_SUMMARY-v${VERSION}.md`:
+
+```markdown
+# Milestone v{VERSION} — Project Summary
+
+**Generated:** {date}
+**Purpose:** Team onboarding and project review
+
+---
+
+## 1. Project Overview
+
+{From PROJECT.md: "What This Is", core value proposition, target users}
+{If mid-milestone: note which phases are complete vs in-progress}
+
+## 2. Architecture & Technical Decisions
+
+{From CONTEXT.md files across phases: key technical choices}
+{From SUMMARY.md decisions: patterns, libraries, frameworks chosen}
+{From PROJECT.md: tech stack if documented}
+
+Present as a bulleted list of decisions with brief rationale:
+- **Decision:** {what was chosen}
+ - **Why:** {rationale from CONTEXT.md}
+ - **Phase:** {which phase made this decision}
+
+## 3. Phases Delivered
+
+| Phase | Name | Status | One-Liner |
+|-------|------|--------|-----------|
+{For each phase: number, name, status (complete/in-progress/planned), one_liner from SUMMARY.md}
+
+## 4. Requirements Coverage
+
+{From REQUIREMENTS.md: list each requirement with status}
+- ✅ {Requirement met}
+- ⚠️ {Requirement partially met — note gap}
+- ❌ {Requirement not met — note reason}
+
+{If MILESTONE-AUDIT.md exists: include audit verdict}
+
+## 5. Key Decisions Log
+
+{Aggregate from all CONTEXT.md sections}
+{Each decision with: ID, description, phase, rationale}
+
+## 6. Tech Debt & Deferred Items
+
+{From VERIFICATION.md files: gaps found, anti-patterns noted}
+{From RETROSPECTIVE.md: lessons learned, what to improve}
+{From CONTEXT.md sections: ideas parked for later}
+
+## 7. Getting Started
+
+{Entry points for new contributors:}
+- **Run the project:** {from PROJECT.md or SUMMARY.md}
+- **Key directories:** {from codebase structure}
+- **Tests:** {test command from PROJECT.md or CLAUDE.md}
+- **Where to look first:** {main entry points, core modules}
+
+---
+
+## Stats
+
+- **Timeline:** {start} → {end} ({duration})
+- **Phases:** {count complete} / {count total}
+- **Commits:** {count}
+- **Files changed:** {count} (+{insertions} / -{deletions})
+- **Contributors:** {list}
+```
+
+## Step 6: Write and Commit
+
+**Overwrite guard:** If `.planning/reports/MILESTONE_SUMMARY-v${VERSION}.md` already exists, ask the user:
+> "A milestone summary for v{VERSION} already exists. Overwrite it, or view the existing one?"
+If "view": display existing file and skip to Step 8 (interactive mode). If "overwrite": proceed.
+
+Create the reports directory if needed:
+```bash
+mkdir -p .planning/reports
+```
+
+Write the summary, then commit:
+```bash
+gsd-tools.cjs commit "docs(v${VERSION}): generate milestone summary for onboarding" \
+ --files ".planning/reports/MILESTONE_SUMMARY-v${VERSION}.md"
+```
+
+## Step 7: Present Summary
+
+Display the full summary document inline.
+
+## Step 8: Offer Interactive Mode
+
+After presenting the summary:
+
+> "Summary written to `.planning/reports/MILESTONE_SUMMARY-v{VERSION}.md`.
+>
+> I have full context from the build artifacts. Want to ask anything about the project?
+> Architecture decisions, specific phases, requirements, tech debt — ask away."
+
+If the user asks questions:
+- Answer from the artifacts already loaded (CONTEXT.md, SUMMARY.md, VERIFICATION.md, etc.)
+- Reference specific files and decisions
+- Stay grounded in what was actually built (not speculation)
+
+If the user is done:
+- Suggest next steps: `/gsd:new-milestone`, `/gsd:progress`, or sharing the summary with the team
+
+## Step 9: Update STATE.md
+
+```bash
+gsd-tools.cjs state record-session \
+ --stopped-at "Milestone v${VERSION} summary generated" \
+ --resume-file ".planning/reports/MILESTONE_SUMMARY-v${VERSION}.md"
+```
diff --git a/tests/copilot-install.test.cjs b/tests/copilot-install.test.cjs
index 227ad1631..a08fe43a0 100644
--- a/tests/copilot-install.test.cjs
+++ b/tests/copilot-install.test.cjs
@@ -620,7 +620,7 @@ describe('copyCommandsAsCopilotSkills', () => {
// Count gsd-* directories — should be 31
const dirs = fs.readdirSync(tempDir, { withFileTypes: true })
.filter(e => e.isDirectory() && e.name.startsWith('gsd-'));
- assert.strictEqual(dirs.length, 54, `expected 54 skill folders, got ${dirs.length}`);
+ assert.strictEqual(dirs.length, 55, `expected 55 skill folders, got ${dirs.length}`);
} finally {
fs.rmSync(tempDir, { recursive: true });
}
@@ -1114,7 +1114,7 @@ const { execFileSync } = require('child_process');
const crypto = require('crypto');
const INSTALL_PATH = path.join(__dirname, '..', 'bin', 'install.js');
-const EXPECTED_SKILLS = 54;
+const EXPECTED_SKILLS = 55;
const EXPECTED_AGENTS = 18;
function runCopilotInstall(cwd) {
diff --git a/tests/milestone-summary.test.cjs b/tests/milestone-summary.test.cjs
new file mode 100644
index 000000000..327f1023c
--- /dev/null
+++ b/tests/milestone-summary.test.cjs
@@ -0,0 +1,330 @@
+/**
+ * GSD Milestone Summary Tests
+ *
+ * Validates the milestone-summary command and workflow files exist
+ * and follow expected patterns. Tests artifact discovery logic.
+ */
+
+const { test, describe } = require('node:test');
+const assert = require('node:assert');
+const fs = require('fs');
+const path = require('path');
+
+const repoRoot = path.resolve(__dirname, '..');
+const commandPath = path.join(repoRoot, 'commands', 'gsd', 'milestone-summary.md');
+const workflowPath = path.join(repoRoot, 'get-shit-done', 'workflows', 'milestone-summary.md');
+
+describe('milestone-summary command', () => {
+ test('command file exists', () => {
+ assert.ok(fs.existsSync(commandPath), 'commands/gsd/milestone-summary.md should exist');
+ });
+
+ test('command has correct frontmatter name', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(content.includes('name: gsd:milestone-summary'), 'should have correct command name');
+ });
+
+ test('command references workflow in execution_context', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(
+ content.includes('workflows/milestone-summary.md'),
+ 'should reference the milestone-summary workflow'
+ );
+ });
+
+ test('command accepts optional version argument', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(content.includes('argument-hint'), 'should have argument-hint');
+ assert.ok(content.includes('[version]'), 'version should be optional (bracketed)');
+ });
+});
+
+describe('milestone-summary workflow', () => {
+ test('workflow file exists', () => {
+ assert.ok(fs.existsSync(workflowPath), 'workflows/milestone-summary.md should exist');
+ });
+
+ test('workflow reads milestone artifacts', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ const requiredArtifacts = [
+ 'ROADMAP.md',
+ 'REQUIREMENTS.md',
+ 'PROJECT.md',
+ 'SUMMARY.md',
+ 'VERIFICATION.md',
+ 'CONTEXT.md',
+ 'RETROSPECTIVE.md',
+ ];
+ for (const artifact of requiredArtifacts) {
+ assert.ok(
+ content.includes(artifact),
+ `workflow should reference ${artifact}`
+ );
+ }
+ });
+
+ test('workflow writes to reports directory', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('.planning/reports/MILESTONE_SUMMARY'),
+ 'should write summary to .planning/reports/'
+ );
+ });
+
+ test('workflow has interactive Q&A mode', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('Interactive Mode') || content.includes('ask anything'),
+ 'should offer interactive Q&A after summary'
+ );
+ });
+
+ test('workflow handles both archived and current milestones', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(content.includes('Archived milestone'), 'should handle archived milestones');
+ assert.ok(content.includes('Current') || content.includes('in-progress'), 'should handle current milestones');
+ });
+
+ test('workflow generates all 7 summary sections', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ const sections = [
+ 'Project Overview',
+ 'Architecture',
+ 'Phases Delivered',
+ 'Requirements Coverage',
+ 'Key Decisions',
+ 'Tech Debt',
+ 'Getting Started',
+ ];
+ for (const section of sections) {
+ assert.ok(
+ content.includes(section),
+ `summary should include "${section}" section`
+ );
+ }
+ });
+
+ test('workflow updates STATE.md', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('state record-session'),
+ 'should update STATE.md via gsd-tools'
+ );
+ });
+
+ test('workflow has overwrite guard for existing summaries', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('already exists'),
+ 'should check for existing summary before overwriting'
+ );
+ });
+
+ test('workflow handles empty phase directories gracefully', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('no phase directories') || content.includes('No phases'),
+ 'should handle case where no phases exist'
+ );
+ });
+
+ test('workflow checks both audit file locations for archived milestones', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('.planning/milestones/v${VERSION}-MILESTONE-AUDIT.md'),
+ 'should check milestones/ directory for archived audit file'
+ );
+ });
+});
+
+describe('milestone-summary command structure', () => {
+ test('command has success_criteria section', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(
+ content.includes(''),
+ 'should have success_criteria section (follows complete-milestone pattern)'
+ );
+ });
+
+ test('command context lists RESEARCH.md', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(
+ content.includes('RESEARCH.md'),
+ 'should list RESEARCH.md in context block'
+ );
+ });
+});
+
+describe('milestone-summary artifact path resolution', () => {
+ const { createTempProject, cleanup } = require('./helpers.cjs');
+ let tmpDir;
+
+ test('archived milestone paths point to milestones/ directory', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ // Archived roadmap path should be under milestones/
+ assert.ok(
+ content.includes('.planning/milestones/v${VERSION}-ROADMAP.md'),
+ 'archived ROADMAP path should be under .planning/milestones/'
+ );
+ assert.ok(
+ content.includes('.planning/milestones/v${VERSION}-REQUIREMENTS.md'),
+ 'archived REQUIREMENTS path should be under .planning/milestones/'
+ );
+ assert.ok(
+ content.includes('.planning/milestones/v${VERSION}-MILESTONE-AUDIT.md'),
+ 'archived AUDIT path should be under .planning/milestones/'
+ );
+ });
+
+ test('current milestone paths point to .planning/ root', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ // Current milestone should read from .planning/ root
+ const lines = content.split('\n');
+ const currentSection = lines.slice(
+ lines.findIndex(l => l.includes('Current/in-progress')),
+ lines.findIndex(l => l.includes('Current/in-progress')) + 10
+ ).join('\n');
+ assert.ok(
+ currentSection.includes('ROADMAP_PATH=".planning/ROADMAP.md"'),
+ 'current ROADMAP path should be at .planning/ root'
+ );
+ });
+});
+
+describe('milestone-summary fixture-based artifact discovery', () => {
+ const os = require('os');
+ let tmpDir;
+
+ function setup() {
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-ms-test-'));
+ }
+
+ function teardown() {
+ if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true });
+ }
+
+ test('discovers artifacts in archived milestone structure', () => {
+ setup();
+ try {
+ // Create archived milestone structure
+ const milestonesDir = path.join(tmpDir, '.planning', 'milestones');
+ fs.mkdirSync(milestonesDir, { recursive: true });
+ fs.writeFileSync(path.join(milestonesDir, 'v1.0-ROADMAP.md'), '# Roadmap v1.0');
+ fs.writeFileSync(path.join(milestonesDir, 'v1.0-REQUIREMENTS.md'), '# Reqs v1.0');
+ fs.writeFileSync(path.join(milestonesDir, 'v1.0-MILESTONE-AUDIT.md'), '# Audit v1.0');
+
+ // Verify all 3 archived files are discoverable
+ const files = fs.readdirSync(milestonesDir);
+ assert.ok(files.includes('v1.0-ROADMAP.md'), 'archived ROADMAP should exist');
+ assert.ok(files.includes('v1.0-REQUIREMENTS.md'), 'archived REQUIREMENTS should exist');
+ assert.ok(files.includes('v1.0-MILESTONE-AUDIT.md'), 'archived AUDIT should exist');
+ } finally {
+ teardown();
+ }
+ });
+
+ test('discovers phase artifacts across multiple phases', () => {
+ setup();
+ try {
+ // Create phase structure with varying artifact completeness
+ const phase1 = path.join(tmpDir, '.planning', 'phases', '01-setup');
+ const phase2 = path.join(tmpDir, '.planning', 'phases', '02-core');
+ const phase3 = path.join(tmpDir, '.planning', 'phases', '03-ui');
+ fs.mkdirSync(phase1, { recursive: true });
+ fs.mkdirSync(phase2, { recursive: true });
+ fs.mkdirSync(phase3, { recursive: true });
+
+ // Phase 1: all artifacts
+ fs.writeFileSync(path.join(phase1, '01-SUMMARY.md'), 'one_liner: Setup');
+ fs.writeFileSync(path.join(phase1, '01-CONTEXT.md'), 'D-01');
+ fs.writeFileSync(path.join(phase1, '01-VERIFICATION.md'), 'status: passed');
+ fs.writeFileSync(path.join(phase1, '01-RESEARCH.md'), '# Research');
+
+ // Phase 2: partial artifacts (no RESEARCH, no VERIFICATION)
+ fs.writeFileSync(path.join(phase2, '02-SUMMARY.md'), 'one_liner: Core');
+ fs.writeFileSync(path.join(phase2, '02-CONTEXT.md'), 'D-02');
+
+ // Phase 3: only SUMMARY
+ fs.writeFileSync(path.join(phase3, '03-SUMMARY.md'), 'one_liner: UI');
+
+ // Verify discovery
+ const phasesDir = path.join(tmpDir, '.planning', 'phases');
+ const phaseDirs = fs.readdirSync(phasesDir, { withFileTypes: true })
+ .filter(e => e.isDirectory())
+ .map(e => e.name);
+ assert.strictEqual(phaseDirs.length, 3, 'should find 3 phase directories');
+
+ // Phase 1 has all 4 artifact types
+ const p1Files = fs.readdirSync(phase1);
+ assert.strictEqual(p1Files.length, 4, 'phase 1 should have 4 artifacts');
+
+ // Phase 2 has 2 artifact types
+ const p2Files = fs.readdirSync(phase2);
+ assert.strictEqual(p2Files.length, 2, 'phase 2 should have 2 artifacts');
+
+ // Phase 3 has 1 artifact type
+ const p3Files = fs.readdirSync(phase3);
+ assert.strictEqual(p3Files.length, 1, 'phase 3 should have 1 artifact');
+ } finally {
+ teardown();
+ }
+ });
+
+ test('handles empty .planning directory without error', () => {
+ setup();
+ try {
+ const planningDir = path.join(tmpDir, '.planning');
+ fs.mkdirSync(planningDir, { recursive: true });
+
+ // No milestones, no phases — just empty .planning/
+ const contents = fs.readdirSync(planningDir);
+ assert.strictEqual(contents.length, 0, 'empty .planning/ should have no contents');
+
+ // Should not throw when checking for milestones dir
+ const milestonesExists = fs.existsSync(path.join(planningDir, 'milestones'));
+ assert.strictEqual(milestonesExists, false, 'milestones/ should not exist');
+
+ const phasesExists = fs.existsSync(path.join(planningDir, 'phases'));
+ assert.strictEqual(phasesExists, false, 'phases/ should not exist');
+ } finally {
+ teardown();
+ }
+ });
+
+ test('output path pattern produces valid filenames', () => {
+ const versions = ['1.0', '1.1', '2.0', '0.1'];
+ for (const v of versions) {
+ const filename = `MILESTONE_SUMMARY-v${v}.md`;
+ assert.ok(
+ /^MILESTONE_SUMMARY-v\d+\.\d+\.md$/.test(filename),
+ `"${filename}" should be a valid milestone summary filename`
+ );
+ }
+ });
+});
+
+describe('milestone-summary git stats resilience', () => {
+ test('workflow has fallback methods when tag does not exist', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('Method 1') && content.includes('Method 2'),
+ 'should have multiple fallback methods for git stats'
+ );
+ });
+
+ test('workflow can skip stats gracefully', () => {
+ const content = fs.readFileSync(workflowPath, 'utf-8');
+ assert.ok(
+ content.includes('Skip stats') || content.includes('statistics unavailable'),
+ 'should handle case where git stats cannot be gathered'
+ );
+ });
+
+ test('command has type: prompt in frontmatter', () => {
+ const content = fs.readFileSync(commandPath, 'utf-8');
+ assert.ok(
+ content.includes('type: prompt'),
+ 'should have type: prompt for consistency with complete-milestone.md'
+ );
+ });
+});