claude-mpm 4.4.0__py3-none-any.whl → 4.4.4__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 (129) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/WORKFLOW.md +2 -14
  3. claude_mpm/agents/agent_loader.py +3 -2
  4. claude_mpm/agents/agent_loader_integration.py +2 -1
  5. claude_mpm/agents/async_agent_loader.py +2 -2
  6. claude_mpm/agents/base_agent_loader.py +2 -2
  7. claude_mpm/agents/frontmatter_validator.py +1 -0
  8. claude_mpm/agents/system_agent_config.py +2 -1
  9. claude_mpm/cli/commands/configure.py +2 -29
  10. claude_mpm/cli/commands/doctor.py +44 -5
  11. claude_mpm/cli/commands/mpm_init.py +117 -63
  12. claude_mpm/cli/parsers/configure_parser.py +6 -15
  13. claude_mpm/cli/startup_logging.py +1 -3
  14. claude_mpm/config/agent_config.py +1 -1
  15. claude_mpm/config/paths.py +2 -1
  16. claude_mpm/core/agent_name_normalizer.py +1 -0
  17. claude_mpm/core/config.py +2 -1
  18. claude_mpm/core/config_aliases.py +2 -1
  19. claude_mpm/core/file_utils.py +0 -1
  20. claude_mpm/core/framework/__init__.py +38 -0
  21. claude_mpm/core/framework/formatters/__init__.py +11 -0
  22. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  23. claude_mpm/core/framework/formatters/content_formatter.py +288 -0
  24. claude_mpm/core/framework/formatters/context_generator.py +184 -0
  25. claude_mpm/core/framework/loaders/__init__.py +13 -0
  26. claude_mpm/core/framework/loaders/agent_loader.py +206 -0
  27. claude_mpm/core/framework/loaders/file_loader.py +223 -0
  28. claude_mpm/core/framework/loaders/instruction_loader.py +161 -0
  29. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  30. claude_mpm/core/framework/processors/__init__.py +11 -0
  31. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  32. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  33. claude_mpm/core/framework/processors/template_processor.py +244 -0
  34. claude_mpm/core/framework_loader.py +298 -1795
  35. claude_mpm/core/log_manager.py +2 -1
  36. claude_mpm/core/tool_access_control.py +1 -0
  37. claude_mpm/core/unified_agent_registry.py +2 -1
  38. claude_mpm/core/unified_paths.py +1 -0
  39. claude_mpm/experimental/cli_enhancements.py +1 -0
  40. claude_mpm/hooks/__init__.py +9 -1
  41. claude_mpm/hooks/base_hook.py +1 -0
  42. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  43. claude_mpm/hooks/kuzu_memory_hook.py +359 -0
  44. claude_mpm/hooks/validation_hooks.py +1 -1
  45. claude_mpm/scripts/mpm_doctor.py +1 -0
  46. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  47. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  48. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  49. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  50. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  51. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  52. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  53. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  54. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  55. claude_mpm/services/async_session_logger.py +1 -1
  56. claude_mpm/services/claude_session_logger.py +1 -0
  57. claude_mpm/services/core/path_resolver.py +2 -0
  58. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  59. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  60. claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
  61. claude_mpm/services/diagnostics/diagnostic_runner.py +4 -0
  62. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  63. claude_mpm/services/event_bus/direct_relay.py +2 -1
  64. claude_mpm/services/event_bus/event_bus.py +1 -0
  65. claude_mpm/services/event_bus/relay.py +3 -2
  66. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  67. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  68. claude_mpm/services/mcp_config_manager.py +67 -4
  69. claude_mpm/services/mcp_gateway/core/process_pool.py +320 -0
  70. claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
  71. claude_mpm/services/mcp_gateway/main.py +3 -13
  72. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
  73. claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
  74. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +38 -6
  75. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +527 -0
  76. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  77. claude_mpm/services/project/archive_manager.py +159 -96
  78. claude_mpm/services/project/documentation_manager.py +64 -45
  79. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  80. claude_mpm/services/project/project_organizer.py +225 -131
  81. claude_mpm/services/response_tracker.py +1 -1
  82. claude_mpm/services/shared/__init__.py +2 -1
  83. claude_mpm/services/shared/service_factory.py +8 -5
  84. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  85. claude_mpm/services/unified/__init__.py +1 -1
  86. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  87. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  88. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  89. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  90. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  91. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  92. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  93. claude_mpm/services/unified/config_strategies/config_schema.py +735 -0
  94. claude_mpm/services/unified/config_strategies/context_strategy.py +750 -0
  95. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1009 -0
  96. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +879 -0
  97. claude_mpm/services/unified/config_strategies/unified_config_service.py +814 -0
  98. claude_mpm/services/unified/config_strategies/validation_strategy.py +1144 -0
  99. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  100. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  101. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  102. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  103. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  104. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  105. claude_mpm/services/unified/interfaces.py +0 -26
  106. claude_mpm/services/unified/migration.py +17 -40
  107. claude_mpm/services/unified/strategies.py +9 -26
  108. claude_mpm/services/unified/unified_analyzer.py +48 -44
  109. claude_mpm/services/unified/unified_config.py +21 -19
  110. claude_mpm/services/unified/unified_deployment.py +21 -26
  111. claude_mpm/storage/state_storage.py +1 -0
  112. claude_mpm/utils/agent_dependency_loader.py +18 -6
  113. claude_mpm/utils/common.py +14 -12
  114. claude_mpm/utils/database_connector.py +15 -12
  115. claude_mpm/utils/error_handler.py +1 -0
  116. claude_mpm/utils/log_cleanup.py +1 -0
  117. claude_mpm/utils/path_operations.py +1 -0
  118. claude_mpm/utils/session_logging.py +1 -1
  119. claude_mpm/utils/subprocess_utils.py +1 -0
  120. claude_mpm/validation/agent_validator.py +1 -1
  121. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +23 -17
  122. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +126 -105
  123. claude_mpm/cli/commands/configure_tui.py +0 -1927
  124. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  125. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  126. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
  127. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
  128. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
  129. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
@@ -25,11 +25,11 @@ def add_configure_subparser(subparsers) -> argparse.ArgumentParser:
25
25
  Returns:
26
26
  The configured configure subparser
27
27
  """
28
- # Configure command - interactive TUI configuration
28
+ # Configure command - interactive configuration
29
29
  configure_parser = subparsers.add_parser(
30
30
  CLICommands.CONFIGURE.value,
31
- help="Interactive terminal-based configuration interface for managing agents and behaviors",
32
- description="Launch an interactive Rich-based TUI for configuring claude-mpm agents, templates, and behavior files",
31
+ help="Interactive configuration interface for managing agents and behaviors",
32
+ description="Launch an interactive Rich-based menu for configuring claude-mpm agents, templates, and behavior files",
33
33
  )
34
34
 
35
35
  # Add common arguments
@@ -122,21 +122,12 @@ def add_configure_subparser(subparsers) -> argparse.ArgumentParser:
122
122
  # Display options
123
123
  display_group = configure_parser.add_argument_group("display options")
124
124
  display_group.add_argument(
125
- "--no-colors", action="store_true", help="Disable colored output in the TUI"
126
- )
127
- display_group.add_argument(
128
- "--compact", action="store_true", help="Use compact display mode"
129
- )
130
- display_group.add_argument(
131
- "--force-rich",
125
+ "--no-colors",
132
126
  action="store_true",
133
- help="Force use of Rich menu interface instead of full-screen Textual TUI",
127
+ help="Disable colored output in the interface",
134
128
  )
135
129
  display_group.add_argument(
136
- "--no-textual",
137
- dest="use_textual",
138
- action="store_false",
139
- help="Disable Textual TUI and use Rich menu interface",
130
+ "--compact", action="store_true", help="Use compact display mode"
140
131
  )
141
132
 
142
133
  return configure_parser
@@ -687,9 +687,7 @@ async def trigger_vector_search_indexing(project_root: Optional[Path] = None) ->
687
687
 
688
688
  # Store PID for logging
689
689
  pid = process.pid
690
- logger.debug(
691
- f"MCP Vector Search: Indexing process started (PID: {pid})"
692
- )
690
+ logger.debug(f"MCP Vector Search: Indexing process started (PID: {pid})")
693
691
 
694
692
  # Don't wait for completion - let it run independently in the background
695
693
  # We don't need to track its completion, so we can safely detach
@@ -20,10 +20,10 @@ from enum import Enum
20
20
  from pathlib import Path
21
21
  from typing import Any, Dict, List, Optional
22
22
 
23
+ from claude_mpm.core.logging_utils import get_logger
23
24
  from claude_mpm.core.shared.config_loader import ConfigLoader, ConfigPattern
24
25
  from claude_mpm.core.unified_paths import get_path_manager
25
26
 
26
- from claude_mpm.core.logging_utils import get_logger
27
27
  logger = get_logger(__name__)
28
28
 
29
29
 
@@ -11,10 +11,11 @@ without fragile parent.parent.parent patterns.
11
11
  from pathlib import Path
12
12
  from typing import Optional, Union
13
13
 
14
+ from claude_mpm.core.logging_utils import get_logger
15
+
14
16
  # Import from the unified path management system
15
17
  from ..core.unified_paths import get_path_manager
16
18
 
17
- from claude_mpm.core.logging_utils import get_logger
18
19
  logger = get_logger(__name__)
19
20
 
20
21
 
@@ -3,6 +3,7 @@
3
3
  from typing import Optional
4
4
 
5
5
  from claude_mpm.core.logging_utils import get_logger
6
+
6
7
  logger = get_logger(__name__)
7
8
 
8
9
 
claude_mpm/core/config.py CHANGED
@@ -14,11 +14,12 @@ from typing import Any, Dict, List, Optional, Tuple, Union
14
14
 
15
15
  import yaml
16
16
 
17
+ from claude_mpm.core.logging_utils import get_logger
18
+
17
19
  from ..utils.config_manager import ConfigurationManager
18
20
  from .exceptions import ConfigurationError, FileOperationError
19
21
  from .unified_paths import get_path_manager
20
22
 
21
- from claude_mpm.core.logging_utils import get_logger
22
23
  logger = get_logger(__name__)
23
24
 
24
25
 
@@ -16,10 +16,11 @@ Aliases are stored in ~/.claude-mpm/config_aliases.json
16
16
  import json
17
17
  from typing import Dict, List, Optional, Tuple
18
18
 
19
+ from claude_mpm.core.logging_utils import get_logger
20
+
19
21
  from ..utils.config_manager import ConfigurationManager
20
22
  from .unified_paths import get_path_manager
21
23
 
22
- from claude_mpm.core.logging_utils import get_logger
23
24
  logger = get_logger(__name__)
24
25
 
25
26
 
@@ -22,7 +22,6 @@ from claude_mpm.core.logging_utils import get_logger
22
22
  logger = get_logger(__name__)
23
23
 
24
24
 
25
-
26
25
  # ==============================================================================
27
26
  # PATH UTILITIES
28
27
  # ==============================================================================
@@ -0,0 +1,38 @@
1
+ """Framework module for Claude MPM.
2
+
3
+ This module provides the modular framework loading system with specialized components
4
+ for handling different aspects of framework initialization and management.
5
+ """
6
+
7
+ from .formatters import (
8
+ CapabilityGenerator,
9
+ ContentFormatter,
10
+ ContextGenerator,
11
+ )
12
+ from .loaders import (
13
+ AgentLoader,
14
+ FileLoader,
15
+ InstructionLoader,
16
+ PackagedLoader,
17
+ )
18
+ from .processors import (
19
+ MemoryProcessor,
20
+ MetadataProcessor,
21
+ TemplateProcessor,
22
+ )
23
+
24
+ __all__ = [
25
+ # Loaders
26
+ "FileLoader",
27
+ "PackagedLoader",
28
+ "InstructionLoader",
29
+ "AgentLoader",
30
+ # Formatters
31
+ "ContentFormatter",
32
+ "CapabilityGenerator",
33
+ "ContextGenerator",
34
+ # Processors
35
+ "MetadataProcessor",
36
+ "TemplateProcessor",
37
+ "MemoryProcessor",
38
+ ]
@@ -0,0 +1,11 @@
1
+ """Framework formatters for content generation and formatting."""
2
+
3
+ from .capability_generator import CapabilityGenerator
4
+ from .content_formatter import ContentFormatter
5
+ from .context_generator import ContextGenerator
6
+
7
+ __all__ = [
8
+ "CapabilityGenerator",
9
+ "ContentFormatter",
10
+ "ContextGenerator",
11
+ ]
@@ -0,0 +1,367 @@
1
+ """Agent capability generator for dynamic agent discovery."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ import yaml
8
+
9
+ from claude_mpm.core.logging_utils import get_logger
10
+
11
+ # Import resource handling for packaged installations
12
+ try:
13
+ from importlib.resources import files
14
+ except ImportError:
15
+ try:
16
+ from importlib_resources import files
17
+ except ImportError:
18
+ files = None
19
+
20
+
21
+ class CapabilityGenerator:
22
+ """Generates agent capability sections from deployed agents."""
23
+
24
+ def __init__(self):
25
+ """Initialize the capability generator."""
26
+ self.logger = get_logger("capability_generator")
27
+
28
+ def generate_capabilities_section(
29
+ self,
30
+ deployed_agents: List[Dict[str, Any]],
31
+ local_agents: Dict[str, Dict[str, Any]],
32
+ ) -> str:
33
+ """Generate dynamic agent capabilities section.
34
+
35
+ Args:
36
+ deployed_agents: List of deployed agent metadata
37
+ local_agents: Dictionary of local JSON template agents
38
+
39
+ Returns:
40
+ Formatted capabilities section string
41
+ """
42
+ # Build capabilities section
43
+ section = "\n\n## Available Agent Capabilities\n\n"
44
+
45
+ # Combine deployed and local agents
46
+ all_agents = {} # key: agent_id, value: (agent_data, priority)
47
+
48
+ # Add local agents first (highest priority)
49
+ for agent_id, agent_data in local_agents.items():
50
+ all_agents[agent_id] = (agent_data, -1) # Priority -1 for local agents
51
+
52
+ # Add deployed agents with lower priority
53
+ for priority, agent_data in enumerate(deployed_agents):
54
+ agent_id = agent_data["id"]
55
+ # Only add if not already present
56
+ if agent_id not in all_agents:
57
+ all_agents[agent_id] = (agent_data, priority)
58
+
59
+ # Extract just the agent data and sort
60
+ final_agents = [agent_data for agent_data, _ in all_agents.values()]
61
+
62
+ if not final_agents:
63
+ return self.get_fallback_capabilities()
64
+
65
+ # Sort agents alphabetically by ID
66
+ final_agents.sort(key=lambda x: x["id"])
67
+
68
+ # Display all agents with their rich descriptions
69
+ for agent in final_agents:
70
+ # Clean up display name - handle common acronyms
71
+ display_name = agent.get("display_name", agent["id"])
72
+ display_name = (
73
+ display_name.replace("Qa ", "QA ")
74
+ .replace("Ui ", "UI ")
75
+ .replace("Api ", "API ")
76
+ )
77
+ if display_name.lower() == "qa agent":
78
+ display_name = "QA Agent"
79
+
80
+ # Add local indicator if this is a local agent
81
+ if agent.get("is_local"):
82
+ tier_label = f" [LOCAL-{agent.get('tier', 'PROJECT').upper()}]"
83
+ section += f"\n### {display_name} (`{agent['id']}`) {tier_label}\n"
84
+ else:
85
+ section += f"\n### {display_name} (`{agent['id']}`)\n"
86
+
87
+ section += f"{agent.get('description', 'Specialized agent')}\n"
88
+
89
+ # Add routing information if available
90
+ if agent.get("routing"):
91
+ routing = agent["routing"]
92
+ routing_hints = []
93
+
94
+ if routing.get("keywords"):
95
+ # Show first 5 keywords for brevity
96
+ keywords = routing["keywords"][:5]
97
+ routing_hints.append(f"Keywords: {', '.join(keywords)}")
98
+
99
+ if routing.get("paths"):
100
+ # Show first 3 paths for brevity
101
+ paths = routing["paths"][:3]
102
+ routing_hints.append(f"Paths: {', '.join(paths)}")
103
+
104
+ if routing.get("priority"):
105
+ routing_hints.append(f"Priority: {routing['priority']}")
106
+
107
+ if routing_hints:
108
+ section += f"- **Routing**: {' | '.join(routing_hints)}\n"
109
+
110
+ # Add when_to_use if present
111
+ if routing.get("when_to_use"):
112
+ section += f"- **When to use**: {routing['when_to_use']}\n"
113
+
114
+ # Add any additional metadata if present
115
+ if agent.get("authority"):
116
+ section += f"- **Authority**: {agent['authority']}\n"
117
+ if agent.get("primary_function"):
118
+ section += f"- **Primary Function**: {agent['primary_function']}\n"
119
+ if agent.get("handoff_to"):
120
+ section += f"- **Handoff To**: {agent['handoff_to']}\n"
121
+ if agent.get("tools") and agent["tools"] != "standard":
122
+ section += f"- **Tools**: {agent['tools']}\n"
123
+ if agent.get("model") and agent["model"] != "opus":
124
+ section += f"- **Model**: {agent['model']}\n"
125
+
126
+ # Add memory routing information if available
127
+ if agent.get("memory_routing"):
128
+ memory_routing = agent["memory_routing"]
129
+ if memory_routing.get("description"):
130
+ section += (
131
+ f"- **Memory Routing**: {memory_routing['description']}\n"
132
+ )
133
+
134
+ # Add simple Context-Aware Agent Selection
135
+ section += "\n## Context-Aware Agent Selection\n\n"
136
+ section += "Select agents based on their descriptions above. Key principles:\n"
137
+ section += "- **PM questions** → Answer directly (only exception)\n"
138
+ section += "- Match task requirements to agent descriptions and authority\n"
139
+ section += "- Consider agent handoff recommendations\n"
140
+ section += "- Use the agent ID in parentheses when delegating via Task tool\n"
141
+
142
+ # Add summary
143
+ section += f"\n**Total Available Agents**: {len(final_agents)}\n"
144
+
145
+ return section
146
+
147
+ def parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
148
+ """Parse agent metadata from deployed agent file.
149
+
150
+ Args:
151
+ agent_file: Path to deployed agent file
152
+
153
+ Returns:
154
+ Dictionary with agent metadata or None
155
+ """
156
+ try:
157
+ with open(agent_file) as f:
158
+ content = f.read()
159
+
160
+ # Default values
161
+ agent_data = {
162
+ "id": agent_file.stem,
163
+ "display_name": agent_file.stem.replace("_", " ")
164
+ .replace("-", " ")
165
+ .title(),
166
+ "description": "Specialized agent",
167
+ }
168
+
169
+ # Extract YAML frontmatter if present
170
+ if content.startswith("---"):
171
+ end_marker = content.find("---", 3)
172
+ if end_marker > 0:
173
+ frontmatter = content[3:end_marker]
174
+ metadata = yaml.safe_load(frontmatter)
175
+ if metadata:
176
+ # Use name as ID for Task tool
177
+ agent_data["id"] = metadata.get("name", agent_data["id"])
178
+ agent_data["display_name"] = (
179
+ metadata.get("name", agent_data["display_name"])
180
+ .replace("-", " ")
181
+ .title()
182
+ )
183
+
184
+ # Copy all metadata fields directly
185
+ for key, value in metadata.items():
186
+ if key not in ["name"]: # Skip already processed fields
187
+ agent_data[key] = value
188
+
189
+ # Try to load routing metadata from JSON template if not in YAML frontmatter
190
+ if "routing" not in agent_data:
191
+ routing_data = self.load_routing_from_template(agent_file.stem)
192
+ if routing_data:
193
+ agent_data["routing"] = routing_data
194
+
195
+ # Try to load memory routing metadata from JSON template
196
+ if "memory_routing" not in agent_data:
197
+ memory_routing_data = self.load_memory_routing_from_template(
198
+ agent_file.stem
199
+ )
200
+ if memory_routing_data:
201
+ agent_data["memory_routing"] = memory_routing_data
202
+
203
+ return agent_data
204
+
205
+ except Exception as e:
206
+ self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
207
+ return None
208
+
209
+ def load_routing_from_template(
210
+ self, agent_name: str, framework_path: Optional[Path] = None
211
+ ) -> Optional[Dict[str, Any]]:
212
+ """Load routing metadata from agent JSON template.
213
+
214
+ Args:
215
+ agent_name: Name of the agent
216
+ framework_path: Path to framework installation
217
+
218
+ Returns:
219
+ Dictionary with routing metadata or None if not found
220
+ """
221
+ try:
222
+ # Check if we have a framework path
223
+ if not framework_path or framework_path == Path("__PACKAGED__"):
224
+ # For packaged installations, try to load from package resources
225
+ if files:
226
+ try:
227
+ templates_package = files("claude_mpm.agents.templates")
228
+ template_file = templates_package / f"{agent_name}.json"
229
+
230
+ if template_file.is_file():
231
+ template_content = template_file.read_text()
232
+ template_data = json.loads(template_content)
233
+ return template_data.get("routing")
234
+ except Exception as e:
235
+ self.logger.debug(
236
+ f"Could not load routing from packaged template for {agent_name}: {e}"
237
+ )
238
+ return None
239
+
240
+ # For development mode, load from filesystem
241
+ templates_dir = (
242
+ framework_path / "src" / "claude_mpm" / "agents" / "templates"
243
+ )
244
+ template_file = templates_dir / f"{agent_name}.json"
245
+
246
+ if template_file.exists():
247
+ with open(template_file) as f:
248
+ template_data = json.load(f)
249
+ return template_data.get("routing")
250
+
251
+ # Also check for variations in naming (underscore vs dash)
252
+ alternative_names = list(
253
+ {
254
+ agent_name.replace("-", "_"),
255
+ agent_name.replace("_", "-"),
256
+ agent_name.replace("-", ""),
257
+ agent_name.replace("_", ""),
258
+ }
259
+ )
260
+
261
+ for alt_name in alternative_names:
262
+ if alt_name != agent_name:
263
+ alt_file = templates_dir / f"{alt_name}.json"
264
+ if alt_file.exists():
265
+ with open(alt_file) as f:
266
+ template_data = json.load(f)
267
+ return template_data.get("routing")
268
+
269
+ return None
270
+
271
+ except Exception as e:
272
+ self.logger.debug(f"Could not load routing metadata for {agent_name}: {e}")
273
+ return None
274
+
275
+ def load_memory_routing_from_template(
276
+ self, agent_name: str, framework_path: Optional[Path] = None
277
+ ) -> Optional[Dict[str, Any]]:
278
+ """Load memory routing metadata from agent JSON template.
279
+
280
+ Args:
281
+ agent_name: Name of the agent
282
+ framework_path: Path to framework installation
283
+
284
+ Returns:
285
+ Dictionary with memory routing metadata or None if not found
286
+ """
287
+ try:
288
+ # Check if we have a framework path
289
+ if not framework_path or framework_path == Path("__PACKAGED__"):
290
+ # For packaged installations, try to load from package resources
291
+ if files:
292
+ try:
293
+ templates_package = files("claude_mpm.agents.templates")
294
+ template_file = templates_package / f"{agent_name}.json"
295
+
296
+ if template_file.is_file():
297
+ template_content = template_file.read_text()
298
+ template_data = json.loads(template_content)
299
+ return template_data.get("memory_routing")
300
+ except Exception as e:
301
+ self.logger.debug(
302
+ f"Could not load memory routing from packaged template for {agent_name}: {e}"
303
+ )
304
+ return None
305
+
306
+ # For development mode, load from filesystem
307
+ templates_dir = (
308
+ framework_path / "src" / "claude_mpm" / "agents" / "templates"
309
+ )
310
+ template_file = templates_dir / f"{agent_name}.json"
311
+
312
+ if template_file.exists():
313
+ with open(template_file) as f:
314
+ template_data = json.load(f)
315
+ return template_data.get("memory_routing")
316
+
317
+ # Also check for variations in naming
318
+ alternative_names = list(
319
+ {
320
+ agent_name.replace("-", "_"),
321
+ agent_name.replace("_", "-"),
322
+ agent_name.replace("-agent", ""),
323
+ agent_name.replace("_agent", ""),
324
+ agent_name + "_agent",
325
+ agent_name + "-agent",
326
+ }
327
+ )
328
+
329
+ for alt_name in alternative_names:
330
+ if alt_name != agent_name:
331
+ alt_file = templates_dir / f"{alt_name}.json"
332
+ if alt_file.exists():
333
+ with open(alt_file) as f:
334
+ template_data = json.load(f)
335
+ return template_data.get("memory_routing")
336
+
337
+ return None
338
+
339
+ except Exception as e:
340
+ self.logger.debug(
341
+ f"Could not load memory routing from template for {agent_name}: {e}"
342
+ )
343
+ return None
344
+
345
+ def get_fallback_capabilities(self) -> str:
346
+ """Return fallback capabilities when dynamic discovery fails.
347
+
348
+ Returns:
349
+ Fallback agent capabilities section
350
+ """
351
+ return """
352
+
353
+ ## Available Agent Capabilities
354
+
355
+ You have the following specialized agents available for delegation:
356
+
357
+ - **Engineer** (`engineer`): Code implementation and development
358
+ - **Research** (`research-agent`): Investigation and analysis
359
+ - **QA** (`qa-agent`): Testing and quality assurance
360
+ - **Documentation** (`documentation-agent`): Documentation creation and maintenance
361
+ - **Security** (`security-agent`): Security analysis and protection
362
+ - **Data Engineer** (`data-engineer`): Data management and pipelines
363
+ - **Ops** (`ops-agent`): Deployment and operations
364
+ - **Version Control** (`version-control`): Git operations and version management
365
+
366
+ **IMPORTANT**: Use the exact agent ID in parentheses when delegating tasks.
367
+ """