@polymorphism-tech/morph-spec 4.18.0 → 4.20.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 (86) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +11 -0
  3. package/bin/task-manager.js +47 -10
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/agents/architecture/architecture-expert.md +98 -0
  8. package/framework/agents/architecture/morph-spec-architect.md +66 -0
  9. package/framework/agents/architecture/packages-validator.md +89 -0
  10. package/framework/agents/architecture/security-expert.md +79 -0
  11. package/framework/agents/backend/ms-agent-expert.md +1 -1
  12. package/framework/agents/frontend/design-system-validator.md +100 -0
  13. package/framework/agents/frontend/nextjs-component-validator.md +97 -0
  14. package/framework/agents/frontend/{ui-ux-designer.md → ui-designer.md} +31 -0
  15. package/framework/agents.json +1 -1
  16. package/framework/hooks/claude-code/post-tool-use/dispatch.js +56 -0
  17. package/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +78 -44
  18. package/framework/hooks/claude-code/post-tool-use/loop-detect.js +103 -0
  19. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +60 -11
  20. package/framework/hooks/claude-code/session-start/inject-morph-context.js +21 -2
  21. package/framework/hooks/claude-code/stop/validate-completion.js +48 -1
  22. package/framework/hooks/shared/activity-logger.js +56 -1
  23. package/framework/hooks/shared/build-check.js +79 -0
  24. package/framework/hooks/shared/payload-utils.js +39 -0
  25. package/framework/hooks/shared/session-snapshot.js +105 -0
  26. package/framework/phases.json +1 -1
  27. package/framework/rubrics/backend.json +36 -0
  28. package/framework/rubrics/default.json +36 -0
  29. package/framework/rubrics/frontend.json +36 -0
  30. package/framework/skills/level-0-meta/mcp-registry.json +34 -1
  31. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  32. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +1 -1
  33. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +11 -1
  34. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +12 -1
  35. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
  36. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
  37. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +119 -11
  38. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  39. package/framework/standards/ai-agents/production.md +5 -2
  40. package/framework/standards/ai-agents/setup.md +13 -14
  41. package/framework/standards/ai-agents/workflows.md +8 -6
  42. package/framework/standards/backend/database/vector-search-rag.md +1 -1
  43. package/framework/templates/code/dotnet/jobs/agent.cs +0 -1
  44. package/package.json +1 -1
  45. package/src/commands/dashboard/dashboard.js +53 -0
  46. package/src/commands/mcp/mcp-setup.js +21 -0
  47. package/src/commands/project/init.js +11 -0
  48. package/src/dashboard/app/App.jsx +31 -0
  49. package/src/dashboard/app/components/DetailPanel.jsx +11 -0
  50. package/src/dashboard/app/components/FlowGraph.jsx +17 -0
  51. package/src/dashboard/app/components/SearchFilter.jsx +22 -0
  52. package/src/dashboard/app/components/Sidebar.jsx +45 -0
  53. package/src/dashboard/app/hooks/useDetailPanel.js +15 -0
  54. package/src/dashboard/app/main.jsx +13 -0
  55. package/src/dashboard/app/pages/AgentMap.jsx +371 -0
  56. package/src/dashboard/app/pages/HookInspector.jsx +418 -0
  57. package/src/dashboard/app/pages/LiveState.jsx +239 -0
  58. package/src/dashboard/app/pages/PhasePipeline.jsx +410 -0
  59. package/src/dashboard/app/pages/RulesMap.jsx +273 -0
  60. package/src/dashboard/app/pages/SkillsLibrary.jsx +367 -0
  61. package/src/dashboard/app/pages/Standards.jsx +332 -0
  62. package/src/dashboard/app/pages/Workflows.jsx +346 -0
  63. package/src/dashboard/app/styles/index.css +47 -0
  64. package/src/dashboard/index.html +12 -0
  65. package/src/dashboard/package.json +24 -0
  66. package/src/dashboard/scanner/agents-scanner.js +35 -0
  67. package/src/dashboard/scanner/hooks-scanner.js +41 -0
  68. package/src/dashboard/scanner/index.js +21 -0
  69. package/src/dashboard/scanner/phases-scanner.js +15 -0
  70. package/src/dashboard/scanner/rubrics-scanner.js +12 -0
  71. package/src/dashboard/scanner/rules-scanner.js +37 -0
  72. package/src/dashboard/scanner/skills-scanner.js +43 -0
  73. package/src/dashboard/scanner/squads-scanner.js +13 -0
  74. package/src/dashboard/scanner/standards-scanner.js +26 -0
  75. package/src/dashboard/scanner/state-scanner.js +8 -0
  76. package/src/dashboard/scanner/workflows-scanner.js +18 -0
  77. package/src/dashboard/vite-plugin-morph-data.js +17 -0
  78. package/src/dashboard/vite.config.js +24 -0
  79. package/src/lib/checkpoints/checkpoint-hooks.js +2 -1
  80. package/src/lib/contracts/sprint-contract-generator.js +137 -0
  81. package/src/lib/generators/recap-generator.js +15 -0
  82. package/src/lib/installers/mcp-installer.js +25 -0
  83. package/src/lib/validators/score-aggregator.js +244 -0
  84. package/src/lib/validators/validation-runner.js +44 -0
  85. package/src/scripts/setup-infra.js +8 -0
  86. package/src/utils/hooks-installer.js +12 -1
@@ -20,11 +20,13 @@
20
20
 
21
21
  import { readFileSync, writeFileSync, existsSync } from 'fs';
22
22
  import { join } from 'path';
23
+ import { runBuildCheck } from '../../shared/build-check.js';
24
+ import { saveSessionSnapshot } from '../../shared/session-snapshot.js';
23
25
  import {
24
26
  stateExists, getActiveFeature, getMostRecentFeature, getMissingOutputs, derivePhaseForFeature,
25
27
  } from '../../shared/state-reader.js';
26
28
  import { injectContext, pass } from '../../shared/hook-response.js';
27
- import { logHookActivity } from '../../shared/activity-logger.js';
29
+ import { logHookActivity, logEvent } from '../../shared/activity-logger.js';
28
30
 
29
31
  // Phases where compaction is strongly recommended before starting
30
32
  const COMPACT_TRIGGER_PHASES = new Set(['implement']);
@@ -82,6 +84,50 @@ try {
82
84
  );
83
85
  }
84
86
 
87
+ // ── Build/typecheck verification ──────────────────────────────────────────
88
+ // Stack-aware build check — advisory warning if build fails.
89
+ // Success is silent (no output on pass).
90
+ try {
91
+ const configPath = join(cwd, '.morph', 'config', 'config.json');
92
+ if (existsSync(configPath)) {
93
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
94
+ const stack = config?.project?.stack;
95
+ if (stack && currentPhase === 'implement') {
96
+ const buildResult = runBuildCheck(cwd, stack);
97
+ if (buildResult.status === 'fail') {
98
+ warnings.push('⚠ Build/typecheck failed:');
99
+ warnings.push(buildResult.output);
100
+ warnings.push('Fix build errors before ending session.');
101
+ }
102
+ // pass and skip → silent (success is silent)
103
+ }
104
+ }
105
+ } catch {
106
+ // Fail-open — build check must never block Stop
107
+ }
108
+ // ────────────────────────────────────────────────────────────────────────
109
+
110
+ // ── Session snapshot ──────────────────────────────────────────────────────
111
+ // Save session state for next session's "getting up to speed" routine.
112
+ try {
113
+ if (active) {
114
+ const { name, feature } = active;
115
+ const taskList = feature.taskList || [];
116
+ saveSessionSnapshot({
117
+ feature: name,
118
+ phase: currentPhase,
119
+ tasksCompleted: taskList.filter(t => t.status === 'completed').map(t => t.id),
120
+ tasksRemaining: taskList.filter(t => t.status === 'pending').map(t => t.id),
121
+ tasksInProgress: taskList.filter(t => t.status === 'in_progress').map(t => t.id),
122
+ buildStatus: 'skip',
123
+ lastEditedFiles: [],
124
+ }, cwd);
125
+ }
126
+ } catch {
127
+ // Fail-open — snapshot save must never block Stop
128
+ }
129
+ // ────────────────────────────────────────────────────────────────────────
130
+
85
131
  // ── Incomplete work checks ────────────────────────────────────────────────
86
132
 
87
133
  // Incomplete tasks during implement phase
@@ -152,6 +198,7 @@ try {
152
198
  ].join('\n');
153
199
 
154
200
  logHookActivity('validate-completion', 'Stop', `warnings(${warnings.length})`);
201
+ logEvent('session_end', { feature: name, phase: currentPhase, warnings: warnings.length });
155
202
  injectContext(message);
156
203
  } catch {
157
204
  process.exit(0);
@@ -11,7 +11,7 @@
11
11
  * - Windows-safe paths via path.join
12
12
  */
13
13
 
14
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
14
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs';
15
15
  import { join } from 'path';
16
16
 
17
17
  const LOGS_DIR = '.morph/logs';
@@ -103,3 +103,58 @@ export function resetActivity(sessionId, feature, phase, projectPath) {
103
103
  // Fail-silent
104
104
  }
105
105
  }
106
+
107
+ /**
108
+ * Log a structured event to the session activity log.
109
+ *
110
+ * @param {string} type - Event type (e.g., 'task_start', 'loop_detected')
111
+ * @param {Object} data - Event data payload
112
+ * @param {string} [projectPath] - Project root (defaults to cwd)
113
+ */
114
+ export function logEvent(type, data, projectPath) {
115
+ try {
116
+ const activityPath = getActivityPath(projectPath);
117
+ ensureLogsDir(projectPath);
118
+
119
+ const now = new Date();
120
+ const ts = now.toTimeString().slice(0, 8); // HH:MM:SS
121
+
122
+ const activity = readRaw(activityPath) || { sessionId: '', feature: '', phase: '', hooks: [], events: [] };
123
+ activity.events = activity.events || [];
124
+ activity.events.push({ type, data, ts });
125
+
126
+ writeFileSync(activityPath, JSON.stringify(activity, null, 2), 'utf-8');
127
+ } catch {
128
+ // Fail-silent
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Archive current activity.json to sessions/ directory for historical logging.
134
+ * Called at the start of a new session.
135
+ *
136
+ * @param {string} [projectPath] - Project root (defaults to cwd)
137
+ */
138
+ export function archiveSession(projectPath) {
139
+ try {
140
+ const activityPath = getActivityPath(projectPath);
141
+ if (!existsSync(activityPath)) return;
142
+
143
+ const data = readRaw(activityPath);
144
+ if (!data) return;
145
+
146
+ // Only archive if there are meaningful events
147
+ if ((!data.hooks || data.hooks.length === 0) && (!data.events || data.events.length === 0)) return;
148
+
149
+ const sessionsDir = join(projectPath || process.cwd(), LOGS_DIR, 'sessions');
150
+ mkdirSync(sessionsDir, { recursive: true });
151
+
152
+ const sessionId = (data.sessionId || new Date().toISOString()).replace(/[:.]/g, '-');
153
+ const archivePath = join(sessionsDir, `${sessionId}.json`);
154
+ writeFileSync(archivePath, JSON.stringify(data, null, 2), 'utf-8');
155
+
156
+ unlinkSync(activityPath);
157
+ } catch {
158
+ // Fail-silent
159
+ }
160
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Build/Typecheck verification utility.
3
+ *
4
+ * Stack-aware: determines the correct build command based on project stack.
5
+ * Used by the Stop hook to verify code health before session ends.
6
+ *
7
+ * Pure functions — no I/O except the actual build execution.
8
+ */
9
+
10
+ import { execSync } from 'child_process';
11
+ import { existsSync } from 'fs';
12
+ import { join } from 'path';
13
+
14
+ /**
15
+ * Determine the build command for a given stack.
16
+ *
17
+ * @param {string} stack - Project stack (e.g., 'dotnet-nextjs', 'nextjs')
18
+ * @param {boolean} [hasTsConfig] - Whether tsconfig.json exists (for TS projects)
19
+ * @returns {string|null} Build command or null if no check available
20
+ */
21
+ export function getBuildCommand(stack, hasTsConfig = false) {
22
+ if (!stack) return null;
23
+ const s = stack.toLowerCase();
24
+
25
+ if (s.includes('dotnet')) {
26
+ return 'dotnet build --no-restore --nologo -v q 2>&1 | tail -20';
27
+ }
28
+
29
+ if ((s.includes('nextjs') || s.includes('node') || s.includes('react')) && hasTsConfig) {
30
+ return 'npx tsc --noEmit 2>&1 | tail -20';
31
+ }
32
+
33
+ return null;
34
+ }
35
+
36
+ /**
37
+ * Parse build command result into a structured object.
38
+ *
39
+ * @param {number} exitCode - Process exit code (0 = success)
40
+ * @param {string} output - stdout+stderr from build
41
+ * @returns {{ status: 'pass'|'fail', output: string }}
42
+ */
43
+ export function parseBuildResult(exitCode, output) {
44
+ const trimmed = (output || '').trim();
45
+ if (exitCode === 0) {
46
+ return { status: 'pass', output: '' };
47
+ }
48
+ // Truncate to last 20 lines
49
+ const lines = trimmed.split('\n');
50
+ const truncated = lines.slice(-20).join('\n');
51
+ return { status: 'fail', output: truncated };
52
+ }
53
+
54
+ /**
55
+ * Run build check for a project.
56
+ *
57
+ * @param {string} cwd - Project root directory
58
+ * @param {string} stack - Project stack string
59
+ * @param {number} [timeout=30000] - Timeout in ms
60
+ * @returns {{ status: 'pass'|'fail'|'skip', output: string }}
61
+ */
62
+ export function runBuildCheck(cwd, stack, timeout = 30000) {
63
+ const hasTsConfig = existsSync(join(cwd, 'tsconfig.json'));
64
+ const cmd = getBuildCommand(stack, hasTsConfig);
65
+ if (!cmd) return { status: 'skip', output: '' };
66
+
67
+ try {
68
+ const output = execSync(cmd, {
69
+ cwd,
70
+ encoding: 'utf-8',
71
+ timeout,
72
+ stdio: ['pipe', 'pipe', 'pipe']
73
+ });
74
+ return parseBuildResult(0, output);
75
+ } catch (err) {
76
+ const output = (err.stdout || '') + (err.stderr || '');
77
+ return parseBuildResult(err.status || 1, output);
78
+ }
79
+ }
@@ -37,3 +37,42 @@ export function getContentToValidate(payload) {
37
37
  export function isWriteOperation(payload) {
38
38
  return typeof payload?.tool_input?.content === 'string';
39
39
  }
40
+
41
+ /**
42
+ * Get the tool name from a hook payload.
43
+ * @param {Object} payload - Hook payload from stdin
44
+ * @returns {string} Tool name or 'unknown'
45
+ */
46
+ export function getToolName(payload) {
47
+ return payload?.tool_name || 'unknown';
48
+ }
49
+
50
+ /**
51
+ * Build a normalized signature for loop detection.
52
+ * - Edit/Write: "Edit:normalized/file/path"
53
+ * - Bash: "Bash:first two words" (e.g., "Bash:npm test")
54
+ * - Other: just the tool name
55
+ *
56
+ * @param {Object} payload - Hook payload from stdin
57
+ * @returns {string} Signature string
58
+ */
59
+ export function getCommandSignature(payload) {
60
+ const tool = getToolName(payload);
61
+ if (tool === 'unknown') return 'unknown';
62
+
63
+ const input = payload?.tool_input;
64
+ if (!input) return tool;
65
+
66
+ if (tool === 'Edit' || tool === 'Write') {
67
+ const path = (input.file_path || input.path || '').replace(/\\/g, '/');
68
+ return path ? `${tool}:${path}` : tool;
69
+ }
70
+
71
+ if (tool === 'Bash') {
72
+ const cmd = (input.command || '').trim();
73
+ const words = cmd.split(/\s+/).slice(0, 2).join(' ');
74
+ return words ? `Bash:${words}` : 'Bash';
75
+ }
76
+
77
+ return tool;
78
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Session Snapshot — cross-session persistence utility
3
+ *
4
+ * Saves and loads session state for "getting up to speed" on next session.
5
+ * Single file (overwrites) — history preserved via git.
6
+ *
7
+ * Fail-silent: never throws.
8
+ */
9
+
10
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, renameSync, unlinkSync } from 'fs';
11
+ import { join } from 'path';
12
+
13
+ const SNAPSHOT_PATH = '.morph/memory/session-snapshot.json';
14
+
15
+ /**
16
+ * Save session snapshot atomically.
17
+ * @param {Object} data - Snapshot data
18
+ * @param {string} [projectPath] - Project root (defaults to cwd)
19
+ */
20
+ export function saveSessionSnapshot(data, projectPath) {
21
+ try {
22
+ const root = projectPath || process.cwd();
23
+ const dir = join(root, '.morph', 'memory');
24
+ mkdirSync(dir, { recursive: true });
25
+
26
+ const snapshot = { ...data, savedAt: new Date().toISOString() };
27
+ const filePath = join(root, SNAPSHOT_PATH);
28
+ const tmpPath = `${filePath}.tmp.${process.pid}`;
29
+
30
+ writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), 'utf-8');
31
+ try {
32
+ renameSync(tmpPath, filePath);
33
+ } catch {
34
+ writeFileSync(filePath, JSON.stringify(snapshot, null, 2), 'utf-8');
35
+ try { unlinkSync(tmpPath); } catch { /* ignore */ }
36
+ }
37
+ } catch {
38
+ // Fail-silent
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Load session snapshot.
44
+ * @param {string} [projectPath] - Project root (defaults to cwd)
45
+ * @returns {Object|null} Parsed snapshot or null
46
+ */
47
+ export function loadSessionSnapshot(projectPath) {
48
+ try {
49
+ const filePath = join(projectPath || process.cwd(), SNAPSHOT_PATH);
50
+ if (!existsSync(filePath)) return null;
51
+ return JSON.parse(readFileSync(filePath, 'utf-8'));
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Format snapshot as concise context string for SessionStart injection.
59
+ * Budget: max ~150 tokens (~600 chars).
60
+ *
61
+ * @param {Object|null} snapshot
62
+ * @returns {string|null} Formatted context or null
63
+ */
64
+ export function formatPreviousSession(snapshot) {
65
+ if (!snapshot) return null;
66
+
67
+ const lines = ['=== PREVIOUS SESSION ==='];
68
+
69
+ // Header line
70
+ const date = snapshot.savedAt ? new Date(snapshot.savedAt).toISOString().slice(0, 16).replace('T', ' ') : '?';
71
+ const phase = snapshot.phase || '?';
72
+ const build = snapshot.buildStatus || 'unknown';
73
+ lines.push(`Last: ${date} | Phase: ${phase} | Build: ${build}`);
74
+
75
+ // Tasks (truncated)
76
+ const done = snapshot.tasksCompleted || [];
77
+ if (done.length > 0) {
78
+ const shown = done.slice(-5).join(', ');
79
+ const prefix = done.length > 5 ? `...${done.length} total, last: ` : '';
80
+ lines.push(`Done: ${prefix}${shown}`);
81
+ }
82
+
83
+ const wip = snapshot.tasksInProgress || [];
84
+ if (wip.length > 0) {
85
+ lines.push(`WIP: ${wip.join(', ')}`);
86
+ }
87
+
88
+ const remaining = snapshot.tasksRemaining || [];
89
+ if (remaining.length > 0) {
90
+ const shown = remaining.slice(0, 5).join(', ');
91
+ const suffix = remaining.length > 5 ? ` +${remaining.length - 5} more` : '';
92
+ lines.push(`Remaining: ${shown}${suffix}`);
93
+ }
94
+
95
+ // Files (truncated)
96
+ const files = snapshot.lastEditedFiles || [];
97
+ if (files.length > 0) {
98
+ const shown = files.slice(0, 3).join(', ');
99
+ const suffix = files.length > 3 ? ` +${files.length - 3} more` : '';
100
+ lines.push(`Files: ${shown}${suffix}`);
101
+ }
102
+
103
+ lines.push('===');
104
+ return lines.join('\n');
105
+ }
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "requiredOutputs": ["uiDesignSystem"],
37
37
  "optionalOutputs": ["uiMockups", "uiComponents", "uiFlows"],
38
- "recommendedMCPs": ["playwright", "context7"],
38
+ "recommendedMCPs": ["playwright", "context7", "stitch"],
39
39
  "pausePoints": [
40
40
  { "id": "uiux", "label": "Approve UI/UX Design" }
41
41
  ],
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "backend",
3
+ "version": "1.0.0",
4
+ "description": "Backend-focused rubric. Higher weight on architecture, security, and package health.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.30,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.30,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns, dependency direction, and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.05,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance (minimal weight for backend projects)"
20
+ },
21
+ "security": {
22
+ "weight": 0.15,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.20,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health, version compatibility, and deprecated packages"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "default",
3
+ "version": "1.0.0",
4
+ "description": "Default rubric for general-purpose projects. Balanced weights across all categories.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.30,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.25,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.15,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance, CSS quality, and UI correctness"
20
+ },
21
+ "security": {
22
+ "weight": 0.15,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.15,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health and compatibility"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "frontend",
3
+ "version": "1.0.0",
4
+ "description": "Frontend-focused rubric. Higher weight on design system compliance and UI quality.",
5
+ "categories": {
6
+ "functionality": {
7
+ "weight": 0.25,
8
+ "validators": ["contract-compliance"],
9
+ "description": "Core feature correctness and contract compliance"
10
+ },
11
+ "code_quality": {
12
+ "weight": 0.15,
13
+ "validators": ["architecture"],
14
+ "description": "Architecture patterns and code structure"
15
+ },
16
+ "design_ui": {
17
+ "weight": 0.35,
18
+ "validators": ["design-system", "css", "contrast", "nextjs-component"],
19
+ "description": "Design system compliance, CSS quality, contrast ratios, and component correctness"
20
+ },
21
+ "security": {
22
+ "weight": 0.10,
23
+ "validators": [],
24
+ "description": "Security posture (agent-evaluated, no automated validator)"
25
+ },
26
+ "packages": {
27
+ "weight": 0.15,
28
+ "validators": ["packages"],
29
+ "description": "Dependency health and compatibility"
30
+ }
31
+ },
32
+ "thresholds": {
33
+ "approve": 8.0,
34
+ "retry": 6.0
35
+ }
36
+ }
@@ -152,11 +152,44 @@
152
152
  "warnings": ["API call execution requires your Asaas access_token. Doc search works without authentication."],
153
153
  "setupGuide": "Run: claude mcp add --transport http asaas https://docs.asaas.com/mcp"
154
154
  }
155
+ },
156
+ "stitch": {
157
+ "phases": ["uiux"],
158
+ "tools": ["create_project", "list_projects", "get_project", "list_screens", "get_screen", "generate_screen_from_text", "fetch_screen_code", "fetch_screen_image"],
159
+ "detection": "mcpServers includes stitch",
160
+ "fallback": "HTML mockup + Playwright screenshots (Step 3.5 workflow)",
161
+ "usage": "AI-generated screen designs, design.md export, visual design exploration",
162
+ "healthCheck": {
163
+ "toolPattern": "stitch",
164
+ "testCall": "Call list_projects to verify connectivity",
165
+ "testParams": {},
166
+ "successIndicator": "Returns a list of projects (possibly empty) without auth errors",
167
+ "failureHint": "Stitch MCP not responding. Ensure @_davideast/stitch-mcp is installed or configure official MCP: claude mcp add stitch --transport http https://stitch.googleapis.com/mcp"
168
+ },
169
+ "install": {
170
+ "autoInstall": true,
171
+ "transport": "stdio",
172
+ "config": {
173
+ "command": "cmd",
174
+ "args": ["/c", "npx", "-y", "@_davideast/stitch-mcp@latest", "proxy"]
175
+ },
176
+ "credentials": [],
177
+ "prerequisites": [],
178
+ "stackRelevance": ["nextjs", "nextjs-neon", "vite"],
179
+ "warnings": ["Community MCP tool. Official alternative: claude mcp add stitch --transport http https://stitch.googleapis.com/mcp (requires gcloud auth)"],
180
+ "setupGuide": "Auto-installed via npx. For official Google MCP: claude mcp add stitch --transport http https://stitch.googleapis.com/mcp"
181
+ },
182
+ "companionSkills": {
183
+ "repo": "google-labs-code/stitch-skills",
184
+ "installCommand": "npx skills add google-labs-code/stitch-skills",
185
+ "skills": ["stitch-design", "stitch-loop", "design-md", "prompt-enhance", "react-components", "shadcn-ui"],
186
+ "description": "Official Stitch agent skills for Claude Code — design generation, multi-page loops, design.md export"
187
+ }
155
188
  }
156
189
  },
157
190
  "phaseMatrix": {
158
191
  "proposal": ["context7"],
159
- "uiux": ["playwright", "context7"],
192
+ "uiux": ["playwright", "context7", "stitch"],
160
193
  "design": ["context7", "github"],
161
194
  "tasks": ["context7", "github"],
162
195
  "implement": ["context7", "playwright", "github", "vercel"]
@@ -10,7 +10,7 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion,
10
10
  mcp__playwright__browser_navigate, mcp__playwright__browser_resize,
11
11
  mcp__playwright__browser_take_screenshot, mcp__playwright__browser_snapshot,
12
12
  mcp__playwright__browser_evaluate, mcp__playwright__browser_console_messages
13
- cliVersion: "4.18.0"
13
+ cliVersion: "4.20.0"
14
14
  stacks:
15
15
  - nextjs
16
16
  ---
@@ -3,7 +3,7 @@ name: morph-phase-codebase-analysis
3
3
  description: MORPH-SPEC Design sub-phase that analyzes existing codebase and database schema, producing schema-analysis.md with real column names, types, relationships, and field mismatches. Use at the start of Design phase before generating contracts.cs to prevent incorrect field names or types.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
6
- cliVersion: "4.18.0"
6
+ cliVersion: "4.20.0"
7
7
  ---
8
8
 
9
9
  # MORPH Codebase Analysis - Design Sub-phase
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 2 (Design). Schema-first interactive design: reads
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Agent
7
- cliVersion: "4.18.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Design — Phase 2
@@ -440,4 +440,14 @@ morph-spec state set $ARGUMENTS costs.estimated {X.XX}
440
440
  | `decisions` | `.morph/features/{feature}/2-design/decisions.md` |
441
441
  <!-- /morph-outputs -->
442
442
 
443
+ ## Relevant Standards
444
+
445
+ Before starting the design phase, proactively read standards relevant to the project's stack:
446
+ - Architecture standards: `.morph/framework/standards/architecture/` — especially vertical-slice patterns
447
+ - Backend standards: `.morph/framework/standards/backend/` — for API contracts and patterns
448
+ - Data standards: `.morph/framework/standards/data/` — for database schema and access patterns
449
+ - These standards are also available as rules that auto-load when editing matching file types.
450
+
451
+ ---
452
+
443
453
  Continue automatically to Plan phase after approval.
@@ -5,7 +5,7 @@ argument-hint: "[feature-name]"
5
5
  context: fork
6
6
  agent: general-purpose
7
7
  user-invocable: false
8
- cliVersion: "4.18.0"
8
+ cliVersion: "4.20.0"
9
9
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Agent
10
10
  ---
11
11
 
@@ -479,4 +479,15 @@ Agent(subagent_type=morph-standards-architect, prompt=<filled prompts/code-quali
479
479
 
480
480
  ---
481
481
 
482
+ ## Relevant Standards
483
+
484
+ During implementation, standards auto-load via rules when editing relevant file types.
485
+ For proactive reference:
486
+ - Architecture: `.morph/framework/standards/architecture/` — structural compliance
487
+ - Backend/Frontend: `.morph/framework/standards/backend/` or `.morph/framework/standards/frontend/`
488
+ - Security: `.morph/framework/standards/security/` — authentication, authorization patterns
489
+ - Testing: follow the project's existing test patterns (check `test/` or `tests/` directory)
490
+
491
+ ---
492
+
482
493
  Feature complete! Consider creating a PR and running `morph-spec generate recap $ARGUMENTS`.
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 3 (Plan). Generates a detailed implementation plan
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.18.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Plan — Phase 3
@@ -4,7 +4,7 @@ description: MORPH-SPEC Phase 4 (Tasks). Breaks approved spec into bottom-up ord
4
4
  argument-hint: "[feature-name]"
5
5
  user-invocable: false
6
6
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
- cliVersion: "4.18.0"
7
+ cliVersion: "4.20.0"
8
8
  ---
9
9
 
10
10
  # MORPH Tasks — Phase 4