claude-mpm 3.1.1__py3-none-any.whl → 3.1.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.
- claude_mpm/__main__.py +10 -3
 - claude_mpm/agents/templates/test-integration-agent.md +34 -0
 - claude_mpm/cli/README.md +109 -0
 - claude_mpm/cli/__init__.py +163 -0
 - claude_mpm/cli/commands/__init__.py +20 -0
 - claude_mpm/cli/commands/agents.py +191 -0
 - claude_mpm/cli/commands/info.py +89 -0
 - claude_mpm/cli/commands/run.py +80 -0
 - claude_mpm/cli/commands/tickets.py +63 -0
 - claude_mpm/cli/commands/ui.py +57 -0
 - claude_mpm/cli/parser.py +337 -0
 - claude_mpm/cli/utils.py +171 -0
 - claude_mpm/cli_enhancements.py +19 -0
 - claude_mpm/models/__init__.py +24 -0
 - claude_mpm/models/agent_definition.py +196 -0
 - claude_mpm/services/agent_lifecycle_manager.py +183 -20
 - claude_mpm/services/agent_modification_tracker.py +10 -2
 - claude_mpm/services/agent_persistence_service.py +94 -0
 - claude_mpm/services/agent_versioning.py +37 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/METADATA +1 -1
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/RECORD +26 -12
 - claude_mpm/cli_main.py +0 -13
 - /claude_mpm/{cli.py → cli_old.py} +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/WHEEL +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/entry_points.txt +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/licenses/LICENSE +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.2.dist-info}/top_level.txt +0 -0
 
    
        claude_mpm/cli/utils.py
    ADDED
    
    | 
         @@ -0,0 +1,171 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """
         
     | 
| 
      
 2 
     | 
    
         
            +
            Utility functions for the CLI.
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            WHY: This module contains shared utility functions used across different CLI commands.
         
     | 
| 
      
 5 
     | 
    
         
            +
            Centralizing these functions reduces code duplication and provides a single place
         
     | 
| 
      
 6 
     | 
    
         
            +
            for common CLI operations.
         
     | 
| 
      
 7 
     | 
    
         
            +
            """
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            import sys
         
     | 
| 
      
 10 
     | 
    
         
            +
            from pathlib import Path
         
     | 
| 
      
 11 
     | 
    
         
            +
            from typing import Optional
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            from ..core.logger import get_logger
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            def get_user_input(input_arg: Optional[str], logger) -> str:
         
     | 
| 
      
 17 
     | 
    
         
            +
                """
         
     | 
| 
      
 18 
     | 
    
         
            +
                Get user input based on command line arguments.
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                WHY: This function handles the three ways users can provide input:
         
     | 
| 
      
 21 
     | 
    
         
            +
                1. Direct text via -i/--input
         
     | 
| 
      
 22 
     | 
    
         
            +
                2. File path via -i/--input
         
     | 
| 
      
 23 
     | 
    
         
            +
                3. stdin (for piping)
         
     | 
| 
      
 24 
     | 
    
         
            +
                
         
     | 
| 
      
 25 
     | 
    
         
            +
                DESIGN DECISION: We check if the input is a file path first, then fall back
         
     | 
| 
      
 26 
     | 
    
         
            +
                to treating it as direct text. This allows maximum flexibility.
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                Args:
         
     | 
| 
      
 29 
     | 
    
         
            +
                    input_arg: The value of the -i/--input argument
         
     | 
| 
      
 30 
     | 
    
         
            +
                    logger: Logger instance for output
         
     | 
| 
      
 31 
     | 
    
         
            +
                    
         
     | 
| 
      
 32 
     | 
    
         
            +
                Returns:
         
     | 
| 
      
 33 
     | 
    
         
            +
                    The user input as a string
         
     | 
| 
      
 34 
     | 
    
         
            +
                """
         
     | 
| 
      
 35 
     | 
    
         
            +
                if input_arg:
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # Check if it's a file path
         
     | 
| 
      
 37 
     | 
    
         
            +
                    input_path = Path(input_arg)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    if input_path.exists():
         
     | 
| 
      
 39 
     | 
    
         
            +
                        logger.info(f"Reading input from file: {input_path}")
         
     | 
| 
      
 40 
     | 
    
         
            +
                        return input_path.read_text()
         
     | 
| 
      
 41 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 42 
     | 
    
         
            +
                        logger.info("Using command line input")
         
     | 
| 
      
 43 
     | 
    
         
            +
                        return input_arg
         
     | 
| 
      
 44 
     | 
    
         
            +
                else:
         
     | 
| 
      
 45 
     | 
    
         
            +
                    # Read from stdin
         
     | 
| 
      
 46 
     | 
    
         
            +
                    logger.info("Reading input from stdin")
         
     | 
| 
      
 47 
     | 
    
         
            +
                    return sys.stdin.read()
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            def get_agent_versions_display() -> Optional[str]:
         
     | 
| 
      
 51 
     | 
    
         
            +
                """
         
     | 
| 
      
 52 
     | 
    
         
            +
                Get formatted agent versions display as a string.
         
     | 
| 
      
 53 
     | 
    
         
            +
                
         
     | 
| 
      
 54 
     | 
    
         
            +
                WHY: This function provides a single source of truth for agent version
         
     | 
| 
      
 55 
     | 
    
         
            +
                information that can be displayed both at startup and on-demand via the
         
     | 
| 
      
 56 
     | 
    
         
            +
                /mpm agents command. This ensures consistency in how agent versions are
         
     | 
| 
      
 57 
     | 
    
         
            +
                presented to users.
         
     | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                Returns:
         
     | 
| 
      
 60 
     | 
    
         
            +
                    Formatted string containing agent version information, or None if failed
         
     | 
| 
      
 61 
     | 
    
         
            +
                """
         
     | 
| 
      
 62 
     | 
    
         
            +
                try:
         
     | 
| 
      
 63 
     | 
    
         
            +
                    from ..services.agent_deployment import AgentDeploymentService
         
     | 
| 
      
 64 
     | 
    
         
            +
                    deployment_service = AgentDeploymentService()
         
     | 
| 
      
 65 
     | 
    
         
            +
                    
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # Get deployed agents
         
     | 
| 
      
 67 
     | 
    
         
            +
                    verification = deployment_service.verify_deployment()
         
     | 
| 
      
 68 
     | 
    
         
            +
                    if not verification.get("agents_found"):
         
     | 
| 
      
 69 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 70 
     | 
    
         
            +
                        
         
     | 
| 
      
 71 
     | 
    
         
            +
                    output_lines = []
         
     | 
| 
      
 72 
     | 
    
         
            +
                    output_lines.append("\nDeployed Agent Versions:")
         
     | 
| 
      
 73 
     | 
    
         
            +
                    output_lines.append("-" * 40)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    
         
     | 
| 
      
 75 
     | 
    
         
            +
                    # Sort agents by name for consistent display
         
     | 
| 
      
 76 
     | 
    
         
            +
                    agents = sorted(verification["agents_found"], key=lambda x: x.get('name', x.get('file', '')))
         
     | 
| 
      
 77 
     | 
    
         
            +
                    
         
     | 
| 
      
 78 
     | 
    
         
            +
                    for agent in agents:
         
     | 
| 
      
 79 
     | 
    
         
            +
                        name = agent.get('name', 'unknown')
         
     | 
| 
      
 80 
     | 
    
         
            +
                        version = agent.get('version', 'unknown')
         
     | 
| 
      
 81 
     | 
    
         
            +
                        # Format: name (version)
         
     | 
| 
      
 82 
     | 
    
         
            +
                        output_lines.append(f"  {name:<20} {version}")
         
     | 
| 
      
 83 
     | 
    
         
            +
                    
         
     | 
| 
      
 84 
     | 
    
         
            +
                    # Add base agent version info
         
     | 
| 
      
 85 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 86 
     | 
    
         
            +
                        import json
         
     | 
| 
      
 87 
     | 
    
         
            +
                        base_agent_path = deployment_service.base_agent_path
         
     | 
| 
      
 88 
     | 
    
         
            +
                        if base_agent_path.exists():
         
     | 
| 
      
 89 
     | 
    
         
            +
                            base_data = json.loads(base_agent_path.read_text())
         
     | 
| 
      
 90 
     | 
    
         
            +
                            # Parse version the same way as AgentDeploymentService
         
     | 
| 
      
 91 
     | 
    
         
            +
                            raw_version = base_data.get('base_version') or base_data.get('version', 0)
         
     | 
| 
      
 92 
     | 
    
         
            +
                            base_version_tuple = deployment_service._parse_version(raw_version)
         
     | 
| 
      
 93 
     | 
    
         
            +
                            base_version_str = deployment_service._format_version_display(base_version_tuple)
         
     | 
| 
      
 94 
     | 
    
         
            +
                            output_lines.append(f"\n  Base Agent Version:  {base_version_str}")
         
     | 
| 
      
 95 
     | 
    
         
            +
                    except:
         
     | 
| 
      
 96 
     | 
    
         
            +
                        pass
         
     | 
| 
      
 97 
     | 
    
         
            +
                    
         
     | 
| 
      
 98 
     | 
    
         
            +
                    # Check for agents needing migration
         
     | 
| 
      
 99 
     | 
    
         
            +
                    if verification.get("agents_needing_migration"):
         
     | 
| 
      
 100 
     | 
    
         
            +
                        output_lines.append(f"\n  ⚠️  {len(verification['agents_needing_migration'])} agent(s) need migration to semantic versioning")
         
     | 
| 
      
 101 
     | 
    
         
            +
                        output_lines.append(f"     Run 'claude-mpm agents deploy' to update")
         
     | 
| 
      
 102 
     | 
    
         
            +
                        
         
     | 
| 
      
 103 
     | 
    
         
            +
                    output_lines.append("-" * 40)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    return "\n".join(output_lines)
         
     | 
| 
      
 105 
     | 
    
         
            +
                except Exception as e:
         
     | 
| 
      
 106 
     | 
    
         
            +
                    # Log error but don't fail
         
     | 
| 
      
 107 
     | 
    
         
            +
                    logger = get_logger("cli")
         
     | 
| 
      
 108 
     | 
    
         
            +
                    logger.debug(f"Failed to get agent versions: {e}")
         
     | 
| 
      
 109 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
            def list_agent_versions_at_startup() -> None:
         
     | 
| 
      
 113 
     | 
    
         
            +
                """
         
     | 
| 
      
 114 
     | 
    
         
            +
                List deployed agent versions at startup.
         
     | 
| 
      
 115 
     | 
    
         
            +
                
         
     | 
| 
      
 116 
     | 
    
         
            +
                WHY: Users want to see what agents are available when they start a session.
         
     | 
| 
      
 117 
     | 
    
         
            +
                This provides immediate feedback about the deployed agent environment.
         
     | 
| 
      
 118 
     | 
    
         
            +
                """
         
     | 
| 
      
 119 
     | 
    
         
            +
                agent_versions = get_agent_versions_display()
         
     | 
| 
      
 120 
     | 
    
         
            +
                if agent_versions:
         
     | 
| 
      
 121 
     | 
    
         
            +
                    print(agent_versions)
         
     | 
| 
      
 122 
     | 
    
         
            +
                    print()  # Extra newline after the display
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            def setup_logging(args) -> object:
         
     | 
| 
      
 126 
     | 
    
         
            +
                """
         
     | 
| 
      
 127 
     | 
    
         
            +
                Set up logging based on parsed arguments.
         
     | 
| 
      
 128 
     | 
    
         
            +
                
         
     | 
| 
      
 129 
     | 
    
         
            +
                WHY: This centralizes logging setup logic, handling the deprecated --debug flag
         
     | 
| 
      
 130 
     | 
    
         
            +
                and the new --logging argument consistently across all commands.
         
     | 
| 
      
 131 
     | 
    
         
            +
                
         
     | 
| 
      
 132 
     | 
    
         
            +
                Args:
         
     | 
| 
      
 133 
     | 
    
         
            +
                    args: Parsed command line arguments
         
     | 
| 
      
 134 
     | 
    
         
            +
                    
         
     | 
| 
      
 135 
     | 
    
         
            +
                Returns:
         
     | 
| 
      
 136 
     | 
    
         
            +
                    Logger instance
         
     | 
| 
      
 137 
     | 
    
         
            +
                """
         
     | 
| 
      
 138 
     | 
    
         
            +
                from ..core.logger import setup_logging as core_setup_logging, get_logger
         
     | 
| 
      
 139 
     | 
    
         
            +
                from ..constants import LogLevel
         
     | 
| 
      
 140 
     | 
    
         
            +
                
         
     | 
| 
      
 141 
     | 
    
         
            +
                # Handle deprecated --debug flag
         
     | 
| 
      
 142 
     | 
    
         
            +
                if hasattr(args, 'debug') and args.debug and args.logging == LogLevel.INFO.value:
         
     | 
| 
      
 143 
     | 
    
         
            +
                    args.logging = LogLevel.DEBUG.value
         
     | 
| 
      
 144 
     | 
    
         
            +
                
         
     | 
| 
      
 145 
     | 
    
         
            +
                # Only setup logging if not OFF
         
     | 
| 
      
 146 
     | 
    
         
            +
                if args.logging != LogLevel.OFF.value:
         
     | 
| 
      
 147 
     | 
    
         
            +
                    logger = core_setup_logging(level=args.logging, log_dir=args.log_dir)
         
     | 
| 
      
 148 
     | 
    
         
            +
                else:
         
     | 
| 
      
 149 
     | 
    
         
            +
                    # Minimal logger for CLI feedback
         
     | 
| 
      
 150 
     | 
    
         
            +
                    import logging
         
     | 
| 
      
 151 
     | 
    
         
            +
                    logger = logging.getLogger("cli")
         
     | 
| 
      
 152 
     | 
    
         
            +
                    logger.setLevel(logging.WARNING)
         
     | 
| 
      
 153 
     | 
    
         
            +
                
         
     | 
| 
      
 154 
     | 
    
         
            +
                return logger
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            def ensure_directories() -> None:
         
     | 
| 
      
 158 
     | 
    
         
            +
                """
         
     | 
| 
      
 159 
     | 
    
         
            +
                Ensure required directories exist on first run.
         
     | 
| 
      
 160 
     | 
    
         
            +
                
         
     | 
| 
      
 161 
     | 
    
         
            +
                WHY: Claude-mpm needs certain directories to function properly. Rather than
         
     | 
| 
      
 162 
     | 
    
         
            +
                failing when they don't exist, we create them automatically for a better
         
     | 
| 
      
 163 
     | 
    
         
            +
                user experience.
         
     | 
| 
      
 164 
     | 
    
         
            +
                """
         
     | 
| 
      
 165 
     | 
    
         
            +
                try:
         
     | 
| 
      
 166 
     | 
    
         
            +
                    from ..init import ensure_directories as init_ensure_directories
         
     | 
| 
      
 167 
     | 
    
         
            +
                    init_ensure_directories()
         
     | 
| 
      
 168 
     | 
    
         
            +
                except Exception:
         
     | 
| 
      
 169 
     | 
    
         
            +
                    # Continue even if initialization fails
         
     | 
| 
      
 170 
     | 
    
         
            +
                    # The individual commands will handle missing directories as needed
         
     | 
| 
      
 171 
     | 
    
         
            +
                    pass
         
     | 
    
        claude_mpm/cli_enhancements.py
    CHANGED
    
    | 
         @@ -1,6 +1,25 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            """
         
     | 
| 
       2 
2 
     | 
    
         
             
            Enhanced CLI operations for claude-mpm.
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
      
 4 
     | 
    
         
            +
            WHY THIS FILE EXISTS:
         
     | 
| 
      
 5 
     | 
    
         
            +
            This module provides an alternative CLI implementation with enhanced error handling
         
     | 
| 
      
 6 
     | 
    
         
            +
            and validation features. It was created to explore advanced CLI patterns including:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Comprehensive prerequisite validation
         
     | 
| 
      
 8 
     | 
    
         
            +
            - User-friendly error messages with suggestions
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Dry-run mode for testing
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Profile validation and generation
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Rich terminal output with status indicators
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            CURRENT STATUS: This is an experimental/alternative CLI implementation that uses
         
     | 
| 
      
 14 
     | 
    
         
            +
            Click instead of argparse. It's kept separate from the main CLI to:
         
     | 
| 
      
 15 
     | 
    
         
            +
            1. Preserve the existing CLI behavior
         
     | 
| 
      
 16 
     | 
    
         
            +
            2. Allow testing of new features without breaking the main interface
         
     | 
| 
      
 17 
     | 
    
         
            +
            3. Provide a reference implementation for future CLI enhancements
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            NOTE: This CLI is not currently used in production. The main CLI is in cli/__init__.py.
         
     | 
| 
      
 20 
     | 
    
         
            +
            To use this enhanced CLI, you would need to create a separate entry point or
         
     | 
| 
      
 21 
     | 
    
         
            +
            integrate selected features into the main CLI.
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       4 
23 
     | 
    
         
             
            Implements error handling and user guidance patterns from awesome-claude-code.
         
     | 
| 
       5 
24 
     | 
    
         
             
            """
         
     | 
| 
       6 
25 
     | 
    
         | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """
         
     | 
| 
      
 2 
     | 
    
         
            +
            Agent models package.
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            WHY: This package centralizes all data models used for agent management,
         
     | 
| 
      
 5 
     | 
    
         
            +
            providing a single source of truth for data structures across the system.
         
     | 
| 
      
 6 
     | 
    
         
            +
            """
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            from .agent_definition import (
         
     | 
| 
      
 9 
     | 
    
         
            +
                AgentDefinition,
         
     | 
| 
      
 10 
     | 
    
         
            +
                AgentMetadata,
         
     | 
| 
      
 11 
     | 
    
         
            +
                AgentType,
         
     | 
| 
      
 12 
     | 
    
         
            +
                AgentSection,
         
     | 
| 
      
 13 
     | 
    
         
            +
                AgentWorkflow,
         
     | 
| 
      
 14 
     | 
    
         
            +
                AgentPermissions
         
     | 
| 
      
 15 
     | 
    
         
            +
            )
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            __all__ = [
         
     | 
| 
      
 18 
     | 
    
         
            +
                'AgentDefinition',
         
     | 
| 
      
 19 
     | 
    
         
            +
                'AgentMetadata',
         
     | 
| 
      
 20 
     | 
    
         
            +
                'AgentType',
         
     | 
| 
      
 21 
     | 
    
         
            +
                'AgentSection',
         
     | 
| 
      
 22 
     | 
    
         
            +
                'AgentWorkflow',
         
     | 
| 
      
 23 
     | 
    
         
            +
                'AgentPermissions'
         
     | 
| 
      
 24 
     | 
    
         
            +
            ]
         
     | 
| 
         @@ -0,0 +1,196 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env python3
         
     | 
| 
      
 2 
     | 
    
         
            +
            """
         
     | 
| 
      
 3 
     | 
    
         
            +
            Agent Definition Models
         
     | 
| 
      
 4 
     | 
    
         
            +
            =======================
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Data models for agent definitions used by AgentManager.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            WHY: These models provide a structured representation of agent data to ensure
         
     | 
| 
      
 9 
     | 
    
         
            +
            consistency across the system. They separate the data structure from the
         
     | 
| 
      
 10 
     | 
    
         
            +
            business logic, following the separation of concerns principle.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            DESIGN DECISION: Using dataclasses for models because:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - They provide automatic __init__, __repr__, and other methods
         
     | 
| 
      
 14 
     | 
    
         
            +
            - Type hints ensure better IDE support and runtime validation
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Easy to serialize/deserialize for persistence
         
     | 
| 
      
 16 
     | 
    
         
            +
            - Less boilerplate than traditional classes
         
     | 
| 
      
 17 
     | 
    
         
            +
            """
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            from dataclasses import dataclass, field
         
     | 
| 
      
 20 
     | 
    
         
            +
            from datetime import datetime
         
     | 
| 
      
 21 
     | 
    
         
            +
            from enum import Enum
         
     | 
| 
      
 22 
     | 
    
         
            +
            from typing import Dict, List, Optional, Any
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            class AgentType(str, Enum):
         
     | 
| 
      
 26 
     | 
    
         
            +
                """Agent type classification.
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                WHY: Enum ensures only valid agent types are used throughout the system,
         
     | 
| 
      
 29 
     | 
    
         
            +
                preventing typos and making the code more maintainable.
         
     | 
| 
      
 30 
     | 
    
         
            +
                """
         
     | 
| 
      
 31 
     | 
    
         
            +
                CORE = "core"
         
     | 
| 
      
 32 
     | 
    
         
            +
                PROJECT = "project"
         
     | 
| 
      
 33 
     | 
    
         
            +
                CUSTOM = "custom"
         
     | 
| 
      
 34 
     | 
    
         
            +
                SYSTEM = "system"
         
     | 
| 
      
 35 
     | 
    
         
            +
                SPECIALIZED = "specialized"
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            class AgentSection(str, Enum):
         
     | 
| 
      
 39 
     | 
    
         
            +
                """Agent markdown section identifiers.
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                WHY: Standardizes section names across the codebase, making it easier
         
     | 
| 
      
 42 
     | 
    
         
            +
                to parse and update specific sections programmatically.
         
     | 
| 
      
 43 
     | 
    
         
            +
                """
         
     | 
| 
      
 44 
     | 
    
         
            +
                PRIMARY_ROLE = "Primary Role"
         
     | 
| 
      
 45 
     | 
    
         
            +
                WHEN_TO_USE = "When to Use This Agent"
         
     | 
| 
      
 46 
     | 
    
         
            +
                CAPABILITIES = "Core Capabilities"
         
     | 
| 
      
 47 
     | 
    
         
            +
                AUTHORITY = "Authority & Permissions"
         
     | 
| 
      
 48 
     | 
    
         
            +
                WORKFLOWS = "Agent-Specific Workflows"
         
     | 
| 
      
 49 
     | 
    
         
            +
                ESCALATION = "Unique Escalation Triggers"
         
     | 
| 
      
 50 
     | 
    
         
            +
                KPI = "Key Performance Indicators"
         
     | 
| 
      
 51 
     | 
    
         
            +
                DEPENDENCIES = "Critical Dependencies"
         
     | 
| 
      
 52 
     | 
    
         
            +
                TOOLS = "Specialized Tools/Commands"
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 56 
     | 
    
         
            +
            class AgentPermissions:
         
     | 
| 
      
 57 
     | 
    
         
            +
                """Agent authority and permissions.
         
     | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                WHY: Separating permissions into a dedicated class allows for:
         
     | 
| 
      
 60 
     | 
    
         
            +
                - Clear permission boundaries
         
     | 
| 
      
 61 
     | 
    
         
            +
                - Easy permission checking and validation
         
     | 
| 
      
 62 
     | 
    
         
            +
                - Future extension without modifying the main agent definition
         
     | 
| 
      
 63 
     | 
    
         
            +
                """
         
     | 
| 
      
 64 
     | 
    
         
            +
                exclusive_write_access: List[str] = field(default_factory=list)
         
     | 
| 
      
 65 
     | 
    
         
            +
                forbidden_operations: List[str] = field(default_factory=list)
         
     | 
| 
      
 66 
     | 
    
         
            +
                read_access: List[str] = field(default_factory=list)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 70 
     | 
    
         
            +
            class AgentWorkflow:
         
     | 
| 
      
 71 
     | 
    
         
            +
                """Agent workflow definition.
         
     | 
| 
      
 72 
     | 
    
         
            +
                
         
     | 
| 
      
 73 
     | 
    
         
            +
                WHY: Workflows are complex structures that benefit from their own model:
         
     | 
| 
      
 74 
     | 
    
         
            +
                - Ensures consistent workflow structure
         
     | 
| 
      
 75 
     | 
    
         
            +
                - Makes workflow validation easier
         
     | 
| 
      
 76 
     | 
    
         
            +
                - Allows workflow-specific operations
         
     | 
| 
      
 77 
     | 
    
         
            +
                """
         
     | 
| 
      
 78 
     | 
    
         
            +
                name: str
         
     | 
| 
      
 79 
     | 
    
         
            +
                trigger: str
         
     | 
| 
      
 80 
     | 
    
         
            +
                process: List[str]
         
     | 
| 
      
 81 
     | 
    
         
            +
                output: str
         
     | 
| 
      
 82 
     | 
    
         
            +
                raw_yaml: Optional[str] = None
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 86 
     | 
    
         
            +
            class AgentMetadata:
         
     | 
| 
      
 87 
     | 
    
         
            +
                """Agent metadata information.
         
     | 
| 
      
 88 
     | 
    
         
            +
                
         
     | 
| 
      
 89 
     | 
    
         
            +
                WHY: Metadata is separated from the main definition because:
         
     | 
| 
      
 90 
     | 
    
         
            +
                - It changes independently of agent behavior
         
     | 
| 
      
 91 
     | 
    
         
            +
                - It's used for discovery and management, not execution
         
     | 
| 
      
 92 
     | 
    
         
            +
                - Different services may need different metadata views
         
     | 
| 
      
 93 
     | 
    
         
            +
                """
         
     | 
| 
      
 94 
     | 
    
         
            +
                type: AgentType
         
     | 
| 
      
 95 
     | 
    
         
            +
                model_preference: str = "claude-3-sonnet"
         
     | 
| 
      
 96 
     | 
    
         
            +
                version: str = "1.0.0"
         
     | 
| 
      
 97 
     | 
    
         
            +
                last_updated: Optional[datetime] = None
         
     | 
| 
      
 98 
     | 
    
         
            +
                author: Optional[str] = None
         
     | 
| 
      
 99 
     | 
    
         
            +
                tags: List[str] = field(default_factory=list)
         
     | 
| 
      
 100 
     | 
    
         
            +
                specializations: List[str] = field(default_factory=list)
         
     | 
| 
      
 101 
     | 
    
         
            +
                
         
     | 
| 
      
 102 
     | 
    
         
            +
                def increment_serial_version(self) -> None:
         
     | 
| 
      
 103 
     | 
    
         
            +
                    """Increment the patch version number.
         
     | 
| 
      
 104 
     | 
    
         
            +
                    
         
     | 
| 
      
 105 
     | 
    
         
            +
                    WHY: Automatic version incrementing ensures every change is tracked
         
     | 
| 
      
 106 
     | 
    
         
            +
                    and follows semantic versioning principles.
         
     | 
| 
      
 107 
     | 
    
         
            +
                    """
         
     | 
| 
      
 108 
     | 
    
         
            +
                    parts = self.version.split('.')
         
     | 
| 
      
 109 
     | 
    
         
            +
                    if len(parts) == 3:
         
     | 
| 
      
 110 
     | 
    
         
            +
                        parts[2] = str(int(parts[2]) + 1)
         
     | 
| 
      
 111 
     | 
    
         
            +
                        self.version = '.'.join(parts)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 113 
     | 
    
         
            +
                        # If version format is unexpected, append .1
         
     | 
| 
      
 114 
     | 
    
         
            +
                        self.version = f"{self.version}.1"
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 118 
     | 
    
         
            +
            class AgentDefinition:
         
     | 
| 
      
 119 
     | 
    
         
            +
                """Complete agent definition.
         
     | 
| 
      
 120 
     | 
    
         
            +
                
         
     | 
| 
      
 121 
     | 
    
         
            +
                WHY: This is the main model that represents an agent's complete configuration:
         
     | 
| 
      
 122 
     | 
    
         
            +
                - Combines all aspects of an agent in one place
         
     | 
| 
      
 123 
     | 
    
         
            +
                - Provides a clear contract for what constitutes an agent
         
     | 
| 
      
 124 
     | 
    
         
            +
                - Makes serialization/deserialization straightforward
         
     | 
| 
      
 125 
     | 
    
         
            +
                
         
     | 
| 
      
 126 
     | 
    
         
            +
                DESIGN DECISION: Using composition over inheritance:
         
     | 
| 
      
 127 
     | 
    
         
            +
                - AgentMetadata, AgentPermissions, and AgentWorkflow are separate classes
         
     | 
| 
      
 128 
     | 
    
         
            +
                - This allows each component to evolve independently
         
     | 
| 
      
 129 
     | 
    
         
            +
                - Services can work with just the parts they need
         
     | 
| 
      
 130 
     | 
    
         
            +
                """
         
     | 
| 
      
 131 
     | 
    
         
            +
                # Core identifiers
         
     | 
| 
      
 132 
     | 
    
         
            +
                name: str
         
     | 
| 
      
 133 
     | 
    
         
            +
                title: str
         
     | 
| 
      
 134 
     | 
    
         
            +
                file_path: str
         
     | 
| 
      
 135 
     | 
    
         
            +
                
         
     | 
| 
      
 136 
     | 
    
         
            +
                # Metadata
         
     | 
| 
      
 137 
     | 
    
         
            +
                metadata: AgentMetadata
         
     | 
| 
      
 138 
     | 
    
         
            +
                
         
     | 
| 
      
 139 
     | 
    
         
            +
                # Agent behavior definition
         
     | 
| 
      
 140 
     | 
    
         
            +
                primary_role: str
         
     | 
| 
      
 141 
     | 
    
         
            +
                when_to_use: Dict[str, List[str]]  # {"select": [...], "do_not_select": [...]}
         
     | 
| 
      
 142 
     | 
    
         
            +
                capabilities: List[str]
         
     | 
| 
      
 143 
     | 
    
         
            +
                authority: AgentPermissions
         
     | 
| 
      
 144 
     | 
    
         
            +
                workflows: List[AgentWorkflow]
         
     | 
| 
      
 145 
     | 
    
         
            +
                escalation_triggers: List[str]
         
     | 
| 
      
 146 
     | 
    
         
            +
                kpis: List[str]
         
     | 
| 
      
 147 
     | 
    
         
            +
                dependencies: List[str]
         
     | 
| 
      
 148 
     | 
    
         
            +
                tools_commands: str
         
     | 
| 
      
 149 
     | 
    
         
            +
                
         
     | 
| 
      
 150 
     | 
    
         
            +
                # Raw content for preservation
         
     | 
| 
      
 151 
     | 
    
         
            +
                raw_content: str = ""
         
     | 
| 
      
 152 
     | 
    
         
            +
                raw_sections: Dict[str, str] = field(default_factory=dict)
         
     | 
| 
      
 153 
     | 
    
         
            +
                
         
     | 
| 
      
 154 
     | 
    
         
            +
                def to_dict(self) -> Dict[str, Any]:
         
     | 
| 
      
 155 
     | 
    
         
            +
                    """Convert to dictionary for API responses.
         
     | 
| 
      
 156 
     | 
    
         
            +
                    
         
     | 
| 
      
 157 
     | 
    
         
            +
                    WHY: Many parts of the system need agent data as dictionaries:
         
     | 
| 
      
 158 
     | 
    
         
            +
                    - JSON serialization for APIs
         
     | 
| 
      
 159 
     | 
    
         
            +
                    - Configuration storage
         
     | 
| 
      
 160 
     | 
    
         
            +
                    - Integration with other services
         
     | 
| 
      
 161 
     | 
    
         
            +
                    """
         
     | 
| 
      
 162 
     | 
    
         
            +
                    return {
         
     | 
| 
      
 163 
     | 
    
         
            +
                        "name": self.name,
         
     | 
| 
      
 164 
     | 
    
         
            +
                        "title": self.title,
         
     | 
| 
      
 165 
     | 
    
         
            +
                        "file_path": self.file_path,
         
     | 
| 
      
 166 
     | 
    
         
            +
                        "metadata": {
         
     | 
| 
      
 167 
     | 
    
         
            +
                            "type": self.metadata.type.value,
         
     | 
| 
      
 168 
     | 
    
         
            +
                            "model_preference": self.metadata.model_preference,
         
     | 
| 
      
 169 
     | 
    
         
            +
                            "version": self.metadata.version,
         
     | 
| 
      
 170 
     | 
    
         
            +
                            "last_updated": self.metadata.last_updated.isoformat() if self.metadata.last_updated else None,
         
     | 
| 
      
 171 
     | 
    
         
            +
                            "author": self.metadata.author,
         
     | 
| 
      
 172 
     | 
    
         
            +
                            "tags": self.metadata.tags,
         
     | 
| 
      
 173 
     | 
    
         
            +
                            "specializations": self.metadata.specializations
         
     | 
| 
      
 174 
     | 
    
         
            +
                        },
         
     | 
| 
      
 175 
     | 
    
         
            +
                        "primary_role": self.primary_role,
         
     | 
| 
      
 176 
     | 
    
         
            +
                        "when_to_use": self.when_to_use,
         
     | 
| 
      
 177 
     | 
    
         
            +
                        "capabilities": self.capabilities,
         
     | 
| 
      
 178 
     | 
    
         
            +
                        "authority": {
         
     | 
| 
      
 179 
     | 
    
         
            +
                            "exclusive_write_access": self.authority.exclusive_write_access,
         
     | 
| 
      
 180 
     | 
    
         
            +
                            "forbidden_operations": self.authority.forbidden_operations,
         
     | 
| 
      
 181 
     | 
    
         
            +
                            "read_access": self.authority.read_access
         
     | 
| 
      
 182 
     | 
    
         
            +
                        },
         
     | 
| 
      
 183 
     | 
    
         
            +
                        "workflows": [
         
     | 
| 
      
 184 
     | 
    
         
            +
                            {
         
     | 
| 
      
 185 
     | 
    
         
            +
                                "name": w.name,
         
     | 
| 
      
 186 
     | 
    
         
            +
                                "trigger": w.trigger,
         
     | 
| 
      
 187 
     | 
    
         
            +
                                "process": w.process,
         
     | 
| 
      
 188 
     | 
    
         
            +
                                "output": w.output
         
     | 
| 
      
 189 
     | 
    
         
            +
                            }
         
     | 
| 
      
 190 
     | 
    
         
            +
                            for w in self.workflows
         
     | 
| 
      
 191 
     | 
    
         
            +
                        ],
         
     | 
| 
      
 192 
     | 
    
         
            +
                        "escalation_triggers": self.escalation_triggers,
         
     | 
| 
      
 193 
     | 
    
         
            +
                        "kpis": self.kpis,
         
     | 
| 
      
 194 
     | 
    
         
            +
                        "dependencies": self.dependencies,
         
     | 
| 
      
 195 
     | 
    
         
            +
                        "tools_commands": self.tools_commands
         
     | 
| 
      
 196 
     | 
    
         
            +
                    }
         
     |