@anhth2/spec-driven-dev-plugin 0.7.0 → 0.9.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.
Files changed (96) hide show
  1. package/ARCHITECTURE.md +6 -2
  2. package/bin/index.js +105 -0
  3. package/commands/debug.md +189 -1
  4. package/commands/debug.tmpl +16 -0
  5. package/commands/define-product.md +94 -1
  6. package/commands/fix-bug.md +190 -1
  7. package/commands/fix-bug.tmpl +17 -0
  8. package/commands/generate-bdd.md +314 -14
  9. package/commands/generate-bdd.tmpl +220 -13
  10. package/commands/generate-code.md +191 -3
  11. package/commands/generate-code.tmpl +97 -2
  12. package/commands/generate-design-spec.md +811 -0
  13. package/commands/generate-design-spec.tmpl +399 -0
  14. package/commands/generate-prd.md +133 -1
  15. package/commands/generate-prd.tmpl +39 -0
  16. package/commands/generate-spec-manifest.md +576 -0
  17. package/commands/generate-spec-manifest.tmpl +164 -0
  18. package/commands/generate-tech-docs.md +116 -2
  19. package/commands/generate-tech-docs.tmpl +22 -1
  20. package/commands/generate-tests.md +94 -1
  21. package/commands/learn.md +554 -0
  22. package/commands/learn.tmpl +63 -0
  23. package/commands/propose-scenario.md +521 -0
  24. package/commands/propose-scenario.tmpl +109 -0
  25. package/commands/refine-prd.md +94 -1
  26. package/commands/report-bug.md +543 -0
  27. package/commands/report-bug.tmpl +131 -0
  28. package/commands/review-code.md +190 -1
  29. package/commands/review-code.tmpl +17 -0
  30. package/commands/review-context.md +134 -1
  31. package/commands/review-context.tmpl +40 -0
  32. package/commands/review-tech-docs.md +176 -5
  33. package/commands/review-tech-docs.tmpl +82 -4
  34. package/commands/run-tests.md +119 -1
  35. package/commands/run-tests.tmpl +25 -0
  36. package/commands/setup-ai-first.md +142 -4
  37. package/commands/setup-ai-first.tmpl +135 -3
  38. package/commands/smoke-test.md +94 -1
  39. package/commands/sync.md +405 -0
  40. package/commands/sync.tmpl +345 -0
  41. package/commands/update-framework.md +211 -0
  42. package/commands/update-framework.tmpl +151 -0
  43. package/commands/validate-traces.md +152 -3
  44. package/commands/validate-traces.tmpl +58 -2
  45. package/core/FRAMEWORK_VERSION +1 -1
  46. package/core/commands/debug.md +189 -1
  47. package/core/commands/define-product.md +94 -1
  48. package/core/commands/fix-bug.md +190 -1
  49. package/core/commands/generate-bdd.md +314 -14
  50. package/core/commands/generate-code.md +191 -3
  51. package/core/commands/generate-design-spec.md +811 -0
  52. package/core/commands/generate-prd.md +133 -1
  53. package/core/commands/generate-spec-manifest.md +576 -0
  54. package/core/commands/generate-tech-docs.md +116 -2
  55. package/core/commands/generate-tests.md +94 -1
  56. package/core/commands/learn.md +554 -0
  57. package/core/commands/propose-scenario.md +521 -0
  58. package/core/commands/refine-prd.md +94 -1
  59. package/core/commands/report-bug.md +543 -0
  60. package/core/commands/review-code.md +190 -1
  61. package/core/commands/review-context.md +134 -1
  62. package/core/commands/review-tech-docs.md +176 -5
  63. package/core/commands/run-tests.md +119 -1
  64. package/core/commands/setup-ai-first.md +142 -4
  65. package/core/commands/smoke-test.md +94 -1
  66. package/core/commands/sync.md +405 -0
  67. package/core/commands/update-framework.md +211 -0
  68. package/core/commands/validate-traces.md +152 -3
  69. package/core/skills/code/SKILL.md +101 -2
  70. package/core/skills/debug/SKILL.md +108 -3
  71. package/core/skills/design-spec/SKILL.md +507 -0
  72. package/core/skills/discovery/SKILL.md +94 -1
  73. package/core/skills/prd/SKILL.md +14 -2
  74. package/core/skills/setup-ai-first/SKILL.md +7 -1
  75. package/core/skills/spec/SKILL.md +14 -2
  76. package/core/skills/test/SKILL.md +195 -3
  77. package/core/steps/capture-lesson.md +79 -0
  78. package/core/steps/context-loader.md +87 -0
  79. package/core/steps/report-footer.md +7 -1
  80. package/core/templates/design-spec.template.md +209 -0
  81. package/core/templates/project-context.yaml +40 -0
  82. package/package.json +1 -1
  83. package/skills/code/SKILL.md +101 -2
  84. package/skills/debug/SKILL.md +108 -3
  85. package/skills/design-spec/SKILL.md +507 -0
  86. package/skills/design-spec/SKILL.tmpl +95 -0
  87. package/skills/discovery/SKILL.md +94 -1
  88. package/skills/prd/SKILL.md +14 -2
  89. package/skills/setup-ai-first/SKILL.md +7 -1
  90. package/skills/spec/SKILL.md +14 -2
  91. package/skills/test/SKILL.md +195 -3
  92. package/steps/capture-lesson.md +79 -0
  93. package/steps/context-loader.md +87 -0
  94. package/steps/report-footer.md +7 -1
  95. package/templates/design-spec.template.md +209 -0
  96. package/templates/project-context.yaml +40 -0
package/ARCHITECTURE.md CHANGED
@@ -196,7 +196,7 @@ spec-driven-dev/
196
196
  │ ├── build.js ← assembles *.tmpl → *.md
197
197
  │ └── index.js ← npm installer + hook installer
198
198
  ├── commands/
199
- │ └── *.tmpl ← slash commands (14 commands)
199
+ │ └── *.tmpl ← slash commands (23 commands)
200
200
  ├── hooks/
201
201
  │ ├── data-guard.js ← PreToolUse sensitive file protection
202
202
  │ └── settings.json ← hook registration template
@@ -209,10 +209,12 @@ spec-driven-dev/
209
209
  │ ├── data-protection.md ← what AI must NEVER read/write
210
210
  │ └── workflow.md ← general AI behavior rules
211
211
  ├── skills/
212
- │ └── {name}/SKILL.tmpl ← Claude plugin skills (7 skills)
212
+ │ └── {name}/SKILL.tmpl ← Claude plugin skills (8 skills)
213
213
  ├── steps/
214
214
  │ ├── gate.md ← shared: file resolve + checkpoint
215
215
  │ ├── context-loader.md ← shared: load all project context
216
+ │ ├── spawn-agent.md ← shared: sub-agent orchestration
217
+ │ ├── capture-lesson.md ← shared: record a guardrail (/learn etc.)
216
218
  │ └── report-footer.md ← shared: standard output format
217
219
  └── templates/
218
220
  ├── project-context.yaml ← consumer project config template
@@ -220,6 +222,8 @@ spec-driven-dev/
220
222
  └── platform-guide.template.md
221
223
  ```
222
224
 
225
+ > Build output (gitignored): `commands/*.md`, `skills/**/SKILL.md`, and `core/` (the distributable copied into a consumer's `.agent/` by `--init`). Consumer-side tester artifacts live in the shared spec repo under `feedback/bug-reports/` and `feedback/bdd-proposals/`.
226
+
223
227
  ---
224
228
 
225
229
  ## Maintenance Guide
package/bin/index.js CHANGED
@@ -29,6 +29,10 @@ const serviceList = servicesRaw
29
29
  }).filter(s => s.name)
30
30
  : [];
31
31
 
32
+ const isUmbrella = args.includes('--umbrella');
33
+ const specSourceIdx = args.indexOf('--spec-source');
34
+ const specSource = specSourceIdx !== -1 ? args[specSourceIdx + 1] : null;
35
+
32
36
  const AVAILABLE_MODULES = [
33
37
  'java-spring', 'angular', 'react', 'nextjs',
34
38
  'dotnet', 'golang', 'php-laravel', 'context-engineering',
@@ -59,6 +63,9 @@ if (showHelp) {
59
63
  console.log('Install modes:');
60
64
  console.log(' --init Install framework to .agent/ + create shortcuts in .claude/commands/');
61
65
  console.log(' Recommended for new projects. Run upgrade.sh to upgrade later.');
66
+ console.log(' --init --umbrella Umbrella repo setup: installs framework at umbrella level only.');
67
+ console.log(' Generates project-context.yaml with services routing.');
68
+ console.log(' Does NOT install into service submodule directories.');
62
69
  console.log(' --project Install full commands to ./.claude/commands/ (project-scoped, legacy)');
63
70
  console.log(' (no flag) Install full commands to ~/.claude/commands/ (global, legacy)');
64
71
  console.log('');
@@ -67,6 +74,9 @@ if (showHelp) {
67
74
  console.log(' --services <list> Monorepo setup: install into each service subfolder in one command.');
68
75
  console.log(' Format: name:module,name:module,...');
69
76
  console.log(' Example: backend:java-spring,web-admin:react,app-mobile:flutter');
77
+ console.log(' --umbrella Umbrella mode (use with --init). See above.');
78
+ console.log(' --spec-source <path> Path to PO spec submodule (e.g. free-trial-specs).');
79
+ console.log(' Auto-configures prd_dir, design_spec_dir, domain_knowledge_dir.');
70
80
  console.log(' --hooks Install data-guard hook to .claude/hooks/ + update .claude/settings.json');
71
81
  console.log('');
72
82
  console.log('Available modules:');
@@ -77,6 +87,9 @@ if (showHelp) {
77
87
  console.log(' npx @anhth2/spec-driven-dev-plugin --init --module java-spring # with stack module');
78
88
  console.log(' npx @anhth2/spec-driven-dev-plugin --init \\');
79
89
  console.log(' --services backend:java-spring,web-admin:react,app-mobile:flutter # monorepo setup');
90
+ console.log(' npx @anhth2/spec-driven-dev-plugin --init --umbrella \\');
91
+ console.log(' --spec-source free-trial-specs \\');
92
+ console.log(' --services mass-product-web:nextjs # umbrella with one FE service');
80
93
  console.log(' npx @anhth2/spec-driven-dev-plugin --project --hooks # legacy project install');
81
94
  process.exit(0);
82
95
  }
@@ -178,6 +191,83 @@ if (isInit) {
178
191
  installDataGuardHook();
179
192
  }
180
193
 
194
+ // 5-alt. Umbrella mode: generate umbrella project-context.yaml (do NOT install into submodules)
195
+ if (isUmbrella) {
196
+ const rootCtxPath = path.join(agentDir, 'project-context.yaml');
197
+ if (!fs.existsSync(rootCtxPath)) {
198
+ const specSrc = specSource || 'TODO-spec-submodule';
199
+
200
+ let servicesBlock = '';
201
+ if (serviceList.length > 0) {
202
+ servicesBlock = serviceList.map(s => [
203
+ ` ${s.name}:`,
204
+ ` path: "${s.name}"`,
205
+ ` module: "${s.module || 'TODO'}"`,
206
+ ` specs_dir: "${s.name}/specs/bdd"`,
207
+ ` tech_docs_dir: "${s.name}/specs/tech-docs"`,
208
+ ].join('\n')).join('\n');
209
+ } else {
210
+ servicesBlock = [
211
+ ` # {domain}:`,
212
+ ` # path: "{service-submodule-dir}"`,
213
+ ` # module: "{stack-module}"`,
214
+ ` # specs_dir: "{service-dir}/specs/bdd"`,
215
+ ` # tech_docs_dir: "{service-dir}/specs/tech-docs"`,
216
+ ].join('\n');
217
+ }
218
+
219
+ const domainsBlock = serviceList.length > 0
220
+ ? serviceList.map(s => ` - "${s.name}"`).join('\n')
221
+ : ` - "TODO"`;
222
+
223
+ const umbrellaYaml = [
224
+ `project:`,
225
+ ` name: "${path.basename(projectRoot)}"`,
226
+ ` description: ""`,
227
+ ``,
228
+ `setup:`,
229
+ ` mode: umbrella`,
230
+ ` spec_source: "${specSrc}"`,
231
+ ``,
232
+ `# Paths auto-derived from spec_source by context-loader.`,
233
+ `# Override here only if your structure differs.`,
234
+ `paths:`,
235
+ ` prd_dir: "${specSrc}/specs/prd"`,
236
+ ` design_spec_dir: "${specSrc}/specs/design-spec"`,
237
+ ` domain_knowledge_dir: "${specSrc}/specs/domain-knowledge"`,
238
+ ` business_dictionary: "${specSrc}/specs/domain-knowledge/business-dictionary.md"`,
239
+ ` core_entities: "${specSrc}/specs/domain-knowledge/core-entities.md"`,
240
+ ` product_definitions_dir: "${specSrc}/specs/product-definition"`,
241
+ ` refinement_dir: ".agent/review"`,
242
+ ` trace_dir: ".trace"`,
243
+ ``,
244
+ `# Domain → service submodule routing.`,
245
+ `# Each key must match @trace.domain in your PRD files.`,
246
+ `services:`,
247
+ servicesBlock,
248
+ ``,
249
+ `tech_stack:`,
250
+ ` language: multi-service`,
251
+ ` module: ""`,
252
+ ``,
253
+ `conventions:`,
254
+ ` ticket_prefix: FEAT`,
255
+ ``,
256
+ `domains:`,
257
+ domainsBlock,
258
+ ``,
259
+ ].join('\n');
260
+
261
+ fs.writeFileSync(rootCtxPath, umbrellaYaml, 'utf8');
262
+ console.log('');
263
+ console.log(' ✅ .agent/project-context.yaml (umbrella mode, generated)');
264
+ if (specSource) console.log(` spec_source : ${specSrc}`);
265
+ if (serviceList.length > 0) console.log(` services : ${serviceList.map(s => s.name).join(', ')}`);
266
+ } else {
267
+ console.log(' ℹ️ .agent/project-context.yaml (already exists — skipped)');
268
+ }
269
+ }
270
+
181
271
  // 5. Monorepo: install into each service subfolder
182
272
  if (serviceList.length > 0) {
183
273
  console.log('');
@@ -307,6 +397,21 @@ if (isInit) {
307
397
  }
308
398
  console.log(`✅ Framework v${frameworkVersion} installed!`);
309
399
  console.log('');
400
+ if (isUmbrella) {
401
+ console.log('Umbrella workspace ready:');
402
+ console.log(' Open Claude Code at project root (umbrella)');
403
+ console.log(' Agent reads specs from: ' + (specSource || 'spec_source in project-context.yaml'));
404
+ if (serviceList.length > 0) {
405
+ console.log(' Service submodules configured:');
406
+ serviceList.forEach(s => console.log(` ${s.name} (${s.module || 'no module'})`));
407
+ }
408
+ console.log('');
409
+ console.log('Next steps:');
410
+ console.log(' 1. Review .agent/project-context.yaml — update service paths + domain names');
411
+ console.log(' 2. Run /setup-ai-first in Claude Code');
412
+ console.log(' 3. Commit .agent/ to git');
413
+ console.log('');
414
+ } else
310
415
  if (serviceList.length > 0) {
311
416
  console.log('Monorepo workspaces ready:');
312
417
  console.log(' PO/BA → open Claude Code at project root');
package/commands/debug.md CHANGED
@@ -134,6 +134,7 @@ Read `.agent/project-context.yaml`. Extract and store:
134
134
  - `paths.core_entities` → path to core-entities.md
135
135
  - `paths.tech_docs_dir` → technical documentation root
136
136
  - `paths.trace_dir` → trace state directory
137
+ - `paths.design_spec_dir` → Design Spec documents root (FE/App only)
137
138
 
138
139
  If `paths` section is absent, use these defaults:
139
140
  - `specs_dir` = `specs/bdd`
@@ -145,11 +146,75 @@ If `paths` section is absent, use these defaults:
145
146
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
146
147
  - `tech_docs_dir` = `specs/tech-docs`
147
148
  - `trace_dir` = `.trace`
149
+ - `design_spec_dir` = `specs/design-spec`
148
150
 
149
151
  If `tech_stack.module` is set, also load `.agent/modules/{module}/stack-profile.yaml` if it exists.
150
152
 
151
153
  ---
152
154
 
155
+ ## Step 1.5 — [SERVICE ROUTING] Resolve service paths (umbrella mode)
156
+
157
+ *Skip this step entirely if `setup.mode` is not `"umbrella"` and `services` section is absent from project-context.yaml.*
158
+
159
+ If `services` section is present:
160
+
161
+ **1. Detect active domain** (in priority order):
162
+ - Read `@trace.domain` from target file frontmatter (if Gate loaded a target file)
163
+ - Extract from target file path: segment immediately after `prd_dir` base path
164
+ *(e.g., `specs/prd/user/FEAT-01.md` → domain = `user`)*
165
+ - If `$ARGUMENTS` contains a path, extract the segment after `prd_dir`
166
+
167
+ **2. Route to service** — if active domain matches a key in `services`:
168
+ - Override `paths.specs_dir` → `services.{domain}.specs_dir`
169
+ - Override `paths.tech_docs_dir` → `services.{domain}.tech_docs_dir`
170
+ - Store `active_service` = `services.{domain}.path`
171
+ - Store `active_service_module` = `services.{domain}.module`
172
+ - If service has its own `module` → use it as `active_module` (overrides `tech_stack.module`)
173
+
174
+ **3. Fallback** — if domain not detected or no matching service key:
175
+ - Keep default paths from Step 1
176
+ - Set `active_service = unresolved`
177
+
178
+ **4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
179
+ - Override `paths.prd_dir` → `{spec_source}/specs/prd`
180
+ - Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
181
+ - Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
182
+ - Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
183
+ - Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
184
+ - Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
185
+ - Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
186
+
187
+ > **Why under `spec_source`:** tester feedback (`/report-bug`, `/propose-scenario`) must land in the **shared spec repo** so PO/Dev see it when they `/sync`. In single-service mode (no `spec_source`), these default to `feedback/bug-reports` and `feedback/bdd-proposals` at repo root — still shared, same repo.
188
+
189
+ ---
190
+
191
+ ## Step 1.6 — [SERVICE CONVENTIONS] Load service-specific conventions (umbrella mode)
192
+
193
+ *Skip this step entirely if `active_service` is `"unresolved"` or context is single-service mode.*
194
+
195
+ When `active_service` has been resolved to a real path in Step 1.5 (e.g., `user-service/`):
196
+
197
+ **1. Locate service config** — try in priority order:
198
+ - `{active_service}/.agent/project-context.yaml`
199
+ - `{active_service}/project-context.yaml`
200
+
201
+ **2. If found, override with service-specific values:**
202
+
203
+ | Variable | Source |
204
+ |----------|--------|
205
+ | `conventions.test_command` | service's `conventions.test_command` |
206
+ | `conventions.build_command` | service's `conventions.build_command` |
207
+ | `paths.trace_dir` | `{active_service}/{service paths.trace_dir}` — default: `{active_service}/.trace` |
208
+ | `paths.specs_dir` | `{active_service}/{service paths.specs_dir}` (if set in service config, else keep Step 1.5 override) |
209
+
210
+ **3. Store** `service_root = {active_service}` as the working directory anchor for all downstream commands:
211
+ - Shell commands (`/run-tests`, `/generate-tests`) run **from within** `service_root`
212
+ - File write operations (test files, trace TSVs) use paths **relative to** `service_root`
213
+
214
+ **4. If service config not found** — keep umbrella defaults, still set `service_root = {active_service}` (path anchor is always needed even without a config override).
215
+
216
+ ---
217
+
153
218
  ## Step 2 — [PROJECT-CONFIG] Load module stack profile (conditional)
154
219
 
155
220
  If `tech_stack.module` is set, read `.agent/modules/{module}/stack-profile.yaml`.
@@ -240,6 +305,25 @@ These two variables (`active_module`, `platform_type`) are the canonical source
240
305
 
241
306
  ---
242
307
 
308
+ ## Step 6.7 — [GUARDRAILS] Load Project Lessons (conditional)
309
+
310
+ *Accumulated mistakes the AI must not repeat in this project. These are added over time via `/learn`
311
+ or accepted during `/review-code`, `/fix-bug`, `/debug`.*
312
+
313
+ Resolve the lessons file path:
314
+ - Use `paths.lessons_file` if set (may be service-overridden in umbrella mode, Step 1.6)
315
+ - Else default `specs/domain-knowledge/lessons-learned.md`
316
+ - In umbrella/service mode (when `service_root` is set), if `paths.lessons_file` is unset, default to `{service_root}/.agent/project-lessons.md`
317
+
318
+ If the file exists, read it and store ALL lessons as **ACTIVE GUARDRAILS** for the session:
319
+ - Treat each lesson's **Rule** as a hard constraint — same priority as CLAUDE.md coding standards (Step 3).
320
+ - Before generating or modifying any artifact (PRD, BDD, tech-doc, code, test), check the output against every lesson whose `category` matches the current command AND whose `scope` matches the target (domain / file).
321
+ - If a generated output would violate a lesson → correct it **before** presenting, and note which lesson (`L-NNN`) was applied.
322
+
323
+ If the file does not exist → skip silently (no lessons captured yet).
324
+
325
+ ---
326
+
243
327
  ## Step 7 — [RECAP] Working Memory Recap (anti-lost-in-middle)
244
328
 
245
329
  After loading all context, synthesize and output a compact summary block.
@@ -255,6 +339,9 @@ Layers : {layer order from CLAUDE.md §2, e.g., Controller → Facade → Ser
255
339
  Ticket : {ticket_prefix}-
256
340
  Dict : {loaded — N canonical terms, M banned terms | missing}
257
341
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
342
+ Lessons : {loaded — N guardrails | none yet}
343
+ Service : {active_service} ({active_service_module}) | single-service
344
+ Svc Root : {service_root} — conventions + trace_dir loaded from service config | —
258
345
  Status : {FULL | PARTIAL — missing: CLAUDE.md / business-dict / core-entities | MINIMAL}
259
346
  ```
260
347
 
@@ -512,7 +599,8 @@ Suggest the logical next command based on workflow phase:
512
599
  | /define-product | `/generate-prd {product-definition-file}` |
513
600
  | /generate-prd | `/refine-prd {prd-file}` then `/review-context {prd-file}` |
514
601
  | /refine-prd | Open Review Board → update PRD → `/review-context {prd-file}` |
515
- | /review-context (PRD) | `/generate-bdd {prd-file}` if APPROVED; fix PRD if NEEDS_FIX |
602
+ | /review-context (PRD) | FE/App: `/generate-design-spec {prd-file}` (then BDD after sign-off); BE: `/generate-bdd {prd-file}` directly; fix PRD if NEEDS_FIX |
603
+ | /generate-design-spec | Designer review → Figma links confirmed → PO + Designer sign-off → `/generate-bdd {prd-file}` |
516
604
  | /generate-bdd | `/review-context {feature-file}` to verify coverage |
517
605
  | /review-context (BDD) | `/generate-tech-docs {UC-ID}` if APPROVED; regenerate if NEEDS_FIX |
518
606
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
@@ -526,6 +614,11 @@ Suggest the logical next command based on workflow phase:
526
614
  | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/generate-tests {UC-ID}`; all OK → create PR |
527
615
  | /fix-bug | Create PR and link to ticket |
528
616
  | /debug | `/fix-bug {ticket-id}` if fix needed |
617
+ | /report-bug | Send to dev (`/fix-bug {BUG-ID}`); if coverage gap → `/propose-scenario {UC-ID}` |
618
+ | /propose-scenario | Notify PO/Dev to review the proposal in `feedback/bdd-proposals/` |
619
+ | /learn | Continue working — lesson applies on next command |
620
+ | /sync | `/validate-traces` for full coverage; act on any `📥 tester feedback` surfaced |
621
+ | /update-framework | Review `git diff .agent/`, commit; `/sync` for project content |
529
622
 
530
623
  Format the footer as:
531
624
  ```
@@ -558,3 +651,98 @@ See CLAUDE.md §{section}
558
651
  - To fully fix → /fix-bug {TICKET_ID}
559
652
  - Just needed analysis → done
560
653
  ```
654
+
655
+ ---
656
+
657
+ ## Offer to Record a Lesson (optional)
658
+
659
+ If the root cause is a **mistake the AI made when generating code and could repeat**
660
+ (not an environment/config issue or external cause), ask:
661
+
662
+ ```
663
+ This looks like a repeatable AI mistake. Record it as a project lesson? (Y/N)
664
+ ```
665
+
666
+ If `Y` → run the capture procedure below with `source=/debug`, an appropriate `category`
667
+ (usually `code-gen`), and `scope` = the affected domain or file glob.
668
+
669
+ # Capture Lesson — Record a Recurring Mistake as a Guardrail
670
+
671
+ Reusable procedure to persist a "lesson" so the AI does not repeat a mistake in this project.
672
+ Used by `/learn` (manual) and offered by `/review-code`, `/fix-bug`, `/debug` (auto).
673
+
674
+ > **Project memory, not model training.** A lesson is plain text injected into context at the
675
+ > start of every command (context-loader Step 6.7). Functionally this stops the repeat — the AI
676
+ > sees the guardrail before it generates. No model weights change.
677
+
678
+ ## L1 — Resolve the lessons file
679
+
680
+ Resolve `lessons_path` in this order:
681
+ 1. `paths.lessons_file` from loaded context (may be service-overridden in umbrella mode, Step 1.6)
682
+ 2. Default `specs/domain-knowledge/lessons-learned.md` (single-service)
683
+ 3. In umbrella/service mode (when `service_root` is set) default `{service_root}/.agent/project-lessons.md`
684
+
685
+ ## L2 — Build the lesson
686
+
687
+ Gather these fields — from `$ARGUMENTS` (for `/learn`) or from the calling command's findings
688
+ (for `/review-code`, `/fix-bug`, `/debug`):
689
+
690
+ | Field | Meaning |
691
+ |-------|---------|
692
+ | `category` | one of: `code-gen` \| `bdd` \| `tech-docs` \| `tests` \| `prd` \| `general` |
693
+ | `title` | short phrase naming the mistake |
694
+ | `mistake` | concretely, what the AI did wrong |
695
+ | `rule` | imperative correction — "Always …" / "Never …" — testable, not vague |
696
+ | `scope` | where it applies: a domain, a file glob (e.g. `*Controller.*`), or `all` |
697
+ | `source` | how captured: `/learn` \| `/review-code {UC-ID}` \| `/fix-bug {TICKET}` \| `/debug` |
698
+
699
+ If `rule` is vague (e.g. "be careful"), rewrite it into a concrete, checkable instruction before saving.
700
+
701
+ ## L3 — De-duplicate
702
+
703
+ Read existing lessons in `lessons_path`. If one already covers the same mistake:
704
+ - **Refine** that entry (tighten the Rule, widen/narrow Scope, bump Date, append the new Source) — do NOT add a duplicate.
705
+
706
+ Otherwise assign the next id `L-{NNN}` = (highest existing number + 1), zero-padded to 3 digits.
707
+
708
+ ## L4 — Write
709
+
710
+ If `lessons_path` does not exist, create it with this header first:
711
+
712
+ ```markdown
713
+ # Project Lessons — Learned Guardrails
714
+
715
+ > Mistakes the AI must NOT repeat in this project. Loaded by context-loader at the start of
716
+ > every command and treated as hard constraints (same priority as CLAUDE.md coding standards).
717
+ > Add with /learn, or accept the prompt during /review-code, /fix-bug, /debug.
718
+ > Commit this file so the whole team shares the guardrails.
719
+
720
+ | Category | Applies to |
721
+ |----------|-----------|
722
+ | code-gen | /generate-code output |
723
+ | bdd | /generate-bdd output |
724
+ | tech-docs | /generate-tech-docs output |
725
+ | tests | /generate-tests output |
726
+ | prd | /generate-prd, /refine-prd output |
727
+ | general | every command |
728
+
729
+ ---
730
+ ```
731
+
732
+ Insert the new lesson directly under the `---` separator (**newest first**), in this exact shape:
733
+
734
+ ```markdown
735
+ ### L-{NNN} — [{category}] {title}
736
+ - **Date**: {today YYYY-MM-DD}
737
+ - **Scope**: {scope}
738
+ - **Mistake**: {mistake}
739
+ - **Rule**: {rule}
740
+ - **Source**: {source}
741
+
742
+ ```
743
+
744
+ ## L5 — Confirm
745
+
746
+ Print: `📝 Lesson {id} recorded → {lessons_path} ([{category}] {title})`
747
+ Then remind: `Commit {lessons_path} so the team shares this guardrail.`
748
+
@@ -239,3 +239,19 @@ See CLAUDE.md §{section}
239
239
  - To fully fix → /fix-bug {TICKET_ID}
240
240
  - Just needed analysis → done
241
241
  ```
242
+
243
+ ---
244
+
245
+ ## Offer to Record a Lesson (optional)
246
+
247
+ If the root cause is a **mistake the AI made when generating code and could repeat**
248
+ (not an environment/config issue or external cause), ask:
249
+
250
+ ```
251
+ This looks like a repeatable AI mistake. Record it as a project lesson? (Y/N)
252
+ ```
253
+
254
+ If `Y` → run the capture procedure below with `source=/debug`, an appropriate `category`
255
+ (usually `code-gen`), and `scope` = the affected domain or file glob.
256
+
257
+ {{include:steps/capture-lesson.md}}
@@ -131,6 +131,7 @@ Read `.agent/project-context.yaml`. Extract and store:
131
131
  - `paths.core_entities` → path to core-entities.md
132
132
  - `paths.tech_docs_dir` → technical documentation root
133
133
  - `paths.trace_dir` → trace state directory
134
+ - `paths.design_spec_dir` → Design Spec documents root (FE/App only)
134
135
 
135
136
  If `paths` section is absent, use these defaults:
136
137
  - `specs_dir` = `specs/bdd`
@@ -142,11 +143,75 @@ If `paths` section is absent, use these defaults:
142
143
  - `core_entities` = `specs/domain-knowledge/core-entities.md`
143
144
  - `tech_docs_dir` = `specs/tech-docs`
144
145
  - `trace_dir` = `.trace`
146
+ - `design_spec_dir` = `specs/design-spec`
145
147
 
146
148
  If `tech_stack.module` is set, also load `.agent/modules/{module}/stack-profile.yaml` if it exists.
147
149
 
148
150
  ---
149
151
 
152
+ ## Step 1.5 — [SERVICE ROUTING] Resolve service paths (umbrella mode)
153
+
154
+ *Skip this step entirely if `setup.mode` is not `"umbrella"` and `services` section is absent from project-context.yaml.*
155
+
156
+ If `services` section is present:
157
+
158
+ **1. Detect active domain** (in priority order):
159
+ - Read `@trace.domain` from target file frontmatter (if Gate loaded a target file)
160
+ - Extract from target file path: segment immediately after `prd_dir` base path
161
+ *(e.g., `specs/prd/user/FEAT-01.md` → domain = `user`)*
162
+ - If `$ARGUMENTS` contains a path, extract the segment after `prd_dir`
163
+
164
+ **2. Route to service** — if active domain matches a key in `services`:
165
+ - Override `paths.specs_dir` → `services.{domain}.specs_dir`
166
+ - Override `paths.tech_docs_dir` → `services.{domain}.tech_docs_dir`
167
+ - Store `active_service` = `services.{domain}.path`
168
+ - Store `active_service_module` = `services.{domain}.module`
169
+ - If service has its own `module` → use it as `active_module` (overrides `tech_stack.module`)
170
+
171
+ **3. Fallback** — if domain not detected or no matching service key:
172
+ - Keep default paths from Step 1
173
+ - Set `active_service = unresolved`
174
+
175
+ **4. Spec source auto-override** — if `setup.spec_source` is set AND the corresponding path was not already explicitly set in `paths:`:
176
+ - Override `paths.prd_dir` → `{spec_source}/specs/prd`
177
+ - Override `paths.design_spec_dir` → `{spec_source}/specs/design-spec`
178
+ - Override `paths.domain_knowledge_dir` → `{spec_source}/specs/domain-knowledge`
179
+ - Override `paths.business_dictionary` → `{spec_source}/specs/domain-knowledge/business-dictionary.md`
180
+ - Override `paths.core_entities` → `{spec_source}/specs/domain-knowledge/core-entities.md`
181
+ - Override `paths.bug_reports_dir` → `{spec_source}/feedback/bug-reports`
182
+ - Override `paths.bdd_proposals_dir` → `{spec_source}/feedback/bdd-proposals`
183
+
184
+ > **Why under `spec_source`:** tester feedback (`/report-bug`, `/propose-scenario`) must land in the **shared spec repo** so PO/Dev see it when they `/sync`. In single-service mode (no `spec_source`), these default to `feedback/bug-reports` and `feedback/bdd-proposals` at repo root — still shared, same repo.
185
+
186
+ ---
187
+
188
+ ## Step 1.6 — [SERVICE CONVENTIONS] Load service-specific conventions (umbrella mode)
189
+
190
+ *Skip this step entirely if `active_service` is `"unresolved"` or context is single-service mode.*
191
+
192
+ When `active_service` has been resolved to a real path in Step 1.5 (e.g., `user-service/`):
193
+
194
+ **1. Locate service config** — try in priority order:
195
+ - `{active_service}/.agent/project-context.yaml`
196
+ - `{active_service}/project-context.yaml`
197
+
198
+ **2. If found, override with service-specific values:**
199
+
200
+ | Variable | Source |
201
+ |----------|--------|
202
+ | `conventions.test_command` | service's `conventions.test_command` |
203
+ | `conventions.build_command` | service's `conventions.build_command` |
204
+ | `paths.trace_dir` | `{active_service}/{service paths.trace_dir}` — default: `{active_service}/.trace` |
205
+ | `paths.specs_dir` | `{active_service}/{service paths.specs_dir}` (if set in service config, else keep Step 1.5 override) |
206
+
207
+ **3. Store** `service_root = {active_service}` as the working directory anchor for all downstream commands:
208
+ - Shell commands (`/run-tests`, `/generate-tests`) run **from within** `service_root`
209
+ - File write operations (test files, trace TSVs) use paths **relative to** `service_root`
210
+
211
+ **4. If service config not found** — keep umbrella defaults, still set `service_root = {active_service}` (path anchor is always needed even without a config override).
212
+
213
+ ---
214
+
150
215
  ## Step 2 — [PROJECT-CONFIG] Load module stack profile (conditional)
151
216
 
152
217
  If `tech_stack.module` is set, read `.agent/modules/{module}/stack-profile.yaml`.
@@ -237,6 +302,25 @@ These two variables (`active_module`, `platform_type`) are the canonical source
237
302
 
238
303
  ---
239
304
 
305
+ ## Step 6.7 — [GUARDRAILS] Load Project Lessons (conditional)
306
+
307
+ *Accumulated mistakes the AI must not repeat in this project. These are added over time via `/learn`
308
+ or accepted during `/review-code`, `/fix-bug`, `/debug`.*
309
+
310
+ Resolve the lessons file path:
311
+ - Use `paths.lessons_file` if set (may be service-overridden in umbrella mode, Step 1.6)
312
+ - Else default `specs/domain-knowledge/lessons-learned.md`
313
+ - In umbrella/service mode (when `service_root` is set), if `paths.lessons_file` is unset, default to `{service_root}/.agent/project-lessons.md`
314
+
315
+ If the file exists, read it and store ALL lessons as **ACTIVE GUARDRAILS** for the session:
316
+ - Treat each lesson's **Rule** as a hard constraint — same priority as CLAUDE.md coding standards (Step 3).
317
+ - Before generating or modifying any artifact (PRD, BDD, tech-doc, code, test), check the output against every lesson whose `category` matches the current command AND whose `scope` matches the target (domain / file).
318
+ - If a generated output would violate a lesson → correct it **before** presenting, and note which lesson (`L-NNN`) was applied.
319
+
320
+ If the file does not exist → skip silently (no lessons captured yet).
321
+
322
+ ---
323
+
240
324
  ## Step 7 — [RECAP] Working Memory Recap (anti-lost-in-middle)
241
325
 
242
326
  After loading all context, synthesize and output a compact summary block.
@@ -252,6 +336,9 @@ Layers : {layer order from CLAUDE.md §2, e.g., Controller → Facade → Ser
252
336
  Ticket : {ticket_prefix}-
253
337
  Dict : {loaded — N canonical terms, M banned terms | missing}
254
338
  Entities : {loaded — EntityA, EntityB, EntityC | missing}
339
+ Lessons : {loaded — N guardrails | none yet}
340
+ Service : {active_service} ({active_service_module}) | single-service
341
+ Svc Root : {service_root} — conventions + trace_dir loaded from service config | —
255
342
  Status : {FULL | PARTIAL — missing: CLAUDE.md / business-dict / core-entities | MINIMAL}
256
343
  ```
257
344
 
@@ -446,7 +533,8 @@ Suggest the logical next command based on workflow phase:
446
533
  | /define-product | `/generate-prd {product-definition-file}` |
447
534
  | /generate-prd | `/refine-prd {prd-file}` then `/review-context {prd-file}` |
448
535
  | /refine-prd | Open Review Board → update PRD → `/review-context {prd-file}` |
449
- | /review-context (PRD) | `/generate-bdd {prd-file}` if APPROVED; fix PRD if NEEDS_FIX |
536
+ | /review-context (PRD) | FE/App: `/generate-design-spec {prd-file}` (then BDD after sign-off); BE: `/generate-bdd {prd-file}` directly; fix PRD if NEEDS_FIX |
537
+ | /generate-design-spec | Designer review → Figma links confirmed → PO + Designer sign-off → `/generate-bdd {prd-file}` |
450
538
  | /generate-bdd | `/review-context {feature-file}` to verify coverage |
451
539
  | /review-context (BDD) | `/generate-tech-docs {UC-ID}` if APPROVED; regenerate if NEEDS_FIX |
452
540
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
@@ -460,6 +548,11 @@ Suggest the logical next command based on workflow phase:
460
548
  | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/generate-tests {UC-ID}`; all OK → create PR |
461
549
  | /fix-bug | Create PR and link to ticket |
462
550
  | /debug | `/fix-bug {ticket-id}` if fix needed |
551
+ | /report-bug | Send to dev (`/fix-bug {BUG-ID}`); if coverage gap → `/propose-scenario {UC-ID}` |
552
+ | /propose-scenario | Notify PO/Dev to review the proposal in `feedback/bdd-proposals/` |
553
+ | /learn | Continue working — lesson applies on next command |
554
+ | /sync | `/validate-traces` for full coverage; act on any `📥 tester feedback` surfaced |
555
+ | /update-framework | Review `git diff .agent/`, commit; `/sync` for project content |
463
556
 
464
557
  Format the footer as:
465
558
  ```