claude-mpm 3.5.6__py3-none-any.whl → 3.6.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 (46) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +96 -23
  3. claude_mpm/agents/BASE_PM.md +273 -0
  4. claude_mpm/agents/INSTRUCTIONS.md +114 -103
  5. claude_mpm/agents/agent_loader.py +36 -1
  6. claude_mpm/agents/async_agent_loader.py +421 -0
  7. claude_mpm/agents/templates/code_analyzer.json +81 -0
  8. claude_mpm/agents/templates/data_engineer.json +18 -3
  9. claude_mpm/agents/templates/documentation.json +18 -3
  10. claude_mpm/agents/templates/engineer.json +19 -4
  11. claude_mpm/agents/templates/ops.json +18 -3
  12. claude_mpm/agents/templates/qa.json +20 -4
  13. claude_mpm/agents/templates/research.json +20 -4
  14. claude_mpm/agents/templates/security.json +18 -3
  15. claude_mpm/agents/templates/version_control.json +16 -3
  16. claude_mpm/cli/__init__.py +5 -1
  17. claude_mpm/cli/commands/__init__.py +5 -1
  18. claude_mpm/cli/commands/agents.py +212 -3
  19. claude_mpm/cli/commands/aggregate.py +462 -0
  20. claude_mpm/cli/commands/config.py +277 -0
  21. claude_mpm/cli/commands/run.py +224 -36
  22. claude_mpm/cli/parser.py +176 -1
  23. claude_mpm/constants.py +19 -0
  24. claude_mpm/core/claude_runner.py +320 -44
  25. claude_mpm/core/config.py +161 -4
  26. claude_mpm/core/framework_loader.py +81 -0
  27. claude_mpm/hooks/claude_hooks/hook_handler.py +391 -9
  28. claude_mpm/init.py +40 -5
  29. claude_mpm/models/agent_session.py +511 -0
  30. claude_mpm/scripts/__init__.py +15 -0
  31. claude_mpm/scripts/start_activity_logging.py +86 -0
  32. claude_mpm/services/agents/deployment/agent_deployment.py +165 -19
  33. claude_mpm/services/agents/deployment/async_agent_deployment.py +461 -0
  34. claude_mpm/services/event_aggregator.py +547 -0
  35. claude_mpm/utils/agent_dependency_loader.py +655 -0
  36. claude_mpm/utils/console.py +11 -0
  37. claude_mpm/utils/dependency_cache.py +376 -0
  38. claude_mpm/utils/dependency_strategies.py +343 -0
  39. claude_mpm/utils/environment_context.py +310 -0
  40. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/METADATA +47 -3
  41. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/RECORD +45 -31
  42. claude_mpm/agents/templates/pm.json +0 -122
  43. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/WHEEL +0 -0
  44. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/entry_points.txt +0 -0
  45. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/licenses/LICENSE +0 -0
  46. {claude_mpm-3.5.6.dist-info → claude_mpm-3.6.2.dist-info}/top_level.txt +0 -0
@@ -37,6 +37,7 @@ from typing import Optional, List, Dict, Any
37
37
  from claude_mpm.core.logger import get_logger
38
38
  from claude_mpm.constants import EnvironmentVars, Paths, AgentMetadata
39
39
  from claude_mpm.config.paths import paths
40
+ from claude_mpm.core.config import Config
40
41
 
41
42
 
42
43
  class AgentDeploymentService:
@@ -131,7 +132,7 @@ class AgentDeploymentService:
131
132
  self.logger.info(f"Templates directory: {self.templates_dir}")
132
133
  self.logger.info(f"Base agent path: {self.base_agent_path}")
133
134
 
134
- def deploy_agents(self, target_dir: Optional[Path] = None, force_rebuild: bool = False, deployment_mode: str = "update") -> Dict[str, Any]:
135
+ def deploy_agents(self, target_dir: Optional[Path] = None, force_rebuild: bool = False, deployment_mode: str = "update", config: Optional[Config] = None, use_async: bool = True) -> Dict[str, Any]:
135
136
  """
136
137
  Build and deploy agents by combining base_agent.md with templates.
137
138
  Also deploys system instructions for PM framework.
@@ -140,6 +141,12 @@ class AgentDeploymentService:
140
141
  - "update": Normal update mode - skip agents with matching versions (default)
141
142
  - "project": Project deployment mode - always deploy all agents regardless of version
142
143
 
144
+ CONFIGURATION:
145
+ The config parameter or default configuration is used to determine:
146
+ - Which agents to exclude from deployment
147
+ - Case sensitivity for agent name matching
148
+ - Whether to exclude agent dependencies
149
+
143
150
  METRICS COLLECTED:
144
151
  - Deployment start/end timestamps
145
152
  - Individual agent deployment durations
@@ -181,6 +188,8 @@ class AgentDeploymentService:
181
188
  target_dir: Target directory for agents (default: .claude/agents/)
182
189
  force_rebuild: Force rebuild even if agents exist (useful for troubleshooting)
183
190
  deployment_mode: "update" for version-aware updates, "project" for always deploy
191
+ config: Optional configuration object (loads default if not provided)
192
+ use_async: Use async operations for 50-70% faster deployment (default: True)
184
193
 
185
194
  Returns:
186
195
  Dictionary with deployment results:
@@ -196,6 +205,64 @@ class AgentDeploymentService:
196
205
  # METRICS: Record deployment start time for performance tracking
197
206
  deployment_start_time = time.time()
198
207
 
208
+ # Try async deployment for better performance if requested
209
+ if use_async:
210
+ try:
211
+ from .async_agent_deployment import deploy_agents_async_wrapper
212
+ self.logger.info("Using async deployment for improved performance")
213
+
214
+ # Run async deployment
215
+ results = deploy_agents_async_wrapper(
216
+ templates_dir=self.templates_dir,
217
+ base_agent_path=self.base_agent_path,
218
+ working_directory=self.working_directory,
219
+ target_dir=target_dir,
220
+ force_rebuild=force_rebuild,
221
+ config=config
222
+ )
223
+
224
+ # Add metrics about async vs sync
225
+ if 'metrics' in results:
226
+ results['metrics']['deployment_method'] = 'async'
227
+ duration_ms = results['metrics'].get('duration_ms', 0)
228
+ self.logger.info(f"Async deployment completed in {duration_ms:.1f}ms")
229
+
230
+ # Update internal metrics
231
+ self._deployment_metrics['total_deployments'] += 1
232
+ if not results.get('errors'):
233
+ self._deployment_metrics['successful_deployments'] += 1
234
+ else:
235
+ self._deployment_metrics['failed_deployments'] += 1
236
+
237
+ return results
238
+
239
+ except ImportError:
240
+ self.logger.warning("Async deployment not available, falling back to sync")
241
+ except Exception as e:
242
+ self.logger.warning(f"Async deployment failed, falling back to sync: {e}")
243
+
244
+ # Continue with synchronous deployment
245
+ self.logger.info("Using synchronous deployment")
246
+
247
+ # Load configuration if not provided
248
+ if config is None:
249
+ config = Config()
250
+
251
+ # Get agent exclusion configuration
252
+ excluded_agents = config.get('agent_deployment.excluded_agents', [])
253
+ case_sensitive = config.get('agent_deployment.case_sensitive', False)
254
+ exclude_dependencies = config.get('agent_deployment.exclude_dependencies', False)
255
+
256
+ # Normalize excluded agents list for comparison
257
+ if not case_sensitive:
258
+ excluded_agents = [agent.lower() for agent in excluded_agents]
259
+
260
+ # Log exclusion configuration if agents are being excluded
261
+ if excluded_agents:
262
+ self.logger.info(f"Excluding agents from deployment: {excluded_agents}")
263
+ self.logger.debug(f"Case sensitive matching: {case_sensitive}")
264
+ self.logger.debug(f"Exclude dependencies: {exclude_dependencies}")
265
+
199
266
  if not target_dir:
200
267
  # Default to working directory's .claude/agents directory (not home)
201
268
  # This ensures we deploy to the user's project directory, not the framework directory
@@ -294,17 +361,54 @@ class AgentDeploymentService:
294
361
 
295
362
  # Get all template files
296
363
  template_files = list(self.templates_dir.glob("*.json"))
297
- # Filter out non-agent files - exclude system files and uppercase special files
298
- # CRITICAL: PM (Project Manager) must NEVER be deployed as it's the main Claude instance
299
- excluded_names = {"__init__", "MEMORIES", "TODOWRITE", "INSTRUCTIONS", "README", "pm", "PM", "project_manager"}
300
- template_files = [
301
- f for f in template_files
302
- if f.stem not in excluded_names
303
- and not f.stem.startswith(".")
304
- and not f.stem.endswith(".backup")
305
- ]
364
+
365
+ # Build the combined exclusion set
366
+ # Start with hardcoded exclusions (these are ALWAYS excluded)
367
+ hardcoded_exclusions = {"__init__", "MEMORIES", "TODOWRITE", "INSTRUCTIONS", "README", "pm", "PM", "project_manager"}
368
+
369
+ # Add user-configured exclusions
370
+ user_exclusions = set()
371
+ for agent in excluded_agents:
372
+ if case_sensitive:
373
+ user_exclusions.add(agent)
374
+ else:
375
+ # For case-insensitive, we'll check during filtering
376
+ user_exclusions.add(agent.lower())
377
+
378
+ # Filter out excluded agents
379
+ filtered_files = []
380
+ excluded_count = 0
381
+ for f in template_files:
382
+ agent_name = f.stem
383
+
384
+ # Check hardcoded exclusions (always case-sensitive)
385
+ if agent_name in hardcoded_exclusions:
386
+ self.logger.debug(f"Excluding {agent_name}: hardcoded system exclusion")
387
+ excluded_count += 1
388
+ continue
389
+
390
+ # Check file patterns
391
+ if agent_name.startswith(".") or agent_name.endswith(".backup"):
392
+ self.logger.debug(f"Excluding {agent_name}: file pattern exclusion")
393
+ excluded_count += 1
394
+ continue
395
+
396
+ # Check user-configured exclusions
397
+ compare_name = agent_name.lower() if not case_sensitive else agent_name
398
+ if compare_name in user_exclusions:
399
+ self.logger.info(f"Excluding {agent_name}: user-configured exclusion")
400
+ excluded_count += 1
401
+ continue
402
+
403
+ # Agent is not excluded, add to filtered list
404
+ filtered_files.append(f)
405
+
406
+ template_files = filtered_files
306
407
  results["total"] = len(template_files)
307
408
 
409
+ if excluded_count > 0:
410
+ self.logger.info(f"Excluded {excluded_count} agents from deployment")
411
+
308
412
  for template_file in template_files:
309
413
  try:
310
414
  # METRICS: Track individual agent deployment time
@@ -983,6 +1087,17 @@ temperature: {temperature}"""
983
1087
 
984
1088
  # List deployed agents
985
1089
  agent_files = list(agents_dir.glob("*.md"))
1090
+
1091
+ # Get exclusion configuration for logging purposes
1092
+ try:
1093
+ from claude_mpm.core.config import Config
1094
+ config = Config()
1095
+ excluded_agents = config.get('agent_deployment.excluded_agents', [])
1096
+ if excluded_agents:
1097
+ self.logger.debug(f"Note: The following agents are configured for exclusion: {excluded_agents}")
1098
+ except Exception:
1099
+ pass # Ignore config loading errors in verification
1100
+
986
1101
  for agent_file in agent_files:
987
1102
  try:
988
1103
  # Read first few lines to get agent name from YAML
@@ -1123,15 +1238,46 @@ temperature: {temperature}"""
1123
1238
  return agents
1124
1239
 
1125
1240
  template_files = sorted(self.templates_dir.glob("*.json"))
1126
- # Filter out non-agent files - exclude system files and uppercase special files
1127
- # CRITICAL: PM (Project Manager) must NEVER be deployed as it's the main Claude instance
1128
- excluded_names = {"__init__", "MEMORIES", "TODOWRITE", "INSTRUCTIONS", "README", "pm", "PM", "project_manager"}
1129
- template_files = [
1130
- f for f in template_files
1131
- if f.stem not in excluded_names
1132
- and not f.stem.startswith(".")
1133
- and not f.stem.endswith(".backup")
1134
- ]
1241
+
1242
+ # Load configuration for exclusions
1243
+ try:
1244
+ from claude_mpm.core.config import Config
1245
+ config = Config()
1246
+ excluded_agents = config.get('agent_deployment.excluded_agents', [])
1247
+ case_sensitive = config.get('agent_deployment.case_sensitive', False)
1248
+
1249
+ # Normalize excluded agents for comparison
1250
+ if not case_sensitive:
1251
+ excluded_agents = [agent.lower() for agent in excluded_agents]
1252
+ except Exception:
1253
+ # If config loading fails, use empty exclusion list
1254
+ excluded_agents = []
1255
+ case_sensitive = False
1256
+
1257
+ # Build combined exclusion set
1258
+ hardcoded_exclusions = {"__init__", "MEMORIES", "TODOWRITE", "INSTRUCTIONS", "README", "pm", "PM", "project_manager"}
1259
+
1260
+ # Filter out excluded agents
1261
+ filtered_files = []
1262
+ for f in template_files:
1263
+ agent_name = f.stem
1264
+
1265
+ # Check hardcoded exclusions
1266
+ if agent_name in hardcoded_exclusions:
1267
+ continue
1268
+
1269
+ # Check file patterns
1270
+ if agent_name.startswith(".") or agent_name.endswith(".backup"):
1271
+ continue
1272
+
1273
+ # Check user-configured exclusions
1274
+ compare_name = agent_name.lower() if not case_sensitive else agent_name
1275
+ if compare_name in excluded_agents:
1276
+ continue
1277
+
1278
+ filtered_files.append(f)
1279
+
1280
+ template_files = filtered_files
1135
1281
 
1136
1282
  for template_file in template_files:
1137
1283
  try: