claude-mpm 3.9.11__py3-none-any.whl → 4.0.3__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 (419) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +1 -1
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +79 -51
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +20 -20
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +140 -905
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1156
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +71 -73
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +35 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +233 -199
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +30 -13
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
  298. claude_mpm/services/mcp_gateway/main.py +287 -137
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +19 -533
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +2 -2
  358. claude_mpm/storage/state_storage.py +177 -181
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/cli/commands/run_guarded.py +0 -511
  385. claude_mpm/config/memory_guardian_config.py +0 -325
  386. claude_mpm/config/memory_guardian_yaml.py +0 -335
  387. claude_mpm/core/config_paths.py +0 -150
  388. claude_mpm/core/memory_aware_runner.py +0 -353
  389. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  390. claude_mpm/deployment_paths.py +0 -261
  391. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  392. claude_mpm/models/state_models.py +0 -433
  393. claude_mpm/services/agent/__init__.py +0 -24
  394. claude_mpm/services/agent/deployment.py +0 -2548
  395. claude_mpm/services/agent/management.py +0 -598
  396. claude_mpm/services/agent/registry.py +0 -813
  397. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  398. claude_mpm/services/communication/socketio.py +0 -1935
  399. claude_mpm/services/communication/websocket.py +0 -479
  400. claude_mpm/services/framework_claude_md_generator.py +0 -624
  401. claude_mpm/services/health_monitor.py +0 -893
  402. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  403. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  404. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  405. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  406. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  407. claude_mpm/services/infrastructure/state_manager.py +0 -774
  408. claude_mpm/services/mcp_gateway/manager.py +0 -334
  409. claude_mpm/services/optimized_hook_service.py +0 -542
  410. claude_mpm/services/project_analyzer.py +0 -864
  411. claude_mpm/services/project_registry.py +0 -608
  412. claude_mpm/services/standalone_socketio_server.py +0 -1300
  413. claude_mpm/services/ticket_manager_di.py +0 -318
  414. claude_mpm/services/ticketing_service_original.py +0 -510
  415. claude_mpm/utils/paths.py +0 -395
  416. claude_mpm/utils/platform_memory.py +0 -524
  417. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  418. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  419. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -1,33 +1,37 @@
1
1
  """Framework loader for Claude MPM."""
2
2
 
3
- import os
4
3
  import logging
5
- from pathlib import Path
6
- from typing import Optional, Dict, Any
4
+ import os
7
5
  from datetime import datetime
6
+ from pathlib import Path
7
+ from typing import Any, Dict, Optional
8
8
 
9
9
  from ..utils.imports import safe_import
10
10
 
11
11
  # Import with fallback support - using absolute imports as primary since we're at module level
12
- get_logger = safe_import('claude_mpm.core.logger', 'core.logger', ['get_logger'])
13
- AgentRegistryAdapter = safe_import('claude_mpm.core.agent_registry', 'core.agent_registry', ['AgentRegistryAdapter'])
12
+ get_logger = safe_import("claude_mpm.core.logger", "core.logger", ["get_logger"])
13
+ AgentRegistryAdapter = safe_import(
14
+ "claude_mpm.core.agent_registry", "core.agent_registry", ["AgentRegistryAdapter"]
15
+ )
14
16
 
15
17
 
16
18
  class FrameworkLoader:
17
19
  """
18
20
  Load and prepare framework instructions for injection.
19
-
21
+
20
22
  This component handles:
21
23
  1. Finding the framework (claude-multiagent-pm)
22
24
  2. Loading INSTRUCTIONS.md instructions
23
25
  3. Preparing agent definitions
24
26
  4. Formatting for injection
25
27
  """
26
-
27
- def __init__(self, framework_path: Optional[Path] = None, agents_dir: Optional[Path] = None):
28
+
29
+ def __init__(
30
+ self, framework_path: Optional[Path] = None, agents_dir: Optional[Path] = None
31
+ ):
28
32
  """
29
33
  Initialize framework loader.
30
-
34
+
31
35
  Args:
32
36
  framework_path: Explicit path to framework (auto-detected if None)
33
37
  agents_dir: Custom agents directory (overrides framework agents)
@@ -38,10 +42,10 @@ class FrameworkLoader:
38
42
  self.framework_version = None
39
43
  self.framework_last_modified = None
40
44
  self.framework_content = self._load_framework_content()
41
-
45
+
42
46
  # Initialize agent registry
43
47
  self.agent_registry = AgentRegistryAdapter(self.framework_path)
44
-
48
+
45
49
  def _detect_framework_path(self) -> Optional[Path]:
46
50
  """Auto-detect claude-mpm framework."""
47
51
  # First check if we're in claude-mpm project
@@ -54,7 +58,7 @@ class FrameworkLoader:
54
58
  self.logger.info(f"Using claude-mpm at: {parent}")
55
59
  return parent
56
60
  break
57
-
61
+
58
62
  # Otherwise check common locations for claude-mpm
59
63
  candidates = [
60
64
  # Development location
@@ -62,26 +66,24 @@ class FrameworkLoader:
62
66
  # Current directory
63
67
  Path.cwd() / "claude-mpm",
64
68
  ]
65
-
69
+
66
70
  for candidate in candidates:
67
71
  if candidate and candidate.exists():
68
72
  # Check for claude-mpm agents directory
69
73
  if (candidate / "src" / "claude_mpm" / "agents").exists():
70
74
  self.logger.info(f"Found claude-mpm at: {candidate}")
71
75
  return candidate
72
-
76
+
73
77
  self.logger.warning("Framework not found, will use minimal instructions")
74
78
  return None
75
-
79
+
76
80
  def _get_npm_global_path(self) -> Optional[Path]:
77
81
  """Get npm global installation path."""
78
82
  try:
79
83
  import subprocess
84
+
80
85
  result = subprocess.run(
81
- ["npm", "root", "-g"],
82
- capture_output=True,
83
- text=True,
84
- timeout=5
86
+ ["npm", "root", "-g"], capture_output=True, text=True, timeout=5
85
87
  )
86
88
  if result.returncode == 0:
87
89
  npm_root = Path(result.stdout.strip())
@@ -89,159 +91,204 @@ class FrameworkLoader:
89
91
  except:
90
92
  pass
91
93
  return None
92
-
93
- def _discover_framework_paths(self) -> tuple[Optional[Path], Optional[Path], Optional[Path]]:
94
+
95
+ def _discover_framework_paths(
96
+ self,
97
+ ) -> tuple[Optional[Path], Optional[Path], Optional[Path]]:
94
98
  """
95
99
  Discover agent directories based on priority.
96
-
100
+
97
101
  Returns:
98
102
  Tuple of (agents_dir, templates_dir, main_dir)
99
103
  """
100
104
  agents_dir = None
101
105
  templates_dir = None
102
106
  main_dir = None
103
-
107
+
104
108
  if self.agents_dir and self.agents_dir.exists():
105
109
  agents_dir = self.agents_dir
106
110
  self.logger.info(f"Using custom agents directory: {agents_dir}")
107
111
  elif self.framework_path:
108
112
  # Prioritize templates directory over main agents directory
109
- templates_dir = self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
113
+ templates_dir = (
114
+ self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
115
+ )
110
116
  main_dir = self.framework_path / "src" / "claude_mpm" / "agents"
111
-
117
+
112
118
  if templates_dir.exists() and any(templates_dir.glob("*.md")):
113
119
  agents_dir = templates_dir
114
120
  self.logger.info(f"Using agents from templates directory: {agents_dir}")
115
121
  elif main_dir.exists() and any(main_dir.glob("*.md")):
116
122
  agents_dir = main_dir
117
123
  self.logger.info(f"Using agents from main directory: {agents_dir}")
118
-
124
+
119
125
  return agents_dir, templates_dir, main_dir
120
-
126
+
121
127
  def _try_load_file(self, file_path: Path, file_type: str) -> Optional[str]:
122
128
  """
123
129
  Try to load a file with error handling.
124
-
130
+
125
131
  Args:
126
132
  file_path: Path to the file to load
127
133
  file_type: Description of file type for logging
128
-
134
+
129
135
  Returns:
130
136
  File content if successful, None otherwise
131
137
  """
132
138
  try:
133
139
  content = file_path.read_text()
134
- if hasattr(self.logger, 'level') and self.logger.level <= logging.INFO:
140
+ if hasattr(self.logger, "level") and self.logger.level <= logging.INFO:
135
141
  self.logger.info(f"Loaded {file_type} from: {file_path}")
136
-
142
+
137
143
  # Extract metadata if present
138
144
  import re
139
- version_match = re.search(r'<!-- FRAMEWORK_VERSION: (\d+) -->', content)
145
+
146
+ version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
140
147
  if version_match:
141
- version = version_match.group(1) # Keep as string to preserve leading zeros
148
+ version = version_match.group(
149
+ 1
150
+ ) # Keep as string to preserve leading zeros
142
151
  self.logger.info(f"Framework version: {version}")
143
152
  # Store framework version if this is the main INSTRUCTIONS.md
144
- if 'INSTRUCTIONS.md' in str(file_path):
153
+ if "INSTRUCTIONS.md" in str(file_path):
145
154
  self.framework_version = version
146
-
155
+
147
156
  # Extract modification timestamp
148
- timestamp_match = re.search(r'<!-- LAST_MODIFIED: ([^>]+) -->', content)
157
+ timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
149
158
  if timestamp_match:
150
159
  timestamp = timestamp_match.group(1).strip()
151
160
  self.logger.info(f"Last modified: {timestamp}")
152
161
  # Store timestamp if this is the main INSTRUCTIONS.md
153
- if 'INSTRUCTIONS.md' in str(file_path):
162
+ if "INSTRUCTIONS.md" in str(file_path):
154
163
  self.framework_last_modified = timestamp
155
-
164
+
156
165
  return content
157
166
  except Exception as e:
158
- if hasattr(self.logger, 'level') and self.logger.level <= logging.ERROR:
167
+ if hasattr(self.logger, "level") and self.logger.level <= logging.ERROR:
159
168
  self.logger.error(f"Failed to load {file_type}: {e}")
160
169
  return None
161
-
170
+
162
171
  def _load_instructions_file(self, content: Dict[str, Any]) -> None:
163
172
  """
164
173
  Load INSTRUCTIONS.md or legacy CLAUDE.md from working directory.
165
-
174
+
166
175
  NOTE: We no longer load CLAUDE.md since Claude Code already picks it up automatically.
167
176
  This prevents duplication of instructions.
168
-
177
+
169
178
  Args:
170
179
  content: Dictionary to update with loaded instructions
171
180
  """
172
181
  # Disabled - Claude Code already reads CLAUDE.md automatically
173
182
  # We don't need to duplicate it in the PM instructions
174
183
  pass
175
-
184
+
176
185
  def _load_workflow_instructions(self, content: Dict[str, Any]) -> None:
177
186
  """
178
187
  Load WORKFLOW.md with project-specific override support.
179
-
188
+
180
189
  Precedence:
181
190
  1. Project-specific: .claude-mpm/agents/WORKFLOW.md
182
191
  2. System default: src/claude_mpm/agents/WORKFLOW.md
183
-
192
+
184
193
  Args:
185
194
  content: Dictionary to update with workflow instructions
186
195
  """
187
196
  # Check for project-specific workflow first
188
197
  project_workflow_path = Path.cwd() / ".claude-mpm" / "agents" / "WORKFLOW.md"
189
198
  if project_workflow_path.exists():
190
- loaded_content = self._try_load_file(project_workflow_path, "project-specific WORKFLOW.md")
199
+ loaded_content = self._try_load_file(
200
+ project_workflow_path, "project-specific WORKFLOW.md"
201
+ )
191
202
  if loaded_content:
192
203
  content["workflow_instructions"] = loaded_content
193
204
  content["project_workflow"] = "project"
194
205
  self.logger.info("Using project-specific WORKFLOW.md")
195
206
  return
196
-
207
+
197
208
  # Fall back to system workflow
198
209
  if self.framework_path:
199
- system_workflow_path = self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
210
+ system_workflow_path = (
211
+ self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
212
+ )
200
213
  if system_workflow_path.exists():
201
- loaded_content = self._try_load_file(system_workflow_path, "system WORKFLOW.md")
214
+ loaded_content = self._try_load_file(
215
+ system_workflow_path, "system WORKFLOW.md"
216
+ )
202
217
  if loaded_content:
203
218
  content["workflow_instructions"] = loaded_content
204
219
  content["project_workflow"] = "system"
205
220
  self.logger.info("Using system WORKFLOW.md")
206
-
221
+
207
222
  def _load_memory_instructions(self, content: Dict[str, Any]) -> None:
208
223
  """
209
224
  Load MEMORY.md with project-specific override support.
210
-
225
+
211
226
  Precedence:
212
227
  1. Project-specific: .claude-mpm/agents/MEMORY.md
213
228
  2. System default: src/claude_mpm/agents/MEMORY.md
214
-
229
+
215
230
  Args:
216
231
  content: Dictionary to update with memory instructions
217
232
  """
218
233
  # Check for project-specific memory instructions first
219
234
  project_memory_path = Path.cwd() / ".claude-mpm" / "agents" / "MEMORY.md"
220
235
  if project_memory_path.exists():
221
- loaded_content = self._try_load_file(project_memory_path, "project-specific MEMORY.md")
236
+ loaded_content = self._try_load_file(
237
+ project_memory_path, "project-specific MEMORY.md"
238
+ )
222
239
  if loaded_content:
223
240
  content["memory_instructions"] = loaded_content
224
241
  content["project_memory"] = "project"
225
242
  self.logger.info("Using project-specific MEMORY.md")
226
243
  return
227
-
244
+
228
245
  # Fall back to system memory instructions
229
246
  if self.framework_path:
230
- system_memory_path = self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
247
+ system_memory_path = (
248
+ self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
249
+ )
231
250
  if system_memory_path.exists():
232
- loaded_content = self._try_load_file(system_memory_path, "system MEMORY.md")
251
+ loaded_content = self._try_load_file(
252
+ system_memory_path, "system MEMORY.md"
253
+ )
233
254
  if loaded_content:
234
255
  content["memory_instructions"] = loaded_content
235
256
  content["project_memory"] = "system"
236
257
  self.logger.info("Using system MEMORY.md")
237
258
 
238
- def _load_single_agent(self, agent_file: Path) -> tuple[Optional[str], Optional[str]]:
259
+ def _load_actual_memories(self, content: Dict[str, Any]) -> None:
239
260
  """
240
- Load a single agent file.
261
+ Load actual PM memories from .claude-mpm/memories/PM.md.
241
262
 
263
+ These are the actual memories/knowledge that the PM should have,
264
+ as opposed to the memory system instructions in MEMORY.md.
265
+
266
+ Args:
267
+ content: Dictionary to update with actual memories
268
+ """
269
+ memories_path = Path.cwd() / ".claude-mpm" / "memories" / "PM.md"
270
+ if memories_path.exists():
271
+ loaded_content = self._try_load_file(
272
+ memories_path, "PM memories"
273
+ )
274
+ if loaded_content:
275
+ content["actual_memories"] = loaded_content
276
+ self.logger.info(f"Loaded PM memories from: {memories_path}")
277
+ # Log memory size for monitoring
278
+ memory_size = len(loaded_content.encode('utf-8'))
279
+ self.logger.debug(f"PM memory size: {memory_size:,} bytes")
280
+ else:
281
+ self.logger.debug(f"No PM memories found at: {memories_path}")
282
+
283
+ def _load_single_agent(
284
+ self, agent_file: Path
285
+ ) -> tuple[Optional[str], Optional[str]]:
286
+ """
287
+ Load a single agent file.
288
+
242
289
  Args:
243
290
  agent_file: Path to the agent file
244
-
291
+
245
292
  Returns:
246
293
  Tuple of (agent_name, agent_content) or (None, None) on failure
247
294
  """
@@ -256,11 +303,13 @@ class FrameworkLoader:
256
303
  except Exception as e:
257
304
  self.logger.error(f"Failed to load agent {agent_file}: {e}")
258
305
  return None, None
259
-
260
- def _load_base_agent_fallback(self, content: Dict[str, Any], main_dir: Optional[Path]) -> None:
306
+
307
+ def _load_base_agent_fallback(
308
+ self, content: Dict[str, Any], main_dir: Optional[Path]
309
+ ) -> None:
261
310
  """
262
311
  Load base_agent.md from main directory as fallback.
263
-
312
+
264
313
  Args:
265
314
  content: Dictionary to update with base agent
266
315
  main_dir: Main agents directory path
@@ -271,12 +320,17 @@ class FrameworkLoader:
271
320
  agent_name, agent_content = self._load_single_agent(base_agent_file)
272
321
  if agent_name and agent_content:
273
322
  content["agents"][agent_name] = agent_content
274
-
275
- def _load_agents_directory(self, content: Dict[str, Any], agents_dir: Optional[Path],
276
- templates_dir: Optional[Path], main_dir: Optional[Path]) -> None:
323
+
324
+ def _load_agents_directory(
325
+ self,
326
+ content: Dict[str, Any],
327
+ agents_dir: Optional[Path],
328
+ templates_dir: Optional[Path],
329
+ main_dir: Optional[Path],
330
+ ) -> None:
277
331
  """
278
332
  Load agent definitions from the appropriate directory.
279
-
333
+
280
334
  Args:
281
335
  content: Dictionary to update with loaded agents
282
336
  agents_dir: Primary agents directory to load from
@@ -285,19 +339,19 @@ class FrameworkLoader:
285
339
  """
286
340
  if not agents_dir or not agents_dir.exists():
287
341
  return
288
-
342
+
289
343
  content["loaded"] = True
290
-
344
+
291
345
  # Load all agent files
292
346
  for agent_file in agents_dir.glob("*.md"):
293
347
  agent_name, agent_content = self._load_single_agent(agent_file)
294
348
  if agent_name and agent_content:
295
349
  content["agents"][agent_name] = agent_content
296
-
350
+
297
351
  # If we used templates dir, also check main dir for base_agent.md
298
352
  if agents_dir == templates_dir:
299
353
  self._load_base_agent_fallback(content, main_dir)
300
-
354
+
301
355
  def _load_framework_content(self) -> Dict[str, Any]:
302
356
  """Load framework content."""
303
357
  content = {
@@ -310,55 +364,69 @@ class FrameworkLoader:
310
364
  "workflow_instructions": "",
311
365
  "project_workflow": "",
312
366
  "memory_instructions": "",
313
- "project_memory": ""
367
+ "project_memory": "",
368
+ "actual_memories": "", # Add field for actual memories from PM.md
314
369
  }
315
-
370
+
316
371
  # Load instructions file from working directory
317
372
  self._load_instructions_file(content)
318
-
373
+
319
374
  if not self.framework_path:
320
375
  return content
321
-
376
+
322
377
  # Load framework's INSTRUCTIONS.md
323
- framework_instructions_path = self.framework_path / "src" / "claude_mpm" / "agents" / "INSTRUCTIONS.md"
378
+ framework_instructions_path = (
379
+ self.framework_path / "src" / "claude_mpm" / "agents" / "INSTRUCTIONS.md"
380
+ )
324
381
  if framework_instructions_path.exists():
325
- loaded_content = self._try_load_file(framework_instructions_path, "framework INSTRUCTIONS.md")
382
+ loaded_content = self._try_load_file(
383
+ framework_instructions_path, "framework INSTRUCTIONS.md"
384
+ )
326
385
  if loaded_content:
327
386
  content["framework_instructions"] = loaded_content
328
387
  content["loaded"] = True
329
388
  # Add framework version to content
330
389
  if self.framework_version:
331
390
  content["instructions_version"] = self.framework_version
332
- content["version"] = self.framework_version # Update main version key
391
+ content[
392
+ "version"
393
+ ] = self.framework_version # Update main version key
333
394
  # Add modification timestamp to content
334
395
  if self.framework_last_modified:
335
396
  content["instructions_last_modified"] = self.framework_last_modified
336
-
397
+
337
398
  # Load BASE_PM.md for core framework requirements
338
- base_pm_path = self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
399
+ base_pm_path = (
400
+ self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
401
+ )
339
402
  if base_pm_path.exists():
340
- base_pm_content = self._try_load_file(base_pm_path, "BASE_PM framework requirements")
403
+ base_pm_content = self._try_load_file(
404
+ base_pm_path, "BASE_PM framework requirements"
405
+ )
341
406
  if base_pm_content:
342
407
  content["base_pm_instructions"] = base_pm_content
343
-
408
+
344
409
  # Load WORKFLOW.md - check for project-specific first, then system
345
410
  self._load_workflow_instructions(content)
346
-
411
+
347
412
  # Load MEMORY.md - check for project-specific first, then system
348
413
  self._load_memory_instructions(content)
349
414
 
415
+ # Load actual memories from .claude-mpm/memories/PM.md
416
+ self._load_actual_memories(content)
417
+
350
418
  # Discover agent directories
351
419
  agents_dir, templates_dir, main_dir = self._discover_framework_paths()
352
-
420
+
353
421
  # Load agents from discovered directory
354
422
  self._load_agents_directory(content, agents_dir, templates_dir, main_dir)
355
-
423
+
356
424
  return content
357
-
425
+
358
426
  def get_framework_instructions(self) -> str:
359
427
  """
360
428
  Get formatted framework instructions for injection.
361
-
429
+
362
430
  Returns:
363
431
  Complete framework instructions ready for injection
364
432
  """
@@ -368,61 +436,83 @@ class FrameworkLoader:
368
436
  else:
369
437
  # Use minimal fallback
370
438
  return self._format_minimal_framework()
371
-
439
+
372
440
  def _strip_metadata_comments(self, content: str) -> str:
373
441
  """Strip metadata HTML comments from content.
374
-
442
+
375
443
  Removes comments like:
376
444
  <!-- FRAMEWORK_VERSION: 0010 -->
377
445
  <!-- LAST_MODIFIED: 2025-08-10T00:00:00Z -->
378
446
  """
379
447
  import re
448
+
380
449
  # Remove HTML comments that contain metadata
381
- cleaned = re.sub(r'<!--\s*(FRAMEWORK_VERSION|LAST_MODIFIED|WORKFLOW_VERSION|PROJECT_WORKFLOW_VERSION|CUSTOM_PROJECT_WORKFLOW)[^>]*-->\n?', '', content)
450
+ cleaned = re.sub(
451
+ r"<!--\s*(FRAMEWORK_VERSION|LAST_MODIFIED|WORKFLOW_VERSION|PROJECT_WORKFLOW_VERSION|CUSTOM_PROJECT_WORKFLOW)[^>]*-->\n?",
452
+ "",
453
+ content,
454
+ )
382
455
  # Also remove any leading blank lines that might result
383
- cleaned = cleaned.lstrip('\n')
456
+ cleaned = cleaned.lstrip("\n")
384
457
  return cleaned
385
-
458
+
386
459
  def _format_full_framework(self) -> str:
387
460
  """Format full framework instructions."""
388
461
  from datetime import datetime
389
-
462
+
390
463
  # If we have the full framework INSTRUCTIONS.md, use it
391
464
  if self.framework_content.get("framework_instructions"):
392
- instructions = self._strip_metadata_comments(self.framework_content["framework_instructions"])
393
-
465
+ instructions = self._strip_metadata_comments(
466
+ self.framework_content["framework_instructions"]
467
+ )
468
+
394
469
  # Note: We don't add working directory CLAUDE.md here since Claude Code
395
470
  # already picks it up automatically. This prevents duplication.
396
-
471
+
397
472
  # Add WORKFLOW.md after instructions
398
473
  if self.framework_content.get("workflow_instructions"):
399
- workflow_content = self._strip_metadata_comments(self.framework_content['workflow_instructions'])
474
+ workflow_content = self._strip_metadata_comments(
475
+ self.framework_content["workflow_instructions"]
476
+ )
400
477
  instructions += f"\n\n{workflow_content}\n"
401
478
  # Note: project-specific workflow is being used (logged elsewhere)
402
-
479
+
403
480
  # Add MEMORY.md after workflow instructions
404
481
  if self.framework_content.get("memory_instructions"):
405
- memory_content = self._strip_metadata_comments(self.framework_content['memory_instructions'])
482
+ memory_content = self._strip_metadata_comments(
483
+ self.framework_content["memory_instructions"]
484
+ )
406
485
  instructions += f"\n\n{memory_content}\n"
407
486
  # Note: project-specific memory instructions being used (logged elsewhere)
408
487
 
488
+ # Add actual PM memories after memory instructions
489
+ if self.framework_content.get("actual_memories"):
490
+ instructions += "\n\n## Current PM Memories\n\n"
491
+ instructions += "**The following are your accumulated memories and knowledge from this project:**\n\n"
492
+ instructions += self.framework_content["actual_memories"]
493
+ instructions += "\n"
494
+
409
495
  # Add dynamic agent capabilities section
410
496
  instructions += self._generate_agent_capabilities_section()
411
-
497
+
412
498
  # Add current date for temporal awareness
413
499
  instructions += f"\n\n## Temporal Context\n**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
414
- instructions += "Apply date awareness to all time-sensitive tasks and decisions.\n"
415
-
500
+ instructions += (
501
+ "Apply date awareness to all time-sensitive tasks and decisions.\n"
502
+ )
503
+
416
504
  # Add BASE_PM.md framework requirements AFTER INSTRUCTIONS.md
417
505
  if self.framework_content.get("base_pm_instructions"):
418
- base_pm = self._strip_metadata_comments(self.framework_content['base_pm_instructions'])
506
+ base_pm = self._strip_metadata_comments(
507
+ self.framework_content["base_pm_instructions"]
508
+ )
419
509
  instructions += f"\n\n{base_pm}"
420
-
510
+
421
511
  # Clean up any trailing whitespace
422
512
  instructions = instructions.rstrip() + "\n"
423
-
513
+
424
514
  return instructions
425
-
515
+
426
516
  # Otherwise fall back to generating framework
427
517
  instructions = """# Claude MPM Framework Instructions
428
518
 
@@ -437,48 +527,71 @@ You are a multi-agent orchestrator. Your primary responsibilities are:
437
527
  - NEVER perform direct implementation work yourself
438
528
 
439
529
  """
440
-
530
+
441
531
  # Note: We don't add working directory CLAUDE.md here since Claude Code
442
532
  # already picks it up automatically. This prevents duplication.
443
-
533
+
444
534
  # Add agent definitions
445
535
  if self.framework_content["agents"]:
446
536
  instructions += "## Available Agents\n\n"
447
537
  instructions += "You have the following specialized agents available for delegation:\n\n"
448
-
538
+
449
539
  # List agents with brief descriptions and correct IDs
450
540
  agent_list = []
451
541
  for agent_name in sorted(self.framework_content["agents"].keys()):
452
542
  # Use the actual agent_name as the ID (it's the filename stem)
453
543
  agent_id = agent_name
454
- clean_name = agent_name.replace('-', ' ').replace('_', ' ').title()
455
- if 'engineer' in agent_name.lower() and 'data' not in agent_name.lower():
456
- agent_list.append(f"- **Engineer Agent** (`{agent_id}`): Code implementation and development")
457
- elif 'qa' in agent_name.lower():
458
- agent_list.append(f"- **QA Agent** (`{agent_id}`): Testing and quality assurance")
459
- elif 'documentation' in agent_name.lower():
460
- agent_list.append(f"- **Documentation Agent** (`{agent_id}`): Documentation creation and maintenance")
461
- elif 'research' in agent_name.lower():
462
- agent_list.append(f"- **Research Agent** (`{agent_id}`): Investigation and analysis")
463
- elif 'security' in agent_name.lower():
464
- agent_list.append(f"- **Security Agent** (`{agent_id}`): Security analysis and protection")
465
- elif 'version' in agent_name.lower():
466
- agent_list.append(f"- **Version Control Agent** (`{agent_id}`): Git operations and version management")
467
- elif 'ops' in agent_name.lower():
468
- agent_list.append(f"- **Ops Agent** (`{agent_id}`): Deployment and operations")
469
- elif 'data' in agent_name.lower():
470
- agent_list.append(f"- **Data Engineer Agent** (`{agent_id}`): Data management and AI API integration")
544
+ clean_name = agent_name.replace("-", " ").replace("_", " ").title()
545
+ if (
546
+ "engineer" in agent_name.lower()
547
+ and "data" not in agent_name.lower()
548
+ ):
549
+ agent_list.append(
550
+ f"- **Engineer Agent** (`{agent_id}`): Code implementation and development"
551
+ )
552
+ elif "qa" in agent_name.lower():
553
+ agent_list.append(
554
+ f"- **QA Agent** (`{agent_id}`): Testing and quality assurance"
555
+ )
556
+ elif "documentation" in agent_name.lower():
557
+ agent_list.append(
558
+ f"- **Documentation Agent** (`{agent_id}`): Documentation creation and maintenance"
559
+ )
560
+ elif "research" in agent_name.lower():
561
+ agent_list.append(
562
+ f"- **Research Agent** (`{agent_id}`): Investigation and analysis"
563
+ )
564
+ elif "security" in agent_name.lower():
565
+ agent_list.append(
566
+ f"- **Security Agent** (`{agent_id}`): Security analysis and protection"
567
+ )
568
+ elif "version" in agent_name.lower():
569
+ agent_list.append(
570
+ f"- **Version Control Agent** (`{agent_id}`): Git operations and version management"
571
+ )
572
+ elif "ops" in agent_name.lower():
573
+ agent_list.append(
574
+ f"- **Ops Agent** (`{agent_id}`): Deployment and operations"
575
+ )
576
+ elif "data" in agent_name.lower():
577
+ agent_list.append(
578
+ f"- **Data Engineer Agent** (`{agent_id}`): Data management and AI API integration"
579
+ )
471
580
  else:
472
- agent_list.append(f"- **{clean_name}** (`{agent_id}`): Available for specialized tasks")
473
-
581
+ agent_list.append(
582
+ f"- **{clean_name}** (`{agent_id}`): Available for specialized tasks"
583
+ )
584
+
474
585
  instructions += "\n".join(agent_list) + "\n\n"
475
-
586
+
476
587
  # Add full agent details
477
588
  instructions += "### Agent Details\n\n"
478
- for agent_name, agent_content in sorted(self.framework_content["agents"].items()):
589
+ for agent_name, agent_content in sorted(
590
+ self.framework_content["agents"].items()
591
+ ):
479
592
  instructions += f"#### {agent_name.replace('-', ' ').title()}\n"
480
593
  instructions += agent_content + "\n\n"
481
-
594
+
482
595
  # Add orchestration principles
483
596
  instructions += """
484
597
  ## Orchestration Principles
@@ -515,174 +628,219 @@ Extract tickets from these patterns:
515
628
 
516
629
  ---
517
630
  """
518
-
631
+
519
632
  return instructions
520
-
633
+
521
634
  def _generate_agent_capabilities_section(self) -> str:
522
635
  """Generate dynamic agent capabilities section from deployed agents."""
523
636
  try:
524
637
  from pathlib import Path
638
+
525
639
  import yaml
526
-
640
+
527
641
  # Read directly from deployed agents in .claude/agents/
528
642
  agents_dir = Path.cwd() / ".claude" / "agents"
529
-
643
+
530
644
  if not agents_dir.exists():
531
645
  self.logger.warning("No .claude/agents directory found")
532
646
  return self._get_fallback_capabilities()
533
-
647
+
534
648
  # Build capabilities section
535
649
  section = "\n\n## Available Agent Capabilities\n\n"
536
-
650
+
537
651
  # Collect deployed agents
538
652
  deployed_agents = []
539
653
  for agent_file in agents_dir.glob("*.md"):
540
- if agent_file.name.startswith('.'):
654
+ if agent_file.name.startswith("."):
541
655
  continue
542
-
656
+
543
657
  # Parse agent metadata
544
658
  agent_data = self._parse_agent_metadata(agent_file)
545
659
  if agent_data:
546
660
  deployed_agents.append(agent_data)
547
-
661
+
548
662
  if not deployed_agents:
549
663
  return self._get_fallback_capabilities()
550
-
664
+
551
665
  # Sort agents alphabetically by ID
552
- deployed_agents.sort(key=lambda x: x['id'])
553
-
666
+ deployed_agents.sort(key=lambda x: x["id"])
667
+
554
668
  # Display all agents with their rich descriptions
555
669
  for agent in deployed_agents:
556
670
  # Clean up display name - handle common acronyms
557
- display_name = agent['display_name']
558
- display_name = display_name.replace('Qa ', 'QA ').replace('Ui ', 'UI ').replace('Api ', 'API ')
559
- if display_name.lower() == 'qa agent':
560
- display_name = 'QA Agent'
561
-
671
+ display_name = agent["display_name"]
672
+ display_name = (
673
+ display_name.replace("Qa ", "QA ")
674
+ .replace("Ui ", "UI ")
675
+ .replace("Api ", "API ")
676
+ )
677
+ if display_name.lower() == "qa agent":
678
+ display_name = "QA Agent"
679
+
562
680
  section += f"\n### {display_name} (`{agent['id']}`)\n"
563
681
  section += f"{agent['description']}\n"
564
-
682
+
565
683
  # Add any additional metadata if present
566
- if agent.get('authority'):
684
+ if agent.get("authority"):
567
685
  section += f"- **Authority**: {agent['authority']}\n"
568
- if agent.get('primary_function'):
686
+ if agent.get("primary_function"):
569
687
  section += f"- **Primary Function**: {agent['primary_function']}\n"
570
- if agent.get('handoff_to'):
688
+ if agent.get("handoff_to"):
571
689
  section += f"- **Handoff To**: {agent['handoff_to']}\n"
572
- if agent.get('tools') and agent['tools'] != 'standard':
690
+ if agent.get("tools") and agent["tools"] != "standard":
573
691
  section += f"- **Tools**: {agent['tools']}\n"
574
- if agent.get('model') and agent['model'] != 'opus':
692
+ if agent.get("model") and agent["model"] != "opus":
575
693
  section += f"- **Model**: {agent['model']}\n"
576
-
694
+
577
695
  # Add simple Context-Aware Agent Selection
578
696
  section += "\n## Context-Aware Agent Selection\n\n"
579
- section += "Select agents based on their descriptions above. Key principles:\n"
697
+ section += (
698
+ "Select agents based on their descriptions above. Key principles:\n"
699
+ )
580
700
  section += "- **PM questions** → Answer directly (only exception)\n"
581
701
  section += "- Match task requirements to agent descriptions and authority\n"
582
702
  section += "- Consider agent handoff recommendations\n"
583
- section += "- Use the agent ID in parentheses when delegating via Task tool\n"
584
-
703
+ section += (
704
+ "- Use the agent ID in parentheses when delegating via Task tool\n"
705
+ )
706
+
585
707
  # Add summary
586
708
  section += f"\n**Total Available Agents**: {len(deployed_agents)}\n"
587
-
709
+
588
710
  return section
589
-
711
+
590
712
  except Exception as e:
591
713
  self.logger.warning(f"Could not generate dynamic agent capabilities: {e}")
592
714
  return self._get_fallback_capabilities()
593
-
715
+
594
716
  def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
595
717
  """Parse agent metadata from deployed agent file.
596
-
718
+
597
719
  Returns:
598
720
  Dictionary with agent metadata directly from YAML frontmatter.
599
721
  """
600
722
  try:
601
723
  import yaml
602
-
603
- with open(agent_file, 'r') as f:
724
+
725
+ with open(agent_file, "r") as f:
604
726
  content = f.read()
605
-
727
+
606
728
  # Default values
607
729
  agent_data = {
608
- 'id': agent_file.stem,
609
- 'display_name': agent_file.stem.replace('_', ' ').replace('-', ' ').title(),
610
- 'description': 'Specialized agent'
730
+ "id": agent_file.stem,
731
+ "display_name": agent_file.stem.replace("_", " ")
732
+ .replace("-", " ")
733
+ .title(),
734
+ "description": "Specialized agent",
611
735
  }
612
-
736
+
613
737
  # Extract YAML frontmatter if present
614
- if content.startswith('---'):
615
- end_marker = content.find('---', 3)
738
+ if content.startswith("---"):
739
+ end_marker = content.find("---", 3)
616
740
  if end_marker > 0:
617
741
  frontmatter = content[3:end_marker]
618
742
  metadata = yaml.safe_load(frontmatter)
619
743
  if metadata:
620
744
  # Use name as ID for Task tool
621
- agent_data['id'] = metadata.get('name', agent_data['id'])
622
- agent_data['display_name'] = metadata.get('name', agent_data['display_name']).replace('-', ' ').title()
623
-
745
+ agent_data["id"] = metadata.get("name", agent_data["id"])
746
+ agent_data["display_name"] = (
747
+ metadata.get("name", agent_data["display_name"])
748
+ .replace("-", " ")
749
+ .title()
750
+ )
751
+
624
752
  # Copy all metadata fields directly
625
753
  for key, value in metadata.items():
626
- if key not in ['name']: # Skip already processed fields
754
+ if key not in ["name"]: # Skip already processed fields
627
755
  agent_data[key] = value
628
-
756
+
629
757
  # IMPORTANT: Do NOT add spaces to tools field - it breaks deployment!
630
758
  # Tools must remain as comma-separated without spaces: "Read,Write,Edit"
631
-
759
+
632
760
  return agent_data
633
-
761
+
634
762
  except Exception as e:
635
763
  self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
636
764
  return None
637
-
765
+
638
766
  def _generate_agent_selection_guide(self, deployed_agents: list) -> str:
639
767
  """Generate Context-Aware Agent Selection guide from deployed agents.
640
-
768
+
641
769
  Creates a mapping of task types to appropriate agents based on their
642
770
  descriptions and capabilities.
643
771
  """
644
772
  guide = ""
645
-
773
+
646
774
  # Build selection mapping based on deployed agents
647
775
  selection_map = {}
648
-
776
+
649
777
  for agent in deployed_agents:
650
- agent_id = agent['id']
651
- desc_lower = agent['description'].lower()
652
-
778
+ agent_id = agent["id"]
779
+ desc_lower = agent["description"].lower()
780
+
653
781
  # Map task types to agents based on their descriptions
654
- if 'implementation' in desc_lower or ('engineer' in agent_id and 'data' not in agent_id):
655
- selection_map['Implementation tasks'] = f"{agent['display_name']} (`{agent_id}`)"
656
- if 'codebase analysis' in desc_lower or 'research' in agent_id:
657
- selection_map['Codebase analysis'] = f"{agent['display_name']} (`{agent_id}`)"
658
- if 'testing' in desc_lower or 'qa' in agent_id:
659
- selection_map['Testing/quality'] = f"{agent['display_name']} (`{agent_id}`)"
660
- if 'documentation' in desc_lower:
661
- selection_map['Documentation'] = f"{agent['display_name']} (`{agent_id}`)"
662
- if 'security' in desc_lower or 'sast' in desc_lower:
663
- selection_map['Security operations'] = f"{agent['display_name']} (`{agent_id}`)"
664
- if 'deployment' in desc_lower or 'infrastructure' in desc_lower or 'ops' in agent_id:
665
- selection_map['Deployment/infrastructure'] = f"{agent['display_name']} (`{agent_id}`)"
666
- if 'data' in desc_lower and ('pipeline' in desc_lower or 'etl' in desc_lower):
667
- selection_map['Data pipeline/ETL'] = f"{agent['display_name']} (`{agent_id}`)"
668
- if 'git' in desc_lower or 'version control' in desc_lower:
669
- selection_map['Version control'] = f"{agent['display_name']} (`{agent_id}`)"
670
- if 'ticket' in desc_lower or 'epic' in desc_lower:
671
- selection_map['Ticket/issue management'] = f"{agent['display_name']} (`{agent_id}`)"
672
- if 'browser' in desc_lower or 'e2e' in desc_lower:
673
- selection_map['Browser/E2E testing'] = f"{agent['display_name']} (`{agent_id}`)"
674
- if 'frontend' in desc_lower or 'ui' in desc_lower or 'html' in desc_lower:
675
- selection_map['Frontend/UI development'] = f"{agent['display_name']} (`{agent_id}`)"
676
-
782
+ if "implementation" in desc_lower or (
783
+ "engineer" in agent_id and "data" not in agent_id
784
+ ):
785
+ selection_map[
786
+ "Implementation tasks"
787
+ ] = f"{agent['display_name']} (`{agent_id}`)"
788
+ if "codebase analysis" in desc_lower or "research" in agent_id:
789
+ selection_map[
790
+ "Codebase analysis"
791
+ ] = f"{agent['display_name']} (`{agent_id}`)"
792
+ if "testing" in desc_lower or "qa" in agent_id:
793
+ selection_map[
794
+ "Testing/quality"
795
+ ] = f"{agent['display_name']} (`{agent_id}`)"
796
+ if "documentation" in desc_lower:
797
+ selection_map[
798
+ "Documentation"
799
+ ] = f"{agent['display_name']} (`{agent_id}`)"
800
+ if "security" in desc_lower or "sast" in desc_lower:
801
+ selection_map[
802
+ "Security operations"
803
+ ] = f"{agent['display_name']} (`{agent_id}`)"
804
+ if (
805
+ "deployment" in desc_lower
806
+ or "infrastructure" in desc_lower
807
+ or "ops" in agent_id
808
+ ):
809
+ selection_map[
810
+ "Deployment/infrastructure"
811
+ ] = f"{agent['display_name']} (`{agent_id}`)"
812
+ if "data" in desc_lower and (
813
+ "pipeline" in desc_lower or "etl" in desc_lower
814
+ ):
815
+ selection_map[
816
+ "Data pipeline/ETL"
817
+ ] = f"{agent['display_name']} (`{agent_id}`)"
818
+ if "git" in desc_lower or "version control" in desc_lower:
819
+ selection_map[
820
+ "Version control"
821
+ ] = f"{agent['display_name']} (`{agent_id}`)"
822
+ if "ticket" in desc_lower or "epic" in desc_lower:
823
+ selection_map[
824
+ "Ticket/issue management"
825
+ ] = f"{agent['display_name']} (`{agent_id}`)"
826
+ if "browser" in desc_lower or "e2e" in desc_lower:
827
+ selection_map[
828
+ "Browser/E2E testing"
829
+ ] = f"{agent['display_name']} (`{agent_id}`)"
830
+ if "frontend" in desc_lower or "ui" in desc_lower or "html" in desc_lower:
831
+ selection_map[
832
+ "Frontend/UI development"
833
+ ] = f"{agent['display_name']} (`{agent_id}`)"
834
+
677
835
  # Always include PM questions
678
- selection_map['PM questions'] = "Answer directly (only exception)"
679
-
836
+ selection_map["PM questions"] = "Answer directly (only exception)"
837
+
680
838
  # Format the selection guide
681
839
  for task_type, agent_info in selection_map.items():
682
840
  guide += f"- **{task_type}** → {agent_info}\n"
683
-
841
+
684
842
  return guide
685
-
843
+
686
844
  def _get_fallback_capabilities(self) -> str:
687
845
  """Return fallback capabilities when dynamic discovery fails."""
688
846
  return """
@@ -692,7 +850,7 @@ Extract tickets from these patterns:
692
850
  You have the following specialized agents available for delegation:
693
851
 
694
852
  - **Engineer** (`engineer`): Code implementation and development
695
- - **Research** (`research-agent`): Investigation and analysis
853
+ - **Research** (`research-agent`): Investigation and analysis
696
854
  - **QA** (`qa-agent`): Testing and quality assurance
697
855
  - **Documentation** (`documentation-agent`): Documentation creation and maintenance
698
856
  - **Security** (`security-agent`): Security analysis and protection
@@ -702,7 +860,7 @@ You have the following specialized agents available for delegation:
702
860
 
703
861
  **IMPORTANT**: Use the exact agent ID in parentheses when delegating tasks.
704
862
  """
705
-
863
+
706
864
  def _format_minimal_framework(self) -> str:
707
865
  """Format minimal framework instructions when full framework not available."""
708
866
  return """
@@ -719,7 +877,7 @@ You are a multi-agent orchestrator. Your primary responsibilities:
719
877
 
720
878
  ## Core Agents
721
879
  - Documentation Agent - Documentation tasks
722
- - Engineer Agent - Code implementation
880
+ - Engineer Agent - Code implementation
723
881
  - QA Agent - Testing and validation
724
882
  - Research Agent - Investigation and analysis
725
883
  - Version Control Agent - Git operations
@@ -732,7 +890,7 @@ You are a multi-agent orchestrator. Your primary responsibilities:
732
890
 
733
891
  ---
734
892
  """
735
-
893
+
736
894
  def get_agent_list(self) -> list:
737
895
  """Get list of available agents."""
738
896
  # First try agent registry
@@ -740,10 +898,10 @@ You are a multi-agent orchestrator. Your primary responsibilities:
740
898
  agents = self.agent_registry.list_agents()
741
899
  if agents:
742
900
  return list(agents.keys())
743
-
901
+
744
902
  # Fallback to loaded content
745
903
  return list(self.framework_content["agents"].keys())
746
-
904
+
747
905
  def get_agent_definition(self, agent_name: str) -> Optional[str]:
748
906
  """Get specific agent definition."""
749
907
  # First try agent registry
@@ -751,12 +909,12 @@ You are a multi-agent orchestrator. Your primary responsibilities:
751
909
  definition = self.agent_registry.get_agent_definition(agent_name)
752
910
  if definition:
753
911
  return definition
754
-
912
+
755
913
  # Fallback to loaded content
756
914
  return self.framework_content["agents"].get(agent_name)
757
-
915
+
758
916
  def get_agent_hierarchy(self) -> Dict[str, list]:
759
917
  """Get agent hierarchy from registry."""
760
918
  if self.agent_registry:
761
919
  return self.agent_registry.get_agent_hierarchy()
762
- return {'project': [], 'user': [], 'system': []}
920
+ return {"project": [], "user": [], "system": []}