claude-mpm 4.5.6__py3-none-any.whl → 4.5.11__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 (62) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +20 -5
  3. claude_mpm/agents/BASE_OPS.md +10 -0
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +28 -4
  5. claude_mpm/agents/agent_loader.py +19 -2
  6. claude_mpm/agents/base_agent_loader.py +5 -5
  7. claude_mpm/agents/templates/agent-manager.json +3 -3
  8. claude_mpm/agents/templates/agentic-coder-optimizer.json +3 -3
  9. claude_mpm/agents/templates/api_qa.json +1 -1
  10. claude_mpm/agents/templates/clerk-ops.json +3 -3
  11. claude_mpm/agents/templates/code_analyzer.json +3 -3
  12. claude_mpm/agents/templates/dart_engineer.json +294 -0
  13. claude_mpm/agents/templates/data_engineer.json +3 -3
  14. claude_mpm/agents/templates/documentation.json +2 -2
  15. claude_mpm/agents/templates/engineer.json +2 -2
  16. claude_mpm/agents/templates/gcp_ops_agent.json +2 -2
  17. claude_mpm/agents/templates/imagemagick.json +1 -1
  18. claude_mpm/agents/templates/local_ops_agent.json +363 -49
  19. claude_mpm/agents/templates/memory_manager.json +2 -2
  20. claude_mpm/agents/templates/nextjs_engineer.json +2 -2
  21. claude_mpm/agents/templates/ops.json +2 -2
  22. claude_mpm/agents/templates/php-engineer.json +1 -1
  23. claude_mpm/agents/templates/project_organizer.json +1 -1
  24. claude_mpm/agents/templates/prompt-engineer.json +6 -4
  25. claude_mpm/agents/templates/python_engineer.json +2 -2
  26. claude_mpm/agents/templates/qa.json +1 -1
  27. claude_mpm/agents/templates/react_engineer.json +3 -3
  28. claude_mpm/agents/templates/refactoring_engineer.json +3 -3
  29. claude_mpm/agents/templates/research.json +2 -2
  30. claude_mpm/agents/templates/security.json +2 -2
  31. claude_mpm/agents/templates/ticketing.json +2 -2
  32. claude_mpm/agents/templates/typescript_engineer.json +2 -2
  33. claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
  34. claude_mpm/agents/templates/version_control.json +2 -2
  35. claude_mpm/agents/templates/web_qa.json +6 -6
  36. claude_mpm/agents/templates/web_ui.json +3 -3
  37. claude_mpm/cli/__init__.py +49 -19
  38. claude_mpm/cli/commands/configure.py +591 -7
  39. claude_mpm/cli/parsers/configure_parser.py +5 -0
  40. claude_mpm/core/__init__.py +53 -17
  41. claude_mpm/core/config.py +1 -1
  42. claude_mpm/core/log_manager.py +7 -0
  43. claude_mpm/hooks/claude_hooks/response_tracking.py +16 -11
  44. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +9 -11
  45. claude_mpm/services/__init__.py +140 -156
  46. claude_mpm/services/agents/deployment/deployment_config_loader.py +21 -0
  47. claude_mpm/services/agents/loading/base_agent_manager.py +12 -2
  48. claude_mpm/services/async_session_logger.py +112 -96
  49. claude_mpm/services/claude_session_logger.py +63 -61
  50. claude_mpm/services/mcp_config_manager.py +328 -38
  51. claude_mpm/services/mcp_gateway/__init__.py +98 -94
  52. claude_mpm/services/monitor/event_emitter.py +1 -1
  53. claude_mpm/services/orphan_detection.py +791 -0
  54. claude_mpm/services/project_port_allocator.py +601 -0
  55. claude_mpm/services/response_tracker.py +17 -6
  56. claude_mpm/services/session_manager.py +176 -0
  57. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/METADATA +1 -1
  58. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/RECORD +62 -58
  59. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/WHEEL +0 -0
  60. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/entry_points.txt +0 -0
  61. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/licenses/LICENSE +0 -0
  62. {claude_mpm-4.5.6.dist-info → claude_mpm-4.5.11.dist-info}/top_level.txt +0 -0
@@ -58,6 +58,11 @@ def add_configure_subparser(subparsers) -> argparse.ArgumentParser:
58
58
  action="store_true",
59
59
  help="Jump directly to behavior file management",
60
60
  )
61
+ nav_group.add_argument(
62
+ "--startup",
63
+ action="store_true",
64
+ help="Configure startup services and agents",
65
+ )
61
66
  nav_group.add_argument(
62
67
  "--version-info",
63
68
  action="store_true",
@@ -1,20 +1,56 @@
1
- """Core components for Claude MPM."""
2
-
3
- from .claude_runner import ClaudeRunner
4
- from .config import Config
5
-
6
- # Import DI components
7
- from .container import DIContainer, ServiceLifetime, get_container
8
- from .factories import (
9
- AgentServiceFactory,
10
- ConfigurationFactory,
11
- ServiceFactory,
12
- SessionManagerFactory,
13
- get_factory_registry,
14
- )
15
- from .injectable_service import InjectableService
16
- from .mixins import LoggerMixin
17
- from .service_registry import ServiceRegistry, get_service_registry, initialize_services
1
+ """Core components for Claude MPM.
2
+
3
+ Lazy imports for all components to avoid loading heavy dependencies
4
+ when only importing lightweight utilities (constants, logging_utils, etc).
5
+ """
6
+
7
+
8
+ # Lazy imports via __getattr__ to prevent loading heavy dependencies
9
+ # when hooks only need lightweight utilities
10
+ def __getattr__(name):
11
+ """Lazy load core components only when accessed using dictionary-based mapping."""
12
+ from importlib import import_module
13
+
14
+ # Dictionary mapping: name -> (module_path, attribute_name)
15
+ _LAZY_IMPORTS = {
16
+ # Core components
17
+ "ClaudeRunner": ("claude_mpm.core.claude_runner", "ClaudeRunner"),
18
+ "Config": ("claude_mpm.core.config", "Config"),
19
+ # Dependency injection
20
+ "DIContainer": ("claude_mpm.core.container", "DIContainer"),
21
+ "ServiceLifetime": ("claude_mpm.core.container", "ServiceLifetime"),
22
+ "get_container": ("claude_mpm.core.container", "get_container"),
23
+ # Factories
24
+ "AgentServiceFactory": ("claude_mpm.core.factories", "AgentServiceFactory"),
25
+ "ConfigurationFactory": ("claude_mpm.core.factories", "ConfigurationFactory"),
26
+ "ServiceFactory": ("claude_mpm.core.factories", "ServiceFactory"),
27
+ "SessionManagerFactory": ("claude_mpm.core.factories", "SessionManagerFactory"),
28
+ "get_factory_registry": ("claude_mpm.core.factories", "get_factory_registry"),
29
+ # Services and utilities
30
+ "InjectableService": (
31
+ "claude_mpm.core.injectable_service",
32
+ "InjectableService",
33
+ ),
34
+ "LoggerMixin": ("claude_mpm.core.mixins", "LoggerMixin"),
35
+ # Service registry
36
+ "ServiceRegistry": ("claude_mpm.core.service_registry", "ServiceRegistry"),
37
+ "get_service_registry": (
38
+ "claude_mpm.core.service_registry",
39
+ "get_service_registry",
40
+ ),
41
+ "initialize_services": (
42
+ "claude_mpm.core.service_registry",
43
+ "initialize_services",
44
+ ),
45
+ }
46
+
47
+ if name in _LAZY_IMPORTS:
48
+ module_path, attr_name = _LAZY_IMPORTS[name]
49
+ module = import_module(module_path)
50
+ return getattr(module, attr_name)
51
+
52
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
53
+
18
54
 
19
55
  __all__ = [
20
56
  "AgentServiceFactory",
claude_mpm/core/config.py CHANGED
@@ -201,7 +201,7 @@ class Config:
201
201
  # Set flag IMMEDIATELY before logging to prevent any possibility of duplicate
202
202
  # messages. No lock needed here since we're already inside __init__ lock
203
203
  Config._success_logged = True
204
- logger.info(
204
+ logger.debug(
205
205
  f"✓ Successfully loaded configuration from {file_path}"
206
206
  )
207
207
  else:
@@ -122,6 +122,13 @@ class LogManager:
122
122
  if run_cleanup_on_startup is None:
123
123
  return # Cleanup utility not available
124
124
 
125
+ # Check environment variable to skip cleanup (for configure command)
126
+ import os
127
+
128
+ if os.environ.get("CLAUDE_MPM_SKIP_CLEANUP", "0") == "1":
129
+ logger.debug("Startup cleanup skipped (CLAUDE_MPM_SKIP_CLEANUP=1)")
130
+ return
131
+
125
132
  try:
126
133
  # Get cleanup configuration
127
134
  cleanup_config = self.config.get("log_cleanup", {})
@@ -10,28 +10,27 @@ import os
10
10
  import re
11
11
  import sys
12
12
  from datetime import datetime, timezone
13
- from typing import Optional
13
+ from typing import Any, Optional
14
14
 
15
15
  # Debug mode
16
16
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
17
17
 
18
18
  # Response tracking integration
19
- RESPONSE_TRACKING_AVAILABLE = False
20
- try:
21
- from claude_mpm.services.response_tracker import ResponseTracker
22
-
23
- RESPONSE_TRACKING_AVAILABLE = True
24
- except Exception as e:
25
- if DEBUG:
26
- print(f"Response tracking not available: {e}", file=sys.stderr)
27
- RESPONSE_TRACKING_AVAILABLE = False
19
+ # NOTE: ResponseTracker import moved to _initialize_response_tracking() for lazy loading
20
+ # This prevents unnecessary import of base_agent_loader and other heavy dependencies
21
+ # when hooks don't need response tracking
22
+ RESPONSE_TRACKING_AVAILABLE = (
23
+ True # Assume available, will check on actual initialization
24
+ )
28
25
 
29
26
 
30
27
  class ResponseTrackingManager:
31
28
  """Manager for response tracking functionality."""
32
29
 
33
30
  def __init__(self):
34
- self.response_tracker: Optional[ResponseTracker] = None
31
+ self.response_tracker: Optional[Any] = (
32
+ None # Type hint changed to Any for lazy import
33
+ )
35
34
  self.response_tracking_enabled = False
36
35
  self.track_all_interactions = (
37
36
  False # Track all Claude interactions, not just delegations
@@ -49,8 +48,14 @@ class ResponseTrackingManager:
49
48
 
50
49
  DESIGN DECISION: Check configuration to allow enabling/disabling
51
50
  response tracking without code changes.
51
+
52
+ NOTE: ResponseTracker is imported lazily here to avoid loading
53
+ base_agent_loader and other heavy dependencies unless actually needed.
52
54
  """
53
55
  try:
56
+ # Lazy import of ResponseTracker to avoid unnecessary dependency loading
57
+ from claude_mpm.services.response_tracker import ResponseTracker
58
+
54
59
  # Create configuration with optional config file using ConfigLoader
55
60
  config_file = os.environ.get("CLAUDE_PM_CONFIG_FILE")
56
61
  from claude_mpm.core.shared.config_loader import ConfigLoader, ConfigPattern
@@ -26,14 +26,8 @@ except ImportError:
26
26
  REQUESTS_AVAILABLE = False
27
27
  requests = None
28
28
 
29
- # Import high-performance event emitter
30
- try:
31
- from claude_mpm.services.monitor.event_emitter import get_event_emitter
32
-
33
- EVENT_EMITTER_AVAILABLE = True
34
- except ImportError:
35
- EVENT_EMITTER_AVAILABLE = False
36
- get_event_emitter = None
29
+ # Import high-performance event emitter - lazy loaded in _async_emit()
30
+ # to reduce hook handler initialization time by ~85% (792ms -> minimal)
37
31
 
38
32
  # Import EventNormalizer for consistent event formatting
39
33
  try:
@@ -137,9 +131,6 @@ class ConnectionManagerService:
137
131
 
138
132
  def _try_async_emit(self, namespace: str, event: str, data: dict) -> bool:
139
133
  """Try to emit event using high-performance async emitter."""
140
- if not EVENT_EMITTER_AVAILABLE:
141
- return False
142
-
143
134
  try:
144
135
  # Run async emission in the current event loop or create one
145
136
  loop = None
@@ -170,8 +161,15 @@ class ConnectionManagerService:
170
161
  async def _async_emit(self, namespace: str, event: str, data: dict) -> bool:
171
162
  """Async helper for event emission."""
172
163
  try:
164
+ # Lazy load event emitter to reduce initialization overhead
165
+ from claude_mpm.services.monitor.event_emitter import get_event_emitter
166
+
173
167
  emitter = await get_event_emitter()
174
168
  return await emitter.emit_event(namespace, "claude_event", data)
169
+ except ImportError:
170
+ if DEBUG:
171
+ print("⚠️ Event emitter not available", file=sys.stderr)
172
+ return False
175
173
  except Exception as e:
176
174
  if DEBUG:
177
175
  print(f"⚠️ Async emitter error: {e}", file=sys.stderr)
@@ -13,169 +13,152 @@ New structure:
13
13
 
14
14
 
15
15
  # Use lazy imports to prevent circular dependency issues
16
- def __getattr__(name): # noqa: PLR0911
17
- """Lazy import to prevent circular dependencies."""
18
- if name == "TicketManager":
19
- from .ticket_manager import TicketManager
20
-
21
- return TicketManager
22
- if name == "AgentDeploymentService":
23
- # Use correct path
24
- from .agents.deployment import AgentDeploymentService
25
-
26
- return AgentDeploymentService
27
- if name == "AgentMemoryManager":
28
- from .agents.memory import AgentMemoryManager
29
-
30
- return AgentMemoryManager
31
- if name == "get_memory_manager":
32
- from .agents.memory import get_memory_manager
33
-
34
- return get_memory_manager
35
- # Add backward compatibility for other agent services
36
- if name == "AgentRegistry":
37
- # Use correct path
38
- from .agents.registry import AgentRegistry
39
-
40
- return AgentRegistry
41
- if name == "AgentLifecycleManager":
42
- from .agents.deployment import AgentLifecycleManager
43
-
44
- return AgentLifecycleManager
45
- if name == "AgentManager":
46
- from .agents.management import AgentManager
47
-
48
- return AgentManager
49
- if name == "AgentCapabilitiesGenerator":
50
- from .agents.management import AgentCapabilitiesGenerator
51
-
52
- return AgentCapabilitiesGenerator
53
- if name == "AgentModificationTracker":
54
- from .agents.registry import AgentModificationTracker
55
-
56
- return AgentModificationTracker
57
- if name == "AgentPersistenceService":
58
- from .agents.memory import AgentPersistenceService
59
-
60
- return AgentPersistenceService
61
- if name == "AgentProfileLoader":
62
- from .agents.loading import AgentProfileLoader
63
-
64
- return AgentProfileLoader
65
- if name == "AgentVersionManager":
66
- from .agents.deployment import AgentVersionManager
67
-
68
- return AgentVersionManager
69
- if name == "BaseAgentManager":
70
- from .agents.loading import BaseAgentManager
71
-
72
- return BaseAgentManager
73
- if name == "DeployedAgentDiscovery":
74
- from .agents.registry import DeployedAgentDiscovery
75
-
76
- return DeployedAgentDiscovery
77
- if name == "FrameworkAgentLoader":
78
- from .agents.loading import FrameworkAgentLoader
79
-
80
- return FrameworkAgentLoader
81
- if name == "HookService":
82
- from .hook_service import HookService
83
-
84
- return HookService
85
- if name == "ProjectAnalyzer":
86
- from .project.analyzer import ProjectAnalyzer
87
-
88
- return ProjectAnalyzer
89
- if name == "AdvancedHealthMonitor":
90
- from .infrastructure.monitoring import AdvancedHealthMonitor
91
-
92
- return AdvancedHealthMonitor
93
- if name == "HealthMonitor":
94
- # For backward compatibility, return AdvancedHealthMonitor
95
- # Note: There's also a different HealthMonitor in infrastructure.health_monitor
96
- from .infrastructure.monitoring import AdvancedHealthMonitor
97
-
98
- return AdvancedHealthMonitor
16
+ def __getattr__(name):
17
+ """Lazy import to prevent circular dependencies using dictionary-based mapping."""
18
+ from importlib import import_module
19
+
20
+ # Dictionary mapping: name -> (module_path, attribute_name)
21
+ # For agent services, we import from the __init__.py modules to respect their import structure
22
+ _LAZY_IMPORTS = {
23
+ # Agent services - use __init__.py modules (not direct file paths) to respect import structure
24
+ "AgentDeploymentService": (
25
+ "claude_mpm.services.agents.deployment",
26
+ "AgentDeploymentService",
27
+ ),
28
+ "AgentMemoryManager": (
29
+ "claude_mpm.services.agents.memory",
30
+ "AgentMemoryManager",
31
+ ),
32
+ "get_memory_manager": (
33
+ "claude_mpm.services.agents.memory",
34
+ "get_memory_manager",
35
+ ),
36
+ "AgentRegistry": ("claude_mpm.services.agents.registry", "AgentRegistry"),
37
+ "AgentLifecycleManager": (
38
+ "claude_mpm.services.agents.deployment",
39
+ "AgentLifecycleManager",
40
+ ),
41
+ "AgentManager": ("claude_mpm.services.agents.management", "AgentManager"),
42
+ "AgentCapabilitiesGenerator": (
43
+ "claude_mpm.services.agents.management",
44
+ "AgentCapabilitiesGenerator",
45
+ ),
46
+ "AgentModificationTracker": (
47
+ "claude_mpm.services.agents.registry",
48
+ "AgentModificationTracker",
49
+ ),
50
+ "AgentPersistenceService": (
51
+ "claude_mpm.services.agents.memory",
52
+ "AgentPersistenceService",
53
+ ),
54
+ "AgentProfileLoader": (
55
+ "claude_mpm.services.agents.loading",
56
+ "AgentProfileLoader",
57
+ ),
58
+ "AgentVersionManager": (
59
+ "claude_mpm.services.agents.deployment",
60
+ "AgentVersionManager",
61
+ ),
62
+ "BaseAgentManager": ("claude_mpm.services.agents.loading", "BaseAgentManager"),
63
+ "DeployedAgentDiscovery": (
64
+ "claude_mpm.services.agents.registry",
65
+ "DeployedAgentDiscovery",
66
+ ),
67
+ "FrameworkAgentLoader": (
68
+ "claude_mpm.services.agents.loading",
69
+ "FrameworkAgentLoader",
70
+ ),
71
+ "AgentManagementService": (
72
+ "claude_mpm.services.agents.management",
73
+ "AgentManager",
74
+ ),
75
+ # Infrastructure services
76
+ "HookService": ("claude_mpm.services.hook_service", "HookService"),
77
+ "ProjectAnalyzer": ("claude_mpm.services.project.analyzer", "ProjectAnalyzer"),
78
+ "AdvancedHealthMonitor": (
79
+ "claude_mpm.services.infrastructure.monitoring",
80
+ "AdvancedHealthMonitor",
81
+ ),
82
+ "HealthMonitor": (
83
+ "claude_mpm.services.infrastructure.monitoring",
84
+ "AdvancedHealthMonitor",
85
+ ),
86
+ "LoggingService": (
87
+ "claude_mpm.services.infrastructure.logging",
88
+ "LoggingService",
89
+ ),
90
+ # Communication services
91
+ "StandaloneSocketIOServer": (
92
+ "claude_mpm.services.socketio_server",
93
+ "SocketIOServer",
94
+ ),
95
+ "SocketIOServer": ("claude_mpm.services.socketio_server", "SocketIOServer"),
96
+ "SocketIOClientManager": (
97
+ "claude_mpm.services.socketio_client_manager",
98
+ "SocketIOClientManager",
99
+ ),
100
+ # Memory services
101
+ "MemoryBuilder": ("claude_mpm.services.memory.builder", "MemoryBuilder"),
102
+ "MemoryRouter": ("claude_mpm.services.memory.router", "MemoryRouter"),
103
+ "MemoryOptimizer": ("claude_mpm.services.memory.optimizer", "MemoryOptimizer"),
104
+ "SimpleCacheService": (
105
+ "claude_mpm.services.memory.cache.simple_cache",
106
+ "SimpleCacheService",
107
+ ),
108
+ "SharedPromptCache": (
109
+ "claude_mpm.services.memory.cache.shared_prompt_cache",
110
+ "SharedPromptCache",
111
+ ),
112
+ # Project services
113
+ "ProjectRegistry": ("claude_mpm.services.project.registry", "ProjectRegistry"),
114
+ # MCP Gateway services
115
+ "MCPConfiguration": (
116
+ "claude_mpm.services.mcp_gateway.config.configuration",
117
+ "MCPConfiguration",
118
+ ),
119
+ "MCPConfigLoader": (
120
+ "claude_mpm.services.mcp_gateway.config.config_loader",
121
+ "MCPConfigLoader",
122
+ ),
123
+ "MCPServer": ("claude_mpm.services.mcp_gateway.server.mcp_server", "MCPServer"),
124
+ "MCPToolRegistry": (
125
+ "claude_mpm.services.mcp_gateway.tools.tool_registry",
126
+ "MCPToolRegistry",
127
+ ),
128
+ "BaseMCPService": (
129
+ "claude_mpm.services.mcp_gateway.core.base",
130
+ "BaseMCPService",
131
+ ),
132
+ # Other services
133
+ "TicketManager": ("claude_mpm.services.ticket_manager", "TicketManager"),
134
+ }
135
+
136
+ # Handle direct mappings
137
+ if name in _LAZY_IMPORTS:
138
+ module_path, attr_name = _LAZY_IMPORTS[name]
139
+ module = import_module(module_path)
140
+ return getattr(module, attr_name)
141
+
142
+ # Handle RecoveryManager with special error handling
99
143
  if name == "RecoveryManager":
100
144
  try:
101
- from .recovery_manager import RecoveryManager
102
-
103
- return RecoveryManager
145
+ module = import_module("claude_mpm.services.recovery_manager")
146
+ return module.RecoveryManager
104
147
  except ImportError:
105
148
  raise AttributeError(f"Recovery management not available: {name}")
106
- elif name in {"StandaloneSocketIOServer", "SocketIOServer"}:
107
- from .socketio_server import SocketIOServer
108
-
109
- return SocketIOServer
110
- # Backward compatibility for memory services
111
- elif name == "MemoryBuilder":
112
- from .memory.builder import MemoryBuilder
113
-
114
- return MemoryBuilder
115
- elif name == "MemoryRouter":
116
- from .memory.router import MemoryRouter
117
-
118
- return MemoryRouter
119
- elif name == "MemoryOptimizer":
120
- from .memory.optimizer import MemoryOptimizer
121
-
122
- return MemoryOptimizer
123
- elif name == "SimpleCacheService":
124
- from .memory.cache.simple_cache import SimpleCacheService
125
-
126
- return SimpleCacheService
127
- elif name == "SharedPromptCache":
128
- from .memory.cache.shared_prompt_cache import SharedPromptCache
129
-
130
- return SharedPromptCache
131
- # New service organization imports
132
- elif name == "AgentManagementService":
133
- from .agents.management import AgentManager
134
-
135
- return AgentManager
136
- elif name == "ProjectRegistry":
137
- from .project.registry import ProjectRegistry
138
149
 
139
- return ProjectRegistry
140
- elif name == "LoggingService":
141
- from .infrastructure.logging import LoggingService
150
+ # Handle MCP interfaces (names starting with "IMCP")
151
+ if name.startswith("IMCP"):
152
+ module = import_module("claude_mpm.services.mcp_gateway.core.interfaces")
153
+ return getattr(module, name)
142
154
 
143
- return LoggingService
144
- elif name == "SocketIOClientManager":
145
- from .socketio_client_manager import SocketIOClientManager
155
+ # Handle MCP exceptions (names starting with "MCP" and containing "Error")
156
+ if name.startswith("MCP") and "Error" in name:
157
+ module = import_module("claude_mpm.services.mcp_gateway.core.exceptions")
158
+ return getattr(module, name)
146
159
 
147
- return SocketIOClientManager
148
- # MCP Gateway services
149
- elif name == "MCPConfiguration":
150
- from .mcp_gateway.config.configuration import MCPConfiguration
151
-
152
- return MCPConfiguration
153
- elif name == "MCPConfigLoader":
154
- from .mcp_gateway.config.config_loader import MCPConfigLoader
155
-
156
- return MCPConfigLoader
157
- elif name == "MCPServer":
158
- from .mcp_gateway.server.mcp_server import MCPServer
159
-
160
- return MCPServer
161
- elif name == "MCPToolRegistry":
162
- from .mcp_gateway.tools.tool_registry import MCPToolRegistry
163
-
164
- return MCPToolRegistry
165
- elif name == "BaseMCPService":
166
- from .mcp_gateway.core.base import BaseMCPService
167
-
168
- return BaseMCPService
169
- elif name.startswith("IMCP"):
170
- from .mcp_gateway.core import interfaces
171
-
172
- return getattr(interfaces, name)
173
- elif name.startswith("MCP") and "Error" in name:
174
- from .mcp_gateway.core import exceptions
175
-
176
- return getattr(exceptions, name)
177
- # Core interfaces and base classes
178
- elif name.startswith("I") or name in [
160
+ # Handle core interfaces and base classes
161
+ if name.startswith("I") or name in [
179
162
  "BaseService",
180
163
  "SyncBaseService",
181
164
  "SingletonService",
@@ -183,6 +166,7 @@ def __getattr__(name): # noqa: PLR0911
183
166
  from . import core
184
167
 
185
168
  return getattr(core, name)
169
+
186
170
  raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
187
171
 
188
172
 
@@ -112,8 +112,29 @@ class DeploymentConfigLoader:
112
112
  Returns:
113
113
  True if the agent should be deployed, False otherwise
114
114
  """
115
+ if config is None:
116
+ config = Config()
117
+
115
118
  settings = self.get_deployment_settings(config)
116
119
 
120
+ # Check startup configuration for system agents
121
+ if agent_source == "system":
122
+ # Check startup configuration first
123
+ startup_enabled = config.get("startup.enabled_agents", [])
124
+ if startup_enabled:
125
+ # Normalize for comparison
126
+ check_id = agent_id if settings["case_sensitive"] else agent_id.lower()
127
+ startup_list = (
128
+ startup_enabled
129
+ if settings["case_sensitive"]
130
+ else [a.lower() for a in startup_enabled]
131
+ )
132
+ if check_id not in startup_list:
133
+ self.logger.debug(
134
+ f"Skipping system agent {agent_id} - not in startup enabled list"
135
+ )
136
+ return False
137
+
117
138
  # Check if the source type is enabled
118
139
  if agent_source == "system" and not settings["deploy_system_agents"]:
119
140
  self.logger.debug(
@@ -13,7 +13,9 @@ from enum import Enum
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, List, Optional
15
15
 
16
- from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
16
+ # Lazy import for base_agent_loader to reduce initialization overhead
17
+ # base_agent_loader adds ~500ms to import time
18
+ # from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
17
19
  from claude_mpm.core.logging_utils import get_logger
18
20
  from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
19
21
  from claude_mpm.services.shared import ConfigServiceBase
@@ -21,6 +23,13 @@ from claude_mpm.services.shared import ConfigServiceBase
21
23
  logger = get_logger(__name__)
22
24
 
23
25
 
26
+ def _get_clear_base_agent_cache():
27
+ """Lazy loader for clear_base_agent_cache function."""
28
+ from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
29
+
30
+ return clear_base_agent_cache
31
+
32
+
24
33
  class BaseAgentSection(str, Enum):
25
34
  """Base agent markdown sections."""
26
35
 
@@ -134,7 +143,8 @@ class BaseAgentManager(ConfigServiceBase):
134
143
  content = self._structure_to_markdown(current)
135
144
  self.base_agent_path.write_text(content, encoding="utf-8")
136
145
 
137
- # Clear caches
146
+ # Clear caches (lazy load to avoid import overhead)
147
+ clear_base_agent_cache = _get_clear_base_agent_cache()
138
148
  clear_base_agent_cache()
139
149
  self.cache.invalidate("base_agent:instructions")
140
150