claude-mpm 5.4.55__py3-none-any.whl → 5.6.1__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.
Files changed (401) 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 +111 -686
  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 +46 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/hook_errors.py +60 -60
  15. claude_mpm/cli/commands/monitor.py +2 -2
  16. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  17. claude_mpm/cli/commands/run.py +35 -3
  18. claude_mpm/cli/commands/skills.py +166 -14
  19. claude_mpm/cli/executor.py +120 -16
  20. claude_mpm/cli/interactive/__init__.py +10 -0
  21. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  22. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  23. claude_mpm/cli/interactive/skill_selector.py +481 -0
  24. claude_mpm/cli/parsers/base_parser.py +76 -1
  25. claude_mpm/cli/parsers/commander_parser.py +83 -0
  26. claude_mpm/cli/parsers/run_parser.py +10 -0
  27. claude_mpm/cli/startup.py +276 -403
  28. claude_mpm/cli/startup_display.py +72 -5
  29. claude_mpm/cli/startup_logging.py +2 -2
  30. claude_mpm/cli/utils.py +7 -3
  31. claude_mpm/commander/__init__.py +72 -0
  32. claude_mpm/commander/adapters/__init__.py +31 -0
  33. claude_mpm/commander/adapters/base.py +191 -0
  34. claude_mpm/commander/adapters/claude_code.py +361 -0
  35. claude_mpm/commander/adapters/communication.py +366 -0
  36. claude_mpm/commander/api/__init__.py +16 -0
  37. claude_mpm/commander/api/app.py +105 -0
  38. claude_mpm/commander/api/errors.py +112 -0
  39. claude_mpm/commander/api/routes/__init__.py +8 -0
  40. claude_mpm/commander/api/routes/events.py +184 -0
  41. claude_mpm/commander/api/routes/inbox.py +171 -0
  42. claude_mpm/commander/api/routes/messages.py +148 -0
  43. claude_mpm/commander/api/routes/projects.py +271 -0
  44. claude_mpm/commander/api/routes/sessions.py +215 -0
  45. claude_mpm/commander/api/routes/work.py +260 -0
  46. claude_mpm/commander/api/schemas.py +182 -0
  47. claude_mpm/commander/chat/__init__.py +7 -0
  48. claude_mpm/commander/chat/cli.py +107 -0
  49. claude_mpm/commander/chat/commands.py +96 -0
  50. claude_mpm/commander/chat/repl.py +310 -0
  51. claude_mpm/commander/config.py +49 -0
  52. claude_mpm/commander/config_loader.py +115 -0
  53. claude_mpm/commander/daemon.py +398 -0
  54. claude_mpm/commander/events/__init__.py +26 -0
  55. claude_mpm/commander/events/manager.py +332 -0
  56. claude_mpm/commander/frameworks/__init__.py +12 -0
  57. claude_mpm/commander/frameworks/base.py +143 -0
  58. claude_mpm/commander/frameworks/claude_code.py +58 -0
  59. claude_mpm/commander/frameworks/mpm.py +62 -0
  60. claude_mpm/commander/inbox/__init__.py +16 -0
  61. claude_mpm/commander/inbox/dedup.py +128 -0
  62. claude_mpm/commander/inbox/inbox.py +224 -0
  63. claude_mpm/commander/inbox/models.py +70 -0
  64. claude_mpm/commander/instance_manager.py +337 -0
  65. claude_mpm/commander/llm/__init__.py +6 -0
  66. claude_mpm/commander/llm/openrouter_client.py +167 -0
  67. claude_mpm/commander/llm/summarizer.py +70 -0
  68. claude_mpm/commander/models/__init__.py +18 -0
  69. claude_mpm/commander/models/events.py +121 -0
  70. claude_mpm/commander/models/project.py +162 -0
  71. claude_mpm/commander/models/work.py +214 -0
  72. claude_mpm/commander/parsing/__init__.py +20 -0
  73. claude_mpm/commander/parsing/extractor.py +132 -0
  74. claude_mpm/commander/parsing/output_parser.py +270 -0
  75. claude_mpm/commander/parsing/patterns.py +100 -0
  76. claude_mpm/commander/persistence/__init__.py +11 -0
  77. claude_mpm/commander/persistence/event_store.py +274 -0
  78. claude_mpm/commander/persistence/state_store.py +309 -0
  79. claude_mpm/commander/persistence/work_store.py +164 -0
  80. claude_mpm/commander/polling/__init__.py +13 -0
  81. claude_mpm/commander/polling/event_detector.py +104 -0
  82. claude_mpm/commander/polling/output_buffer.py +49 -0
  83. claude_mpm/commander/polling/output_poller.py +153 -0
  84. claude_mpm/commander/project_session.py +268 -0
  85. claude_mpm/commander/proxy/__init__.py +12 -0
  86. claude_mpm/commander/proxy/formatter.py +89 -0
  87. claude_mpm/commander/proxy/output_handler.py +191 -0
  88. claude_mpm/commander/proxy/relay.py +155 -0
  89. claude_mpm/commander/registry.py +404 -0
  90. claude_mpm/commander/runtime/__init__.py +10 -0
  91. claude_mpm/commander/runtime/executor.py +191 -0
  92. claude_mpm/commander/runtime/monitor.py +316 -0
  93. claude_mpm/commander/session/__init__.py +6 -0
  94. claude_mpm/commander/session/context.py +81 -0
  95. claude_mpm/commander/session/manager.py +59 -0
  96. claude_mpm/commander/tmux_orchestrator.py +361 -0
  97. claude_mpm/commander/web/__init__.py +1 -0
  98. claude_mpm/commander/work/__init__.py +30 -0
  99. claude_mpm/commander/work/executor.py +189 -0
  100. claude_mpm/commander/work/queue.py +405 -0
  101. claude_mpm/commander/workflow/__init__.py +27 -0
  102. claude_mpm/commander/workflow/event_handler.py +219 -0
  103. claude_mpm/commander/workflow/notifier.py +146 -0
  104. claude_mpm/commands/mpm-config.md +8 -0
  105. claude_mpm/commands/mpm-doctor.md +8 -0
  106. claude_mpm/commands/mpm-help.md +8 -0
  107. claude_mpm/commands/mpm-init.md +8 -0
  108. claude_mpm/commands/mpm-monitor.md +8 -0
  109. claude_mpm/commands/mpm-organize.md +8 -0
  110. claude_mpm/commands/mpm-postmortem.md +8 -0
  111. claude_mpm/commands/mpm-session-resume.md +9 -1
  112. claude_mpm/commands/mpm-status.md +8 -0
  113. claude_mpm/commands/mpm-ticket-view.md +8 -0
  114. claude_mpm/commands/mpm-version.md +8 -0
  115. claude_mpm/commands/mpm.md +8 -0
  116. claude_mpm/config/agent_presets.py +8 -7
  117. claude_mpm/constants.py +1 -0
  118. claude_mpm/core/claude_runner.py +2 -2
  119. claude_mpm/core/config.py +5 -0
  120. claude_mpm/core/hook_manager.py +51 -3
  121. claude_mpm/core/interactive_session.py +7 -7
  122. claude_mpm/core/logger.py +10 -7
  123. claude_mpm/core/logging_utils.py +4 -2
  124. claude_mpm/core/output_style_manager.py +31 -13
  125. claude_mpm/core/unified_config.py +54 -8
  126. claude_mpm/core/unified_paths.py +30 -13
  127. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  128. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  129. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  130. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  131. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  132. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  133. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  134. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  135. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  136. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  137. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  138. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  139. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  140. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  141. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  142. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  143. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  144. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  145. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  146. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  147. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  148. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  149. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  150. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  151. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  152. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  153. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  154. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  155. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  156. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  157. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  185. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  186. claude_mpm/experimental/cli_enhancements.py +2 -1
  187. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  188. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  189. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
  190. claude_mpm/hooks/claude_hooks/event_handlers.py +250 -11
  191. claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
  192. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  193. claude_mpm/hooks/claude_hooks/installer.py +69 -5
  194. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
  195. claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
  196. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
  197. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
  198. claude_mpm/hooks/session_resume_hook.py +85 -1
  199. claude_mpm/init.py +1 -1
  200. claude_mpm/scripts/claude-hook-handler.sh +36 -10
  201. claude_mpm/scripts/start_activity_logging.py +0 -0
  202. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  203. claude_mpm/services/agents/cache_git_manager.py +1 -1
  204. claude_mpm/services/agents/deployment/agent_template_builder.py +8 -0
  205. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  206. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  207. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  208. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  209. claude_mpm/services/agents/sources/git_source_sync_service.py +7 -4
  210. claude_mpm/services/agents/startup_sync.py +5 -2
  211. claude_mpm/services/cli/__init__.py +3 -0
  212. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  213. claude_mpm/services/cli/session_resume_helper.py +10 -2
  214. claude_mpm/services/delegation_detector.py +175 -0
  215. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  216. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  217. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  218. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  219. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  220. claude_mpm/services/diagnostics/models.py +14 -1
  221. claude_mpm/services/event_log.py +325 -0
  222. claude_mpm/services/infrastructure/__init__.py +4 -0
  223. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  224. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  225. claude_mpm/services/monitor/daemon_manager.py +15 -4
  226. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  227. claude_mpm/services/monitor/server.py +106 -16
  228. claude_mpm/services/pm_skills_deployer.py +261 -85
  229. claude_mpm/services/skills/git_skill_source_manager.py +75 -10
  230. claude_mpm/services/skills/selective_skill_deployer.py +177 -80
  231. claude_mpm/services/skills/skill_discovery_service.py +57 -3
  232. claude_mpm/services/socketio/handlers/hook.py +14 -7
  233. claude_mpm/services/socketio/server/main.py +12 -4
  234. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  235. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  236. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  237. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  238. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  239. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  240. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  241. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  242. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  243. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  244. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  245. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  246. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  247. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  248. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  249. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  250. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  251. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  252. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  253. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  254. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  255. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  256. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  257. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  258. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  259. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  260. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  261. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  262. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  263. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  264. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  265. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  266. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  267. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  268. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  269. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  270. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  271. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  272. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  273. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  274. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  275. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  276. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  277. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  278. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  279. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  280. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  281. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  282. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  283. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  284. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  285. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  286. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  287. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  288. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  289. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  290. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  291. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  292. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  293. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  294. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  295. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  296. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  297. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  298. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  299. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  300. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  301. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  302. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  303. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  304. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  305. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  306. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  307. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  308. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  309. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  310. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  311. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  312. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  313. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  314. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  315. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  316. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  317. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  318. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  319. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  320. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  321. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  322. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  323. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  324. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  325. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  326. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  327. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  328. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  329. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  330. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  331. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  332. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  333. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  334. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  335. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  336. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  337. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  338. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  339. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  340. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  341. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  342. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  343. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  344. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  345. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  346. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  347. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  348. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  349. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  350. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  351. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  352. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  353. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  354. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  355. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  356. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  357. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  358. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  359. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  360. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  361. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  362. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  363. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  364. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  365. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  366. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  367. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  368. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  369. claude_mpm/skills/skill_manager.py +4 -4
  370. claude_mpm/utils/agent_dependency_loader.py +103 -4
  371. claude_mpm/utils/robust_installer.py +45 -24
  372. claude_mpm-5.6.1.dist-info/METADATA +391 -0
  373. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/RECORD +377 -166
  374. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  375. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  376. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  377. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  378. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  379. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  380. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  381. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  382. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  383. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  384. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  385. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  386. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  387. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  388. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  389. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  390. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  391. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  392. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  393. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  394. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  395. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  396. claude_mpm-5.4.55.dist-info/METADATA +0 -999
  397. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/WHEEL +0 -0
  398. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/entry_points.txt +0 -0
  399. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE +0 -0
  400. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  401. {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/top_level.txt +0 -0
@@ -682,7 +682,7 @@ class GitSkillSourceManager:
682
682
  try:
683
683
  with open(etag_cache_file, encoding="utf-8") as f:
684
684
  etag_cache = json.load(f)
685
- except Exception:
685
+ except Exception: # nosec B110 - intentional: proceed without cache on read failure
686
686
  pass
687
687
 
688
688
  cached_etag = etag_cache.get(str(local_path))
@@ -991,12 +991,17 @@ class GitSkillSourceManager:
991
991
  progress_callback=None,
992
992
  skill_filter: Optional[Set[str]] = None,
993
993
  ) -> Dict[str, Any]:
994
- """Deploy skills from cache to target directory with flat structure.
994
+ """Deploy skills from cache to target directory with flat structure and automatic cleanup.
995
995
 
996
996
  Flattens nested Git repository structure into Claude Code compatible
997
997
  flat directory structure. Each skill directory is copied with a
998
998
  hyphen-separated name derived from its path.
999
999
 
1000
+ CRITICAL: When skill_filter is provided (agent-referenced skills), this function:
1001
+ 1. Deploys ONLY the filtered skills
1002
+ 2. REMOVES orphaned skills (deployed but not in filter)
1003
+ 3. Returns removed_count and removed_skills in result
1004
+
1000
1005
  Transformation Example:
1001
1006
  Cache: collaboration/dispatching-parallel-agents/SKILL.md
1002
1007
  Deploy: collaboration-dispatching-parallel-agents/SKILL.md
@@ -1006,8 +1011,8 @@ class GitSkillSourceManager:
1006
1011
  force: Overwrite existing skills
1007
1012
  progress_callback: Optional callback(increment: int) called for each skill deployed
1008
1013
  skill_filter: Optional set of skill names to deploy (selective deployment).
1009
- If None, deploys all skills. If provided, only deploys skills
1010
- whose name matches an entry in the filter set.
1014
+ If None, deploys ALL skills WITHOUT cleanup.
1015
+ If provided, deploys ONLY filtered skills AND removes orphans.
1011
1016
 
1012
1017
  Returns:
1013
1018
  Dict with deployment results:
@@ -1018,7 +1023,9 @@ class GitSkillSourceManager:
1018
1023
  "deployed_skills": List[str],
1019
1024
  "skipped_skills": List[str],
1020
1025
  "errors": List[str],
1021
- "filtered_count": int # Number of skills filtered out
1026
+ "filtered_count": int, # Number of skills filtered out
1027
+ "removed_count": int, # Number of orphaned skills removed
1028
+ "removed_skills": List[str] # Names of removed orphaned skills
1022
1029
  }
1023
1030
 
1024
1031
  Example:
@@ -1026,10 +1033,10 @@ class GitSkillSourceManager:
1026
1033
  >>> result = manager.deploy_skills()
1027
1034
  >>> print(f"Deployed {result['deployed_count']} skills")
1028
1035
 
1029
- # Selective deployment based on agent requirements:
1036
+ # Selective deployment based on agent requirements (with cleanup):
1030
1037
  >>> required = {"typescript-core", "react-patterns"}
1031
1038
  >>> result = manager.deploy_skills(skill_filter=required)
1032
- >>> print(f"Deployed {result['deployed_count']} of {len(required)} required skills")
1039
+ >>> print(f"Deployed {result['deployed_count']}, removed {result['removed_count']} orphans")
1033
1040
  """
1034
1041
  if target_dir is None:
1035
1042
  target_dir = Path.home() / ".claude" / "skills"
@@ -1040,6 +1047,7 @@ class GitSkillSourceManager:
1040
1047
  skipped = []
1041
1048
  errors = []
1042
1049
  filtered_count = 0
1050
+ removed_skills = [] # Track removed orphaned skills
1043
1051
 
1044
1052
  # Get all skills from all sources
1045
1053
  all_skills = self.get_all_skills()
@@ -1082,11 +1090,16 @@ class GitSkillSourceManager:
1082
1090
  )
1083
1091
 
1084
1092
  # Cleanup: Remove skills from target directory that aren't in the filtered set
1085
- # This ensures only the skills in the profile are deployed
1093
+ # This ensures only agent-referenced skills remain deployed
1086
1094
  removed_skills = self._cleanup_unfiltered_skills(target_dir, all_skills)
1087
1095
  if removed_skills:
1088
1096
  self.logger.info(
1089
- f"Removed {len(removed_skills)} skills not in profile filter: {removed_skills}"
1097
+ f"Removed {len(removed_skills)} orphaned skills not referenced by agents: {removed_skills[:10]}"
1098
+ + (
1099
+ f" (and {len(removed_skills) - 10} more)"
1100
+ if len(removed_skills) > 10
1101
+ else ""
1102
+ )
1090
1103
  )
1091
1104
 
1092
1105
  self.logger.info(
@@ -1130,6 +1143,7 @@ class GitSkillSourceManager:
1130
1143
  self.logger.info(
1131
1144
  f"Deployment complete: {len(deployed)} deployed, "
1132
1145
  f"{len(skipped)} skipped, {len(errors)} errors"
1146
+ + (f", {len(removed_skills)} removed" if removed_skills else "")
1133
1147
  )
1134
1148
 
1135
1149
  return {
@@ -1140,6 +1154,8 @@ class GitSkillSourceManager:
1140
1154
  "skipped_skills": skipped,
1141
1155
  "errors": errors,
1142
1156
  "filtered_count": filtered_count,
1157
+ "removed_count": len(removed_skills),
1158
+ "removed_skills": removed_skills,
1143
1159
  }
1144
1160
 
1145
1161
  def _cleanup_unfiltered_skills(
@@ -1147,6 +1163,10 @@ class GitSkillSourceManager:
1147
1163
  ) -> List[str]:
1148
1164
  """Remove skills from target directory that aren't in the filtered skill list.
1149
1165
 
1166
+ CRITICAL: Only removes MPM-managed skills (those in our cache). Custom user skills
1167
+ are preserved. This prevents accidental deletion of user-created skills that were
1168
+ never part of MPM's skill repository.
1169
+
1150
1170
  Uses fuzzy matching to handle both exact deployment names and short skill names.
1151
1171
  For example:
1152
1172
  - "toolchains-python-frameworks-flask" (deployed dir) matches "flask" (filter)
@@ -1197,6 +1217,40 @@ class GitSkillSourceManager:
1197
1217
 
1198
1218
  return False
1199
1219
 
1220
+ def is_mpm_managed_skill(skill_dir_name: str) -> bool:
1221
+ """Check if skill is managed by MPM (exists in our cache).
1222
+
1223
+ Custom user skills (not in cache) are NEVER deleted, even if not in filter.
1224
+ Only MPM-managed skills (in cache but not in filter) are candidates for removal.
1225
+
1226
+ Args:
1227
+ skill_dir_name: Name of deployed skill directory
1228
+
1229
+ Returns:
1230
+ True if skill exists in MPM cache (MPM-managed), False if custom user skill
1231
+ """
1232
+ # Check all configured skill sources for this skill
1233
+ for source in self.config.get_enabled_sources():
1234
+ cache_path = self._get_source_cache_path(source)
1235
+ if not cache_path.exists():
1236
+ continue
1237
+
1238
+ # Check if this skill directory exists anywhere in the cache
1239
+ # Use glob to find matching directories recursively
1240
+ matches = list(cache_path.rglob(f"*{skill_dir_name}*"))
1241
+ if matches:
1242
+ # Found in cache - this is MPM-managed
1243
+ self.logger.debug(
1244
+ f"Skill '{skill_dir_name}' found in cache at {matches[0]} - MPM-managed"
1245
+ )
1246
+ return True
1247
+
1248
+ # Not found in any cache - this is a custom user skill
1249
+ self.logger.debug(
1250
+ f"Skill '{skill_dir_name}' not found in cache - custom user skill, preserving"
1251
+ )
1252
+ return False
1253
+
1200
1254
  # Check each directory in target_dir
1201
1255
  if not target_dir.exists():
1202
1256
  return removed_skills
@@ -1213,6 +1267,15 @@ class GitSkillSourceManager:
1213
1267
 
1214
1268
  # Check if this skill directory should be kept (fuzzy matching)
1215
1269
  if not should_keep_skill(item.name):
1270
+ # CRITICAL: Check if this is an MPM-managed skill before deletion
1271
+ if not is_mpm_managed_skill(item.name):
1272
+ # This is a custom user skill - NEVER delete
1273
+ self.logger.debug(
1274
+ f"Preserving custom user skill (not in MPM cache): {item.name}"
1275
+ )
1276
+ continue
1277
+
1278
+ # It's MPM-managed but not in filter - safe to remove
1216
1279
  try:
1217
1280
  # Security: Validate path is within target_dir
1218
1281
  if not self._validate_safe_path(target_dir, item):
@@ -1228,7 +1291,9 @@ class GitSkillSourceManager:
1228
1291
  shutil.rmtree(item)
1229
1292
 
1230
1293
  removed_skills.append(item.name)
1231
- self.logger.info(f"Removed orphaned skill: {item.name}")
1294
+ self.logger.info(
1295
+ f"Removed orphaned MPM-managed skill: {item.name}"
1296
+ )
1232
1297
 
1233
1298
  except Exception as e:
1234
1299
  self.logger.warning(
@@ -44,13 +44,56 @@ from typing import Any, Dict, List, Set, Tuple
44
44
  import yaml
45
45
 
46
46
  from claude_mpm.core.logging_config import get_logger
47
- from claude_mpm.services.skills.skill_to_agent_mapper import SkillToAgentMapper
48
47
 
49
48
  logger = get_logger(__name__)
50
49
 
51
50
  # Deployment tracking index file
52
51
  DEPLOYED_INDEX_FILE = ".mpm-deployed-skills.json"
53
52
 
53
+ # Core skills that are universally useful across all projects
54
+ # These are deployed when skill mapping returns too many skills (>60)
55
+ # Target: ~25-30 core skills for balanced functionality
56
+ CORE_SKILLS = {
57
+ # Universal debugging and verification (4 skills)
58
+ "universal-debugging-systematic-debugging",
59
+ "universal-debugging-verification-before-completion",
60
+ "universal-verification-pre-merge",
61
+ "universal-verification-screenshot",
62
+ # Universal testing patterns (2 skills)
63
+ "universal-testing-test-driven-development",
64
+ "universal-testing-testing-anti-patterns",
65
+ # Universal architecture and design (1 skill)
66
+ "universal-architecture-software-patterns",
67
+ # Universal infrastructure (3 skills)
68
+ "universal-infrastructure-env-manager",
69
+ "universal-infrastructure-docker",
70
+ "universal-infrastructure-github-actions",
71
+ # Universal collaboration (1 skill)
72
+ "universal-collaboration-stacked-prs",
73
+ # Universal emergency/operations (1 skill)
74
+ "toolchains-universal-emergency-release",
75
+ "toolchains-universal-dependency-audit",
76
+ # Common language toolchains (6 skills)
77
+ "toolchains-typescript-core",
78
+ "toolchains-python-core",
79
+ "toolchains-javascript-tooling-biome",
80
+ "toolchains-python-tooling-mypy",
81
+ "toolchains-typescript-testing-vitest",
82
+ "toolchains-python-frameworks-flask",
83
+ # Common web frameworks (4 skills)
84
+ "toolchains-javascript-frameworks-nextjs",
85
+ "toolchains-nextjs-core",
86
+ "toolchains-typescript-frameworks-nodejs-backend",
87
+ "toolchains-javascript-frameworks-react-state-machine",
88
+ # Common testing tools (2 skills)
89
+ "toolchains-javascript-testing-playwright",
90
+ "toolchains-typescript-testing-jest",
91
+ # Common data/UI tools (3 skills)
92
+ "universal-data-xlsx",
93
+ "toolchains-ui-styling-tailwind",
94
+ "toolchains-ui-components-headlessui",
95
+ }
96
+
54
97
 
55
98
  def parse_agent_frontmatter(agent_file: Path) -> Dict[str, Any]:
56
99
  """Parse YAML frontmatter from agent markdown file.
@@ -140,22 +183,14 @@ def get_skills_from_agent(frontmatter: Dict[str, Any]) -> Set[str]:
140
183
  def get_skills_from_mapping(agent_ids: List[str]) -> Set[str]:
141
184
  """Get skills for agents using SkillToAgentMapper inference.
142
185
 
143
- Uses SkillToAgentMapper to find all skills associated with given agent IDs.
144
- This provides pattern-based skill discovery beyond explicit frontmatter declarations.
145
-
146
- CRITICAL DESIGN DECISION: This function ONLY returns skills for the DEPLOYED agents
147
- provided in agent_ids. It does NOT return skills for all agents in the mapping
148
- configuration (skill_to_agent_mapping.yaml lists 41 agents, but only 33 may be deployed).
186
+ DEPRECATED: This function is deprecated as of Phase 3 refactor.
187
+ Skills are now declared exclusively in agent frontmatter.
149
188
 
150
- GENERIC AGENT HANDLING: The generic "engineer" agent is mapped to 100+ skills in the
151
- configuration because it's designed as a fallback. To prevent over-deployment when
152
- specialized agents exist, we skip "engineer" if specialized agents are present.
189
+ The static skill_to_agent_mapping.yaml is no longer used for skill deployment.
190
+ Each agent must declare its skills in frontmatter or it gets zero skills.
153
191
 
154
- WHY THIS MATTERS:
155
- - skill_to_agent_mapping.yaml lists ALL possible agents (41 total)
156
- - User may only have 33 agents deployed in ~/.claude/agents/
157
- - Without filtering, we'd deploy skills for all 41 agents (over-deployment)
158
- - Solution: Only query skills for DEPLOYED agents (passed in agent_ids)
192
+ This function remains for backward compatibility but is NO LONGER CALLED
193
+ by get_required_skills_from_agents().
159
194
 
160
195
  Args:
161
196
  agent_ids: List of DEPLOYED agent identifiers (e.g., ["python-engineer", "typescript-engineer"])
@@ -163,67 +198,106 @@ def get_skills_from_mapping(agent_ids: List[str]) -> Set[str]:
163
198
 
164
199
  Returns:
165
200
  Set of unique skill names inferred from mapping configuration for DEPLOYED agents only
201
+ NOTE: This is now an empty set as the function is deprecated.
166
202
 
167
203
  Example:
168
- >>> # DEPLOYED agents only (from ~/.claude/agents/)
204
+ >>> # DEPRECATED - use frontmatter instead
169
205
  >>> deployed_agent_ids = ["python-engineer", "typescript-engineer", "qa"]
170
- >>> skills = get_skills_from_mapping(deployed_agent_ids)
171
- >>> print(f"Found {len(skills)} skills for {len(deployed_agent_ids)} deployed agents")
206
+ >>> skills = get_skills_from_mapping(deployed_agent_ids) # Returns empty set
172
207
  """
173
- try:
174
- mapper = SkillToAgentMapper()
175
- all_skills = set()
176
-
177
- # CRITICAL FIX: Skip generic "engineer" agent if specialized agents exist
178
- # The "engineer" agent is mapped to ~107 skills (almost all skills) because
179
- # it's a fallback agent. This causes over-deployment when you have specialized
180
- # agents like "python-engineer", "typescript-engineer", etc.
181
- #
182
- # Solution: Filter out "engineer" from agent_ids if specialized agents exist
183
- specialized_engineers = [
184
- aid for aid in agent_ids if aid.endswith("-engineer") and aid != "engineer"
185
- ]
186
-
187
- # If specialized engineers exist, exclude generic "engineer" from skill mapping
188
- # This prevents deploying 100+ skills when only a subset is needed
189
- agents_to_query = agent_ids
190
- if specialized_engineers and "engineer" in agent_ids:
191
- agents_to_query = [aid for aid in agent_ids if aid != "engineer"]
192
- logger.info(
193
- f"Excluding generic 'engineer' agent from skill mapping "
194
- f"(found {len(specialized_engineers)} specialized engineers: "
195
- f"{', '.join(specialized_engineers[:5])}{'...' if len(specialized_engineers) > 5 else ''})"
196
- )
208
+ # DEPRECATED: Return empty set
209
+ logger.warning(
210
+ "get_skills_from_mapping() is DEPRECATED and returns empty set. "
211
+ "Skills are now declared in agent frontmatter only. "
212
+ "Update your agents with 'skills:' field in frontmatter."
213
+ )
214
+ return set()
197
215
 
198
- # IMPORTANT: Only query skills for DEPLOYED agents (those in agent_ids)
199
- # Do NOT query all agents from skill_to_agent_mapping.yaml (that's 41 agents)
200
- for agent_id in agents_to_query:
201
- agent_skills = mapper.get_skills_for_agent(agent_id)
202
- if agent_skills:
203
- all_skills.update(agent_skills)
204
- logger.debug(f"Mapped {len(agent_skills)} skills to {agent_id}")
205
216
 
206
- logger.info(
207
- f"Mapped {len(all_skills)} unique skills for {len(agents_to_query)} deployed agents "
208
- f"(out of {len(agent_ids)} total deployed, excluding generic 'engineer' if specialized exist)"
209
- )
210
- return all_skills
217
+ def extract_skills_from_content(agent_file: Path) -> Set[str]:
218
+ """Extract skill names from [SKILL: skill-name] markers in agent file content.
219
+
220
+ This function complements frontmatter skill extraction by finding inline
221
+ skill references in the agent's markdown content body.
222
+
223
+ Supports multiple formats:
224
+ - Bold marker: **[SKILL: skill-name]**
225
+ - Plain marker: [SKILL: skill-name]
226
+ - Backtick list: - `skill-name` - Description
227
+ - With spaces: [SKILL: skill-name ]
211
228
 
229
+ Args:
230
+ agent_file: Path to agent markdown file
231
+
232
+ Returns:
233
+ Set of skill names found in content body
234
+
235
+ Example:
236
+ >>> skills = extract_skills_from_content(Path("pm.md"))
237
+ >>> # Finds skills from markers like **[SKILL: mpm-delegation-patterns]**
238
+ >>> # Also finds from lists like - `mpm-teaching-mode` - Description
239
+ >>> print(f"Found {len(skills)} skills in content")
240
+ """
241
+ try:
242
+ content = agent_file.read_text(encoding="utf-8")
212
243
  except Exception as e:
213
- logger.warning(f"Failed to load SkillToAgentMapper: {e}")
214
- logger.info("Falling back to frontmatter-only skill discovery")
244
+ logger.warning(f"Failed to read {agent_file}: {e}")
215
245
  return set()
216
246
 
247
+ skills = set()
248
+
249
+ # Pattern 1: [SKILL: skill-name] markers (with optional markdown bold)
250
+ # Handles: **[SKILL: skill-name]** or [SKILL: skill-name]
251
+ # Pattern breakdown:
252
+ # - \*{0,2}: Optional bold markdown (0-2 asterisks)
253
+ # - \[SKILL:\s*: Opening bracket with optional whitespace
254
+ # - ([a-zA-Z0-9_-]+): Skill name (capture group)
255
+ # - \s*\]: Closing bracket with optional whitespace
256
+ # - \*{0,2}: Optional closing bold markdown
257
+ pattern1 = r"\*{0,2}\[SKILL:\s*([a-zA-Z0-9_-]+)\s*\]\*{0,2}"
258
+ matches1 = re.findall(pattern1, content, re.IGNORECASE)
259
+ skills.update(matches1)
260
+
261
+ # Pattern 2: Backtick list items with mpm-* or toolchains-* skills
262
+ # Handles: - `mpm-skill-name` - Description
263
+ # Pattern breakdown:
264
+ # - ^-\s+: Start with dash and whitespace (list item)
265
+ # - `: Opening backtick
266
+ # - ((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+): Skill name starting with prefix
267
+ # - `: Closing backtick
268
+ # - \s+-: Followed by whitespace and dash (description separator)
269
+ pattern2 = r"^-\s+`((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+)`\s+-"
270
+ matches2 = re.findall(pattern2, content, re.MULTILINE | re.IGNORECASE)
271
+ skills.update(matches2)
272
+
273
+ if skills:
274
+ logger.debug(
275
+ f"Found {len(skills)} skills from content markers in {agent_file.name}"
276
+ )
277
+
278
+ return skills
279
+
217
280
 
218
281
  def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
219
282
  """Extract all skills referenced by deployed agents.
220
283
 
221
- Combines skills from two sources:
222
- 1. Explicit frontmatter declarations (skills: field in agent .md files)
223
- 2. SkillToAgentMapper inference (pattern-based skill discovery)
284
+ MAJOR CHANGE (Phase 3): Now uses TWO sources for skill discovery:
285
+ 1. Frontmatter-declared skills (skills: field)
286
+ 2. Content body markers ([SKILL: skill-name])
287
+
288
+ The static skill_to_agent_mapping.yaml is DEPRECATED. Each agent must
289
+ declare its skills via frontmatter OR inline markers.
224
290
 
225
- This dual-source approach ensures agents get both explicitly declared skills
226
- and skills inferred from their domain/toolchain patterns.
291
+ This change:
292
+ - Eliminates dual-source complexity (frontmatter + mapping)
293
+ - Makes skill requirements explicit per agent
294
+ - Enables per-agent customization via frontmatter or inline markers
295
+ - Removes dependency on static YAML mapping
296
+ - Fixes PM skills being removed as orphaned (they use inline markers)
297
+
298
+ Special handling for PM_INSTRUCTIONS.md:
299
+ - Also scans .claude-mpm/PM_INSTRUCTIONS.md for skill markers
300
+ - PM instructions are not in agents_dir but contain [SKILL: ...] references
227
301
 
228
302
  Args:
229
303
  agents_dir: Path to deployed agents directory (e.g., .claude/agents/)
@@ -242,43 +316,66 @@ def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
242
316
 
243
317
  # Scan all agent markdown files
244
318
  agent_files = list(agents_dir.glob("*.md"))
245
- logger.debug(f"Scanning {len(agent_files)} agent files in {agents_dir}")
246
319
 
247
- # Source 1: Extract skills from frontmatter
320
+ # Special case: Add PM_INSTRUCTIONS.md if it exists
321
+ # PM instructions live in .claude-mpm/ not .claude/agents/
322
+ pm_instructions = agents_dir.parent.parent / ".claude-mpm" / "PM_INSTRUCTIONS.md"
323
+ if pm_instructions.exists():
324
+ agent_files.append(pm_instructions)
325
+ logger.debug("Added PM_INSTRUCTIONS.md for skill scanning")
326
+
327
+ logger.debug(f"Scanning {len(agent_files)} agent files (including PM instructions)")
328
+
329
+ # Use TWO sources: frontmatter AND content markers
248
330
  frontmatter_skills = set()
249
- agent_ids = []
331
+ content_skills = set()
250
332
 
251
333
  for agent_file in agent_files:
252
334
  agent_id = agent_file.stem
253
- agent_ids.append(agent_id)
254
335
 
336
+ # Source 1: Extract from frontmatter
255
337
  frontmatter = parse_agent_frontmatter(agent_file)
256
- agent_skills = get_skills_from_agent(frontmatter)
338
+ agent_fm_skills = get_skills_from_agent(frontmatter)
257
339
 
258
- if agent_skills:
259
- frontmatter_skills.update(agent_skills)
340
+ if agent_fm_skills:
341
+ frontmatter_skills.update(agent_fm_skills)
260
342
  logger.debug(
261
- f"Agent {agent_id}: {len(agent_skills)} skills from frontmatter"
343
+ f"Agent {agent_id}: {len(agent_fm_skills)} skills from frontmatter"
262
344
  )
263
345
 
264
- logger.info(f"Found {len(frontmatter_skills)} unique skills from frontmatter")
346
+ # Source 2: Extract from content body [SKILL: ...] markers
347
+ agent_content_skills = extract_skills_from_content(agent_file)
348
+
349
+ if agent_content_skills:
350
+ content_skills.update(agent_content_skills)
351
+ logger.debug(
352
+ f"Agent {agent_id}: {len(agent_content_skills)} skills from content markers"
353
+ )
265
354
 
266
- # Source 2: Get skills from SkillToAgentMapper
267
- mapped_skills = get_skills_from_mapping(agent_ids)
355
+ if not agent_fm_skills and not agent_content_skills:
356
+ logger.debug(
357
+ f"Agent {agent_id}: No skills declared (checked frontmatter + content)"
358
+ )
268
359
 
269
360
  # Combine both sources
270
- required_skills = frontmatter_skills | mapped_skills
271
-
272
- # Normalize skill paths: convert slashes to dashes for compatibility with deployment
273
- # SkillToAgentMapper returns paths like "toolchains/python/frameworks/django"
274
- # but deployment expects "toolchains-python-frameworks-django"
275
- normalized_skills = {skill.replace("/", "-") for skill in required_skills}
361
+ all_skills = frontmatter_skills | content_skills
276
362
 
277
363
  logger.info(
278
- f"Combined {len(frontmatter_skills)} frontmatter + {len(mapped_skills)} mapped "
279
- f"= {len(required_skills)} total unique skills (normalized to {len(normalized_skills)})"
364
+ f"Found {len(all_skills)} unique skills "
365
+ f"({len(frontmatter_skills)} from frontmatter, "
366
+ f"{len(content_skills)} from content markers)"
280
367
  )
281
368
 
369
+ # Normalize skill paths: convert slashes to dashes for compatibility with deployment
370
+ # Some skills may use slash format, normalize to dashes
371
+ normalized_skills = {skill.replace("/", "-") for skill in all_skills}
372
+
373
+ if normalized_skills != all_skills:
374
+ logger.debug(
375
+ f"Normalized {len(all_skills)} skills to {len(normalized_skills)} "
376
+ "(converted slashes to dashes)"
377
+ )
378
+
282
379
  return normalized_skills
283
380
 
284
381
 
@@ -163,10 +163,22 @@ class SkillDiscoveryService:
163
163
  skill_md_files = list(self.skills_dir.rglob("SKILL.md"))
164
164
 
165
165
  # Also find legacy *.md files in top-level directory for backward compatibility
166
+ # Exclude common non-skill documentation files
167
+ excluded_filenames = {
168
+ "skill.md", # Case variations of SKILL.md
169
+ "readme.md",
170
+ "claude.md",
171
+ "contributing.md",
172
+ "changelog.md",
173
+ "license.md",
174
+ "authors.md",
175
+ "code_of_conduct.md",
176
+ }
177
+
166
178
  legacy_md_files = [
167
179
  f
168
180
  for f in self.skills_dir.glob("*.md")
169
- if f.name != "SKILL.md" and f.name.lower() != "readme.md"
181
+ if f.name.lower() not in excluded_filenames
170
182
  ]
171
183
 
172
184
  all_skill_files = skill_md_files + legacy_md_files
@@ -255,7 +267,35 @@ class SkillDiscoveryService:
255
267
  try:
256
268
  frontmatter, body = self._extract_frontmatter(content)
257
269
  except Exception as e:
258
- self.logger.warning(f"No valid frontmatter in {skill_file.name}: {e}")
270
+ # Only log as debug for documentation files to reduce noise
271
+ # Common documentation files (CLAUDE.md, README.md) are expected to lack skill frontmatter
272
+ relative_path = (
273
+ skill_file.relative_to(self.skills_dir)
274
+ if skill_file.is_relative_to(self.skills_dir)
275
+ else skill_file
276
+ )
277
+
278
+ # Check if this looks like a documentation file
279
+ is_documentation = any(
280
+ doc_pattern in skill_file.name.lower()
281
+ for doc_pattern in [
282
+ "readme",
283
+ "claude",
284
+ "contributing",
285
+ "changelog",
286
+ "license",
287
+ ]
288
+ )
289
+
290
+ if is_documentation:
291
+ self.logger.debug(
292
+ f"Skipping documentation file {relative_path} (no skill frontmatter): {e}"
293
+ )
294
+ else:
295
+ # For actual skill files with invalid YAML, use warning level
296
+ self.logger.warning(
297
+ f"Failed to parse skill frontmatter in {relative_path}: {e}"
298
+ )
259
299
  return None
260
300
 
261
301
  # Validate required fields
@@ -354,10 +394,24 @@ class SkillDiscoveryService:
354
394
  frontmatter_text = match.group(1)
355
395
  body = match.group(2)
356
396
 
357
- # Parse YAML
397
+ # Parse YAML with improved error handling
358
398
  try:
359
399
  frontmatter = yaml.safe_load(frontmatter_text)
360
400
  except yaml.YAMLError as e:
401
+ # Provide more specific error message with context
402
+ error_line = getattr(e, "problem_mark", None)
403
+ if error_line:
404
+ line_num = error_line.line + 1
405
+ col_num = error_line.column + 1
406
+ # Extract problematic line for context
407
+ lines = frontmatter_text.split("\n")
408
+ problem_line = (
409
+ lines[error_line.line] if error_line.line < len(lines) else ""
410
+ )
411
+ raise ValueError(
412
+ f"Invalid YAML in frontmatter at line {line_num}, column {col_num}: {e.problem}\n"
413
+ f" Problematic line: {problem_line.strip()}"
414
+ ) from e
361
415
  raise ValueError(f"Invalid YAML in frontmatter: {e}") from e
362
416
 
363
417
  if not isinstance(frontmatter, dict):
@@ -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}"