claude-mpm 0.3.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 (159) hide show
  1. claude_mpm/__init__.py +17 -0
  2. claude_mpm/__main__.py +14 -0
  3. claude_mpm/_version.py +32 -0
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +88 -0
  5. claude_mpm/agents/INSTRUCTIONS.md +375 -0
  6. claude_mpm/agents/__init__.py +118 -0
  7. claude_mpm/agents/agent_loader.py +621 -0
  8. claude_mpm/agents/agent_loader_integration.py +229 -0
  9. claude_mpm/agents/agents_metadata.py +204 -0
  10. claude_mpm/agents/base_agent.json +27 -0
  11. claude_mpm/agents/base_agent_loader.py +519 -0
  12. claude_mpm/agents/schema/agent_schema.json +160 -0
  13. claude_mpm/agents/system_agent_config.py +587 -0
  14. claude_mpm/agents/templates/__init__.py +101 -0
  15. claude_mpm/agents/templates/data_engineer_agent.json +46 -0
  16. claude_mpm/agents/templates/documentation_agent.json +45 -0
  17. claude_mpm/agents/templates/engineer_agent.json +49 -0
  18. claude_mpm/agents/templates/ops_agent.json +46 -0
  19. claude_mpm/agents/templates/qa_agent.json +45 -0
  20. claude_mpm/agents/templates/research_agent.json +49 -0
  21. claude_mpm/agents/templates/security_agent.json +46 -0
  22. claude_mpm/agents/templates/update-optimized-specialized-agents.json +374 -0
  23. claude_mpm/agents/templates/version_control_agent.json +46 -0
  24. claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +6 -0
  25. claude_mpm/cli.py +655 -0
  26. claude_mpm/cli_main.py +13 -0
  27. claude_mpm/cli_module/__init__.py +15 -0
  28. claude_mpm/cli_module/args.py +222 -0
  29. claude_mpm/cli_module/commands.py +203 -0
  30. claude_mpm/cli_module/migration_example.py +183 -0
  31. claude_mpm/cli_module/refactoring_guide.md +253 -0
  32. claude_mpm/cli_old/__init__.py +1 -0
  33. claude_mpm/cli_old/ticket_cli.py +102 -0
  34. claude_mpm/config/__init__.py +5 -0
  35. claude_mpm/config/hook_config.py +42 -0
  36. claude_mpm/constants.py +150 -0
  37. claude_mpm/core/__init__.py +45 -0
  38. claude_mpm/core/agent_name_normalizer.py +248 -0
  39. claude_mpm/core/agent_registry.py +627 -0
  40. claude_mpm/core/agent_registry.py.bak +312 -0
  41. claude_mpm/core/agent_session_manager.py +273 -0
  42. claude_mpm/core/base_service.py +747 -0
  43. claude_mpm/core/base_service.py.bak +406 -0
  44. claude_mpm/core/config.py +334 -0
  45. claude_mpm/core/config_aliases.py +292 -0
  46. claude_mpm/core/container.py +347 -0
  47. claude_mpm/core/factories.py +281 -0
  48. claude_mpm/core/framework_loader.py +472 -0
  49. claude_mpm/core/injectable_service.py +206 -0
  50. claude_mpm/core/interfaces.py +539 -0
  51. claude_mpm/core/logger.py +468 -0
  52. claude_mpm/core/minimal_framework_loader.py +107 -0
  53. claude_mpm/core/mixins.py +150 -0
  54. claude_mpm/core/service_registry.py +299 -0
  55. claude_mpm/core/session_manager.py +190 -0
  56. claude_mpm/core/simple_runner.py +511 -0
  57. claude_mpm/core/tool_access_control.py +173 -0
  58. claude_mpm/hooks/README.md +243 -0
  59. claude_mpm/hooks/__init__.py +5 -0
  60. claude_mpm/hooks/base_hook.py +154 -0
  61. claude_mpm/hooks/builtin/__init__.py +1 -0
  62. claude_mpm/hooks/builtin/logging_hook_example.py +165 -0
  63. claude_mpm/hooks/builtin/post_delegation_hook_example.py +124 -0
  64. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +125 -0
  65. claude_mpm/hooks/builtin/submit_hook_example.py +100 -0
  66. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +237 -0
  67. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +239 -0
  68. claude_mpm/hooks/builtin/workflow_start_hook.py +181 -0
  69. claude_mpm/hooks/hook_client.py +264 -0
  70. claude_mpm/hooks/hook_runner.py +370 -0
  71. claude_mpm/hooks/json_rpc_executor.py +259 -0
  72. claude_mpm/hooks/json_rpc_hook_client.py +319 -0
  73. claude_mpm/hooks/tool_call_interceptor.py +204 -0
  74. claude_mpm/init.py +246 -0
  75. claude_mpm/orchestration/SUBPROCESS_DESIGN.md +66 -0
  76. claude_mpm/orchestration/__init__.py +6 -0
  77. claude_mpm/orchestration/archive/direct_orchestrator.py +195 -0
  78. claude_mpm/orchestration/archive/factory.py +215 -0
  79. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +188 -0
  80. claude_mpm/orchestration/archive/hook_integration_example.py +178 -0
  81. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +826 -0
  82. claude_mpm/orchestration/archive/orchestrator.py +501 -0
  83. claude_mpm/orchestration/archive/pexpect_orchestrator.py +252 -0
  84. claude_mpm/orchestration/archive/pty_orchestrator.py +270 -0
  85. claude_mpm/orchestration/archive/simple_orchestrator.py +82 -0
  86. claude_mpm/orchestration/archive/subprocess_orchestrator.py +801 -0
  87. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +278 -0
  88. claude_mpm/orchestration/archive/wrapper_orchestrator.py +187 -0
  89. claude_mpm/scripts/__init__.py +1 -0
  90. claude_mpm/scripts/ticket.py +269 -0
  91. claude_mpm/services/__init__.py +10 -0
  92. claude_mpm/services/agent_deployment.py +955 -0
  93. claude_mpm/services/agent_lifecycle_manager.py +948 -0
  94. claude_mpm/services/agent_management_service.py +596 -0
  95. claude_mpm/services/agent_modification_tracker.py +841 -0
  96. claude_mpm/services/agent_profile_loader.py +606 -0
  97. claude_mpm/services/agent_registry.py +677 -0
  98. claude_mpm/services/base_agent_manager.py +380 -0
  99. claude_mpm/services/framework_agent_loader.py +337 -0
  100. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  101. claude_mpm/services/framework_claude_md_generator/__init__.py +206 -0
  102. claude_mpm/services/framework_claude_md_generator/content_assembler.py +151 -0
  103. claude_mpm/services/framework_claude_md_generator/content_validator.py +126 -0
  104. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +137 -0
  105. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +106 -0
  106. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +582 -0
  107. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +97 -0
  108. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +27 -0
  109. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +23 -0
  110. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +23 -0
  111. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +20 -0
  112. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +26 -0
  113. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +30 -0
  114. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +37 -0
  115. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +111 -0
  116. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +89 -0
  117. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +39 -0
  118. claude_mpm/services/framework_claude_md_generator/section_manager.py +106 -0
  119. claude_mpm/services/framework_claude_md_generator/version_manager.py +121 -0
  120. claude_mpm/services/framework_claude_md_generator.py +621 -0
  121. claude_mpm/services/hook_service.py +388 -0
  122. claude_mpm/services/hook_service_manager.py +223 -0
  123. claude_mpm/services/json_rpc_hook_manager.py +92 -0
  124. claude_mpm/services/parent_directory_manager/README.md +83 -0
  125. claude_mpm/services/parent_directory_manager/__init__.py +577 -0
  126. claude_mpm/services/parent_directory_manager/backup_manager.py +258 -0
  127. claude_mpm/services/parent_directory_manager/config_manager.py +210 -0
  128. claude_mpm/services/parent_directory_manager/deduplication_manager.py +279 -0
  129. claude_mpm/services/parent_directory_manager/framework_protector.py +143 -0
  130. claude_mpm/services/parent_directory_manager/operations.py +186 -0
  131. claude_mpm/services/parent_directory_manager/state_manager.py +624 -0
  132. claude_mpm/services/parent_directory_manager/template_deployer.py +579 -0
  133. claude_mpm/services/parent_directory_manager/validation_manager.py +378 -0
  134. claude_mpm/services/parent_directory_manager/version_control_helper.py +339 -0
  135. claude_mpm/services/parent_directory_manager/version_manager.py +222 -0
  136. claude_mpm/services/shared_prompt_cache.py +819 -0
  137. claude_mpm/services/ticket_manager.py +213 -0
  138. claude_mpm/services/ticket_manager_di.py +318 -0
  139. claude_mpm/services/ticketing_service_original.py +508 -0
  140. claude_mpm/services/version_control/VERSION +1 -0
  141. claude_mpm/services/version_control/__init__.py +70 -0
  142. claude_mpm/services/version_control/branch_strategy.py +670 -0
  143. claude_mpm/services/version_control/conflict_resolution.py +744 -0
  144. claude_mpm/services/version_control/git_operations.py +784 -0
  145. claude_mpm/services/version_control/semantic_versioning.py +703 -0
  146. claude_mpm/ui/__init__.py +1 -0
  147. claude_mpm/ui/rich_terminal_ui.py +295 -0
  148. claude_mpm/ui/terminal_ui.py +328 -0
  149. claude_mpm/utils/__init__.py +16 -0
  150. claude_mpm/utils/config_manager.py +468 -0
  151. claude_mpm/utils/import_migration_example.py +80 -0
  152. claude_mpm/utils/imports.py +182 -0
  153. claude_mpm/utils/path_operations.py +357 -0
  154. claude_mpm/utils/paths.py +289 -0
  155. claude_mpm-0.3.0.dist-info/METADATA +290 -0
  156. claude_mpm-0.3.0.dist-info/RECORD +159 -0
  157. claude_mpm-0.3.0.dist-info/WHEEL +5 -0
  158. claude_mpm-0.3.0.dist-info/entry_points.txt +4 -0
  159. claude_mpm-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,627 @@
1
+ """
2
+ Consolidated Agent Registry for Claude MPM.
3
+
4
+ This module combines functionality from:
5
+ - agent_registry.py (current working implementation)
6
+ - agent_registry_original.py (legacy convenience functions)
7
+
8
+ Provides:
9
+ - Agent discovery from the framework
10
+ - Agent listing and selection
11
+ - Compatibility with both sync and async interfaces
12
+ - Legacy function names for backwards compatibility
13
+ """
14
+
15
+ import os
16
+ import sys
17
+ from pathlib import Path
18
+ from typing import Optional, Dict, Any, List, Set
19
+ import importlib.util
20
+ from datetime import datetime
21
+ from dataclasses import dataclass
22
+
23
+ try:
24
+ from ..core.logger import get_logger
25
+ except ImportError:
26
+ from core.logger import get_logger
27
+
28
+
29
+ @dataclass
30
+ class AgentMetadata:
31
+ """Metadata for an agent."""
32
+ name: str
33
+ type: str
34
+ path: str
35
+ tier: str = "system"
36
+ last_modified: float = 0.0
37
+ specializations: List[str] = None
38
+ description: str = ""
39
+
40
+ def __post_init__(self):
41
+ if self.specializations is None:
42
+ self.specializations = []
43
+
44
+
45
+ class SimpleAgentRegistry:
46
+ """Simple agent registry implementation."""
47
+
48
+ def __init__(self, framework_path: Path):
49
+ self.framework_path = framework_path
50
+ self.agents = {}
51
+ self._discover_agents()
52
+
53
+ def _discover_agents(self):
54
+ """Discover agents from the framework."""
55
+ # Check multiple possible locations
56
+ agent_locations = [
57
+ self.framework_path / "src" / "claude_mpm" / "agents" / "templates",
58
+ self.framework_path / "src" / "claude_mpm" / "agents",
59
+ self.framework_path / "agents",
60
+ ]
61
+
62
+ for agents_dir in agent_locations:
63
+ if agents_dir.exists():
64
+ # Look for both .md and .json files
65
+ for pattern in ["*.md", "*.json"]:
66
+ for agent_file in agents_dir.glob(pattern):
67
+ agent_id = agent_file.stem
68
+ self.agents[agent_id] = {
69
+ 'name': agent_id,
70
+ 'type': agent_id,
71
+ 'path': str(agent_file),
72
+ 'last_modified': agent_file.stat().st_mtime,
73
+ 'tier': self._determine_tier(agent_file),
74
+ 'specializations': self._extract_specializations(agent_id),
75
+ 'description': self._extract_description(agent_id)
76
+ }
77
+
78
+ def _determine_tier(self, agent_path: Path) -> str:
79
+ """Determine agent tier based on path."""
80
+ path_str = str(agent_path)
81
+ if 'project' in path_str or '.claude-mpm' in path_str:
82
+ return 'project'
83
+ elif 'user' in path_str or str(Path.home()) in path_str:
84
+ return 'user'
85
+ else:
86
+ return 'system'
87
+
88
+ def _extract_specializations(self, agent_id: str) -> List[str]:
89
+ """Extract specializations based on agent type."""
90
+ specialization_map = {
91
+ 'engineer': ['coding', 'architecture', 'implementation'],
92
+ 'documentation': ['docs', 'api', 'guides'],
93
+ 'qa': ['testing', 'quality', 'validation'],
94
+ 'research': ['analysis', 'investigation', 'exploration'],
95
+ 'ops': ['deployment', 'monitoring', 'infrastructure'],
96
+ 'security': ['security', 'audit', 'compliance'],
97
+ 'version_control': ['git', 'versioning', 'releases'],
98
+ 'data_engineer': ['data', 'etl', 'analytics']
99
+ }
100
+ return specialization_map.get(agent_id, [])
101
+
102
+ def _extract_description(self, agent_id: str) -> str:
103
+ """Extract description for agent."""
104
+ descriptions = {
105
+ 'engineer': 'Software engineering and implementation',
106
+ 'documentation': 'Documentation creation and maintenance',
107
+ 'qa': 'Quality assurance and testing',
108
+ 'research': 'Research and investigation',
109
+ 'ops': 'Operations and deployment',
110
+ 'security': 'Security analysis and compliance',
111
+ 'version_control': 'Version control and release management',
112
+ 'data_engineer': 'Data engineering and analytics'
113
+ }
114
+ return descriptions.get(agent_id, f'{agent_id.title()} agent')
115
+
116
+ def listAgents(self, **kwargs) -> Dict[str, Any]:
117
+ """List all agents (camelCase for compatibility)."""
118
+ return self.agents
119
+
120
+ def list_agents(self, agent_type: Optional[str] = None, tier: Optional[str] = None) -> List[AgentMetadata]:
121
+ """List agents with optional filtering."""
122
+ results = []
123
+ for agent_id, metadata in self.agents.items():
124
+ if agent_type and metadata.get('type') != agent_type:
125
+ continue
126
+ if tier and metadata.get('tier') != tier:
127
+ continue
128
+
129
+ results.append(AgentMetadata(
130
+ name=metadata['name'],
131
+ type=metadata['type'],
132
+ path=metadata['path'],
133
+ tier=metadata.get('tier', 'system'),
134
+ last_modified=metadata.get('last_modified', 0),
135
+ specializations=metadata.get('specializations', []),
136
+ description=metadata.get('description', '')
137
+ ))
138
+ return results
139
+
140
+ def get_agent(self, agent_name: str) -> Optional[AgentMetadata]:
141
+ """Get a specific agent."""
142
+ metadata = self.agents.get(agent_name)
143
+ if metadata:
144
+ return AgentMetadata(
145
+ name=metadata['name'],
146
+ type=metadata['type'],
147
+ path=metadata['path'],
148
+ tier=metadata.get('tier', 'system'),
149
+ last_modified=metadata.get('last_modified', 0),
150
+ specializations=metadata.get('specializations', []),
151
+ description=metadata.get('description', '')
152
+ )
153
+ return None
154
+
155
+ def discover_agents(self, force_refresh: bool = False) -> Dict[str, AgentMetadata]:
156
+ """Discover agents (optionally refresh)."""
157
+ if force_refresh:
158
+ self.agents.clear()
159
+ self._discover_agents()
160
+
161
+ return {
162
+ agent_id: AgentMetadata(
163
+ name=metadata['name'],
164
+ type=metadata['type'],
165
+ path=metadata['path'],
166
+ tier=metadata.get('tier', 'system'),
167
+ last_modified=metadata.get('last_modified', 0),
168
+ specializations=metadata.get('specializations', []),
169
+ description=metadata.get('description', '')
170
+ )
171
+ for agent_id, metadata in self.agents.items()
172
+ }
173
+
174
+ @property
175
+ def core_agent_types(self) -> Set[str]:
176
+ """Get core agent types."""
177
+ return {
178
+ 'documentation',
179
+ 'engineer',
180
+ 'qa',
181
+ 'research',
182
+ 'ops',
183
+ 'security',
184
+ 'version_control',
185
+ 'data_engineer'
186
+ }
187
+
188
+ @property
189
+ def specialized_agent_types(self) -> Set[str]:
190
+ """Get specialized agent types beyond core."""
191
+ all_types = set(metadata['type'] for metadata in self.agents.values())
192
+ return all_types - self.core_agent_types
193
+
194
+
195
+ class AgentRegistryAdapter:
196
+ """
197
+ Adapter to integrate agent registry functionality.
198
+
199
+ This adapter:
200
+ 1. Locates the claude-mpm installation
201
+ 2. Provides a clean interface for agent operations
202
+ 3. Maintains backwards compatibility
203
+ """
204
+
205
+ def __init__(self, framework_path: Optional[Path] = None):
206
+ """
207
+ Initialize the agent registry adapter.
208
+
209
+ Args:
210
+ framework_path: Path to claude-mpm (auto-detected if None)
211
+ """
212
+ self.logger = get_logger("agent_registry")
213
+ self.framework_path = framework_path or self._find_framework()
214
+ self.registry = None
215
+ self._initialize_registry()
216
+
217
+ def _find_framework(self) -> Optional[Path]:
218
+ """Find claude-mpm installation.
219
+
220
+ Search order:
221
+ 1. CLAUDE_MPM_PATH environment variable
222
+ 2. Current working directory (if it's claude-mpm)
223
+ 3. Walk up from current file location
224
+ 4. Common development locations
225
+ """
226
+ # Check environment variable first
227
+ env_path = os.environ.get("CLAUDE_MPM_PATH")
228
+ if env_path:
229
+ candidate = Path(env_path)
230
+ if self._is_valid_framework_path(candidate):
231
+ self.logger.info(f"Using claude-mpm from CLAUDE_MPM_PATH: {candidate}")
232
+ return candidate
233
+ else:
234
+ self.logger.warning(f"CLAUDE_MPM_PATH is set but invalid: {env_path}")
235
+
236
+ # Check current working directory
237
+ cwd = Path.cwd()
238
+ if self._is_valid_framework_path(cwd):
239
+ return cwd
240
+
241
+ # Check if we're running from within the installed package
242
+ current_file = Path(__file__).resolve()
243
+ for parent in current_file.parents:
244
+ if self._is_valid_framework_path(parent):
245
+ return parent
246
+ # Stop at site-packages or similar
247
+ if parent.name in ("site-packages", "dist-packages", "lib"):
248
+ break
249
+
250
+ # Check common development locations
251
+ candidates = [
252
+ Path.home() / "Projects" / "claude-mpm",
253
+ Path.home() / "claude-mpm",
254
+ ]
255
+
256
+ for candidate in candidates:
257
+ if self._is_valid_framework_path(candidate):
258
+ self.logger.info(f"Found claude-mpm at: {candidate}")
259
+ return candidate
260
+
261
+ return None
262
+
263
+ def _is_valid_framework_path(self, path: Path) -> bool:
264
+ """Check if a path is a valid claude-mpm installation."""
265
+ return (
266
+ path.exists() and
267
+ (path / "src" / "claude_mpm").exists()
268
+ )
269
+
270
+ def _initialize_registry(self):
271
+ """Initialize the agent registry."""
272
+ if not self.framework_path:
273
+ self.logger.warning("No framework path, registry unavailable")
274
+ return
275
+
276
+ try:
277
+ self.registry = SimpleAgentRegistry(self.framework_path)
278
+ self.logger.info("Agent registry initialized successfully")
279
+
280
+ except Exception as e:
281
+ self.logger.error(f"Failed to initialize registry: {e}")
282
+
283
+ def list_agents(self, **kwargs) -> Dict[str, Any]:
284
+ """
285
+ List available agents.
286
+
287
+ Args:
288
+ **kwargs: Arguments to pass to registry
289
+
290
+ Returns:
291
+ Dictionary of agents with metadata
292
+ """
293
+ if not self.registry:
294
+ return {}
295
+
296
+ try:
297
+ return self.registry.listAgents(**kwargs)
298
+ except Exception as e:
299
+ self.logger.error(f"Error listing agents: {e}")
300
+ return {}
301
+
302
+ def get_agent_definition(self, agent_name: str) -> Optional[str]:
303
+ """
304
+ Get agent definition by name.
305
+
306
+ Args:
307
+ agent_name: Name of the agent
308
+
309
+ Returns:
310
+ Agent definition content or None
311
+ """
312
+ if not self.registry:
313
+ return None
314
+
315
+ try:
316
+ # Try to load agent definition
317
+ agents = self.registry.listAgents()
318
+ for agent_id, metadata in agents.items():
319
+ if agent_name in agent_id or agent_name == metadata.get('type'):
320
+ # Load the agent file
321
+ agent_path = Path(metadata['path'])
322
+ if agent_path.exists():
323
+ return agent_path.read_text()
324
+
325
+ return None
326
+
327
+ except Exception as e:
328
+ self.logger.error(f"Error getting agent definition: {e}")
329
+ return None
330
+
331
+ def select_agent_for_task(self, task_description: str, required_specializations: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
332
+ """
333
+ Select optimal agent for a task.
334
+
335
+ Args:
336
+ task_description: Description of the task
337
+ required_specializations: Required agent specializations
338
+
339
+ Returns:
340
+ Agent metadata or None
341
+ """
342
+ if not self.registry:
343
+ return None
344
+
345
+ try:
346
+ # Get agents with required specializations
347
+ agents = self.registry.listAgents()
348
+
349
+ if required_specializations:
350
+ # Filter by specializations
351
+ filtered = {}
352
+ for agent_id, metadata in agents.items():
353
+ agent_specs = set(metadata.get('specializations', []))
354
+ if any(spec in agent_specs for spec in required_specializations):
355
+ filtered[agent_id] = metadata
356
+ agents = filtered
357
+
358
+ if not agents:
359
+ return None
360
+
361
+ # For now, return the first matching agent
362
+ # In future, could implement more sophisticated selection
363
+ agent_id = next(iter(agents))
364
+ return {
365
+ 'id': agent_id,
366
+ 'metadata': agents[agent_id]
367
+ }
368
+
369
+ except Exception as e:
370
+ self.logger.error(f"Error selecting agent: {e}")
371
+ return None
372
+
373
+ def get_agent_hierarchy(self) -> Dict[str, List[str]]:
374
+ """
375
+ Get agent hierarchy (project → user → system).
376
+
377
+ Returns:
378
+ Dictionary with hierarchy levels and agent names
379
+ """
380
+ if not self.registry:
381
+ return {
382
+ 'project': [],
383
+ 'user': [],
384
+ 'system': []
385
+ }
386
+
387
+ try:
388
+ # Get all agents
389
+ all_agents = self.registry.listAgents()
390
+
391
+ hierarchy = {
392
+ 'project': [],
393
+ 'user': [],
394
+ 'system': []
395
+ }
396
+
397
+ # Categorize by tier
398
+ for agent_id, metadata in all_agents.items():
399
+ tier = metadata.get('tier', 'system')
400
+ hierarchy[tier].append(agent_id)
401
+
402
+ return hierarchy
403
+
404
+ except Exception as e:
405
+ self.logger.error(f"Error getting hierarchy: {e}")
406
+ return {'project': [], 'user': [], 'system': []}
407
+
408
+ def get_core_agents(self) -> List[str]:
409
+ """
410
+ Get list of core system agents.
411
+
412
+ Returns:
413
+ List of core agent names
414
+ """
415
+ return [
416
+ 'documentation',
417
+ 'engineer',
418
+ 'qa',
419
+ 'research',
420
+ 'ops',
421
+ 'security',
422
+ 'version_control',
423
+ 'data_engineer'
424
+ ]
425
+
426
+ def format_agent_for_task_tool(self, agent_name: str, task: str, context: str = "") -> str:
427
+ """
428
+ Format agent delegation for Task Tool.
429
+
430
+ Args:
431
+ agent_name: Name of the agent
432
+ task: Task description
433
+ context: Additional context
434
+
435
+ Returns:
436
+ Formatted Task Tool prompt
437
+ """
438
+ # Map agent names to nicknames
439
+ nicknames = {
440
+ 'documentation': 'Documenter',
441
+ 'engineer': 'Engineer',
442
+ 'qa': 'QA',
443
+ 'research': 'Researcher',
444
+ 'ops': 'Ops',
445
+ 'security': 'Security',
446
+ 'version_control': 'Versioner',
447
+ 'data_engineer': 'Data Engineer'
448
+ }
449
+
450
+ nickname = nicknames.get(agent_name, agent_name.title())
451
+
452
+ today = datetime.now().strftime("%Y-%m-%d")
453
+
454
+ return f"""**{nickname}**: {task}
455
+
456
+ TEMPORAL CONTEXT: Today is {today}. Apply date awareness to task execution.
457
+
458
+ **Task**: {task}
459
+
460
+ **Context**: {context}
461
+
462
+ **Authority**: Agent has full authority for {agent_name} operations
463
+ **Expected Results**: Completed task with operational insights"""
464
+
465
+
466
+ # Export main class as AgentRegistry for compatibility
467
+ AgentRegistry = SimpleAgentRegistry
468
+
469
+ # Convenience functions for backwards compatibility
470
+ def create_agent_registry(cache_service: Any = None, framework_path: Optional[Path] = None) -> AgentRegistry:
471
+ """
472
+ Create a new AgentRegistry instance
473
+
474
+ Args:
475
+ cache_service: Ignored for compatibility
476
+ framework_path: Path to framework (auto-detected if None)
477
+
478
+ Returns:
479
+ AgentRegistry instance
480
+ """
481
+ if not framework_path:
482
+ adapter = AgentRegistryAdapter()
483
+ framework_path = adapter.framework_path
484
+
485
+ if framework_path:
486
+ return AgentRegistry(framework_path)
487
+ else:
488
+ raise ValueError("Could not find claude-mpm framework path")
489
+
490
+ def discover_agents(force_refresh: bool = False) -> Dict[str, AgentMetadata]:
491
+ """
492
+ Convenience function for synchronous agent discovery
493
+
494
+ Args:
495
+ force_refresh: Force cache refresh
496
+
497
+ Returns:
498
+ Dictionary of discovered agents
499
+ """
500
+ adapter = AgentRegistryAdapter()
501
+ if adapter.registry:
502
+ return adapter.registry.discover_agents(force_refresh=force_refresh)
503
+ return {}
504
+
505
+ def get_core_agent_types() -> Set[str]:
506
+ """
507
+ Get the set of core agent types
508
+
509
+ Returns:
510
+ Set of core agent type names
511
+ """
512
+ adapter = AgentRegistryAdapter()
513
+ if adapter.registry:
514
+ return adapter.registry.core_agent_types
515
+ return set()
516
+
517
+ def get_specialized_agent_types() -> Set[str]:
518
+ """
519
+ Get the set of specialized agent types beyond core 9
520
+
521
+ Returns:
522
+ Set of specialized agent type names
523
+ """
524
+ adapter = AgentRegistryAdapter()
525
+ if adapter.registry:
526
+ return adapter.registry.specialized_agent_types
527
+ return set()
528
+
529
+ def listAgents() -> Dict[str, Dict[str, Any]]:
530
+ """
531
+ Synchronous function for listing all agents (camelCase compatibility)
532
+
533
+ Returns:
534
+ Dictionary of agent name -> agent metadata
535
+ """
536
+ adapter = AgentRegistryAdapter()
537
+ if adapter.registry:
538
+ return adapter.registry.listAgents()
539
+ return {}
540
+
541
+ def list_agents(agent_type: Optional[str] = None, tier: Optional[str] = None) -> List[AgentMetadata]:
542
+ """
543
+ Synchronous function to list agents with optional filtering
544
+
545
+ Args:
546
+ agent_type: Filter by agent type
547
+ tier: Filter by hierarchy tier
548
+
549
+ Returns:
550
+ List of agent metadata dictionaries
551
+ """
552
+ adapter = AgentRegistryAdapter()
553
+ if adapter.registry:
554
+ return adapter.registry.list_agents(agent_type=agent_type, tier=tier)
555
+ return []
556
+
557
+ def discover_agents_sync(force_refresh: bool = False) -> Dict[str, AgentMetadata]:
558
+ """
559
+ Synchronous function for agent discovery
560
+
561
+ Args:
562
+ force_refresh: Force cache refresh
563
+
564
+ Returns:
565
+ Dictionary of discovered agents
566
+ """
567
+ return discover_agents(force_refresh)
568
+
569
+ def get_agent(agent_name: str) -> Optional[Dict[str, Any]]:
570
+ """
571
+ Synchronous function to get a specific agent
572
+
573
+ Args:
574
+ agent_name: Name of agent to retrieve
575
+
576
+ Returns:
577
+ Agent metadata or None
578
+ """
579
+ adapter = AgentRegistryAdapter()
580
+ if adapter.registry:
581
+ agent = adapter.registry.get_agent(agent_name)
582
+ if agent:
583
+ return {
584
+ 'name': agent.name,
585
+ 'type': agent.type,
586
+ 'path': agent.path,
587
+ 'tier': agent.tier,
588
+ 'last_modified': agent.last_modified,
589
+ 'specializations': agent.specializations,
590
+ 'description': agent.description
591
+ }
592
+ return None
593
+
594
+ def get_registry_stats() -> Dict[str, Any]:
595
+ """
596
+ Synchronous function to get registry statistics
597
+
598
+ Returns:
599
+ Dictionary of registry statistics
600
+ """
601
+ adapter = AgentRegistryAdapter()
602
+ if adapter.registry:
603
+ agents = adapter.registry.list_agents()
604
+ return {
605
+ 'total_agents': len(agents),
606
+ 'agent_types': len(set(a.type for a in agents)),
607
+ 'tiers': list(set(a.tier for a in agents))
608
+ }
609
+ return {'total_agents': 0, 'agent_types': 0, 'tiers': []}
610
+
611
+
612
+ # Export all public symbols
613
+ __all__ = [
614
+ 'AgentRegistry',
615
+ 'AgentRegistryAdapter',
616
+ 'AgentMetadata',
617
+ 'SimpleAgentRegistry',
618
+ 'create_agent_registry',
619
+ 'discover_agents',
620
+ 'get_core_agent_types',
621
+ 'get_specialized_agent_types',
622
+ 'listAgents',
623
+ 'list_agents',
624
+ 'discover_agents_sync',
625
+ 'get_agent',
626
+ 'get_registry_stats'
627
+ ]