@polymorphism-tech/morph-spec 8.25.0 → 8.27.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 (45) hide show
  1. package/README.md +3 -3
  2. package/bin/morph-spec.js +2 -1
  3. package/claude-plugin.json +1 -1
  4. package/docs/CHEATSHEET.md +1 -1
  5. package/docs/QUICKSTART.md +3 -3
  6. package/framework/CLAUDE.md +2 -2
  7. package/framework/MORPH.md +22 -21
  8. package/framework/agents.json +1 -1
  9. package/framework/commands/create-umbraco-lp.md +1 -1
  10. package/framework/commands/migrate-lp-to-umbraco.md +1 -1
  11. package/framework/commands/morph-apply.md +4 -4
  12. package/framework/commands/morph-hotfix.md +3 -3
  13. package/framework/commands/morph-proposal.md +5 -5
  14. package/framework/docs/CLI.md +3 -3
  15. package/framework/evals/rubrics/condensed.md +2 -2
  16. package/framework/evals/rubrics/test-coverage.md +7 -0
  17. package/framework/hooks/claude-code/core/protect-spec-files.js +115 -4
  18. package/framework/hooks/shared/payload-utils.js +19 -4
  19. package/framework/rules/dotnet-templates.md +2 -1
  20. package/framework/rules/morph-task-tracking.md +11 -34
  21. package/framework/rules/morph-workflow.md +42 -29
  22. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  23. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  24. package/framework/skills/core/morph-apply/SKILL.md +8 -8
  25. package/framework/skills/core/morph-brainstorming/SKILL.md +2 -2
  26. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  27. package/framework/skills/core/morph-hotfix/SKILL.md +7 -7
  28. package/framework/skills/core/morph-implement/SKILL.md +21 -6
  29. package/framework/skills/core/morph-plan/SKILL.md +15 -3
  30. package/framework/skills/core/morph-proposal/SKILL.md +7 -7
  31. package/framework/skills/core/morph-review/SKILL.md +10 -3
  32. package/framework/skills/core/morph-stack-scan/SKILL.md +3 -3
  33. package/framework/skills/core/morph-standards/SKILL.md +4 -4
  34. package/framework/skills/core/morph-uiux/SKILL.md +3 -3
  35. package/framework/templates/README.md +72 -643
  36. package/framework/templates/docs/onboarding.md +4 -4
  37. package/framework/templates/examples/spec-examples.md +2 -1
  38. package/package.json +1 -1
  39. package/src/commands/project/claim.js +19 -3
  40. package/src/commands/state/approve.js +17 -3
  41. package/src/commands/state/finish.js +11 -1
  42. package/src/commands/state/gate-check.js +9 -20
  43. package/src/commands/state/report-check.js +157 -5
  44. package/src/lib/evaluator-report.js +72 -0
  45. package/src/lib/risk-detector.js +35 -0
@@ -1,12 +1,16 @@
1
1
  # MORPH-SPEC Template System
2
2
 
3
- > **Technology-Based Organization for Multi-Stack Reusability**
3
+ > Handlebars templates organized by **technology**, indexed by `REGISTRY.json`.
4
4
 
5
5
  ## Overview
6
6
 
7
- The MORPH-SPEC template system provides **57 production-ready templates** organized by **technology** (not by stack) to enable maximum reusability across current and future stacks.
7
+ **89 templates**, grouped by the technology they target (dotnet, typescript, sql, docker,
8
+ nextjs) rather than by stack. A template for a .NET slice serves every stack with a .NET
9
+ backend, so a new stack reuses what exists instead of copying it.
8
10
 
9
- **Key Principle:** Templates are grouped by the **technology they use** (dotnet, typescript, sql, docker), allowing new stacks like `vue-firebase` or `angular-mongodb` to reuse existing templates for .NET, TypeScript, SQL, etc.
11
+ `REGISTRY.json` is the source of truth: it maps each template `id` to its `path`, category,
12
+ technology and applicable stacks. Nothing resolves a template by hardcoded path — code goes
13
+ through the registry, and this README never repeats a path the registry already owns.
10
14
 
11
15
  ---
12
16
 
@@ -14,135 +18,57 @@ The MORPH-SPEC template system provides **57 production-ready templates** organi
14
18
 
15
19
  ```
16
20
  framework/templates/
17
- ├── docs/ # Universal documentation templates
18
- │ ├── proposal.md # Feature proposal (required)
19
- │ └── spec.md # Technical specification (required)
21
+ ├── docs/ # Phase documents (proposal, spec, user-stories, ui-*, onboarding…)
22
+ ├── feature/ # decisions.md, recap.md
23
+ ├── context/ # ARCHITECTURE.md, design-system.md
20
24
  │
21
- ├── feature/ # Feature management
22
- │ ├── decisions.md # Architecture Decision Records (required)
23
- │ └── recap.md # Post-implementation summary (required)
25
+ ├── code/ # Code templates, by technology
26
+ │ ├── dotnet/ # abstractions, ai-agents, constants, contracts, database,
27
+ │ │ # exceptions, extensions, feature, jobs, pipelines
28
+ │ ├── typescript/ # contracts.ts
29
+ │ └── sql/ # postgresql migrations, RLS policy, ai-agents
24
30
  │
25
- ├── context/ # Context generation
26
- │ ├── CONTEXT.md # Project-level context
27
- │ └── CONTEXT-FEATURE.md # Feature-level context
28
- │
29
- ├── code/ # Code templates organized by technology
30
- │ ├── dotnet/
31
- │ │ ├── backend/
32
- │ │ │ ├── service.cs # Service layer
33
- │ │ │ └── test.cs # Unit tests
34
- │ │ ├── database/
35
- │ │ │ └── migration.cs # EF Core migrations
36
- │ │ ├── jobs/
37
- │ │ │ ├── job.cs # Hangfire background jobs
38
- │ │ │ └── agent.cs # MS Agent Framework agents
39
- │ │ └── contracts/
40
- │ │ ├── contracts.cs # Base contracts
41
- │ │ ├── Commands.cs # CQRS commands
42
- │ │ ├── Queries.cs # CQRS queries
43
- │ │ ├── Entities.cs # Domain entities
44
- │ │ ├── api-contracts.cs # API contracts
45
- │ │ └── README.md # Contracts documentation
46
- │ │
47
- │ ├── typescript/
48
- │ │ └── contracts.ts # TypeScript type definitions
49
- │ │
50
- │ └── sql/
51
- │ ├── postgresql-migration.sql # Basic migration
52
- │ ├── postgresql-migration.template.sql # Enhanced migration
53
- │ └── postgresql-rls-policy.sql # Row-level security
31
+ ├── frontend/
32
+ │ └── nextjs/ # page, client-component, feature-form, use-feature, env, tsconfig…
54
33
  │
55
34
  ├── infrastructure/
56
- │ ├── docker/ # Docker & Coolify
57
- │ │ ├── dockerfile-api.dockerfile # .NET API
58
- │ │ ├── dockerfile-web.dockerfile # Next.js web
59
- │ │ ├── Dockerfile.template # Generic
60
- │ │ ├── docker-compose.template.yml # Compose
61
- │ │ └── coolify.template.json # Coolify config
62
- │ │
63
- │ └── github/ # GitHub Actions CI/CD
64
- │ ├── workflows/ # Reusable workflow templates
65
- │ │ ├── dotnet-build.yml.hbs # .NET restore, build, test
66
- │ │ ├── docker-build-push.yml.hbs # Docker build & push
67
- │ │ └── deploy-coolify.yml.hbs # Coolify deployment (via SSH)
68
- │ │
69
- │ ├── actions/ # Composite action templates
70
- │ │ ├── docker-build-push/action.yml.hbs
71
- │ │ └── health-check/action.yml.hbs
72
- │ │
73
- │ └── README.md # GitHub Actions docs
74
- │
75
- ├── integrations/ # Platform-agnostic integrations
76
- │ ├── asaas-client.cs # Asaas financial API
77
- │ ├── asaas-webhook.cs # Asaas webhooks
78
- │ └── neon-auth-config.cs # Neon Auth (Better Auth)
79
- │
80
- ├── ui/ # Design systems
81
- │ └── design-system.css # CSS tokens
35
+ │ ├── docker/ # Dockerfiles, compose, Coolify config
36
+ │ └── github/ # Actions workflows + composite actions (.hbs)
82
37
  │
83
- ├── saas/ # Multi-tenant patterns
84
- │
85
- ├── examples/ # Reference implementations
86
- │ ├── spec-examples.md # Example specs
87
- │ └── design-system-examples.md # Design system examples
88
- │
89
- └── REGISTRY.json # Template metadata registry
38
+ ├── integrations/ # asaas-client, asaas-webhook, neon-auth-config
39
+ ├── ui/ # design-system.css
40
+ ├── meta-prompts/ # fusion, squad-leaders, validators
41
+ ├── examples/ # spec-examples.md, design-system-examples.md
42
+ └── REGISTRY.json # template metadata — the index every consumer reads
90
43
  ```
91
44
 
92
45
  ---
93
46
 
94
- ## 🏗️ Technology-Based Architecture
95
-
96
- **Why organize by technology instead of by stack?**
97
-
98
- | Organization | Pros | Cons | Best For |
99
- |--------------|------|------|----------|
100
- | **By Stack** (old v1) | Stack-specific optimizations | Duplicate templates, hard to reuse | Single-stack projects |
101
- | **By Technology** (new v2) | Reusable, DRY, future-proof | Requires stack override mechanism | Multi-stack frameworks |
102
-
103
- **Example:** A `.NET service.cs` template works for both `dotnet-nextjs` and `nextjs-neon` stacks (both use .NET backend). No need to duplicate!
104
-
105
- **Future-proof:** When we create `vue-firebase` stack, we can reuse:
106
- - `code/typescript/` templates
107
- - `infrastructure/docker/` templates
108
- - `integrations/` templates (Neon Auth, etc.)
109
-
110
- **Only create NEW templates for Vue-specific code.**
111
-
112
- ---
113
-
114
47
  ## ⚙️ Template Engine: Handlebars
115
48
 
116
- All templates use **Handlebars** with **20+ custom helpers**.
117
-
118
- ### Basic Syntax
49
+ All templates render through Handlebars with custom helpers registered in
50
+ `src/core/templates/template-renderer.js`.
119
51
 
120
52
  ```handlebars
121
53
  # Feature: {{titleCase FEATURE_NAME}}
122
54
 
123
- Namespace: {{pascalCase FEATURE_NAME}}
55
+ namespace {{pascalCase FEATURE_NAME}};
124
56
 
125
- Created: {{DATE}}
57
+ Created: {{now}}
126
58
  ```
127
59
 
128
- ### Available Helpers
129
-
130
- | Helper | Input | Output | Usage |
131
- |--------|-------|--------|-------|
132
- | `{{pascalCase str}}` | `user-profile` | `UserProfile` | Class names |
133
- | `{{camelCase str}}` | `user-profile` | `userProfile` | Variable names |
134
- | `{{snakeCase str}}` | `user-profile` | `user_profile` | SQL tables |
135
- | `{{upperSnakeCase str}}` | `user-profile` | `USER_PROFILE` | Constants |
136
- | `{{titleCase str}}` | `user-profile` | `User Profile` | Titles |
137
- | `{{kebabCase str}}` | `User Profile` | `user-profile` | URLs |
138
- | `{{pluralize str}}` | `user` | `users` | Collections |
139
- | `{{singularize str}}` | `users` | `user` | Entities |
140
- | `{{eq a b}}` | `"nextjs" "nextjs"` | `true` | Conditionals |
141
- | `{{or a b}}` | `false true` | `true` | Logical OR |
142
- | `{{and a b}}` | `true false` | `false` | Logical AND |
143
- | `{{default val fallback}}` | `null "default"` | `"default"` | Defaults |
144
-
145
- ### Conditional Logic
60
+ ### Available helpers
61
+
62
+ | Group | Helpers |
63
+ |-------|---------|
64
+ | **Case** | `pascalCase` `camelCase` `snakeCase` `upperSnakeCase` `kebabCase` `titleCase` `uppercase` `lowercase` `capitalize` |
65
+ | **Words** | `pluralize` `singularize` |
66
+ | **Comparison** | `eq` `ne` `lt` `gt` `lte` `gte` |
67
+ | **Logic** | `and` `or` `not` `default` |
68
+ | **String** | `trim` `replace` `concat` `substr` `startsWith` `endsWith` `contains` `length` |
69
+ | **Math** | `add` `subtract` `multiply` `divide` `mod` `round` |
70
+ | **Array** | `join` `first` `last` `slice` |
71
+ | **Misc** | `json` `now` `year` `formatDate` |
146
72
 
147
73
  ```handlebars
148
74
  {{#if (eq STACK "nextjs-neon")}}
@@ -152,556 +78,59 @@ Created: {{DATE}}
152
78
  {{/if}}
153
79
  ```
154
80
 
155
- ### Deprecated: Pre-computed Variables
156
-
157
- **❌ Old (v1):**
158
- ```handlebars
159
- {{pascalCase FEATURE_NAME}} <!-- Pre-computed in bin/render-template.js -->
160
- ```
161
-
162
- **✅ New (v2):**
163
- ```handlebars
164
- {{pascalCase FEATURE_NAME}} <!-- Computed via Handlebars helper -->
165
- ```
166
-
167
- ---
168
-
169
- ## 🛠️ CLI Commands
170
-
171
- ### List All Templates
172
-
173
- ```bash
174
- # List all templates
175
- morph-spec template list
176
-
177
- # Filter by category
178
- morph-spec template list --category code
179
- morph-spec template list --category infrastructure
180
-
181
- # Filter by phase
182
- morph-spec template list --phase implement
183
-
184
- # Filter by stack applicability
185
- morph-spec template list --stack dotnet-nextjs
186
-
187
- # Show only required templates
188
- morph-spec template list --required
189
- ```
190
-
191
- **Output:**
192
- ```
193
- 📦 Universal Templates (9)
194
- proposal Feature Proposal [REQUIRED] [UNIVERSAL] [HBS]
195
- spec Technical Specification [REQUIRED] [UNIVERSAL] [HBS]
196
- tasks Implementation Tasks [REQUIRED] [UNIVERSAL] [HBS]
197
- ...
198
-
199
- 📦 Technology-Based Templates (48)
200
- dotnet-backend-service .NET Service Class [UNIVERSAL] [HBS] (dotnet)
201
- typescript-contracts TypeScript Contracts [UNIVERSAL] [HBS] (typescript)
202
- ...
203
- ```
204
-
205
- ### Show Template Details
206
-
207
- ```bash
208
- # Show metadata
209
- morph-spec template show dotnet-backend-service
210
-
211
- # Show with file preview
212
- morph-spec template show dotnet-backend-service --preview
213
-
214
- # Show with resolved path
215
- morph-spec template show dotnet-backend-service --show-path
216
- ```
217
-
218
- **Output:**
219
- ```
220
- Template: dotnet-backend-service
221
-
222
- 📋 Metadata
223
- ID: dotnet-backend-service
224
- Name: .NET Service Class
225
- Path: code/dotnet/backend/service.cs
226
- Location: framework
227
- Category: code
228
- Phase: implement
229
- Required: No
230
- Technology: dotnet
231
- Applicable Stacks: dotnet-nextjs, nextjs-neon
232
-
233
- 📝 Description
234
- C# service class template with dependency injection and interface pattern
235
-
236
- 🔑 Variables
237
- {{FEATURE_NAME}}
238
- {{NAMESPACE}}
239
-
240
- 📄 Output Name
241
- {FeatureName}Service.cs
242
-
243
- 💡 Usage Hint
244
- morph-spec template render dotnet-backend-service output.cs '{"FEATURE_NAME":"user-auth","NAMESPACE":"MyApp"}'
245
- ```
246
-
247
- ### Render Template
248
-
249
- ```bash
250
- # Render to file
251
- morph-spec template render dotnet-backend-service UserAuthService.cs '{
252
- "FEATURE_NAME": "user-auth",
253
- "NAMESPACE": "MyApp.Services"
254
- }'
255
-
256
- # Dry run (preview only)
257
- morph-spec template render dotnet-backend-service output.cs '{"FEATURE_NAME":"test"}' --dry-run
258
-
259
- # Auto-resolve path (searches framework → stack override)
260
- morph-spec template render proposal proposal.md '{"FEATURE_NAME":"auth"}' --resolve-path
261
- ```
262
-
263
- **Default Variables (auto-injected):**
264
- - `DATE`: `2026-02-17`
265
- - `YEAR`: `2026`
266
- - `TIMESTAMP`: `2026-02-17T19:38:00.000Z`
267
-
268
- ### Customize Template (Stack Override)
269
-
270
- ```bash
271
- # Copy to stack-specific directory (override framework version)
272
- morph-spec template customize dotnet-backend-service --stack dotnet-nextjs
273
-
274
- # Copy to project-local (cross-stack override)
275
- morph-spec template customize dotnet-backend-service --local
276
-
277
- # Force overwrite if exists
278
- morph-spec template customize dotnet-backend-service --stack dotnet-nextjs --force
279
- ```
280
-
281
- **Output:**
282
- ```
283
- Source: framework/templates/code/dotnet/backend/service.cs
284
- Destination: stacks/dotnet-nextjs/.morph/framework/templates/code/dotnet/backend/service.cs
285
-
286
- ✅ Template copied for customization
287
-
288
- 📝 Next Steps
289
- 1. Edit the template file:
290
- stacks/dotnet-nextjs/.morph/framework/templates/code/dotnet/backend/service.cs
291
-
292
- 2. Template will now be used instead of framework version
293
- (Stack-specific templates take precedence)
294
-
295
- 3. Test rendering:
296
- morph-spec template render dotnet-backend-service output.cs '{"FEATURE_NAME":"test"}'
297
-
298
- ⚠️ Customized templates won't receive framework updates
299
- To get updates: delete customized version and re-run this command
300
- ```
301
-
302
- ---
303
-
304
- ## 🔄 GitHub Actions Templates
305
-
306
- The framework provides reusable GitHub Actions workflows and composite actions for CI/CD automation.
307
-
308
- ### Structure
309
-
310
- ```
311
- infrastructure/github/
312
- ├── workflows/ # Reusable workflow templates
313
- │ ├── dotnet-build.yml.hbs # .NET restore, build, test
314
- │ ├── docker-build-push.yml.hbs # Docker build & push
315
- │ └── deploy-coolify.yml.hbs # Coolify deployment via SSH
316
- │
317
- └── actions/ # Composite action templates
318
- ├── docker-build-push/action.yml.hbs
319
- └── health-check/action.yml.hbs
320
- ```
321
-
322
- ### Reusable Workflows vs Composite Actions
323
-
324
- | Type | Purpose | Location | Usage |
325
- |------|---------|----------|-------|
326
- | **Reusable Workflows** | Complete CI/CD pipelines (multi-job) | `workflows/*.yml.hbs` | Called via `uses:` from stack workflows |
327
- | **Composite Actions** | Reusable step logic (single responsibility) | `actions/*/action.yml.hbs` | Called via `uses:` in workflow steps |
328
-
329
- ### Deployment Strategy Difference
330
-
331
- **NextJS-Neon:** Docker containers to Coolify
332
- - `docker build` → `docker push` → Coolify deploy triggered via SSH (Coolify's API is not publicly exposed — the runner SSHes into the VPS and calls `localhost:8000/api/v1/deploy` there)
333
- - Multi-service deployment (API + Web)
334
- - Registry: GitHub Container Registry (ghcr.io)
335
-
336
- ### Template Rendering
337
-
338
- **GitHub Actions Constraint:**
339
- - ❌ GitHub Actions CANNOT reference parent directories (`../../../../framework/`)
340
- - ✅ Solution: Framework templates are **rendered** into each stack's `.github/` directory
341
- - Rendered `.yml` files are **committed** to repos (not `.yml.hbs` templates)
342
-
343
- **Rendering Process:**
344
- ```bash
345
- # Render all GitHub Actions templates for a stack (manual for now)
346
- # Future: morph-spec template render github-workflows --stack dotnet-nextjs
347
- ```
348
-
349
- ### Handlebars Variables
350
-
351
- - `{{APP_NAME}}` - Application name from config.json
352
- - `{{DOTNET_VERSION}}` - .NET SDK version
353
- - `{{GITHUB_OWNER}}` - GitHub organization/user
354
- - `{{kebabCase APP_NAME}}` - Docker image name format
355
- - `${{{{ inputs.* }}}}` - GitHub Actions runtime syntax (escaped with `{{{{raw}}}}`)
356
-
357
- ### Authentication & Secrets
358
-
359
- **Docker Registry (NextJS-Neon):**
360
- ```yaml
361
- # GitHub Container Registry (ghcr.io)
362
- - uses: docker/login-action@v3
363
- with:
364
- registry: ghcr.io
365
- username: ${{{{ github.actor }}}}
366
- password: ${{{{ secrets.GITHUB_TOKEN }}}}
367
- ```
368
-
369
- **GitHub Secrets to Configure:**
370
- - NextJS-Neon: `GITHUB_TOKEN` (auto), `COOLIFY_SSH_HOST`, `COOLIFY_SSH_USER`, `COOLIFY_SSH_KEY`, `COOLIFY_APPLICATION_UUID`
371
-
372
- ### Stack-Specific Overrides
373
-
374
- Stack-specific workflow templates in:
375
- - `stacks/nextjs-neon/.morph/framework/templates/infrastructure/github/workflows/`
376
-
377
- **Resolution Order:**
378
- 1. Project-local: `.morph/framework/templates/infrastructure/github/workflows/ci-build.yml.hbs`
379
- 2. Stack default: `stacks/{stack}/.morph/framework/templates/infrastructure/github/workflows/ci-build.yml.hbs`
380
- 3. Framework fallback: `framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs`
381
-
382
- ---
383
-
384
- ## 🔀 Stack Override Mechanism
385
-
386
- **Resolution Order:**
387
-
388
- 1. **Stack-specific override** (highest priority)
389
- - `stacks/{stack}/.morph/framework/templates/code/dotnet/backend/service.cs`
390
-
391
- 2. **Project-local override** (medium priority)
392
- - `.morph/framework/templates/code/dotnet/backend/service.cs`
393
-
394
- 3. **Framework template** (fallback)
395
- - `framework/templates/code/dotnet/backend/service.cs`
396
-
397
- **Use Cases for Overrides:**
398
-
399
- | Scenario | Override Location | Example |
400
- |----------|-------------------|---------|
401
- | Stack-specific tweak | `stacks/{stack}/.morph/framework/templates/` | Stack uses different DI pattern |
402
- | Project-wide customization | `.morph/framework/templates/` | Company-specific code style |
403
- | Use framework default | None (no override) | Standard templates work fine |
404
-
405
- **Example:**
406
-
407
- ```bash
408
- # Create stack override
409
- morph-spec template customize dotnet-backend-service --stack dotnet-nextjs
410
-
411
- # Edit the override
412
- code stacks/dotnet-nextjs/.morph/framework/templates/code/dotnet/backend/service.cs
413
-
414
- # Now all renders for dotnet-nextjs will use the override
415
- morph-spec template render dotnet-backend-service UserService.cs '...' --stack dotnet-nextjs
416
- ```
417
-
418
- ---
419
-
420
- ## 📊 Template Registry (REGISTRY.json)
421
-
422
- The `REGISTRY.json` file is the **single source of truth** for all template metadata.
423
-
424
- ### Schema
425
-
426
- ```json
427
- {
428
- "version": "2.0.0",
429
- "templates": [
430
- {
431
- "id": "dotnet-backend-service",
432
- "name": ".NET Service Class",
433
- "path": "code/dotnet/backend/service.cs",
434
- "location": "framework",
435
- "category": "code",
436
- "phase": "implement",
437
- "required": false,
438
- "technology": "dotnet",
439
- "applicableStacks": ["dotnet-nextjs", "nextjs-neon"],
440
- "engine": "handlebars",
441
- "placeholders": ["FEATURE_NAME", "NAMESPACE"],
442
- "outputName": "{FeatureName}Service.cs",
443
- "deprecated": false
444
- }
445
- ]
446
- }
447
- ```
448
-
449
- ### Discovery API
450
-
451
- ```javascript
452
- import {
453
- getAllTemplates,
454
- getTemplateById,
455
- getTemplatesByCategory,
456
- getTemplatesByTechnology,
457
- resolveTemplatePathById
458
- } from '../src/lib/template-registry.js';
459
-
460
- // Get all templates
461
- const all = getAllTemplates();
462
-
463
- // Get specific template
464
- const service = getTemplateById('dotnet-backend-service');
465
-
466
- // Filter by category
467
- const codeTemplates = getTemplatesByCategory('code');
468
-
469
- // Filter by technology
470
- const dotnetTemplates = getTemplatesByTechnology('dotnet');
471
-
472
- // Resolve path with fallback
473
- const path = resolveTemplatePathById('dotnet-backend-service', '/project', 'dotnet-nextjs');
474
- // Returns: framework/templates/code/dotnet/backend/service.cs
475
- // Or: stacks/dotnet-nextjs/.morph/framework/templates/code/dotnet/backend/service.cs (if override exists)
476
- ```
477
-
478
81
  ---
479
82
 
480
- ## 🚀 Creating New Templates
83
+ ## 🔗 How templates are consumed
481
84
 
482
- ### 1. Create Template File
85
+ Templates are **resolved from the installed npm package**, not copied into projects.
86
+ `morph-spec setup-infra` deliberately skips copying `framework/templates/` — a target project
87
+ gets the package's templates for free and stays current on every upgrade.
483
88
 
484
- ```bash
485
- # For .NET templates
486
- touch framework/templates/code/dotnet/backend/my-template.cs
487
-
488
- # For infrastructure templates
489
- touch framework/templates/infrastructure/docker/my-resource.dockerfile
490
- ```
491
-
492
- ### 2. Add Handlebars Placeholders
493
-
494
- ```handlebars
495
- namespace {{pascalCase NAMESPACE}};
496
-
497
- public class {{pascalCase FEATURE_NAME}}Service
498
- {
499
- // TODO: Implement {{titleCase FEATURE_NAME}} logic
500
- }
501
- ```
502
-
503
- ### 3. Register in REGISTRY.json
504
-
505
- ```json
506
- {
507
- "id": "dotnet-backend-my-template",
508
- "name": "My Custom Template",
509
- "path": "code/dotnet/backend/my-template.cs",
510
- "location": "framework",
511
- "category": "code",
512
- "phase": "implement",
513
- "required": false,
514
- "technology": "dotnet",
515
- "applicableStacks": ["dotnet-nextjs"],
516
- "engine": "handlebars",
517
- "placeholders": ["FEATURE_NAME", "NAMESPACE"],
518
- "outputName": "{FeatureName}MyTemplate.cs",
519
- "deprecated": false
520
- }
521
- ```
522
-
523
- ### 4. Test Rendering
89
+ **The consumer is the scaffolder**, which pairs a REGISTRY `id` with an output shape:
524
90
 
525
91
  ```bash
526
- morph-spec template render dotnet-backend-my-template output.cs '{
527
- "FEATURE_NAME": "user-auth",
528
- "NAMESPACE": "MyApp.Services"
529
- }'
530
- ```
531
-
532
- ---
533
-
534
- ## 📦 Migration Guide: v1 → v2
535
-
536
- ### What Changed
537
-
538
- | Aspect | v1 (Stack-Based) | v2 (Technology-Based) |
539
- |--------|------------------|----------------------|
540
- | **Location** | `stacks/{stack}/.morph/framework/templates/` | `framework/templates/{technology}/` |
541
- | **Organization** | By stack (dotnet-nextjs, nextjs-neon) | By technology (dotnet, docker) |
542
- | **Duplication** | High (proposal.md × 2, decisions.md × 2) | Low (shared templates in framework) |
543
- | **Template Engine** | 3 engines (custom, Handlebars, mixed) | 1 engine (Handlebars with helpers) |
544
- | **Pre-computed Variables** | `{{pascalCase FEATURE_NAME}}` | `{{pascalCase FEATURE_NAME}}` (helpers) |
545
- | **Registry** | None (hardcoded paths) | `REGISTRY.json` (centralized metadata) |
546
- | **CLI** | None | `morph-spec template list/show/render/customize` |
547
- | **Future Stacks** | Must copy templates | Reuse existing technology templates |
548
-
549
- ### Breaking Changes
550
-
551
- **1. Template Paths**
552
-
553
- ```diff
554
- - stacks/dotnet-nextjs/.morph/framework/templates/service.cs
555
- + framework/templates/code/dotnet/backend/service.cs
556
-
557
- - stacks/nextjs-neon/.morph/framework/templates/dockerfile-web.dockerfile
558
- + framework/templates/infrastructure/docker/dockerfile-web.dockerfile
559
- ```
560
-
561
- **2. Pre-computed Variables**
562
-
563
- ```diff
564
- - {{pascalCase FEATURE_NAME}}
565
- + {{pascalCase FEATURE_NAME}}
566
-
567
- - {{camelCase FEATURE_NAME}}
568
- + {{camelCase FEATURE_NAME}}
569
-
570
- - {{snakeCase FEATURE_NAME}}
571
- + {{snakeCase FEATURE_NAME}}
572
- ```
573
-
574
- **3. Template Resolution**
575
-
576
- ```javascript
577
- // Old (v1)
578
- const templatePath = join(resolveTemplatesDir(projectPath), 'service.cs');
579
-
580
- // New (v2)
581
- const templatePath = resolveTemplatePath(projectPath, 'code/dotnet/backend/service.cs', stackId);
582
- // Automatically falls back: stack override → framework
583
- ```
584
-
585
- ### Migration Steps
586
-
587
- **Step 1:** Update code to use `resolveTemplatePath()`
588
-
589
- ```javascript
590
- import { resolveTemplatePath } from '../lib/stack-resolver.js';
591
-
592
- // Before
593
- const path = join(resolveTemplatesDir(process.cwd()), 'service.cs');
594
-
595
- // After
596
- const path = resolveTemplatePath(process.cwd(), 'code/dotnet/backend/service.cs', 'dotnet-nextjs');
92
+ morph-spec scaffold dotnet <feature> <slice-name> # VSA slice (endpoint, handler, request,
93
+ # response, validator, errors, entity)
94
+ morph-spec scaffold nextjs <feature> # page, client component, form, hook
597
95
  ```
598
96
 
599
- **Step 2:** Update template syntax to Handlebars
97
+ There is **no `morph-spec template` command** — the v4 CLI surface (`list`/`show`/`render`/
98
+ `customize`) was removed in the v4→v5 migration. To use a template by hand, read the file and
99
+ follow its pattern, or call `renderTemplate()` from the renderer module.
600
100
 
601
- ```handlebars
602
- <!-- Before -->
603
- namespace {{NAMESPACE}};
604
- public class {{pascalCase FEATURE_NAME}}Service { }
605
-
606
- <!-- After -->
607
- namespace {{pascalCase NAMESPACE}};
608
- public class {{pascalCase FEATURE_NAME}}Service { }
609
- ```
610
-
611
- **Step 3:** Use CLI commands instead of hardcoded paths
612
-
613
- ```bash
614
- # Before (hardcoded)
615
- cp framework/templates/proposal.md .morph/features/user-auth/proposal.md
101
+ ### Local override
616
102
 
617
- # After (CLI)
618
- morph-spec template render proposal .morph/features/user-auth/proposal.md '{
619
- "FEATURE_NAME": "user-auth"
620
- }'
621
- ```
103
+ A project may shadow any packaged template by placing a file at the same relative path under
104
+ `.morph/framework/templates/{path}`. The local copy wins, and **stops receiving framework
105
+ updates** — only override when the packaged template genuinely does not fit.
622
106
 
623
107
  ---
624
108
 
625
- ## 🎯 Best Practices
626
-
627
- ### 1. **Use Helpers, Not Pre-computed Variables**
628
-
629
- ```handlebars
630
- ✅ GOOD:
631
- {{pascalCase FEATURE_NAME}}Service
632
-
633
- ❌ BAD:
634
- {{pascalCase FEATURE_NAME}}Service // Deprecated, won't work
635
- ```
636
-
637
- ### 2. **Keep Templates Technology-Agnostic**
638
-
639
- ```handlebars
640
- ✅ GOOD: code/dotnet/backend/service.cs
641
- Works for: dotnet-nextjs, nextjs-neon, future-dotnet-stack
642
-
643
- ❌ BAD: code/stack-specific/service.cs
644
- Locked to one stack only
645
- ```
646
-
647
- ### 3. **Use Stack Conditionals for Differences**
648
-
649
- ```handlebars
650
- {{#if (eq STACK "nextjs-neon")}}
651
- // Neon-specific implementation
652
- {{else}}
653
- // Generic implementation
654
- {{/if}}
655
- ```
656
-
657
- ### 4. **Document Applicability in Registry**
658
-
659
- ```json
660
- {
661
- "technology": "dotnet",
662
- "applicableStacks": ["dotnet-nextjs", "nextjs-neon"],
663
- "description": "Works with any .NET backend stack"
664
- }
665
- ```
109
+ ## ➕ Adding a template
666
110
 
667
- ### 5. **Override Only When Necessary**
111
+ 1. Create the file under the right technology directory:
112
+ `framework/templates/code/{technology}/...` (Handlebars syntax, `.hbs` when the extension
113
+ would otherwise confuse tooling).
114
+ 2. Register it in `REGISTRY.json` with a unique `id`, its `path`, `category`, `technology`
115
+ and applicable stacks.
116
+ 3. If a generator should emit it, add the `id` to the relevant list in
117
+ `src/lib/generators/scaffold-generator.js`.
668
118
 
669
- ```bash
670
- # Only customize if framework template doesn't meet needs
671
- morph-spec template customize dotnet-backend-service --stack dotnet-nextjs
119
+ ### Deprecating a template
672
120
 
673
- # Otherwise, use framework version (gets updates automatically)
674
- morph-spec template render dotnet-backend-service output.cs '...'
675
- ```
121
+ Add `"deprecated": true` plus `"deprecationReason"` to its `REGISTRY.json` entry. Keep the
122
+ file until a major version bump.
676
123
 
677
124
  ---
678
125
 
679
126
  ## 📚 References
680
127
 
681
- - **Template Registry API:** [`src/lib/template-registry.js`](../../src/lib/template-registry.js)
682
- - **Template Renderer:** [`src/lib/template-renderer.js`](../../src/lib/template-renderer.js)
683
- - **Stack Resolver:** [`src/lib/stack-resolver.js`](../../src/lib/stack-resolver.js)
684
- - **CLI Commands:** [`src/commands/template-*.js`](../../src/commands/)
685
- - **Handlebars Docs:** https://handlebarsjs.com/
686
-
687
- ---
688
-
689
- ## 🤝 Contributing
690
-
691
- ### Adding New Technology
692
-
693
- 1. Create directory: `framework/templates/code/{technology}/`
694
- 2. Add templates with Handlebars syntax
695
- 3. Register in `REGISTRY.json` with `"technology": "{technology}"`
696
- 4. Test with `morph-spec template render`
697
- 5. Document in this README
698
-
699
- ### Deprecating Templates
700
-
701
- 1. Add `"deprecated": true` to `REGISTRY.json`
702
- 2. Add `"deprecationReason": "Reason here"`
703
- 3. Keep file for backward compatibility or remove after major version bump
128
+ - **Registry API:** [`src/core/templates/template-registry.js`](../../src/core/templates/template-registry.js)
129
+ - **Renderer + helpers:** [`src/core/templates/template-renderer.js`](../../src/core/templates/template-renderer.js)
130
+ - **Scaffold generator:** [`src/lib/generators/scaffold-generator.js`](../../src/lib/generators/scaffold-generator.js)
131
+ - **Stack filtering:** [`src/lib/stack-filter.js`](../../src/lib/stack-filter.js)
132
+ - **Handlebars docs:** https://handlebarsjs.com/
704
133
 
705
134
  ---
706
135
 
707
- **MORPH-SPEC Template System v2.0** - Technology-Based, Future-Proof, DRY ✨
136
+ **MORPH-SPEC Template System** — technology-based, registry-indexed, resolved from the package.