@polymorphism-tech/morph-spec 4.3.6 → 4.5.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 (375) hide show
  1. package/.morph/.morphversion +3 -3
  2. package/.morph/analytics/threads-log.jsonl +44 -9
  3. package/.morph/config/config.json +2 -3
  4. package/.morph/framework/standards/STANDARDS.json +812 -0
  5. package/.morph/{standards → framework/standards}/ai-agents/team-orchestration.md +3 -3
  6. package/.morph/framework/standards/integration/mcp/mcp-tools.md +384 -0
  7. package/.morph/{templates → framework/templates}/README.md +17 -17
  8. package/.morph/{templates → framework/templates}/REGISTRY.json +48 -233
  9. package/.morph/framework/templates/code/dotnet/contracts/contracts.cs.hbs +172 -0
  10. package/.morph/{templates → framework/templates}/context/CONTEXT-FEATURE.md +1 -1
  11. package/.morph/{templates → framework/templates}/context/CONTEXT.md +3 -3
  12. package/.morph/framework/templates/docs/clarifications.md +253 -0
  13. package/.morph/framework/templates/docs/onboarding.md +123 -0
  14. package/.morph/framework/templates/docs/schema-analysis.md +119 -0
  15. package/.morph/{templates → framework/templates}/docs/spec.md +149 -149
  16. package/.morph/framework/templates/docs/ui-components.md +124 -0
  17. package/.morph/framework/templates/docs/ui-design-system.md +76 -0
  18. package/.morph/framework/templates/docs/ui-flows.md +167 -0
  19. package/.morph/framework/templates/docs/ui-mockups.md +98 -0
  20. package/.morph/{templates → framework/templates}/examples/spec-examples.md +1 -1
  21. package/.morph/{templates → framework/templates}/infrastructure/github/README.md +11 -11
  22. package/.morph/{templates → framework/templates}/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +2 -2
  23. package/.morph/{templates → framework/templates}/meta-prompts/parallel-workers/parallel-worker.md +2 -2
  24. package/.morph/{templates → framework/templates}/meta-prompts/validators/pre-commit-validator.md +1 -1
  25. package/.morph/logs/tool-failures.log +51 -0
  26. package/.morph/memory/pre-compact-2026-02-22T17-01-01-658Z.json +16 -0
  27. package/.morph/state.json +1 -1
  28. package/CLAUDE.md +20 -119
  29. package/README.md +20 -18
  30. package/bin/detect-agents.js +1 -1
  31. package/bin/morph-spec.js +116 -266
  32. package/bin/task-manager.cjs +2 -2
  33. package/bin/validate.js +1 -1
  34. package/claude-plugin.json +14 -0
  35. package/docs/claude-alignment-report.md +137 -0
  36. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +512 -0
  37. package/docs/plans/2026-02-22-claude-settings.md +515 -0
  38. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +728 -0
  39. package/docs/plans/2026-02-22-morph-spec-next.md +478 -0
  40. package/docs/plans/2026-02-22-native-alignment-design.md +199 -0
  41. package/docs/plans/2026-02-22-native-alignment-impl.md +925 -0
  42. package/docs/plans/2026-02-22-native-enrichment-design.md +244 -0
  43. package/docs/plans/2026-02-22-native-enrichment.md +735 -0
  44. package/framework/CLAUDE.md +77 -0
  45. package/framework/commands/morph-apply.md +9 -9
  46. package/framework/commands/morph-archive.md +8 -8
  47. package/framework/commands/morph-infra.md +1 -1
  48. package/framework/commands/morph-proposal.md +9 -9
  49. package/framework/commands/morph-status.md +3 -3
  50. package/framework/commands/morph-troubleshoot.md +1 -1
  51. package/framework/hooks/README.md +201 -282
  52. package/framework/hooks/claude-code/notification/approval-reminder.js +52 -0
  53. package/framework/hooks/claude-code/post-tool-use/dispatch.js +83 -0
  54. package/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +42 -0
  55. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +61 -0
  56. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +71 -0
  57. package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +58 -0
  58. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +64 -0
  59. package/framework/hooks/claude-code/session-start/inject-morph-context.js +94 -0
  60. package/framework/hooks/claude-code/statusline.py +239 -0
  61. package/framework/hooks/claude-code/statusline.sh +7 -0
  62. package/framework/hooks/claude-code/stop/validate-completion.js +88 -0
  63. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +91 -0
  64. package/framework/hooks/shared/hook-response.js +45 -0
  65. package/framework/hooks/shared/phase-utils.js +129 -0
  66. package/framework/hooks/shared/state-reader.js +138 -0
  67. package/framework/hooks/shared/stdin-reader.js +26 -0
  68. package/framework/phases.json +145 -0
  69. package/framework/rules/csharp-standards.md +10 -0
  70. package/framework/rules/frontend-standards.md +14 -0
  71. package/framework/rules/infrastructure-standards.md +13 -0
  72. package/framework/rules/morph-workflow.md +86 -0
  73. package/framework/rules/testing-standards.md +11 -0
  74. package/framework/skills/level-0-meta/brainstorming.md +133 -0
  75. package/framework/skills/level-0-meta/code-review.md +12 -4
  76. package/framework/skills/level-0-meta/mcp-registry.json +207 -0
  77. package/framework/skills/level-0-meta/morph-checklist.md +9 -1
  78. package/framework/skills/level-0-meta/simulation-checklist.md +9 -1
  79. package/framework/skills/level-0-meta/tool-usage-guide.md +335 -0
  80. package/framework/skills/level-0-meta/verification-before-completion.md +145 -0
  81. package/framework/skills/level-1-workflows/morph-replicate.md +9 -1
  82. package/framework/skills/level-1-workflows/phase-clarify.md +65 -4
  83. package/framework/skills/level-1-workflows/phase-codebase-analysis.md +182 -0
  84. package/framework/skills/level-1-workflows/phase-design.md +342 -80
  85. package/framework/skills/level-1-workflows/phase-implement.md +254 -0
  86. package/framework/skills/level-1-workflows/phase-setup.md +76 -10
  87. package/framework/skills/level-1-workflows/phase-tasks.md +88 -7
  88. package/framework/skills/level-1-workflows/phase-uiux.md +95 -17
  89. package/framework/skills/level-2-domains/ai-agents/ai-system-architect.md +8 -1
  90. package/framework/skills/level-2-domains/architecture/po-pm-advisor.md +8 -1
  91. package/framework/skills/level-2-domains/architecture/prompt-engineer.md +8 -1
  92. package/framework/skills/level-2-domains/architecture/seo-growth-hacker.md +8 -1
  93. package/framework/skills/level-2-domains/architecture/standards-architect.md +11 -4
  94. package/framework/skills/level-2-domains/backend/api-designer.md +8 -1
  95. package/framework/skills/level-2-domains/backend/dotnet-senior.md +8 -1
  96. package/framework/skills/level-2-domains/backend/ef-modeler.md +8 -1
  97. package/framework/skills/level-2-domains/backend/hangfire-orchestrator.md +9 -2
  98. package/framework/skills/level-2-domains/backend/ms-agent-expert.md +8 -1
  99. package/framework/skills/level-2-domains/frontend/blazor-builder.md +8 -1
  100. package/framework/skills/level-2-domains/frontend/nextjs-expert.md +8 -1
  101. package/framework/skills/level-2-domains/frontend/ui-ux-designer.md +9 -2
  102. package/framework/skills/level-2-domains/infrastructure/azure-architect.md +8 -1
  103. package/framework/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +8 -1
  104. package/framework/skills/level-2-domains/infrastructure/bicep-architect.md +8 -1
  105. package/framework/skills/level-2-domains/infrastructure/container-specialist.md +8 -1
  106. package/framework/skills/level-2-domains/infrastructure/devops-engineer.md +8 -1
  107. package/framework/skills/level-2-domains/integrations/asaas-financial.md +8 -1
  108. package/framework/skills/level-2-domains/integrations/azure-identity.md +8 -1
  109. package/framework/skills/level-2-domains/integrations/clerk-auth.md +8 -1
  110. package/framework/skills/level-2-domains/integrations/{hangfire-orchestrator.md → hangfire-integration.md} +8 -1
  111. package/framework/skills/level-2-domains/integrations/resend-email.md +8 -1
  112. package/framework/skills/level-2-domains/quality/code-analyzer.md +10 -3
  113. package/framework/skills/level-2-domains/quality/testing-specialist.md +8 -1
  114. package/framework/standards/STANDARDS.json +812 -0
  115. package/framework/standards/ai-agents/team-orchestration.md +3 -3
  116. package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -0
  117. package/framework/standards/integration/mcp/mcp-tools.md +384 -0
  118. package/framework/templates/README.md +17 -17
  119. package/framework/templates/REGISTRY.json +48 -233
  120. package/framework/templates/code/dotnet/contracts/contracts.cs.hbs +172 -0
  121. package/framework/templates/context/CONTEXT-FEATURE.md +1 -1
  122. package/framework/templates/context/CONTEXT.md +3 -3
  123. package/framework/templates/docs/clarifications.md +253 -0
  124. package/framework/templates/docs/onboarding.md +123 -0
  125. package/framework/templates/docs/schema-analysis.md +119 -0
  126. package/framework/templates/docs/spec.md +149 -149
  127. package/framework/templates/docs/ui-components.md +124 -0
  128. package/framework/templates/docs/ui-design-system.md +76 -0
  129. package/framework/templates/docs/ui-flows.md +167 -0
  130. package/framework/templates/docs/ui-mockups.md +98 -0
  131. package/framework/templates/docs/user-stories.md +34 -0
  132. package/framework/templates/examples/spec-examples.md +1 -1
  133. package/framework/templates/infrastructure/github/README.md +11 -11
  134. package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +2 -2
  135. package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +2 -2
  136. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +1 -1
  137. package/framework/workflows/configs/express.json +45 -0
  138. package/framework/workflows/configs/spec-only.json +43 -0
  139. package/framework/workflows/docs/enforcement-pipeline.md +8 -8
  140. package/framework/workflows/docs/full-morph.md +3 -3
  141. package/package.json +3 -2
  142. package/scripts/generate-refs.js +336 -0
  143. package/scripts/generate-standards-registry.js +44 -0
  144. package/scripts/validate-real.mjs +255 -0
  145. package/src/commands/feature/create-story.js +362 -361
  146. package/src/commands/feature/shard-spec.js +225 -224
  147. package/src/commands/feature/sprint-status.js +1 -1
  148. package/src/commands/generation/generate-onboarding.js +169 -0
  149. package/src/commands/generation/generate.js +2 -2
  150. package/src/commands/mcp/mcp-setup.js +315 -0
  151. package/src/commands/project/changes.js +66 -0
  152. package/src/commands/project/checkpoint.js +209 -0
  153. package/src/commands/project/cost.js +179 -0
  154. package/src/commands/project/diff.js +278 -0
  155. package/src/commands/project/doctor.js +55 -7
  156. package/src/commands/project/init.js +318 -76
  157. package/src/commands/project/revert.js +173 -0
  158. package/src/commands/project/standards.js +80 -0
  159. package/src/commands/project/status.js +376 -0
  160. package/src/commands/project/update-agents.js +23 -0
  161. package/src/commands/project/update.js +63 -30
  162. package/src/commands/state/advance-phase.js +4 -3
  163. package/src/commands/state/state.js +10 -3
  164. package/src/commands/state/validate-phase.js +19 -2
  165. package/src/commands/templates/template-customize.js +4 -4
  166. package/src/commands/templates/template-render.js +1 -1
  167. package/src/commands/templates/template-show.js +1 -1
  168. package/src/commands/validation/validate-feature.js +359 -0
  169. package/src/core/orchestrator.js +3 -38
  170. package/src/core/paths/output-schema.js +135 -0
  171. package/src/core/state/state-manager.js +831 -592
  172. package/src/core/templates/template-registry.js +2 -2
  173. package/src/core/workflows/workflow-detector.js +17 -1
  174. package/src/lib/agents/micro-agent-factory.js +1 -1
  175. package/src/lib/context/context-bundler.js +2 -1
  176. package/src/lib/detectors/claude-config-detector.js +392 -0
  177. package/src/lib/detectors/conversation-analyzer.js +4 -4
  178. package/src/lib/detectors/design-system-detector.js +6 -5
  179. package/src/lib/detectors/standards-generator.js +2 -2
  180. package/src/lib/generators/context-generator.js +539 -538
  181. package/src/lib/generators/recap-generator.js +1 -1
  182. package/src/lib/generators/settings-generator.js +210 -0
  183. package/src/lib/hooks/hook-executor.js +1 -1
  184. package/src/lib/installers/mcp-installer.js +299 -0
  185. package/src/lib/learning/learning-system.js +3 -3
  186. package/src/lib/orchestration/team-orchestrator.js +1 -1
  187. package/src/lib/standards/standards-context-injector.js +7 -7
  188. package/src/lib/threads/thread-coordinator.js +1 -1
  189. package/src/lib/troubleshooting/troubleshoot-grep.js +1 -1
  190. package/src/lib/validators/contracts/contract-compliance-validator.js +274 -273
  191. package/src/lib/validators/design-system/design-system-validator.js +1 -1
  192. package/src/lib/validators/spec-validator.js +258 -258
  193. package/src/lib/validators/validation-runner.js +270 -269
  194. package/src/utils/agents-installer.js +206 -0
  195. package/src/utils/claude-settings-manager.js +258 -0
  196. package/src/utils/file-copier.js +1 -1
  197. package/src/utils/hooks-installer.js +354 -28
  198. package/src/utils/skills-installer.js +74 -0
  199. package/.morph/project/context/detection-log.md +0 -16
  200. package/.morph/project/standards/inferred.md +0 -59
  201. package/framework/hooks/agent-stop/validate-and-continue.js +0 -96
  202. package/framework/hooks/agent-stop/validate-checkpoints.js +0 -101
  203. package/framework/hooks/agent-stop/validate-tests.js +0 -109
  204. package/framework/hooks/agent-teams/dispatch.js +0 -67
  205. package/framework/hooks/agent-teams/phase-advanced.js +0 -80
  206. package/framework/hooks/agent-teams/task-completed.js +0 -76
  207. package/framework/hooks/agent-teams/teammate-idle.js +0 -70
  208. package/src/commands/agents/agents-fuse.js +0 -97
  209. package/src/commands/agents/micro-agent.js +0 -112
  210. package/src/commands/agents/spawn-team.js +0 -237
  211. package/src/commands/agents/squad-template.js +0 -146
  212. package/src/commands/analytics/analytics.js +0 -176
  213. package/src/commands/context/context-prime.js +0 -63
  214. package/src/commands/context/core-four.js +0 -54
  215. package/src/commands/generation/generate-context.js +0 -40
  216. package/src/commands/project/detect-agents.js +0 -207
  217. package/src/commands/project/detect-workflow.js +0 -174
  218. package/src/commands/threads/thread-template.js +0 -103
  219. package/src/commands/threads/threads.js +0 -261
  220. package/src/commands/utils/session-summary.js +0 -291
  221. package/src/llm/analyzer.js +0 -215
  222. package/src/llm/few-shot-examples.js +0 -216
  223. package/src/llm/project-config-schema.json +0 -188
  224. package/src/llm/prompt-builder.js +0 -96
  225. /package/.morph/{project/context → context}/README.md +0 -0
  226. /package/.morph/{config → framework}/agents.json +0 -0
  227. /package/.morph/{standards → framework/standards}/ai-agents/blazor-ui.md +0 -0
  228. /package/.morph/{standards → framework/standards}/ai-agents/production.md +0 -0
  229. /package/.morph/{standards → framework/standards}/ai-agents/setup.md +0 -0
  230. /package/.morph/{standards → framework/standards}/ai-agents/workflows.md +0 -0
  231. /package/.morph/{standards → framework/standards}/architecture/ddd/aggregates.md +0 -0
  232. /package/.morph/{standards → framework/standards}/architecture/ddd/entities.md +0 -0
  233. /package/.morph/{standards → framework/standards}/architecture/ddd/value-objects.md +0 -0
  234. /package/.morph/{standards → framework/standards}/backend/api/minimal-api.md +0 -0
  235. /package/.morph/{standards → framework/standards}/backend/api/rest.md +0 -0
  236. /package/.morph/{standards → framework/standards}/backend/api/validation.md +0 -0
  237. /package/.morph/{standards → framework/standards}/backend/authentication/passkeys.md +0 -0
  238. /package/.morph/{standards → framework/standards}/backend/database/ef-core.md +0 -0
  239. /package/.morph/{standards → framework/standards}/backend/database/migrations.md +0 -0
  240. /package/.morph/{standards → framework/standards}/backend/database/postgresql/database.md +0 -0
  241. /package/.morph/{standards → framework/standards}/backend/database/repository-patterns.md +0 -0
  242. /package/.morph/{standards → framework/standards}/backend/database/vector-search-rag.md +0 -0
  243. /package/.morph/{standards → framework/standards}/backend/dotnet/async.md +0 -0
  244. /package/.morph/{standards → framework/standards}/backend/dotnet/core.md +0 -0
  245. /package/.morph/{standards → framework/standards}/backend/dotnet/di.md +0 -0
  246. /package/.morph/{standards → framework/standards}/backend/dotnet/program-cs-checklist.md +0 -0
  247. /package/.morph/{standards → framework/standards}/backend/integrations/asaas/asaas-api.md +0 -0
  248. /package/.morph/{standards → framework/standards}/backend/integrations/clerk/clerk-auth.md +0 -0
  249. /package/.morph/{standards → framework/standards}/backend/integrations/hangfire/hangfire-jobs.md +0 -0
  250. /package/.morph/{standards → framework/standards}/backend/integrations/resend/resend-email.md +0 -0
  251. /package/.morph/{standards → framework/standards}/context/analytics.md +0 -0
  252. /package/.morph/{standards → framework/standards}/context/bundles.md +0 -0
  253. /package/.morph/{standards → framework/standards}/context/priming.md +0 -0
  254. /package/.morph/{standards → framework/standards}/core/architecture.md +0 -0
  255. /package/.morph/{standards → framework/standards}/core/coding.md +0 -0
  256. /package/.morph/{standards → framework/standards}/core/git-branching-strategy.md +0 -0
  257. /package/.morph/{standards → framework/standards}/core/git.md +0 -0
  258. /package/.morph/{standards → framework/standards}/core/testing.md +0 -0
  259. /package/.morph/{standards → framework/standards}/data/nosql/blob-storage.md +0 -0
  260. /package/.morph/{standards → framework/standards}/data/nosql/cache/redis.md +0 -0
  261. /package/.morph/{standards → framework/standards}/data/nosql/cosmos-db.md +0 -0
  262. /package/.morph/{standards → framework/standards}/data/vector-search/azure-ai-search.md +0 -0
  263. /package/.morph/{standards → framework/standards}/data/vector-search/rag-chunking.md +0 -0
  264. /package/.morph/{standards → framework/standards}/frontend/blazor/design-checklist.md +0 -0
  265. /package/.morph/{standards → framework/standards}/frontend/blazor/fluent-ui-setup.md +0 -0
  266. /package/.morph/{standards → framework/standards}/frontend/blazor/fluent-ui.md +0 -0
  267. /package/.morph/{standards → framework/standards}/frontend/blazor/html-conversion.md +0 -0
  268. /package/.morph/{standards → framework/standards}/frontend/blazor/lifecycle.md +0 -0
  269. /package/.morph/{standards → framework/standards}/frontend/blazor/pitfalls.md +0 -0
  270. /package/.morph/{standards → framework/standards}/frontend/blazor/state.md +0 -0
  271. /package/.morph/{standards → framework/standards}/frontend/design-system/animations.md +0 -0
  272. /package/.morph/{standards → framework/standards}/frontend/design-system/naming.md +0 -0
  273. /package/.morph/{standards → framework/standards}/frontend/nextjs/nextjs-patterns.md +0 -0
  274. /package/.morph/{standards → framework/standards}/infrastructure/azure/azure.md +0 -0
  275. /package/.morph/{standards → framework/standards}/infrastructure/azure/bicep/bicep-patterns.md +0 -0
  276. /package/.morph/{standards → framework/standards}/infrastructure/azure/devops/azure-devops-setup.md +0 -0
  277. /package/.morph/{standards → framework/standards}/infrastructure/azure/devops/local-development.md +0 -0
  278. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/functions.md +0 -0
  279. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/service-bus.md +0 -0
  280. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/storage.md +0 -0
  281. /package/.morph/{standards → framework/standards}/infrastructure/docker/easypanel-deploy.md +0 -0
  282. /package/.morph/{standards → framework/standards}/infrastructure/supabase/mcp-setup.md +0 -0
  283. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-auth.md +0 -0
  284. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-pgvector.md +0 -0
  285. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-rls.md +0 -0
  286. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-storage.md +0 -0
  287. /package/.morph/{standards → framework/standards}/integration/api/graphql.md +0 -0
  288. /package/.morph/{standards → framework/standards}/integration/api/grpc.md +0 -0
  289. /package/.morph/{standards → framework/standards}/integration/api/rest-design.md +0 -0
  290. /package/.morph/{standards → framework/standards}/integration/event-driven/cqrs.md +0 -0
  291. /package/.morph/{standards → framework/standards}/integration/event-driven/event-sourcing.md +0 -0
  292. /package/.morph/{standards → framework/standards}/integration/event-driven/service-bus.md +0 -0
  293. /package/.morph/{standards → framework/standards}/observability/logging.md +0 -0
  294. /package/.morph/{standards → framework/standards}/observability/metrics.md +0 -0
  295. /package/.morph/{standards → framework/standards}/observability/monitoring.md +0 -0
  296. /package/.morph/{standards → framework/standards}/observability/tracing.md +0 -0
  297. /package/.morph/{standards → framework/standards}/workflows/parallel-execution.md +0 -0
  298. /package/.morph/{standards → framework/standards}/workflows/thread-management.md +0 -0
  299. /package/.morph/{templates → framework/templates}/.idea/morph-templates.xml +0 -0
  300. /package/.morph/{templates → framework/templates}/.vscode/morph-templates.code-snippets +0 -0
  301. /package/.morph/{templates → framework/templates}/IDE-SNIPPETS.md +0 -0
  302. /package/.morph/{templates → framework/templates}/code/dotnet/backend/repository.cs +0 -0
  303. /package/.morph/{templates → framework/templates}/code/dotnet/backend/service.cs +0 -0
  304. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Commands.cs +0 -0
  305. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Entities.cs +0 -0
  306. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Queries.cs +0 -0
  307. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/README.md +0 -0
  308. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/api-contracts.cs +0 -0
  309. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/contracts.cs +0 -0
  310. /package/.morph/{templates → framework/templates}/code/dotnet/database/migration.cs +0 -0
  311. /package/.morph/{templates → framework/templates}/code/dotnet/frontend/component.razor +0 -0
  312. /package/.morph/{templates → framework/templates}/code/dotnet/jobs/agent.cs +0 -0
  313. /package/.morph/{templates → framework/templates}/code/dotnet/jobs/job.cs +0 -0
  314. /package/.morph/{templates → framework/templates}/code/dotnet/test.cs +0 -0
  315. /package/.morph/{templates → framework/templates}/code/sql/rls-policy.sql +0 -0
  316. /package/.morph/{templates → framework/templates}/code/sql/supabase-migration.sql +0 -0
  317. /package/.morph/{templates → framework/templates}/code/sql/supabase-migration.template.sql +0 -0
  318. /package/.morph/{templates → framework/templates}/code/typescript/contracts.ts +0 -0
  319. /package/.morph/{templates → framework/templates}/docs/proposal.md +0 -0
  320. /package/.morph/{templates → framework/templates}/examples/design-system-examples.md +0 -0
  321. /package/.morph/{templates → framework/templates}/feature/decisions.md +0 -0
  322. /package/.morph/{templates → framework/templates}/feature/recap.md +0 -0
  323. /package/.morph/{templates → framework/templates}/feature/tasks.md +0 -0
  324. /package/.morph/{templates → framework/templates}/infrastructure/azure/Dockerfile.example +0 -0
  325. /package/.morph/{templates → framework/templates}/infrastructure/azure/README.md +0 -0
  326. /package/.morph/{templates → framework/templates}/infrastructure/azure/app-insights.bicep +0 -0
  327. /package/.morph/{templates → framework/templates}/infrastructure/azure/app-service.bicep +0 -0
  328. /package/.morph/{templates → framework/templates}/infrastructure/azure/container-app-env.bicep +0 -0
  329. /package/.morph/{templates → framework/templates}/infrastructure/azure/container-app.bicep +0 -0
  330. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy-checklist.md +0 -0
  331. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy.ps1 +0 -0
  332. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy.sh +0 -0
  333. /package/.morph/{templates → framework/templates}/infrastructure/azure/key-vault.bicep +0 -0
  334. /package/.morph/{templates → framework/templates}/infrastructure/azure/main.bicep +0 -0
  335. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.dev.json +0 -0
  336. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.prod.json +0 -0
  337. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.staging.json +0 -0
  338. /package/.morph/{templates → framework/templates}/infrastructure/azure/sql-database.bicep +0 -0
  339. /package/.morph/{templates → framework/templates}/infrastructure/azure/storage.bicep +0 -0
  340. /package/.morph/{templates → framework/templates}/infrastructure/docker/Dockerfile.template +0 -0
  341. /package/.morph/{templates → framework/templates}/infrastructure/docker/docker-compose.template.yml +0 -0
  342. /package/.morph/{templates → framework/templates}/infrastructure/docker/dockerfile-api.dockerfile +0 -0
  343. /package/.morph/{templates → framework/templates}/infrastructure/docker/dockerfile-web.dockerfile +0 -0
  344. /package/.morph/{templates → framework/templates}/infrastructure/docker/easypanel.template.json +0 -0
  345. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -0
  346. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/docker-build-push/action.yml.hbs +0 -0
  347. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/health-check/action.yml.hbs +0 -0
  348. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -0
  349. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/docker-build-push.yml.hbs +0 -0
  350. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/dotnet-build.yml.hbs +0 -0
  351. /package/.morph/{templates → framework/templates}/integrations/asaas-client.cs +0 -0
  352. /package/.morph/{templates → framework/templates}/integrations/asaas-webhook.cs +0 -0
  353. /package/.morph/{templates → framework/templates}/integrations/azure-identity-config.cs +0 -0
  354. /package/.morph/{templates → framework/templates}/integrations/clerk-config.cs +0 -0
  355. /package/.morph/{templates → framework/templates}/meta-prompts/fusion/fusion-agent.md +0 -0
  356. /package/.morph/{templates → framework/templates}/meta-prompts/fusion/fusion-aggregator.md +0 -0
  357. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-retry.md +0 -0
  358. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-validation.md +0 -0
  359. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-wrapper.md +0 -0
  360. /package/.morph/{templates → framework/templates}/meta-prompts/parallel-workers/parallel-coordinator.md +0 -0
  361. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/backend-squad.md +0 -0
  362. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/frontend-squad.md +0 -0
  363. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/squad-leader.md +0 -0
  364. /package/.morph/{templates → framework/templates}/meta-prompts/validators/checkpoint-validator.md +0 -0
  365. /package/.morph/{templates → framework/templates}/saas/subscription.cs +0 -0
  366. /package/.morph/{templates → framework/templates}/saas/tenant.cs +0 -0
  367. /package/.morph/{templates → framework/templates}/state.template.json +0 -0
  368. /package/.morph/{templates → framework/templates}/ui/FluentDesignTheme.cs +0 -0
  369. /package/.morph/{templates → framework/templates}/ui/MudTheme.cs +0 -0
  370. /package/.morph/{templates → framework/templates}/ui/design-system.css +0 -0
  371. /package/framework/hooks/{commit-msg → git/commit-msg}/conventional-commits.sh +0 -0
  372. /package/framework/hooks/{pre-commit → git/pre-commit}/agents.sh +0 -0
  373. /package/framework/hooks/{pre-commit → git/pre-commit}/orchestrator.sh +0 -0
  374. /package/framework/hooks/{pre-commit → git/pre-commit}/specs.sh +0 -0
  375. /package/framework/hooks/{pre-push → git/pre-push}/run-tests.sh +0 -0
@@ -0,0 +1,735 @@
1
+ # Claude Code Native Enrichment Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Enrich morph-spec's use of Claude Code native primitives — richer agent frontmatter, Stop hook upgrade, level-2 skill installation, and SubagentStart telemetry.
6
+
7
+ **Architecture:** Four independent improvements to `agents-installer.js`, `skills-installer.js`, `hooks-installer.js`, and a new `log-agent-start.js` hook. Each follows TDD with tests first. All are self-contained and can be committed independently.
8
+
9
+ **Tech Stack:** Node.js ESM, node:test, fs/promises, Claude Code settings.json schema
10
+
11
+ **Design doc:** `docs/plans/2026-02-22-native-enrichment-design.md`
12
+
13
+ ---
14
+
15
+ ## Task 1: Richer agent frontmatter
16
+
17
+ **Context:** Currently generated `.claude/agents/morph-*.md` files have only `name` and `description` in YAML. Claude Code supports `model`, `tools`, `maxTurns`, `skills`, and `memory`. This task adds tier-based defaults to the installer.
18
+
19
+ **Files:**
20
+ - Modify: `src/utils/agents-installer.js`
21
+ - Modify: `test/utils/agents-installer.test.js`
22
+
23
+ **Tier defaults:**
24
+
25
+ | Tier | model | tools | maxTurns | skills | memory |
26
+ |------|-------|-------|----------|--------|--------|
27
+ | 1 (Orchestrators) | `inherit` | `Read, Grep, Glob, Bash, Task` | `30` | `morph-checklist` | `project` |
28
+ | 2 (Domain Leaders) | `inherit` | `Read, Grep, Glob, Bash` | `20` | `morph-checklist` | `local` |
29
+
30
+ `morph-checklist` refers to `.claude/skills/morph-checklist.md` (installed from `framework/skills/level-0-meta/morph-checklist.md`).
31
+
32
+ ---
33
+
34
+ ### Step 1: Write failing tests
35
+
36
+ Add to the bottom of `test/utils/agents-installer.test.js`:
37
+
38
+ ```js
39
+ describe('installAgents — richer frontmatter', () => {
40
+ let tmpDir;
41
+
42
+ before(async () => {
43
+ tmpDir = await mkdtemp(join(tmpdir(), 'morph-agents-rich-'));
44
+ await installAgents(tmpDir, FRAMEWORK_DIR);
45
+ });
46
+
47
+ after(async () => {
48
+ await rm(tmpDir, { recursive: true, force: true });
49
+ });
50
+
51
+ test('tier-1 agent has model field', async () => {
52
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
53
+ const tier1File = files.find(f => f.includes('standards-architect') || f.includes('ai-system'));
54
+ assert.ok(tier1File, 'should have a tier-1 agent file');
55
+ const content = await readFile(join(tmpDir, '.claude', 'agents', tier1File), 'utf-8');
56
+ assert.ok(content.includes('model:'), `${tier1File} should have model field`);
57
+ });
58
+
59
+ test('tier-1 agent has tools field including Task', async () => {
60
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
61
+ const tier1File = files.find(f => f.includes('standards-architect'));
62
+ assert.ok(tier1File);
63
+ const content = await readFile(join(tmpDir, '.claude', 'agents', tier1File), 'utf-8');
64
+ assert.ok(content.includes('tools:'), `${tier1File} should have tools field`);
65
+ assert.ok(content.includes('Task'), `${tier1File} tier-1 should have Task tool`);
66
+ });
67
+
68
+ test('tier-2 agent has tools field without Task', async () => {
69
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
70
+ // tier-2 agents don't have Task in their tools
71
+ const tier2File = files.find(f => f.includes('thread-orchestrator'));
72
+ if (tier2File) {
73
+ const content = await readFile(join(tmpDir, '.claude', 'agents', tier2File), 'utf-8');
74
+ assert.ok(content.includes('tools:'), `${tier2File} should have tools field`);
75
+ }
76
+ // At minimum, all files should have a tools: field
77
+ for (const file of files) {
78
+ const content = await readFile(join(tmpDir, '.claude', 'agents', file), 'utf-8');
79
+ assert.ok(content.includes('tools:'), `${file} should have tools field`);
80
+ }
81
+ });
82
+
83
+ test('all agents have maxTurns field', async () => {
84
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
85
+ for (const file of files) {
86
+ const content = await readFile(join(tmpDir, '.claude', 'agents', file), 'utf-8');
87
+ assert.ok(content.includes('maxTurns:'), `${file} should have maxTurns field`);
88
+ }
89
+ });
90
+
91
+ test('all agents have memory field', async () => {
92
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
93
+ for (const file of files) {
94
+ const content = await readFile(join(tmpDir, '.claude', 'agents', file), 'utf-8');
95
+ assert.ok(content.includes('memory:'), `${file} should have memory field`);
96
+ }
97
+ });
98
+
99
+ test('all agents have skills field with morph-checklist', async () => {
100
+ const files = await readdir(join(tmpDir, '.claude', 'agents'));
101
+ for (const file of files) {
102
+ const content = await readFile(join(tmpDir, '.claude', 'agents', file), 'utf-8');
103
+ assert.ok(content.includes('skills:'), `${file} should have skills field`);
104
+ assert.ok(content.includes('morph-checklist'), `${file} should reference morph-checklist skill`);
105
+ }
106
+ });
107
+ });
108
+ ```
109
+
110
+ ### Step 2: Run test to verify it fails
111
+
112
+ ```bash
113
+ npm test -- test/utils/agents-installer.test.js
114
+ ```
115
+
116
+ Expected: FAIL — `model:` / `tools:` / `maxTurns:` / `memory:` / `skills:` not found in generated files.
117
+
118
+ ### Step 3: Implement the changes in `agents-installer.js`
119
+
120
+ In `buildDescription()` — no change.
121
+
122
+ Replace the content generation line in `installAgents()`:
123
+
124
+ ```js
125
+ // BEFORE (line 46):
126
+ const content = `---\nname: ${agent.title ?? agent.name}\ndescription: ${description}\n---\n\n${body}\n`;
127
+
128
+ // AFTER:
129
+ const frontmatter = buildFrontmatter(agent, description);
130
+ const content = `---\n${frontmatter}---\n\n${body}\n`;
131
+ ```
132
+
133
+ Add `buildFrontmatter()` function after `buildDescription()`:
134
+
135
+ ```js
136
+ function buildFrontmatter(agent, description) {
137
+ const isOrchestrator = agent.tier === 1;
138
+ const tools = isOrchestrator
139
+ ? 'Read, Grep, Glob, Bash, Task'
140
+ : 'Read, Grep, Glob, Bash';
141
+ const maxTurns = isOrchestrator ? 30 : 20;
142
+ const memory = isOrchestrator ? 'project' : 'local';
143
+ const name = agent.title ?? agent.name;
144
+
145
+ return [
146
+ `name: ${name}`,
147
+ `description: ${description}`,
148
+ `model: inherit`,
149
+ `tools: ${tools}`,
150
+ `maxTurns: ${maxTurns}`,
151
+ `skills:`,
152
+ ` - morph-checklist`,
153
+ `memory: ${memory}`,
154
+ ``
155
+ ].join('\n');
156
+ }
157
+ ```
158
+
159
+ ### Step 4: Run tests to verify they pass
160
+
161
+ ```bash
162
+ npm test -- test/utils/agents-installer.test.js
163
+ ```
164
+
165
+ Expected: All 11 tests pass (5 original + 6 new).
166
+
167
+ ### Step 5: Run full suite to verify no regressions
168
+
169
+ ```bash
170
+ npm test
171
+ ```
172
+
173
+ Expected: All existing tests pass, 6 new tests pass.
174
+
175
+ ### Step 6: Commit
176
+
177
+ ```bash
178
+ git add src/utils/agents-installer.js test/utils/agents-installer.test.js
179
+ git commit -m "feat(agents): add tier-based model/tools/maxTurns/skills/memory to agent frontmatter"
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Task 2: Upgrade Stop hook to `type: "agent"`
185
+
186
+ **Context:** The current Stop hook runs `validate-completion.js`, a Node.js script that reads `state.json` and injects advisory context. The docs support `type: "agent"` — a subagent with tool access that makes a `{"ok": true/false}` decision. This replaces the Node.js script with an inline LLM-based check.
187
+
188
+ **Key difference:** The current hook is *advisory* (injects context, always exits 0). The new hook is *blocking* (returns `ok: false` to continue Claude working). This changes behavior — Claude will be asked to continue if work is incomplete, rather than just warned.
189
+
190
+ **Marker problem:** `removeMorphHooks()` identifies morph hooks by path pattern in `command`. Agent hooks have no `command`. We must add `_morph: true` to all morph hook entries so the cleanup logic can identify them regardless of type.
191
+
192
+ **Files:**
193
+ - Modify: `src/utils/hooks-installer.js`
194
+ - Test: `test/hooks/hooks-installer.test.js`
195
+
196
+ ---
197
+
198
+ ### Step 1: Write failing tests
199
+
200
+ Add to `test/hooks/hooks-installer.test.js` inside the `describe('installClaudeHooks', ...)` block:
201
+
202
+ ```js
203
+ test('Stop hook uses type "agent" not type "command"', async () => {
204
+ await installClaudeHooks(tempDir);
205
+ const settings = readSettings();
206
+
207
+ const stopHooks = settings.hooks.Stop;
208
+ assert.ok(stopHooks, 'Stop event should exist');
209
+ assert.ok(stopHooks.length > 0);
210
+ const stopHook = stopHooks[0];
211
+ assert.ok(stopHook.hooks?.length > 0);
212
+ assert.strictEqual(stopHook.hooks[0].type, 'agent', 'Stop hook should use type: agent');
213
+ });
214
+
215
+ test('Stop hook has prompt and timeout fields', async () => {
216
+ await installClaudeHooks(tempDir);
217
+ const settings = readSettings();
218
+
219
+ const stopHook = settings.hooks.Stop[0].hooks[0];
220
+ assert.ok(typeof stopHook.prompt === 'string', 'agent hook should have prompt');
221
+ assert.ok(stopHook.prompt.includes('.morph/state.json'), 'prompt should reference state.json');
222
+ assert.ok(typeof stopHook.timeout === 'number', 'agent hook should have timeout');
223
+ });
224
+
225
+ test('SubagentStart hook is installed with morph-.* matcher', async () => {
226
+ await installClaudeHooks(tempDir);
227
+ const settings = readSettings();
228
+
229
+ assert.ok(settings.hooks.SubagentStart, 'SubagentStart event should exist');
230
+ const entry = settings.hooks.SubagentStart[0];
231
+ assert.strictEqual(entry.matcher, 'morph-.*');
232
+ });
233
+
234
+ test('morph hook entries have _morph marker for cleanup identification', async () => {
235
+ await installClaudeHooks(tempDir);
236
+ const settings = readSettings();
237
+
238
+ // Check a known morph hook event
239
+ const preToolUse = settings.hooks.PreToolUse;
240
+ const morphEntry = preToolUse.find(e => e._morph === true);
241
+ assert.ok(morphEntry, 'at least one PreToolUse entry should have _morph: true');
242
+ });
243
+ ```
244
+
245
+ ### Step 2: Run tests to verify they fail
246
+
247
+ ```bash
248
+ npm test -- test/hooks/hooks-installer.test.js
249
+ ```
250
+
251
+ Expected: FAIL — Stop hook still uses `type: "command"`, no `SubagentStart`, no `_morph` marker.
252
+
253
+ ### Step 3: Update `MORPH_HOOKS` in `hooks-installer.js`
254
+
255
+ **3a.** Add `_morph: true` to each hook entry in `MORPH_HOOKS`. Change every `hooks: [...]` array item wrapper to include the marker. Example — the SessionStart entry becomes:
256
+
257
+ ```js
258
+ {
259
+ event: 'SessionStart',
260
+ matcher: 'startup|resume|compact',
261
+ _morph: true,
262
+ hooks: [{ type: 'command', command: 'node framework/hooks/claude-code/session-start/inject-morph-context.js' }]
263
+ },
264
+ ```
265
+
266
+ Do this for ALL entries in `MORPH_HOOKS` (9 existing entries).
267
+
268
+ **3b.** Replace the Stop entry:
269
+
270
+ ```js
271
+ // BEFORE:
272
+ {
273
+ event: 'Stop',
274
+ matcher: null,
275
+ hooks: [{
276
+ type: 'command',
277
+ command: 'node framework/hooks/claude-code/stop/validate-completion.js'
278
+ }]
279
+ },
280
+
281
+ // AFTER:
282
+ {
283
+ event: 'Stop',
284
+ matcher: null,
285
+ _morph: true,
286
+ hooks: [{
287
+ type: 'agent',
288
+ prompt: `Check if the active morph-spec feature phase outputs are complete.
289
+ 1. Read the file .morph/state.json to find features with status "in_progress".
290
+ 2. For each in_progress feature, check if required output files for the current phase exist and are non-empty.
291
+ - proposal phase: .morph/features/{feature}/0-proposal/proposal.md
292
+ - design phase: .morph/features/{feature}/1-design/spec.md
293
+ - tasks phase: .morph/features/{feature}/3-tasks/tasks.md
294
+ - implement phase: check tasks.completed vs tasks.total from state.json
295
+ 3. If all required outputs exist and tasks are complete, return {"ok": true}.
296
+ 4. If any required output is missing or empty, return {"ok": false, "reason": "Missing output: <path>"}.
297
+ 5. If state.json does not exist or no feature is in_progress, return {"ok": true}.
298
+ Do NOT modify any files. Read only.`,
299
+ timeout: 60
300
+ }]
301
+ },
302
+ ```
303
+
304
+ **3c.** Add SubagentStart entry (after the Notification entry):
305
+
306
+ ```js
307
+ // === SubagentStart ===
308
+ {
309
+ event: 'SubagentStart',
310
+ matcher: 'morph-.*',
311
+ _morph: true,
312
+ hooks: [{
313
+ type: 'command',
314
+ command: 'node framework/hooks/claude-code/subagent/log-agent-start.js'
315
+ }]
316
+ },
317
+ ```
318
+
319
+ **3d.** Update `removeMorphHooks()` to detect `_morph: true` marker (not just command path):
320
+
321
+ ```js
322
+ function removeMorphHooks(settings) {
323
+ const morphPathPattern = /framework\/hooks\/claude-code\//;
324
+
325
+ for (const [event, entries] of Object.entries(settings.hooks)) {
326
+ if (!Array.isArray(entries)) continue;
327
+
328
+ settings.hooks[event] = entries.filter(entry => {
329
+ // Remove if marked with _morph flag
330
+ if (entry._morph === true) return false;
331
+
332
+ if (!Array.isArray(entry.hooks)) return true;
333
+ // Legacy detection: remove if all hooks are morph-managed command hooks
334
+ const nonMorphHooks = entry.hooks.filter(h =>
335
+ typeof h.command !== 'string' || !morphPathPattern.test(h.command)
336
+ );
337
+ return nonMorphHooks.length > 0;
338
+ });
339
+
340
+ if (settings.hooks[event].length === 0) {
341
+ delete settings.hooks[event];
342
+ }
343
+ }
344
+ }
345
+ ```
346
+
347
+ **3e.** Update the install loop to propagate `_morph: true` to the installed entry:
348
+
349
+ ```js
350
+ // In the for loop inside installClaudeHooks():
351
+ const entry = { _morph: true }; // ← add this flag
352
+ if (matcher) {
353
+ entry.matcher = matcher;
354
+ }
355
+ entry.hooks = hooks.map(h => {
356
+ // For agent/prompt type hooks, pass through as-is (no command path transform)
357
+ if (h.type === 'agent' || h.type === 'prompt') {
358
+ return { type: h.type, prompt: h.prompt, timeout: h.timeout };
359
+ }
360
+ return {
361
+ type: h.type,
362
+ command: `node "$CLAUDE_PROJECT_DIR/framework/hooks/claude-code/${getHookSubpath(h.command)}"`,
363
+ ...(h.timeout ? { timeout: h.timeout } : {})
364
+ };
365
+ });
366
+ ```
367
+
368
+ ### Step 4: Run tests to verify they pass
369
+
370
+ ```bash
371
+ npm test -- test/hooks/hooks-installer.test.js
372
+ ```
373
+
374
+ Expected: All tests pass, including the 4 new ones.
375
+
376
+ ### Step 5: Run full suite
377
+
378
+ ```bash
379
+ npm test
380
+ ```
381
+
382
+ Expected: All existing tests pass. Note: the `installs all hook events` test checks `settings.hooks.Stop` — this still passes since Stop still exists, just uses type:agent now.
383
+
384
+ ### Step 6: Commit
385
+
386
+ ```bash
387
+ git add src/utils/hooks-installer.js test/hooks/hooks-installer.test.js
388
+ git commit -m "feat(hooks): upgrade Stop hook to type:agent; add SubagentStart hook; add _morph marker"
389
+ ```
390
+
391
+ ---
392
+
393
+ ## Task 3: Create `framework/hooks/claude-code/subagent/log-agent-start.js`
394
+
395
+ **Context:** The SubagentStart hook added in Task 2 references this script. It needs to exist and be a simple, fail-open logger.
396
+
397
+ **Files:**
398
+ - Create: `framework/hooks/claude-code/subagent/log-agent-start.js`
399
+
400
+ ---
401
+
402
+ ### Step 1: Write the hook script
403
+
404
+ ```js
405
+ #!/usr/bin/env node
406
+
407
+ /**
408
+ * SubagentStart Hook: Log Morph Agent Activation
409
+ *
410
+ * Event: SubagentStart (matcher: morph-.*)
411
+ *
412
+ * Appends a JSON line to .morph/logs/agents.log whenever a morph
413
+ * native subagent is activated. Fail-open: exits 0 on any error.
414
+ */
415
+
416
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
417
+ import { join } from 'path';
418
+
419
+ try {
420
+ const input = readFileSync('/dev/stdin', 'utf-8');
421
+ const data = JSON.parse(input);
422
+
423
+ const logDir = join(process.cwd(), '.morph', 'logs');
424
+ if (!existsSync(logDir)) {
425
+ mkdirSync(logDir, { recursive: true });
426
+ }
427
+
428
+ const logPath = join(logDir, 'agents.log');
429
+ const entry = JSON.stringify({
430
+ timestamp: new Date().toISOString(),
431
+ agentType: data.agent_type ?? data.agentType ?? 'unknown',
432
+ sessionId: data.session_id ?? null
433
+ }) + '\n';
434
+
435
+ writeFileSync(logPath, entry, { flag: 'a', encoding: 'utf-8' });
436
+ } catch {
437
+ // Fail-open: never block agent activation
438
+ }
439
+
440
+ process.exit(0);
441
+ ```
442
+
443
+ **Windows note:** `/dev/stdin` does not exist on Windows. Use `process.stdin` with a streaming approach. For cross-platform support, replace the stdin read with:
444
+
445
+ ```js
446
+ import { readFileSync } from 'node:fs';
447
+
448
+ function readStdin() {
449
+ try {
450
+ // Unix
451
+ return readFileSync('/dev/stdin', 'utf-8');
452
+ } catch {
453
+ // Windows fallback: read from fd 0
454
+ return readFileSync(0, 'utf-8');
455
+ }
456
+ }
457
+ ```
458
+
459
+ Actually, use the pattern already used by the other hooks. Check `framework/hooks/shared/stdin-reader.js` for the correct stdin reading utility.
460
+
461
+ ### Step 2: Check the existing stdin pattern
462
+
463
+ ```bash
464
+ cat framework/hooks/shared/stdin-reader.js
465
+ ```
466
+
467
+ Use whatever pattern it exports (likely `readStdin()` or similar). Import and use it.
468
+
469
+ ### Step 3: Run full test suite (no new unit tests for this hook — it's a simple I/O script)
470
+
471
+ ```bash
472
+ npm test
473
+ ```
474
+
475
+ Expected: All tests still pass. No regressions.
476
+
477
+ ### Step 4: Commit
478
+
479
+ ```bash
480
+ git add framework/hooks/claude-code/subagent/log-agent-start.js
481
+ git commit -m "feat(hooks): add SubagentStart log-agent-start.js hook script"
482
+ ```
483
+
484
+ ---
485
+
486
+ ## Task 4: Install level-2 skills in `skills-installer.js`
487
+
488
+ **Context:** Level-2 domain skills (`level-2-domains/`) contain 17 `.md` files across 7 subdirectories. The skills-installer currently only handles flat directories (level-0 and level-1). Level-2 requires recursive walk. Level-3 and level-4 only have README.md — no content to install yet.
489
+
490
+ **Duplicate file warning:** `hangfire-orchestrator.md` exists in both `backend/` and `integrations/` subdirectories. The flat install will overwrite with whichever comes last. This is acceptable — they likely have different content, but users get one version. Document this in comments.
491
+
492
+ **Files:**
493
+ - Modify: `src/utils/skills-installer.js`
494
+ - Create: `test/utils/skills-installer.test.js`
495
+
496
+ ---
497
+
498
+ ### Step 1: Write failing tests
499
+
500
+ Create `test/utils/skills-installer.test.js`:
501
+
502
+ ```js
503
+ /**
504
+ * Tests for src/utils/skills-installer.js
505
+ */
506
+
507
+ import { test, describe, before, after } from 'node:test';
508
+ import assert from 'node:assert/strict';
509
+ import { mkdtemp, rm, readdir } from 'node:fs/promises';
510
+ import { join } from 'path';
511
+ import { tmpdir } from 'os';
512
+ import { fileURLToPath } from 'url';
513
+ import { dirname } from 'path';
514
+ import { installSkills } from '../../src/utils/skills-installer.js';
515
+
516
+ const __dirname = dirname(fileURLToPath(import.meta.url));
517
+ // skills-installer uses FRAMEWORK_SKILLS_DIR hardcoded from __dirname
518
+ // So we can only test with the real framework directory
519
+
520
+ describe('installSkills', () => {
521
+ let tmpDir;
522
+
523
+ before(async () => {
524
+ tmpDir = await mkdtemp(join(tmpdir(), 'morph-skills-'));
525
+ });
526
+
527
+ after(async () => {
528
+ await rm(tmpDir, { recursive: true, force: true });
529
+ });
530
+
531
+ test('creates .claude/skills/ directory', async () => {
532
+ await installSkills(tmpDir);
533
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
534
+ assert.ok(files.length > 0, 'should have skill files installed');
535
+ });
536
+
537
+ test('installs level-0-meta skills', async () => {
538
+ await installSkills(tmpDir);
539
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
540
+ // morph-checklist comes from level-0-meta
541
+ assert.ok(files.some(f => f === 'morph-checklist.md'), 'morph-checklist.md should be installed');
542
+ assert.ok(files.some(f => f === 'code-review.md'), 'code-review.md should be installed');
543
+ });
544
+
545
+ test('installs level-1-workflows skills', async () => {
546
+ await installSkills(tmpDir);
547
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
548
+ assert.ok(files.some(f => f === 'phase-design.md'), 'phase-design.md should be installed');
549
+ assert.ok(files.some(f => f === 'phase-implement.md'), 'phase-implement.md should be installed');
550
+ });
551
+
552
+ test('installs level-2-domains skills from subdirectories', async () => {
553
+ await installSkills(tmpDir);
554
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
555
+ // These come from level-2-domains subdirectories
556
+ assert.ok(files.some(f => f === 'blazor-builder.md'), 'blazor-builder.md should be installed');
557
+ assert.ok(files.some(f => f === 'dotnet-senior.md'), 'dotnet-senior.md should be installed');
558
+ assert.ok(files.some(f => f === 'azure-architect.md'), 'azure-architect.md should be installed');
559
+ assert.ok(files.some(f => f === 'testing-specialist.md'), 'testing-specialist.md should be installed');
560
+ });
561
+
562
+ test('does not install README.md files', async () => {
563
+ await installSkills(tmpDir);
564
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
565
+ assert.ok(!files.includes('README.md'), 'README.md should not be installed');
566
+ });
567
+
568
+ test('installs more than 20 skills total (level-0 + level-1 + level-2)', async () => {
569
+ await installSkills(tmpDir);
570
+ const files = await readdir(join(tmpDir, '.claude', 'skills'));
571
+ // level-0: 6, level-1: 8, level-2: ~17 = ~31 total
572
+ assert.ok(files.length > 20, `should install more than 20 skills, got ${files.length}`);
573
+ });
574
+
575
+ test('is idempotent — running twice produces same result', async () => {
576
+ await installSkills(tmpDir);
577
+ const firstCount = (await readdir(join(tmpDir, '.claude', 'skills'))).length;
578
+ await installSkills(tmpDir);
579
+ const secondCount = (await readdir(join(tmpDir, '.claude', 'skills'))).length;
580
+ assert.strictEqual(firstCount, secondCount, 'file count should not change on second run');
581
+ });
582
+ });
583
+ ```
584
+
585
+ ### Step 2: Run tests to verify they fail
586
+
587
+ ```bash
588
+ npm test -- test/utils/skills-installer.test.js
589
+ ```
590
+
591
+ Expected: FAIL — `blazor-builder.md`, `dotnet-senior.md`, `azure-architect.md`, `testing-specialist.md` not found (level-2 not installed). Also fails on `> 20 skills` count.
592
+
593
+ ### Step 3: Update `skills-installer.js`
594
+
595
+ Replace the `SKILL_LEVELS_TO_INSTALL` constant and add a recursive walk helper:
596
+
597
+ ```js
598
+ /**
599
+ * Skill levels to install as flat files in .claude/skills/.
600
+ * Level-0 (meta), Level-1 (workflows), Level-2 (domain specialists).
601
+ * Level-3 and Level-4 only contain README.md — no content to install.
602
+ * For Level-2, subdirectories are walked recursively and files are installed flat.
603
+ * Note: if two subdirs have a file with the same name, last-write wins.
604
+ */
605
+ const SKILL_LEVELS_TO_INSTALL = ['level-0-meta', 'level-1-workflows', 'level-2-domains'];
606
+ ```
607
+
608
+ Replace the install loop to handle subdirectories:
609
+
610
+ ```js
611
+ export async function installSkills(projectDir) {
612
+ const claudeSkillsDir = join(projectDir, '.claude', 'skills');
613
+ mkdirSync(claudeSkillsDir, { recursive: true });
614
+
615
+ for (const level of SKILL_LEVELS_TO_INSTALL) {
616
+ const levelDir = join(FRAMEWORK_SKILLS_DIR, level);
617
+ if (!existsSync(levelDir)) continue;
618
+
619
+ installSkillsFromDir(levelDir, claudeSkillsDir);
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Recursively copy all .md skill files (excluding README.md) from srcDir
625
+ * to destDir as flat files.
626
+ * @param {string} srcDir
627
+ * @param {string} destDir
628
+ */
629
+ function installSkillsFromDir(srcDir, destDir) {
630
+ const entries = readdirSync(srcDir);
631
+ for (const entry of entries) {
632
+ const srcPath = join(srcDir, entry);
633
+ const stat = statSync(srcPath);
634
+
635
+ if (stat.isDirectory()) {
636
+ // Recurse into subdirectory
637
+ installSkillsFromDir(srcPath, destDir);
638
+ } else if (entry.endsWith('.md') && entry !== 'README.md') {
639
+ const destPath = join(destDir, basename(entry));
640
+ copyFileSync(srcPath, destPath);
641
+ }
642
+ }
643
+ }
644
+ ```
645
+
646
+ ### Step 4: Run tests to verify they pass
647
+
648
+ ```bash
649
+ npm test -- test/utils/skills-installer.test.js
650
+ ```
651
+
652
+ Expected: All 7 tests pass.
653
+
654
+ ### Step 5: Run full suite
655
+
656
+ ```bash
657
+ npm test
658
+ ```
659
+
660
+ Expected: All existing tests pass, 7 new tests pass.
661
+
662
+ ### Step 6: Commit
663
+
664
+ ```bash
665
+ git add src/utils/skills-installer.js test/utils/skills-installer.test.js
666
+ git commit -m "feat(skills): install level-2 domain skills to .claude/skills/ with recursive walk"
667
+ ```
668
+
669
+ ---
670
+
671
+ ## Task 5: Final verification
672
+
673
+ ### Step 1: Confirm test counts
674
+
675
+ ```bash
676
+ npm run test:coverage:summary
677
+ ```
678
+
679
+ Expected: More tests than before Task 1 (was ~588). Verify no regressions.
680
+
681
+ ### Step 2: Smoke test with `morph-spec init`
682
+
683
+ ```bash
684
+ node bin/morph-spec.js init --force --skip-mcp --skip-detection
685
+ ```
686
+
687
+ Verify:
688
+ ```bash
689
+ # Check agents have new frontmatter
690
+ head -15 .claude/agents/morph-standards-architect.md
691
+ # Expected: model:, tools:, maxTurns:, skills:, memory: all present
692
+
693
+ # Check Stop hook type
694
+ node -e "const s=JSON.parse(require('fs').readFileSync('.claude/settings.local.json')); console.log('Stop type:', s.hooks.Stop[0].hooks[0].type)"
695
+ # Expected: Stop type: agent
696
+
697
+ # Check SubagentStart hook exists
698
+ node -e "const s=JSON.parse(require('fs').readFileSync('.claude/settings.local.json')); console.log('SubagentStart:', !!s.hooks.SubagentStart)"
699
+ # Expected: SubagentStart: true
700
+
701
+ # Check level-2 skills installed
702
+ ls .claude/skills/ | grep -E "blazor|dotnet|azure" | head
703
+ # Expected: blazor-builder.md, dotnet-senior.md, azure-architect.md etc.
704
+
705
+ # Check total skill count
706
+ ls .claude/skills/*.md | wc -l
707
+ # Expected: > 20
708
+ ```
709
+
710
+ ### Step 3: Commit any final cleanup
711
+
712
+ If any cleanup needed:
713
+ ```bash
714
+ git add <changed files>
715
+ git commit -m "chore: native enrichment cleanup after smoke test"
716
+ ```
717
+
718
+ ---
719
+
720
+ ## Summary of Files Changed
721
+
722
+ | File | Change |
723
+ |------|--------|
724
+ | `src/utils/agents-installer.js` | Add `buildFrontmatter()` with tier-based model/tools/maxTurns/skills/memory |
725
+ | `test/utils/agents-installer.test.js` | 6 new tests for richer frontmatter |
726
+ | `src/utils/hooks-installer.js` | Stop→type:agent, SubagentStart hook, `_morph` marker, updated `removeMorphHooks()` |
727
+ | `test/hooks/hooks-installer.test.js` | 4 new tests for Stop type, SubagentStart, `_morph` marker |
728
+ | `framework/hooks/claude-code/subagent/log-agent-start.js` | **NEW** — fail-open agent activation logger |
729
+ | `src/utils/skills-installer.js` | Add level-2 to install list, add recursive `installSkillsFromDir()` |
730
+ | `test/utils/skills-installer.test.js` | **NEW** — 7 tests for skills installation |
731
+
732
+ ---
733
+
734
+ *Plan saved: 2026-02-22*
735
+ *Design doc: `docs/plans/2026-02-22-native-enrichment-design.md`*