claude-mpm 5.4.22__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 (487) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT.md +164 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  4. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  5. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  6. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  7. claude_mpm/agents/MEMORY.md +1 -1
  8. claude_mpm/agents/PM_INSTRUCTIONS.md +374 -1257
  9. claude_mpm/agents/WORKFLOW.md +6 -253
  10. claude_mpm/agents/agent_loader.py +1 -1
  11. claude_mpm/agents/base_agent.json +31 -0
  12. claude_mpm/agents/frontmatter_validator.py +2 -2
  13. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  14. claude_mpm/cli/__init__.py +5 -1
  15. claude_mpm/cli/commands/agent_state_manager.py +10 -10
  16. claude_mpm/cli/commands/agents.py +11 -13
  17. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  18. claude_mpm/cli/commands/auto_configure.py +4 -4
  19. claude_mpm/cli/commands/autotodos.py +566 -0
  20. claude_mpm/cli/commands/commander.py +216 -0
  21. claude_mpm/cli/commands/configure.py +621 -22
  22. claude_mpm/cli/commands/configure_agent_display.py +12 -0
  23. claude_mpm/cli/commands/hook_errors.py +60 -60
  24. claude_mpm/cli/commands/monitor.py +2 -2
  25. claude_mpm/cli/commands/mpm_init/core.py +72 -0
  26. claude_mpm/cli/commands/postmortem.py +1 -1
  27. claude_mpm/cli/commands/profile.py +276 -0
  28. claude_mpm/cli/commands/run.py +35 -3
  29. claude_mpm/cli/commands/skill_source.py +51 -2
  30. claude_mpm/cli/commands/skills.py +182 -32
  31. claude_mpm/cli/executor.py +130 -16
  32. claude_mpm/cli/interactive/__init__.py +10 -0
  33. claude_mpm/cli/interactive/agent_wizard.py +32 -52
  34. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  35. claude_mpm/cli/interactive/skill_selector.py +481 -0
  36. claude_mpm/cli/parsers/base_parser.py +83 -1
  37. claude_mpm/cli/parsers/commander_parser.py +116 -0
  38. claude_mpm/cli/parsers/profile_parser.py +147 -0
  39. claude_mpm/cli/parsers/run_parser.py +10 -0
  40. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  41. claude_mpm/cli/parsers/skills_parser.py +2 -3
  42. claude_mpm/cli/startup.py +690 -386
  43. claude_mpm/cli/startup_display.py +74 -6
  44. claude_mpm/cli/startup_logging.py +2 -2
  45. claude_mpm/cli/utils.py +7 -3
  46. claude_mpm/commander/__init__.py +78 -0
  47. claude_mpm/commander/adapters/__init__.py +60 -0
  48. claude_mpm/commander/adapters/auggie.py +260 -0
  49. claude_mpm/commander/adapters/base.py +288 -0
  50. claude_mpm/commander/adapters/claude_code.py +392 -0
  51. claude_mpm/commander/adapters/codex.py +237 -0
  52. claude_mpm/commander/adapters/communication.py +366 -0
  53. claude_mpm/commander/adapters/example_usage.py +310 -0
  54. claude_mpm/commander/adapters/mpm.py +389 -0
  55. claude_mpm/commander/adapters/registry.py +204 -0
  56. claude_mpm/commander/api/__init__.py +16 -0
  57. claude_mpm/commander/api/app.py +121 -0
  58. claude_mpm/commander/api/errors.py +133 -0
  59. claude_mpm/commander/api/routes/__init__.py +8 -0
  60. claude_mpm/commander/api/routes/events.py +184 -0
  61. claude_mpm/commander/api/routes/inbox.py +171 -0
  62. claude_mpm/commander/api/routes/messages.py +148 -0
  63. claude_mpm/commander/api/routes/projects.py +271 -0
  64. claude_mpm/commander/api/routes/sessions.py +226 -0
  65. claude_mpm/commander/api/routes/work.py +296 -0
  66. claude_mpm/commander/api/schemas.py +186 -0
  67. claude_mpm/commander/chat/__init__.py +7 -0
  68. claude_mpm/commander/chat/cli.py +146 -0
  69. claude_mpm/commander/chat/commands.py +96 -0
  70. claude_mpm/commander/chat/repl.py +310 -0
  71. claude_mpm/commander/config.py +51 -0
  72. claude_mpm/commander/config_loader.py +115 -0
  73. claude_mpm/commander/core/__init__.py +10 -0
  74. claude_mpm/commander/core/block_manager.py +325 -0
  75. claude_mpm/commander/core/response_manager.py +323 -0
  76. claude_mpm/commander/daemon.py +603 -0
  77. claude_mpm/commander/env_loader.py +59 -0
  78. claude_mpm/commander/events/__init__.py +26 -0
  79. claude_mpm/commander/events/manager.py +332 -0
  80. claude_mpm/commander/frameworks/__init__.py +12 -0
  81. claude_mpm/commander/frameworks/base.py +146 -0
  82. claude_mpm/commander/frameworks/claude_code.py +58 -0
  83. claude_mpm/commander/frameworks/mpm.py +62 -0
  84. claude_mpm/commander/inbox/__init__.py +16 -0
  85. claude_mpm/commander/inbox/dedup.py +128 -0
  86. claude_mpm/commander/inbox/inbox.py +224 -0
  87. claude_mpm/commander/inbox/models.py +70 -0
  88. claude_mpm/commander/instance_manager.py +450 -0
  89. claude_mpm/commander/llm/__init__.py +6 -0
  90. claude_mpm/commander/llm/openrouter_client.py +167 -0
  91. claude_mpm/commander/llm/summarizer.py +70 -0
  92. claude_mpm/commander/memory/__init__.py +45 -0
  93. claude_mpm/commander/memory/compression.py +347 -0
  94. claude_mpm/commander/memory/embeddings.py +230 -0
  95. claude_mpm/commander/memory/entities.py +310 -0
  96. claude_mpm/commander/memory/example_usage.py +290 -0
  97. claude_mpm/commander/memory/integration.py +325 -0
  98. claude_mpm/commander/memory/search.py +381 -0
  99. claude_mpm/commander/memory/store.py +657 -0
  100. claude_mpm/commander/models/__init__.py +18 -0
  101. claude_mpm/commander/models/events.py +121 -0
  102. claude_mpm/commander/models/project.py +162 -0
  103. claude_mpm/commander/models/work.py +214 -0
  104. claude_mpm/commander/parsing/__init__.py +20 -0
  105. claude_mpm/commander/parsing/extractor.py +132 -0
  106. claude_mpm/commander/parsing/output_parser.py +270 -0
  107. claude_mpm/commander/parsing/patterns.py +100 -0
  108. claude_mpm/commander/persistence/__init__.py +11 -0
  109. claude_mpm/commander/persistence/event_store.py +274 -0
  110. claude_mpm/commander/persistence/state_store.py +309 -0
  111. claude_mpm/commander/persistence/work_store.py +164 -0
  112. claude_mpm/commander/polling/__init__.py +13 -0
  113. claude_mpm/commander/polling/event_detector.py +104 -0
  114. claude_mpm/commander/polling/output_buffer.py +49 -0
  115. claude_mpm/commander/polling/output_poller.py +153 -0
  116. claude_mpm/commander/project_session.py +268 -0
  117. claude_mpm/commander/proxy/__init__.py +12 -0
  118. claude_mpm/commander/proxy/formatter.py +89 -0
  119. claude_mpm/commander/proxy/output_handler.py +191 -0
  120. claude_mpm/commander/proxy/relay.py +155 -0
  121. claude_mpm/commander/registry.py +410 -0
  122. claude_mpm/commander/runtime/__init__.py +10 -0
  123. claude_mpm/commander/runtime/executor.py +191 -0
  124. claude_mpm/commander/runtime/monitor.py +346 -0
  125. claude_mpm/commander/session/__init__.py +6 -0
  126. claude_mpm/commander/session/context.py +81 -0
  127. claude_mpm/commander/session/manager.py +59 -0
  128. claude_mpm/commander/tmux_orchestrator.py +361 -0
  129. claude_mpm/commander/web/__init__.py +1 -0
  130. claude_mpm/commander/work/__init__.py +30 -0
  131. claude_mpm/commander/work/executor.py +207 -0
  132. claude_mpm/commander/work/queue.py +405 -0
  133. claude_mpm/commander/workflow/__init__.py +27 -0
  134. claude_mpm/commander/workflow/event_handler.py +241 -0
  135. claude_mpm/commander/workflow/notifier.py +146 -0
  136. claude_mpm/commands/mpm-config.md +20 -249
  137. claude_mpm/commands/mpm-doctor.md +16 -21
  138. claude_mpm/commands/mpm-help.md +12 -205
  139. claude_mpm/commands/mpm-init.md +88 -506
  140. claude_mpm/commands/mpm-monitor.md +22 -401
  141. claude_mpm/commands/mpm-organize.md +70 -442
  142. claude_mpm/commands/mpm-postmortem.md +13 -107
  143. claude_mpm/commands/mpm-session-resume.md +20 -363
  144. claude_mpm/commands/mpm-status.md +13 -69
  145. claude_mpm/commands/mpm-ticket-view.md +60 -495
  146. claude_mpm/commands/mpm-version.md +13 -107
  147. claude_mpm/commands/mpm.md +8 -0
  148. claude_mpm/config/agent_presets.py +8 -7
  149. claude_mpm/config/skill_sources.py +16 -0
  150. claude_mpm/constants.py +1 -0
  151. claude_mpm/core/claude_runner.py +154 -2
  152. claude_mpm/core/config.py +37 -26
  153. claude_mpm/core/config_constants.py +74 -9
  154. claude_mpm/core/constants.py +56 -12
  155. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  156. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  157. claude_mpm/core/hook_manager.py +51 -3
  158. claude_mpm/core/interactive_session.py +12 -11
  159. claude_mpm/core/logger.py +26 -9
  160. claude_mpm/core/logging_utils.py +39 -13
  161. claude_mpm/core/network_config.py +148 -0
  162. claude_mpm/core/oneshot_session.py +7 -6
  163. claude_mpm/core/optimized_startup.py +61 -0
  164. claude_mpm/core/output_style_manager.py +66 -18
  165. claude_mpm/core/shared/config_loader.py +3 -1
  166. claude_mpm/core/socketio_pool.py +47 -15
  167. claude_mpm/core/unified_agent_registry.py +1 -1
  168. claude_mpm/core/unified_config.py +54 -8
  169. claude_mpm/core/unified_paths.py +95 -90
  170. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  236. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  237. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  238. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  239. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  240. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  241. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  242. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  243. claude_mpm/experimental/cli_enhancements.py +2 -1
  244. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  245. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  246. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  252. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  255. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  256. claude_mpm/hooks/claude_hooks/hook_handler.py +313 -99
  257. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  258. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  259. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  260. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  261. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  262. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  269. claude_mpm/hooks/claude_hooks/services/connection_manager.py +67 -32
  270. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  271. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  272. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  273. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  274. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  275. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  276. claude_mpm/hooks/session_resume_hook.py +89 -1
  277. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  278. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  279. claude_mpm/init.py +276 -0
  280. claude_mpm/models/git_repository.py +3 -3
  281. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  282. claude_mpm/services/agents/agent_builder.py +3 -3
  283. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  284. claude_mpm/services/agents/agent_selection_service.py +2 -2
  285. claude_mpm/services/agents/cache_git_manager.py +7 -7
  286. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  287. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -2
  288. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  289. claude_mpm/services/agents/deployment/agent_template_builder.py +39 -19
  290. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  291. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  292. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  293. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  294. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +169 -26
  295. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +101 -75
  296. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  297. claude_mpm/services/agents/git_source_manager.py +23 -4
  298. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  299. claude_mpm/services/agents/recommender.py +5 -3
  300. claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
  301. claude_mpm/services/agents/sources/git_source_sync_service.py +121 -10
  302. claude_mpm/services/agents/startup_sync.py +27 -4
  303. claude_mpm/services/cli/__init__.py +3 -0
  304. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  305. claude_mpm/services/cli/session_resume_helper.py +10 -2
  306. claude_mpm/services/command_deployment_service.py +44 -26
  307. claude_mpm/services/delegation_detector.py +175 -0
  308. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  309. claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
  310. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  311. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  312. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  313. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  314. claude_mpm/services/diagnostics/models.py +14 -1
  315. claude_mpm/services/event_log.py +325 -0
  316. claude_mpm/services/git/git_operations_service.py +8 -8
  317. claude_mpm/services/hook_installer_service.py +77 -8
  318. claude_mpm/services/infrastructure/__init__.py +4 -0
  319. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  320. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  321. claude_mpm/services/monitor/daemon_manager.py +15 -4
  322. claude_mpm/services/monitor/management/lifecycle.py +15 -3
  323. claude_mpm/services/monitor/server.py +571 -11
  324. claude_mpm/services/pm_skills_deployer.py +884 -0
  325. claude_mpm/services/profile_manager.py +337 -0
  326. claude_mpm/services/skills/git_skill_source_manager.py +281 -20
  327. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  328. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  329. claude_mpm/services/skills_deployer.py +192 -70
  330. claude_mpm/services/socketio/dashboard_server.py +1 -0
  331. claude_mpm/services/socketio/event_normalizer.py +37 -6
  332. claude_mpm/services/socketio/handlers/hook.py +14 -7
  333. claude_mpm/services/socketio/server/core.py +262 -123
  334. claude_mpm/services/socketio/server/main.py +12 -4
  335. claude_mpm/skills/__init__.py +2 -1
  336. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  337. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  338. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  339. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  340. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  341. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  342. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  343. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  344. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  345. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  346. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  347. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  348. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  349. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  350. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  351. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  352. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  353. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  354. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  355. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  356. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  357. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  358. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  359. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  360. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  361. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  362. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  363. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  364. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  365. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  366. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  367. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  368. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  369. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  370. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  371. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  372. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  373. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  374. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  375. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  376. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  377. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  378. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  379. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  380. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  381. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  382. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  383. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  384. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  385. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  386. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  387. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  388. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  389. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  390. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  391. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  392. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  393. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  394. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  395. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  396. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  397. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  398. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  399. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  400. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  401. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  402. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  403. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  404. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  405. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  406. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  407. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  408. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  409. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  410. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  411. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  412. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  413. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  414. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  415. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  416. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  417. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  418. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  419. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  420. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  421. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  422. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  423. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  424. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  425. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  426. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  427. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  428. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  429. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  430. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  431. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  432. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  433. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  434. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  435. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  436. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  437. claude_mpm/skills/bundled/security-scanning.md +112 -0
  438. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  439. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  440. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  441. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  442. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  443. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  444. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  445. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  446. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  447. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  448. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  449. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  450. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  451. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  452. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  453. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  454. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  455. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  456. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  457. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  458. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  459. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  460. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  461. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  462. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  463. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  464. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  465. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  466. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  467. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  468. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  469. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  470. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  471. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  472. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  473. claude_mpm/skills/registry.py +295 -90
  474. claude_mpm/skills/skill_manager.py +98 -3
  475. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  476. claude_mpm/utils/agent_dependency_loader.py +115 -4
  477. claude_mpm/utils/agent_filters.py +1 -1
  478. claude_mpm/utils/migration.py +4 -4
  479. claude_mpm/utils/robust_installer.py +86 -21
  480. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  481. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +486 -145
  482. claude_mpm-5.4.22.dist-info/METADATA +0 -996
  483. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  484. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  485. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  486. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  487. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
@@ -28,7 +28,7 @@ References:
28
28
  import json
29
29
  import platform
30
30
  import shutil
31
- import subprocess
31
+ import subprocess # nosec B404 - subprocess needed for safe git operations
32
32
  from pathlib import Path
33
33
  from typing import Any, Dict, List, Optional
34
34
 
@@ -174,44 +174,93 @@ class SkillsDeployerService(LoggerMixin):
174
174
  if selective:
175
175
  # Auto-detect project root if not provided
176
176
  if project_root is None:
177
- # Try to find project root by looking for .claude directory
177
+ # Try to find project root by looking for .claude-mpm directory
178
178
  # Start from current directory and walk up
179
179
  current = Path.cwd()
180
180
  while current != current.parent:
181
- if (current / ".claude").exists():
181
+ if (current / ".claude-mpm").exists():
182
182
  project_root = current
183
183
  break
184
184
  current = current.parent
185
185
 
186
+ # Read skills from configuration.yaml instead of agent frontmatter
186
187
  if project_root:
187
- agents_dir = Path(project_root) / ".claude" / "agents"
188
+ config_path = Path(project_root) / ".claude-mpm" / "configuration.yaml"
188
189
  else:
189
- # Fallback to current directory's .claude/agents
190
- agents_dir = Path.cwd() / ".claude" / "agents"
190
+ # Fallback to current directory's configuration
191
+ config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
191
192
 
192
193
  from claude_mpm.services.skills.selective_skill_deployer import (
193
194
  get_required_skills_from_agents,
195
+ get_skills_to_deploy,
196
+ save_agent_skills_to_config,
194
197
  )
195
198
 
196
- required_skill_names = get_required_skills_from_agents(agents_dir)
199
+ # Check if agent_referenced is empty and needs to be populated
200
+ required_skill_names, source = get_skills_to_deploy(config_path)
201
+
202
+ if not required_skill_names and project_root:
203
+ # agent_referenced is empty, scan deployed agents to populate it
204
+ agents_dir = Path(project_root) / ".claude" / "agents"
205
+ if agents_dir.exists():
206
+ self.logger.info(
207
+ "agent_referenced is empty in configuration.yaml, scanning deployed agents..."
208
+ )
209
+ agent_skills = get_required_skills_from_agents(agents_dir)
210
+ if agent_skills:
211
+ save_agent_skills_to_config(list(agent_skills), config_path)
212
+ self.logger.info(
213
+ f"Populated agent_referenced with {len(agent_skills)} skills from deployed agents"
214
+ )
215
+ # Re-read configuration after update
216
+ required_skill_names, source = get_skills_to_deploy(config_path)
217
+ else:
218
+ self.logger.warning(
219
+ "No skills found in deployed agents - configuration.yaml remains empty"
220
+ )
221
+ else:
222
+ self.logger.warning(
223
+ f"Agents directory not found at {agents_dir} - cannot scan for skills"
224
+ )
197
225
 
198
226
  if required_skill_names:
227
+ # Convert required_skill_names to a set for O(1) lookup
228
+ required_set = set(required_skill_names)
229
+
199
230
  # Filter to only required skills
200
- # Match on either 'name' or 'skill_id' field
231
+ # Match on: 'name', 'skill_id', or normalized 'source_path'
232
+ # source_path example: "universal/web/api-design-patterns/SKILL.md"
233
+ # normalized: "universal-web-api-design-patterns"
234
+ def skill_matches_requirement(skill):
235
+ # Check basic name and skill_id
236
+ if skill.get("name") in required_set:
237
+ return True
238
+ if skill.get("skill_id") in required_set:
239
+ return True
240
+
241
+ # Check normalized source_path
242
+ source_path = skill.get("source_path", "")
243
+ if source_path:
244
+ # Remove /SKILL.md suffix and replace / with -
245
+ normalized = source_path.replace("/SKILL.md", "").replace(
246
+ "/", "-"
247
+ )
248
+ if normalized in required_set:
249
+ return True
250
+
251
+ return False
252
+
201
253
  filtered_skills = [
202
- s
203
- for s in filtered_skills
204
- if s.get("name") in required_skill_names
205
- or s.get("skill_id") in required_skill_names
254
+ s for s in filtered_skills if skill_matches_requirement(s)
206
255
  ]
207
256
 
208
257
  self.logger.info(
209
258
  f"Selective deployment: {len(filtered_skills)}/{total_available} skills "
210
- f"(agent-referenced only)"
259
+ f"(source: {source})"
211
260
  )
212
261
  else:
213
262
  self.logger.warning(
214
- f"No skills found in agent frontmatter at {agents_dir}. "
263
+ f"No skills found in configuration at {config_path}. "
215
264
  f"Deploying all {total_available} skills."
216
265
  )
217
266
  else:
@@ -224,12 +273,19 @@ class SkillsDeployerService(LoggerMixin):
224
273
  skipped = []
225
274
  errors = []
226
275
 
227
- # Extract skill names for cleanup (needed regardless of deployment outcome)
228
- filtered_skills_names = [
229
- skill["name"]
230
- for skill in filtered_skills
231
- if isinstance(skill, dict) and "name" in skill
232
- ]
276
+ # Extract normalized skill names for cleanup (needed regardless of deployment outcome)
277
+ # Must match the names used during deployment (normalized from source_path)
278
+ filtered_skills_names = []
279
+ for skill in filtered_skills:
280
+ if isinstance(skill, dict) and "name" in skill:
281
+ source_path = skill.get("source_path", "")
282
+ if source_path:
283
+ # Normalize: "universal/web/api-design-patterns/SKILL.md" -> "universal-web-api-design-patterns"
284
+ normalized = source_path.replace("/SKILL.md", "").replace("/", "-")
285
+ filtered_skills_names.append(normalized)
286
+ else:
287
+ # Fallback to skill name
288
+ filtered_skills_names.append(skill["name"])
233
289
 
234
290
  for skill in filtered_skills:
235
291
  try:
@@ -243,9 +299,25 @@ class SkillsDeployerService(LoggerMixin):
243
299
  skill, skills_data["temp_dir"], collection_name, force=force
244
300
  )
245
301
  if result["deployed"]:
246
- deployed.append(skill["name"])
302
+ # Use normalized name for reporting
303
+ source_path = skill.get("source_path", "")
304
+ if source_path:
305
+ normalized = source_path.replace("/SKILL.md", "").replace(
306
+ "/", "-"
307
+ )
308
+ deployed.append(normalized)
309
+ else:
310
+ deployed.append(skill["name"])
247
311
  elif result["skipped"]:
248
- skipped.append(skill["name"])
312
+ # Use normalized name for reporting
313
+ source_path = skill.get("source_path", "")
314
+ if source_path:
315
+ normalized = source_path.replace("/SKILL.md", "").replace(
316
+ "/", "-"
317
+ )
318
+ skipped.append(normalized)
319
+ else:
320
+ skipped.append(skill["name"])
249
321
  if result["error"]:
250
322
  errors.append(result["error"])
251
323
  except Exception as e:
@@ -257,9 +329,9 @@ class SkillsDeployerService(LoggerMixin):
257
329
  self.logger.error(f"Failed to deploy {skill_name}: {e}")
258
330
  errors.append(f"{skill_name}: {e}")
259
331
 
260
- # Step 5: Cleanup orphaned skills (if selective mode enabled)
332
+ # Step 5: Cleanup orphaned skills (always run in selective mode)
261
333
  cleanup_result = {"removed_count": 0, "removed_skills": []}
262
- if selective and len(deployed) > 0:
334
+ if selective:
263
335
  # Get the set of skills that should remain deployed
264
336
  # This is the union of what we just deployed and what was already there
265
337
  try:
@@ -267,7 +339,8 @@ class SkillsDeployerService(LoggerMixin):
267
339
  cleanup_orphan_skills,
268
340
  )
269
341
 
270
- # Only cleanup if we're in selective mode
342
+ # Cleanup orphaned skills not referenced by agents
343
+ # This runs even if nothing new was deployed to remove stale skills
271
344
  cleanup_result = cleanup_orphan_skills(
272
345
  self.CLAUDE_SKILLS_DIR, set(filtered_skills_names)
273
346
  )
@@ -580,7 +653,7 @@ class SkillsDeployerService(LoggerMixin):
580
653
  f"Updating existing collection '{collection_name}' at {target_dir}"
581
654
  )
582
655
  try:
583
- result = subprocess.run(
656
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
584
657
  ["git", "pull"],
585
658
  cwd=target_dir,
586
659
  capture_output=True,
@@ -611,7 +684,7 @@ class SkillsDeployerService(LoggerMixin):
611
684
  f"Installing new collection '{collection_name}' to {target_dir}"
612
685
  )
613
686
  try:
614
- result = subprocess.run(
687
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded git command
615
688
  ["git", "clone", repo_url, str(target_dir)],
616
689
  capture_output=True,
617
690
  text=True,
@@ -700,6 +773,32 @@ class SkillsDeployerService(LoggerMixin):
700
773
  if isinstance(skills_data, dict):
701
774
  flat_skills = []
702
775
 
776
+ # Define valid top-level categories
777
+ VALID_CATEGORIES = {"universal", "toolchains"}
778
+
779
+ # Check for unknown categories and warn user
780
+ unknown_categories = set(skills_data.keys()) - VALID_CATEGORIES
781
+ if unknown_categories:
782
+ # Count skills in unknown categories
783
+ skipped_count = 0
784
+ for cat in unknown_categories:
785
+ cat_data = skills_data.get(cat, [])
786
+ if isinstance(cat_data, list):
787
+ skipped_count += len(cat_data)
788
+ elif isinstance(cat_data, dict):
789
+ # If it's a dict like toolchains, count nested skills
790
+ for skills_list in cat_data.values():
791
+ if isinstance(skills_list, list):
792
+ skipped_count += len(skills_list)
793
+
794
+ self.logger.warning(
795
+ f"Unknown categories in manifest will be skipped: "
796
+ f"{', '.join(sorted(unknown_categories))} ({skipped_count} skills)"
797
+ )
798
+ self.logger.info(
799
+ f"Valid top-level categories: {', '.join(sorted(VALID_CATEGORIES))}"
800
+ )
801
+
703
802
  # Add universal skills
704
803
  universal_skills = skills_data.get("universal", [])
705
804
  if isinstance(universal_skills, list):
@@ -804,55 +903,76 @@ class SkillsDeployerService(LoggerMixin):
804
903
  Dict with deployed, skipped, error flags
805
904
  """
806
905
  skill_name = skill["name"]
807
- target_dir = self.CLAUDE_SKILLS_DIR / skill_name
906
+
907
+ # Use normalized source_path for both target directory and deployment tracking
908
+ # This ensures consistency with configuration.yaml skill names
909
+ source_path = skill.get("source_path", "")
910
+ if source_path:
911
+ # Normalize: "universal/web/api-design-patterns/SKILL.md" -> "universal-web-api-design-patterns"
912
+ normalized_name = source_path.replace("/SKILL.md", "").replace("/", "-")
913
+ target_dir = self.CLAUDE_SKILLS_DIR / normalized_name
914
+ else:
915
+ # Fallback to skill name if no source_path
916
+ target_dir = self.CLAUDE_SKILLS_DIR / skill_name
808
917
 
809
918
  # Check if already deployed
810
919
  if target_dir.exists() and not force:
811
920
  self.logger.debug(f"Skipped {skill_name} (already deployed)")
812
921
  return {"deployed": False, "skipped": True, "error": None}
813
922
 
814
- # Find skill source in collection directory
815
- # Updated structure: collection_dir / skills / category / skill-name
816
- # OR: collection_dir / universal / skill-name
817
- # OR: collection_dir / toolchains / toolchain-name / skill-name
923
+ # Find skill source using source_path from manifest
924
+ source_dir = None
818
925
 
819
- skills_base = collection_dir / "skills"
820
- category = skill.get("category", "")
926
+ if source_path:
927
+ # Direct lookup using source_path (most reliable)
928
+ # Example: "universal/web/api-design-patterns/SKILL.md" -> "universal/web/api-design-patterns"
929
+ skill_dir_path = source_path.replace("/SKILL.md", "")
930
+ potential_source = collection_dir / skill_dir_path
931
+ if potential_source.exists():
932
+ source_dir = potential_source
933
+ else:
934
+ self.logger.debug(
935
+ f"Source path {skill_dir_path} not found, trying fallback search"
936
+ )
821
937
 
822
- # Try multiple possible locations
823
- source_dir = None
824
- search_paths = []
825
-
826
- # Try category-based path
827
- if category and skills_base.exists():
828
- search_paths.append(skills_base / category / skill_name)
829
-
830
- # Try universal/toolchains structure
831
- if (collection_dir / "universal").exists():
832
- search_paths.append(collection_dir / "universal" / skill_name)
833
-
834
- if (collection_dir / "toolchains").exists():
835
- toolchain_dir = collection_dir / "toolchains"
836
- for tc in toolchain_dir.iterdir():
837
- if tc.is_dir():
838
- search_paths.append(tc / skill_name)
839
-
840
- # Search in all possible locations
841
- for path in search_paths:
842
- if path.exists():
843
- source_dir = path
844
- break
845
-
846
- # Fallback: search recursively for skill in skills directory
847
- if not source_dir and skills_base.exists():
848
- for cat_dir in skills_base.iterdir():
849
- if not cat_dir.is_dir():
850
- continue
851
- potential = cat_dir / skill_name
852
- if potential.exists():
853
- source_dir = potential
938
+ # Fallback: search using old logic (for backward compatibility)
939
+ if not source_dir:
940
+ skills_base = collection_dir / "skills"
941
+ category = skill.get("category", "")
942
+
943
+ # Try multiple possible locations
944
+ search_paths = []
945
+
946
+ # Try category-based path
947
+ if category and skills_base.exists():
948
+ search_paths.append(skills_base / category / skill_name)
949
+
950
+ # Try universal/toolchains structure
951
+ if (collection_dir / "universal").exists():
952
+ search_paths.append(collection_dir / "universal" / skill_name)
953
+
954
+ if (collection_dir / "toolchains").exists():
955
+ toolchain_dir = collection_dir / "toolchains"
956
+ for tc in toolchain_dir.iterdir():
957
+ if tc.is_dir():
958
+ search_paths.append(tc / skill_name)
959
+
960
+ # Search in all possible locations
961
+ for path in search_paths:
962
+ if path.exists():
963
+ source_dir = path
854
964
  break
855
965
 
966
+ # Final fallback: search recursively for skill in skills directory
967
+ if not source_dir and skills_base.exists():
968
+ for cat_dir in skills_base.iterdir():
969
+ if not cat_dir.is_dir():
970
+ continue
971
+ potential = cat_dir / skill_name
972
+ if potential.exists():
973
+ source_dir = potential
974
+ break
975
+
856
976
  if not source_dir or not source_dir.exists():
857
977
  return {
858
978
  "deployed": False,
@@ -887,12 +1007,14 @@ class SkillsDeployerService(LoggerMixin):
887
1007
  # NOTE: We use copy instead of symlink to maintain Claude Code compatibility
888
1008
  shutil.copytree(source_dir, target_dir)
889
1009
 
890
- # Track deployment in index
1010
+ # Track deployment in index using normalized name
891
1011
  from claude_mpm.services.skills.selective_skill_deployer import (
892
1012
  track_deployed_skill,
893
1013
  )
894
1014
 
895
- track_deployed_skill(self.CLAUDE_SKILLS_DIR, skill_name, collection_name)
1015
+ # Use normalized name for tracking (matches configuration.yaml format)
1016
+ track_name = normalized_name if source_path else skill_name
1017
+ track_deployed_skill(self.CLAUDE_SKILLS_DIR, track_name, collection_name)
896
1018
 
897
1019
  self.logger.debug(
898
1020
  f"Deployed {skill_name} from {source_dir} to {target_dir}"
@@ -926,12 +1048,12 @@ class SkillsDeployerService(LoggerMixin):
926
1048
  """
927
1049
  try:
928
1050
  if platform.system() == "Windows":
929
- result = subprocess.run(
1051
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded tasklist command
930
1052
  ["tasklist"], check=False, capture_output=True, text=True, timeout=5
931
1053
  )
932
1054
  return "claude" in result.stdout.lower()
933
1055
  # macOS and Linux
934
- result = subprocess.run(
1056
+ result = subprocess.run( # nosec B603 B607 - Safe: hardcoded ps command
935
1057
  ["ps", "aux"], check=False, capture_output=True, text=True, timeout=5
936
1058
  )
937
1059
  # Look for "Claude Code" or "claude-code" process
@@ -152,6 +152,7 @@ class DashboardServer(SocketIOServiceInterface):
152
152
 
153
153
  # Register handlers for all events we want to relay from monitor to dashboard
154
154
  relay_events = [
155
+ "claude_event", # Tool events from Claude Code hooks
155
156
  "session_started",
156
157
  "session_ended",
157
158
  "claude_status",
@@ -6,7 +6,7 @@ This normalizer ensures all events follow a consistent schema before broadcastin
6
6
  providing backward compatibility while establishing a standard format.
7
7
 
8
8
  DESIGN DECISION: Transform all events to a consistent schema:
9
- - event: Socket.IO event name (always "claude_event")
9
+ - event: Socket.IO event name (always "mpm_event")
10
10
  - type: Main category (hook, system, session, file, connection)
11
11
  - subtype: Specific event type (pre_tool, heartbeat, started, etc.)
12
12
  - timestamp: ISO format timestamp
@@ -72,7 +72,7 @@ class NormalizedEvent:
72
72
  structure explicit and self-documenting.
73
73
  """
74
74
 
75
- event: str = "claude_event" # Socket.IO event name
75
+ event: str = "mpm_event" # Socket.IO event name
76
76
  source: str = "" # WHERE the event comes from
77
77
  type: str = "" # WHAT category of event
78
78
  subtype: str = "" # Specific event type
@@ -81,6 +81,8 @@ class NormalizedEvent:
81
81
  correlation_id: Optional[str] = (
82
82
  None # For correlating related events (e.g., pre_tool/post_tool)
83
83
  )
84
+ session_id: Optional[str] = None # Session identifier for stream grouping
85
+ cwd: Optional[str] = None # Working directory for project identification
84
86
 
85
87
  def to_dict(self) -> Dict[str, Any]:
86
88
  """Convert to dictionary for emission."""
@@ -95,6 +97,12 @@ class NormalizedEvent:
95
97
  # Include correlation_id if present
96
98
  if self.correlation_id:
97
99
  result["correlation_id"] = self.correlation_id
100
+ # Include session_id if present
101
+ if self.session_id:
102
+ result["session_id"] = self.session_id
103
+ # Include cwd if present
104
+ if self.cwd:
105
+ result["cwd"] = self.cwd
98
106
  return result
99
107
 
100
108
 
@@ -113,6 +121,7 @@ class EventNormalizer:
113
121
  "pre_response": (EventType.HOOK, "pre_response"),
114
122
  "post_response": (EventType.HOOK, "post_response"),
115
123
  "hook_event": (EventType.HOOK, "generic"),
124
+ "hook_execution": (EventType.HOOK, "execution"), # Hook execution metadata
116
125
  "UserPrompt": (EventType.HOOK, "user_prompt"), # Legacy format
117
126
  # Test events (legacy format)
118
127
  "TestStart": (EventType.TEST, "start"),
@@ -225,20 +234,32 @@ class EventNormalizer:
225
234
  # Get or generate timestamp
226
235
  timestamp = self._extract_timestamp(event_data)
227
236
 
228
- # Extract correlation_id if present
237
+ # Extract correlation_id, session_id, and cwd if present
229
238
  correlation_id = None
239
+ session_id = None
240
+ cwd = None
230
241
  if isinstance(event_data, dict):
231
242
  correlation_id = event_data.get("correlation_id")
243
+ # Try both naming conventions for session_id
244
+ session_id = event_data.get("session_id") or event_data.get("sessionId")
245
+ # Try multiple field names for working directory
246
+ cwd = (
247
+ event_data.get("cwd")
248
+ or event_data.get("working_directory")
249
+ or event_data.get("workingDirectory")
250
+ )
232
251
 
233
252
  # Create normalized event
234
253
  normalized = NormalizedEvent(
235
- event="claude_event",
254
+ event="mpm_event",
236
255
  source=event_source,
237
256
  type=event_type,
238
257
  subtype=subtype,
239
258
  timestamp=timestamp,
240
259
  data=data,
241
260
  correlation_id=correlation_id,
261
+ session_id=session_id,
262
+ cwd=cwd,
242
263
  )
243
264
 
244
265
  self.stats["normalized"] += 1
@@ -252,7 +273,7 @@ class EventNormalizer:
252
273
 
253
274
  # Return a generic event on error
254
275
  return NormalizedEvent(
255
- event="claude_event",
276
+ event="mpm_event",
256
277
  source="system",
257
278
  type="unknown",
258
279
  subtype="error",
@@ -285,8 +306,16 @@ class EventNormalizer:
285
306
  # If source is not a valid EventSource value, keep it as-is
286
307
  pass
287
308
 
309
+ # Extract session_id and cwd, trying multiple naming conventions
310
+ session_id = event_data.get("session_id") or event_data.get("sessionId")
311
+ cwd = (
312
+ event_data.get("cwd")
313
+ or event_data.get("working_directory")
314
+ or event_data.get("workingDirectory")
315
+ )
316
+
288
317
  return NormalizedEvent(
289
- event="claude_event", # Always use standard event name
318
+ event="mpm_event", # Always use standard event name
290
319
  source=source,
291
320
  type=event_data.get("type", "unknown"),
292
321
  subtype=event_data.get("subtype", "generic"),
@@ -295,6 +324,8 @@ class EventNormalizer:
295
324
  ),
296
325
  data=event_data.get("data", {}),
297
326
  correlation_id=event_data.get("correlation_id"),
327
+ session_id=session_id,
328
+ cwd=cwd,
298
329
  )
299
330
 
300
331
  def _extract_event_info(self, event_data: Any) -> Tuple[str, str, Dict[str, Any]]:
@@ -118,7 +118,8 @@ class HookEventHandler(BaseEventHandler):
118
118
  self.server.active_sessions[session_id] = {
119
119
  "session_id": session_id,
120
120
  "start_time": datetime.now(timezone.utc).isoformat(),
121
- "agent": agent_type,
121
+ "current_agent": agent_type, # Current active agent
122
+ "agents": [agent_type], # All agents used in this session
122
123
  "status": ServiceState.RUNNING,
123
124
  "prompt": data.get("prompt", "")[:100], # First 100 chars
124
125
  "last_activity": datetime.now(timezone.utc).isoformat(),
@@ -169,7 +170,8 @@ class HookEventHandler(BaseEventHandler):
169
170
  self.server.active_sessions[session_id] = {
170
171
  "session_id": session_id,
171
172
  "start_time": datetime.now(timezone.utc).isoformat(),
172
- "agent": "pm", # Default to PM
173
+ "current_agent": "pm", # Current active agent
174
+ "agents": ["pm"], # All agents used in this session
173
175
  "status": ServiceState.RUNNING,
174
176
  "prompt": data.get("prompt_text", "")[:100],
175
177
  "working_directory": data.get("working_directory", ""),
@@ -200,11 +202,16 @@ class HookEventHandler(BaseEventHandler):
200
202
  # Update session with new agent
201
203
  if hasattr(self.server, "active_sessions"):
202
204
  if session_id in self.server.active_sessions:
203
- self.server.active_sessions[session_id]["agent"] = agent_type
204
- self.server.active_sessions[session_id]["status"] = "delegated"
205
- self.server.active_sessions[session_id]["last_activity"] = datetime.now(
206
- timezone.utc
207
- ).isoformat()
205
+ session = self.server.active_sessions[session_id]
206
+ session["current_agent"] = agent_type
207
+ session["status"] = "delegated"
208
+ session["last_activity"] = datetime.now(timezone.utc).isoformat()
209
+
210
+ # Add to agents list if not already present
211
+ if "agents" not in session:
212
+ session["agents"] = []
213
+ if agent_type not in session["agents"]:
214
+ session["agents"].append(agent_type)
208
215
 
209
216
  self.logger.debug(
210
217
  f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"