claude-mpm 4.3.12__py3-none-any.whl → 4.3.13__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 (199) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/cli/commands/agent_manager.py +3 -3
  5. claude_mpm/cli/commands/agents.py +2 -2
  6. claude_mpm/cli/commands/aggregate.py +1 -1
  7. claude_mpm/cli/commands/config.py +2 -2
  8. claude_mpm/cli/commands/configure.py +5 -5
  9. claude_mpm/cli/commands/configure_tui.py +7 -7
  10. claude_mpm/cli/commands/dashboard.py +1 -1
  11. claude_mpm/cli/commands/debug.py +5 -5
  12. claude_mpm/cli/commands/mcp.py +1 -1
  13. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  14. claude_mpm/cli/commands/mcp_config.py +7 -10
  15. claude_mpm/cli/commands/mcp_external_commands.py +40 -32
  16. claude_mpm/cli/commands/mcp_install_commands.py +38 -10
  17. claude_mpm/cli/commands/mcp_setup_external.py +143 -102
  18. claude_mpm/cli/commands/monitor.py +2 -2
  19. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  20. claude_mpm/cli/commands/run.py +46 -2
  21. claude_mpm/cli/commands/search.py +41 -34
  22. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  23. claude_mpm/cli/parsers/mcp_parser.py +1 -3
  24. claude_mpm/cli/parsers/search_parser.py +10 -4
  25. claude_mpm/cli/startup_logging.py +3 -5
  26. claude_mpm/cli/utils.py +1 -1
  27. claude_mpm/core/agent_registry.py +12 -8
  28. claude_mpm/core/agent_session_manager.py +8 -8
  29. claude_mpm/core/api_validator.py +4 -4
  30. claude_mpm/core/base_service.py +10 -10
  31. claude_mpm/core/cache.py +5 -5
  32. claude_mpm/core/config_constants.py +1 -1
  33. claude_mpm/core/container.py +1 -1
  34. claude_mpm/core/error_handler.py +2 -2
  35. claude_mpm/core/file_utils.py +1 -1
  36. claude_mpm/core/framework_loader.py +3 -3
  37. claude_mpm/core/hook_manager.py +8 -6
  38. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  39. claude_mpm/core/interactive_session.py +1 -1
  40. claude_mpm/core/lazy.py +3 -3
  41. claude_mpm/core/log_manager.py +16 -12
  42. claude_mpm/core/logger.py +16 -11
  43. claude_mpm/core/logging_config.py +4 -2
  44. claude_mpm/core/oneshot_session.py +1 -1
  45. claude_mpm/core/optimized_agent_loader.py +6 -6
  46. claude_mpm/core/output_style_manager.py +1 -1
  47. claude_mpm/core/pm_hook_interceptor.py +3 -3
  48. claude_mpm/core/service_registry.py +1 -1
  49. claude_mpm/core/session_manager.py +11 -9
  50. claude_mpm/core/socketio_pool.py +13 -13
  51. claude_mpm/core/types.py +2 -2
  52. claude_mpm/core/unified_agent_registry.py +2 -2
  53. claude_mpm/core/unified_paths.py +1 -1
  54. claude_mpm/dashboard/analysis_runner.py +4 -4
  55. claude_mpm/dashboard/api/simple_directory.py +1 -1
  56. claude_mpm/generators/agent_profile_generator.py +4 -2
  57. claude_mpm/hooks/base_hook.py +2 -2
  58. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  59. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  60. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  61. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  62. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  63. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  64. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  65. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  66. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  67. claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
  68. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  69. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  70. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  71. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  72. claude_mpm/hooks/memory_integration_hook.py +1 -1
  73. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  74. claude_mpm/models/agent_session.py +5 -5
  75. claude_mpm/services/__init__.py +1 -1
  76. claude_mpm/services/agent_capabilities_service.py +1 -1
  77. claude_mpm/services/agents/agent_builder.py +3 -3
  78. claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
  79. claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
  80. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
  81. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  82. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  83. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  84. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  85. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  86. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  87. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  88. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  89. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  90. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  91. claude_mpm/services/agents/local_template_manager.py +6 -6
  92. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  93. claude_mpm/services/agents/memory/content_manager.py +3 -3
  94. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  95. claude_mpm/services/agents/memory/template_generator.py +3 -3
  96. claude_mpm/services/agents/registry/__init__.py +1 -1
  97. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  98. claude_mpm/services/async_session_logger.py +3 -3
  99. claude_mpm/services/claude_session_logger.py +4 -4
  100. claude_mpm/services/cli/agent_listing_service.py +1 -1
  101. claude_mpm/services/cli/agent_validation_service.py +1 -0
  102. claude_mpm/services/cli/memory_crud_service.py +11 -6
  103. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  104. claude_mpm/services/cli/session_manager.py +15 -11
  105. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  106. claude_mpm/services/core/memory_manager.py +81 -23
  107. claude_mpm/services/core/path_resolver.py +2 -2
  108. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  109. claude_mpm/services/event_aggregator.py +4 -2
  110. claude_mpm/services/event_bus/direct_relay.py +5 -3
  111. claude_mpm/services/event_bus/event_bus.py +3 -3
  112. claude_mpm/services/event_bus/relay.py +6 -4
  113. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  114. claude_mpm/services/events/core.py +3 -3
  115. claude_mpm/services/events/producers/hook.py +6 -6
  116. claude_mpm/services/events/producers/system.py +8 -8
  117. claude_mpm/services/exceptions.py +5 -5
  118. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  119. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  120. claude_mpm/services/hook_installer_service.py +1 -1
  121. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  122. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  123. claude_mpm/services/infrastructure/logging.py +2 -2
  124. claude_mpm/services/mcp_config_manager.py +175 -30
  125. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  126. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  127. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  128. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  129. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  130. claude_mpm/services/mcp_gateway/main.py +21 -7
  131. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  132. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  133. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  134. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
  135. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  136. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  137. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
  138. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  139. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  140. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  141. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
  142. claude_mpm/services/memory/builder.py +7 -5
  143. claude_mpm/services/memory/indexed_memory.py +4 -4
  144. claude_mpm/services/memory/optimizer.py +6 -6
  145. claude_mpm/services/memory/router.py +3 -3
  146. claude_mpm/services/monitor/daemon.py +1 -1
  147. claude_mpm/services/monitor/daemon_manager.py +6 -6
  148. claude_mpm/services/monitor/event_emitter.py +2 -2
  149. claude_mpm/services/monitor/handlers/file.py +1 -1
  150. claude_mpm/services/monitor/management/lifecycle.py +1 -1
  151. claude_mpm/services/monitor/server.py +4 -4
  152. claude_mpm/services/monitor_build_service.py +2 -2
  153. claude_mpm/services/port_manager.py +2 -2
  154. claude_mpm/services/response_tracker.py +2 -2
  155. claude_mpm/services/session_management_service.py +3 -2
  156. claude_mpm/services/socketio/client_proxy.py +2 -2
  157. claude_mpm/services/socketio/dashboard_server.py +4 -3
  158. claude_mpm/services/socketio/event_normalizer.py +12 -8
  159. claude_mpm/services/socketio/handlers/base.py +2 -2
  160. claude_mpm/services/socketio/handlers/connection.py +10 -10
  161. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  162. claude_mpm/services/socketio/handlers/file.py +1 -1
  163. claude_mpm/services/socketio/handlers/git.py +1 -1
  164. claude_mpm/services/socketio/handlers/hook.py +16 -15
  165. claude_mpm/services/socketio/migration_utils.py +1 -1
  166. claude_mpm/services/socketio/monitor_client.py +5 -5
  167. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  168. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  169. claude_mpm/services/socketio/server/core.py +7 -5
  170. claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
  171. claude_mpm/services/socketio/server/main.py +13 -13
  172. claude_mpm/services/socketio_client_manager.py +4 -4
  173. claude_mpm/services/system_instructions_service.py +2 -2
  174. claude_mpm/services/ticket_services/validation_service.py +1 -1
  175. claude_mpm/services/utility_service.py +5 -2
  176. claude_mpm/services/version_control/branch_strategy.py +2 -2
  177. claude_mpm/services/version_control/git_operations.py +22 -20
  178. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  179. claude_mpm/services/version_control/version_parser.py +7 -5
  180. claude_mpm/services/visualization/mermaid_generator.py +1 -1
  181. claude_mpm/storage/state_storage.py +1 -1
  182. claude_mpm/tools/code_tree_analyzer.py +19 -18
  183. claude_mpm/tools/code_tree_builder.py +2 -2
  184. claude_mpm/tools/code_tree_events.py +10 -8
  185. claude_mpm/tools/socketio_debug.py +3 -3
  186. claude_mpm/utils/agent_dependency_loader.py +2 -2
  187. claude_mpm/utils/dependency_strategies.py +8 -3
  188. claude_mpm/utils/environment_context.py +2 -2
  189. claude_mpm/utils/error_handler.py +2 -2
  190. claude_mpm/utils/file_utils.py +1 -1
  191. claude_mpm/utils/imports.py +1 -1
  192. claude_mpm/utils/log_cleanup.py +21 -7
  193. claude_mpm/validation/agent_validator.py +2 -2
  194. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +1 -1
  195. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +199 -199
  196. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
  197. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
  198. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
  199. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
@@ -138,7 +138,7 @@ def summarize_todos(todos: list) -> dict:
138
138
  }
139
139
 
140
140
 
141
- def classify_tool_operation(tool_name: str, tool_input: dict) -> str:
141
+ def classify_tool_operation(tool_name: str, tool_input: dict) -> str: # noqa: PLR0911
142
142
  """Classify the type of operation being performed."""
143
143
  if tool_name in ["Read", "LS", "Glob", "Grep", "NotebookRead"]:
144
144
  return "read"
@@ -155,7 +155,7 @@ def classify_tool_operation(tool_name: str, tool_input: dict) -> str:
155
155
  return "other"
156
156
 
157
157
 
158
- def assess_security_risk(tool_name: str, tool_input: dict) -> str:
158
+ def assess_security_risk(tool_name: str, tool_input: dict) -> str: # noqa: PLR0911
159
159
  """Assess the security risk level of the tool operation."""
160
160
  if tool_name == "Bash":
161
161
  command = tool_input.get("command", "").lower()
@@ -234,7 +234,7 @@ class MemoryPostDelegationHook(PostDelegationHook):
234
234
  "context": "context", # Current Technical Context
235
235
  }
236
236
 
237
- def execute(self, context: HookContext) -> HookResult:
237
+ def execute(self, context: HookContext) -> HookResult: # noqa: PLR0911
238
238
  """Extract and store learnings from delegation result.
239
239
 
240
240
  WHY: Capturing learnings immediately after task completion ensures we
@@ -2,7 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  from collections import defaultdict
5
- from datetime import datetime
5
+ from datetime import datetime, timezone
6
6
  from typing import Any, Dict, List, Optional
7
7
 
8
8
  from claude_mpm.core.logger import get_logger
@@ -105,7 +105,7 @@ class ToolCallInterceptor:
105
105
  "parameters": parameters.copy(), # Copy to avoid modifying original
106
106
  },
107
107
  metadata=metadata or {},
108
- timestamp=datetime.now(),
108
+ timestamp=datetime.now(timezone.utc),
109
109
  )
110
110
 
111
111
  # Run hooks
@@ -13,7 +13,7 @@ chronological order for session replay and analysis.
13
13
 
14
14
  import json
15
15
  from dataclasses import asdict, dataclass, field
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from enum import Enum
18
18
  from typing import Any, Dict, List, Optional, Set
19
19
 
@@ -204,7 +204,7 @@ class AgentSession:
204
204
  and metric updates.
205
205
  """
206
206
  if timestamp is None:
207
- timestamp = datetime.utcnow().isoformat() + "Z"
207
+ timestamp = datetime.now(timezone.utc).isoformat() + "Z"
208
208
 
209
209
  # Categorize the event
210
210
  category = self._categorize_event(event_type, data)
@@ -232,7 +232,7 @@ class AgentSession:
232
232
 
233
233
  return event
234
234
 
235
- def _categorize_event(self, event_type: str, data: Dict[str, Any]) -> EventCategory:
235
+ def _categorize_event(self, event_type: str, data: Dict[str, Any]) -> EventCategory: # noqa: PLR0911
236
236
  """Categorize an event based on its type and data.
237
237
 
238
238
  WHY: Categories help with filtering and analysis of related events.
@@ -338,7 +338,7 @@ class AgentSession:
338
338
  event.timestamp.replace("Z", "+00:00")
339
339
  )
340
340
  tool_op.duration_ms = int((end - start).total_seconds() * 1000)
341
- except:
341
+ except Exception:
342
342
  pass
343
343
 
344
344
  event.correlation_id = corr_id
@@ -393,7 +393,7 @@ class AgentSession:
393
393
  self.metrics.session_duration_ms = int(
394
394
  (end - start).total_seconds() * 1000
395
395
  )
396
- except:
396
+ except Exception:
397
397
  pass
398
398
 
399
399
  # Finalize any pending delegations
@@ -13,7 +13,7 @@ New structure:
13
13
 
14
14
 
15
15
  # Use lazy imports to prevent circular dependency issues
16
- def __getattr__(name):
16
+ def __getattr__(name): # noqa: PLR0911
17
17
  """Lazy import to prevent circular dependencies."""
18
18
  if name == "TicketManager":
19
19
  from .ticket_manager import TicketManager
@@ -215,7 +215,7 @@ class AgentCapabilitiesService(BaseService, AgentCapabilitiesInterface):
215
215
  self.logger.debug(f"Could not parse agent {agent_file}: {e}")
216
216
  continue
217
217
 
218
- def _categorize_agent(self, agent_id: str, content: str) -> str:
218
+ def _categorize_agent(self, agent_id: str, content: str) -> str: # noqa: PLR0911
219
219
  """Categorize an agent based on its ID and content."""
220
220
  agent_id_lower = agent_id.lower()
221
221
  content_lower = content.lower()
@@ -10,7 +10,7 @@ This service provides comprehensive agent lifecycle management including:
10
10
 
11
11
  import json
12
12
  import re
13
- from datetime import datetime
13
+ from datetime import datetime, timezone
14
14
  from pathlib import Path
15
15
  from typing import Any, Dict, List, Optional, Tuple
16
16
 
@@ -108,7 +108,7 @@ class AgentBuilderService:
108
108
  agent_metadata = {
109
109
  "description": description,
110
110
  "version": "1.0.0",
111
- "created": datetime.now().isoformat(),
111
+ "created": datetime.now(timezone.utc).isoformat(),
112
112
  "author": "Agent Manager",
113
113
  "category": "custom",
114
114
  }
@@ -179,7 +179,7 @@ class AgentBuilderService:
179
179
  {
180
180
  "base_agent": base_agent_id,
181
181
  "variant": True,
182
- "variant_created": datetime.now().isoformat(),
182
+ "variant_created": datetime.now(timezone.utc).isoformat(),
183
183
  }
184
184
  )
185
185
 
@@ -799,7 +799,8 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
799
799
  if filtered_agents and comparison_results.get("version_upgrades"):
800
800
  # Filter upgrades to only those actually being deployed
801
801
  deployed_upgrades = [
802
- upgrade for upgrade in comparison_results["version_upgrades"]
802
+ upgrade
803
+ for upgrade in comparison_results["version_upgrades"]
803
804
  if upgrade["name"] in filtered_agents
804
805
  ]
805
806
 
@@ -219,7 +219,9 @@ class AgentDiscoveryService:
219
219
  # Handle capabilities as either dict or list
220
220
  if isinstance(capabilities, list):
221
221
  # If capabilities is a list (like in php-engineer.json), treat it as capabilities list
222
- tools_list = template_data.get("tools", []) # Look for tools at root level
222
+ tools_list = template_data.get(
223
+ "tools", []
224
+ ) # Look for tools at root level
223
225
  model_value = template_data.get("model", "sonnet")
224
226
  else:
225
227
  # If capabilities is a dict, extract tools and model from it
@@ -228,9 +230,13 @@ class AgentDiscoveryService:
228
230
 
229
231
  agent_info = {
230
232
  "name": metadata.get("name", template_file.stem),
231
- "description": metadata.get("description", template_data.get("description", "No description available")),
233
+ "description": metadata.get(
234
+ "description",
235
+ template_data.get("description", "No description available"),
236
+ ),
232
237
  "type": template_data.get(
233
- "agent_type", metadata.get("category", template_data.get("category", "agent"))
238
+ "agent_type",
239
+ metadata.get("category", template_data.get("category", "agent")),
234
240
  ), # Extract agent type
235
241
  "version": template_data.get(
236
242
  "agent_version",
@@ -183,9 +183,11 @@ class AgentFileSystemManager:
183
183
  try:
184
184
  # Generate backup directory name if not provided
185
185
  if not backup_dir:
186
- import datetime
186
+ from datetime import datetime, timezone
187
187
 
188
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
188
+ timestamp = datetime.now(timezone.utc).strftime(
189
+ "%Y%m%d_%H%M%S"
190
+ )
189
191
  backup_dir = agents_dir.parent / f"agents_backup_{timestamp}"
190
192
 
191
193
  # Create backup
@@ -324,7 +326,7 @@ class AgentFileSystemManager:
324
326
 
325
327
  def _convert_yaml_to_markdown(self, yaml_content: str, agent_name: str) -> str:
326
328
  """Convert YAML agent content to Markdown format with frontmatter."""
327
- from datetime import datetime
329
+ from datetime import datetime, timezone
328
330
 
329
331
  # Extract YAML fields (simplified parsing)
330
332
  name = self._extract_yaml_field(yaml_content, "name") or agent_name
@@ -356,8 +358,8 @@ name: {name}
356
358
  description: "{description}"
357
359
  version: "{version}"
358
360
  author: "claude-mpm@anthropic.com"
359
- created: "{datetime.now().isoformat()}Z"
360
- updated: "{datetime.now().isoformat()}Z"
361
+ created: "{datetime.now(timezone.utc).isoformat()}Z"
362
+ updated: "{datetime.now(timezone.utc).isoformat()}Z"
361
363
  tags: ["{agent_name}", "mpm-framework"]
362
364
  tools: {tools_list}
363
365
  model: "sonnet"
@@ -32,6 +32,7 @@ Created for ISS-0118: Agent Registry and Hierarchical Discovery System
32
32
 
33
33
  import asyncio
34
34
  import time
35
+ from datetime import datetime, timezone
35
36
  from pathlib import Path
36
37
  from typing import Any, Dict, List, Optional
37
38
 
@@ -52,6 +53,7 @@ from claude_mpm.services.agents.registry.modification_tracker import (
52
53
  ModificationType,
53
54
  )
54
55
  from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
56
+ from claude_mpm.core.unified_paths import get_path_manager
55
57
  from claude_mpm.utils.path_operations import path_ops
56
58
 
57
59
  # Import extracted services
@@ -758,7 +760,7 @@ class AgentLifecycleManager(BaseService):
758
760
  backup_dir = get_path_manager().get_tracking_dir() / "backups"
759
761
  path_ops.ensure_dir(backup_dir)
760
762
 
761
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
763
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
762
764
  backup_filename = f"{agent_name}_deleted_{timestamp}{source_path.suffix}"
763
765
  backup_path = backup_dir / backup_filename
764
766
 
@@ -227,7 +227,7 @@ class AgentMetricsCollector:
227
227
  return "validation_error"
228
228
  return "other_error"
229
229
 
230
- def _extract_agent_type(self, agent_name: str) -> str:
230
+ def _extract_agent_type(self, agent_name: str) -> str: # noqa: PLR0911
231
231
  """
232
232
  Extract agent type from agent name for categorization.
233
233
 
@@ -479,9 +479,9 @@ class AgentOperationService(BaseService):
479
479
  backup_dir = get_path_manager().get_tracking_dir() / "backups"
480
480
  path_ops.ensure_dir(backup_dir)
481
481
 
482
- from datetime import datetime
482
+ from datetime import datetime, timezone
483
483
 
484
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
484
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
485
485
  backup_filename = f"{agent_name}_deleted_{timestamp}{source_path.suffix}"
486
486
  backup_path = backup_dir / backup_filename
487
487
 
@@ -59,9 +59,9 @@ class AgentLifecycleRecord:
59
59
  @property
60
60
  def last_modified_datetime(self):
61
61
  """Get last modified as datetime."""
62
- from datetime import datetime
62
+ from datetime import datetime, timezone
63
63
 
64
- return datetime.fromtimestamp(self.last_modified)
64
+ return datetime.fromtimestamp(self.last_modified, tz=timezone.utc)
65
65
 
66
66
 
67
67
  @dataclass
@@ -230,7 +230,7 @@ class AgentTemplateBuilder:
230
230
  )
231
231
 
232
232
  # Convert tools list to comma-separated string (without spaces for compatibility)
233
- tools_str = ",".join(tools)
233
+ ",".join(tools)
234
234
 
235
235
  # Map model names to Claude Code format (as required)
236
236
  model_map = {
@@ -30,5 +30,5 @@ class AgentVersionManager:
30
30
  for part in parts:
31
31
  int(part)
32
32
  return True
33
- except:
33
+ except Exception:
34
34
  return False
@@ -1,5 +1,6 @@
1
1
  """Temporary wrapper to provide backward compatibility for CLI commands."""
2
2
 
3
+ import contextlib
3
4
  from pathlib import Path
4
5
  from typing import Any, Dict
5
6
 
@@ -101,10 +102,8 @@ class DeploymentServiceWrapper:
101
102
  # Extract frontmatter
102
103
  parts = content.split("---", 2)
103
104
  if len(parts) >= 2:
104
- try:
105
+ with contextlib.suppress(yaml.YAMLError):
105
106
  metadata = yaml.safe_load(parts[1])
106
- except yaml.YAMLError:
107
- pass
108
107
 
109
108
  return {
110
109
  "name": agent_name,
@@ -229,7 +229,7 @@ class AgentProcessingStep(BaseDeploymentStep):
229
229
  cwd = Path.cwd()
230
230
  if str(cwd) in template_str:
231
231
  return "project"
232
- except:
232
+ except Exception:
233
233
  pass
234
234
 
235
235
  # Check if it's a user agent
@@ -24,7 +24,7 @@ import json
24
24
  import logging
25
25
  import os
26
26
  from dataclasses import dataclass, field
27
- from datetime import datetime
27
+ from datetime import datetime, timezone
28
28
  from enum import Enum
29
29
  from pathlib import Path
30
30
  from typing import Any, Dict, List, Optional, Tuple
@@ -227,7 +227,9 @@ class AgentProfileLoader(BaseService):
227
227
  # Check cache first
228
228
  if use_cache and agent_name in self.profile_cache:
229
229
  profile = self.profile_cache[agent_name]
230
- if (datetime.now() - profile.loaded_at).seconds < self.cache_ttl:
230
+ if (
231
+ datetime.now(timezone.utc) - profile.loaded_at
232
+ ).seconds < self.cache_ttl:
231
233
  self.load_metrics[f"{agent_name}_cache_hit"] = (
232
234
  asyncio.get_event_loop().time() - start_time
233
235
  )
@@ -322,7 +324,7 @@ class AgentProfileLoader(BaseService):
322
324
  try:
323
325
  data = yaml.safe_load(content)
324
326
  instructions = data.get("instructions", "")
325
- except:
327
+ except Exception:
326
328
  data = json.loads(content)
327
329
  instructions = data.get("instructions", "")
328
330
 
@@ -9,7 +9,7 @@ Enforces template structure and provides section-specific update methods.
9
9
 
10
10
  import logging
11
11
  from dataclasses import dataclass, field
12
- from datetime import datetime
12
+ from datetime import datetime, timezone
13
13
  from enum import Enum
14
14
  from pathlib import Path
15
15
  from typing import Any, Dict, List, Optional
@@ -358,7 +358,7 @@ class BaseAgentManager(ConfigServiceBase):
358
358
 
359
359
  def _create_backup(self) -> Path:
360
360
  """Create a timestamped backup of base_agent.md."""
361
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
361
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
362
362
  backup_path = self.base_agent_path.parent / f"base_agent_{timestamp}.backup"
363
363
 
364
364
  if self.base_agent_path.exists():
@@ -15,7 +15,7 @@ Key Features:
15
15
 
16
16
  import json
17
17
  from dataclasses import dataclass
18
- from datetime import datetime
18
+ from datetime import datetime, timezone
19
19
  from pathlib import Path
20
20
  from typing import Any, Dict, List, Optional, Tuple, Union
21
21
 
@@ -57,9 +57,9 @@ class LocalAgentTemplate:
57
57
  if self.configuration is None:
58
58
  self.configuration = {}
59
59
  if self.created_at is None:
60
- self.created_at = datetime.now().isoformat()
60
+ self.created_at = datetime.now(timezone.utc).isoformat()
61
61
  if self.updated_at is None:
62
- self.updated_at = datetime.now().isoformat()
62
+ self.updated_at = datetime.now(timezone.utc).isoformat()
63
63
 
64
64
  # Ensure metadata has required fields
65
65
  if "name" not in self.metadata:
@@ -303,7 +303,7 @@ class LocalAgentTemplateManager:
303
303
  target_dir.mkdir(parents=True, exist_ok=True)
304
304
 
305
305
  # Update timestamp
306
- template.updated_at = datetime.now().isoformat()
306
+ template.updated_at = datetime.now(timezone.utc).isoformat()
307
307
 
308
308
  # Save to JSON file
309
309
  template_file = target_dir / f"{template.agent_id}.json"
@@ -455,7 +455,7 @@ class LocalAgentTemplateManager:
455
455
 
456
456
  try:
457
457
  # Create backup directory
458
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
458
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
459
459
  backup_dir = (
460
460
  self.working_directory
461
461
  / ".claude-mpm"
@@ -633,7 +633,7 @@ class LocalAgentTemplateManager:
633
633
 
634
634
  # Update template version
635
635
  template.agent_version = new_version
636
- template.updated_at = datetime.now().isoformat()
636
+ template.updated_at = datetime.now(timezone.utc).isoformat()
637
637
 
638
638
  # Save updated template
639
639
  self.save_local_template(template)
@@ -13,7 +13,7 @@ Uses python-frontmatter and mistune for markdown parsing as recommended.
13
13
 
14
14
  import logging
15
15
  import re
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from typing import Any, Dict, List, Optional
18
18
 
19
19
  import frontmatter
@@ -156,7 +156,7 @@ class AgentManager:
156
156
  # Increment version if requested
157
157
  if increment_version:
158
158
  agent_def.metadata.increment_serial_version()
159
- agent_def.metadata.last_updated = datetime.now()
159
+ agent_def.metadata.last_updated = datetime.now(timezone.utc)
160
160
 
161
161
  # Write back
162
162
  agent_path = self._find_agent_file(name)
@@ -234,7 +234,7 @@ class AgentManager:
234
234
  # Increment version
235
235
  if increment_version:
236
236
  agent_def.metadata.increment_serial_version()
237
- agent_def.metadata.last_updated = datetime.now()
237
+ agent_def.metadata.last_updated = datetime.now(timezone.utc)
238
238
 
239
239
  # Write back
240
240
  return self.update_agent(name, {}, increment_version=False)
@@ -14,7 +14,7 @@ This module provides:
14
14
 
15
15
  import logging
16
16
  import re
17
- from datetime import datetime
17
+ from datetime import datetime, timezone
18
18
  from difflib import SequenceMatcher
19
19
  from typing import Any, Dict, List, Optional, Tuple
20
20
 
@@ -203,7 +203,7 @@ class MemoryContentManager:
203
203
  Returns:
204
204
  str: Content with updated timestamp
205
205
  """
206
- timestamp = datetime.now().isoformat() + "Z"
206
+ timestamp = datetime.now(timezone.utc).isoformat() + "Z"
207
207
  # Handle both old and new timestamp formats
208
208
  content = re.sub(
209
209
  r"<!-- Last Updated: .+? -->",
@@ -260,7 +260,7 @@ class MemoryContentManager:
260
260
 
261
261
  if not has_timestamp:
262
262
  new_lines.append(
263
- f"<!-- Last Updated: {datetime.now().isoformat()}Z -->"
263
+ f"<!-- Last Updated: {datetime.now(timezone.utc).isoformat()}Z -->"
264
264
  )
265
265
  new_lines.append("")
266
266
  else:
@@ -3,7 +3,7 @@
3
3
 
4
4
  import logging
5
5
  import re
6
- from datetime import datetime
6
+ from datetime import datetime, timezone
7
7
  from typing import Dict, List
8
8
 
9
9
 
@@ -26,7 +26,7 @@ class MemoryFormatService:
26
26
  """
27
27
  # Build header
28
28
  header = f"# {agent_id.title()} Agent Memory\n\n"
29
- header += f"Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
29
+ header += f"Last Updated: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}\n\n"
30
30
  header += "## Learnings\n\n"
31
31
 
32
32
  # Build item list
@@ -13,7 +13,7 @@ This module provides:
13
13
  """
14
14
 
15
15
  import logging
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from pathlib import Path
18
18
  from typing import Any, Dict
19
19
 
@@ -58,7 +58,7 @@ class MemoryTemplateGenerator:
58
58
  """
59
59
  # Convert agent_id to proper name, handling cases like "test_agent" -> "Test"
60
60
  agent_id.replace("_agent", "").replace("_", " ").title()
61
- datetime.now().strftime("%Y-%m-%d %H:%M:%S")
61
+ datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
62
62
 
63
63
  # Create a simple template that agents will populate through learning
64
64
  return self._create_basic_memory_template(agent_id, limits)
@@ -75,7 +75,7 @@ class MemoryTemplateGenerator:
75
75
  Returns:
76
76
  str: Basic memory template
77
77
  """
78
- timestamp = datetime.now().isoformat() + "Z"
78
+ timestamp = datetime.now(timezone.utc).isoformat() + "Z"
79
79
 
80
80
  return f"""# Agent Memory: {agent_id}
81
81
  <!-- Last Updated: {timestamp} -->
@@ -4,8 +4,8 @@ from claude_mpm.core.unified_agent_registry import (
4
4
  AgentMetadata,
5
5
  AgentTier,
6
6
  AgentType,
7
- UnifiedAgentRegistry as AgentRegistry,
8
7
  )
8
+ from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
9
9
 
10
10
  from .deployed_agent_discovery import DeployedAgentDiscovery
11
11
  from .modification_tracker import (
@@ -30,7 +30,7 @@ import shutil
30
30
  import time
31
31
  import uuid
32
32
  from dataclasses import asdict, dataclass, field
33
- from datetime import datetime
33
+ from datetime import datetime, timezone
34
34
  from enum import Enum
35
35
  from typing import Any, Callable, Dict, List, Optional, Set, Tuple
36
36
 
@@ -90,7 +90,7 @@ class AgentModification:
90
90
  @property
91
91
  def modification_datetime(self) -> datetime:
92
92
  """Get modification timestamp as datetime."""
93
- return datetime.fromtimestamp(self.timestamp)
93
+ return datetime.fromtimestamp(self.timestamp, tz=timezone.utc)
94
94
 
95
95
  @property
96
96
  def age_seconds(self) -> float:
@@ -22,7 +22,7 @@ import os
22
22
  import sys
23
23
  import time
24
24
  from dataclasses import asdict, dataclass
25
- from datetime import datetime
25
+ from datetime import datetime, timezone
26
26
  from enum import Enum
27
27
  from queue import Full, Queue
28
28
  from threading import Lock, Thread
@@ -184,7 +184,7 @@ class AsyncSessionLogger:
184
184
  return session_id
185
185
 
186
186
  # Generate timestamp-based session ID
187
- session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
187
+ session_id = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
188
188
  logger.info(f"Generated session ID: {session_id}")
189
189
  return session_id
190
190
 
@@ -406,7 +406,7 @@ class AsyncSessionLogger:
406
406
  agent_name = metadata["agent"].replace(" ", "_").lower()
407
407
 
408
408
  # Create timestamp with microsecond precision
409
- now = datetime.now()
409
+ now = datetime.now(timezone.utc)
410
410
  timestamp = now.isoformat()
411
411
  microseconds = now.microsecond
412
412
 
@@ -13,7 +13,7 @@ Configuration via .claude-mpm/configuration.yaml.
13
13
  import json
14
14
  import logging
15
15
  import os
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from typing import Any, Dict, Optional
18
18
 
19
19
  # Import configuration manager
@@ -133,7 +133,7 @@ class ClaudeSessionLogger:
133
133
  # Generate a default based on timestamp if nothing found
134
134
  if not session_id:
135
135
  # Use a timestamp-based session ID as fallback
136
- session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
136
+ session_id = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
137
137
  logger.info(f"No Claude session ID found, using generated: {session_id}")
138
138
  else:
139
139
  logger.info(f"Using Claude session ID: {session_id}")
@@ -156,7 +156,7 @@ class ClaudeSessionLogger:
156
156
  agent_name = agent_name.replace(" ", "_").lower()
157
157
 
158
158
  # Generate timestamp with microseconds for uniqueness
159
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
159
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S_%f")
160
160
 
161
161
  # Create filename: session_id-agent-timestamp.json
162
162
  return f"{self.session_id}-{agent_name}-{timestamp}.json"
@@ -216,7 +216,7 @@ class ClaudeSessionLogger:
216
216
 
217
217
  # Prepare response data with standardized field names
218
218
  response_data = {
219
- "timestamp": datetime.now().isoformat(),
219
+ "timestamp": datetime.now(timezone.utc).isoformat(),
220
220
  "session_id": self.session_id,
221
221
  "request": request_summary, # Standardized field name
222
222
  "response": response_content, # Already correct
@@ -336,7 +336,7 @@ class AgentListingService(IAgentListingService):
336
336
  self.logger.error(f"Error listing agents by tier: {e}", exc_info=True)
337
337
  return AgentTierInfo(project=[], user=[], system=[])
338
338
 
339
- def get_agent_details(self, agent_name: str) -> Optional[Dict[str, Any]]:
339
+ def get_agent_details(self, agent_name: str) -> Optional[Dict[str, Any]]: # noqa: PLR0911
340
340
  """Get detailed information for a specific agent."""
341
341
  cache_key = f"agent_details_{agent_name}"
342
342
  cached = self._get_from_cache(cache_key)
@@ -1,3 +1,4 @@
1
+ import re
1
2
  """
2
3
  Agent Validation Service
3
4
  ========================