claude-mpm 2.1.0__py3-none-any.whl → 3.0.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.
Files changed (31) hide show
  1. claude_mpm/_version.py +2 -2
  2. claude_mpm/agents/agent_loader.py +682 -102
  3. claude_mpm/agents/base_agent_loader.py +23 -8
  4. claude_mpm/agents/schema/agent_schema.json +237 -83
  5. claude_mpm/agents/templates/data_engineer.json +6 -3
  6. claude_mpm/agents/templates/documentation.json +6 -3
  7. claude_mpm/agents/templates/engineer.json +7 -4
  8. claude_mpm/agents/templates/ops.json +6 -3
  9. claude_mpm/agents/templates/qa.json +10 -5
  10. claude_mpm/agents/templates/research.json +31 -42
  11. claude_mpm/agents/templates/security.json +14 -6
  12. claude_mpm/agents/templates/version_control.json +9 -5
  13. claude_mpm/core/base_service.py +61 -1
  14. claude_mpm/hooks/claude_hooks/hook_handler.py +224 -20
  15. claude_mpm/schemas/README_SECURITY.md +92 -0
  16. claude_mpm/schemas/agent_schema.json +130 -51
  17. claude_mpm/schemas/agent_schema_security_notes.md +165 -0
  18. claude_mpm/services/agent_capabilities_generator.py +0 -1
  19. claude_mpm/services/agent_deployment.py +479 -91
  20. claude_mpm/services/agent_lifecycle_manager.py +62 -4
  21. claude_mpm/services/deployed_agent_discovery.py +6 -2
  22. claude_mpm/services/version_control/semantic_versioning.py +165 -16
  23. claude_mpm/validation/agent_validator.py +147 -13
  24. {claude_mpm-2.1.0.dist-info → claude_mpm-3.0.0.dist-info}/METADATA +4 -2
  25. {claude_mpm-2.1.0.dist-info → claude_mpm-3.0.0.dist-info}/RECORD +29 -28
  26. claude_mpm-3.0.0.dist-info/licenses/LICENSE +21 -0
  27. claude_mpm/cli_old/__init__.py +0 -1
  28. claude_mpm/cli_old/ticket_cli.py +0 -102
  29. {claude_mpm-2.1.0.dist-info → claude_mpm-3.0.0.dist-info}/WHEEL +0 -0
  30. {claude_mpm-2.1.0.dist-info → claude_mpm-3.0.0.dist-info}/entry_points.txt +0 -0
  31. {claude_mpm-2.1.0.dist-info → claude_mpm-3.0.0.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,36 @@
1
- """Agent deployment service for Claude Code native subagents."""
1
+ """Agent deployment service for Claude Code native subagents.
2
+
3
+ This service handles the complete lifecycle of agent deployment:
4
+ 1. Building agent YAML files from JSON templates
5
+ 2. Managing versioning and updates
6
+ 3. Deploying to Claude Code's .claude/agents directory
7
+ 4. Environment configuration for agent discovery
8
+ 5. Deployment verification and cleanup
9
+
10
+ OPERATIONAL CONSIDERATIONS:
11
+ - Deployment is idempotent - safe to run multiple times
12
+ - Version checking prevents unnecessary rebuilds (saves I/O)
13
+ - Supports force rebuild for troubleshooting
14
+ - Maintains backward compatibility with legacy versions
15
+ - Handles migration from old serial versioning to semantic versioning
16
+
17
+ MONITORING:
18
+ - Check logs for deployment status and errors
19
+ - Monitor disk space in .claude/agents directory
20
+ - Track version migration progress
21
+ - Verify agent discovery after deployment
22
+
23
+ ROLLBACK PROCEDURES:
24
+ - Keep backups of .claude/agents before major updates
25
+ - Use clean_deployment() to remove system agents
26
+ - User-created agents are preserved during cleanup
27
+ - Version tracking allows targeted rollbacks
28
+ """
2
29
 
3
30
  import os
4
31
  import shutil
5
32
  import logging
33
+ import time
6
34
  from pathlib import Path
7
35
  from typing import Optional, List, Dict, Any
8
36
 
@@ -11,7 +39,35 @@ from claude_mpm.constants import EnvironmentVars, Paths, AgentMetadata
11
39
 
12
40
 
13
41
  class AgentDeploymentService:
14
- """Service for deploying Claude Code native agents."""
42
+ """Service for deploying Claude Code native agents.
43
+
44
+ METRICS COLLECTION OPPORTUNITIES:
45
+ This service could collect valuable deployment metrics including:
46
+ - Agent deployment frequency and success rates
47
+ - Template validation performance
48
+ - Version migration patterns
49
+ - Deployment duration by agent type
50
+ - Cache hit rates for agent templates
51
+ - Resource usage during deployment (memory, CPU)
52
+ - Agent file sizes and complexity metrics
53
+ - Deployment failure reasons and patterns
54
+
55
+ DEPLOYMENT PIPELINE:
56
+ 1. Initialize with template and base agent paths
57
+ 2. Load base agent configuration (shared settings)
58
+ 3. Iterate through agent templates
59
+ 4. Check version and update requirements
60
+ 5. Build YAML files with proper formatting
61
+ 6. Deploy to target directory
62
+ 7. Set environment variables for discovery
63
+ 8. Verify deployment success
64
+
65
+ ENVIRONMENT REQUIREMENTS:
66
+ - Write access to .claude/agents directory
67
+ - Python 3.8+ for pathlib and typing features
68
+ - JSON parsing for template files
69
+ - YAML generation capabilities
70
+ """
15
71
 
16
72
  def __init__(self, templates_dir: Optional[Path] = None, base_agent_path: Optional[Path] = None):
17
73
  """
@@ -20,9 +76,29 @@ class AgentDeploymentService:
20
76
  Args:
21
77
  templates_dir: Directory containing agent template files
22
78
  base_agent_path: Path to base_agent.md file
79
+
80
+ METRICS OPPORTUNITY: Track initialization performance:
81
+ - Template directory scan time
82
+ - Base agent loading time
83
+ - Initial validation overhead
23
84
  """
24
85
  self.logger = get_logger(self.__class__.__name__)
25
86
 
87
+ # METRICS: Initialize deployment metrics tracking
88
+ # This data structure would be used for collecting deployment telemetry
89
+ self._deployment_metrics = {
90
+ 'total_deployments': 0,
91
+ 'successful_deployments': 0,
92
+ 'failed_deployments': 0,
93
+ 'migrations_performed': 0,
94
+ 'average_deployment_time_ms': 0.0,
95
+ 'deployment_times': [], # Keep last 100 for rolling average
96
+ 'agent_type_counts': {}, # Track deployments by agent type
97
+ 'version_migration_count': 0,
98
+ 'template_validation_times': {}, # Track validation performance
99
+ 'deployment_errors': {} # Track error types and frequencies
100
+ }
101
+
26
102
  # Find templates directory
27
103
  module_path = Path(__file__).parent.parent
28
104
  if templates_dir:
@@ -46,13 +122,59 @@ class AgentDeploymentService:
46
122
  Build and deploy agents by combining base_agent.md with templates.
47
123
  Also deploys system instructions for PM framework.
48
124
 
125
+ METRICS COLLECTED:
126
+ - Deployment start/end timestamps
127
+ - Individual agent deployment durations
128
+ - Success/failure rates by agent type
129
+ - Version migration statistics
130
+ - Template validation performance
131
+ - Error type frequencies
132
+
133
+ OPERATIONAL FLOW:
134
+ 1. Validates target directory (creates if needed)
135
+ 2. Loads base agent configuration
136
+ 3. Discovers all agent templates
137
+ 4. For each agent:
138
+ - Checks if update needed (version comparison)
139
+ - Builds YAML configuration
140
+ - Writes to target directory
141
+ - Tracks deployment status
142
+
143
+ PERFORMANCE CONSIDERATIONS:
144
+ - Skips unchanged agents (version-based caching)
145
+ - Batch processes all agents in single pass
146
+ - Minimal file I/O with in-memory building
147
+ - Parallel-safe (no shared state mutations)
148
+
149
+ ERROR HANDLING:
150
+ - Continues deployment on individual agent failures
151
+ - Collects all errors for reporting
152
+ - Logs detailed error context
153
+ - Returns comprehensive results dict
154
+
155
+ MONITORING POINTS:
156
+ - Track total deployment time
157
+ - Monitor skipped vs updated vs new agents
158
+ - Check error rates and patterns
159
+ - Verify migration completion
160
+
49
161
  Args:
50
162
  target_dir: Target directory for agents (default: .claude/agents/)
51
- force_rebuild: Force rebuild even if agents exist
163
+ force_rebuild: Force rebuild even if agents exist (useful for troubleshooting)
52
164
 
53
165
  Returns:
54
- Dictionary with deployment results
166
+ Dictionary with deployment results:
167
+ - target_dir: Deployment location
168
+ - deployed: List of newly deployed agents
169
+ - updated: List of updated agents
170
+ - migrated: List of agents migrated to new version format
171
+ - skipped: List of unchanged agents
172
+ - errors: List of deployment errors
173
+ - total: Total number of agents processed
55
174
  """
175
+ # METRICS: Record deployment start time for performance tracking
176
+ deployment_start_time = time.time()
177
+
56
178
  if not target_dir:
57
179
  target_dir = Path(Paths.CLAUDE_AGENTS_DIR.value).expanduser()
58
180
 
@@ -64,7 +186,16 @@ class AgentDeploymentService:
64
186
  "skipped": [],
65
187
  "updated": [],
66
188
  "migrated": [], # Track agents migrated from old format
67
- "total": 0
189
+ "total": 0,
190
+ # METRICS: Add detailed timing and performance data to results
191
+ "metrics": {
192
+ "start_time": deployment_start_time,
193
+ "end_time": None,
194
+ "duration_ms": None,
195
+ "agent_timings": {}, # Track individual agent deployment times
196
+ "validation_times": {}, # Track template validation times
197
+ "resource_usage": {} # Could track memory/CPU if needed
198
+ }
68
199
  }
69
200
 
70
201
  try:
@@ -82,6 +213,9 @@ class AgentDeploymentService:
82
213
  return results
83
214
 
84
215
  # Load base agent content
216
+ # OPERATIONAL NOTE: Base agent contains shared configuration and instructions
217
+ # that all agents inherit. This reduces duplication and ensures consistency.
218
+ # If base agent fails to load, deployment continues with agent-specific configs only.
85
219
  base_agent_data = {}
86
220
  base_agent_version = 0
87
221
  if self.base_agent_path.exists():
@@ -89,9 +223,11 @@ class AgentDeploymentService:
89
223
  import json
90
224
  base_agent_data = json.loads(self.base_agent_path.read_text())
91
225
  # Handle both 'base_version' (new format) and 'version' (old format)
226
+ # MIGRATION PATH: Supporting both formats during transition period
92
227
  base_agent_version = self._parse_version(base_agent_data.get('base_version') or base_agent_data.get('version', 0))
93
228
  self.logger.info(f"Loaded base agent template (version {self._format_version_display(base_agent_version)})")
94
229
  except Exception as e:
230
+ # NON-FATAL: Base agent is optional enhancement, not required
95
231
  self.logger.warning(f"Could not load base agent: {e}")
96
232
 
97
233
  # Get all template files
@@ -102,8 +238,11 @@ class AgentDeploymentService:
102
238
 
103
239
  for template_file in template_files:
104
240
  try:
241
+ # METRICS: Track individual agent deployment time
242
+ agent_start_time = time.time()
243
+
105
244
  agent_name = template_file.stem
106
- target_file = target_dir / f"{agent_name}.md"
245
+ target_file = target_dir / f"{agent_name}.yaml"
107
246
 
108
247
  # Check if agent needs update
109
248
  needs_update = force_rebuild
@@ -127,32 +266,48 @@ class AgentDeploymentService:
127
266
  continue
128
267
 
129
268
  # Build the agent file
130
- agent_md = self._build_agent_markdown(agent_name, template_file, base_agent_data)
269
+ agent_yaml = self._build_agent_yaml(agent_name, template_file, base_agent_data)
131
270
 
132
271
  # Write the agent file
133
272
  is_update = target_file.exists()
134
- target_file.write_text(agent_md)
273
+ target_file.write_text(agent_yaml)
274
+
275
+ # METRICS: Record deployment time for this agent
276
+ agent_deployment_time = (time.time() - agent_start_time) * 1000 # Convert to ms
277
+ results["metrics"]["agent_timings"][agent_name] = agent_deployment_time
278
+
279
+ # METRICS: Update agent type deployment counts
280
+ self._deployment_metrics['agent_type_counts'][agent_name] = \
281
+ self._deployment_metrics['agent_type_counts'].get(agent_name, 0) + 1
135
282
 
136
283
  if is_migration:
137
284
  results["migrated"].append({
138
285
  "name": agent_name,
139
286
  "template": str(template_file),
140
287
  "target": str(target_file),
141
- "reason": reason
288
+ "reason": reason,
289
+ "deployment_time_ms": agent_deployment_time # METRICS: Include timing
142
290
  })
143
291
  self.logger.info(f"Successfully migrated agent: {agent_name} to semantic versioning")
292
+
293
+ # METRICS: Track migration statistics
294
+ self._deployment_metrics['migrations_performed'] += 1
295
+ self._deployment_metrics['version_migration_count'] += 1
296
+
144
297
  elif is_update:
145
298
  results["updated"].append({
146
299
  "name": agent_name,
147
300
  "template": str(template_file),
148
- "target": str(target_file)
301
+ "target": str(target_file),
302
+ "deployment_time_ms": agent_deployment_time # METRICS: Include timing
149
303
  })
150
304
  self.logger.debug(f"Updated agent: {agent_name}")
151
305
  else:
152
306
  results["deployed"].append({
153
307
  "name": agent_name,
154
308
  "template": str(template_file),
155
- "target": str(target_file)
309
+ "target": str(target_file),
310
+ "deployment_time_ms": agent_deployment_time # METRICS: Include timing
156
311
  })
157
312
  self.logger.debug(f"Built and deployed agent: {agent_name}")
158
313
 
@@ -173,9 +328,122 @@ class AgentDeploymentService:
173
328
  error_msg = f"Agent deployment failed: {e}"
174
329
  self.logger.error(error_msg)
175
330
  results["errors"].append(error_msg)
331
+
332
+ # METRICS: Track deployment failure
333
+ self._deployment_metrics['failed_deployments'] += 1
334
+ error_type = type(e).__name__
335
+ self._deployment_metrics['deployment_errors'][error_type] = \
336
+ self._deployment_metrics['deployment_errors'].get(error_type, 0) + 1
337
+
338
+ # METRICS: Calculate final deployment metrics
339
+ deployment_end_time = time.time()
340
+ deployment_duration = (deployment_end_time - deployment_start_time) * 1000 # ms
341
+
342
+ results["metrics"]["end_time"] = deployment_end_time
343
+ results["metrics"]["duration_ms"] = deployment_duration
344
+
345
+ # METRICS: Update rolling averages and statistics
346
+ self._update_deployment_metrics(deployment_duration, results)
176
347
 
177
348
  return results
178
349
 
350
+ def _update_deployment_metrics(self, duration_ms: float, results: Dict[str, Any]) -> None:
351
+ """
352
+ Update internal deployment metrics.
353
+
354
+ METRICS TRACKING:
355
+ - Rolling average of deployment times (last 100)
356
+ - Success/failure rates
357
+ - Agent type distribution
358
+ - Version migration patterns
359
+ - Error frequency analysis
360
+
361
+ This method demonstrates ETL-like processing:
362
+ 1. Extract: Gather raw metrics from deployment results
363
+ 2. Transform: Calculate averages, rates, and distributions
364
+ 3. Load: Store in internal metrics structure for reporting
365
+ """
366
+ # Update total deployment count
367
+ self._deployment_metrics['total_deployments'] += 1
368
+
369
+ # Track success/failure
370
+ if not results.get('errors'):
371
+ self._deployment_metrics['successful_deployments'] += 1
372
+ else:
373
+ self._deployment_metrics['failed_deployments'] += 1
374
+
375
+ # Update rolling average deployment time
376
+ self._deployment_metrics['deployment_times'].append(duration_ms)
377
+ if len(self._deployment_metrics['deployment_times']) > 100:
378
+ # Keep only last 100 for memory efficiency
379
+ self._deployment_metrics['deployment_times'] = \
380
+ self._deployment_metrics['deployment_times'][-100:]
381
+
382
+ # Calculate new average
383
+ if self._deployment_metrics['deployment_times']:
384
+ self._deployment_metrics['average_deployment_time_ms'] = \
385
+ sum(self._deployment_metrics['deployment_times']) / \
386
+ len(self._deployment_metrics['deployment_times'])
387
+
388
+ def get_deployment_metrics(self) -> Dict[str, Any]:
389
+ """
390
+ Get current deployment metrics.
391
+
392
+ Returns:
393
+ Dictionary containing:
394
+ - Total deployments and success rates
395
+ - Average deployment time
396
+ - Agent type distribution
397
+ - Migration statistics
398
+ - Error analysis
399
+
400
+ This demonstrates a metrics API endpoint that could be:
401
+ - Exposed via REST API for monitoring tools
402
+ - Pushed to time-series databases (Prometheus, InfluxDB)
403
+ - Used for dashboards and alerting
404
+ - Integrated with AI observability platforms
405
+ """
406
+ success_rate = 0.0
407
+ if self._deployment_metrics['total_deployments'] > 0:
408
+ success_rate = (self._deployment_metrics['successful_deployments'] /
409
+ self._deployment_metrics['total_deployments']) * 100
410
+
411
+ return {
412
+ 'total_deployments': self._deployment_metrics['total_deployments'],
413
+ 'successful_deployments': self._deployment_metrics['successful_deployments'],
414
+ 'failed_deployments': self._deployment_metrics['failed_deployments'],
415
+ 'success_rate_percent': success_rate,
416
+ 'average_deployment_time_ms': self._deployment_metrics['average_deployment_time_ms'],
417
+ 'migrations_performed': self._deployment_metrics['migrations_performed'],
418
+ 'agent_type_distribution': self._deployment_metrics['agent_type_counts'].copy(),
419
+ 'version_migrations': self._deployment_metrics['version_migration_count'],
420
+ 'error_distribution': self._deployment_metrics['deployment_errors'].copy(),
421
+ 'recent_deployment_times': self._deployment_metrics['deployment_times'][-10:] # Last 10
422
+ }
423
+
424
+ def reset_metrics(self) -> None:
425
+ """
426
+ Reset deployment metrics.
427
+
428
+ Useful for:
429
+ - Starting fresh metrics collection periods
430
+ - Testing and development
431
+ - Scheduled metric rotation (e.g., daily reset)
432
+ """
433
+ self._deployment_metrics = {
434
+ 'total_deployments': 0,
435
+ 'successful_deployments': 0,
436
+ 'failed_deployments': 0,
437
+ 'migrations_performed': 0,
438
+ 'average_deployment_time_ms': 0.0,
439
+ 'deployment_times': [],
440
+ 'agent_type_counts': {},
441
+ 'version_migration_count': 0,
442
+ 'template_validation_times': {},
443
+ 'deployment_errors': {}
444
+ }
445
+ self.logger.info("Deployment metrics reset")
446
+
179
447
  def _extract_version(self, content: str, version_marker: str) -> int:
180
448
  """
181
449
  Extract version number from content.
@@ -223,18 +491,29 @@ class AgentDeploymentService:
223
491
  version_string = self._format_version_display(agent_version)
224
492
 
225
493
  # Build YAML frontmatter
494
+ # Check new format first (metadata.description), then old format
226
495
  description = (
496
+ template_data.get('metadata', {}).get('description') or
227
497
  template_data.get('configuration_fields', {}).get('description') or
228
498
  template_data.get('description') or
229
499
  'Agent for specialized tasks'
230
500
  )
231
501
 
502
+ # Get tags from new format (metadata.tags) or old format
232
503
  tags = (
504
+ template_data.get('metadata', {}).get('tags') or
233
505
  template_data.get('configuration_fields', {}).get('tags') or
234
506
  template_data.get('tags') or
235
507
  [agent_name, 'mpm-framework']
236
508
  )
237
509
 
510
+ # Get tools from capabilities.tools in new format
511
+ tools = (
512
+ template_data.get('capabilities', {}).get('tools') or
513
+ template_data.get('configuration_fields', {}).get('tools') or
514
+ ["Read", "Write", "Edit", "Grep", "Glob", "LS"] # Default fallback
515
+ )
516
+
238
517
  frontmatter = f"""---
239
518
  name: {agent_name}
240
519
  description: "{description}"
@@ -243,6 +522,7 @@ author: "{template_data.get('author', 'claude-mpm@anthropic.com')}"
243
522
  created: "{datetime.now().isoformat()}Z"
244
523
  updated: "{datetime.now().isoformat()}Z"
245
524
  tags: {tags}
525
+ tools: {tools}
246
526
  metadata:
247
527
  base_version: "{self._format_version_display(base_version)}"
248
528
  agent_version: "{self._format_version_display(agent_version)}"
@@ -265,6 +545,7 @@ metadata:
265
545
  def _build_agent_yaml(self, agent_name: str, template_path: Path, base_agent_data: dict) -> str:
266
546
  """
267
547
  Build a complete agent YAML file by combining base agent and template.
548
+ Only includes essential fields for Claude Code best practices.
268
549
 
269
550
  Args:
270
551
  agent_name: Name of the agent
@@ -275,92 +556,80 @@ metadata:
275
556
  Complete agent YAML content
276
557
  """
277
558
  import json
278
- from datetime import datetime
279
559
 
280
560
  # Read template JSON
281
561
  template_data = json.loads(template_path.read_text())
282
562
 
283
- # Extract versions
284
- # Handle both 'agent_version' (new format) and 'version' (old format)
285
- agent_version = self._parse_version(template_data.get('agent_version') or template_data.get('version', 0))
286
- base_version = self._parse_version(base_agent_data.get('base_version') or base_agent_data.get('version', 0))
563
+ # Extract capabilities
564
+ capabilities = template_data.get('capabilities', {})
565
+ metadata = template_data.get('metadata', {})
287
566
 
288
- # Use semantic version format
567
+ # Extract version information
568
+ agent_version = self._parse_version(template_data.get('agent_version') or template_data.get('version', 0))
289
569
  version_string = self._format_version_display(agent_version)
290
570
 
291
- # Merge narrative fields (base + agent specific)
292
- narrative_fields = self._merge_narrative_fields(base_agent_data, template_data)
571
+ # Get tools list
572
+ tools = capabilities.get('tools', [])
573
+ tools_str = ', '.join(tools) if tools else 'Read, Write, Edit, Grep, Glob, LS'
574
+
575
+ # Get description
576
+ description = (
577
+ metadata.get('description') or
578
+ template_data.get('description') or
579
+ f'{agent_name.title()} agent for specialized tasks'
580
+ )
581
+
582
+ # Get priority based on agent type
583
+ priority_map = {
584
+ 'security': 'high',
585
+ 'qa': 'high',
586
+ 'engineer': 'high',
587
+ 'documentation': 'medium',
588
+ 'research': 'medium',
589
+ 'ops': 'high',
590
+ 'data_engineer': 'medium',
591
+ 'version_control': 'high'
592
+ }
593
+ priority = priority_map.get(agent_name, 'medium')
293
594
 
294
- # Merge configuration fields (agent overrides base)
295
- config_fields = self._merge_configuration_fields(base_agent_data, template_data)
595
+ # Get model
596
+ model = capabilities.get('model', 'claude-3-5-sonnet-20241022')
296
597
 
297
- # Build YAML frontmatter following best practices
598
+ # Get temperature
599
+ temperature = capabilities.get('temperature', 0.3)
600
+
601
+ # Build clean YAML frontmatter with only essential fields
298
602
  yaml_content = f"""---
299
- # Core Identity
300
- name: "{agent_name}"
301
- description: "{config_fields.get('description', '')}"
603
+ name: {agent_name}
604
+ description: "{description}"
302
605
  version: "{version_string}"
303
- author: "claude-mpm@anthropic.com"
304
- created: "{datetime.now().isoformat()}Z"
305
- updated: "{datetime.now().isoformat()}Z"
306
-
307
- # Categorization
308
- tags: {config_fields.get('tags', [])}
309
- team: "{config_fields.get('team', 'mpm-framework')}"
310
- project: "{config_fields.get('project', 'claude-mpm')}"
311
- priority: "{config_fields.get('priority', 'high')}"
312
-
313
- # Behavioral Configuration
314
- tools: {config_fields.get('tools', [])}
315
- timeout: {config_fields.get('timeout', 600)}
316
- max_tokens: {config_fields.get('max_tokens', 8192)}
317
- model: "{config_fields.get('model', 'claude-3-5-sonnet-20241022')}"
318
- temperature: {config_fields.get('temperature', 0.3)}
319
-
320
- # Access Control
321
- file_access: "{config_fields.get('file_access', 'project')}"
322
- network_access: {str(config_fields.get('network_access', True)).lower()}
323
- dangerous_tools: {str(config_fields.get('dangerous_tools', False)).lower()}
324
- review_required: {str(config_fields.get('review_required', False)).lower()}
325
-
326
- # Resource Management
327
- memory_limit: {config_fields.get('memory_limit', 2048)}
328
- cpu_limit: {config_fields.get('cpu_limit', 50)}
329
- execution_timeout: {config_fields.get('timeout', 600)}
330
-
331
- # When/Why/What sections extracted from template
332
- when_to_use:
333
- {self._format_yaml_list(narrative_fields.get('when_to_use', []), 2)}
334
-
335
- rationale:
336
- specialized_knowledge:
337
- {self._format_yaml_list(narrative_fields.get('specialized_knowledge', []), 4)}
338
- unique_capabilities:
339
- {self._format_yaml_list(narrative_fields.get('unique_capabilities', []), 4)}
340
-
341
- capabilities:
342
- primary_role: "{config_fields.get('primary_role', '')}"
343
- specializations: {config_fields.get('specializations', [])}
344
- authority: "{config_fields.get('authority', '')}"
345
-
346
- # Agent Metadata
347
- metadata:
348
- source: "claude-mpm"
349
- template_version: "{self._format_version_display(agent_version)}"
350
- base_version: "{self._format_version_display(base_version)}"
351
- deployment_type: "system"
352
-
353
- ...
354
- ---
355
-
356
- # System Prompt
357
-
358
- """
606
+ tools: {tools_str}
607
+ priority: {priority}
608
+ model: {model}
609
+ temperature: {temperature}"""
610
+
611
+ # Add allowed_tools if present
612
+ if 'allowed_tools' in capabilities:
613
+ yaml_content += f"\nallowed_tools: {json.dumps(capabilities['allowed_tools'])}"
614
+
615
+ # Add disallowed_tools if present
616
+ if 'disallowed_tools' in capabilities:
617
+ yaml_content += f"\ndisallowed_tools: {json.dumps(capabilities['disallowed_tools'])}"
618
+
619
+ yaml_content += "\n---\n"
620
+
621
+ # Get instructions from template
622
+ instructions = (
623
+ template_data.get('instructions') or
624
+ base_agent_data.get('narrative_fields', {}).get('instructions', '')
625
+ )
359
626
 
360
- # Add combined instructions
361
- combined_instructions = narrative_fields.get('instructions', '')
362
- if combined_instructions:
363
- yaml_content += combined_instructions
627
+ # Add base instructions if not already included
628
+ base_instructions = base_agent_data.get('narrative_fields', {}).get('instructions', '')
629
+ if base_instructions and base_instructions not in instructions:
630
+ yaml_content += base_instructions + "\n\n---\n\n"
631
+
632
+ yaml_content += instructions
364
633
 
365
634
  return yaml_content
366
635
 
@@ -421,17 +690,74 @@ metadata:
421
690
  # Override with template-specific configuration
422
691
  merged.update(template_config)
423
692
 
693
+ # Also merge in capabilities from new format if not already in config
694
+ capabilities = template_data.get('capabilities', {})
695
+ if capabilities:
696
+ # Map capabilities fields to configuration fields
697
+ if 'tools' not in merged and 'tools' in capabilities:
698
+ merged['tools'] = capabilities['tools']
699
+ if 'max_tokens' not in merged and 'max_tokens' in capabilities:
700
+ merged['max_tokens'] = capabilities['max_tokens']
701
+ if 'temperature' not in merged and 'temperature' in capabilities:
702
+ merged['temperature'] = capabilities['temperature']
703
+ if 'timeout' not in merged and 'timeout' in capabilities:
704
+ merged['timeout'] = capabilities['timeout']
705
+ if 'memory_limit' not in merged and 'memory_limit' in capabilities:
706
+ merged['memory_limit'] = capabilities['memory_limit']
707
+ if 'cpu_limit' not in merged and 'cpu_limit' in capabilities:
708
+ merged['cpu_limit'] = capabilities['cpu_limit']
709
+ if 'network_access' not in merged and 'network_access' in capabilities:
710
+ merged['network_access'] = capabilities['network_access']
711
+ if 'model' not in merged and 'model' in capabilities:
712
+ merged['model'] = capabilities['model']
713
+
714
+ # Also check metadata for description and tags in new format
715
+ metadata = template_data.get('metadata', {})
716
+ if metadata:
717
+ if 'description' not in merged and 'description' in metadata:
718
+ merged['description'] = metadata['description']
719
+ if 'tags' not in merged and 'tags' in metadata:
720
+ merged['tags'] = metadata['tags']
721
+
424
722
  return merged
425
723
 
426
724
  def set_claude_environment(self, config_dir: Optional[Path] = None) -> Dict[str, str]:
427
725
  """
428
726
  Set Claude environment variables for agent discovery.
429
727
 
728
+ OPERATIONAL PURPOSE:
729
+ Claude Code discovers agents through environment variables that
730
+ point to configuration directories. This method ensures proper
731
+ environment setup for agent runtime discovery.
732
+
733
+ ENVIRONMENT VARIABLES SET:
734
+ 1. CLAUDE_CONFIG_DIR: Root configuration directory path
735
+ 2. CLAUDE_MAX_PARALLEL_SUBAGENTS: Concurrency limit (default: 5)
736
+ 3. CLAUDE_TIMEOUT: Agent execution timeout (default: 600s)
737
+
738
+ DEPLOYMENT CONSIDERATIONS:
739
+ - Call after agent deployment for immediate availability
740
+ - Environment changes affect current process and children
741
+ - Does not persist across system restarts
742
+ - Add to shell profile for permanent configuration
743
+
744
+ TROUBLESHOOTING:
745
+ - Verify with: echo $CLAUDE_CONFIG_DIR
746
+ - Check agent discovery: ls $CLAUDE_CONFIG_DIR/agents/
747
+ - Monitor timeout issues in production
748
+ - Adjust parallel limits based on system resources
749
+
750
+ PERFORMANCE TUNING:
751
+ - Increase parallel agents for CPU-bound tasks
752
+ - Reduce for memory-constrained environments
753
+ - Balance timeout with longest expected operations
754
+ - Monitor resource usage during parallel execution
755
+
430
756
  Args:
431
757
  config_dir: Claude configuration directory (default: .claude/)
432
758
 
433
759
  Returns:
434
- Dictionary of environment variables set
760
+ Dictionary of environment variables set for verification
435
761
  """
436
762
  if not config_dir:
437
763
  config_dir = Path.cwd() / Paths.CLAUDE_CONFIG_DIR.value
@@ -458,11 +784,46 @@ metadata:
458
784
  """
459
785
  Verify agent deployment and Claude configuration.
460
786
 
787
+ OPERATIONAL PURPOSE:
788
+ Post-deployment verification ensures agents are correctly deployed
789
+ and discoverable by Claude Code. Critical for deployment validation
790
+ and troubleshooting runtime issues.
791
+
792
+ VERIFICATION CHECKS:
793
+ 1. Configuration directory exists and is accessible
794
+ 2. Agents directory contains expected YAML files
795
+ 3. Agent files have valid YAML frontmatter
796
+ 4. Version format is current (identifies migration needs)
797
+ 5. Environment variables are properly set
798
+
799
+ MONITORING INTEGRATION:
800
+ - Call after deployment for health checks
801
+ - Include in deployment pipelines
802
+ - Log results for audit trails
803
+ - Alert on missing agents or errors
804
+
805
+ TROUBLESHOOTING GUIDE:
806
+ - Missing config_dir: Check deployment target path
807
+ - No agents found: Verify deployment completed
808
+ - Migration needed: Run with force_rebuild
809
+ - Environment warnings: Call set_claude_environment()
810
+
811
+ RESULT INTERPRETATION:
812
+ - agents_found: Successfully deployed agents
813
+ - agents_needing_migration: Require version update
814
+ - warnings: Non-critical issues to address
815
+ - environment: Current runtime configuration
816
+
461
817
  Args:
462
818
  config_dir: Claude configuration directory (default: .claude/)
463
819
 
464
820
  Returns:
465
- Verification results
821
+ Verification results dictionary:
822
+ - config_dir: Checked directory path
823
+ - agents_found: List of discovered agents with metadata
824
+ - agents_needing_migration: Agents with old version format
825
+ - environment: Current environment variables
826
+ - warnings: List of potential issues
466
827
  """
467
828
  if not config_dir:
468
829
  config_dir = Path.cwd() / ".claude"
@@ -487,7 +848,7 @@ metadata:
487
848
  return results
488
849
 
489
850
  # List deployed agents
490
- agent_files = list(agents_dir.glob("*.md"))
851
+ agent_files = list(agents_dir.glob("*.yaml"))
491
852
  for agent_file in agent_files:
492
853
  try:
493
854
  # Read first few lines to get agent name from YAML
@@ -592,13 +953,40 @@ metadata:
592
953
  """
593
954
  Check if a deployed agent needs to be updated.
594
955
 
956
+ OPERATIONAL LOGIC:
957
+ 1. Verifies agent is system-managed (claude-mpm authored)
958
+ 2. Extracts version from deployed YAML frontmatter
959
+ 3. Detects old version formats requiring migration
960
+ 4. Compares semantic versions for update decision
961
+ 5. Returns detailed reason for update/skip decision
962
+
963
+ VERSION MIGRATION STRATEGY:
964
+ - Old serial format (0002-0005) -> Semantic (2.5.0)
965
+ - Missing versions -> Force update to latest
966
+ - Non-semantic formats -> Trigger migration
967
+ - Preserves user modifications (non-system agents)
968
+
969
+ PERFORMANCE OPTIMIZATION:
970
+ - Early exit for non-system agents
971
+ - Regex compilation cached by Python
972
+ - Minimal file reads (frontmatter only)
973
+ - Version comparison without full parse
974
+
975
+ ERROR RECOVERY:
976
+ - Assumes update needed on parse failures
977
+ - Logs warnings for investigation
978
+ - Never blocks deployment pipeline
979
+ - Safe fallback to force update
980
+
595
981
  Args:
596
982
  deployed_file: Path to the deployed agent file
597
983
  template_file: Path to the template file
598
- current_base_version: Current base agent version
984
+ current_base_version: Current base agent version (unused in new strategy)
599
985
 
600
986
  Returns:
601
- Tuple of (needs_update, reason)
987
+ Tuple of (needs_update: bool, reason: str)
988
+ - needs_update: True if agent should be redeployed
989
+ - reason: Human-readable explanation for decision
602
990
  """
603
991
  try:
604
992
  # Read deployed agent content
@@ -713,7 +1101,7 @@ metadata:
713
1101
  return results
714
1102
 
715
1103
  # Remove system agents only (identified by claude-mpm author)
716
- agent_files = list(agents_dir.glob("*.md"))
1104
+ agent_files = list(agents_dir.glob("*.yaml"))
717
1105
 
718
1106
  for agent_file in agent_files:
719
1107
  try: