claude-mpm 5.4.48__py3-none-any.whl → 5.6.34__py3-none-any.whl

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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (467) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  3. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +119 -689
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/cli/__init__.py +5 -1
  9. claude_mpm/cli/commands/agents.py +2 -4
  10. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  11. claude_mpm/cli/commands/autotodos.py +566 -0
  12. claude_mpm/cli/commands/commander.py +216 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/configure_agent_display.py +3 -1
  15. claude_mpm/cli/commands/hook_errors.py +60 -60
  16. claude_mpm/cli/commands/monitor.py +2 -2
  17. claude_mpm/cli/commands/mpm_init/core.py +15 -8
  18. claude_mpm/cli/commands/profile.py +9 -10
  19. claude_mpm/cli/commands/run.py +35 -3
  20. claude_mpm/cli/commands/skill_source.py +51 -2
  21. claude_mpm/cli/commands/skills.py +171 -17
  22. claude_mpm/cli/executor.py +120 -16
  23. claude_mpm/cli/interactive/__init__.py +10 -0
  24. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  25. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  26. claude_mpm/cli/interactive/skill_selector.py +481 -0
  27. claude_mpm/cli/parsers/base_parser.py +76 -1
  28. claude_mpm/cli/parsers/commander_parser.py +116 -0
  29. claude_mpm/cli/parsers/profile_parser.py +0 -1
  30. claude_mpm/cli/parsers/run_parser.py +10 -0
  31. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  32. claude_mpm/cli/parsers/skills_parser.py +5 -0
  33. claude_mpm/cli/startup.py +544 -511
  34. claude_mpm/cli/startup_display.py +74 -6
  35. claude_mpm/cli/startup_logging.py +2 -2
  36. claude_mpm/cli/utils.py +7 -3
  37. claude_mpm/commander/__init__.py +78 -0
  38. claude_mpm/commander/adapters/__init__.py +60 -0
  39. claude_mpm/commander/adapters/auggie.py +260 -0
  40. claude_mpm/commander/adapters/base.py +288 -0
  41. claude_mpm/commander/adapters/claude_code.py +392 -0
  42. claude_mpm/commander/adapters/codex.py +237 -0
  43. claude_mpm/commander/adapters/communication.py +366 -0
  44. claude_mpm/commander/adapters/example_usage.py +310 -0
  45. claude_mpm/commander/adapters/mpm.py +389 -0
  46. claude_mpm/commander/adapters/registry.py +204 -0
  47. claude_mpm/commander/api/__init__.py +16 -0
  48. claude_mpm/commander/api/app.py +121 -0
  49. claude_mpm/commander/api/errors.py +133 -0
  50. claude_mpm/commander/api/routes/__init__.py +8 -0
  51. claude_mpm/commander/api/routes/events.py +184 -0
  52. claude_mpm/commander/api/routes/inbox.py +171 -0
  53. claude_mpm/commander/api/routes/messages.py +148 -0
  54. claude_mpm/commander/api/routes/projects.py +271 -0
  55. claude_mpm/commander/api/routes/sessions.py +226 -0
  56. claude_mpm/commander/api/routes/work.py +296 -0
  57. claude_mpm/commander/api/schemas.py +186 -0
  58. claude_mpm/commander/chat/__init__.py +7 -0
  59. claude_mpm/commander/chat/cli.py +146 -0
  60. claude_mpm/commander/chat/commands.py +96 -0
  61. claude_mpm/commander/chat/repl.py +310 -0
  62. claude_mpm/commander/config.py +51 -0
  63. claude_mpm/commander/config_loader.py +115 -0
  64. claude_mpm/commander/core/__init__.py +10 -0
  65. claude_mpm/commander/core/block_manager.py +325 -0
  66. claude_mpm/commander/core/response_manager.py +323 -0
  67. claude_mpm/commander/daemon.py +603 -0
  68. claude_mpm/commander/env_loader.py +59 -0
  69. claude_mpm/commander/events/__init__.py +26 -0
  70. claude_mpm/commander/events/manager.py +332 -0
  71. claude_mpm/commander/frameworks/__init__.py +12 -0
  72. claude_mpm/commander/frameworks/base.py +146 -0
  73. claude_mpm/commander/frameworks/claude_code.py +58 -0
  74. claude_mpm/commander/frameworks/mpm.py +62 -0
  75. claude_mpm/commander/inbox/__init__.py +16 -0
  76. claude_mpm/commander/inbox/dedup.py +128 -0
  77. claude_mpm/commander/inbox/inbox.py +224 -0
  78. claude_mpm/commander/inbox/models.py +70 -0
  79. claude_mpm/commander/instance_manager.py +450 -0
  80. claude_mpm/commander/llm/__init__.py +6 -0
  81. claude_mpm/commander/llm/openrouter_client.py +167 -0
  82. claude_mpm/commander/llm/summarizer.py +70 -0
  83. claude_mpm/commander/memory/__init__.py +45 -0
  84. claude_mpm/commander/memory/compression.py +347 -0
  85. claude_mpm/commander/memory/embeddings.py +230 -0
  86. claude_mpm/commander/memory/entities.py +310 -0
  87. claude_mpm/commander/memory/example_usage.py +290 -0
  88. claude_mpm/commander/memory/integration.py +325 -0
  89. claude_mpm/commander/memory/search.py +381 -0
  90. claude_mpm/commander/memory/store.py +657 -0
  91. claude_mpm/commander/models/__init__.py +18 -0
  92. claude_mpm/commander/models/events.py +121 -0
  93. claude_mpm/commander/models/project.py +162 -0
  94. claude_mpm/commander/models/work.py +214 -0
  95. claude_mpm/commander/parsing/__init__.py +20 -0
  96. claude_mpm/commander/parsing/extractor.py +132 -0
  97. claude_mpm/commander/parsing/output_parser.py +270 -0
  98. claude_mpm/commander/parsing/patterns.py +100 -0
  99. claude_mpm/commander/persistence/__init__.py +11 -0
  100. claude_mpm/commander/persistence/event_store.py +274 -0
  101. claude_mpm/commander/persistence/state_store.py +309 -0
  102. claude_mpm/commander/persistence/work_store.py +164 -0
  103. claude_mpm/commander/polling/__init__.py +13 -0
  104. claude_mpm/commander/polling/event_detector.py +104 -0
  105. claude_mpm/commander/polling/output_buffer.py +49 -0
  106. claude_mpm/commander/polling/output_poller.py +153 -0
  107. claude_mpm/commander/project_session.py +268 -0
  108. claude_mpm/commander/proxy/__init__.py +12 -0
  109. claude_mpm/commander/proxy/formatter.py +89 -0
  110. claude_mpm/commander/proxy/output_handler.py +191 -0
  111. claude_mpm/commander/proxy/relay.py +155 -0
  112. claude_mpm/commander/registry.py +410 -0
  113. claude_mpm/commander/runtime/__init__.py +10 -0
  114. claude_mpm/commander/runtime/executor.py +191 -0
  115. claude_mpm/commander/runtime/monitor.py +346 -0
  116. claude_mpm/commander/session/__init__.py +6 -0
  117. claude_mpm/commander/session/context.py +81 -0
  118. claude_mpm/commander/session/manager.py +59 -0
  119. claude_mpm/commander/tmux_orchestrator.py +361 -0
  120. claude_mpm/commander/web/__init__.py +1 -0
  121. claude_mpm/commander/work/__init__.py +30 -0
  122. claude_mpm/commander/work/executor.py +207 -0
  123. claude_mpm/commander/work/queue.py +405 -0
  124. claude_mpm/commander/workflow/__init__.py +27 -0
  125. claude_mpm/commander/workflow/event_handler.py +241 -0
  126. claude_mpm/commander/workflow/notifier.py +146 -0
  127. claude_mpm/commands/mpm-config.md +8 -0
  128. claude_mpm/commands/mpm-doctor.md +8 -0
  129. claude_mpm/commands/mpm-help.md +8 -0
  130. claude_mpm/commands/mpm-init.md +8 -0
  131. claude_mpm/commands/mpm-monitor.md +8 -0
  132. claude_mpm/commands/mpm-organize.md +8 -0
  133. claude_mpm/commands/mpm-postmortem.md +8 -0
  134. claude_mpm/commands/mpm-session-resume.md +9 -1
  135. claude_mpm/commands/mpm-status.md +8 -0
  136. claude_mpm/commands/mpm-ticket-view.md +8 -0
  137. claude_mpm/commands/mpm-version.md +8 -0
  138. claude_mpm/commands/mpm.md +8 -0
  139. claude_mpm/config/agent_presets.py +8 -7
  140. claude_mpm/config/skill_sources.py +16 -0
  141. claude_mpm/constants.py +1 -0
  142. claude_mpm/core/claude_runner.py +154 -2
  143. claude_mpm/core/config.py +35 -22
  144. claude_mpm/core/config_constants.py +74 -9
  145. claude_mpm/core/constants.py +56 -12
  146. claude_mpm/core/hook_manager.py +51 -3
  147. claude_mpm/core/interactive_session.py +12 -11
  148. claude_mpm/core/logger.py +26 -9
  149. claude_mpm/core/logging_utils.py +39 -13
  150. claude_mpm/core/network_config.py +148 -0
  151. claude_mpm/core/oneshot_session.py +7 -6
  152. claude_mpm/core/optimized_startup.py +3 -1
  153. claude_mpm/core/output_style_manager.py +66 -18
  154. claude_mpm/core/shared/config_loader.py +3 -1
  155. claude_mpm/core/socketio_pool.py +47 -15
  156. claude_mpm/core/unified_config.py +54 -8
  157. claude_mpm/core/unified_paths.py +95 -90
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  223. claude_mpm/dashboard/static/svelte-build/index.html +11 -11
  224. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  225. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  226. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  227. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  228. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  229. claude_mpm/experimental/cli_enhancements.py +2 -1
  230. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  231. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  232. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  233. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  234. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  235. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  236. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  237. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  238. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  239. claude_mpm/hooks/claude_hooks/hook_handler.py +170 -104
  240. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  241. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  242. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  243. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  244. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  245. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  246. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  252. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  253. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  254. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  255. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  256. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  257. claude_mpm/hooks/session_resume_hook.py +89 -1
  258. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  259. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  260. claude_mpm/init.py +215 -2
  261. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  262. claude_mpm/scripts/start_activity_logging.py +0 -0
  263. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  264. claude_mpm/services/agents/agent_selection_service.py +2 -2
  265. claude_mpm/services/agents/cache_git_manager.py +1 -1
  266. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  267. claude_mpm/services/agents/deployment/agent_format_converter.py +8 -6
  268. claude_mpm/services/agents/deployment/agent_template_builder.py +14 -4
  269. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  270. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -4
  271. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +4 -1
  272. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  273. claude_mpm/services/agents/git_source_manager.py +6 -2
  274. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  275. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  276. claude_mpm/services/agents/sources/git_source_sync_service.py +10 -5
  277. claude_mpm/services/agents/startup_sync.py +5 -2
  278. claude_mpm/services/cli/__init__.py +3 -0
  279. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  280. claude_mpm/services/cli/session_resume_helper.py +10 -2
  281. claude_mpm/services/command_deployment_service.py +44 -26
  282. claude_mpm/services/delegation_detector.py +175 -0
  283. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  284. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  285. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  286. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  287. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  288. claude_mpm/services/diagnostics/models.py +14 -1
  289. claude_mpm/services/event_log.py +325 -0
  290. claude_mpm/services/hook_installer_service.py +77 -8
  291. claude_mpm/services/infrastructure/__init__.py +4 -0
  292. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  293. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  294. claude_mpm/services/monitor/daemon_manager.py +15 -4
  295. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  296. claude_mpm/services/monitor/server.py +106 -16
  297. claude_mpm/services/pm_skills_deployer.py +267 -94
  298. claude_mpm/services/profile_manager.py +10 -4
  299. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  300. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  301. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  302. claude_mpm/services/skills_deployer.py +188 -67
  303. claude_mpm/services/socketio/handlers/hook.py +14 -7
  304. claude_mpm/services/socketio/server/main.py +12 -4
  305. claude_mpm/skills/__init__.py +2 -1
  306. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  307. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  308. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  309. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  310. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  311. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  312. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  313. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  314. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  315. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  316. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  317. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  318. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  319. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  320. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  321. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  322. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  323. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  324. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  325. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  326. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  327. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  328. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  329. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  330. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  331. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  332. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  333. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  334. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  335. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  336. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  337. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  338. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  339. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  340. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  341. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  342. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  343. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  344. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  345. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  346. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  347. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  348. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  349. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  350. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  351. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  352. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  353. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  354. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  355. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  356. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  357. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  358. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  359. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  360. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  361. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  362. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  363. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  364. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  365. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  366. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  367. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  368. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  369. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  370. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  371. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  372. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  373. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  374. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  375. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  376. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  377. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  378. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  379. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  380. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  381. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  382. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  383. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  384. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  385. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  386. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  387. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  388. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  389. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  390. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  391. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  392. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  393. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  394. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  395. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  396. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  397. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  398. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  399. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  400. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  401. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  402. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  403. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  404. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  405. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  406. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  407. claude_mpm/skills/bundled/security-scanning.md +112 -0
  408. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  409. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  410. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  411. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  412. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  413. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  414. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  415. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  416. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  417. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  418. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  419. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  420. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  421. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  422. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  423. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  424. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  425. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  426. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  427. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  428. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  429. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  430. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  431. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  432. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  433. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  434. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  435. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  436. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  437. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  438. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  439. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  440. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  441. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  442. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  443. claude_mpm/skills/registry.py +295 -90
  444. claude_mpm/skills/skill_manager.py +29 -23
  445. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  446. claude_mpm/utils/agent_dependency_loader.py +103 -4
  447. claude_mpm/utils/robust_installer.py +45 -24
  448. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  449. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +453 -151
  450. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  451. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  452. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  453. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  454. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  455. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  456. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  457. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  458. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  459. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  460. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  461. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  462. claude_mpm-5.4.48.dist-info/METADATA +0 -999
  463. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  464. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  465. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  466. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  467. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
@@ -14,35 +14,144 @@ logger = get_logger(__name__)
14
14
 
15
15
  @dataclass
16
16
  class Skill:
17
- """Represents a skill that can be used by agents."""
18
-
17
+ """Represents a skill that can be used by agents.
18
+
19
+ Supports agentskills.io specification with backward compatibility for legacy claude-mpm format.
20
+
21
+ Spec fields (agentskills.io):
22
+ - name: Required, 1-64 chars, lowercase alphanumeric + hyphens
23
+ - description: Required, 1-1024 chars
24
+ - license: Optional, license name or reference
25
+ - compatibility: Optional, max 500 chars, environment requirements
26
+ - metadata: Optional, key-value mapping for arbitrary data
27
+ - allowed_tools: Optional, list of pre-approved tools
28
+
29
+ Internal fields:
30
+ - path: Path to skill file
31
+ - content: Skill content (markdown)
32
+ - source: Origin of skill ('bundled', 'user', 'project', 'pm')
33
+ - version: Skill version (from metadata.version or top-level)
34
+ - skill_id: Internal ID (defaults to name)
35
+ - agent_types: Which agent types can use this skill
36
+ - updated_at: Last update timestamp (from metadata.updated)
37
+ - tags: Tags for discovery (from metadata.tags or top-level)
38
+
39
+ Claude-mpm extensions (preserved for backward compat):
40
+ - category: Skill category for organization
41
+ - toolchain: Associated toolchain (python, javascript, etc.)
42
+ - progressive_disclosure: Progressive disclosure configuration
43
+ - user_invocable: Whether skill can be manually invoked
44
+ """
45
+
46
+ # Core spec fields (agentskills.io)
19
47
  name: str
20
- path: Path
21
- content: str
22
- source: str # 'bundled', 'user', or 'project'
23
-
24
- # Version tracking fields
25
- version: str = "0.1.0"
26
- skill_id: str = "" # defaults to name if not provided
27
-
28
- # Existing fields
29
- description: str = ""
48
+ description: str
49
+ license: Optional[str] = None
50
+ compatibility: Optional[str] = None
51
+ metadata: Dict[str, Any] = None
52
+ allowed_tools: List[str] = None
53
+
54
+ # Internal fields (not in frontmatter spec)
55
+ path: Path = None
56
+ content: str = ""
57
+ source: str = "bundled" # 'bundled', 'user', 'project', 'pm'
58
+
59
+ # Derived fields (from metadata or fallback)
60
+ version: str = "0.1.0" # From metadata.version or top-level
61
+ skill_id: str = "" # Internal ID (defaults to name)
30
62
  agent_types: List[str] = None # Which agent types can use this skill
63
+ updated_at: Optional[str] = None # From metadata.updated
64
+ tags: List[str] = None # From metadata.tags or top-level
31
65
 
32
- # Optional metadata
33
- updated_at: Optional[str] = None
34
- tags: List[str] = None
66
+ # Claude-mpm extensions (preserved for backward compat)
67
+ category: Optional[str] = None
68
+ toolchain: Optional[str] = None
69
+ progressive_disclosure: Optional[Dict[str, Any]] = None
70
+ user_invocable: bool = False
35
71
 
36
72
  def __post_init__(self):
37
73
  """Initialize default values if not provided."""
74
+ if self.metadata is None:
75
+ self.metadata = {}
38
76
  if self.agent_types is None:
39
77
  self.agent_types = []
40
78
  if self.tags is None:
41
79
  self.tags = []
80
+ if self.allowed_tools is None:
81
+ self.allowed_tools = []
42
82
  if not self.skill_id:
43
83
  self.skill_id = self.name
44
84
 
45
85
 
86
+ def validate_agentskills_spec(skill: Skill) -> tuple[bool, List[str]]:
87
+ """Validate skill against agentskills.io specification.
88
+
89
+ Args:
90
+ skill: Skill object to validate
91
+
92
+ Returns:
93
+ Tuple of (is_valid, list_of_warnings)
94
+ - is_valid: True if skill meets spec requirements
95
+ - warnings: List of warning messages for spec violations
96
+ """
97
+ warnings = []
98
+
99
+ # Validate name (required field)
100
+ if not skill.name:
101
+ warnings.append("Missing required field: name")
102
+ return False, warnings
103
+
104
+ # Validate name format: lowercase alphanumeric + hyphens, no leading/trailing hyphens
105
+ if not re.match(r"^[a-z0-9]+(-[a-z0-9]+)*$", skill.name):
106
+ warnings.append(
107
+ f"Invalid name format: '{skill.name}' (must be lowercase alphanumeric with hyphens, "
108
+ "no leading/trailing hyphens, no consecutive hyphens)"
109
+ )
110
+
111
+ # Validate name length (max 64 chars)
112
+ if len(skill.name) > 64:
113
+ warnings.append(
114
+ f"Name too long: {len(skill.name)} chars (max 64 per agentskills.io spec)"
115
+ )
116
+
117
+ # Validate description (required field)
118
+ if not skill.description:
119
+ warnings.append("Missing required field: description")
120
+ return False, warnings
121
+
122
+ # Validate description length (1-1024 chars)
123
+ desc_len = len(skill.description)
124
+ if desc_len < 1 or desc_len > 1024:
125
+ warnings.append(
126
+ f"Description length {desc_len} chars is outside spec range (1-1024 chars)"
127
+ )
128
+
129
+ # Validate compatibility length (max 500 chars)
130
+ if skill.compatibility and len(skill.compatibility) > 500:
131
+ warnings.append(
132
+ f"Compatibility field too long: {len(skill.compatibility)} chars (max 500)"
133
+ )
134
+
135
+ # Validate metadata is dict
136
+ if skill.metadata is not None and not isinstance(skill.metadata, dict):
137
+ warnings.append("Metadata must be a key-value mapping (dict)")
138
+
139
+ # Check for spec-compliant metadata structure
140
+ spec_metadata_fields = ["version", "author", "updated", "tags"]
141
+ for field in spec_metadata_fields:
142
+ if hasattr(skill, field):
143
+ field_value = getattr(skill, field)
144
+ if field_value and field not in skill.metadata:
145
+ warnings.append(
146
+ f"Field '{field}' should be in metadata block per agentskills.io spec "
147
+ f"(found as top-level field)"
148
+ )
149
+
150
+ # Valid if no errors (only warnings allowed)
151
+ is_valid = len(warnings) == 0 or all("should be in metadata" in w for w in warnings)
152
+ return is_valid, warnings
153
+
154
+
46
155
  class SkillsRegistry:
47
156
  """Registry for managing skills across all tiers."""
48
157
 
@@ -54,7 +163,10 @@ class SkillsRegistry:
54
163
  self._load_project_skills()
55
164
 
56
165
  def _parse_skill_frontmatter(self, content: str) -> Dict[str, Any]:
57
- """Parse YAML frontmatter from skill markdown file.
166
+ """Parse YAML frontmatter from skill markdown file with spec validation.
167
+
168
+ Supports both agentskills.io spec format and legacy claude-mpm format
169
+ with automatic migration.
58
170
 
59
171
  Returns:
60
172
  Dict with frontmatter fields or empty dict if no frontmatter
@@ -70,11 +182,150 @@ class SkillsRegistry:
70
182
 
71
183
  try:
72
184
  frontmatter = yaml.safe_load(match.group(1))
73
- return frontmatter or {}
185
+ if not frontmatter:
186
+ return {}
187
+
188
+ # Apply backward compatibility migration
189
+ return self._apply_backward_compatibility(frontmatter)
74
190
  except yaml.YAMLError as e:
75
191
  logger.warning(f"Failed to parse skill frontmatter: {e}")
76
192
  return {}
77
193
 
194
+ def _apply_backward_compatibility(
195
+ self, frontmatter: Dict[str, Any]
196
+ ) -> Dict[str, Any]:
197
+ """Apply backward compatibility transformations to legacy frontmatter.
198
+
199
+ Auto-migrates legacy claude-mpm fields to agentskills.io spec format:
200
+ - version → metadata.version
201
+ - author → metadata.author
202
+ - updated → metadata.updated
203
+ - tags → metadata.tags (if not already present)
204
+
205
+ Args:
206
+ frontmatter: Parsed frontmatter dict
207
+
208
+ Returns:
209
+ Transformed frontmatter with spec-compliant structure
210
+ """
211
+ # Initialize metadata if not present
212
+ if "metadata" not in frontmatter:
213
+ frontmatter["metadata"] = {}
214
+
215
+ metadata = frontmatter["metadata"]
216
+
217
+ # Auto-migrate version (top-level → metadata.version)
218
+ if "version" in frontmatter and "version" not in metadata:
219
+ metadata["version"] = frontmatter["version"]
220
+ logger.debug(
221
+ f"Auto-migrated 'version' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
222
+ )
223
+
224
+ # Auto-migrate author (top-level → metadata.author)
225
+ if "author" in frontmatter and "author" not in metadata:
226
+ metadata["author"] = frontmatter["author"]
227
+ logger.debug(
228
+ f"Auto-migrated 'author' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
229
+ )
230
+
231
+ # Auto-migrate updated (top-level → metadata.updated)
232
+ if "updated" in frontmatter and "updated" not in metadata:
233
+ metadata["updated"] = frontmatter["updated"]
234
+ logger.debug(
235
+ f"Auto-migrated 'updated' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
236
+ )
237
+
238
+ # Auto-migrate tags (top-level → metadata.tags)
239
+ if "tags" in frontmatter and "tags" not in metadata:
240
+ metadata["tags"] = frontmatter["tags"]
241
+ logger.debug(
242
+ f"Auto-migrated 'tags' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
243
+ )
244
+
245
+ # Parse allowed-tools from space-delimited string to list
246
+ if "allowed-tools" in frontmatter:
247
+ allowed_tools = frontmatter["allowed-tools"]
248
+ if isinstance(allowed_tools, str):
249
+ frontmatter["allowed-tools"] = allowed_tools.split()
250
+
251
+ # Set default compatibility for claude-code if not present
252
+ if "compatibility" not in frontmatter:
253
+ frontmatter["compatibility"] = "claude-code"
254
+
255
+ return frontmatter
256
+
257
+ def _create_skill_from_frontmatter(
258
+ self, frontmatter: Dict[str, Any], path: Path, content: str, source: str
259
+ ) -> Optional[Skill]:
260
+ """Create Skill object from frontmatter with spec compliance.
261
+
262
+ Args:
263
+ frontmatter: Parsed and migrated frontmatter dict
264
+ path: Path to skill file
265
+ content: Full skill content
266
+ source: Source type ('bundled', 'user', 'project', 'pm')
267
+
268
+ Returns:
269
+ Skill object or None if required fields missing
270
+ """
271
+ # Extract spec fields (required)
272
+ name = frontmatter.get("name")
273
+ description = frontmatter.get("description", "")
274
+
275
+ # If name not in frontmatter, use filename stem
276
+ if not name:
277
+ name = path.stem
278
+
279
+ # If description not in frontmatter, extract from content
280
+ if not description:
281
+ description = self._extract_description(content)
282
+
283
+ # Validate required fields
284
+ if not name or not description:
285
+ logger.warning(
286
+ f"Skipping skill at {path}: missing required field (name or description)"
287
+ )
288
+ return None
289
+
290
+ # Extract spec fields (optional)
291
+ license_field = frontmatter.get("license")
292
+ compatibility = frontmatter.get("compatibility", "claude-code")
293
+ metadata = frontmatter.get("metadata", {})
294
+ allowed_tools = frontmatter.get("allowed-tools", [])
295
+
296
+ # Extract derived fields from metadata or top-level
297
+ version = frontmatter.get("version") or metadata.get("version", "0.1.0")
298
+ skill_id = frontmatter.get("skill_id", name)
299
+ updated_at = frontmatter.get("updated_at") or metadata.get("updated")
300
+ tags = frontmatter.get("tags", []) or metadata.get("tags", [])
301
+
302
+ # Extract claude-mpm extensions
303
+ category = frontmatter.get("category")
304
+ toolchain = frontmatter.get("toolchain")
305
+ progressive_disclosure = frontmatter.get("progressive_disclosure")
306
+ user_invocable = frontmatter.get("user-invocable", False)
307
+
308
+ # Create skill object
309
+ return Skill(
310
+ name=name,
311
+ description=description,
312
+ license=license_field,
313
+ compatibility=compatibility,
314
+ metadata=metadata,
315
+ allowed_tools=allowed_tools,
316
+ path=path,
317
+ content=content,
318
+ source=source,
319
+ version=version,
320
+ skill_id=skill_id,
321
+ updated_at=updated_at,
322
+ tags=tags,
323
+ category=category,
324
+ toolchain=toolchain,
325
+ progressive_disclosure=progressive_disclosure,
326
+ user_invocable=user_invocable,
327
+ )
328
+
78
329
  def _load_bundled_skills(self):
79
330
  """Load skills bundled with MPM."""
80
331
  bundled_dir = Path(__file__).parent / "bundled"
@@ -88,32 +339,16 @@ class SkillsRegistry:
88
339
  skill_name = skill_file.stem
89
340
  content = skill_file.read_text(encoding="utf-8")
90
341
 
91
- # Parse frontmatter
342
+ # Parse frontmatter with backward compatibility
92
343
  frontmatter = self._parse_skill_frontmatter(content)
93
344
 
94
- # Extract version fields from frontmatter
95
- version = frontmatter.get("skill_version", "0.1.0")
96
- skill_id = frontmatter.get("skill_id", skill_name)
97
- updated_at = frontmatter.get("updated_at")
98
- tags = frontmatter.get("tags", [])
99
-
100
- # Extract description (from frontmatter or fallback to content parsing)
101
- description = frontmatter.get("description", "")
102
- if not description:
103
- description = self._extract_description(content)
104
-
105
- self.skills[skill_name] = Skill(
106
- name=skill_name,
107
- path=skill_file,
108
- content=content,
109
- source="bundled",
110
- version=version,
111
- skill_id=skill_id,
112
- description=description,
113
- updated_at=updated_at,
114
- tags=tags,
345
+ # Create skill from frontmatter
346
+ skill = self._create_skill_from_frontmatter(
347
+ frontmatter, skill_file, content, "bundled"
115
348
  )
116
- skill_count += 1
349
+ if skill:
350
+ self.skills[skill_name] = skill
351
+ skill_count += 1
117
352
  except Exception as e:
118
353
  logger.error(f"Error loading bundled skill {skill_file}: {e}")
119
354
 
@@ -130,36 +365,20 @@ class SkillsRegistry:
130
365
  for skill_file in user_skills_dir.glob("*.md"):
131
366
  try:
132
367
  skill_name = skill_file.stem
133
- # User skills override bundled skills
134
368
  content = skill_file.read_text(encoding="utf-8")
135
369
 
136
- # Parse frontmatter
370
+ # Parse frontmatter with backward compatibility
137
371
  frontmatter = self._parse_skill_frontmatter(content)
138
372
 
139
- # Extract version fields from frontmatter
140
- version = frontmatter.get("skill_version", "0.1.0")
141
- skill_id = frontmatter.get("skill_id", skill_name)
142
- updated_at = frontmatter.get("updated_at")
143
- tags = frontmatter.get("tags", [])
144
-
145
- # Extract description (from frontmatter or fallback to content parsing)
146
- description = frontmatter.get("description", "")
147
- if not description:
148
- description = self._extract_description(content)
149
-
150
- self.skills[skill_name] = Skill(
151
- name=skill_name,
152
- path=skill_file,
153
- content=content,
154
- source="user",
155
- version=version,
156
- skill_id=skill_id,
157
- description=description,
158
- updated_at=updated_at,
159
- tags=tags,
373
+ # Create skill from frontmatter
374
+ skill = self._create_skill_from_frontmatter(
375
+ frontmatter, skill_file, content, "user"
160
376
  )
161
- skill_count += 1
162
- logger.debug(f"User skill '{skill_name}' overrides bundled version")
377
+ if skill:
378
+ # User skills override bundled skills
379
+ self.skills[skill_name] = skill
380
+ skill_count += 1
381
+ logger.debug(f"User skill '{skill_name}' overrides bundled version")
163
382
  except Exception as e:
164
383
  logger.error(f"Error loading user skill {skill_file}: {e}")
165
384
 
@@ -177,36 +396,22 @@ class SkillsRegistry:
177
396
  for skill_file in project_skills_dir.glob("*.md"):
178
397
  try:
179
398
  skill_name = skill_file.stem
180
- # Project skills override both user and bundled skills
181
399
  content = skill_file.read_text(encoding="utf-8")
182
400
 
183
- # Parse frontmatter
401
+ # Parse frontmatter with backward compatibility
184
402
  frontmatter = self._parse_skill_frontmatter(content)
185
403
 
186
- # Extract version fields from frontmatter
187
- version = frontmatter.get("skill_version", "0.1.0")
188
- skill_id = frontmatter.get("skill_id", skill_name)
189
- updated_at = frontmatter.get("updated_at")
190
- tags = frontmatter.get("tags", [])
191
-
192
- # Extract description (from frontmatter or fallback to content parsing)
193
- description = frontmatter.get("description", "")
194
- if not description:
195
- description = self._extract_description(content)
196
-
197
- self.skills[skill_name] = Skill(
198
- name=skill_name,
199
- path=skill_file,
200
- content=content,
201
- source="project",
202
- version=version,
203
- skill_id=skill_id,
204
- description=description,
205
- updated_at=updated_at,
206
- tags=tags,
404
+ # Create skill from frontmatter
405
+ skill = self._create_skill_from_frontmatter(
406
+ frontmatter, skill_file, content, "project"
207
407
  )
208
- skill_count += 1
209
- logger.debug(f"Project skill '{skill_name}' overrides other versions")
408
+ if skill:
409
+ # Project skills override both user and bundled skills
410
+ self.skills[skill_name] = skill
411
+ skill_count += 1
412
+ logger.debug(
413
+ f"Project skill '{skill_name}' overrides other versions"
414
+ )
210
415
  except Exception as e:
211
416
  logger.error(f"Error loading project skill {skill_file}: {e}")
212
417
 
@@ -58,11 +58,13 @@ class SkillManager:
58
58
  if mapping_count > 0:
59
59
  logger.info(f"Loaded skill mappings for {mapping_count} agents")
60
60
 
61
- def _get_pm_skills(self, project_dir: Optional[Path] = None) -> List[Dict[str, Any]]:
62
- """Load PM skills from project's .claude-mpm/skills/pm/ directory.
61
+ def _get_pm_skills(
62
+ self, project_dir: Optional[Path] = None
63
+ ) -> List[Dict[str, Any]]:
64
+ """Load PM skills from project's .claude/skills/ directory.
63
65
 
64
- PM skills are special required skills deployed per-project,
65
- NOT fetched from the skills repository.
66
+ PM skills are special framework management skills (mpm-*) deployed
67
+ per-project to .claude/skills/, NOT fetched from the skills repository.
66
68
 
67
69
  Args:
68
70
  project_dir: Project directory. Defaults to current working directory.
@@ -73,7 +75,7 @@ class SkillManager:
73
75
  if project_dir is None:
74
76
  project_dir = Path.cwd()
75
77
 
76
- pm_skills_dir = project_dir / ".claude-mpm" / "skills" / "pm"
78
+ pm_skills_dir = project_dir / ".claude" / "skills"
77
79
 
78
80
  if not pm_skills_dir.exists():
79
81
  logger.debug("PM skills directory not found")
@@ -103,22 +105,22 @@ class SkillManager:
103
105
  Dictionary with skill metadata and content, or None if failed
104
106
  """
105
107
  try:
106
- content = skill_file.read_text(encoding='utf-8')
108
+ content = skill_file.read_text(encoding="utf-8")
107
109
 
108
110
  # Parse YAML frontmatter
109
- if content.startswith('---'):
110
- parts = content.split('---', 2)
111
+ if content.startswith("---"):
112
+ parts = content.split("---", 2)
111
113
  if len(parts) >= 3:
112
114
  metadata = yaml.safe_load(parts[1])
113
115
  body = parts[2].strip()
114
116
 
115
117
  return {
116
- 'name': metadata.get('name', skill_file.parent.name),
117
- 'version': metadata.get('version', '1.0.0'),
118
- 'description': metadata.get('description', ''),
119
- 'when_to_use': metadata.get('when_to_use', ''),
120
- 'content': body,
121
- 'is_pm_skill': True
118
+ "name": metadata.get("name", skill_file.parent.name),
119
+ "version": metadata.get("version", "1.0.0"),
120
+ "description": metadata.get("description", ""),
121
+ "when_to_use": metadata.get("when_to_use", ""),
122
+ "content": body,
123
+ "is_pm_skill": True,
122
124
  }
123
125
  except Exception as e:
124
126
  logger.warning(f"Failed to load PM skill {skill_file}: {e}")
@@ -156,19 +158,23 @@ class SkillManager:
156
158
  skills.append(skill)
157
159
 
158
160
  # Add PM skills for PM agent only
159
- if agent_type.lower() in ('pm', 'project-manager', 'project_manager'):
161
+ if agent_type.lower() in ("pm", "project-manager", "project_manager"):
160
162
  pm_skill_dicts = self._get_pm_skills()
161
163
  for pm_skill_dict in pm_skill_dicts:
162
164
  # Convert PM skill dict to Skill object
163
165
  pm_skill = Skill(
164
- name=pm_skill_dict['name'],
165
- path=Path.cwd() / ".claude-mpm" / "skills" / "pm" / pm_skill_dict['name'],
166
- content=pm_skill_dict['content'],
167
- source='pm', # Special source type for PM skills
168
- version=pm_skill_dict['version'],
169
- skill_id=pm_skill_dict['name'],
170
- description=pm_skill_dict['description'],
171
- agent_types=['pm', 'project-manager', 'project_manager']
166
+ name=pm_skill_dict["name"],
167
+ path=Path.cwd()
168
+ / ".claude-mpm"
169
+ / "skills"
170
+ / "pm"
171
+ / pm_skill_dict["name"],
172
+ content=pm_skill_dict["content"],
173
+ source="pm", # Special source type for PM skills
174
+ version=pm_skill_dict["version"],
175
+ skill_id=pm_skill_dict["name"],
176
+ description=pm_skill_dict["description"],
177
+ agent_types=["pm", "project-manager", "project_manager"],
172
178
  )
173
179
  skills.append(pm_skill)
174
180
 
@@ -0,0 +1,112 @@
1
+ # Pre-commit hooks configuration for claude-mpm
2
+ # See https://pre-commit.com for more information
3
+ # See https://pre-commit.com/hooks.html for more hooks
4
+
5
+ repos:
6
+ # Standard pre-commit hooks
7
+ - repo: https://github.com/pre-commit/pre-commit-hooks
8
+ rev: v4.5.0
9
+ hooks:
10
+ - id: trailing-whitespace
11
+ exclude: ^(.*\.md|.*\.txt)$
12
+ - id: end-of-file-fixer
13
+ exclude: ^(.*\.md|.*\.txt)$
14
+ - id: check-yaml
15
+ args: ['--unsafe'] # Allow custom YAML tags
16
+ - id: check-json
17
+ - id: check-toml
18
+ - id: check-merge-conflict
19
+ - id: check-added-large-files
20
+ args: ['--maxkb=1000']
21
+ - id: check-case-conflict
22
+ - id: check-executables-have-shebangs
23
+ - id: check-shebang-scripts-are-executable
24
+ - id: mixed-line-ending
25
+ args: ['--fix=lf']
26
+
27
+ # Ruff - replaces black, isort, flake8, pyupgrade (10-200x faster)
28
+ - repo: https://github.com/astral-sh/ruff-pre-commit
29
+ rev: v0.8.4 # Use latest version
30
+ hooks:
31
+ # Run the linter
32
+ - id: ruff
33
+ args: [--fix]
34
+ # Run the formatter
35
+ - id: ruff-format
36
+
37
+ # Type checking with mypy
38
+ - repo: https://github.com/pre-commit/mirrors-mypy
39
+ rev: v1.8.0
40
+ hooks:
41
+ - id: mypy
42
+ additional_dependencies: [types-PyYAML, types-requests]
43
+ args: ['--config-file=mypy.ini']
44
+ exclude: ^(venv/|\.venv/|env/|\.env/|build/|dist/|\.git/|tests/.*\.py|scripts/.*\.py)
45
+
46
+ # Security scanning with bandit
47
+ - repo: https://github.com/pycqa/bandit
48
+ rev: 1.7.5
49
+ hooks:
50
+ - id: bandit
51
+ args: ['-r', '-f', 'json']
52
+ exclude: ^(venv/|\.venv/|env/|\.env/|build/|dist/|\.git/|tests/.*\.py)
53
+
54
+ # Secret detection with detect-secrets
55
+ - repo: https://github.com/Yelp/detect-secrets
56
+ rev: v1.5.0
57
+ hooks:
58
+ - id: detect-secrets
59
+ args: ['--baseline', '.secrets.baseline']
60
+ exclude: |
61
+ (?x)^(
62
+ venv/.*|
63
+ \.venv/.*|
64
+ node_modules/.*|
65
+ \.git/.*|
66
+ __pycache__/.*|
67
+ .*\.lock|
68
+ .*package-lock\.json|
69
+ .*\.pyc
70
+ )$
71
+
72
+ # Documentation linting
73
+ - repo: https://github.com/pycqa/doc8
74
+ rev: v1.1.1
75
+ hooks:
76
+ - id: doc8
77
+ args: ['--max-line-length=88']
78
+ files: \.rst$
79
+
80
+ # Commitizen for conventional commits
81
+ - repo: https://github.com/commitizen-tools/commitizen
82
+ rev: v3.13.0
83
+ hooks:
84
+ - id: commitizen
85
+ stages: [commit-msg]
86
+
87
+ # Configuration for specific file types
88
+ exclude: |
89
+ (?x)^(
90
+ venv/.*|
91
+ \.venv/.*|
92
+ env/.*|
93
+ \.env/.*|
94
+ build/.*|
95
+ dist/.*|
96
+ \.git/.*|
97
+ __pycache__/.*|
98
+ .*\.pyc|
99
+ .*\.pyo|
100
+ .*\.egg-info/.*|
101
+ \.coverage|
102
+ \.pytest_cache/.*|
103
+ \.mypy_cache/.*|
104
+ node_modules/.*|
105
+ \.DS_Store|
106
+ \.vscode/.*|
107
+ \.idea/.*
108
+ )$
109
+
110
+ # Global settings
111
+ default_stages: [pre-commit]
112
+ fail_fast: false