aped-method 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { run } from '../src/index.js';
4
+
5
+ run().catch((err) => {
6
+ console.error('\x1b[31mError:\x1b[0m', err.message);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "aped-method",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Scaffold the APED pipeline (Analyze, PRD, Epics, Dev, Review) into any Claude Code project",
6
+ "bin": {
7
+ "aped-method": "./bin/aped-method.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "src/"
12
+ ],
13
+ "keywords": [
14
+ "claude-code",
15
+ "skills",
16
+ "pipeline",
17
+ "tdd",
18
+ "code-review",
19
+ "product-development",
20
+ "aped"
21
+ ],
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/yabafre/aped-claude.git"
26
+ },
27
+ "author": "yabafre",
28
+ "engines": {
29
+ "node": ">=18"
30
+ }
31
+ }
package/src/index.js ADDED
@@ -0,0 +1,348 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { stdin, stdout } from 'node:process';
3
+ import { scaffold } from './scaffold.js';
4
+
5
+ const DEFAULTS = {
6
+ apedDir: '.aped',
7
+ outputDir: 'docs/aped',
8
+ commandsDir: '.claude/commands',
9
+ authorName: '',
10
+ projectName: '',
11
+ communicationLang: 'english',
12
+ documentLang: 'english',
13
+ };
14
+
15
+ // ── ANSI helpers ──
16
+ const ESC = '\x1b';
17
+ const a = {
18
+ reset: `${ESC}[0m`,
19
+ bold: `${ESC}[1m`,
20
+ dim: `${ESC}[2m`,
21
+ italic: `${ESC}[3m`,
22
+ underline: `${ESC}[4m`,
23
+ red: `${ESC}[31m`,
24
+ green: `${ESC}[32m`,
25
+ yellow: `${ESC}[33m`,
26
+ blue: `${ESC}[34m`,
27
+ magenta: `${ESC}[35m`,
28
+ cyan: `${ESC}[36m`,
29
+ white: `${ESC}[37m`,
30
+ // 256-color greens for richer palette
31
+ lime: `${ESC}[38;5;118m`, // bright lime
32
+ emerald: `${ESC}[38;5;42m`, // emerald
33
+ mint: `${ESC}[38;5;48m`, // mint
34
+ forest: `${ESC}[38;5;34m`, // forest
35
+ spring: `${ESC}[38;5;82m`, // spring green
36
+ };
37
+
38
+ const bold = (s) => `${a.bold}${s}${a.reset}`;
39
+ const dim = (s) => `${a.dim}${s}${a.reset}`;
40
+ const green = (s) => `${a.green}${s}${a.reset}`;
41
+ const lime = (s) => `${a.lime}${s}${a.reset}`;
42
+ const emerald = (s) => `${a.emerald}${s}${a.reset}`;
43
+ const mint = (s) => `${a.mint}${s}${a.reset}`;
44
+ const yellow = (s) => `${a.yellow}${s}${a.reset}`;
45
+ const magenta = (s) => `${a.magenta}${s}${a.reset}`;
46
+ const red = (s) => `${a.red}${s}${a.reset}`;
47
+ const cyan = (s) => `${a.cyan}${s}${a.reset}`;
48
+
49
+ // ── ASCII Art Logo ──
50
+ const LOGO = `
51
+ ${a.emerald}${a.bold} █████╗ ██████╗ ███████╗██████╗
52
+ ██╔══██╗██╔══██╗██╔════╝██╔══██╗
53
+ ███████║██████╔╝█████╗ ██║ ██║
54
+ ██╔══██║██╔═══╝ ██╔══╝ ██║ ██║
55
+ ██║ ██║██║ ███████╗██████╔╝
56
+ ╚═╝ ╚═╝╚═╝ ╚══════╝╚═════╝${a.reset}
57
+ ${a.dim} ─────────────────────────────────${a.reset}
58
+ ${a.lime}${a.bold} M E T H O D${a.reset}
59
+ ${a.dim} ─────────────────────────────────${a.reset}
60
+ `;
61
+
62
+ const PIPELINE = ` ${a.emerald}${a.bold}A${a.reset}${a.dim}nalyze${a.reset} ${a.dim}→${a.reset} ${a.mint}${a.bold}P${a.reset}${a.dim}RD${a.reset} ${a.dim}→${a.reset} ${a.yellow}${a.bold}E${a.reset}${a.dim}pics${a.reset} ${a.dim}→${a.reset} ${a.lime}${a.bold}D${a.reset}${a.dim}ev${a.reset} ${a.dim}→${a.reset} ${a.red}${a.bold}R${a.reset}${a.dim}eview${a.reset}`;
63
+
64
+ // ── Spinner ──
65
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
66
+
67
+ function createSpinner(text) {
68
+ let i = 0;
69
+ let interval;
70
+ return {
71
+ start() {
72
+ process.stdout.write('\x1b[?25l'); // hide cursor
73
+ interval = setInterval(() => {
74
+ const frame = SPINNER_FRAMES[i % SPINNER_FRAMES.length];
75
+ process.stdout.write(`\r ${a.emerald}${frame}${a.reset} ${text}`);
76
+ i++;
77
+ }, 80);
78
+ },
79
+ stop(finalText) {
80
+ clearInterval(interval);
81
+ process.stdout.write(`\r ${a.lime}${a.bold}✓${a.reset} ${finalText}\x1b[K\n`);
82
+ process.stdout.write('\x1b[?25h'); // show cursor
83
+ },
84
+ fail(finalText) {
85
+ clearInterval(interval);
86
+ process.stdout.write(`\r ${a.red}${a.bold}✗${a.reset} ${finalText}\x1b[K\n`);
87
+ process.stdout.write('\x1b[?25h');
88
+ },
89
+ };
90
+ }
91
+
92
+ function sleep(ms) {
93
+ return new Promise((resolve) => setTimeout(resolve, ms));
94
+ }
95
+
96
+ // ── Section display ──
97
+ function sectionHeader(title) {
98
+ console.log('');
99
+ console.log(` ${a.emerald}${a.bold}┌─${a.reset} ${a.bold}${title}${a.reset}`);
100
+ console.log(` ${a.emerald}│${a.reset}`);
101
+ }
102
+
103
+ function sectionEnd() {
104
+ console.log(` ${a.emerald}${a.bold}└──────────────────────────────────${a.reset}`);
105
+ }
106
+
107
+ // ── Args ──
108
+ function parseArgs(argv) {
109
+ const args = {};
110
+ for (let i = 2; i < argv.length; i++) {
111
+ const arg = argv[i];
112
+ if (arg === '--yes' || arg === '-y') { args.yes = true; continue; }
113
+ const match = arg.match(/^--(\w[\w-]*)=(.+)$/);
114
+ if (match) {
115
+ const key = match[1].replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
116
+ args[key] = match[2];
117
+ }
118
+ }
119
+ return args;
120
+ }
121
+
122
+ function ask(rl, question, defaultVal) {
123
+ return new Promise((resolve) => {
124
+ const suffix = defaultVal ? ` ${dim(`(${defaultVal})`)}` : '';
125
+ rl.question(` ${a.emerald}│${a.reset} ${question}${suffix}: `, (answer) => {
126
+ resolve(answer.trim() || defaultVal || '');
127
+ });
128
+ });
129
+ }
130
+
131
+ async function readStdinLines() {
132
+ if (stdin.isTTY) return null;
133
+ return new Promise((resolve) => {
134
+ let data = '';
135
+ stdin.setEncoding('utf-8');
136
+ stdin.on('data', (chunk) => { data += chunk; });
137
+ stdin.on('end', () => resolve(data.split('\n')));
138
+ setTimeout(() => resolve(null), 100);
139
+ });
140
+ }
141
+
142
+ // ── Main ──
143
+ export async function run() {
144
+ const args = parseArgs(process.argv);
145
+ const stdinLines = await readStdinLines();
146
+ let lineIndex = 0;
147
+
148
+ let detectedProject = '';
149
+ try {
150
+ const { readFileSync } = await import('node:fs');
151
+ const pkg = JSON.parse(readFileSync('package.json', 'utf-8'));
152
+ detectedProject = pkg.name || '';
153
+ } catch {
154
+ detectedProject = process.cwd().split('/').pop();
155
+ }
156
+
157
+ // ── Banner ──
158
+ console.log(LOGO);
159
+ console.log(PIPELINE);
160
+ console.log('');
161
+
162
+ if (args.yes) {
163
+ const config = {
164
+ projectName: args.project || args.projectName || detectedProject || 'my-project',
165
+ authorName: args.author || args.authorName || '',
166
+ communicationLang: args.lang || args.communicationLang || DEFAULTS.communicationLang,
167
+ documentLang: args.docLang || args.documentLang || DEFAULTS.documentLang,
168
+ apedDir: args.aped || args.apedDir || DEFAULTS.apedDir,
169
+ outputDir: args.output || args.outputDir || DEFAULTS.outputDir,
170
+ commandsDir: args.commands || args.commandsDir || DEFAULTS.commandsDir,
171
+ };
172
+
173
+ await runScaffold(config);
174
+ return;
175
+ }
176
+
177
+ const rl = createInterface({ input: stdin, output: stdout });
178
+
179
+ const prompt = stdinLines
180
+ ? (question, def) => {
181
+ const val = (stdinLines[lineIndex++] || '').trim();
182
+ const result = val || def || '';
183
+ console.log(` ${a.emerald}│${a.reset} ${question}: ${result}`);
184
+ return Promise.resolve(result);
185
+ }
186
+ : (question, def) => ask(rl, question, def);
187
+
188
+ try {
189
+ sectionHeader('Configuration');
190
+
191
+ const config = {};
192
+ config.projectName = await prompt(`${bold('Project name')}`, detectedProject);
193
+ config.authorName = await prompt(`${bold('Author')}`, DEFAULTS.authorName);
194
+ config.communicationLang = await prompt(`${bold('Communication language')}`, DEFAULTS.communicationLang);
195
+ config.documentLang = await prompt(`${bold('Document language')}`, DEFAULTS.documentLang);
196
+ config.apedDir = await prompt(`${bold('APED dir')} ${dim('(engine)')}`, DEFAULTS.apedDir);
197
+ config.outputDir = await prompt(`${bold('Output dir')} ${dim('(artifacts)')}`, DEFAULTS.outputDir);
198
+ config.commandsDir = await prompt(`${bold('Commands dir')}`, DEFAULTS.commandsDir);
199
+
200
+ sectionEnd();
201
+ console.log('');
202
+ printConfig(config);
203
+ console.log('');
204
+
205
+ const confirm = await prompt(`${bold('Proceed?')}`, 'Y');
206
+ if (confirm.toLowerCase() === 'n') {
207
+ console.log(`\n ${yellow('Cancelled.')}\n`);
208
+ return;
209
+ }
210
+
211
+ await runScaffold(config);
212
+ } finally {
213
+ rl.close();
214
+ }
215
+ }
216
+
217
+ async function runScaffold(config) {
218
+ // ── Phase 1: Validating config ──
219
+ const s1 = createSpinner('Validating configuration...');
220
+ s1.start();
221
+ await sleep(400);
222
+ s1.stop('Configuration validated');
223
+
224
+ // ── Phase 2: Creating directory structure ──
225
+ const s2 = createSpinner('Creating directory structure...');
226
+ s2.start();
227
+ await sleep(300);
228
+ s2.stop('Directory structure ready');
229
+
230
+ // ── Phase 3: Scaffolding ──
231
+ sectionHeader('Scaffolding Pipeline');
232
+ console.log(` ${a.emerald}│${a.reset}`);
233
+
234
+ const count = await scaffoldWithCheckpoints(config);
235
+
236
+ sectionEnd();
237
+
238
+ // ── Phase 4: Setting up hooks ──
239
+ const s3 = createSpinner('Installing guardrail hook...');
240
+ s3.start();
241
+ await sleep(350);
242
+ s3.stop('Guardrail hook installed');
243
+
244
+ // ── Phase 5: Final verification ──
245
+ const s4 = createSpinner('Verifying installation...');
246
+ s4.start();
247
+ await sleep(300);
248
+ s4.stop(`Installation verified — ${bold(String(count))} files`);
249
+
250
+ // ── Done ──
251
+ printDone(count);
252
+ }
253
+
254
+ async function scaffoldWithCheckpoints(config) {
255
+ const { getTemplates } = await import('./templates/index.js');
256
+ const { mkdirSync, writeFileSync, chmodSync, existsSync } = await import('node:fs');
257
+ const { join, dirname } = await import('node:path');
258
+
259
+ const cwd = process.cwd();
260
+ const templates = getTemplates(config);
261
+
262
+ const groups = {
263
+ config: { label: 'Config & State', icon: '⚙', items: [] },
264
+ templates: { label: 'Templates', icon: '📄', items: [] },
265
+ commands: { label: 'Slash Commands', icon: '⚡', items: [] },
266
+ skills: { label: 'Skills (SKILL.md)', icon: '🧠', items: [] },
267
+ scripts: { label: 'Validation Scripts', icon: '🔧', items: [] },
268
+ references: { label: 'Reference Docs', icon: '📚', items: [] },
269
+ hooks: { label: 'Hooks & Settings', icon: '🛡', items: [] },
270
+ };
271
+
272
+ for (const tpl of templates) {
273
+ const p = tpl.path;
274
+ if (p.includes('/hooks/') || p.includes('settings')) groups.hooks.items.push(tpl);
275
+ else if (p.includes('/scripts/')) groups.scripts.items.push(tpl);
276
+ else if (p.includes('/references/')) groups.references.items.push(tpl);
277
+ else if (p.includes('SKILL.md')) groups.skills.items.push(tpl);
278
+ else if (p.includes('/commands/')) groups.commands.items.push(tpl);
279
+ else if (p.includes('/templates/')) groups.templates.items.push(tpl);
280
+ else groups.config.items.push(tpl);
281
+ }
282
+
283
+ let count = 0;
284
+
285
+ for (const [, group] of Object.entries(groups)) {
286
+ if (group.items.length === 0) continue;
287
+
288
+ const sp = createSpinner(`${group.label}...`);
289
+ sp.start();
290
+ await sleep(200);
291
+
292
+ let groupCount = 0;
293
+ for (const tpl of group.items) {
294
+ const fullPath = join(cwd, tpl.path);
295
+ mkdirSync(dirname(fullPath), { recursive: true });
296
+ if (!existsSync(fullPath)) {
297
+ writeFileSync(fullPath, tpl.content, 'utf-8');
298
+ if (tpl.executable) chmodSync(fullPath, 0o755);
299
+ groupCount++;
300
+ count++;
301
+ }
302
+ }
303
+
304
+ sp.stop(`${group.icon} ${group.label} ${dim(`(${groupCount} files)`)}`);
305
+ }
306
+
307
+ return count;
308
+ }
309
+
310
+ function printConfig(config) {
311
+ const box = (label, value, extra) => {
312
+ const e = extra ? ` ${dim(extra)}` : '';
313
+ console.log(` ${a.emerald}│${a.reset} ${dim(label.padEnd(16))}${bold(value)}${e}`);
314
+ };
315
+
316
+ console.log(` ${a.emerald}${a.bold}┌─${a.reset} ${bold('Summary')}`);
317
+ console.log(` ${a.emerald}│${a.reset}`);
318
+ box('Project', config.projectName);
319
+ box('Author', config.authorName || dim('(not set)'));
320
+ box('Communication', config.communicationLang);
321
+ box('Documents', config.documentLang);
322
+ box('APED', config.apedDir + '/', 'engine');
323
+ box('Output', config.outputDir + '/', 'artifacts');
324
+ box('Commands', config.commandsDir + '/');
325
+ console.log(` ${a.emerald}│${a.reset}`);
326
+ console.log(` ${a.emerald}${a.bold}└──────────────────────────────────${a.reset}`);
327
+ }
328
+
329
+ function printDone(count) {
330
+ console.log('');
331
+ console.log(` ${a.emerald}${a.bold}╔══════════════════════════════════════╗${a.reset}`);
332
+ console.log(` ${a.emerald}${a.bold}║${a.reset} ${a.lime}${a.bold}✓${a.reset} ${bold(`${count} files scaffolded`)} ${a.emerald}${a.bold}║${a.reset}`);
333
+ console.log(` ${a.emerald}${a.bold}║${a.reset} ${dim('Pipeline ready to use')} ${a.emerald}${a.bold}║${a.reset}`);
334
+ console.log(` ${a.emerald}${a.bold}╚══════════════════════════════════════╝${a.reset}`);
335
+ console.log('');
336
+
337
+ console.log(` ${a.bold}Available commands:${a.reset}`);
338
+ console.log('');
339
+ console.log(` ${a.emerald}${a.bold}/aped-a${a.reset} ${dim('Analyze — parallel research → product brief')}`);
340
+ console.log(` ${a.mint}${a.bold}/aped-p${a.reset} ${dim('PRD — autonomous generation from brief')}`);
341
+ console.log(` ${a.yellow}${a.bold}/aped-e${a.reset} ${dim('Epics — requirements decomposition')}`);
342
+ console.log(` ${a.lime}${a.bold}/aped-d${a.reset} ${dim('Dev — TDD story implementation')}`);
343
+ console.log(` ${a.red}${a.bold}/aped-r${a.reset} ${dim('Review — adversarial code review')}`);
344
+ console.log(` ${a.spring}${a.bold}/aped-all${a.reset} ${dim('Full pipeline A→P→E→D→R')}`);
345
+ console.log('');
346
+ console.log(` ${dim('Guardrail hook active — pipeline coherence enforced')}`);
347
+ console.log('');
348
+ }
@@ -0,0 +1,21 @@
1
+ import { mkdirSync, writeFileSync, chmodSync, existsSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { getTemplates } from './templates/index.js';
4
+
5
+ export async function scaffold(config) {
6
+ const cwd = process.cwd();
7
+ const templates = getTemplates(config);
8
+ let count = 0;
9
+
10
+ for (const tpl of templates) {
11
+ const fullPath = join(cwd, tpl.path);
12
+ mkdirSync(dirname(fullPath), { recursive: true });
13
+ if (!existsSync(fullPath)) {
14
+ writeFileSync(fullPath, tpl.content, 'utf-8');
15
+ if (tpl.executable) chmodSync(fullPath, 0o755);
16
+ count++;
17
+ }
18
+ }
19
+
20
+ return count;
21
+ }
@@ -0,0 +1,65 @@
1
+ export function commands(c) {
2
+ const a = c.apedDir;
3
+ return [
4
+ {
5
+ path: `${c.commandsDir}/aped-a.md`,
6
+ content: `---
7
+ name: aped-a
8
+ description: 'Analyze project through parallel research. Use when user says "analyze", "research project", or "aped analyze"'
9
+ ---
10
+
11
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-a/SKILL.md
12
+ `,
13
+ },
14
+ {
15
+ path: `${c.commandsDir}/aped-p.md`,
16
+ content: `---
17
+ name: aped-p
18
+ description: 'Generate PRD from product brief. Use when user says "create PRD", "generate PRD", or "aped prd"'
19
+ ---
20
+
21
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-p/SKILL.md
22
+ `,
23
+ },
24
+ {
25
+ path: `${c.commandsDir}/aped-e.md`,
26
+ content: `---
27
+ name: aped-e
28
+ description: 'Create epics and stories from PRD. Use when user says "create epics", "break into stories", or "aped epics"'
29
+ ---
30
+
31
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-e/SKILL.md
32
+ `,
33
+ },
34
+ {
35
+ path: `${c.commandsDir}/aped-d.md`,
36
+ content: `---
37
+ name: aped-d
38
+ description: 'Dev sprint - implement next story with TDD. Use when user says "start dev", "implement story", or "aped dev"'
39
+ ---
40
+
41
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-d/SKILL.md
42
+ `,
43
+ },
44
+ {
45
+ path: `${c.commandsDir}/aped-r.md`,
46
+ content: `---
47
+ name: aped-r
48
+ description: 'Adversarial code review for completed story. Use when user says "review code", "run review", or "aped review"'
49
+ ---
50
+
51
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-r/SKILL.md
52
+ `,
53
+ },
54
+ {
55
+ path: `${c.commandsDir}/aped-all.md`,
56
+ content: `---
57
+ name: aped-all
58
+ description: 'Run full APED pipeline (Analyze>PRD>Epics>Dev>Review). Use when user says "run full pipeline", "aped all", or "start from scratch"'
59
+ ---
60
+
61
+ Read and follow the SKILL.md at $PROJECT_ROOT/${a}/aped-all/SKILL.md
62
+ `,
63
+ },
64
+ ];
65
+ }
@@ -0,0 +1,230 @@
1
+ export function configFiles(c) {
2
+ const a = c.apedDir;
3
+ const o = c.outputDir;
4
+ return [
5
+ {
6
+ path: `${a}/config.yaml`,
7
+ content: `# APED Project Configuration
8
+ project_name: ${c.projectName}
9
+ user_name: ${c.authorName}
10
+ communication_language: ${c.communicationLang}
11
+ document_output_language: ${c.documentLang}
12
+ aped_path: ${a}
13
+ output_path: ${o}
14
+ `,
15
+ },
16
+ {
17
+ path: `${a}/state.yaml`,
18
+ content: `# APED Pipeline State
19
+ pipeline:
20
+ current_phase: "none"
21
+ phases: {}
22
+
23
+ # Sprint state (generated by aped-e, consumed by aped-d and aped-r)
24
+ sprint:
25
+ project: ""
26
+ stories: {}
27
+ `,
28
+ },
29
+ {
30
+ path: `${a}/templates/product-brief.md`,
31
+ content: `# Product Brief: {{project_name}}
32
+
33
+ ## Executive Summary
34
+
35
+ <!-- 2-3 sentences: what we're building and why it matters -->
36
+
37
+ ## Core Vision
38
+
39
+ ### Problem Statement
40
+
41
+ <!-- What specific problem exists today? -->
42
+
43
+ ### Problem Impact
44
+
45
+ <!-- Who is affected and how? Quantify where possible. -->
46
+
47
+ ### Proposed Solution
48
+
49
+ <!-- High-level description of the solution approach -->
50
+
51
+ ### Key Differentiators
52
+
53
+ <!-- What makes this different from existing solutions? -->
54
+
55
+ ## Target Users
56
+
57
+ ### Primary Users
58
+
59
+ <!-- Who are the main users? Demographics, behaviors, technical level -->
60
+
61
+ ### Secondary Users
62
+
63
+ <!-- Other stakeholders who interact with the product -->
64
+
65
+ ### User Journey
66
+
67
+ <!-- Key touchpoints from discovery to daily usage -->
68
+
69
+ ## Success Metrics
70
+
71
+ ### Business Objectives
72
+
73
+ <!-- What business outcomes define success? -->
74
+
75
+ ### KPIs
76
+
77
+ <!-- Measurable indicators with targets and timeframes -->
78
+
79
+ ## MVP Scope
80
+
81
+ ### Core Features
82
+
83
+ <!-- Minimum feature set for first viable release -->
84
+
85
+ ### Out of Scope
86
+
87
+ <!-- Explicitly excluded from MVP -->
88
+
89
+ ### Success Criteria
90
+
91
+ <!-- How we know MVP succeeded -->
92
+
93
+ ### Future Vision
94
+
95
+ <!-- Post-MVP direction and growth areas -->
96
+ `,
97
+ },
98
+ {
99
+ path: `${a}/templates/prd.md`,
100
+ content: `# Product Requirements Document — {{project_name}}
101
+
102
+ **Author:** {{user_name}}
103
+ **Date:** {{date}}
104
+
105
+ ## Executive Summary
106
+
107
+ ## Success Criteria
108
+
109
+ ### User Outcomes
110
+
111
+ ### Business Outcomes
112
+
113
+ ### Technical Outcomes
114
+
115
+ ### Measurable Outcomes
116
+
117
+ ## Product Scope
118
+
119
+ ### MVP (Phase 1)
120
+
121
+ ### Growth (Phase 2)
122
+
123
+ ### Vision (Phase 3)
124
+
125
+ ## User Journeys
126
+
127
+ ## Domain Requirements
128
+
129
+ <!-- Conditional: only if domain-complexity.csv flags high/medium complexity -->
130
+
131
+ ## Functional Requirements
132
+
133
+ <!-- Format: FR#: [Actor] can [capability] [context/constraint] -->
134
+ <!-- Target: 10-80 FRs -->
135
+
136
+ ## Non-Functional Requirements
137
+
138
+ ### Performance
139
+
140
+ ### Security
141
+
142
+ ### Scalability
143
+
144
+ ### Accessibility
145
+
146
+ ### Integration
147
+ `,
148
+ },
149
+ {
150
+ path: `${a}/templates/epics.md`,
151
+ content: `# Epics & Stories — {{project_name}}
152
+
153
+ **Generated:** {{date}}
154
+ **Source PRD:** {{prd_path}}
155
+
156
+ ## Requirements Inventory
157
+
158
+ ### Functional Requirements
159
+
160
+ ### Non-Functional Requirements
161
+
162
+ ### Additional Requirements
163
+
164
+ ## FR Coverage Map
165
+
166
+ <!-- Every FR mapped to exactly one epic. Format: FR# -> Epic N -->
167
+
168
+ ## Epics
169
+
170
+ ### Epic 1: {{epic_title}}
171
+
172
+ **Goal:** {{user-value-focused goal}}
173
+
174
+ #### Story 1.1: {{story_title}}
175
+
176
+ **As a** {{role}}, **I want** {{capability}}, **so that** {{benefit}}.
177
+
178
+ **Acceptance Criteria:**
179
+ - **Given** {{context}}, **When** {{action}}, **Then** {{outcome}}
180
+
181
+ **Tasks:**
182
+ - [ ] {{task description}} [AC: {{ac_ref}}]
183
+
184
+ **Dev Notes:**
185
+ - Architecture: {{relevant patterns}}
186
+ - Files: {{files to create/modify}}
187
+ - Testing: {{test approach}}
188
+ `,
189
+ },
190
+ {
191
+ path: `${a}/templates/story.md`,
192
+ content: `# Story: {{story_key}} — {{story_title}}
193
+
194
+ **Epic:** {{epic_title}}
195
+ **Status:** {{status}}
196
+
197
+ ## User Story
198
+
199
+ **As a** {{role}}, **I want** {{capability}}, **so that** {{benefit}}.
200
+
201
+ ## Acceptance Criteria
202
+
203
+ - **Given** {{context}}, **When** {{action}}, **Then** {{outcome}}
204
+
205
+ ## Tasks
206
+
207
+ - [ ] {{task description}} [AC: {{ac_ref}}]
208
+
209
+ ## Dev Notes
210
+
211
+ - **Architecture:** {{relevant architecture decisions and patterns}}
212
+ - **Files:** {{files to create or modify}}
213
+ - **Testing:** {{test approach and framework}}
214
+ - **Dependencies:** {{external libs, APIs, services}}
215
+
216
+ ## Dev Agent Record
217
+
218
+ - **Model:** {{model used}}
219
+ - **Started:** {{timestamp}}
220
+ - **Completed:** {{timestamp}}
221
+
222
+ ### Debug Log
223
+
224
+ ### Completion Notes
225
+
226
+ ### File List
227
+ `,
228
+ },
229
+ ];
230
+ }