claude-mpm 4.1.6__py3-none-any.whl → 4.24.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (866) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__init__.py +20 -5
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  5. claude_mpm/agents/BASE_DOCUMENTATION.md +53 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/BASE_OPS.md +219 -0
  8. claude_mpm/agents/BASE_PM.md +431 -214
  9. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +787 -0
  10. claude_mpm/agents/BASE_QA.md +167 -0
  11. claude_mpm/agents/BASE_RESEARCH.md +53 -0
  12. claude_mpm/agents/MEMORY.md +3 -0
  13. claude_mpm/agents/OUTPUT_STYLE.md +335 -0
  14. claude_mpm/agents/PM_INSTRUCTIONS.md +1159 -0
  15. claude_mpm/agents/WORKFLOW.md +355 -187
  16. claude_mpm/agents/agent_loader.py +40 -10
  17. claude_mpm/agents/agent_loader_integration.py +3 -2
  18. claude_mpm/agents/agents_metadata.py +57 -0
  19. claude_mpm/agents/async_agent_loader.py +3 -3
  20. claude_mpm/agents/base_agent_loader.py +11 -9
  21. claude_mpm/agents/frontmatter_validator.py +291 -251
  22. claude_mpm/agents/system_agent_config.py +3 -2
  23. claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
  24. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
  25. claude_mpm/agents/templates/README.md +465 -0
  26. claude_mpm/agents/templates/agent-manager.json +267 -18
  27. claude_mpm/agents/templates/agentic-coder-optimizer.json +248 -0
  28. claude_mpm/agents/templates/api_qa.json +16 -4
  29. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  30. claude_mpm/agents/templates/clerk-ops.json +235 -0
  31. claude_mpm/agents/templates/code_analyzer.json +25 -9
  32. claude_mpm/agents/templates/content-agent.json +358 -0
  33. claude_mpm/agents/templates/dart_engineer.json +307 -0
  34. claude_mpm/agents/templates/data_engineer.json +87 -14
  35. claude_mpm/agents/templates/documentation.json +76 -13
  36. claude_mpm/agents/templates/engineer.json +44 -10
  37. claude_mpm/agents/templates/gcp_ops_agent.json +253 -0
  38. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  39. claude_mpm/agents/templates/golang_engineer.json +270 -0
  40. claude_mpm/agents/templates/imagemagick.json +5 -2
  41. claude_mpm/agents/templates/java_engineer.json +346 -0
  42. claude_mpm/agents/templates/javascript_engineer_agent.json +380 -0
  43. claude_mpm/agents/templates/local_ops_agent.json +1840 -0
  44. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
  45. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +400 -0
  46. claude_mpm/agents/templates/memory_manager.json +6 -3
  47. claude_mpm/agents/templates/nextjs_engineer.json +285 -0
  48. claude_mpm/agents/templates/ops.json +27 -8
  49. claude_mpm/agents/templates/php-engineer.json +287 -0
  50. claude_mpm/agents/templates/pm_examples.md +474 -0
  51. claude_mpm/agents/templates/pm_red_flags.md +262 -0
  52. claude_mpm/agents/templates/product_owner.json +338 -0
  53. claude_mpm/agents/templates/project_organizer.json +19 -5
  54. claude_mpm/agents/templates/prompt-engineer.json +737 -0
  55. claude_mpm/agents/templates/python_engineer.json +387 -0
  56. claude_mpm/agents/templates/qa.json +26 -6
  57. claude_mpm/agents/templates/react_engineer.json +239 -0
  58. claude_mpm/agents/templates/refactoring_engineer.json +15 -5
  59. claude_mpm/agents/templates/research.json +47 -22
  60. claude_mpm/agents/templates/response_format.md +583 -0
  61. claude_mpm/agents/templates/ruby-engineer.json +280 -0
  62. claude_mpm/agents/templates/rust_engineer.json +275 -0
  63. claude_mpm/agents/templates/security.json +59 -10
  64. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  65. claude_mpm/agents/templates/tauri_engineer.json +274 -0
  66. claude_mpm/agents/templates/ticketing.json +16 -7
  67. claude_mpm/agents/templates/typescript_engineer.json +285 -0
  68. claude_mpm/agents/templates/validation_templates.md +312 -0
  69. claude_mpm/agents/templates/vercel_ops_agent.json +164 -33
  70. claude_mpm/agents/templates/version_control.json +16 -4
  71. claude_mpm/agents/templates/web_qa.json +243 -21
  72. claude_mpm/agents/templates/web_ui.json +18 -5
  73. claude_mpm/cli/__init__.py +38 -363
  74. claude_mpm/cli/commands/__init__.py +8 -0
  75. claude_mpm/cli/commands/agent_manager.py +675 -20
  76. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  77. claude_mpm/cli/commands/agents.py +722 -150
  78. claude_mpm/cli/commands/agents_detect.py +380 -0
  79. claude_mpm/cli/commands/agents_recommend.py +309 -0
  80. claude_mpm/cli/commands/aggregate.py +10 -6
  81. claude_mpm/cli/commands/analyze.py +553 -0
  82. claude_mpm/cli/commands/analyze_code.py +528 -0
  83. claude_mpm/cli/commands/auto_configure.py +570 -0
  84. claude_mpm/cli/commands/cleanup.py +12 -12
  85. claude_mpm/cli/commands/config.py +47 -13
  86. claude_mpm/cli/commands/configure.py +488 -884
  87. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  88. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  89. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  90. claude_mpm/cli/commands/configure_models.py +18 -0
  91. claude_mpm/cli/commands/configure_navigation.py +167 -0
  92. claude_mpm/cli/commands/configure_paths.py +104 -0
  93. claude_mpm/cli/commands/configure_persistence.py +254 -0
  94. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  95. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  96. claude_mpm/cli/commands/configure_validators.py +73 -0
  97. claude_mpm/cli/commands/dashboard.py +286 -0
  98. claude_mpm/cli/commands/debug.py +1386 -0
  99. claude_mpm/cli/commands/doctor.py +43 -7
  100. claude_mpm/cli/commands/info.py +3 -4
  101. claude_mpm/cli/commands/local_deploy.py +537 -0
  102. claude_mpm/cli/commands/mcp.py +17 -10
  103. claude_mpm/cli/commands/mcp_command_router.py +11 -0
  104. claude_mpm/cli/commands/mcp_config.py +154 -0
  105. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  106. claude_mpm/cli/commands/mcp_install_commands.py +101 -32
  107. claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
  108. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  109. claude_mpm/cli/commands/memory.py +55 -21
  110. claude_mpm/cli/commands/monitor.py +168 -617
  111. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  112. claude_mpm/cli/commands/mpm_init/core.py +525 -0
  113. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  114. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  115. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  116. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  117. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  118. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  119. claude_mpm/cli/commands/run.py +169 -42
  120. claude_mpm/cli/commands/search.py +458 -0
  121. claude_mpm/cli/commands/skills.py +488 -0
  122. claude_mpm/cli/commands/uninstall.py +176 -0
  123. claude_mpm/cli/commands/upgrade.py +152 -0
  124. claude_mpm/cli/commands/verify.py +119 -0
  125. claude_mpm/cli/executor.py +204 -0
  126. claude_mpm/cli/helpers.py +105 -0
  127. claude_mpm/cli/interactive/__init__.py +21 -0
  128. claude_mpm/cli/interactive/agent_wizard.py +962 -0
  129. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  130. claude_mpm/cli/parser.py +79 -2
  131. claude_mpm/cli/parsers/__init__.py +7 -1
  132. claude_mpm/cli/parsers/agent_manager_parser.py +161 -1
  133. claude_mpm/cli/parsers/agents_parser.py +116 -0
  134. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  135. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  136. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  137. claude_mpm/cli/parsers/base_parser.py +187 -3
  138. claude_mpm/cli/parsers/configure_parser.py +34 -15
  139. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  140. claude_mpm/cli/parsers/debug_parser.py +319 -0
  141. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  142. claude_mpm/cli/parsers/mcp_parser.py +15 -0
  143. claude_mpm/cli/parsers/monitor_parser.py +12 -2
  144. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  145. claude_mpm/cli/parsers/run_parser.py +5 -0
  146. claude_mpm/cli/parsers/search_parser.py +245 -0
  147. claude_mpm/cli/parsers/skills_parser.py +137 -0
  148. claude_mpm/cli/shared/argument_patterns.py +20 -13
  149. claude_mpm/cli/shared/base_command.py +2 -2
  150. claude_mpm/cli/shared/output_formatters.py +28 -19
  151. claude_mpm/cli/startup.py +562 -0
  152. claude_mpm/cli/startup_logging.py +179 -13
  153. claude_mpm/cli/utils.py +53 -2
  154. claude_mpm/commands/__init__.py +14 -0
  155. claude_mpm/commands/mpm-agents-detect.md +168 -0
  156. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  157. claude_mpm/commands/mpm-agents.md +122 -0
  158. claude_mpm/commands/mpm-auto-configure.md +269 -0
  159. claude_mpm/commands/mpm-config.md +141 -0
  160. claude_mpm/commands/mpm-doctor.md +24 -0
  161. claude_mpm/commands/mpm-help.md +290 -0
  162. claude_mpm/commands/mpm-init.md +521 -0
  163. claude_mpm/commands/mpm-monitor.md +409 -0
  164. claude_mpm/commands/mpm-organize.md +295 -0
  165. claude_mpm/commands/mpm-resume.md +372 -0
  166. claude_mpm/commands/mpm-status.md +75 -0
  167. claude_mpm/commands/mpm-tickets.md +151 -0
  168. claude_mpm/commands/mpm-version.md +113 -0
  169. claude_mpm/commands/mpm.md +21 -0
  170. claude_mpm/config/agent_config.py +4 -4
  171. claude_mpm/config/experimental_features.py +7 -7
  172. claude_mpm/config/model_config.py +428 -0
  173. claude_mpm/config/paths.py +3 -2
  174. claude_mpm/config/socketio_config.py +36 -7
  175. claude_mpm/constants.py +27 -1
  176. claude_mpm/core/__init__.py +53 -17
  177. claude_mpm/core/agent_name_normalizer.py +3 -2
  178. claude_mpm/core/agent_registry.py +2 -2
  179. claude_mpm/core/agent_session_manager.py +10 -10
  180. claude_mpm/core/api_validator.py +330 -0
  181. claude_mpm/core/base_service.py +33 -23
  182. claude_mpm/core/cache.py +9 -9
  183. claude_mpm/core/claude_runner.py +19 -8
  184. claude_mpm/core/config.py +103 -8
  185. claude_mpm/core/config_aliases.py +7 -6
  186. claude_mpm/core/constants.py +65 -0
  187. claude_mpm/core/container.py +11 -5
  188. claude_mpm/core/enums.py +452 -0
  189. claude_mpm/core/error_handler.py +623 -0
  190. claude_mpm/core/factories.py +1 -1
  191. claude_mpm/core/file_utils.py +764 -0
  192. claude_mpm/core/framework/__init__.py +38 -0
  193. claude_mpm/core/framework/formatters/__init__.py +11 -0
  194. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  195. claude_mpm/core/framework/formatters/content_formatter.py +288 -0
  196. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  197. claude_mpm/core/framework/loaders/__init__.py +13 -0
  198. claude_mpm/core/framework/loaders/agent_loader.py +210 -0
  199. claude_mpm/core/framework/loaders/file_loader.py +223 -0
  200. claude_mpm/core/framework/loaders/instruction_loader.py +161 -0
  201. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  202. claude_mpm/core/framework/processors/__init__.py +11 -0
  203. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  204. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  205. claude_mpm/core/framework/processors/template_processor.py +244 -0
  206. claude_mpm/core/framework_loader.py +323 -1491
  207. claude_mpm/core/hook_manager.py +8 -6
  208. claude_mpm/core/injectable_service.py +11 -8
  209. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  210. claude_mpm/core/interactive_session.py +55 -8
  211. claude_mpm/core/interfaces.py +56 -1
  212. claude_mpm/core/lazy.py +3 -3
  213. claude_mpm/core/log_manager.py +100 -28
  214. claude_mpm/core/logger.py +19 -14
  215. claude_mpm/core/logging_config.py +6 -2
  216. claude_mpm/core/logging_utils.py +520 -0
  217. claude_mpm/core/oneshot_session.py +51 -7
  218. claude_mpm/core/optimized_agent_loader.py +9 -9
  219. claude_mpm/core/optimized_startup.py +1 -1
  220. claude_mpm/core/output_style_manager.py +12 -192
  221. claude_mpm/core/pm_hook_interceptor.py +118 -15
  222. claude_mpm/core/service_registry.py +7 -3
  223. claude_mpm/core/session_manager.py +14 -12
  224. claude_mpm/core/shared/config_loader.py +1 -1
  225. claude_mpm/core/socketio_pool.py +15 -15
  226. claude_mpm/core/tool_access_control.py +3 -2
  227. claude_mpm/core/types.py +4 -11
  228. claude_mpm/core/typing_utils.py +7 -6
  229. claude_mpm/core/unified_agent_registry.py +116 -12
  230. claude_mpm/core/unified_config.py +6 -6
  231. claude_mpm/core/unified_paths.py +23 -20
  232. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
  233. claude_mpm/dashboard/__init__.py +12 -0
  234. claude_mpm/dashboard/analysis_runner.py +455 -0
  235. claude_mpm/dashboard/api/simple_directory.py +261 -0
  236. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
  237. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
  238. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
  239. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
  240. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
  241. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
  242. claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
  243. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
  244. claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
  245. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
  246. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
  247. claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
  248. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
  249. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
  250. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
  251. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
  252. claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
  253. claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
  254. claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
  255. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
  256. claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
  257. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
  258. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  259. claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
  260. claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
  261. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
  262. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
  263. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
  264. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
  265. claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
  266. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
  267. claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
  268. claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
  269. claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
  270. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  271. claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
  272. claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
  273. claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
  274. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  275. claude_mpm/dashboard/static/built/components/file-viewer.js +2 -0
  276. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  277. claude_mpm/dashboard/static/built/components/nav-bar.js +145 -0
  278. claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
  279. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  280. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +2 -0
  281. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  282. claude_mpm/dashboard/static/built/connection-manager.js +536 -0
  283. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  284. claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
  285. claude_mpm/dashboard/static/built/react/events.js +30 -0
  286. claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
  287. claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
  288. claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
  289. claude_mpm/dashboard/static/built/shared/logger.js +385 -0
  290. claude_mpm/dashboard/static/built/shared/page-structure.js +249 -0
  291. claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
  292. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  293. claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
  294. claude_mpm/dashboard/static/css/activity.css +1958 -0
  295. claude_mpm/dashboard/static/css/dashboard.css +1413 -72
  296. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
  297. claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
  298. claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
  299. claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
  300. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  301. claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
  302. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  303. claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
  304. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
  305. claude_mpm/dashboard/static/dist/components/file-viewer.js +2 -0
  306. claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
  307. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  308. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +2 -0
  309. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  310. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  311. claude_mpm/dashboard/static/dist/react/events.js +30 -0
  312. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  313. claude_mpm/dashboard/static/events.html +607 -0
  314. claude_mpm/dashboard/static/index.html +635 -0
  315. claude_mpm/dashboard/static/js/components/activity-tree.js +1871 -0
  316. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
  317. claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
  318. claude_mpm/dashboard/static/js/components/build-tracker.js +23 -13
  319. claude_mpm/dashboard/static/js/components/code-simple.js +857 -0
  320. claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
  321. claude_mpm/dashboard/static/js/components/event-processor.js +3 -107
  322. claude_mpm/dashboard/static/js/components/event-viewer.js +98 -11
  323. claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
  324. claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
  325. claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
  326. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +30 -10
  327. claude_mpm/dashboard/static/js/components/file-viewer.js +580 -0
  328. claude_mpm/dashboard/static/js/components/module-viewer.js +68 -205
  329. claude_mpm/dashboard/static/js/components/session-manager.js +46 -10
  330. claude_mpm/dashboard/static/js/components/socket-manager.js +16 -0
  331. claude_mpm/dashboard/static/js/components/ui-state-manager.js +359 -40
  332. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +1824 -0
  333. claude_mpm/dashboard/static/js/components/working-directory.js +61 -10
  334. claude_mpm/dashboard/static/js/connection-manager.js +1 -1
  335. claude_mpm/dashboard/static/js/dashboard.js +523 -622
  336. claude_mpm/dashboard/static/js/shared/dom-helpers.js +396 -0
  337. claude_mpm/dashboard/static/js/shared/event-bus.js +330 -0
  338. claude_mpm/dashboard/static/js/shared/logger.js +385 -0
  339. claude_mpm/dashboard/static/js/shared/tooltip-service.js +253 -0
  340. claude_mpm/dashboard/static/js/socket-client.js +549 -62
  341. claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
  342. claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
  343. claude_mpm/dashboard/static/legacy/activity.html +736 -0
  344. claude_mpm/dashboard/static/legacy/agents.html +786 -0
  345. claude_mpm/dashboard/static/legacy/files.html +747 -0
  346. claude_mpm/dashboard/static/legacy/tools.html +831 -0
  347. claude_mpm/dashboard/static/monitors.html +431 -0
  348. claude_mpm/dashboard/static/production/events.html +659 -0
  349. claude_mpm/dashboard/static/production/main.html +698 -0
  350. claude_mpm/dashboard/static/production/monitors.html +483 -0
  351. claude_mpm/dashboard/static/socket.io.min.js +7 -0
  352. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
  353. claude_mpm/dashboard/static/test-archive/dashboard.html +635 -0
  354. claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
  355. claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
  356. claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
  357. claude_mpm/dashboard/static/test-archive/test_debug.html +25 -0
  358. claude_mpm/dashboard/templates/code_simple.html +153 -0
  359. claude_mpm/dashboard/templates/index.html +267 -9
  360. claude_mpm/experimental/__init__.py +10 -0
  361. claude_mpm/experimental/cli_enhancements.py +4 -2
  362. claude_mpm/generators/agent_profile_generator.py +5 -3
  363. claude_mpm/hooks/__init__.py +37 -1
  364. claude_mpm/hooks/base_hook.py +5 -4
  365. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  366. claude_mpm/hooks/claude_hooks/event_handlers.py +21 -18
  367. claude_mpm/hooks/claude_hooks/hook_handler.py +209 -25
  368. claude_mpm/hooks/claude_hooks/installer.py +783 -0
  369. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  370. claude_mpm/hooks/claude_hooks/response_tracking.py +57 -17
  371. claude_mpm/hooks/claude_hooks/services/connection_manager.py +64 -49
  372. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +140 -76
  373. claude_mpm/hooks/claude_hooks/services/state_manager.py +11 -9
  374. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  375. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  376. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  377. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  378. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  379. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  380. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  381. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  382. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  383. claude_mpm/hooks/memory_integration_hook.py +1 -1
  384. claude_mpm/hooks/session_resume_hook.py +121 -0
  385. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  386. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  387. claude_mpm/hooks/tool_call_interceptor.py +8 -5
  388. claude_mpm/hooks/validation_hooks.py +3 -3
  389. claude_mpm/init.py +23 -4
  390. claude_mpm/models/agent_session.py +8 -6
  391. claude_mpm/models/resume_log.py +340 -0
  392. claude_mpm/schemas/__init__.py +12 -0
  393. claude_mpm/scripts/claude-hook-handler.sh +187 -0
  394. claude_mpm/scripts/launch_monitor.py +85 -0
  395. claude_mpm/scripts/mcp_server.py +3 -5
  396. claude_mpm/scripts/mpm_doctor.py +3 -2
  397. claude_mpm/scripts/socketio_daemon.py +156 -396
  398. claude_mpm/services/__init__.py +144 -160
  399. claude_mpm/services/agents/__init__.py +18 -5
  400. claude_mpm/services/agents/agent_builder.py +13 -11
  401. claude_mpm/services/agents/auto_config_manager.py +796 -0
  402. claude_mpm/services/agents/deployment/agent_config_provider.py +127 -27
  403. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  404. claude_mpm/services/agents/deployment/agent_deployment.py +38 -15
  405. claude_mpm/services/agents/deployment/agent_discovery_service.py +125 -7
  406. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
  407. claude_mpm/services/agents/deployment/agent_format_converter.py +56 -12
  408. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +4 -2
  409. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  410. claude_mpm/services/agents/deployment/agent_record_service.py +5 -6
  411. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  412. claude_mpm/services/agents/deployment/agent_template_builder.py +722 -37
  413. claude_mpm/services/agents/deployment/agent_validator.py +31 -7
  414. claude_mpm/services/agents/deployment/agent_version_manager.py +9 -1
  415. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  416. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  417. claude_mpm/services/agents/deployment/deployment_config_loader.py +131 -7
  418. claude_mpm/services/agents/deployment/deployment_type_detector.py +10 -14
  419. claude_mpm/services/agents/deployment/deployment_wrapper.py +58 -0
  420. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  421. claude_mpm/services/agents/deployment/local_template_deployment.py +360 -0
  422. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +134 -38
  423. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +8 -7
  424. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  425. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  426. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +7 -5
  427. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  428. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  429. claude_mpm/services/agents/deployment/system_instructions_deployer.py +9 -6
  430. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  431. claude_mpm/services/agents/deployment/validation/template_validator.py +64 -44
  432. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  433. claude_mpm/services/agents/loading/agent_profile_loader.py +10 -9
  434. claude_mpm/services/agents/loading/base_agent_manager.py +16 -6
  435. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -2
  436. claude_mpm/services/agents/local_template_manager.py +744 -0
  437. claude_mpm/services/agents/management/agent_capabilities_generator.py +3 -2
  438. claude_mpm/services/agents/management/agent_management_service.py +5 -5
  439. claude_mpm/services/agents/memory/agent_memory_manager.py +32 -29
  440. claude_mpm/services/agents/memory/content_manager.py +17 -9
  441. claude_mpm/services/agents/memory/memory_categorization_service.py +4 -2
  442. claude_mpm/services/agents/memory/memory_file_service.py +32 -6
  443. claude_mpm/services/agents/memory/memory_format_service.py +7 -7
  444. claude_mpm/services/agents/memory/memory_limits_service.py +4 -2
  445. claude_mpm/services/agents/memory/template_generator.py +3 -3
  446. claude_mpm/services/agents/observers.py +547 -0
  447. claude_mpm/services/agents/recommender.py +615 -0
  448. claude_mpm/services/agents/registry/deployed_agent_discovery.py +3 -3
  449. claude_mpm/services/agents/registry/modification_tracker.py +30 -19
  450. claude_mpm/services/async_session_logger.py +141 -98
  451. claude_mpm/services/claude_session_logger.py +82 -74
  452. claude_mpm/services/cli/agent_cleanup_service.py +6 -5
  453. claude_mpm/services/cli/agent_dependency_service.py +1 -1
  454. claude_mpm/services/cli/agent_listing_service.py +5 -5
  455. claude_mpm/services/cli/agent_validation_service.py +6 -5
  456. claude_mpm/services/cli/memory_crud_service.py +12 -7
  457. claude_mpm/services/cli/memory_output_formatter.py +2 -2
  458. claude_mpm/services/cli/resume_service.py +617 -0
  459. claude_mpm/services/cli/session_manager.py +104 -13
  460. claude_mpm/services/cli/session_pause_manager.py +504 -0
  461. claude_mpm/services/cli/session_resume_helper.py +372 -0
  462. claude_mpm/services/cli/startup_checker.py +13 -21
  463. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  464. claude_mpm/services/command_deployment_service.py +17 -9
  465. claude_mpm/services/command_handler_service.py +11 -5
  466. claude_mpm/services/core/__init__.py +33 -1
  467. claude_mpm/services/core/base.py +26 -11
  468. claude_mpm/services/core/cache_manager.py +1 -3
  469. claude_mpm/services/core/interfaces/__init__.py +90 -3
  470. claude_mpm/services/core/interfaces/agent.py +184 -0
  471. claude_mpm/services/core/interfaces/health.py +172 -0
  472. claude_mpm/services/core/interfaces/model.py +281 -0
  473. claude_mpm/services/core/interfaces/process.py +372 -0
  474. claude_mpm/services/core/interfaces/project.py +121 -0
  475. claude_mpm/services/core/interfaces/restart.py +307 -0
  476. claude_mpm/services/core/interfaces/stability.py +260 -0
  477. claude_mpm/services/core/interfaces.py +56 -1
  478. claude_mpm/services/core/memory_manager.py +92 -47
  479. claude_mpm/services/core/models/__init__.py +79 -0
  480. claude_mpm/services/core/models/agent_config.py +384 -0
  481. claude_mpm/services/core/models/health.py +162 -0
  482. claude_mpm/services/core/models/process.py +239 -0
  483. claude_mpm/services/core/models/restart.py +302 -0
  484. claude_mpm/services/core/models/stability.py +264 -0
  485. claude_mpm/services/core/models/toolchain.py +306 -0
  486. claude_mpm/services/core/path_resolver.py +37 -18
  487. claude_mpm/services/core/service_container.py +2 -2
  488. claude_mpm/services/diagnostics/__init__.py +2 -2
  489. claude_mpm/services/diagnostics/checks/__init__.py +4 -2
  490. claude_mpm/services/diagnostics/checks/agent_check.py +30 -32
  491. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  492. claude_mpm/services/diagnostics/checks/common_issues_check.py +28 -27
  493. claude_mpm/services/diagnostics/checks/configuration_check.py +26 -25
  494. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  495. claude_mpm/services/diagnostics/checks/installation_check.py +165 -60
  496. claude_mpm/services/diagnostics/checks/instructions_check.py +22 -24
  497. claude_mpm/services/diagnostics/checks/mcp_check.py +57 -43
  498. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1066 -0
  499. claude_mpm/services/diagnostics/checks/monitor_check.py +24 -23
  500. claude_mpm/services/diagnostics/checks/startup_log_check.py +14 -11
  501. claude_mpm/services/diagnostics/diagnostic_runner.py +22 -13
  502. claude_mpm/services/diagnostics/doctor_reporter.py +275 -47
  503. claude_mpm/services/diagnostics/models.py +37 -21
  504. claude_mpm/services/event_aggregator.py +5 -3
  505. claude_mpm/services/event_bus/direct_relay.py +152 -13
  506. claude_mpm/services/event_bus/event_bus.py +51 -9
  507. claude_mpm/services/event_bus/relay.py +33 -14
  508. claude_mpm/services/events/consumers/dead_letter.py +7 -5
  509. claude_mpm/services/events/core.py +5 -6
  510. claude_mpm/services/events/producers/hook.py +6 -6
  511. claude_mpm/services/events/producers/system.py +8 -8
  512. claude_mpm/services/exceptions.py +5 -5
  513. claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
  514. claude_mpm/services/framework_claude_md_generator/content_assembler.py +5 -5
  515. claude_mpm/services/framework_claude_md_generator/content_validator.py +2 -2
  516. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
  517. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  518. claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
  519. claude_mpm/services/hook_installer_service.py +506 -0
  520. claude_mpm/services/hook_service.py +5 -6
  521. claude_mpm/services/infrastructure/context_preservation.py +13 -11
  522. claude_mpm/services/infrastructure/daemon_manager.py +9 -9
  523. claude_mpm/services/infrastructure/logging.py +2 -2
  524. claude_mpm/services/infrastructure/monitoring/__init__.py +12 -12
  525. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  526. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  527. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  528. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  529. claude_mpm/services/infrastructure/monitoring/resources.py +8 -7
  530. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  531. claude_mpm/services/infrastructure/monitoring.py +12 -12
  532. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  533. claude_mpm/services/local_ops/__init__.py +165 -0
  534. claude_mpm/services/local_ops/crash_detector.py +257 -0
  535. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  536. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  537. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  538. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  539. claude_mpm/services/local_ops/health_manager.py +430 -0
  540. claude_mpm/services/local_ops/log_monitor.py +396 -0
  541. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  542. claude_mpm/services/local_ops/process_manager.py +595 -0
  543. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  544. claude_mpm/services/local_ops/restart_manager.py +401 -0
  545. claude_mpm/services/local_ops/restart_policy.py +387 -0
  546. claude_mpm/services/local_ops/state_manager.py +372 -0
  547. claude_mpm/services/local_ops/unified_manager.py +600 -0
  548. claude_mpm/services/mcp_config_manager.py +1612 -0
  549. claude_mpm/services/mcp_gateway/__init__.py +97 -93
  550. claude_mpm/services/mcp_gateway/auto_configure.py +43 -38
  551. claude_mpm/services/mcp_gateway/config/config_loader.py +3 -3
  552. claude_mpm/services/mcp_gateway/config/configuration.py +23 -4
  553. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  554. claude_mpm/services/mcp_gateway/core/base.py +20 -33
  555. claude_mpm/services/mcp_gateway/core/process_pool.py +585 -31
  556. claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
  557. claude_mpm/services/mcp_gateway/core/startup_verification.py +3 -3
  558. claude_mpm/services/mcp_gateway/main.py +90 -15
  559. claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
  560. claude_mpm/services/mcp_gateway/registry/tool_registry.py +12 -9
  561. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  562. claude_mpm/services/mcp_gateway/server/stdio_server.py +9 -15
  563. claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
  564. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  565. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +10 -9
  566. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +654 -0
  567. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +36 -34
  568. claude_mpm/services/mcp_gateway/tools/hello_world.py +8 -8
  569. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +551 -0
  570. claude_mpm/services/mcp_gateway/utils/__init__.py +14 -0
  571. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +160 -0
  572. claude_mpm/services/mcp_gateway/utils/update_preferences.py +170 -0
  573. claude_mpm/services/mcp_service_verifier.py +729 -0
  574. claude_mpm/services/memory/builder.py +9 -8
  575. claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
  576. claude_mpm/services/memory/cache/simple_cache.py +2 -2
  577. claude_mpm/services/memory/failure_tracker.py +578 -0
  578. claude_mpm/services/memory/indexed_memory.py +8 -8
  579. claude_mpm/services/memory/optimizer.py +8 -9
  580. claude_mpm/services/memory/router.py +3 -3
  581. claude_mpm/services/memory_hook_service.py +165 -4
  582. claude_mpm/services/model/__init__.py +147 -0
  583. claude_mpm/services/model/base_provider.py +365 -0
  584. claude_mpm/services/model/claude_provider.py +412 -0
  585. claude_mpm/services/model/model_router.py +453 -0
  586. claude_mpm/services/model/ollama_provider.py +415 -0
  587. claude_mpm/services/monitor/__init__.py +20 -0
  588. claude_mpm/services/monitor/daemon.py +671 -0
  589. claude_mpm/services/monitor/daemon_manager.py +963 -0
  590. claude_mpm/services/monitor/event_emitter.py +350 -0
  591. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  592. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  593. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  594. claude_mpm/services/monitor/handlers/file.py +264 -0
  595. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  596. claude_mpm/services/monitor/management/__init__.py +18 -0
  597. claude_mpm/services/monitor/management/health.py +124 -0
  598. claude_mpm/services/monitor/management/lifecycle.py +724 -0
  599. claude_mpm/services/monitor/server.py +817 -0
  600. claude_mpm/services/monitor_build_service.py +2 -2
  601. claude_mpm/services/native_agent_converter.py +356 -0
  602. claude_mpm/services/orphan_detection.py +786 -0
  603. claude_mpm/services/port_manager.py +2 -2
  604. claude_mpm/services/project/__init__.py +23 -0
  605. claude_mpm/services/project/analyzer.py +3 -3
  606. claude_mpm/services/project/architecture_analyzer.py +6 -6
  607. claude_mpm/services/project/archive_manager.py +1045 -0
  608. claude_mpm/services/project/dependency_analyzer.py +8 -8
  609. claude_mpm/services/project/detection_strategies.py +719 -0
  610. claude_mpm/services/project/documentation_manager.py +553 -0
  611. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  612. claude_mpm/services/project/language_analyzer.py +3 -3
  613. claude_mpm/services/project/metrics_collector.py +7 -10
  614. claude_mpm/services/project/project_organizer.py +1005 -0
  615. claude_mpm/services/project/registry.py +13 -7
  616. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  617. claude_mpm/services/project_port_allocator.py +596 -0
  618. claude_mpm/services/response_tracker.py +21 -10
  619. claude_mpm/services/runner_configuration_service.py +1 -0
  620. claude_mpm/services/self_upgrade_service.py +500 -0
  621. claude_mpm/services/session_management_service.py +7 -5
  622. claude_mpm/services/session_manager.py +380 -0
  623. claude_mpm/services/shared/__init__.py +2 -1
  624. claude_mpm/services/shared/async_service_base.py +16 -27
  625. claude_mpm/services/shared/config_service_base.py +17 -14
  626. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  627. claude_mpm/services/shared/service_factory.py +8 -5
  628. claude_mpm/services/socketio/client_proxy.py +60 -5
  629. claude_mpm/services/socketio/dashboard_server.py +361 -0
  630. claude_mpm/services/socketio/event_normalizer.py +74 -6
  631. claude_mpm/services/socketio/handlers/__init__.py +5 -0
  632. claude_mpm/services/socketio/handlers/base.py +2 -2
  633. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  634. claude_mpm/services/socketio/handlers/connection.py +21 -40
  635. claude_mpm/services/socketio/handlers/connection_handler.py +16 -28
  636. claude_mpm/services/socketio/handlers/file.py +46 -10
  637. claude_mpm/services/socketio/handlers/git.py +8 -8
  638. claude_mpm/services/socketio/handlers/hook.py +29 -17
  639. claude_mpm/services/socketio/handlers/registry.py +4 -0
  640. claude_mpm/services/socketio/monitor_client.py +364 -0
  641. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  642. claude_mpm/services/socketio/server/connection_manager.py +131 -68
  643. claude_mpm/services/socketio/server/core.py +275 -22
  644. claude_mpm/services/socketio/server/eventbus_integration.py +20 -14
  645. claude_mpm/services/socketio/server/main.py +99 -29
  646. claude_mpm/services/socketio_client_manager.py +4 -4
  647. claude_mpm/services/subprocess_launcher_service.py +19 -15
  648. claude_mpm/services/system_instructions_service.py +2 -2
  649. claude_mpm/services/ticket_services/formatter_service.py +1 -1
  650. claude_mpm/services/ticket_services/validation_service.py +5 -5
  651. claude_mpm/services/unified/__init__.py +65 -0
  652. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  653. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  654. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  655. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +903 -0
  656. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +746 -0
  657. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  658. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  659. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  660. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  661. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  662. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  663. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  664. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  665. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  666. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  667. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  668. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  669. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  670. claude_mpm/services/unified/deployment_strategies/vercel.py +475 -0
  671. claude_mpm/services/unified/interfaces.py +475 -0
  672. claude_mpm/services/unified/migration.py +509 -0
  673. claude_mpm/services/unified/strategies.py +534 -0
  674. claude_mpm/services/unified/unified_analyzer.py +542 -0
  675. claude_mpm/services/unified/unified_config.py +691 -0
  676. claude_mpm/services/unified/unified_deployment.py +470 -0
  677. claude_mpm/services/utility_service.py +6 -3
  678. claude_mpm/services/version_control/branch_strategy.py +2 -2
  679. claude_mpm/services/version_control/conflict_resolution.py +8 -4
  680. claude_mpm/services/version_control/git_operations.py +26 -24
  681. claude_mpm/services/version_control/semantic_versioning.py +14 -14
  682. claude_mpm/services/version_control/version_parser.py +14 -11
  683. claude_mpm/services/version_service.py +104 -1
  684. claude_mpm/services/visualization/__init__.py +19 -0
  685. claude_mpm/services/visualization/mermaid_generator.py +938 -0
  686. claude_mpm/skills/__init__.py +42 -0
  687. claude_mpm/skills/agent_skills_injector.py +324 -0
  688. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  689. claude_mpm/skills/bundled/__init__.py +6 -0
  690. claude_mpm/skills/bundled/api-documentation.md +393 -0
  691. claude_mpm/skills/bundled/async-testing.md +571 -0
  692. claude_mpm/skills/bundled/code-review.md +143 -0
  693. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  694. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  695. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  696. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  697. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  698. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  699. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  700. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  701. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  702. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  703. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  704. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  705. claude_mpm/skills/bundled/database-migration.md +199 -0
  706. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  707. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  708. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  709. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  710. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  711. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  712. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  713. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  714. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  715. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  716. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  717. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  718. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  719. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  720. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  721. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  722. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  723. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  724. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  725. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  726. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  727. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  728. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  729. claude_mpm/skills/bundled/git-workflow.md +414 -0
  730. claude_mpm/skills/bundled/imagemagick.md +204 -0
  731. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  732. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  733. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  734. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  735. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  736. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  737. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  738. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  739. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  740. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  741. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  742. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  743. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  744. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  745. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  746. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  747. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  748. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  749. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  750. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  751. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  752. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  753. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  754. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  755. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  756. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  757. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  758. claude_mpm/skills/bundled/pdf.md +141 -0
  759. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  760. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  761. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  762. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  763. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  764. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  765. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  766. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  767. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  768. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  769. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  770. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  771. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  772. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  773. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  774. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  775. claude_mpm/skills/bundled/security-scanning.md +327 -0
  776. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  777. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  778. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  779. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  780. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  781. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  782. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  783. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  784. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  785. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  786. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  787. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  788. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  789. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  790. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  791. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  792. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  793. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  794. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  795. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  796. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  797. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  798. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  799. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  800. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  801. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  802. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  803. claude_mpm/skills/bundled/xlsx.md +157 -0
  804. claude_mpm/skills/registry.py +286 -0
  805. claude_mpm/skills/skill_manager.py +310 -0
  806. claude_mpm/skills/skills_registry.py +348 -0
  807. claude_mpm/skills/skills_service.py +739 -0
  808. claude_mpm/storage/state_storage.py +31 -31
  809. claude_mpm/tools/__init__.py +10 -0
  810. claude_mpm/tools/__main__.py +208 -0
  811. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  812. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  813. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  814. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  815. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  816. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  817. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  818. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  819. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  820. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  821. claude_mpm/tools/code_tree_builder.py +631 -0
  822. claude_mpm/tools/code_tree_events.py +420 -0
  823. claude_mpm/tools/socketio_debug.py +671 -0
  824. claude_mpm/utils/agent_dependency_loader.py +108 -27
  825. claude_mpm/utils/common.py +544 -0
  826. claude_mpm/utils/config_manager.py +12 -6
  827. claude_mpm/utils/database_connector.py +298 -0
  828. claude_mpm/utils/dependency_cache.py +2 -2
  829. claude_mpm/utils/dependency_strategies.py +15 -10
  830. claude_mpm/utils/display_helper.py +260 -0
  831. claude_mpm/utils/environment_context.py +4 -3
  832. claude_mpm/utils/error_handler.py +5 -3
  833. claude_mpm/utils/file_utils.py +13 -14
  834. claude_mpm/utils/git_analyzer.py +407 -0
  835. claude_mpm/utils/log_cleanup.py +627 -0
  836. claude_mpm/utils/path_operations.py +7 -4
  837. claude_mpm/utils/robust_installer.py +133 -24
  838. claude_mpm/utils/session_logging.py +2 -2
  839. claude_mpm/utils/subprocess_utils.py +9 -8
  840. claude_mpm/validation/agent_validator.py +6 -6
  841. claude_mpm/validation/frontmatter_validator.py +6 -6
  842. claude_mpm-4.24.0.dist-info/METADATA +675 -0
  843. claude_mpm-4.24.0.dist-info/RECORD +1018 -0
  844. {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/entry_points.txt +1 -0
  845. claude_mpm/agents/INSTRUCTIONS.md +0 -237
  846. claude_mpm/agents/schema/agent_schema.json +0 -314
  847. claude_mpm/agents/templates/agent-manager.md +0 -304
  848. claude_mpm/cli/commands/configure_tui.py +0 -1921
  849. claude_mpm/cli/commands/socketio_monitor.py +0 -233
  850. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  851. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1040
  852. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  853. claude_mpm/scripts/socketio_daemon_hardened.py +0 -937
  854. claude_mpm/scripts/socketio_server_manager.py +0 -349
  855. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  856. claude_mpm/services/cli/dashboard_launcher.py +0 -424
  857. claude_mpm/services/cli/socketio_manager.py +0 -498
  858. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +0 -286
  859. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  860. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  861. claude_mpm/services/project/analyzer_refactored.py +0 -450
  862. claude_mpm-4.1.6.dist-info/METADATA +0 -325
  863. claude_mpm-4.1.6.dist-info/RECORD +0 -550
  864. {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/WHEEL +0 -0
  865. {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/licenses/LICENSE +0 -0
  866. {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/top_level.txt +0 -0
@@ -1,31 +1,37 @@
1
- """Framework loader for Claude MPM."""
1
+ """Framework loader for Claude MPM - Refactored modular version."""
2
2
 
3
- import logging
4
- import time
5
- from datetime import datetime
3
+ import asyncio
4
+ import os
6
5
  from pathlib import Path
7
- from typing import Any, Dict, Optional
8
-
9
- # Import resource handling for packaged installations
10
- try:
11
- # Python 3.9+
12
- from importlib.resources import files
13
- except ImportError:
14
- # Python 3.8 fallback
15
- try:
16
- from importlib_resources import files
17
- except ImportError:
18
- # Final fallback for development environments
19
- files = None
20
-
21
- from ..utils.imports import safe_import
6
+ from typing import Any, Dict, List, Optional, Set
7
+
8
+ # Import framework components
9
+ from claude_mpm.core.framework import (
10
+ AgentLoader,
11
+ CapabilityGenerator,
12
+ ContentFormatter,
13
+ ContextGenerator,
14
+ FileLoader,
15
+ InstructionLoader,
16
+ MemoryProcessor,
17
+ MetadataProcessor,
18
+ PackagedLoader,
19
+ TemplateProcessor,
20
+ )
21
+ from claude_mpm.core.logging_utils import get_logger
22
+ from claude_mpm.utils.imports import safe_import
22
23
 
23
- # Import with fallback support - using absolute imports as primary since we're at module level
24
- get_logger = safe_import("claude_mpm.core.logger", "core.logger", ["get_logger"])
24
+ # Import with fallback support
25
25
  AgentRegistryAdapter = safe_import(
26
26
  "claude_mpm.core.agent_registry", "core.agent_registry", ["AgentRegistryAdapter"]
27
27
  )
28
28
 
29
+ # Import API validator
30
+ try:
31
+ from claude_mpm.core.api_validator import validate_api_keys
32
+ except ImportError:
33
+ from ..core.api_validator import validate_api_keys
34
+
29
35
  # Import the service container and interfaces
30
36
  try:
31
37
  from claude_mpm.services.core.cache_manager import CacheManager
@@ -57,43 +63,13 @@ class FrameworkLoader:
57
63
  """
58
64
  Load and prepare framework instructions for injection.
59
65
 
60
- This component handles:
61
- 1. Finding the framework (claude-multiagent-pm)
62
- 2. Loading custom instructions from .claude-mpm/ directories
63
- 3. Preparing agent definitions
64
- 4. Formatting for injection
65
-
66
- Custom Instructions Loading:
67
- The framework loader supports custom instructions through .claude-mpm/ directories.
68
- It NEVER reads from .claude/ directories to avoid conflicts with Claude Code.
69
-
70
- File Loading Precedence (highest to lowest):
71
-
72
- INSTRUCTIONS.md:
73
- 1. Project: ./.claude-mpm/INSTRUCTIONS.md
74
- 2. User: ~/.claude-mpm/INSTRUCTIONS.md
75
- 3. System: (built-in framework instructions)
76
-
77
- WORKFLOW.md:
78
- 1. Project: ./.claude-mpm/WORKFLOW.md
79
- 2. User: ~/.claude-mpm/WORKFLOW.md
80
- 3. System: src/claude_mpm/agents/WORKFLOW.md
81
-
82
- MEMORY.md:
83
- 1. Project: ./.claude-mpm/MEMORY.md
84
- 2. User: ~/.claude-mpm/MEMORY.md
85
- 3. System: src/claude_mpm/agents/MEMORY.md
86
-
87
- Actual Memories:
88
- - User: ~/.claude-mpm/memories/PM_memories.md
89
- - Project: ./.claude-mpm/memories/PM_memories.md (overrides user)
90
- - Agent memories: *_memories.md files (only loaded if agent is deployed)
91
-
92
- Important Notes:
93
- - Project-level files always override user-level files
94
- - User-level files always override system defaults
95
- - The framework NEVER reads from .claude/ directories
96
- - Custom instructions are clearly labeled with their source level
66
+ This refactored version uses modular components for better maintainability
67
+ and testability while maintaining backward compatibility.
68
+
69
+ Components:
70
+ - Loaders: Handle file I/O and resource loading
71
+ - Formatters: Generate and format content sections
72
+ - Processors: Process metadata, templates, and memories
97
73
  """
98
74
 
99
75
  def __init__(
@@ -101,35 +77,80 @@ class FrameworkLoader:
101
77
  framework_path: Optional[Path] = None,
102
78
  agents_dir: Optional[Path] = None,
103
79
  service_container: Optional[ServiceContainer] = None,
80
+ config: Optional[Dict[str, Any]] = None,
104
81
  ):
105
82
  """
106
- Initialize framework loader.
83
+ Initialize framework loader with modular components.
107
84
 
108
85
  Args:
109
86
  framework_path: Explicit path to framework (auto-detected if None)
110
87
  agents_dir: Custom agents directory (overrides framework agents)
111
88
  service_container: Optional service container for dependency injection
89
+ config: Optional configuration dictionary for API validation and other settings
112
90
  """
113
91
  self.logger = get_logger("framework_loader")
114
92
  self.agents_dir = agents_dir
115
93
  self.framework_version = None
116
94
  self.framework_last_modified = None
95
+ self.config = config or {}
96
+
97
+ # Validate API keys on startup (before any other initialization)
98
+ self._validate_api_keys()
117
99
 
118
- # Use provided container or get global container
100
+ # Initialize service container
119
101
  self.container = service_container or get_global_container()
102
+ self._register_services()
103
+
104
+ # Resolve services from container
105
+ self._cache_manager = self.container.resolve(ICacheManager)
106
+ self._path_resolver = self.container.resolve(IPathResolver)
107
+ self._memory_manager = self.container.resolve(IMemoryManager)
108
+
109
+ # Initialize framework path
110
+ self.framework_path = (
111
+ framework_path or self._path_resolver.detect_framework_path()
112
+ )
113
+
114
+ # Initialize modular components
115
+ self._init_components()
116
+
117
+ # Keep cache TTL constants for backward compatibility
118
+ self._init_cache_ttl()
119
+
120
+ # Load framework content
121
+ self.framework_content = self._load_framework_content()
122
+
123
+ # Initialize agent registry
124
+ self.agent_registry = AgentRegistryAdapter(self.framework_path)
120
125
 
121
- # Register services if not already registered
126
+ # Output style manager (deferred initialization)
127
+ self.output_style_manager = None
128
+
129
+ def _validate_api_keys(self) -> None:
130
+ """Validate API keys if enabled in config."""
131
+ if self.config.get("validate_api_keys", True):
132
+ try:
133
+ self.logger.info("Validating configured API keys...")
134
+ validate_api_keys(config=self.config, strict=True)
135
+ self.logger.info("✅ API key validation completed successfully")
136
+ except ValueError as e:
137
+ self.logger.error(f"❌ API key validation failed: {e}")
138
+ raise
139
+ except Exception as e:
140
+ self.logger.error(f"❌ Unexpected error during API validation: {e}")
141
+ raise
142
+
143
+ def _register_services(self) -> None:
144
+ """Register services in the container if not already registered."""
122
145
  if not self.container.is_registered(ICacheManager):
123
- self.container.register(ICacheManager, CacheManager, True) # singleton=True
146
+ self.container.register(ICacheManager, CacheManager, True)
124
147
 
125
148
  if not self.container.is_registered(IPathResolver):
126
- # PathResolver depends on CacheManager, so resolve it first
127
149
  cache_manager = self.container.resolve(ICacheManager)
128
150
  path_resolver = PathResolver(cache_manager=cache_manager)
129
151
  self.container.register_instance(IPathResolver, path_resolver)
130
152
 
131
153
  if not self.container.is_registered(IMemoryManager):
132
- # MemoryManager depends on both CacheManager and PathResolver
133
154
  cache_manager = self.container.resolve(ICacheManager)
134
155
  path_resolver = self.container.resolve(IPathResolver)
135
156
  memory_manager = MemoryManager(
@@ -137,18 +158,26 @@ class FrameworkLoader:
137
158
  )
138
159
  self.container.register_instance(IMemoryManager, memory_manager)
139
160
 
140
- # Resolve services from container
141
- self._cache_manager = self.container.resolve(ICacheManager)
142
- self._path_resolver = self.container.resolve(IPathResolver)
143
- self._memory_manager = self.container.resolve(IMemoryManager)
144
-
145
- # Initialize framework path using PathResolver
146
- self.framework_path = (
147
- framework_path or self._path_resolver.detect_framework_path()
148
- )
149
-
150
- # Keep TTL constants for backward compatibility
151
- # These are implementation-specific, so we use defaults if not available
161
+ def _init_components(self) -> None:
162
+ """Initialize modular components."""
163
+ # Loaders
164
+ self.file_loader = FileLoader()
165
+ self.packaged_loader = PackagedLoader()
166
+ self.instruction_loader = InstructionLoader(self.framework_path)
167
+ self.agent_loader = AgentLoader(self.framework_path)
168
+
169
+ # Formatters
170
+ self.content_formatter = ContentFormatter()
171
+ self.capability_generator = CapabilityGenerator()
172
+ self.context_generator = ContextGenerator()
173
+
174
+ # Processors
175
+ self.metadata_processor = MetadataProcessor()
176
+ self.template_processor = TemplateProcessor(self.framework_path)
177
+ self.memory_processor = MemoryProcessor()
178
+
179
+ def _init_cache_ttl(self) -> None:
180
+ """Initialize cache TTL constants for backward compatibility."""
152
181
  if hasattr(self._cache_manager, "capabilities_ttl"):
153
182
  self.CAPABILITIES_CACHE_TTL = self._cache_manager.capabilities_ttl
154
183
  self.DEPLOYED_AGENTS_CACHE_TTL = self._cache_manager.deployed_agents_ttl
@@ -161,430 +190,24 @@ class FrameworkLoader:
161
190
  self.METADATA_CACHE_TTL = 60
162
191
  self.MEMORIES_CACHE_TTL = 60
163
192
 
164
- self.framework_content = self._load_framework_content()
165
-
166
- # Initialize agent registry
167
- self.agent_registry = AgentRegistryAdapter(self.framework_path)
168
-
169
- # Initialize output style manager (must be after content is loaded)
170
- self.output_style_manager = None
171
- # Defer initialization until first use to ensure content is loaded
193
+ # === Cache Management Methods (backward compatibility) ===
172
194
 
173
195
  def clear_all_caches(self) -> None:
174
196
  """Clear all caches to force reload on next access."""
175
197
  self._cache_manager.clear_all()
176
198
 
177
199
  def clear_agent_caches(self) -> None:
178
- """Clear agent-related caches (capabilities, deployed agents, metadata)."""
200
+ """Clear agent-related caches."""
179
201
  self._cache_manager.clear_agent_caches()
180
202
 
181
203
  def clear_memory_caches(self) -> None:
182
204
  """Clear memory-related caches."""
183
205
  self._cache_manager.clear_memory_caches()
184
206
 
185
- def _initialize_output_style(self) -> None:
186
- """Initialize output style management and deploy if applicable."""
187
- try:
188
- from claude_mpm.core.output_style_manager import OutputStyleManager
189
-
190
- self.output_style_manager = OutputStyleManager()
191
-
192
- # Log detailed output style status
193
- self._log_output_style_status()
194
-
195
- # Extract and save output style content (pass self to reuse loaded content)
196
- output_style_content = (
197
- self.output_style_manager.extract_output_style_content(
198
- framework_loader=self
199
- )
200
- )
201
- self.output_style_manager.save_output_style(output_style_content)
202
-
203
- # Deploy to Claude Code if supported
204
- deployed = self.output_style_manager.deploy_output_style(
205
- output_style_content
206
- )
207
-
208
- if deployed:
209
- self.logger.info("✅ Output style deployed to Claude Code >= 1.0.83")
210
- else:
211
- self.logger.info(
212
- "📝 Output style will be injected into instructions for older Claude versions"
213
- )
214
-
215
- except Exception as e:
216
- self.logger.warning(f"❌ Failed to initialize output style manager: {e}")
217
- # Continue without output style management
218
-
219
- def _log_output_style_status(self) -> None:
220
- """Log comprehensive output style status information."""
221
- if not self.output_style_manager:
222
- return
223
-
224
- # Claude version detection
225
- claude_version = self.output_style_manager.claude_version
226
- if claude_version:
227
- self.logger.info(f"Claude Code version detected: {claude_version}")
228
-
229
- # Check if version supports output styles
230
- if self.output_style_manager.supports_output_styles():
231
- self.logger.info("✅ Claude Code supports output styles (>= 1.0.83)")
232
-
233
- # Check deployment status
234
- output_style_path = self.output_style_manager.output_style_path
235
- if output_style_path.exists():
236
- self.logger.info(
237
- f"📁 Output style file exists: {output_style_path}"
238
- )
239
- else:
240
- self.logger.info(
241
- f"📝 Output style will be created at: {output_style_path}"
242
- )
243
-
244
- else:
245
- self.logger.info(
246
- f"⚠️ Claude Code {claude_version} does not support output styles (< 1.0.83)"
247
- )
248
- self.logger.info(
249
- "📝 Output style content will be injected into framework instructions"
250
- )
251
- else:
252
- self.logger.info("⚠️ Claude Code not detected or version unknown")
253
- self.logger.info(
254
- "📝 Output style content will be injected into framework instructions as fallback"
255
- )
256
-
257
- def _try_load_file(self, file_path: Path, file_type: str) -> Optional[str]:
258
- """
259
- Try to load a file with error handling.
260
-
261
- Args:
262
- file_path: Path to the file to load
263
- file_type: Description of file type for logging
264
-
265
- Returns:
266
- File content if successful, None otherwise
267
- """
268
- try:
269
- content = file_path.read_text()
270
- if hasattr(self.logger, "level") and self.logger.level <= logging.INFO:
271
- self.logger.info(f"Loaded {file_type} from: {file_path}")
272
-
273
- # Extract metadata if present
274
- import re
275
-
276
- version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
277
- if version_match:
278
- version = version_match.group(
279
- 1
280
- ) # Keep as string to preserve leading zeros
281
- self.logger.info(f"Framework version: {version}")
282
- # Store framework version if this is the main INSTRUCTIONS.md
283
- if "INSTRUCTIONS.md" in str(file_path):
284
- self.framework_version = version
285
-
286
- # Extract modification timestamp
287
- timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
288
- if timestamp_match:
289
- timestamp = timestamp_match.group(1).strip()
290
- self.logger.info(f"Last modified: {timestamp}")
291
- # Store timestamp if this is the main INSTRUCTIONS.md
292
- if "INSTRUCTIONS.md" in str(file_path):
293
- self.framework_last_modified = timestamp
294
-
295
- return content
296
- except Exception as e:
297
- if hasattr(self.logger, "level") and self.logger.level <= logging.ERROR:
298
- self.logger.error(f"Failed to load {file_type}: {e}")
299
- return None
300
-
301
- def _load_instructions_file(self, content: Dict[str, Any]) -> None:
302
- """
303
- Load custom INSTRUCTIONS.md from .claude-mpm directories.
304
-
305
- Precedence (highest to lowest):
306
- 1. Project-specific: ./.claude-mpm/INSTRUCTIONS.md
307
- 2. User-specific: ~/.claude-mpm/INSTRUCTIONS.md
308
-
309
- NOTE: We do NOT load CLAUDE.md files since Claude Code already picks them up automatically.
310
- This prevents duplication of instructions.
311
-
312
- Args:
313
- content: Dictionary to update with loaded instructions
314
- """
315
- # Check for project-specific INSTRUCTIONS.md first
316
- project_instructions_path = Path.cwd() / ".claude-mpm" / "INSTRUCTIONS.md"
317
- if project_instructions_path.exists():
318
- loaded_content = self._try_load_file(
319
- project_instructions_path, "project-specific INSTRUCTIONS.md"
320
- )
321
- if loaded_content:
322
- content["custom_instructions"] = loaded_content
323
- content["custom_instructions_level"] = "project"
324
- self.logger.info(
325
- "Using project-specific PM instructions from .claude-mpm/INSTRUCTIONS.md"
326
- )
327
- return
328
-
329
- # Check for user-specific INSTRUCTIONS.md
330
- user_instructions_path = Path.home() / ".claude-mpm" / "INSTRUCTIONS.md"
331
- if user_instructions_path.exists():
332
- loaded_content = self._try_load_file(
333
- user_instructions_path, "user-specific INSTRUCTIONS.md"
334
- )
335
- if loaded_content:
336
- content["custom_instructions"] = loaded_content
337
- content["custom_instructions_level"] = "user"
338
- self.logger.info(
339
- "Using user-specific PM instructions from ~/.claude-mpm/INSTRUCTIONS.md"
340
- )
341
- return
342
-
343
- def _load_workflow_instructions(self, content: Dict[str, Any]) -> None:
344
- """
345
- Load WORKFLOW.md from .claude-mpm directories.
346
-
347
- Precedence (highest to lowest):
348
- 1. Project-specific: ./.claude-mpm/WORKFLOW.md
349
- 2. User-specific: ~/.claude-mpm/WORKFLOW.md
350
- 3. System default: src/claude_mpm/agents/WORKFLOW.md or packaged
351
-
352
- NOTE: We do NOT load from .claude/ directories to avoid conflicts.
353
-
354
- Args:
355
- content: Dictionary to update with workflow instructions
356
- """
357
- # Check for project-specific WORKFLOW.md first (highest priority)
358
- project_workflow_path = Path.cwd() / ".claude-mpm" / "WORKFLOW.md"
359
- if project_workflow_path.exists():
360
- loaded_content = self._try_load_file(
361
- project_workflow_path, "project-specific WORKFLOW.md"
362
- )
363
- if loaded_content:
364
- content["workflow_instructions"] = loaded_content
365
- content["workflow_instructions_level"] = "project"
366
- self.logger.info(
367
- "Using project-specific workflow instructions from .claude-mpm/WORKFLOW.md"
368
- )
369
- return
370
-
371
- # Check for user-specific WORKFLOW.md (medium priority)
372
- user_workflow_path = Path.home() / ".claude-mpm" / "WORKFLOW.md"
373
- if user_workflow_path.exists():
374
- loaded_content = self._try_load_file(
375
- user_workflow_path, "user-specific WORKFLOW.md"
376
- )
377
- if loaded_content:
378
- content["workflow_instructions"] = loaded_content
379
- content["workflow_instructions_level"] = "user"
380
- self.logger.info(
381
- "Using user-specific workflow instructions from ~/.claude-mpm/WORKFLOW.md"
382
- )
383
- return
384
-
385
- # Fall back to system workflow (lowest priority)
386
- if self.framework_path and self.framework_path != Path("__PACKAGED__"):
387
- system_workflow_path = (
388
- self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
389
- )
390
- if system_workflow_path.exists():
391
- loaded_content = self._try_load_file(
392
- system_workflow_path, "system WORKFLOW.md"
393
- )
394
- if loaded_content:
395
- content["workflow_instructions"] = loaded_content
396
- content["workflow_instructions_level"] = "system"
397
- self.logger.info("Using system workflow instructions")
398
-
399
- def _load_memory_instructions(self, content: Dict[str, Any]) -> None:
400
- """
401
- Load MEMORY.md from .claude-mpm directories.
402
-
403
- Precedence (highest to lowest):
404
- 1. Project-specific: ./.claude-mpm/MEMORY.md
405
- 2. User-specific: ~/.claude-mpm/MEMORY.md
406
- 3. System default: src/claude_mpm/agents/MEMORY.md or packaged
407
-
408
- NOTE: We do NOT load from .claude/ directories to avoid conflicts.
409
-
410
- Args:
411
- content: Dictionary to update with memory instructions
412
- """
413
- # Check for project-specific MEMORY.md first (highest priority)
414
- project_memory_path = Path.cwd() / ".claude-mpm" / "MEMORY.md"
415
- if project_memory_path.exists():
416
- loaded_content = self._try_load_file(
417
- project_memory_path, "project-specific MEMORY.md"
418
- )
419
- if loaded_content:
420
- content["memory_instructions"] = loaded_content
421
- content["memory_instructions_level"] = "project"
422
- self.logger.info(
423
- "Using project-specific memory instructions from .claude-mpm/MEMORY.md"
424
- )
425
- return
426
-
427
- # Check for user-specific MEMORY.md (medium priority)
428
- user_memory_path = Path.home() / ".claude-mpm" / "MEMORY.md"
429
- if user_memory_path.exists():
430
- loaded_content = self._try_load_file(
431
- user_memory_path, "user-specific MEMORY.md"
432
- )
433
- if loaded_content:
434
- content["memory_instructions"] = loaded_content
435
- content["memory_instructions_level"] = "user"
436
- self.logger.info(
437
- "Using user-specific memory instructions from ~/.claude-mpm/MEMORY.md"
438
- )
439
- return
440
-
441
- # Fall back to system memory instructions (lowest priority)
442
- if self.framework_path and self.framework_path != Path("__PACKAGED__"):
443
- system_memory_path = (
444
- self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
445
- )
446
- if system_memory_path.exists():
447
- loaded_content = self._try_load_file(
448
- system_memory_path, "system MEMORY.md"
449
- )
450
- if loaded_content:
451
- content["memory_instructions"] = loaded_content
452
- content["memory_instructions_level"] = "system"
453
- self.logger.info("Using system memory instructions")
454
-
455
- def _get_deployed_agents(self) -> set:
456
- """
457
- Get a set of deployed agent names from .claude/agents/ directories.
458
- Uses caching to avoid repeated filesystem scans.
459
-
460
- Returns:
461
- Set of agent names (file stems) that are deployed
462
- """
463
- # Try to get from cache first
464
- cached = self._cache_manager.get_deployed_agents()
465
- if cached is not None:
466
- return cached
467
-
468
- # Cache miss or expired - perform actual scan
469
- self.logger.debug("Scanning for deployed agents (cache miss or expired)")
470
- deployed = set()
471
-
472
- # Check multiple locations for deployed agents
473
- agents_dirs = [
474
- Path.cwd() / ".claude" / "agents", # Project-specific agents
475
- Path.home() / ".claude" / "agents", # User's system agents
476
- ]
477
-
478
- for agents_dir in agents_dirs:
479
- if agents_dir.exists():
480
- for agent_file in agents_dir.glob("*.md"):
481
- if not agent_file.name.startswith("."):
482
- # Use stem to get agent name without extension
483
- deployed.add(agent_file.stem)
484
- self.logger.debug(
485
- f"Found deployed agent: {agent_file.stem} in {agents_dir}"
486
- )
487
-
488
- self.logger.debug(f"Total deployed agents found: {len(deployed)}")
489
-
490
- # Update cache
491
- self._cache_manager.set_deployed_agents(deployed)
492
-
493
- return deployed
494
-
495
- def _load_actual_memories(self, content: Dict[str, Any]) -> None:
496
- """
497
- Load actual memories using the MemoryManager service.
498
-
499
- This method delegates all memory loading operations to the MemoryManager,
500
- which handles caching, aggregation, deduplication, and legacy format migration.
501
-
502
- Args:
503
- content: Dictionary to update with actual memories
504
- """
505
- # Use MemoryManager to load all memories
506
- memories = self._memory_manager.load_memories()
507
-
508
- # Apply loaded memories to content
509
- if "actual_memories" in memories:
510
- content["actual_memories"] = memories["actual_memories"]
511
- if "agent_memories" in memories:
512
- content["agent_memories"] = memories["agent_memories"]
513
-
514
- def _load_single_agent(
515
- self, agent_file: Path
516
- ) -> tuple[Optional[str], Optional[str]]:
517
- """
518
- Load a single agent file.
519
-
520
- Args:
521
- agent_file: Path to the agent file
522
-
523
- Returns:
524
- Tuple of (agent_name, agent_content) or (None, None) on failure
525
- """
526
- try:
527
- agent_name = agent_file.stem
528
- # Skip README files
529
- if agent_name.upper() == "README":
530
- return None, None
531
- content = agent_file.read_text()
532
- self.logger.debug(f"Loaded agent: {agent_name}")
533
- return agent_name, content
534
- except Exception as e:
535
- self.logger.error(f"Failed to load agent {agent_file}: {e}")
536
- return None, None
537
-
538
- def _load_base_agent_fallback(
539
- self, content: Dict[str, Any], main_dir: Optional[Path]
540
- ) -> None:
541
- """
542
- Load base_agent.md from main directory as fallback.
543
-
544
- Args:
545
- content: Dictionary to update with base agent
546
- main_dir: Main agents directory path
547
- """
548
- if main_dir and main_dir.exists() and "base_agent" not in content["agents"]:
549
- base_agent_file = main_dir / "base_agent.md"
550
- if base_agent_file.exists():
551
- agent_name, agent_content = self._load_single_agent(base_agent_file)
552
- if agent_name and agent_content:
553
- content["agents"][agent_name] = agent_content
554
-
555
- def _load_agents_directory(
556
- self,
557
- content: Dict[str, Any],
558
- agents_dir: Optional[Path],
559
- templates_dir: Optional[Path],
560
- main_dir: Optional[Path],
561
- ) -> None:
562
- """
563
- Load agent definitions from the appropriate directory.
564
-
565
- Args:
566
- content: Dictionary to update with loaded agents
567
- agents_dir: Primary agents directory to load from
568
- templates_dir: Templates directory path
569
- main_dir: Main agents directory path
570
- """
571
- if not agents_dir or not agents_dir.exists():
572
- return
573
-
574
- content["loaded"] = True
575
-
576
- # Load all agent files
577
- for agent_file in agents_dir.glob("*.md"):
578
- agent_name, agent_content = self._load_single_agent(agent_file)
579
- if agent_name and agent_content:
580
- content["agents"][agent_name] = agent_content
581
-
582
- # If we used templates dir, also check main dir for base_agent.md
583
- if agents_dir == templates_dir:
584
- self._load_base_agent_fallback(content, main_dir)
207
+ # === Content Loading Methods ===
585
208
 
586
209
  def _load_framework_content(self) -> Dict[str, Any]:
587
- """Load framework content."""
210
+ """Load framework content using modular components."""
588
211
  content = {
589
212
  "claude_md": "",
590
213
  "agents": {},
@@ -593,242 +216,102 @@ class FrameworkLoader:
593
216
  "working_claude_md": "",
594
217
  "framework_instructions": "",
595
218
  "workflow_instructions": "",
596
- "workflow_instructions_level": "", # Track source level
219
+ "workflow_instructions_level": "",
597
220
  "memory_instructions": "",
598
- "memory_instructions_level": "", # Track source level
599
- "project_workflow": "", # Deprecated, use workflow_instructions_level
600
- "project_memory": "", # Deprecated, use memory_instructions_level
601
- "actual_memories": "", # Add field for actual memories from PM_memories.md
221
+ "memory_instructions_level": "",
222
+ "project_workflow": "", # Deprecated
223
+ "project_memory": "", # Deprecated
224
+ "actual_memories": "",
225
+ "agent_memories": {},
602
226
  }
603
227
 
604
- # Load instructions file from working directory
605
- self._load_instructions_file(content)
228
+ # Load all instructions
229
+ self.instruction_loader.load_all_instructions(content)
606
230
 
607
- if not self.framework_path:
608
- return content
231
+ # Transfer metadata from loaders
232
+ if self.file_loader.framework_version:
233
+ self.framework_version = self.file_loader.framework_version
234
+ content["version"] = self.framework_version
235
+ if self.file_loader.framework_last_modified:
236
+ self.framework_last_modified = self.file_loader.framework_last_modified
609
237
 
610
- # Check if this is a packaged installation
611
- if self.framework_path == Path("__PACKAGED__"):
612
- # Load files using importlib.resources for packaged installations
613
- self._load_packaged_framework_content(content)
614
- else:
615
- # Load from filesystem for development mode
616
- # Load framework's INSTRUCTIONS.md
617
- framework_instructions_path = (
618
- self.framework_path
619
- / "src"
620
- / "claude_mpm"
621
- / "agents"
622
- / "INSTRUCTIONS.md"
623
- )
624
- if framework_instructions_path.exists():
625
- loaded_content = self._try_load_file(
626
- framework_instructions_path, "framework INSTRUCTIONS.md"
627
- )
628
- if loaded_content:
629
- content["framework_instructions"] = loaded_content
630
- content["loaded"] = True
631
- # Add framework version to content
632
- if self.framework_version:
633
- content["instructions_version"] = self.framework_version
634
- content["version"] = (
635
- self.framework_version
636
- ) # Update main version key
637
- # Add modification timestamp to content
638
- if self.framework_last_modified:
639
- content["instructions_last_modified"] = (
640
- self.framework_last_modified
641
- )
642
-
643
- # Load BASE_PM.md for core framework requirements
644
- base_pm_path = (
645
- self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
646
- )
647
- if base_pm_path.exists():
648
- base_pm_content = self._try_load_file(
649
- base_pm_path, "BASE_PM framework requirements"
650
- )
651
- if base_pm_content:
652
- content["base_pm_instructions"] = base_pm_content
653
-
654
- # Load WORKFLOW.md - check for project-specific first, then system
655
- self._load_workflow_instructions(content)
656
-
657
- # Load MEMORY.md - check for project-specific first, then system
658
- self._load_memory_instructions(content)
659
-
660
- # Load actual memories from .claude-mpm/memories/PM_memories.md
238
+ # Load memories
661
239
  self._load_actual_memories(content)
662
240
 
663
- # Discover agent directories using PathResolver
241
+ # Discover and load agents
664
242
  agents_dir, templates_dir, main_dir = self._path_resolver.discover_agent_paths(
665
243
  agents_dir=self.agents_dir, framework_path=self.framework_path
666
244
  )
667
-
668
- # Load agents from discovered directory
669
- self._load_agents_directory(content, agents_dir, templates_dir, main_dir)
245
+ agents = self.agent_loader.load_agents_directory(
246
+ agents_dir, templates_dir, main_dir
247
+ )
248
+ if agents:
249
+ content["agents"] = agents
250
+ content["loaded"] = True
670
251
 
671
252
  return content
672
253
 
673
- def _load_packaged_framework_content(self, content: Dict[str, Any]) -> None:
674
- """Load framework content from packaged installation using importlib.resources."""
675
- if not files:
676
- self.logger.warning(
677
- "importlib.resources not available, cannot load packaged framework"
678
- )
679
- self.logger.debug(f"files variable is: {files}")
680
- # Try alternative import methods
681
- try:
682
- from importlib import resources
683
-
684
- self.logger.info("Using importlib.resources as fallback")
685
- self._load_packaged_framework_content_fallback(content, resources)
686
- return
687
- except ImportError:
688
- self.logger.error(
689
- "No importlib.resources available, using minimal framework"
690
- )
691
- return
692
-
693
- try:
694
- # Load INSTRUCTIONS.md
695
- instructions_content = self._load_packaged_file("INSTRUCTIONS.md")
696
- if instructions_content:
697
- content["framework_instructions"] = instructions_content
698
- content["loaded"] = True
699
- # Extract and store version/timestamp metadata
700
- self._extract_metadata_from_content(
701
- instructions_content, "INSTRUCTIONS.md"
702
- )
703
- if self.framework_version:
704
- content["instructions_version"] = self.framework_version
705
- content["version"] = self.framework_version
706
- if self.framework_last_modified:
707
- content["instructions_last_modified"] = self.framework_last_modified
708
-
709
- # Load BASE_PM.md
710
- base_pm_content = self._load_packaged_file("BASE_PM.md")
711
- if base_pm_content:
712
- content["base_pm_instructions"] = base_pm_content
713
-
714
- # Load WORKFLOW.md
715
- workflow_content = self._load_packaged_file("WORKFLOW.md")
716
- if workflow_content:
717
- content["workflow_instructions"] = workflow_content
718
- content["project_workflow"] = "system"
719
-
720
- # Load MEMORY.md
721
- memory_content = self._load_packaged_file("MEMORY.md")
722
- if memory_content:
723
- content["memory_instructions"] = memory_content
724
- content["project_memory"] = "system"
725
-
726
- except Exception as e:
727
- self.logger.error(f"Failed to load packaged framework content: {e}")
254
+ def _load_actual_memories(self, content: Dict[str, Any]) -> None:
255
+ """Load actual memories using the MemoryManager service."""
256
+ memories = self._memory_manager.load_memories()
728
257
 
729
- def _load_packaged_framework_content_fallback(
730
- self, content: Dict[str, Any], resources
731
- ) -> None:
732
- """Load framework content using importlib.resources fallback."""
733
- try:
734
- # Load INSTRUCTIONS.md
735
- instructions_content = self._load_packaged_file_fallback(
736
- "INSTRUCTIONS.md", resources
737
- )
738
- if instructions_content:
739
- content["framework_instructions"] = instructions_content
740
- content["loaded"] = True
741
- # Extract and store version/timestamp metadata
742
- self._extract_metadata_from_content(
743
- instructions_content, "INSTRUCTIONS.md"
744
- )
745
- if self.framework_version:
746
- content["instructions_version"] = self.framework_version
747
- content["version"] = self.framework_version
748
- if self.framework_last_modified:
749
- content["instructions_last_modified"] = self.framework_last_modified
750
-
751
- # Load BASE_PM.md
752
- base_pm_content = self._load_packaged_file_fallback("BASE_PM.md", resources)
753
- if base_pm_content:
754
- content["base_pm_instructions"] = base_pm_content
755
-
756
- # Load WORKFLOW.md
757
- workflow_content = self._load_packaged_file_fallback(
758
- "WORKFLOW.md", resources
759
- )
760
- if workflow_content:
761
- content["workflow_instructions"] = workflow_content
762
- content["project_workflow"] = "system"
258
+ if "actual_memories" in memories:
259
+ content["actual_memories"] = memories["actual_memories"]
260
+ if "agent_memories" in memories:
261
+ content["agent_memories"] = memories["agent_memories"]
763
262
 
764
- # Load MEMORY.md
765
- memory_content = self._load_packaged_file_fallback("MEMORY.md", resources)
766
- if memory_content:
767
- content["memory_instructions"] = memory_content
768
- content["project_memory"] = "system"
263
+ # === Agent Discovery Methods ===
769
264
 
770
- except Exception as e:
771
- self.logger.error(
772
- f"Failed to load packaged framework content with fallback: {e}"
773
- )
265
+ def _get_deployed_agents(self) -> Set[str]:
266
+ """Get deployed agents with caching."""
267
+ cached = self._cache_manager.get_deployed_agents()
268
+ if cached is not None:
269
+ return cached
774
270
 
775
- def _load_packaged_file_fallback(self, filename: str, resources) -> Optional[str]:
776
- """Load a file from the packaged installation using importlib.resources fallback."""
777
- try:
778
- # Try different resource loading methods
779
- try:
780
- # Method 1: resources.read_text (Python 3.9+)
781
- content = resources.read_text("claude_mpm.agents", filename)
782
- self.logger.info(f"Loaded {filename} from package using read_text")
783
- return content
784
- except AttributeError:
785
- # Method 2: resources.files (Python 3.9+)
786
- agents_files = resources.files("claude_mpm.agents")
787
- file_path = agents_files / filename
788
- if file_path.is_file():
789
- content = file_path.read_text()
790
- self.logger.info(f"Loaded {filename} from package using files")
791
- return content
792
- self.logger.warning(f"File {filename} not found in package")
793
- return None
794
- except Exception as e:
795
- self.logger.error(
796
- f"Failed to load {filename} from package with fallback: {e}"
797
- )
798
- return None
271
+ deployed = self.agent_loader.get_deployed_agents()
272
+ self._cache_manager.set_deployed_agents(deployed)
273
+ return deployed
799
274
 
800
- def _load_packaged_file(self, filename: str) -> Optional[str]:
801
- """Load a file from the packaged installation."""
802
- try:
803
- # Use importlib.resources to load file from package
804
- agents_package = files("claude_mpm.agents")
805
- file_path = agents_package / filename
806
-
807
- if file_path.is_file():
808
- content = file_path.read_text()
809
- self.logger.info(f"Loaded {filename} from package")
810
- return content
811
- self.logger.warning(f"File {filename} not found in package")
812
- return None
813
- except Exception as e:
814
- self.logger.error(f"Failed to load {filename} from package: {e}")
815
- return None
275
+ def _discover_local_json_templates(self) -> Dict[str, Dict[str, Any]]:
276
+ """Discover local JSON agent templates."""
277
+ return self.agent_loader.discover_local_json_templates()
816
278
 
817
- def _extract_metadata_from_content(self, content: str, filename: str) -> None:
818
- """Extract metadata from content string."""
819
- import re
279
+ def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
280
+ """Parse agent metadata with caching."""
281
+ cache_key = str(agent_file)
282
+ file_mtime = agent_file.stat().st_mtime
283
+
284
+ # Try cache first
285
+ cached_result = self._cache_manager.get_agent_metadata(cache_key)
286
+ if cached_result is not None:
287
+ cached_data, cached_mtime = cached_result
288
+ if cached_mtime == file_mtime:
289
+ self.logger.debug(f"Using cached metadata for {agent_file.name}")
290
+ return cached_data
291
+
292
+ # Cache miss - parse the file
293
+ agent_data = self.metadata_processor.parse_agent_metadata(agent_file)
294
+
295
+ # Add routing information if not present
296
+ if agent_data and "routing" not in agent_data:
297
+ template_data = self.template_processor.load_template(agent_file.stem)
298
+ if template_data:
299
+ routing = self.template_processor.extract_routing(template_data)
300
+ if routing:
301
+ agent_data["routing"] = routing
302
+ memory_routing = self.template_processor.extract_memory_routing(
303
+ template_data
304
+ )
305
+ if memory_routing:
306
+ agent_data["memory_routing"] = memory_routing
307
+
308
+ # Cache the result
309
+ if agent_data:
310
+ self._cache_manager.set_agent_metadata(cache_key, agent_data, file_mtime)
820
311
 
821
- # Extract version
822
- version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
823
- if version_match and "INSTRUCTIONS.md" in filename:
824
- self.framework_version = version_match.group(1)
825
- self.logger.info(f"Framework version: {self.framework_version}")
312
+ return agent_data
826
313
 
827
- # Extract timestamp
828
- timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
829
- if timestamp_match and "INSTRUCTIONS.md" in filename:
830
- self.framework_last_modified = timestamp_match.group(1).strip()
831
- self.logger.info(f"Last modified: {self.framework_last_modified}")
314
+ # === Framework Instructions Generation ===
832
315
 
833
316
  def get_framework_instructions(self) -> str:
834
317
  """
@@ -837,872 +320,221 @@ class FrameworkLoader:
837
320
  Returns:
838
321
  Complete framework instructions ready for injection
839
322
  """
840
- # Import LogManager for prompt logging
841
- try:
842
- from .log_manager import get_log_manager
843
-
844
- log_manager = get_log_manager()
845
- except ImportError:
846
- log_manager = None
323
+ # Log the system prompt if needed
324
+ self._log_system_prompt()
847
325
 
848
326
  # Generate the instructions
849
327
  if self.framework_content["loaded"]:
850
- # Build framework from components
851
- instructions = self._format_full_framework()
852
- else:
853
- # Use minimal fallback
854
- instructions = self._format_minimal_framework()
855
-
856
- # Log the system prompt if LogManager is available
857
- if log_manager:
858
- try:
859
- import asyncio
860
- import os
861
-
862
- # Get or create event loop
863
- try:
864
- loop = asyncio.get_running_loop()
865
- except RuntimeError:
866
- loop = asyncio.new_event_loop()
867
- asyncio.set_event_loop(loop)
868
-
869
- # Prepare metadata
870
- metadata = {
871
- "framework_version": self.framework_version,
872
- "framework_loaded": self.framework_content.get("loaded", False),
873
- "session_id": os.environ.get("CLAUDE_SESSION_ID", "unknown"),
874
- "instructions_length": len(instructions),
875
- }
876
-
877
- # Log the prompt asynchronously
878
- if loop.is_running():
879
- asyncio.create_task(
880
- log_manager.log_prompt("system_prompt", instructions, metadata)
881
- )
882
- else:
883
- loop.run_until_complete(
884
- log_manager.log_prompt("system_prompt", instructions, metadata)
885
- )
886
-
887
- self.logger.debug("System prompt logged to prompts directory")
888
- except Exception as e:
889
- self.logger.debug(f"Could not log system prompt: {e}")
890
-
891
- return instructions
892
-
893
- def _strip_metadata_comments(self, content: str) -> str:
894
- """Strip metadata HTML comments from content.
895
-
896
- Removes comments like:
897
- <!-- FRAMEWORK_VERSION: 0010 -->
898
- <!-- LAST_MODIFIED: 2025-08-10T00:00:00Z -->
899
- """
900
- import re
901
-
902
- # Remove HTML comments that contain metadata
903
- cleaned = re.sub(
904
- r"<!--\s*(FRAMEWORK_VERSION|LAST_MODIFIED|WORKFLOW_VERSION|PROJECT_WORKFLOW_VERSION|CUSTOM_PROJECT_WORKFLOW)[^>]*-->\n?",
905
- "",
906
- content,
907
- )
908
- # Also remove any leading blank lines that might result
909
- return cleaned.lstrip("\n")
328
+ return self._format_full_framework()
329
+ return self._format_minimal_framework()
910
330
 
911
331
  def _format_full_framework(self) -> str:
912
- """Format full framework instructions."""
913
-
914
- # Initialize output style manager on first use (ensures content is loaded)
332
+ """Format full framework instructions using modular components."""
333
+ # Initialize output style manager on first use
915
334
  if self.output_style_manager is None:
916
335
  self._initialize_output_style()
917
336
 
918
- # Check if we need to inject output style content for older Claude versions
337
+ # Check if we need to inject output style
919
338
  inject_output_style = False
339
+ output_style_content = None
920
340
  if self.output_style_manager:
921
341
  inject_output_style = self.output_style_manager.should_inject_content()
922
342
  if inject_output_style:
923
- self.logger.info(
924
- "Injecting output style content into instructions for Claude < 1.0.83"
925
- )
926
-
927
- # If we have the full framework INSTRUCTIONS.md, use it
928
- if self.framework_content.get("framework_instructions"):
929
- instructions = self._strip_metadata_comments(
930
- self.framework_content["framework_instructions"]
931
- )
932
-
933
- # Note: We don't add working directory CLAUDE.md here since Claude Code
934
- # already picks it up automatically. This prevents duplication.
935
-
936
- # Add custom INSTRUCTIONS.md if present (overrides or extends framework instructions)
937
- if self.framework_content.get("custom_instructions"):
938
- level = self.framework_content.get(
939
- "custom_instructions_level", "unknown"
940
- )
941
- instructions += f"\n\n## Custom PM Instructions ({level} level)\n\n"
942
- instructions += "**The following custom instructions override or extend the framework defaults:**\n\n"
943
- instructions += self._strip_metadata_comments(
944
- self.framework_content["custom_instructions"]
945
- )
946
- instructions += "\n"
947
-
948
- # Add WORKFLOW.md after instructions
949
- if self.framework_content.get("workflow_instructions"):
950
- workflow_content = self._strip_metadata_comments(
951
- self.framework_content["workflow_instructions"]
952
- )
953
- level = self.framework_content.get(
954
- "workflow_instructions_level", "system"
955
- )
956
- if level != "system":
957
- instructions += f"\n\n## Workflow Instructions ({level} level)\n\n"
958
- instructions += "**The following workflow instructions override system defaults:**\n\n"
959
- instructions += f"{workflow_content}\n"
960
-
961
- # Add MEMORY.md after workflow instructions
962
- if self.framework_content.get("memory_instructions"):
963
- memory_content = self._strip_metadata_comments(
964
- self.framework_content["memory_instructions"]
965
- )
966
- level = self.framework_content.get(
967
- "memory_instructions_level", "system"
968
- )
969
- if level != "system":
970
- instructions += f"\n\n## Memory Instructions ({level} level)\n\n"
971
- instructions += "**The following memory instructions override system defaults:**\n\n"
972
- instructions += f"{memory_content}\n"
973
-
974
- # Add actual PM memories after memory instructions
975
- if self.framework_content.get("actual_memories"):
976
- instructions += "\n\n## Current PM Memories\n\n"
977
- instructions += "**The following are your accumulated memories and knowledge from this project:**\n\n"
978
- instructions += self.framework_content["actual_memories"]
979
- instructions += "\n"
980
-
981
- # Add agent memories if available
982
- if self.framework_content.get("agent_memories"):
983
- agent_memories = self.framework_content["agent_memories"]
984
- if agent_memories:
985
- instructions += "\n\n## Agent Memories\n\n"
986
- instructions += "**The following are accumulated memories from specialized agents:**\n\n"
987
-
988
- for agent_name in sorted(agent_memories.keys()):
989
- memory_content = agent_memories[agent_name]
990
- if memory_content:
991
- instructions += f"### {agent_name.replace('_', ' ').title()} Agent Memory\n\n"
992
- instructions += memory_content
993
- instructions += "\n\n"
994
-
995
- # Add dynamic agent capabilities section
996
- instructions += self._generate_agent_capabilities_section()
997
-
998
- # Add current date for temporal awareness
999
- instructions += f"\n\n## Temporal Context\n**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
1000
- instructions += (
1001
- "Apply date awareness to all time-sensitive tasks and decisions.\n"
1002
- )
1003
-
1004
- # Add BASE_PM.md framework requirements AFTER INSTRUCTIONS.md
1005
- if self.framework_content.get("base_pm_instructions"):
1006
- base_pm = self._strip_metadata_comments(
1007
- self.framework_content["base_pm_instructions"]
1008
- )
1009
- instructions += f"\n\n{base_pm}"
1010
-
1011
- # Inject output style content if needed (for Claude < 1.0.83)
1012
- if inject_output_style and self.output_style_manager:
1013
343
  output_style_content = self.output_style_manager.get_injectable_content(
1014
344
  framework_loader=self
1015
345
  )
1016
- if output_style_content:
1017
- instructions += "\n\n## Output Style Configuration\n"
1018
- instructions += "**Note: The following output style is injected for Claude < 1.0.83**\n\n"
1019
- instructions += output_style_content
1020
- instructions += "\n"
1021
-
1022
- # Clean up any trailing whitespace
1023
- return instructions.rstrip() + "\n"
1024
-
1025
- # Otherwise fall back to generating framework
1026
- instructions = """# Claude MPM Framework Instructions
1027
-
1028
- You are operating within the Claude Multi-Agent Project Manager (MPM) framework.
1029
-
1030
- ## Core Role
1031
- You are a multi-agent orchestrator. Your primary responsibilities are:
1032
- - Delegate all implementation work to specialized agents via Task Tool
1033
- - Coordinate multi-agent workflows and cross-agent collaboration
1034
- - Extract and track TODO/BUG/FEATURE items for ticket creation
1035
- - Maintain project visibility and strategic oversight
1036
- - NEVER perform direct implementation work yourself
1037
-
1038
- """
1039
-
1040
- # Note: We don't add working directory CLAUDE.md here since Claude Code
1041
- # already picks it up automatically. This prevents duplication.
1042
-
1043
- # Add agent definitions
1044
- if self.framework_content["agents"]:
1045
- instructions += "## Available Agents\n\n"
1046
- instructions += "You have the following specialized agents available for delegation:\n\n"
1047
-
1048
- # List agents with brief descriptions and correct IDs
1049
- agent_list = []
1050
- for agent_name in sorted(self.framework_content["agents"].keys()):
1051
- # Use the actual agent_name as the ID (it's the filename stem)
1052
- agent_id = agent_name
1053
- clean_name = agent_name.replace("-", " ").replace("_", " ").title()
1054
- if (
1055
- "engineer" in agent_name.lower()
1056
- and "data" not in agent_name.lower()
1057
- ):
1058
- agent_list.append(
1059
- f"- **Engineer Agent** (`{agent_id}`): Code implementation and development"
1060
- )
1061
- elif "qa" in agent_name.lower():
1062
- agent_list.append(
1063
- f"- **QA Agent** (`{agent_id}`): Testing and quality assurance"
1064
- )
1065
- elif "documentation" in agent_name.lower():
1066
- agent_list.append(
1067
- f"- **Documentation Agent** (`{agent_id}`): Documentation creation and maintenance"
1068
- )
1069
- elif "research" in agent_name.lower():
1070
- agent_list.append(
1071
- f"- **Research Agent** (`{agent_id}`): Investigation and analysis"
1072
- )
1073
- elif "security" in agent_name.lower():
1074
- agent_list.append(
1075
- f"- **Security Agent** (`{agent_id}`): Security analysis and protection"
1076
- )
1077
- elif "version" in agent_name.lower():
1078
- agent_list.append(
1079
- f"- **Version Control Agent** (`{agent_id}`): Git operations and version management"
1080
- )
1081
- elif "ops" in agent_name.lower():
1082
- agent_list.append(
1083
- f"- **Ops Agent** (`{agent_id}`): Deployment and operations"
1084
- )
1085
- elif "data" in agent_name.lower():
1086
- agent_list.append(
1087
- f"- **Data Engineer Agent** (`{agent_id}`): Data management and AI API integration"
1088
- )
1089
- else:
1090
- agent_list.append(
1091
- f"- **{clean_name}** (`{agent_id}`): Available for specialized tasks"
1092
- )
346
+ self.logger.info("Injecting output style content for Claude < 1.0.83")
1093
347
 
1094
- instructions += "\n".join(agent_list) + "\n\n"
1095
-
1096
- # Add full agent details
1097
- instructions += "### Agent Details\n\n"
1098
- for agent_name, agent_content in sorted(
1099
- self.framework_content["agents"].items()
1100
- ):
1101
- instructions += f"#### {agent_name.replace('-', ' ').title()}\n"
1102
- instructions += agent_content + "\n\n"
1103
-
1104
- # Add orchestration principles
1105
- instructions += """
1106
- ## Orchestration Principles
1107
- 1. **Always Delegate**: Never perform direct work - use Task Tool for all implementation
1108
- 2. **Comprehensive Context**: Provide rich, filtered context to each agent
1109
- 3. **Track Everything**: Extract all TODO/BUG/FEATURE items systematically
1110
- 4. **Cross-Agent Coordination**: Orchestrate workflows spanning multiple agents
1111
- 5. **Results Integration**: Actively receive and integrate agent results
1112
-
1113
- ## Task Tool Format
1114
- ```
1115
- **[Agent Name]**: [Clear task description with deliverables]
1116
-
1117
- TEMPORAL CONTEXT: Today is [date]. Apply date awareness to [specific considerations].
1118
-
1119
- **Task**: [Detailed task breakdown]
1120
- 1. [Specific action item 1]
1121
- 2. [Specific action item 2]
1122
- 3. [Specific action item 3]
1123
-
1124
- **Context**: [Comprehensive filtered context for this agent]
1125
- **Authority**: [Agent's decision-making scope]
1126
- **Expected Results**: [Specific deliverables needed]
1127
- **Integration**: [How results integrate with other work]
1128
- ```
1129
-
1130
- ## Ticket Extraction Patterns
1131
- Extract tickets from these patterns:
1132
- - TODO: [description] → TODO ticket
1133
- - BUG: [description] → BUG ticket
1134
- - FEATURE: [description] → FEATURE ticket
1135
- - ISSUE: [description] → ISSUE ticket
1136
- - FIXME: [description] → BUG ticket
1137
-
1138
- ---
1139
- """
1140
-
1141
- return instructions
348
+ # Generate dynamic sections
349
+ capabilities_section = self._generate_agent_capabilities_section()
350
+ context_section = self.context_generator.generate_temporal_user_context()
1142
351
 
1143
- def _generate_agent_capabilities_section(self) -> str:
1144
- """Generate dynamic agent capabilities section from deployed agents.
1145
- Uses caching to avoid repeated file I/O and parsing operations."""
352
+ # Format the complete framework
353
+ return self.content_formatter.format_full_framework(
354
+ self.framework_content,
355
+ capabilities_section,
356
+ context_section,
357
+ inject_output_style,
358
+ output_style_content,
359
+ )
360
+
361
+ def _format_minimal_framework(self) -> str:
362
+ """Format minimal framework instructions."""
363
+ return self.content_formatter.format_minimal_framework(self.framework_content)
1146
364
 
1147
- # Try to get from cache first
365
+ def _generate_agent_capabilities_section(self) -> str:
366
+ """Generate agent capabilities section with caching."""
367
+ # Try cache first
1148
368
  cached_capabilities = self._cache_manager.get_capabilities()
1149
369
  if cached_capabilities is not None:
1150
370
  return cached_capabilities
1151
371
 
1152
- # Will be used for updating cache later
1153
- current_time = time.time()
1154
-
1155
- # Cache miss or expired - generate capabilities
1156
- self.logger.debug("Generating agent capabilities (cache miss or expired)")
372
+ self.logger.debug("Generating agent capabilities (cache miss)")
1157
373
 
1158
374
  try:
1159
- from pathlib import Path
375
+ # Discover local JSON templates
376
+ local_agents = self._discover_local_json_templates()
1160
377
 
1161
- # Read directly from deployed agents in .claude/agents/
1162
- # Check multiple locations for deployed agents
1163
- # Priority order: project > user home > fallback
378
+ # Get deployed agents from .claude/agents/
379
+ deployed_agents = []
1164
380
  agents_dirs = [
1165
- Path.cwd() / ".claude" / "agents", # Project-specific agents
1166
- Path.home() / ".claude" / "agents", # User's system agents
381
+ Path.cwd() / ".claude" / "agents",
382
+ Path.home() / ".claude" / "agents",
1167
383
  ]
1168
384
 
1169
- # Collect agents from all directories with proper precedence
1170
- # Project agents override user agents with the same name
1171
- all_agents = {} # key: agent_id, value: (agent_data, priority)
1172
-
1173
- for priority, potential_dir in enumerate(agents_dirs):
1174
- if potential_dir.exists() and any(potential_dir.glob("*.md")):
1175
- self.logger.debug(f"Found agents directory at: {potential_dir}")
1176
-
1177
- # Collect agents from this directory
1178
- for agent_file in potential_dir.glob("*.md"):
1179
- if agent_file.name.startswith("."):
1180
- continue
1181
-
1182
- # Parse agent metadata (with caching)
1183
- agent_data = self._parse_agent_metadata(agent_file)
1184
- if agent_data:
1185
- agent_id = agent_data["id"]
1186
- # Only add if not already present (project has priority 0, user has priority 1)
1187
- # Lower priority number wins (project > user)
1188
- if (
1189
- agent_id not in all_agents
1190
- or priority < all_agents[agent_id][1]
1191
- ):
1192
- all_agents[agent_id] = (agent_data, priority)
1193
- self.logger.debug(
1194
- f"Added/Updated agent {agent_id} from {potential_dir} (priority {priority})"
1195
- )
1196
-
1197
- if not all_agents:
1198
- self.logger.warning(f"No agents found in any location: {agents_dirs}")
1199
- result = self._get_fallback_capabilities()
1200
- # Cache the fallback result too
1201
- self._cache_manager.set_capabilities(result)
1202
- return result
1203
-
1204
- # Log agent collection summary
1205
- project_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 0]
1206
- user_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 1]
1207
-
1208
- if project_agents:
1209
- self.logger.info(
1210
- f"Loaded {len(project_agents)} project agents: {', '.join(sorted(project_agents))}"
1211
- )
1212
- if user_agents:
1213
- self.logger.info(
1214
- f"Loaded {len(user_agents)} user agents: {', '.join(sorted(user_agents))}"
1215
- )
1216
-
1217
- # Build capabilities section
1218
- section = "\n\n## Available Agent Capabilities\n\n"
1219
-
1220
- # Extract just the agent data (drop priority info) and sort
1221
- deployed_agents = [agent_data for agent_data, _ in all_agents.values()]
1222
-
1223
- if not deployed_agents:
1224
- result = self._get_fallback_capabilities()
1225
- # Cache the fallback result
1226
- self._cache_manager.set_capabilities(result)
1227
- return result
1228
-
1229
- # Sort agents alphabetically by ID
1230
- deployed_agents.sort(key=lambda x: x["id"])
1231
-
1232
- # Display all agents with their rich descriptions
1233
- for agent in deployed_agents:
1234
- # Clean up display name - handle common acronyms
1235
- display_name = agent["display_name"]
1236
- display_name = (
1237
- display_name.replace("Qa ", "QA ")
1238
- .replace("Ui ", "UI ")
1239
- .replace("Api ", "API ")
1240
- )
1241
- if display_name.lower() == "qa agent":
1242
- display_name = "QA Agent"
1243
-
1244
- section += f"\n### {display_name} (`{agent['id']}`)\n"
1245
- section += f"{agent['description']}\n"
1246
-
1247
- # Add routing information if available
1248
- if agent.get("routing"):
1249
- routing = agent["routing"]
1250
-
1251
- # Format routing hints for PM usage
1252
- routing_hints = []
1253
-
1254
- if routing.get("keywords"):
1255
- # Show first 5 keywords for brevity
1256
- keywords = routing["keywords"][:5]
1257
- routing_hints.append(f"Keywords: {', '.join(keywords)}")
1258
-
1259
- if routing.get("paths"):
1260
- # Show first 3 paths for brevity
1261
- paths = routing["paths"][:3]
1262
- routing_hints.append(f"Paths: {', '.join(paths)}")
1263
-
1264
- if routing.get("priority"):
1265
- routing_hints.append(f"Priority: {routing['priority']}")
1266
-
1267
- if routing_hints:
1268
- section += f"- **Routing**: {' | '.join(routing_hints)}\n"
1269
-
1270
- # Add when_to_use if present
1271
- if routing.get("when_to_use"):
1272
- section += f"- **When to use**: {routing['when_to_use']}\n"
1273
-
1274
- # Add any additional metadata if present
1275
- if agent.get("authority"):
1276
- section += f"- **Authority**: {agent['authority']}\n"
1277
- if agent.get("primary_function"):
1278
- section += f"- **Primary Function**: {agent['primary_function']}\n"
1279
- if agent.get("handoff_to"):
1280
- section += f"- **Handoff To**: {agent['handoff_to']}\n"
1281
- if agent.get("tools") and agent["tools"] != "standard":
1282
- section += f"- **Tools**: {agent['tools']}\n"
1283
- if agent.get("model") and agent["model"] != "opus":
1284
- section += f"- **Model**: {agent['model']}\n"
1285
-
1286
- # Add memory routing information if available
1287
- if agent.get("memory_routing"):
1288
- memory_routing = agent["memory_routing"]
1289
- if memory_routing.get("description"):
1290
- section += (
1291
- f"- **Memory Routing**: {memory_routing['description']}\n"
1292
- )
1293
-
1294
- # Add simple Context-Aware Agent Selection
1295
- section += "\n## Context-Aware Agent Selection\n\n"
1296
- section += (
1297
- "Select agents based on their descriptions above. Key principles:\n"
385
+ for agents_dir in agents_dirs:
386
+ if agents_dir.exists():
387
+ for agent_file in agents_dir.glob("*.md"):
388
+ if not agent_file.name.startswith("."):
389
+ agent_data = self._parse_agent_metadata(agent_file)
390
+ if agent_data:
391
+ deployed_agents.append(agent_data)
392
+
393
+ # Generate capabilities section
394
+ section = self.capability_generator.generate_capabilities_section(
395
+ deployed_agents, local_agents
1298
396
  )
1299
- section += "- **PM questions** → Answer directly (only exception)\n"
1300
- section += "- Match task requirements to agent descriptions and authority\n"
1301
- section += "- Consider agent handoff recommendations\n"
1302
- section += (
1303
- "- Use the agent ID in parentheses when delegating via Task tool\n"
1304
- )
1305
-
1306
- # Add summary
1307
- section += f"\n**Total Available Agents**: {len(deployed_agents)}\n"
1308
397
 
1309
- # Cache the generated capabilities
398
+ # Cache the result
1310
399
  self._cache_manager.set_capabilities(section)
1311
- self.logger.debug(
1312
- f"Cached agent capabilities section ({len(section)} chars)"
1313
- )
400
+ self.logger.debug(f"Cached agent capabilities ({len(section)} chars)")
1314
401
 
1315
402
  return section
1316
403
 
1317
404
  except Exception as e:
1318
- self.logger.warning(f"Could not generate dynamic agent capabilities: {e}")
1319
- result = self._get_fallback_capabilities()
1320
- # Cache even the fallback result
1321
- self._agent_capabilities_cache = result
1322
- self._agent_capabilities_cache_time = current_time
1323
- return result
405
+ self.logger.warning(f"Could not generate agent capabilities: {e}")
406
+ fallback = self.content_formatter.get_fallback_capabilities()
407
+ self._cache_manager.set_capabilities(fallback)
408
+ return fallback
1324
409
 
1325
- def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
1326
- """Parse agent metadata from deployed agent file.
1327
- Uses caching based on file path and modification time.
410
+ # === Output Style Management ===
1328
411
 
1329
- Returns:
1330
- Dictionary with agent metadata directly from YAML frontmatter.
1331
- """
412
+ def _initialize_output_style(self) -> None:
413
+ """Initialize output style management."""
1332
414
  try:
1333
- # Check cache based on file path and modification time
1334
- cache_key = str(agent_file)
1335
- file_mtime = agent_file.stat().st_mtime
1336
- current_time = time.time()
1337
-
1338
- # Try to get from cache first
1339
- cached_result = self._cache_manager.get_agent_metadata(cache_key)
1340
- if cached_result is not None:
1341
- cached_data, cached_mtime = cached_result
1342
- # Use cache if file hasn't been modified and cache isn't too old
1343
- if cached_mtime == file_mtime:
1344
- self.logger.debug(f"Using cached metadata for {agent_file.name}")
1345
- return cached_data
1346
-
1347
- # Cache miss or expired - parse the file
1348
- self.logger.debug(
1349
- f"Parsing metadata for {agent_file.name} (cache miss or expired)"
1350
- )
1351
-
1352
- import yaml
1353
-
1354
- with open(agent_file) as f:
1355
- content = f.read()
415
+ from claude_mpm.core.output_style_manager import OutputStyleManager
1356
416
 
1357
- # Default values
1358
- agent_data = {
1359
- "id": agent_file.stem,
1360
- "display_name": agent_file.stem.replace("_", " ")
1361
- .replace("-", " ")
1362
- .title(),
1363
- "description": "Specialized agent",
1364
- }
417
+ self.output_style_manager = OutputStyleManager()
418
+ self._log_output_style_status()
1365
419
 
1366
- # Extract YAML frontmatter if present
1367
- if content.startswith("---"):
1368
- end_marker = content.find("---", 3)
1369
- if end_marker > 0:
1370
- frontmatter = content[3:end_marker]
1371
- metadata = yaml.safe_load(frontmatter)
1372
- if metadata:
1373
- # Use name as ID for Task tool
1374
- agent_data["id"] = metadata.get("name", agent_data["id"])
1375
- agent_data["display_name"] = (
1376
- metadata.get("name", agent_data["display_name"])
1377
- .replace("-", " ")
1378
- .title()
1379
- )
1380
-
1381
- # Copy all metadata fields directly
1382
- for key, value in metadata.items():
1383
- if key not in ["name"]: # Skip already processed fields
1384
- agent_data[key] = value
1385
-
1386
- # IMPORTANT: Do NOT add spaces to tools field - it breaks deployment!
1387
- # Tools must remain as comma-separated without spaces: "Read,Write,Edit"
1388
-
1389
- # Try to load routing metadata from JSON template if not in YAML frontmatter
1390
- if "routing" not in agent_data:
1391
- routing_data = self._load_routing_from_template(agent_file.stem)
1392
- if routing_data:
1393
- agent_data["routing"] = routing_data
1394
-
1395
- # Try to load memory routing metadata from JSON template if not in YAML frontmatter
1396
- if "memory_routing" not in agent_data:
1397
- memory_routing_data = self._load_memory_routing_from_template(
1398
- agent_file.stem
420
+ # Extract and save output style content
421
+ output_style_content = (
422
+ self.output_style_manager.extract_output_style_content(
423
+ framework_loader=self
1399
424
  )
1400
- if memory_routing_data:
1401
- agent_data["memory_routing"] = memory_routing_data
1402
-
1403
- # Cache the parsed metadata
1404
- self._cache_manager.set_agent_metadata(cache_key, agent_data, file_mtime)
1405
-
1406
- return agent_data
1407
-
1408
- except Exception as e:
1409
- self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
1410
- return None
1411
-
1412
- def _load_memory_routing_from_template(
1413
- self, agent_name: str
1414
- ) -> Optional[Dict[str, Any]]:
1415
- """Load memory routing metadata from agent JSON template.
1416
-
1417
- Args:
1418
- agent_name: Name of the agent (stem of the file)
1419
-
1420
- Returns:
1421
- Dictionary with memory routing metadata or None if not found
1422
- """
1423
- try:
1424
- import json
1425
-
1426
- # Check if we have a framework path
1427
- if not self.framework_path or self.framework_path == Path("__PACKAGED__"):
1428
- # For packaged installations, try to load from package resources
1429
- if files:
1430
- try:
1431
- templates_package = files("claude_mpm.agents.templates")
1432
- template_file = templates_package / f"{agent_name}.json"
1433
-
1434
- if template_file.is_file():
1435
- template_content = template_file.read_text()
1436
- template_data = json.loads(template_content)
1437
- return template_data.get("memory_routing")
1438
- except Exception as e:
1439
- self.logger.debug(
1440
- f"Could not load memory routing from packaged template for {agent_name}: {e}"
1441
- )
1442
- return None
1443
-
1444
- # For development mode, load from filesystem
1445
- templates_dir = (
1446
- self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
1447
- )
1448
- template_file = templates_dir / f"{agent_name}.json"
1449
-
1450
- if template_file.exists():
1451
- with open(template_file) as f:
1452
- template_data = json.load(f)
1453
- return template_data.get("memory_routing")
1454
-
1455
- # Also check for variations in naming (underscore vs dash)
1456
- # Handle common naming variations between deployed .md files and .json templates
1457
- # Remove duplicates by using a set
1458
- alternative_names = list(
1459
- {
1460
- agent_name.replace("-", "_"), # api-qa -> api_qa
1461
- agent_name.replace("_", "-"), # api_qa -> api-qa
1462
- agent_name.replace("-", ""), # api-qa -> apiqa
1463
- agent_name.replace("_", ""), # api_qa -> apiqa
1464
- agent_name.replace("-agent", ""), # research-agent -> research
1465
- agent_name.replace("_agent", ""), # research_agent -> research
1466
- agent_name + "_agent", # research -> research_agent
1467
- agent_name + "-agent", # research -> research-agent
1468
- }
1469
425
  )
426
+ self.output_style_manager.save_output_style(output_style_content)
1470
427
 
1471
- for alt_name in alternative_names:
1472
- if alt_name != agent_name: # Skip the original name we already tried
1473
- alt_file = templates_dir / f"{alt_name}.json"
1474
- if alt_file.exists():
1475
- with open(alt_file) as f:
1476
- template_data = json.load(f)
1477
- return template_data.get("memory_routing")
1478
-
1479
- return None
1480
-
1481
- except Exception as e:
1482
- self.logger.debug(
1483
- f"Could not load memory routing from template for {agent_name}: {e}"
1484
- )
1485
- return None
1486
-
1487
- def _load_routing_from_template(self, agent_name: str) -> Optional[Dict[str, Any]]:
1488
- """Load routing metadata from agent JSON template.
1489
-
1490
- Args:
1491
- agent_name: Name of the agent (stem of the file)
1492
-
1493
- Returns:
1494
- Dictionary with routing metadata or None if not found
1495
- """
1496
- try:
1497
- import json
1498
-
1499
- # Check if we have a framework path
1500
- if not self.framework_path or self.framework_path == Path("__PACKAGED__"):
1501
- # For packaged installations, try to load from package resources
1502
- if files:
1503
- try:
1504
- templates_package = files("claude_mpm.agents.templates")
1505
- template_file = templates_package / f"{agent_name}.json"
1506
-
1507
- if template_file.is_file():
1508
- template_content = template_file.read_text()
1509
- template_data = json.loads(template_content)
1510
- return template_data.get("routing")
1511
- except Exception as e:
1512
- self.logger.debug(
1513
- f"Could not load routing from packaged template for {agent_name}: {e}"
1514
- )
1515
- return None
1516
-
1517
- # For development mode, load from filesystem
1518
- templates_dir = (
1519
- self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
1520
- )
1521
- template_file = templates_dir / f"{agent_name}.json"
1522
-
1523
- if template_file.exists():
1524
- with open(template_file) as f:
1525
- template_data = json.load(f)
1526
- return template_data.get("routing")
1527
-
1528
- # Also check for variations in naming (underscore vs dash)
1529
- # Handle common naming variations between deployed .md files and .json templates
1530
- # Remove duplicates by using a set
1531
- alternative_names = list(
1532
- {
1533
- agent_name.replace("-", "_"), # api-qa -> api_qa
1534
- agent_name.replace("_", "-"), # api_qa -> api-qa
1535
- agent_name.replace("-", ""), # api-qa -> apiqa
1536
- agent_name.replace("_", ""), # api_qa -> apiqa
1537
- }
428
+ # Deploy to Claude Code if supported
429
+ deployed = self.output_style_manager.deploy_output_style(
430
+ output_style_content
1538
431
  )
1539
432
 
1540
- for alt_name in alternative_names:
1541
- if alt_name != agent_name:
1542
- alt_file = templates_dir / f"{alt_name}.json"
1543
- if alt_file.exists():
1544
- with open(alt_file) as f:
1545
- template_data = json.load(f)
1546
- return template_data.get("routing")
1547
-
1548
- self.logger.debug(f"No JSON template found for agent: {agent_name}")
1549
- return None
433
+ if deployed:
434
+ self.logger.info("✅ Output style deployed to Claude Code >= 1.0.83")
435
+ else:
436
+ self.logger.info("📝 Output style will be injected into instructions")
1550
437
 
1551
438
  except Exception as e:
1552
- self.logger.debug(f"Could not load routing metadata for {agent_name}: {e}")
1553
- return None
1554
-
1555
- def _generate_agent_selection_guide(self, deployed_agents: list) -> str:
1556
- """Generate Context-Aware Agent Selection guide from deployed agents.
1557
-
1558
- Creates a mapping of task types to appropriate agents based on their
1559
- descriptions and capabilities.
1560
- """
1561
- guide = ""
439
+ self.logger.warning(f" Failed to initialize output style manager: {e}")
1562
440
 
1563
- # Build selection mapping based on deployed agents
1564
- selection_map = {}
441
+ def _log_output_style_status(self) -> None:
442
+ """Log output style status information."""
443
+ if not self.output_style_manager:
444
+ return
1565
445
 
1566
- for agent in deployed_agents:
1567
- agent_id = agent["id"]
1568
- desc_lower = agent["description"].lower()
446
+ claude_version = self.output_style_manager.claude_version
447
+ if claude_version:
448
+ self.logger.info(f"Claude Code version detected: {claude_version}")
1569
449
 
1570
- # Map task types to agents based on their descriptions
1571
- if "implementation" in desc_lower or (
1572
- "engineer" in agent_id and "data" not in agent_id
1573
- ):
1574
- selection_map["Implementation tasks"] = (
1575
- f"{agent['display_name']} (`{agent_id}`)"
1576
- )
1577
- if "codebase analysis" in desc_lower or "research" in agent_id:
1578
- selection_map["Codebase analysis"] = (
1579
- f"{agent['display_name']} (`{agent_id}`)"
1580
- )
1581
- if "testing" in desc_lower or "qa" in agent_id:
1582
- selection_map["Testing/quality"] = (
1583
- f"{agent['display_name']} (`{agent_id}`)"
1584
- )
1585
- if "documentation" in desc_lower:
1586
- selection_map["Documentation"] = (
1587
- f"{agent['display_name']} (`{agent_id}`)"
1588
- )
1589
- if "security" in desc_lower or "sast" in desc_lower:
1590
- selection_map["Security operations"] = (
1591
- f"{agent['display_name']} (`{agent_id}`)"
1592
- )
1593
- if (
1594
- "deployment" in desc_lower
1595
- or "infrastructure" in desc_lower
1596
- or "ops" in agent_id
1597
- ):
1598
- selection_map["Deployment/infrastructure"] = (
1599
- f"{agent['display_name']} (`{agent_id}`)"
1600
- )
1601
- if "data" in desc_lower and (
1602
- "pipeline" in desc_lower or "etl" in desc_lower
1603
- ):
1604
- selection_map["Data pipeline/ETL"] = (
1605
- f"{agent['display_name']} (`{agent_id}`)"
1606
- )
1607
- if "git" in desc_lower or "version control" in desc_lower:
1608
- selection_map["Version control"] = (
1609
- f"{agent['display_name']} (`{agent_id}`)"
1610
- )
1611
- if "ticket" in desc_lower or "epic" in desc_lower:
1612
- selection_map["Ticket/issue management"] = (
1613
- f"{agent['display_name']} (`{agent_id}`)"
1614
- )
1615
- if "browser" in desc_lower or "e2e" in desc_lower:
1616
- selection_map["Browser/E2E testing"] = (
1617
- f"{agent['display_name']} (`{agent_id}`)"
450
+ if self.output_style_manager.supports_output_styles():
451
+ self.logger.info(" Claude Code supports output styles (>= 1.0.83)")
452
+ output_style_path = self.output_style_manager.output_style_path
453
+ if output_style_path.exists():
454
+ self.logger.info(
455
+ f"📁 Output style file exists: {output_style_path}"
456
+ )
457
+ else:
458
+ self.logger.info(
459
+ f"📝 Output style will be created at: {output_style_path}"
460
+ )
461
+ else:
462
+ self.logger.info(
463
+ f"⚠️ Claude Code {claude_version} does not support output styles"
1618
464
  )
1619
- if "frontend" in desc_lower or "ui" in desc_lower or "html" in desc_lower:
1620
- selection_map["Frontend/UI development"] = (
1621
- f"{agent['display_name']} (`{agent_id}`)"
465
+ self.logger.info(
466
+ "📝 Output style will be injected into framework instructions"
1622
467
  )
468
+ else:
469
+ self.logger.info("⚠️ Claude Code not detected or version unknown")
470
+ self.logger.info("📝 Output style will be injected as fallback")
1623
471
 
1624
- # Always include PM questions
1625
- selection_map["PM questions"] = "Answer directly (only exception)"
472
+ # === Logging Methods ===
1626
473
 
1627
- # Format the selection guide
1628
- for task_type, agent_info in selection_map.items():
1629
- guide += f"- **{task_type}** → {agent_info}\n"
474
+ def _log_system_prompt(self) -> None:
475
+ """Log the system prompt if LogManager is available."""
476
+ try:
477
+ from .log_manager import get_log_manager
1630
478
 
1631
- return guide
479
+ log_manager = get_log_manager()
480
+ except ImportError:
481
+ return
1632
482
 
1633
- def _get_fallback_capabilities(self) -> str:
1634
- """Return fallback capabilities when dynamic discovery fails."""
1635
- return """
483
+ try:
484
+ # Get or create event loop
485
+ try:
486
+ loop = asyncio.get_running_loop()
487
+ except RuntimeError:
488
+ loop = asyncio.new_event_loop()
489
+ asyncio.set_event_loop(loop)
490
+
491
+ # Prepare metadata
492
+ metadata = {
493
+ "framework_version": self.framework_version,
494
+ "framework_loaded": self.framework_content.get("loaded", False),
495
+ "session_id": os.environ.get("CLAUDE_SESSION_ID", "unknown"),
496
+ }
1636
497
 
1637
- ## Available Agent Capabilities
498
+ # Log the prompt asynchronously
499
+ instructions = (
500
+ self._format_full_framework()
501
+ if self.framework_content["loaded"]
502
+ else self._format_minimal_framework()
503
+ )
504
+ metadata["instructions_length"] = len(instructions)
1638
505
 
1639
- You have the following specialized agents available for delegation:
506
+ if loop.is_running():
507
+ _task = asyncio.create_task(
508
+ log_manager.log_prompt("system_prompt", instructions, metadata)
509
+ ) # Fire-and-forget logging
510
+ else:
511
+ loop.run_until_complete(
512
+ log_manager.log_prompt("system_prompt", instructions, metadata)
513
+ )
1640
514
 
1641
- - **Engineer** (`engineer`): Code implementation and development
1642
- - **Research** (`research-agent`): Investigation and analysis
1643
- - **QA** (`qa-agent`): Testing and quality assurance
1644
- - **Documentation** (`documentation-agent`): Documentation creation and maintenance
1645
- - **Security** (`security-agent`): Security analysis and protection
1646
- - **Data Engineer** (`data-engineer`): Data management and pipelines
1647
- - **Ops** (`ops-agent`): Deployment and operations
1648
- - **Version Control** (`version-control`): Git operations and version management
515
+ self.logger.debug("System prompt logged to prompts directory")
516
+ except Exception as e:
517
+ self.logger.debug(f"Could not log system prompt: {e}")
1649
518
 
1650
- **IMPORTANT**: Use the exact agent ID in parentheses when delegating tasks.
1651
- """
519
+ # === Agent Registry Methods (backward compatibility) ===
1652
520
 
1653
- def _format_minimal_framework(self) -> str:
1654
- """Format minimal framework instructions when full framework not available."""
1655
- return """
1656
- # Claude PM Framework Instructions
1657
-
1658
- You are operating within a Claude PM Framework deployment.
1659
-
1660
- ## Role
1661
- You are a multi-agent orchestrator. Your primary responsibilities:
1662
- - Delegate tasks to specialized agents via Task Tool
1663
- - Coordinate multi-agent workflows
1664
- - Extract TODO/BUG/FEATURE items for ticket creation
1665
- - NEVER perform direct implementation work
1666
-
1667
- ## Core Agents
1668
- - Documentation Agent - Documentation tasks
1669
- - Engineer Agent - Code implementation
1670
- - QA Agent - Testing and validation
1671
- - Research Agent - Investigation and analysis
1672
- - Version Control Agent - Git operations
1673
-
1674
- ## Important Rules
1675
- 1. Always delegate work via Task Tool
1676
- 2. Provide comprehensive context to agents
1677
- 3. Track all TODO/BUG/FEATURE items
1678
- 4. Maintain project visibility
1679
-
1680
- ---
1681
- """
1682
-
1683
- def get_agent_list(self) -> list:
521
+ def get_agent_list(self) -> List[str]:
1684
522
  """Get list of available agents."""
1685
- # First try agent registry
1686
523
  if self.agent_registry:
1687
524
  agents = self.agent_registry.list_agents()
1688
525
  if agents:
1689
526
  return list(agents.keys())
1690
-
1691
- # Fallback to loaded content
1692
527
  return list(self.framework_content["agents"].keys())
1693
528
 
1694
529
  def get_agent_definition(self, agent_name: str) -> Optional[str]:
1695
530
  """Get specific agent definition."""
1696
- # First try agent registry
1697
531
  if self.agent_registry:
1698
532
  definition = self.agent_registry.get_agent_definition(agent_name)
1699
533
  if definition:
1700
534
  return definition
1701
-
1702
- # Fallback to loaded content
1703
535
  return self.framework_content["agents"].get(agent_name)
1704
536
 
1705
- def get_agent_hierarchy(self) -> Dict[str, list]:
537
+ def get_agent_hierarchy(self) -> Dict[str, List]:
1706
538
  """Get agent hierarchy from registry."""
1707
539
  if self.agent_registry:
1708
540
  return self.agent_registry.get_agent_hierarchy()