claude-mpm 4.7.4__py3-none-any.whl → 4.18.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,568 @@
1
+ """
2
+ Agent Recommender Service for Claude MPM Framework
3
+ ===================================================
4
+
5
+ WHY: Automated agent recommendation is critical for the auto-configuration feature.
6
+ This service analyzes project toolchains and recommends appropriate specialized agents
7
+ using configuration-driven mappings and intelligent scoring algorithms.
8
+
9
+ DESIGN DECISION: Configuration-driven approach using YAML for flexibility and
10
+ maintainability. Scoring algorithm weighs language, framework, and deployment matches
11
+ with configurable weights. Returns ranked recommendations with detailed reasoning.
12
+
13
+ Part of TSK-0054: Auto-Configuration Feature - Phase 3
14
+ """
15
+
16
+ from pathlib import Path
17
+ from typing import Any, Dict, List, Optional
18
+
19
+ import yaml
20
+
21
+ from claude_mpm.core.base_service import BaseService
22
+ from claude_mpm.services.core.interfaces.agent import IAgentRecommender
23
+ from claude_mpm.services.core.models.agent_config import (
24
+ AgentCapabilities,
25
+ AgentRecommendation,
26
+ AgentSpecialization,
27
+ )
28
+ from claude_mpm.services.core.models.toolchain import ToolchainAnalysis
29
+
30
+
31
+ class AgentRecommenderService(BaseService, IAgentRecommender):
32
+ """
33
+ Service for recommending agents based on toolchain analysis.
34
+
35
+ This service:
36
+ - Loads agent capabilities from YAML configuration
37
+ - Calculates match scores between toolchains and agents
38
+ - Returns ranked recommendations with confidence scores
39
+ - Provides detailed reasoning for each recommendation
40
+
41
+ Matching Algorithm:
42
+ - Primary language match (50% weight)
43
+ - Framework match (30% weight)
44
+ - Deployment target match (20% weight)
45
+ - Apply agent-specific confidence weights
46
+ - Framework-specific agents override language agents
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ config_path: Optional[Path] = None,
52
+ config: Optional[Dict[str, Any]] = None,
53
+ container: Optional[Any] = None,
54
+ ):
55
+ """
56
+ Initialize the Agent Recommender Service.
57
+
58
+ Args:
59
+ config_path: Optional path to agent_capabilities.yaml
60
+ config: Optional configuration dictionary
61
+ container: Optional service container for dependency injection
62
+ """
63
+ super().__init__(
64
+ name="AgentRecommenderService",
65
+ config=config,
66
+ enable_enhanced_features=False,
67
+ container=container,
68
+ )
69
+
70
+ # Determine config file path
71
+ if config_path is None:
72
+ # Default to config directory in the package
73
+ package_config_dir = Path(__file__).parent.parent.parent / "config"
74
+ config_path = package_config_dir / "agent_capabilities.yaml"
75
+
76
+ self.config_path = config_path
77
+ self._capabilities_config: Dict[str, Any] = {}
78
+ self._agent_capabilities_cache: Dict[str, AgentCapabilities] = {}
79
+ self._load_configuration()
80
+
81
+ self.logger.info(
82
+ f"AgentRecommenderService initialized with config: {self.config_path}"
83
+ )
84
+
85
+ async def _initialize(self) -> None:
86
+ """Initialize the service (required by BaseService)."""
87
+ # Configuration is loaded in __init__, no additional initialization needed
88
+
89
+ async def _cleanup(self) -> None:
90
+ """Cleanup service resources (required by BaseService)."""
91
+ # Clear caches
92
+ self._agent_capabilities_cache.clear()
93
+ self._capabilities_config.clear()
94
+
95
+ def _load_configuration(self) -> None:
96
+ """
97
+ Load agent capabilities configuration from YAML file.
98
+
99
+ Raises:
100
+ FileNotFoundError: If configuration file does not exist
101
+ yaml.YAMLError: If configuration file is invalid YAML
102
+ """
103
+ if not self.config_path.exists():
104
+ raise FileNotFoundError(
105
+ f"Agent capabilities config not found: {self.config_path}"
106
+ )
107
+
108
+ try:
109
+ with self.config_path.open(encoding="utf-8") as f:
110
+ self._capabilities_config = yaml.safe_load(f)
111
+
112
+ if (
113
+ not self._capabilities_config
114
+ or "agent_capabilities" not in self._capabilities_config
115
+ ):
116
+ raise ValueError(
117
+ "Invalid configuration: missing 'agent_capabilities' section"
118
+ )
119
+
120
+ self.logger.info(
121
+ f"Loaded {len(self._capabilities_config['agent_capabilities'])} "
122
+ f"agent capability definitions"
123
+ )
124
+
125
+ except yaml.YAMLError as e:
126
+ self.logger.error(f"Failed to parse YAML configuration: {e}")
127
+ raise
128
+
129
+ def recommend_agents(
130
+ self,
131
+ toolchain: ToolchainAnalysis,
132
+ constraints: Optional[Dict[str, Any]] = None,
133
+ ) -> List[AgentRecommendation]:
134
+ """
135
+ Recommend agents based on toolchain analysis.
136
+
137
+ Analyzes the toolchain and recommends agents that best match the
138
+ project's technical requirements. Considers:
139
+ - Language compatibility
140
+ - Framework expertise
141
+ - Deployment environment requirements
142
+ - Optional user-defined constraints
143
+
144
+ Args:
145
+ toolchain: Complete toolchain analysis results
146
+ constraints: Optional constraints for recommendations:
147
+ - max_agents: Maximum number of agents to recommend
148
+ - required_capabilities: List of required agent capabilities
149
+ - excluded_agents: List of agent IDs to exclude
150
+ - min_confidence: Minimum confidence score threshold
151
+
152
+ Returns:
153
+ List[AgentRecommendation]: Ordered list of recommended agents
154
+ with confidence scores and reasoning
155
+
156
+ Raises:
157
+ ValueError: If constraints are invalid or contradictory
158
+ """
159
+ constraints = constraints or {}
160
+ min_confidence = constraints.get(
161
+ "min_confidence",
162
+ self._capabilities_config.get("recommendation_rules", {}).get(
163
+ "min_confidence_threshold", 0.5
164
+ ),
165
+ )
166
+ excluded_agents = set(constraints.get("excluded_agents", []))
167
+ max_agents = constraints.get("max_agents")
168
+
169
+ recommendations: List[AgentRecommendation] = []
170
+ agent_configs = self._capabilities_config.get("agent_capabilities", {})
171
+
172
+ # Calculate scores for all agents
173
+ for agent_id, agent_config in agent_configs.items():
174
+ # Skip excluded agents
175
+ if agent_id in excluded_agents:
176
+ continue
177
+
178
+ # Skip agents that shouldn't auto-deploy unless explicitly allowed
179
+ if not agent_config.get("auto_deploy", True) and not constraints.get(
180
+ "include_non_auto_deploy", False
181
+ ):
182
+ continue
183
+
184
+ # Calculate match score
185
+ score = self.match_score(agent_id, toolchain)
186
+
187
+ # Filter by minimum confidence
188
+ if score < min_confidence:
189
+ continue
190
+
191
+ # Get agent capabilities
192
+ capabilities = self.get_agent_capabilities(agent_id)
193
+
194
+ # Generate match reasons and concerns
195
+ match_reasons, concerns = self._generate_reasoning(
196
+ agent_id, agent_config, toolchain, score
197
+ )
198
+
199
+ # Determine deployment priority
200
+ deployment_priority = self._calculate_deployment_priority(
201
+ agent_config, toolchain
202
+ )
203
+
204
+ recommendation = AgentRecommendation(
205
+ agent_id=agent_id,
206
+ agent_name=agent_config.get("name", agent_id),
207
+ confidence_score=score,
208
+ match_reasons=match_reasons,
209
+ concerns=concerns,
210
+ capabilities=capabilities,
211
+ deployment_priority=deployment_priority,
212
+ configuration_hints=self._generate_config_hints(
213
+ agent_config, toolchain
214
+ ),
215
+ metadata={
216
+ "specialization": agent_config.get("specialization"),
217
+ "auto_deploy": agent_config.get("auto_deploy", True),
218
+ },
219
+ )
220
+ recommendations.append(recommendation)
221
+
222
+ # Sort by confidence score (descending), then by deployment priority (ascending)
223
+ recommendations.sort(key=lambda r: (-r.confidence_score, r.deployment_priority))
224
+
225
+ # Apply max agents limit if specified
226
+ if max_agents is not None:
227
+ recommendations = recommendations[:max_agents]
228
+
229
+ self.logger.info(
230
+ f"Generated {len(recommendations)} agent recommendations "
231
+ f"for project: {toolchain.project_path}"
232
+ )
233
+
234
+ return recommendations
235
+
236
+ def get_agent_capabilities(self, agent_id: str) -> AgentCapabilities:
237
+ """
238
+ Get detailed capabilities for an agent.
239
+
240
+ Retrieves comprehensive capability information for a specific agent:
241
+ - Supported languages and frameworks
242
+ - Specialization areas
243
+ - Required toolchain components
244
+ - Performance characteristics
245
+
246
+ Args:
247
+ agent_id: Unique identifier of the agent
248
+
249
+ Returns:
250
+ AgentCapabilities: Complete capability information
251
+
252
+ Raises:
253
+ KeyError: If agent_id does not exist
254
+ """
255
+ # Check cache first
256
+ if agent_id in self._agent_capabilities_cache:
257
+ return self._agent_capabilities_cache[agent_id]
258
+
259
+ # Get from config
260
+ agent_configs = self._capabilities_config.get("agent_capabilities", {})
261
+ if agent_id not in agent_configs:
262
+ raise KeyError(f"Agent not found: {agent_id}")
263
+
264
+ agent_config = agent_configs[agent_id]
265
+ supports = agent_config.get("supports", {})
266
+
267
+ # Determine specializations
268
+ specializations = []
269
+ spec_type = agent_config.get("specialization", "general")
270
+ if spec_type == "engineering":
271
+ specializations.append(AgentSpecialization.LANGUAGE_SPECIFIC)
272
+ elif spec_type == "devops":
273
+ specializations.append(AgentSpecialization.DEVOPS)
274
+
275
+ # Create capabilities object
276
+ capabilities = AgentCapabilities(
277
+ agent_id=agent_id,
278
+ agent_name=agent_config.get("name", agent_id),
279
+ specializations=specializations,
280
+ supported_languages=supports.get("languages", []),
281
+ supported_frameworks=supports.get("frameworks", []),
282
+ required_tools=supports.get("build_tools", []),
283
+ deployment_targets=supports.get("deployment", []),
284
+ description=agent_config.get("description", ""),
285
+ metadata=agent_config.get("metadata", {}),
286
+ )
287
+
288
+ # Cache for future use
289
+ self._agent_capabilities_cache[agent_id] = capabilities
290
+
291
+ return capabilities
292
+
293
+ def match_score(self, agent_id: str, toolchain: ToolchainAnalysis) -> float:
294
+ """
295
+ Calculate match score between agent and toolchain.
296
+
297
+ Computes a numerical score (0.0 to 1.0) indicating how well an agent
298
+ matches the project's toolchain. Higher scores indicate better matches.
299
+ Considers:
300
+ - Language compatibility (50% weight)
301
+ - Framework experience (30% weight)
302
+ - Deployment target alignment (20% weight)
303
+ - Toolchain component coverage
304
+
305
+ Args:
306
+ agent_id: Unique identifier of the agent
307
+ toolchain: Complete toolchain analysis
308
+
309
+ Returns:
310
+ float: Match score between 0.0 (no match) and 1.0 (perfect match)
311
+
312
+ Raises:
313
+ KeyError: If agent_id does not exist
314
+ """
315
+ agent_configs = self._capabilities_config.get("agent_capabilities", {})
316
+ if agent_id not in agent_configs:
317
+ raise KeyError(f"Agent not found: {agent_id}")
318
+
319
+ agent_config = agent_configs[agent_id]
320
+ supports = agent_config.get("supports", {})
321
+
322
+ # Get scoring weights
323
+ scoring_weights = self._capabilities_config.get("recommendation_rules", {}).get(
324
+ "scoring_weights", {}
325
+ )
326
+ language_weight = scoring_weights.get("language_match", 0.5)
327
+ framework_weight = scoring_weights.get("framework_match", 0.3)
328
+ deployment_weight = scoring_weights.get("deployment_match", 0.2)
329
+
330
+ # Calculate language match score
331
+ language_score = self._calculate_language_score(
332
+ supports.get("languages", []), toolchain
333
+ )
334
+
335
+ # Calculate framework match score
336
+ framework_score = self._calculate_framework_score(
337
+ supports.get("frameworks", []), toolchain
338
+ )
339
+
340
+ # Calculate deployment match score
341
+ deployment_score = self._calculate_deployment_score(
342
+ supports.get("deployment", []), toolchain
343
+ )
344
+
345
+ # Calculate base score
346
+ base_score = (
347
+ language_score * language_weight
348
+ + framework_score * framework_weight
349
+ + deployment_score * deployment_weight
350
+ )
351
+
352
+ # Apply agent confidence weight
353
+ agent_confidence_weight = agent_config.get("confidence_weight", 1.0)
354
+ final_score = base_score * agent_confidence_weight
355
+
356
+ # Apply framework priority boost if applicable
357
+ if framework_score > 0.5: # Strong framework match
358
+ framework_boost = self._capabilities_config.get(
359
+ "recommendation_rules", {}
360
+ ).get("framework_priority_boost", 0.15)
361
+ final_score = min(1.0, final_score + framework_boost)
362
+
363
+ # Apply deployment match boost if applicable
364
+ if deployment_score > 0.5: # Strong deployment match
365
+ deployment_boost = self._capabilities_config.get(
366
+ "recommendation_rules", {}
367
+ ).get("deployment_match_boost", 0.1)
368
+ final_score = min(1.0, final_score + deployment_boost)
369
+
370
+ # Ensure score is in valid range and return
371
+ return max(0.0, min(1.0, final_score))
372
+
373
+ def _calculate_language_score(
374
+ self, supported_languages: List[str], toolchain: ToolchainAnalysis
375
+ ) -> float:
376
+ """Calculate language match score."""
377
+ if not supported_languages:
378
+ return 0.0
379
+
380
+ primary_language = toolchain.primary_language.lower()
381
+ all_languages = [lang.lower() for lang in toolchain.all_languages]
382
+
383
+ # Check for primary language match
384
+ for lang in supported_languages:
385
+ if lang.lower() == primary_language:
386
+ return 1.0 # Perfect match on primary language
387
+
388
+ # Check for secondary language match
389
+ for lang in supported_languages:
390
+ if lang.lower() in all_languages:
391
+ return 0.6 # Partial match on secondary language
392
+
393
+ return 0.0
394
+
395
+ def _calculate_framework_score(
396
+ self, supported_frameworks: List[str], toolchain: ToolchainAnalysis
397
+ ) -> float:
398
+ """Calculate framework match score."""
399
+ if not supported_frameworks:
400
+ return 0.0
401
+
402
+ detected_frameworks = [fw.name.lower() for fw in toolchain.frameworks]
403
+ if not detected_frameworks:
404
+ return 0.0
405
+
406
+ # Check for exact framework matches
407
+ matches = 0
408
+ for fw in supported_frameworks:
409
+ fw_lower = fw.lower()
410
+ # Normalize common variants (next.js vs nextjs, etc.)
411
+ fw_normalized = fw_lower.replace(".", "").replace("-", "")
412
+ for detected_fw in detected_frameworks:
413
+ detected_normalized = detected_fw.replace(".", "").replace("-", "")
414
+ if fw_normalized == detected_normalized:
415
+ matches += 1
416
+ break
417
+
418
+ if matches == 0:
419
+ return 0.0
420
+
421
+ # Calculate score based on match proportion
422
+ match_ratio = matches / len(detected_frameworks)
423
+ return min(1.0, match_ratio * 1.2) # Boost for framework matches
424
+
425
+ def _calculate_deployment_score(
426
+ self, supported_deployments: List[str], toolchain: ToolchainAnalysis
427
+ ) -> float:
428
+ """Calculate deployment target match score."""
429
+ if not supported_deployments or not toolchain.deployment_target:
430
+ return 0.0
431
+
432
+ target_platform = toolchain.deployment_target.platform
433
+ target_type = toolchain.deployment_target.target_type
434
+
435
+ # Check for exact platform match
436
+ for deployment in supported_deployments:
437
+ deployment_lower = deployment.lower()
438
+ if target_platform and deployment_lower == target_platform.lower():
439
+ return 1.0 # Perfect match on platform
440
+ if deployment_lower == target_type.lower():
441
+ return 0.8 # Good match on target type
442
+
443
+ # Check for container/cloud general matches
444
+ if any(d.lower() in ["docker", "kubernetes"] for d in supported_deployments):
445
+ if target_type in ["container", "cloud"]:
446
+ return 0.5 # General container/cloud match
447
+
448
+ return 0.0
449
+
450
+ def _generate_reasoning(
451
+ self,
452
+ agent_id: str,
453
+ agent_config: Dict[str, Any],
454
+ toolchain: ToolchainAnalysis,
455
+ score: float,
456
+ ) -> tuple[List[str], List[str]]:
457
+ """
458
+ Generate match reasons and concerns for recommendation.
459
+
460
+ Returns:
461
+ Tuple of (match_reasons, concerns)
462
+ """
463
+ match_reasons = []
464
+ concerns = []
465
+ supports = agent_config.get("supports", {})
466
+
467
+ # Check language match
468
+ primary_language = toolchain.primary_language.lower()
469
+ supported_languages = [lang.lower() for lang in supports.get("languages", [])]
470
+ if primary_language in supported_languages:
471
+ match_reasons.append(
472
+ f"Primary language match: {toolchain.primary_language}"
473
+ )
474
+
475
+ # Check framework matches
476
+ detected_frameworks = [fw.name for fw in toolchain.frameworks]
477
+ supported_frameworks = supports.get("frameworks", [])
478
+ framework_matches = []
479
+ for fw in detected_frameworks:
480
+ for supported_fw in supported_frameworks:
481
+ if fw.lower().replace("-", "").replace(
482
+ ".", ""
483
+ ) == supported_fw.lower().replace("-", "").replace(".", ""):
484
+ framework_matches.append(fw)
485
+ break
486
+
487
+ if framework_matches:
488
+ match_reasons.append(f"Framework expertise: {', '.join(framework_matches)}")
489
+
490
+ # Check deployment target match
491
+ if toolchain.deployment_target:
492
+ supported_deployments = supports.get("deployment", [])
493
+ platform = toolchain.deployment_target.platform
494
+ if platform and any(
495
+ d.lower() == platform.lower() for d in supported_deployments
496
+ ):
497
+ match_reasons.append(f"Deployment platform match: {platform}")
498
+
499
+ # Add concerns for low/medium confidence
500
+ if score < 0.6:
501
+ concerns.append(
502
+ "Moderate confidence - consider reviewing agent capabilities"
503
+ )
504
+ elif score < 0.8:
505
+ concerns.append("Good match but may benefit from additional configuration")
506
+
507
+ # If no specific matches found but score > 0, add general reason
508
+ if not match_reasons and score > 0:
509
+ match_reasons.append(
510
+ f"General {agent_config.get('specialization', 'agent')} capabilities"
511
+ )
512
+
513
+ return match_reasons, concerns
514
+
515
+ def _calculate_deployment_priority(
516
+ self, agent_config: Dict[str, Any], toolchain: ToolchainAnalysis
517
+ ) -> int:
518
+ """
519
+ Calculate deployment priority (lower = higher priority).
520
+
521
+ Priority rules:
522
+ - Framework-specific agents: Priority 1
523
+ - Language-specific engineers: Priority 2
524
+ - DevOps agents: Priority 3
525
+ - General agents: Priority 4
526
+ """
527
+ specialization = agent_config.get("specialization", "general")
528
+ supports = agent_config.get("supports", {})
529
+
530
+ # Check if this is a framework-specific agent
531
+ framework_matches = False
532
+ if toolchain.frameworks:
533
+ detected_frameworks = [fw.name.lower() for fw in toolchain.frameworks]
534
+ supported_frameworks = [fw.lower() for fw in supports.get("frameworks", [])]
535
+ framework_matches = any(
536
+ fw in supported_frameworks for fw in detected_frameworks
537
+ )
538
+
539
+ if framework_matches and specialization == "engineering":
540
+ return 1 # Highest priority for framework-specific engineers
541
+
542
+ if specialization == "engineering":
543
+ return 2 # Language-specific engineers
544
+
545
+ if specialization == "devops":
546
+ return 3 # DevOps agents
547
+
548
+ return 4 # General agents (lowest priority)
549
+
550
+ def _generate_config_hints(
551
+ self, agent_config: Dict[str, Any], toolchain: ToolchainAnalysis
552
+ ) -> Dict[str, Any]:
553
+ """Generate configuration hints for the agent."""
554
+ hints = {}
555
+
556
+ # Add framework-specific hints
557
+ if toolchain.frameworks:
558
+ hints["detected_frameworks"] = [fw.name for fw in toolchain.frameworks]
559
+
560
+ # Add deployment hints
561
+ if toolchain.deployment_target:
562
+ hints["deployment_target"] = toolchain.deployment_target.platform
563
+
564
+ # Add build tool hints
565
+ if toolchain.build_tools:
566
+ hints["build_tools"] = [tool.name for tool in toolchain.build_tools]
567
+
568
+ return hints
@@ -36,6 +36,7 @@ from watchdog.events import FileSystemEvent, FileSystemEventHandler
36
36
  from watchdog.observers import Observer
37
37
 
38
38
  from claude_mpm.core.base_service import BaseService
39
+ from claude_mpm.core.enums import OperationResult
39
40
  from claude_mpm.core.logging_utils import get_logger
40
41
  from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
41
42
  from claude_mpm.core.unified_paths import get_path_manager
@@ -551,12 +552,14 @@ class AgentModificationTracker(BaseService):
551
552
  errors.append(f"File does not exist: {modification.file_path}")
552
553
 
553
554
  # Update validation status
554
- modification.validation_status = "failed" if errors else "passed"
555
+ modification.validation_status = (
556
+ OperationResult.FAILED if errors else OperationResult.SUCCESS
557
+ )
555
558
  modification.validation_errors = errors
556
559
 
557
560
  except Exception as e:
558
561
  self.logger.error(f"Validation error: {e}")
559
- modification.validation_status = "error"
562
+ modification.validation_status = OperationResult.ERROR
560
563
  modification.validation_errors.append(str(e))
561
564
 
562
565
  async def _invalidate_agent_cache(self, agent_name: str) -> None:
@@ -12,6 +12,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
12
12
  from typing import Any, Dict, List
13
13
 
14
14
  from claude_mpm.core.base_service import BaseService
15
+ from claude_mpm.core.enums import OperationResult
15
16
  from claude_mpm.services.core.interfaces import CommandHandlerInterface
16
17
 
17
18
 
@@ -169,7 +170,7 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
169
170
  if command == "test":
170
171
  success = self._handle_test_command(args)
171
172
  return {
172
- "success": success,
173
+ OperationResult.SUCCESS.value: success,
173
174
  "command": command,
174
175
  "args": args,
175
176
  "message": (
@@ -179,7 +180,7 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
179
180
  if command == "agents":
180
181
  success = self._handle_agents_command(args)
181
182
  return {
182
- "success": success,
183
+ OperationResult.SUCCESS.value: success,
183
184
  "command": command,
184
185
  "args": args,
185
186
  "message": (
@@ -189,14 +190,19 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
189
190
  ),
190
191
  }
191
192
  return {
192
- "success": False,
193
+ OperationResult.SUCCESS.value: False,
193
194
  "command": command,
194
195
  "args": args,
195
- "error": f"Unknown command: {command}",
196
+ OperationResult.ERROR.value: f"Unknown command: {command}",
196
197
  "available_commands": self.get_available_commands(),
197
198
  }
198
199
  except Exception as e:
199
- return {"success": False, "command": command, "args": args, "error": str(e)}
200
+ return {
201
+ OperationResult.SUCCESS.value: False,
202
+ "command": command,
203
+ "args": args,
204
+ OperationResult.ERROR.value: str(e),
205
+ }
200
206
 
201
207
  def get_command_help(self, command: str) -> str:
202
208
  """Get help text for a specific command.