@polymorphism-tech/morph-spec 4.21.0 → 5.0.1

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 (213) hide show
  1. package/CLAUDE.md +57 -71
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +224 -491
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +55 -38
  8. package/framework/MORPH.md +244 -0
  9. package/framework/agents.json +127 -1183
  10. package/framework/commands/morph-apply.md +56 -240
  11. package/framework/commands/morph-archive.md +48 -85
  12. package/framework/commands/morph-preflight.md +7 -7
  13. package/framework/commands/morph-proposal.md +35 -191
  14. package/framework/commands/morph-status.md +19 -50
  15. package/framework/commands/morph-troubleshoot.md +2 -2
  16. package/framework/evals/rubrics/README.md +44 -0
  17. package/framework/evals/rubrics/architecture.md +46 -0
  18. package/framework/evals/rubrics/code-quality.md +50 -0
  19. package/framework/evals/rubrics/contracts.md +47 -0
  20. package/framework/evals/rubrics/test-coverage.md +50 -0
  21. package/framework/evals/scenarios/dotnet-crud.yaml +42 -0
  22. package/framework/evals/scenarios/nextjs-auth.yaml +38 -0
  23. package/framework/evals/suites/standard.yaml +5 -0
  24. package/framework/evals/trace-schema.md +67 -0
  25. package/framework/hooks/claude-code/core/README.md +3 -0
  26. package/framework/hooks/claude-code/core/denylist.json +14 -0
  27. package/framework/hooks/claude-code/{pre-tool-use → core}/enforce-phase-writes.js +5 -5
  28. package/framework/hooks/claude-code/core/post-edit-typecheck.js +69 -0
  29. package/framework/hooks/claude-code/core/pre-bash-denylist.js +29 -0
  30. package/framework/hooks/claude-code/{pre-tool-use → core}/protect-spec-files.js +4 -6
  31. package/framework/hooks/claude-code/{stop → core}/validate-completion.js +13 -82
  32. package/framework/hooks/shared/phase-utils.js +20 -28
  33. package/framework/hooks/shared/state-reader.js +4 -5
  34. package/framework/{skills/level-0-meta/mcp-registry.json → mcp/registry.json} +254 -210
  35. package/framework/phases.json +40 -114
  36. package/framework/rubrics/eval-rubric.json +66 -0
  37. package/framework/skills/README.md +39 -64
  38. package/framework/skills/core/README.md +3 -0
  39. package/framework/skills/core/morph-brainstorming/SKILL.md +102 -0
  40. package/framework/skills/core/morph-eval/SKILL.md +57 -0
  41. package/framework/skills/core/morph-implement/SKILL.md +83 -0
  42. package/framework/skills/core/morph-plan/SKILL.md +64 -0
  43. package/framework/skills/core/morph-review/SKILL.md +62 -0
  44. package/framework/skills/core/morph-stack-scan/SKILL.md +109 -0
  45. package/framework/skills/core/morph-standards/SKILL.md +49 -0
  46. package/framework/standards/STANDARDS.json +32 -0
  47. package/framework/standards/frontend/design-system/ai-image-generation.md +244 -0
  48. package/framework/standards/integration/mcp/mcp-tools.md +48 -0
  49. package/framework/templates/CLAUDE.md.core.guide.md +29 -0
  50. package/framework/templates/CLAUDE.md.core.template +22 -0
  51. package/framework/templates/REGISTRY.json +4 -4
  52. package/framework/workflows/configs/fast-track.json +5 -10
  53. package/framework/workflows/configs/full.json +4 -8
  54. package/framework/workflows/configs/quick.json +32 -0
  55. package/framework/workflows/configs/standard.json +57 -64
  56. package/package.json +7 -6
  57. package/src/commands/mcp/mcp-setup.js +58 -31
  58. package/src/commands/project/doctor.js +69 -70
  59. package/src/commands/project/init.js +26 -5
  60. package/src/commands/project/status.js +18 -19
  61. package/src/commands/state/approve.js +1 -1
  62. package/src/commands/validation/validate-feature.js +18 -112
  63. package/src/core/paths/output-schema.js +133 -151
  64. package/src/core/state/phase-state-machine.js +10 -24
  65. package/src/core/state/state-manager.js +17 -17
  66. package/src/core/workflows/workflow-detector.js +214 -31
  67. package/src/core/workflows/workflow-router.js +204 -0
  68. package/src/dashboard/app/pages/AgentMap.jsx +32 -33
  69. package/src/dashboard/app/pages/LiveState.jsx +1 -1
  70. package/src/dashboard/app/pages/PhasePipeline.jsx +2 -4
  71. package/src/dashboard/app/pages/SkillsLibrary.jsx +2 -3
  72. package/src/dashboard/app/pages/Workflows.jsx +2 -2
  73. package/src/dashboard/scanner/agents-scanner.js +30 -35
  74. package/src/lib/agents/metrics-aggregator.js +1 -1
  75. package/src/lib/agents/output-collector.js +7 -8
  76. package/src/lib/context/context-builder.js +289 -0
  77. package/src/lib/detectors/claude-config-detector.js +19 -3
  78. package/src/lib/generators/context-generator.js +20 -42
  79. package/src/lib/generators/index.js +1 -0
  80. package/src/lib/generators/mandate-generator.js +512 -0
  81. package/src/lib/generators/metadata-extractor.js +1 -1
  82. package/src/lib/generators/recap-generator.js +3 -4
  83. package/src/lib/installers/mcp-installer.js +300 -92
  84. package/src/lib/phase-chain/phase-validator.js +36 -40
  85. package/src/lib/stack/stack-profile.js +74 -91
  86. package/src/lib/tasks/task-parser.js +1 -1
  87. package/src/lib/tasks/wave-resolver.js +353 -0
  88. package/src/lib/validators/checkpoint-persistence.js +2 -2
  89. package/src/lib/validators/content/cross-phase-validator.js +281 -0
  90. package/src/lib/validators/content/index.js +1 -0
  91. package/src/lib/validators/shared/emit-validator-dispatch.js +6 -56
  92. package/src/scripts/global-install.js +2 -27
  93. package/src/utils/agents-installer.js +224 -447
  94. package/src/utils/claude-settings-manager.js +57 -15
  95. package/src/utils/file-copier.js +1 -0
  96. package/src/utils/hooks-installer.js +15 -117
  97. package/src/utils/skills-installer.js +12 -18
  98. package/bin/detect-agents.js +0 -226
  99. package/bin/task-manager.js +0 -1036
  100. package/framework/agents/README.md +0 -13
  101. package/framework/agents/ai-agents/ai-system-architect.md +0 -194
  102. package/framework/agents/ai-agents/vector-search-expert.md +0 -247
  103. package/framework/agents/architecture/architecture-expert.md +0 -98
  104. package/framework/agents/architecture/morph-spec-architect.md +0 -66
  105. package/framework/agents/architecture/packages-validator.md +0 -89
  106. package/framework/agents/architecture/security-expert.md +0 -79
  107. package/framework/agents/architecture/seo-growth-hacker.md +0 -168
  108. package/framework/agents/architecture/standards-architect.md +0 -153
  109. package/framework/agents/backend/dotnet-senior.md +0 -163
  110. package/framework/agents/backend/ef-modeler.md +0 -119
  111. package/framework/agents/backend/hangfire-orchestrator.md +0 -133
  112. package/framework/agents/backend/ms-agent-expert.md +0 -55
  113. package/framework/agents/backend/neon-expert.md +0 -379
  114. package/framework/agents/frontend/css-specialist.md +0 -89
  115. package/framework/agents/frontend/design-system-validator.md +0 -100
  116. package/framework/agents/frontend/gsap-animator.md +0 -131
  117. package/framework/agents/frontend/nextjs-component-validator.md +0 -97
  118. package/framework/agents/frontend/nextjs-expert.md +0 -201
  119. package/framework/agents/frontend/ui-designer.md +0 -259
  120. package/framework/agents/infrastructure/infra-architect.md +0 -215
  121. package/framework/agents/integrations/asaas-financial.md +0 -138
  122. package/framework/agents/integrations/neon-auth.md +0 -151
  123. package/framework/agents/integrations/resend-email.md +0 -127
  124. package/framework/hooks/claude-code/post-tool-use/agent-complete.js +0 -122
  125. package/framework/hooks/claude-code/post-tool-use/dispatch.js +0 -363
  126. package/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +0 -78
  127. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +0 -194
  128. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +0 -199
  129. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +0 -55
  130. package/framework/hooks/claude-code/session-start/inject-morph-context.js +0 -323
  131. package/framework/hooks/claude-code/session-start/post-compact-restore.js +0 -41
  132. package/framework/hooks/claude-code/session-start/resume-context.js +0 -77
  133. package/framework/hooks/claude-code/teammate-idle/teammate-idle.js +0 -90
  134. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +0 -114
  135. package/framework/hooks/shared/compact-restore.js +0 -123
  136. package/framework/hooks/shared/dispatch-helpers.js +0 -147
  137. package/framework/hooks/shared/skill-reminder-helpers.js +0 -79
  138. package/framework/hooks/shared/stale-task-reset.js +0 -57
  139. package/framework/hooks/shared/worktree-helpers.js +0 -75
  140. package/framework/skills/level-0-meta/README.md +0 -7
  141. package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +0 -472
  142. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +0 -174
  143. package/framework/skills/level-0-meta/morph-brainstorming/references/proposal-example.md +0 -138
  144. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +0 -145
  145. package/framework/skills/level-0-meta/morph-code-review/SKILL.md +0 -250
  146. package/framework/skills/level-0-meta/morph-code-review/references/review-example.md +0 -164
  147. package/framework/skills/level-0-meta/morph-code-review/references/review-guidelines.md +0 -100
  148. package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +0 -151
  149. package/framework/skills/level-0-meta/morph-code-review-nextjs/SKILL.md +0 -165
  150. package/framework/skills/level-0-meta/morph-code-review-nextjs/references/review-example-nextjs.md +0 -254
  151. package/framework/skills/level-0-meta/morph-code-review-nextjs/scripts/scan-nextjs.mjs +0 -189
  152. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +0 -344
  153. package/framework/skills/level-0-meta/morph-frontend-review/scripts/scan-accessibility.mjs +0 -376
  154. package/framework/skills/level-0-meta/morph-init/SKILL.md +0 -537
  155. package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +0 -225
  156. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +0 -382
  157. package/framework/skills/level-0-meta/morph-post-implementation/scripts/detect-dev-server.mjs +0 -153
  158. package/framework/skills/level-0-meta/morph-post-implementation/scripts/detect-stack.mjs +0 -234
  159. package/framework/skills/level-0-meta/morph-simulation-checklist/SKILL.md +0 -106
  160. package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +0 -243
  161. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +0 -169
  162. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +0 -148
  163. package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +0 -110
  164. package/framework/skills/level-1-workflows/README.md +0 -7
  165. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +0 -269
  166. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +0 -453
  167. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +0 -44
  168. package/framework/skills/level-1-workflows/morph-phase-design/references/spec-authoring-guide.md +0 -55
  169. package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +0 -253
  170. package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +0 -38
  171. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +0 -493
  172. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +0 -50
  173. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +0 -46
  174. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +0 -47
  175. package/framework/skills/level-1-workflows/morph-phase-implement/references/recap-example.md +0 -132
  176. package/framework/skills/level-1-workflows/morph-phase-implement/references/vsa-implementation-guide.md +0 -92
  177. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +0 -257
  178. package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +0 -14
  179. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +0 -291
  180. package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +0 -143
  181. package/framework/skills/level-1-workflows/morph-phase-tasks/references/tasks-example.md +0 -404
  182. package/framework/skills/level-1-workflows/morph-phase-tasks/scripts/validate-tasks.mjs +0 -112
  183. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +0 -788
  184. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +0 -147
  185. package/framework/squad-templates/backend-only.json +0 -47
  186. package/framework/squad-templates/frontend-only.json +0 -56
  187. package/framework/squad-templates/full-stack.json +0 -74
  188. package/src/commands/agents/agent-metrics.js +0 -174
  189. package/src/commands/agents/audit-dispatch.js +0 -82
  190. package/src/commands/agents/detect-agents.js +0 -275
  191. package/src/commands/agents/dispatch-agents.js +0 -461
  192. package/src/commands/agents/index.js +0 -13
  193. package/src/commands/agents/manage-agents.js +0 -352
  194. package/src/commands/agents/project-metrics.js +0 -74
  195. package/src/commands/phase/phase-reset.js +0 -74
  196. package/src/commands/scope/escalate.js +0 -217
  197. package/src/commands/state/advance-phase.js +0 -600
  198. package/src/commands/state/phase-runner.js +0 -215
  199. package/src/commands/state/state.js +0 -444
  200. package/src/commands/task/expand.js +0 -100
  201. package/src/commands/tasks/index.js +0 -4
  202. package/src/commands/tasks/task.js +0 -105
  203. package/src/commands/templates/index.js +0 -5
  204. package/src/commands/templates/template-render.js +0 -93
  205. package/src/commands/trust/trust.js +0 -118
  206. package/src/lib/agents/agents-manager.js +0 -349
  207. package/src/lib/build/build-runner.js +0 -99
  208. package/src/lib/checkpoints/checkpoint-hooks.js +0 -111
  209. package/src/lib/contracts/sprint-contract-generator.js +0 -137
  210. package/src/lib/scope/impact-analyzer.js +0 -106
  211. package/src/lib/trust/trust-manager.js +0 -157
  212. package/src/utils/tier-helpers.js +0 -24
  213. /package/framework/hooks/claude-code/{post-tool-use → core}/loop-detect.js +0 -0
@@ -68,30 +68,23 @@ function getNpmGlobalPrefix() {
68
68
  }
69
69
  }
70
70
 
71
- // lib files
71
+ // lib files (v5 — minimal surface)
72
72
  const REQUIRED_LIB_FILES = [
73
- 'src/lib/trust/trust-manager.js'
73
+ 'src/lib/stack-filter.js'
74
74
  ];
75
75
 
76
- // command files (current CLI surface after radical simplification)
76
+ // command files (v5 CLI surface — installer-only)
77
77
  const REQUIRED_COMMAND_FILES = [
78
78
  'src/commands/project/init.js',
79
79
  'src/commands/project/update.js',
80
80
  'src/commands/project/doctor.js',
81
81
  'src/commands/project/status.js',
82
- 'src/commands/state/state.js',
83
- 'src/commands/state/advance-phase.js',
82
+ 'src/commands/project/worktree.js',
84
83
  'src/commands/state/approve.js',
85
- 'src/commands/tasks/task.js',
86
- 'src/commands/trust/trust.js',
87
84
  'src/commands/validation/validate-feature.js',
88
- 'src/commands/templates/template-render.js',
89
- 'src/commands/agents/dispatch-agents.js',
90
- 'src/commands/project/worktree.js',
91
- 'src/commands/phase/phase-reset.js',
92
- 'src/commands/scope/escalate.js',
93
- 'src/commands/task/expand.js',
94
- 'src/lib/scope/impact-analyzer.js'
85
+ 'src/commands/scaffold/scaffold.js',
86
+ 'src/commands/mcp/mcp-setup.js',
87
+ 'src/commands/context/context-refresh.js',
95
88
  ];
96
89
 
97
90
  // framework standards (stack-relevant only)
@@ -105,9 +98,9 @@ const FRAMEWORK_STANDARDS = [
105
98
  'framework/standards/workflows/parallel-execution.md'
106
99
  ];
107
100
 
108
- // required agents expected in agents.json
101
+ // required personas expected in agents.json (v5 — at least the universal evaluator)
109
102
  const REQUIRED_AGENTS = [
110
- 'vector-search-expert'
103
+ 'evaluator'
111
104
  ];
112
105
 
113
106
  /**
@@ -211,7 +204,7 @@ async function doctorFullCommand(frameworkRoot) {
211
204
  check('state.json parse', false, false, 'invalid JSON');
212
205
  }
213
206
  } else {
214
- check('state.json', false, true, 'not found (run: morph-spec state init)');
207
+ check('state.json', false, true, 'not found (run: morph-spec init)');
215
208
  }
216
209
 
217
210
  // ── Display ──────────────────────────────────────────────────────────────
@@ -242,8 +235,8 @@ async function doctorFullCommand(frameworkRoot) {
242
235
  }
243
236
 
244
237
  /**
245
- * MCP health check: reads settings.json / settings.local.json and validates
246
- * each configured MCP server's command binary and env var requirements.
238
+ * MCP health check: reads .mcp.json, settings.json, and settings.local.json
239
+ * and validates each configured MCP server's command binary and env var requirements.
247
240
  *
248
241
  * Strategy:
249
242
  * - "ok" : command binary exists (or is a known runtime like npx/node) AND
@@ -258,23 +251,43 @@ async function doctorMcpCommand(targetPath) {
258
251
  logger.header('MCP Server Health Check');
259
252
  logger.blank();
260
253
 
254
+ const allMcpServers = {};
255
+ const sourcesFound = [];
256
+
257
+ // Primary: .mcp.json (Claude Code reads MCPs from here)
258
+ const mcpJsonPath = join(targetPath, '.mcp.json');
259
+ if (await pathExists(mcpJsonPath)) {
260
+ try {
261
+ const mcpJson = JSON.parse(await fs.readFile(mcpJsonPath, 'utf8'));
262
+ const mcps = mcpJson.mcpServers || {};
263
+ const count = Object.keys(mcps).length;
264
+ if (count > 0) {
265
+ Object.assign(allMcpServers, mcps);
266
+ sourcesFound.push(`.mcp.json (${count})`);
267
+ }
268
+ } catch { /* invalid JSON — ignore */ }
269
+ }
270
+
271
+ // Legacy: settings files (for backward compat)
261
272
  const settingsPaths = [
262
273
  join(targetPath, '.claude', 'settings.json'),
263
274
  join(targetPath, '.claude', 'settings.local.json'),
264
275
  ];
265
276
 
266
- const allMcpServers = {};
267
- const sourcesFound = [];
268
-
269
277
  for (const sp of settingsPaths) {
270
278
  if (await pathExists(sp)) {
271
279
  try {
272
280
  const settings = JSON.parse(await fs.readFile(sp, 'utf8'));
273
281
  const mcps = settings.mcpServers || {};
274
- const count = Object.keys(mcps).length;
275
- if (count > 0) {
276
- Object.assign(allMcpServers, mcps);
277
- sourcesFound.push(`${relative(targetPath, sp)} (${count})`);
282
+ let addedCount = 0;
283
+ for (const [name, config] of Object.entries(mcps)) {
284
+ if (!allMcpServers[name]) {
285
+ allMcpServers[name] = config;
286
+ addedCount++;
287
+ }
288
+ }
289
+ if (addedCount > 0) {
290
+ sourcesFound.push(`${relative(targetPath, sp)} (${addedCount})`);
278
291
  }
279
292
  } catch { /* invalid JSON — ignore */ }
280
293
  }
@@ -283,7 +296,7 @@ async function doctorMcpCommand(targetPath) {
283
296
  if (Object.keys(allMcpServers).length === 0) {
284
297
  logger.warn('No MCP servers configured');
285
298
  logger.blank();
286
- logger.dim('Configure MCPs in: .claude/settings.json → mcpServers: { ... }');
299
+ logger.dim('Configure MCPs in: .mcp.json → mcpServers: { ... }');
287
300
  logger.dim('Or use: morph-spec mcp setup');
288
301
  return;
289
302
  }
@@ -564,77 +577,63 @@ export async function doctorCommand(options = {}) {
564
577
  checks.push({ name: 'agents.json count', status: 'ok', msg: `${actualCount} agents` });
565
578
  }
566
579
 
567
- // Check 2: required tier-2 agents present
568
- const requiredTier2 = ['standards-architect', 'dotnet-senior', 'infra-architect'];
569
- const missingTier2 = requiredTier2.filter(id => !agentsData.agents[id]);
570
- if (missingTier2.length > 0) {
580
+ // Check 2: required v5 personas present
581
+ const requiredPersonas = REQUIRED_AGENTS;
582
+ const missingPersonas = requiredPersonas.filter(id => !agentsData.agents[id]);
583
+ if (missingPersonas.length > 0) {
571
584
  checks.push({
572
- name: 'agents.json required agents',
585
+ name: 'agents.json required personas',
573
586
  status: 'error',
574
- msg: `Missing required agents: ${missingTier2.join(', ')}`
587
+ msg: `Missing required personas: ${missingPersonas.join(', ')}`
575
588
  });
576
589
  hasErrors = true;
577
590
  } else {
578
- checks.push({ name: 'agents.json required agents', status: 'ok' });
579
- }
580
-
581
- // Check 3: tier counts sum matches total
582
- const tierCounts = [1, 2, 3, 4].map(t =>
583
- agentEntries.filter(([, v]) => v.tier === t).length
584
- );
585
- const tierSum = tierCounts.reduce((a, b) => a + b, 0);
586
- if (tierSum !== actualCount) {
587
- checks.push({
588
- name: 'agents.json tier counts',
589
- status: 'warn',
590
- msg: `Tier counts sum to ${tierSum} but total is ${actualCount}`
591
- });
592
- hasWarnings = true;
593
- } else {
594
- checks.push({ name: 'agents.json tier counts', status: 'ok' });
591
+ checks.push({ name: 'agents.json required personas', status: 'ok' });
595
592
  }
596
593
 
597
- // Check 4: v4 schema validation
594
+ // Check 3: v5 schema validation (flat personas, no tiers)
598
595
  const version = agentsData.version || 'unknown';
599
- const isV4 = version.startsWith('4.');
600
- const v3Fields = [];
601
- const missingV4Fields = [];
596
+ const isV5 = version.startsWith('5.');
597
+ const v4Fields = [];
598
+ const missingV5Fields = [];
602
599
 
603
600
  for (const [id, data] of agentEntries) {
604
- if (data.role !== undefined) v3Fields.push(`${id}.role`);
605
- if (data.always_active !== undefined) v3Fields.push(`${id}.always_active`);
606
- if (data.relationships !== undefined) v3Fields.push(`${id}.relationships`);
607
- if (!data.group) missingV4Fields.push(`${id}.group`);
608
- if (!Array.isArray(data.active_phases)) missingV4Fields.push(`${id}.active_phases`);
601
+ if (data.tier !== undefined) v4Fields.push(`${id}.tier`);
602
+ if (data.active_phases !== undefined) v4Fields.push(`${id}.active_phases`);
603
+ if (data.reports_to !== undefined) v4Fields.push(`${id}.reports_to`);
604
+ if (data.teammate !== undefined) v4Fields.push(`${id}.teammate`);
605
+ if (!data.title) missingV5Fields.push(`${id}.title`);
606
+ if (!Array.isArray(data.domains)) missingV5Fields.push(`${id}.domains`);
607
+ if (typeof data.persona !== 'string' || !data.persona) missingV5Fields.push(`${id}.persona`);
609
608
  }
610
609
 
611
- if (isV4) {
610
+ if (isV5) {
612
611
  checks.push({ name: `agents.json schema (v${version})`, status: 'ok' });
613
612
  } else {
614
613
  checks.push({
615
614
  name: `agents.json schema (v${version})`,
616
615
  status: 'warn',
617
- msg: 'expected v4.x — run agents migration'
616
+ msg: 'expected v5.x — run agents migration'
618
617
  });
619
618
  hasWarnings = true;
620
619
  }
621
620
 
622
- if (v3Fields.length > 0) {
623
- const sample = v3Fields.slice(0, 3).join(', ');
621
+ if (v4Fields.length > 0) {
622
+ const sample = v4Fields.slice(0, 3).join(', ');
624
623
  checks.push({
625
- name: 'agents.json deprecated fields',
624
+ name: 'agents.json deprecated v4 fields',
626
625
  status: 'warn',
627
- msg: `${v3Fields.length} v3 field(s) found: ${sample}${v3Fields.length > 3 ? '...' : ''}`
626
+ msg: `${v4Fields.length} v4 field(s) found: ${sample}${v4Fields.length > 3 ? '...' : ''}`
628
627
  });
629
628
  hasWarnings = true;
630
629
  }
631
630
 
632
- if (missingV4Fields.length > 0 && isV4) {
633
- const sample = missingV4Fields.slice(0, 3).join(', ');
631
+ if (missingV5Fields.length > 0 && isV5) {
632
+ const sample = missingV5Fields.slice(0, 3).join(', ');
634
633
  checks.push({
635
- name: 'agents.json v4 required fields',
634
+ name: 'agents.json v5 required fields',
636
635
  status: 'warn',
637
- msg: `${missingV4Fields.length} missing: ${sample}${missingV4Fields.length > 3 ? '...' : ''}`
636
+ msg: `${missingV5Fields.length} missing: ${sample}${missingV5Fields.length > 3 ? '...' : ''}`
638
637
  });
639
638
  hasWarnings = true;
640
639
  }
@@ -853,7 +852,7 @@ export async function doctorCommand(options = {}) {
853
852
  hasErrors = true;
854
853
  }
855
854
  } else {
856
- checks.push({ name: 'state.json', status: 'warn', msg: 'not initialized (run: morph-spec state init)' });
855
+ checks.push({ name: 'state.json', status: 'warn', msg: 'not initialized (run: morph-spec init)' });
857
856
  hasWarnings = true;
858
857
  }
859
858
 
@@ -24,7 +24,8 @@ import {
24
24
  installMcpWithCredentials,
25
25
  generateSetupInstructions,
26
26
  formatMcpStatusTable,
27
- isRemoteMcp
27
+ isRemoteMcp,
28
+ setupStitch
28
29
  } from '../../lib/installers/mcp-installer.js';
29
30
  import { setupInfra, installRulesForStack } from '../../scripts/setup-infra.js';
30
31
  import { installSkills } from '../../utils/skills-installer.js';
@@ -209,7 +210,7 @@ export async function initCommand(options) {
209
210
  // Skills
210
211
  await installSkills(targetPath, { projectTags: stackTags });
211
212
 
212
- // Agents (tier 1/2/4 from agents.json + domain agents)
213
+ // Agents (domain personas from agents.json)
213
214
  await installAgents(targetPath, fwSrcDir, { projectTags: stackTags });
214
215
  await installDomainAgents(targetPath, fwSrcDir, { projectTags: stackTags });
215
216
 
@@ -290,6 +291,26 @@ export async function initCommand(options) {
290
291
  }]);
291
292
 
292
293
  if (setupNow) {
294
+ // Stitch — automated setup via setupStitch()
295
+ if (name === 'stitch' && !entry.install.autoInstall) {
296
+ spinner.start('Setting up Stitch MCP...');
297
+ const stitchResult = await setupStitch(targetPath);
298
+ if (stitchResult.success) {
299
+ spinner.succeed('Stitch MCP setup complete');
300
+ manualInstalled[name] = entry;
301
+ } else {
302
+ const failedStep = stitchResult.steps.find(s => !s.success && s.step !== 'enable-api' && s.step !== 'health-check');
303
+ spinner.fail(`Stitch setup failed: ${failedStep?.error || 'unknown'}`);
304
+ }
305
+ if (entry.companionSkills?.installCommand) {
306
+ const skillResults = installCompanionSkills({ stitch: entry });
307
+ for (const r of skillResults) {
308
+ if (r.success) logger.success(` Companion skills installed: ${r.repo}`);
309
+ }
310
+ }
311
+ continue;
312
+ }
313
+
293
314
  // Remote MCPs — launch OAuth via claude mcp add
294
315
  if (isRemoteMcp(entry.install.config)) {
295
316
  const url = entry.install.config.url;
@@ -327,7 +348,7 @@ export async function initCommand(options) {
327
348
  // Show setup instructions
328
349
  const instructions = generateSetupInstructions(name, entry);
329
350
  logger.blank();
330
- logger.dim(' Add to .claude/settings.local.json → mcpServers:');
351
+ logger.dim(' Add to .mcp.json → mcpServers:');
331
352
  logger.dim(' ' + '─'.repeat(55));
332
353
  for (const line of instructions.configSnippet.split('\n')) {
333
354
  logger.dim(` ${line}`);
@@ -434,8 +455,8 @@ export async function initCommand(options) {
434
455
  // Show agent team breakdown from setup-infra result
435
456
  const agents = infraResult?.agents;
436
457
  if (agents) {
437
- const total = agents.tier1 + agents.tier2 + agents.specialists;
438
- logger.dim(` ✓ .claude/agents/ (${total} agents: ${agents.tier1} orchestrators, ${agents.tier2} domain leaders, ${agents.specialists} specialists)`);
458
+ const total = (agents.tier1 || 0) + (agents.tier2 || 0) + (agents.specialists || 0) + (agents.personas || 0);
459
+ logger.dim(` ✓ .claude/agents/ (${total} domain personas installed)`);
439
460
  } else {
440
461
  logger.dim(' ✓ .claude/agents/ (native subagents installed)');
441
462
  }
@@ -32,11 +32,9 @@ const PHASE_SYMBOLS = {
32
32
  const PHASE_ORDER = [
33
33
  { key: 'proposal', name: 'FASE 0: PROPOSAL', order: 0 },
34
34
  { key: 'uiux', name: 'FASE 1: UI/UX', order: 1, optional: true },
35
- { key: 'design', name: 'FASE 2: DESIGN', order: 2 },
36
- { key: 'plan', name: 'FASE 3: PLAN', order: 3 },
37
- { key: 'tasks', name: 'FASE 4: TASKS', order: 4 },
38
- { key: 'implement', name: 'FASE 5: IMPLEMENT', order: 5 },
39
- { key: 'sync', name: 'FASE 6: SYNC', order: 6, optional: true }
35
+ { key: 'plan', name: 'FASE 2: PLAN', order: 2 },
36
+ { key: 'implement', name: 'FASE 3: IMPLEMENT', order: 3 },
37
+ { key: 'review', name: 'FASE 4: REVIEW', order: 4 }
40
38
  ];
41
39
 
42
40
  /**
@@ -65,10 +63,11 @@ function getPhaseStatus(phaseKey, currentPhase, feature) {
65
63
  */
66
64
  function checkPhaseOutputs(phaseKey, feature) {
67
65
  const phaseOutputMap = {
68
- proposal: ['proposal'],
66
+ proposal: ['proposal', 'stackScan', 'migrationPlan'],
69
67
  uiux: ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
70
- design: ['spec', 'contracts', 'schemaAnalysis', 'decisions'],
71
- tasks: ['tasks']
68
+ plan: ['spec', 'mandate', 'tasks', 'decisions'],
69
+ implement: ['recap'],
70
+ review: ['reviewReport']
72
71
  };
73
72
 
74
73
  const outputs = phaseOutputMap[phaseKey] || [];
@@ -102,11 +101,11 @@ function formatPhase(phaseKey, currentPhase, feature, options = {}) {
102
101
  // Add output files if verbose
103
102
  if (options.verbose && status !== 'pending' && status !== 'skipped') {
104
103
  const phaseOutputMap = {
105
- proposal: ['proposal'],
104
+ proposal: ['proposal', 'stackScan', 'migrationPlan'],
106
105
  uiux: ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
107
- design: ['spec', 'contracts', 'schemaAnalysis', 'decisions'],
108
- tasks: ['tasks'],
109
- implement: ['recap']
106
+ plan: ['spec', 'mandate', 'tasks', 'decisions'],
107
+ implement: ['recap'],
108
+ review: ['reviewReport']
110
109
  };
111
110
 
112
111
  const outputs = phaseOutputMap[phaseKey] || [];
@@ -143,9 +142,9 @@ function getNextSteps(feature) {
143
142
  const phaseApprovalMap = {
144
143
  proposal: 'proposal',
145
144
  uiux: 'uiux',
146
- design: 'design',
147
- tasks: 'tasks',
148
- implement: 'tasks'
145
+ plan: 'plan',
146
+ implement: 'plan',
147
+ review: 'review'
149
148
  };
150
149
 
151
150
  const relevantGate = phaseApprovalMap[feature.phase];
@@ -162,9 +161,9 @@ function getNextSteps(feature) {
162
161
  // Check for missing outputs in current phase
163
162
  const phaseOutputMap = {
164
163
  proposal: ['proposal'],
165
- design: ['spec', 'contracts'],
166
- tasks: ['tasks'],
167
- implement: ['recap']
164
+ plan: ['spec', 'mandate', 'tasks'],
165
+ implement: ['recap'],
166
+ review: ['reviewReport']
168
167
  };
169
168
 
170
169
  const requiredOutputs = phaseOutputMap[feature.phase] || [];
@@ -240,7 +239,7 @@ export async function statusCommand(featureName, options = {}) {
240
239
  }
241
240
  if (!feature) {
242
241
  console.error(chalk.red(`✗ Error: Feature '${featureName}' not found`));
243
- console.error(chalk.gray(`Run 'morph-spec state get ${featureName}' to check if feature exists`));
242
+ console.error(chalk.gray(`Run 'morph-spec status' to list known features`));
244
243
  process.exit(1);
245
244
  }
246
245
 
@@ -54,7 +54,7 @@ const program = new Command();
54
54
  /**
55
55
  * Valid approval gate names
56
56
  */
57
- const VALID_GATES = ['proposal', 'uiux', 'design', 'plan', 'tasks'];
57
+ const VALID_GATES = ['proposal', 'uiux', 'plan', 'review'];
58
58
 
59
59
  /**
60
60
  * Approve action function - Mark a gate as approved
@@ -35,13 +35,9 @@ const OUTPUT_SECTIONS = {
35
35
  'Performance', 'Edge Cases', 'Clarifications'
36
36
  ]
37
37
  },
38
- 'contracts.cs': {
39
- required: ['namespace', 'record', 'interface'],
40
- isCode: true
41
- },
42
- 'schema-analysis.md': {
43
- required: ['Tables Analyzed', 'Columns', 'Relationships'],
44
- optional: ['CRITICAL FINDINGS', 'Recommendations', 'Indexes']
38
+ 'mandate.md': {
39
+ required: ['Stack', 'Standards', 'Done'],
40
+ optional: ['Patterns proibidos', 'Riscos']
45
41
  },
46
42
  'decisions.md': {
47
43
  required: ['ADR', 'Status', 'Context', 'Decision'],
@@ -51,29 +47,32 @@ const OUTPUT_SECTIONS = {
51
47
  required: ['T001', 'category', 'dependencies'],
52
48
  optional: ['CHECKPOINT', 'estimatedMinutes']
53
49
  },
50
+ 'review-report.md': {
51
+ required: ['Scores', 'Recommendation'],
52
+ optional: ['Blockers', 'Improvements']
53
+ },
54
54
  };
55
55
 
56
56
  /**
57
- * Phase-to-output mapping
57
+ * Phase-to-output mapping (v5 NLH)
58
58
  */
59
59
  const PHASE_OUTPUTS = {
60
60
  proposal: ['proposal.md'],
61
61
  uiux: ['design-system.md', 'mockups.md', 'components.md', 'flows.md'],
62
- design: ['spec.md', 'contracts.cs', 'schema-analysis.md', 'decisions.md'],
63
- tasks: ['tasks.md'],
64
- implement: ['spec.md', 'contracts.cs', 'tasks.md']
62
+ plan: ['spec.md', 'mandate.md', 'tasks.md'],
63
+ implement: ['recap.md'],
64
+ review: ['review-report.md'],
65
65
  };
66
66
 
67
67
  /**
68
- * Phase-to-folder mapping (filesystem convention)
68
+ * Phase-to-folder mapping (v5 filesystem convention)
69
69
  */
70
70
  const PHASE_FOLDERS = {
71
71
  proposal: '0-proposal',
72
72
  uiux: '1-ui',
73
- design: '2-design',
74
- plan: '3-plan',
75
- tasks: '4-tasks',
76
- implement: '5-implement',
73
+ plan: '2-plan',
74
+ implement: '3-implement',
75
+ review: '4-review',
77
76
  };
78
77
 
79
78
  /**
@@ -105,13 +104,8 @@ function validateOutput(featurePath, outputFile) {
105
104
  return result;
106
105
  }
107
106
 
108
- if (sections.isCode) {
109
- // C# code validation
110
- validateCSharpContent(content, result);
111
- } else {
112
- // Markdown section validation
113
- validateMarkdownSections(content, sections, result);
114
- }
107
+ // v5: only markdown outputs — contracts moved into spec.md
108
+ validateMarkdownSections(content, sections, result);
115
109
 
116
110
  // Size warnings
117
111
  if (result.lineCount < 10) {
@@ -143,94 +137,6 @@ function validateMarkdownSections(content, sections, result) {
143
137
  }
144
138
  }
145
139
 
146
- /**
147
- * Validate C# contracts content
148
- */
149
- function validateCSharpContent(content, result) {
150
- // Check for namespace
151
- if (/namespace\s+\S+/.test(content)) {
152
- result.sections.found.push('namespace');
153
- } else {
154
- result.sections.missing.push('namespace');
155
- result.errors.push('Missing namespace declaration');
156
- }
157
-
158
- // Check for records (DTOs)
159
- const records = content.match(/public\s+record\s+\w+/g) || [];
160
- if (records.length > 0) {
161
- result.sections.found.push(`${records.length} record(s)`);
162
- } else {
163
- result.warnings.push('No record types found — DTOs expected');
164
- }
165
-
166
- // Check for interfaces
167
- const interfaces = content.match(/public\s+interface\s+I\w+/g) || [];
168
- if (interfaces.length > 0) {
169
- result.sections.found.push(`${interfaces.length} interface(s)`);
170
- } else {
171
- result.warnings.push('No interfaces found — service contracts expected');
172
- }
173
-
174
- // Check for CancellationToken in async methods
175
- const asyncMethods = content.match(/Task<.*>\s+\w+\(/g) || [];
176
- const methodsWithCt = content.match(/CancellationToken\s+ct/g) || [];
177
- if (asyncMethods.length > 0 && methodsWithCt.length < asyncMethods.length) {
178
- result.warnings.push(
179
- `${asyncMethods.length - methodsWithCt.length} async method(s) may be missing CancellationToken`
180
- );
181
- }
182
-
183
- // Check for schema-analysis reference
184
- if (content.includes('schema-analysis')) {
185
- result.sections.found.push('schema reference');
186
- } else {
187
- result.warnings.push('No reference to schema-analysis.md — fields may not match database');
188
- }
189
- }
190
-
191
- /**
192
- * Cross-validate contracts against schema-analysis
193
- */
194
- function crossValidateSchema(featurePath) {
195
- const schemaPath = path.join(featurePath, 'schema-analysis.md');
196
- const contractsPath = path.join(featurePath, 'contracts.cs');
197
- const warnings = [];
198
-
199
- if (!fs.existsSync(schemaPath) || !fs.existsSync(contractsPath)) {
200
- return warnings;
201
- }
202
-
203
- const schema = fs.readFileSync(schemaPath, 'utf8');
204
- const contracts = fs.readFileSync(contractsPath, 'utf8');
205
-
206
- // Extract field names from schema (look for column names in tables)
207
- const schemaFields = new Set();
208
- const columnRegex = /\|\s*(\w+)\s*\|/g;
209
- let match;
210
- while ((match = columnRegex.exec(schema)) !== null) {
211
- const field = match[1].toLowerCase();
212
- if (!['column', 'name', 'type', 'nullable', 'default', 'notes', 'table', '---'].includes(field)) {
213
- schemaFields.add(field);
214
- }
215
- }
216
-
217
- // Extract field names from contracts
218
- const contractFields = new Set();
219
- const fieldRegex = /(?:string|int|Guid|DateTime|bool|decimal|JsonObject)\???\s+(\w+)/g;
220
- while ((match = fieldRegex.exec(contracts)) !== null) {
221
- contractFields.add(match[1].toLowerCase());
222
- }
223
-
224
- // Check for contract fields not in schema
225
- for (const field of contractFields) {
226
- if (schemaFields.size > 0 && !schemaFields.has(field) && field !== 'ct') {
227
- warnings.push(`Contract field "${field}" not found in schema-analysis.md — verify correctness`);
228
- }
229
- }
230
-
231
- return warnings;
232
- }
233
-
234
140
  /**
235
141
  * Main validate command
236
142
  */
@@ -282,7 +188,7 @@ export async function validateFeatureCommand(featureName, options = {}) {
282
188
  const results = phase
283
189
  ? outputFiles.map(file => validateOutput(searchPath, file))
284
190
  : outputFiles.map(({ file, dir }) => validateOutput(dir, file));
285
- const schemaWarnings = crossValidateSchema(featurePath);
191
+ const schemaWarnings = []; // v5: cross-validation removed (contracts in spec.md)
286
192
 
287
193
  // Aggregate results
288
194
  const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);