claude-mpm 4.3.12__py3-none-any.whl → 4.3.14__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 (206) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +414 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/agents/templates/engineer.json +11 -3
  5. claude_mpm/cli/commands/agent_manager.py +3 -3
  6. claude_mpm/cli/commands/agents.py +2 -2
  7. claude_mpm/cli/commands/aggregate.py +1 -1
  8. claude_mpm/cli/commands/config.py +2 -2
  9. claude_mpm/cli/commands/configure.py +5 -5
  10. claude_mpm/cli/commands/configure_tui.py +7 -7
  11. claude_mpm/cli/commands/dashboard.py +1 -1
  12. claude_mpm/cli/commands/debug.py +5 -5
  13. claude_mpm/cli/commands/mcp.py +1 -1
  14. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  15. claude_mpm/cli/commands/mcp_config.py +7 -10
  16. claude_mpm/cli/commands/mcp_external_commands.py +40 -32
  17. claude_mpm/cli/commands/mcp_install_commands.py +38 -10
  18. claude_mpm/cli/commands/mcp_setup_external.py +143 -102
  19. claude_mpm/cli/commands/monitor.py +2 -2
  20. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  21. claude_mpm/cli/commands/run.py +54 -2
  22. claude_mpm/cli/commands/search.py +41 -34
  23. claude_mpm/cli/interactive/agent_wizard.py +6 -2
  24. claude_mpm/cli/parsers/mcp_parser.py +1 -3
  25. claude_mpm/cli/parsers/search_parser.py +10 -4
  26. claude_mpm/cli/startup_logging.py +158 -5
  27. claude_mpm/cli/utils.py +1 -1
  28. claude_mpm/core/agent_registry.py +2 -2
  29. claude_mpm/core/agent_session_manager.py +8 -8
  30. claude_mpm/core/api_validator.py +6 -4
  31. claude_mpm/core/base_service.py +10 -10
  32. claude_mpm/core/cache.py +5 -5
  33. claude_mpm/core/config_constants.py +1 -1
  34. claude_mpm/core/container.py +1 -1
  35. claude_mpm/core/error_handler.py +2 -2
  36. claude_mpm/core/file_utils.py +1 -1
  37. claude_mpm/core/framework_loader.py +3 -3
  38. claude_mpm/core/hook_manager.py +8 -6
  39. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  40. claude_mpm/core/interactive_session.py +3 -1
  41. claude_mpm/core/lazy.py +3 -3
  42. claude_mpm/core/log_manager.py +16 -12
  43. claude_mpm/core/logger.py +16 -11
  44. claude_mpm/core/optimized_agent_loader.py +6 -6
  45. claude_mpm/core/output_style_manager.py +1 -1
  46. claude_mpm/core/pm_hook_interceptor.py +3 -3
  47. claude_mpm/core/service_registry.py +1 -1
  48. claude_mpm/core/session_manager.py +11 -9
  49. claude_mpm/core/socketio_pool.py +13 -13
  50. claude_mpm/core/types.py +2 -2
  51. claude_mpm/core/unified_agent_registry.py +2 -2
  52. claude_mpm/core/unified_paths.py +1 -1
  53. claude_mpm/dashboard/analysis_runner.py +4 -4
  54. claude_mpm/dashboard/api/simple_directory.py +1 -1
  55. claude_mpm/generators/agent_profile_generator.py +4 -2
  56. claude_mpm/hooks/base_hook.py +2 -2
  57. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  63. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  64. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  65. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  66. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  67. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  68. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  69. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  70. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  71. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  72. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  73. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  74. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
  75. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  76. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/services/connection_manager.py +8 -5
  80. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  81. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  82. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  83. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  84. claude_mpm/hooks/memory_integration_hook.py +1 -1
  85. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  86. claude_mpm/models/agent_session.py +7 -5
  87. claude_mpm/scripts/mcp_server.py +0 -0
  88. claude_mpm/scripts/start_activity_logging.py +0 -0
  89. claude_mpm/services/__init__.py +1 -1
  90. claude_mpm/services/agent_capabilities_service.py +1 -1
  91. claude_mpm/services/agents/agent_builder.py +3 -3
  92. claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
  93. claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
  94. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
  95. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  96. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  97. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  98. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  99. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  100. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  101. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  102. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  103. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  104. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  105. claude_mpm/services/agents/local_template_manager.py +6 -6
  106. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  107. claude_mpm/services/agents/memory/content_manager.py +3 -3
  108. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  109. claude_mpm/services/agents/memory/template_generator.py +3 -3
  110. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  111. claude_mpm/services/async_session_logger.py +3 -3
  112. claude_mpm/services/claude_session_logger.py +4 -4
  113. claude_mpm/services/cli/agent_listing_service.py +3 -1
  114. claude_mpm/services/cli/agent_validation_service.py +2 -0
  115. claude_mpm/services/cli/memory_crud_service.py +11 -6
  116. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  117. claude_mpm/services/cli/session_manager.py +15 -11
  118. claude_mpm/services/core/memory_manager.py +81 -23
  119. claude_mpm/services/core/path_resolver.py +1 -1
  120. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  121. claude_mpm/services/event_aggregator.py +4 -2
  122. claude_mpm/services/event_bus/direct_relay.py +5 -3
  123. claude_mpm/services/event_bus/event_bus.py +3 -3
  124. claude_mpm/services/event_bus/relay.py +6 -4
  125. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  126. claude_mpm/services/events/core.py +3 -3
  127. claude_mpm/services/events/producers/hook.py +6 -6
  128. claude_mpm/services/events/producers/system.py +8 -8
  129. claude_mpm/services/exceptions.py +5 -5
  130. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  131. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  132. claude_mpm/services/hook_installer_service.py +1 -1
  133. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  134. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  135. claude_mpm/services/infrastructure/logging.py +2 -2
  136. claude_mpm/services/mcp_config_manager.py +175 -30
  137. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  138. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  139. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  140. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  141. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  142. claude_mpm/services/mcp_gateway/main.py +21 -7
  143. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  144. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  145. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  146. claude_mpm/services/mcp_gateway/server/stdio_server.py +5 -2
  147. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  148. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  149. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
  150. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  151. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  152. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  153. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +16 -16
  154. claude_mpm/services/memory/builder.py +7 -5
  155. claude_mpm/services/memory/indexed_memory.py +4 -4
  156. claude_mpm/services/memory/optimizer.py +6 -6
  157. claude_mpm/services/memory/router.py +3 -3
  158. claude_mpm/services/monitor/daemon.py +1 -1
  159. claude_mpm/services/monitor/daemon_manager.py +6 -6
  160. claude_mpm/services/monitor/event_emitter.py +2 -2
  161. claude_mpm/services/monitor/management/lifecycle.py +3 -1
  162. claude_mpm/services/monitor/server.py +4 -4
  163. claude_mpm/services/monitor_build_service.py +2 -2
  164. claude_mpm/services/port_manager.py +3 -1
  165. claude_mpm/services/response_tracker.py +2 -2
  166. claude_mpm/services/session_management_service.py +3 -2
  167. claude_mpm/services/socketio/client_proxy.py +2 -2
  168. claude_mpm/services/socketio/dashboard_server.py +4 -3
  169. claude_mpm/services/socketio/event_normalizer.py +11 -7
  170. claude_mpm/services/socketio/handlers/base.py +2 -2
  171. claude_mpm/services/socketio/handlers/connection.py +10 -10
  172. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  173. claude_mpm/services/socketio/handlers/hook.py +16 -15
  174. claude_mpm/services/socketio/migration_utils.py +1 -1
  175. claude_mpm/services/socketio/monitor_client.py +5 -5
  176. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  177. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  178. claude_mpm/services/socketio/server/core.py +7 -5
  179. claude_mpm/services/socketio/server/eventbus_integration.py +18 -12
  180. claude_mpm/services/socketio/server/main.py +13 -13
  181. claude_mpm/services/socketio_client_manager.py +4 -4
  182. claude_mpm/services/system_instructions_service.py +2 -2
  183. claude_mpm/services/utility_service.py +5 -2
  184. claude_mpm/services/version_control/branch_strategy.py +2 -2
  185. claude_mpm/services/version_control/git_operations.py +22 -20
  186. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  187. claude_mpm/services/version_control/version_parser.py +7 -5
  188. claude_mpm/services/visualization/mermaid_generator.py +3 -1
  189. claude_mpm/storage/state_storage.py +1 -1
  190. claude_mpm/tools/code_tree_analyzer.py +23 -18
  191. claude_mpm/tools/code_tree_builder.py +2 -2
  192. claude_mpm/tools/code_tree_events.py +10 -8
  193. claude_mpm/tools/socketio_debug.py +3 -3
  194. claude_mpm/utils/agent_dependency_loader.py +6 -2
  195. claude_mpm/utils/dependency_strategies.py +8 -3
  196. claude_mpm/utils/environment_context.py +1 -1
  197. claude_mpm/utils/error_handler.py +2 -2
  198. claude_mpm/utils/file_utils.py +1 -1
  199. claude_mpm/utils/log_cleanup.py +21 -7
  200. claude_mpm/validation/agent_validator.py +2 -2
  201. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/METADATA +1 -1
  202. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/RECORD +204 -191
  203. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/WHEEL +0 -0
  204. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/entry_points.txt +0 -0
  205. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/licenses/LICENSE +0 -0
  206. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/top_level.txt +0 -0
@@ -85,7 +85,7 @@ try:
85
85
  else:
86
86
  # Installed package - just return the package location
87
87
  print(os.path.dirname(pkg_dir))
88
- except:
88
+ except Exception:
89
89
  pass
90
90
  " 2>/dev/null)
91
91
 
@@ -714,7 +714,7 @@ main "$@"
714
714
  if "hooks" in settings:
715
715
  status["configured_events"] = list(settings["hooks"].keys())
716
716
  configured_in_local = True
717
- except:
717
+ except Exception:
718
718
  pass
719
719
 
720
720
  # Also check old settings file
@@ -728,7 +728,7 @@ main "$@"
728
728
  status["warning"] = (
729
729
  "Hooks found in settings.local.json but Claude Code reads from settings.json"
730
730
  )
731
- except:
731
+ except Exception:
732
732
  pass
733
733
 
734
734
  status["settings_location"] = (
@@ -7,7 +7,7 @@ including pre and post delegation hooks.
7
7
 
8
8
  import os
9
9
  import sys
10
- from datetime import datetime
10
+ from datetime import datetime, timezone
11
11
  from typing import Optional
12
12
 
13
13
  # Debug mode
@@ -122,7 +122,7 @@ class MemoryHookManager:
122
122
  "session_id": session_id,
123
123
  },
124
124
  metadata={"source": "claude_hook_handler", "tool_name": "Task"},
125
- timestamp=datetime.now().isoformat(),
125
+ timestamp=datetime.now(timezone.utc).isoformat(),
126
126
  session_id=session_id,
127
127
  )
128
128
 
@@ -200,7 +200,7 @@ class MemoryHookManager:
200
200
  "tool_name": "Task",
201
201
  "duration_ms": event.get("duration_ms", 0),
202
202
  },
203
- timestamp=datetime.now().isoformat(),
203
+ timestamp=datetime.now(timezone.utc).isoformat(),
204
204
  session_id=session_id,
205
205
  )
206
206
 
@@ -9,7 +9,7 @@ import json
9
9
  import os
10
10
  import re
11
11
  import sys
12
- from datetime import datetime
12
+ from datetime import datetime, timezone
13
13
  from typing import Optional
14
14
 
15
15
  # Debug mode
@@ -192,7 +192,7 @@ class ResponseTrackingManager:
192
192
  "has_error": bool(event.get("error")),
193
193
  "duration_ms": event.get("duration_ms"),
194
194
  "working_directory": event.get("cwd", ""),
195
- "timestamp": datetime.now().isoformat(),
195
+ "timestamp": datetime.now(timezone.utc).isoformat(),
196
196
  "tool_name": "Task",
197
197
  "original_request_timestamp": request_info.get("timestamp"),
198
198
  }
@@ -344,7 +344,7 @@ class ResponseTrackingManager:
344
344
 
345
345
  # Track the response
346
346
  metadata = {
347
- "timestamp": datetime.now().isoformat(),
347
+ "timestamp": datetime.now(timezone.utc).isoformat(),
348
348
  "prompt_timestamp": prompt_data.get("timestamp"),
349
349
  "working_directory": prompt_data.get("working_directory", ""),
350
350
  "event_type": "assistant_response",
@@ -18,7 +18,7 @@ This service manages:
18
18
 
19
19
  import os
20
20
  import sys
21
- from datetime import datetime
21
+ from datetime import datetime, timezone
22
22
 
23
23
  # Debug mode is enabled by default for better visibility into hook processing
24
24
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
@@ -62,7 +62,7 @@ except ImportError:
62
62
  "type": event_data.get("type", "unknown"),
63
63
  "subtype": event_data.get("subtype", "generic"),
64
64
  "timestamp": event_data.get(
65
- "timestamp", datetime.now().isoformat()
65
+ "timestamp", datetime.now(timezone.utc).isoformat()
66
66
  ),
67
67
  "data": event_data.get("data", event_data),
68
68
  }
@@ -119,7 +119,7 @@ class ConnectionManagerService:
119
119
  raw_event = {
120
120
  "type": "hook",
121
121
  "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
122
- "timestamp": datetime.now().isoformat(),
122
+ "timestamp": datetime.now(timezone.utc).isoformat(),
123
123
  "data": data,
124
124
  "source": "claude_hooks", # Identify the source
125
125
  "session_id": data.get("sessionId"), # Include session if available
@@ -190,7 +190,10 @@ class ConnectionManagerService:
190
190
 
191
191
  # Warn if no emission method is available
192
192
  if not self.connection_pool and DEBUG:
193
- print(f"⚠️ No event emission method available for: {event}", file=sys.stderr)
193
+ print(
194
+ f"⚠️ No event emission method available for: {claude_event_data.get('event', 'unknown')}",
195
+ file=sys.stderr,
196
+ )
194
197
 
195
198
  def cleanup(self):
196
199
  """Cleanup connections on service destruction."""
@@ -198,5 +201,5 @@ class ConnectionManagerService:
198
201
  if self.connection_pool:
199
202
  try:
200
203
  self.connection_pool.cleanup()
201
- except:
204
+ except Exception:
202
205
  pass # Ignore cleanup errors during destruction
@@ -12,7 +12,7 @@ This eliminates disconnection issues and matches the process lifecycle.
12
12
  import asyncio
13
13
  import os
14
14
  import sys
15
- from datetime import datetime
15
+ from datetime import datetime, timezone
16
16
 
17
17
  # Debug mode is enabled by default for better visibility into hook processing
18
18
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
@@ -52,7 +52,7 @@ except ImportError:
52
52
  "type": event_data.get("type", "unknown"),
53
53
  "subtype": event_data.get("subtype", "generic"),
54
54
  "timestamp": event_data.get(
55
- "timestamp", datetime.now().isoformat()
55
+ "timestamp", datetime.now(timezone.utc).isoformat()
56
56
  ),
57
57
  "data": event_data.get("data", event_data),
58
58
  }
@@ -101,7 +101,7 @@ class ConnectionManagerService:
101
101
  raw_event = {
102
102
  "type": "hook",
103
103
  "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
104
- "timestamp": datetime.now().isoformat(),
104
+ "timestamp": datetime.now(timezone.utc).isoformat(),
105
105
  "data": data,
106
106
  "source": "claude_hooks", # Identify the source
107
107
  "session_id": data.get("sessionId"), # Include session if available
@@ -11,7 +11,7 @@ import os
11
11
  import subprocess
12
12
  import time
13
13
  from collections import deque
14
- from datetime import datetime
14
+ from datetime import datetime, timezone
15
15
  from typing import Optional
16
16
 
17
17
  # Import constants for configuration
@@ -77,7 +77,7 @@ class StateManagerService:
77
77
 
78
78
  if session_id and agent_type and agent_type != "unknown":
79
79
  self.active_delegations[session_id] = agent_type
80
- key = f"{session_id}:{datetime.now().timestamp()}"
80
+ key = f"{session_id}:{datetime.now(timezone.utc).timestamp()}"
81
81
  self.delegation_history.append((key, agent_type))
82
82
 
83
83
  # Store request data for response tracking correlation
@@ -85,7 +85,7 @@ class StateManagerService:
85
85
  self.delegation_requests[session_id] = {
86
86
  "agent_type": agent_type,
87
87
  "request": request_data,
88
- "timestamp": datetime.now().isoformat(),
88
+ "timestamp": datetime.now(timezone.utc).isoformat(),
89
89
  }
90
90
  if DEBUG:
91
91
  import sys
@@ -100,7 +100,7 @@ class StateManagerService:
100
100
  )
101
101
 
102
102
  # Clean up old delegations (older than 5 minutes)
103
- cutoff_time = datetime.now().timestamp() - 300
103
+ cutoff_time = datetime.now(timezone.utc).timestamp() - 300
104
104
  keys_to_remove = []
105
105
  for sid in list(self.active_delegations.keys()):
106
106
  # Check if this is an old entry by looking in history
@@ -136,7 +136,7 @@ class StateManagerService:
136
136
 
137
137
  def cleanup_old_entries(self):
138
138
  """Clean up old entries to prevent memory growth."""
139
- datetime.now().timestamp() - self.MAX_CACHE_AGE_SECONDS
139
+ datetime.now(timezone.utc).timestamp() - self.MAX_CACHE_AGE_SECONDS
140
140
 
141
141
  # Clean up delegation tracking dictionaries
142
142
  for storage in [self.active_delegations, self.delegation_requests]:
@@ -158,7 +158,8 @@ class StateManagerService:
158
158
  expired_keys = [
159
159
  key
160
160
  for key, cache_time in self._git_branch_cache_time.items()
161
- if datetime.now().timestamp() - cache_time > self.MAX_CACHE_AGE_SECONDS
161
+ if datetime.now(timezone.utc).timestamp() - cache_time
162
+ > self.MAX_CACHE_AGE_SECONDS
162
163
  ]
163
164
  for key in expired_keys:
164
165
  self._git_branch_cache.pop(key, None)
@@ -178,7 +179,7 @@ class StateManagerService:
178
179
  working_dir = os.getcwd()
179
180
 
180
181
  # Check cache first (cache for 30 seconds)
181
- current_time = datetime.now().timestamp()
182
+ current_time = datetime.now(timezone.utc).timestamp()
182
183
  cache_key = working_dir
183
184
 
184
185
  if (
@@ -11,7 +11,7 @@ import json
11
11
  import os
12
12
  import re
13
13
  import sys
14
- from datetime import datetime
14
+ from datetime import datetime, timezone
15
15
  from typing import Optional, Tuple
16
16
 
17
17
  # Debug mode is enabled by default for better visibility into hook processing
@@ -272,7 +272,7 @@ class SubagentResponseProcessor:
272
272
  "duration_ms": event.get("duration_ms"),
273
273
  "working_directory": working_dir,
274
274
  "git_branch": git_branch,
275
- "timestamp": datetime.now().isoformat(),
275
+ "timestamp": datetime.now(timezone.utc).isoformat(),
276
276
  "event_type": "subagent_stop",
277
277
  "reason": reason,
278
278
  "original_request_timestamp": request_info.get("timestamp"),
@@ -347,7 +347,7 @@ class SubagentResponseProcessor:
347
347
  "session_id": session_id,
348
348
  "working_directory": working_dir,
349
349
  "git_branch": git_branch,
350
- "timestamp": datetime.now().isoformat(),
350
+ "timestamp": datetime.now(timezone.utc).isoformat(),
351
351
  "is_successful_completion": reason in ["completed", "finished", "done"],
352
352
  "is_error_termination": reason in ["error", "timeout", "failed", "blocked"],
353
353
  "is_delegation_related": agent_type
@@ -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,9 @@ 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(
236
+ self, event_type: str, data: Dict[str, Any]
237
+ ) -> EventCategory:
236
238
  """Categorize an event based on its type and data.
237
239
 
238
240
  WHY: Categories help with filtering and analysis of related events.
@@ -338,7 +340,7 @@ class AgentSession:
338
340
  event.timestamp.replace("Z", "+00:00")
339
341
  )
340
342
  tool_op.duration_ms = int((end - start).total_seconds() * 1000)
341
- except:
343
+ except Exception:
342
344
  pass
343
345
 
344
346
  event.correlation_id = corr_id
@@ -393,7 +395,7 @@ class AgentSession:
393
395
  self.metrics.session_duration_ms = int(
394
396
  (end - start).total_seconds() * 1000
395
397
  )
396
- except:
398
+ except Exception:
397
399
  pass
398
400
 
399
401
  # Finalize any pending delegations
File without changes
File without changes
@@ -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,9 @@ 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("%Y%m%d_%H%M%S")
189
189
  backup_dir = agents_dir.parent / f"agents_backup_{timestamp}"
190
190
 
191
191
  # Create backup
@@ -324,7 +324,7 @@ class AgentFileSystemManager:
324
324
 
325
325
  def _convert_yaml_to_markdown(self, yaml_content: str, agent_name: str) -> str:
326
326
  """Convert YAML agent content to Markdown format with frontmatter."""
327
- from datetime import datetime
327
+ from datetime import datetime, timezone
328
328
 
329
329
  # Extract YAML fields (simplified parsing)
330
330
  name = self._extract_yaml_field(yaml_content, "name") or agent_name
@@ -356,8 +356,8 @@ name: {name}
356
356
  description: "{description}"
357
357
  version: "{version}"
358
358
  author: "claude-mpm@anthropic.com"
359
- created: "{datetime.now().isoformat()}Z"
360
- updated: "{datetime.now().isoformat()}Z"
359
+ created: "{datetime.now(timezone.utc).isoformat()}Z"
360
+ updated: "{datetime.now(timezone.utc).isoformat()}Z"
361
361
  tags: ["{agent_name}", "mpm-framework"]
362
362
  tools: {tools_list}
363
363
  model: "sonnet"
@@ -32,10 +32,12 @@ 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
 
38
39
  from claude_mpm.core.base_service import BaseService
40
+ from claude_mpm.core.unified_paths import get_path_manager
39
41
  from claude_mpm.models.agent_definition import AgentDefinition
40
42
  from claude_mpm.services.agents.management import AgentManager
41
43
  from claude_mpm.services.agents.memory import (
@@ -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():