claude-mpm 1.0.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. claude_mpm/_version.py +4 -2
  2. claude_mpm/agents/INSTRUCTIONS.md +117 -312
  3. claude_mpm/agents/__init__.py +2 -2
  4. claude_mpm/agents/agent-template.yaml +83 -0
  5. claude_mpm/agents/agent_loader.py +192 -310
  6. claude_mpm/agents/base_agent.json +1 -1
  7. claude_mpm/agents/base_agent_loader.py +10 -15
  8. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +46 -0
  9. claude_mpm/agents/templates/{engineer_agent.json → backup/engineer_agent_20250726_234551.json} +1 -1
  10. claude_mpm/agents/templates/data_engineer.json +107 -0
  11. claude_mpm/agents/templates/documentation.json +106 -0
  12. claude_mpm/agents/templates/engineer.json +110 -0
  13. claude_mpm/agents/templates/ops.json +106 -0
  14. claude_mpm/agents/templates/qa.json +106 -0
  15. claude_mpm/agents/templates/research.json +107 -0
  16. claude_mpm/agents/templates/security.json +105 -0
  17. claude_mpm/agents/templates/version_control.json +103 -0
  18. claude_mpm/cli.py +41 -47
  19. claude_mpm/cli_enhancements.py +297 -0
  20. claude_mpm/core/factories.py +1 -46
  21. claude_mpm/core/service_registry.py +0 -8
  22. claude_mpm/core/simple_runner.py +43 -0
  23. claude_mpm/generators/__init__.py +5 -0
  24. claude_mpm/generators/agent_profile_generator.py +137 -0
  25. claude_mpm/hooks/README.md +75 -221
  26. claude_mpm/hooks/builtin/mpm_command_hook.py +125 -0
  27. claude_mpm/hooks/claude_hooks/__init__.py +5 -0
  28. claude_mpm/hooks/claude_hooks/hook_handler.py +399 -0
  29. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +47 -0
  30. claude_mpm/hooks/validation_hooks.py +181 -0
  31. claude_mpm/schemas/agent_schema.json +328 -0
  32. claude_mpm/services/agent_management_service.py +4 -4
  33. claude_mpm/services/agent_profile_loader.py +1 -1
  34. claude_mpm/services/agent_registry.py +0 -1
  35. claude_mpm/services/base_agent_manager.py +3 -3
  36. claude_mpm/utils/error_handler.py +247 -0
  37. claude_mpm/validation/__init__.py +5 -0
  38. claude_mpm/validation/agent_validator.py +302 -0
  39. {claude_mpm-1.0.0.dist-info → claude_mpm-2.0.0.dist-info}/METADATA +133 -22
  40. {claude_mpm-1.0.0.dist-info → claude_mpm-2.0.0.dist-info}/RECORD +49 -37
  41. claude_mpm/agents/templates/data_engineer_agent.json +0 -46
  42. claude_mpm/agents/templates/update-optimized-specialized-agents.json +0 -374
  43. claude_mpm/config/hook_config.py +0 -42
  44. claude_mpm/hooks/hook_client.py +0 -264
  45. claude_mpm/hooks/hook_runner.py +0 -370
  46. claude_mpm/hooks/json_rpc_executor.py +0 -259
  47. claude_mpm/hooks/json_rpc_hook_client.py +0 -319
  48. claude_mpm/services/hook_service.py +0 -388
  49. claude_mpm/services/hook_service_manager.py +0 -223
  50. claude_mpm/services/json_rpc_hook_manager.py +0 -92
  51. /claude_mpm/agents/templates/{documentation_agent.json → backup/documentation_agent_20250726_234551.json} +0 -0
  52. /claude_mpm/agents/templates/{ops_agent.json → backup/ops_agent_20250726_234551.json} +0 -0
  53. /claude_mpm/agents/templates/{qa_agent.json → backup/qa_agent_20250726_234551.json} +0 -0
  54. /claude_mpm/agents/templates/{research_agent.json → backup/research_agent_20250726_234551.json} +0 -0
  55. /claude_mpm/agents/templates/{security_agent.json → backup/security_agent_20250726_234551.json} +0 -0
  56. /claude_mpm/agents/templates/{version_control_agent.json → backup/version_control_agent_20250726_234551.json} +0 -0
  57. {claude_mpm-1.0.0.dist-info → claude_mpm-2.0.0.dist-info}/WHEEL +0 -0
  58. {claude_mpm-1.0.0.dist-info → claude_mpm-2.0.0.dist-info}/entry_points.txt +0 -0
  59. {claude_mpm-1.0.0.dist-info → claude_mpm-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,328 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Claude MPM Agent Schema",
4
+ "description": "Schema definition for Claude MPM agent templates",
5
+ "type": "object",
6
+ "required": ["id", "version", "metadata", "capabilities", "instructions"],
7
+ "properties": {
8
+ "id": {
9
+ "type": "string",
10
+ "pattern": "^[a-z][a-z0-9_]*$",
11
+ "description": "Unique agent identifier (lowercase, alphanumeric with underscores)",
12
+ "examples": ["research", "engineer", "qa", "security"]
13
+ },
14
+ "version": {
15
+ "type": "string",
16
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
17
+ "description": "Semantic version of the agent template",
18
+ "examples": ["1.0.0", "2.1.3"]
19
+ },
20
+ "metadata": {
21
+ "type": "object",
22
+ "required": ["name", "description", "category", "tags"],
23
+ "properties": {
24
+ "name": {
25
+ "type": "string",
26
+ "minLength": 3,
27
+ "maxLength": 50,
28
+ "description": "Human-readable agent name"
29
+ },
30
+ "description": {
31
+ "type": "string",
32
+ "minLength": 10,
33
+ "maxLength": 200,
34
+ "description": "Brief description of agent purpose"
35
+ },
36
+ "category": {
37
+ "type": "string",
38
+ "enum": ["engineering", "research", "quality", "operations", "specialized"],
39
+ "description": "Agent category for organization"
40
+ },
41
+ "tags": {
42
+ "type": "array",
43
+ "items": {
44
+ "type": "string",
45
+ "pattern": "^[a-z][a-z0-9-]*$"
46
+ },
47
+ "minItems": 1,
48
+ "maxItems": 10,
49
+ "uniqueItems": true,
50
+ "description": "Tags for agent discovery"
51
+ },
52
+ "author": {
53
+ "type": "string",
54
+ "description": "Agent template author"
55
+ },
56
+ "created_at": {
57
+ "type": "string",
58
+ "format": "date-time",
59
+ "description": "Creation timestamp"
60
+ },
61
+ "updated_at": {
62
+ "type": "string",
63
+ "format": "date-time",
64
+ "description": "Last update timestamp"
65
+ }
66
+ }
67
+ },
68
+ "capabilities": {
69
+ "type": "object",
70
+ "required": ["model", "tools", "resource_tier"],
71
+ "properties": {
72
+ "model": {
73
+ "type": "string",
74
+ "enum": [
75
+ "claude-3-haiku-20240307",
76
+ "claude-3-5-haiku-20241022",
77
+ "claude-3-sonnet-20240229",
78
+ "claude-3-5-sonnet-20241022",
79
+ "claude-3-opus-20240229",
80
+ "claude-3-5-sonnet-20240620",
81
+ "claude-sonnet-4-20250514",
82
+ "claude-4-sonnet-20250514",
83
+ "claude-opus-4-20250514",
84
+ "claude-4-opus-20250514"
85
+ ],
86
+ "description": "Claude model to use for this agent"
87
+ },
88
+ "tools": {
89
+ "type": "array",
90
+ "items": {
91
+ "type": "string",
92
+ "enum": [
93
+ "Read", "Write", "Edit", "MultiEdit",
94
+ "Grep", "Glob", "LS", "Bash",
95
+ "WebSearch", "WebFetch",
96
+ "NotebookRead", "NotebookEdit",
97
+ "TodoWrite", "ExitPlanMode",
98
+ "git", "docker", "kubectl", "terraform",
99
+ "aws", "gcloud", "azure"
100
+ ]
101
+ },
102
+ "uniqueItems": true,
103
+ "description": "Available tools for the agent"
104
+ },
105
+ "resource_tier": {
106
+ "type": "string",
107
+ "enum": ["intensive", "standard", "lightweight"],
108
+ "description": "Resource allocation tier"
109
+ },
110
+ "max_tokens": {
111
+ "type": "integer",
112
+ "minimum": 1000,
113
+ "maximum": 200000,
114
+ "default": 8192,
115
+ "description": "Maximum tokens for response"
116
+ },
117
+ "temperature": {
118
+ "type": "number",
119
+ "minimum": 0,
120
+ "maximum": 1,
121
+ "default": 0.7,
122
+ "description": "Model temperature setting"
123
+ },
124
+ "timeout": {
125
+ "type": "integer",
126
+ "minimum": 30,
127
+ "maximum": 3600,
128
+ "default": 300,
129
+ "description": "Operation timeout in seconds"
130
+ },
131
+ "memory_limit": {
132
+ "type": "integer",
133
+ "minimum": 512,
134
+ "maximum": 8192,
135
+ "description": "Memory limit in MB (for resource tier)"
136
+ },
137
+ "cpu_limit": {
138
+ "type": "integer",
139
+ "minimum": 10,
140
+ "maximum": 100,
141
+ "description": "CPU limit percentage (for resource tier)"
142
+ },
143
+ "network_access": {
144
+ "type": "boolean",
145
+ "default": false,
146
+ "description": "Whether agent needs network access"
147
+ },
148
+ "file_access": {
149
+ "type": "object",
150
+ "properties": {
151
+ "read_paths": {
152
+ "type": "array",
153
+ "items": {"type": "string"},
154
+ "description": "Allowed read paths"
155
+ },
156
+ "write_paths": {
157
+ "type": "array",
158
+ "items": {"type": "string"},
159
+ "description": "Allowed write paths"
160
+ }
161
+ }
162
+ }
163
+ }
164
+ },
165
+ "instructions": {
166
+ "type": "string",
167
+ "minLength": 100,
168
+ "maxLength": 8000,
169
+ "description": "Agent system instructions (8000 character limit)"
170
+ },
171
+ "knowledge": {
172
+ "type": "object",
173
+ "description": "Agent-specific knowledge and context",
174
+ "properties": {
175
+ "domain_expertise": {
176
+ "type": "array",
177
+ "items": {"type": "string"},
178
+ "description": "Areas of expertise"
179
+ },
180
+ "best_practices": {
181
+ "type": "array",
182
+ "items": {"type": "string"},
183
+ "description": "Best practices the agent follows"
184
+ },
185
+ "constraints": {
186
+ "type": "array",
187
+ "items": {"type": "string"},
188
+ "description": "Operating constraints"
189
+ },
190
+ "examples": {
191
+ "type": "array",
192
+ "items": {
193
+ "type": "object",
194
+ "properties": {
195
+ "scenario": {"type": "string"},
196
+ "approach": {"type": "string"}
197
+ }
198
+ },
199
+ "description": "Example scenarios and approaches"
200
+ }
201
+ }
202
+ },
203
+ "interactions": {
204
+ "type": "object",
205
+ "description": "Agent interaction patterns",
206
+ "properties": {
207
+ "input_format": {
208
+ "type": "object",
209
+ "properties": {
210
+ "required_fields": {
211
+ "type": "array",
212
+ "items": {"type": "string"}
213
+ },
214
+ "optional_fields": {
215
+ "type": "array",
216
+ "items": {"type": "string"}
217
+ }
218
+ }
219
+ },
220
+ "output_format": {
221
+ "type": "object",
222
+ "properties": {
223
+ "structure": {
224
+ "type": "string",
225
+ "enum": ["markdown", "json", "structured", "free-form"]
226
+ },
227
+ "includes": {
228
+ "type": "array",
229
+ "items": {"type": "string"}
230
+ }
231
+ }
232
+ },
233
+ "handoff_agents": {
234
+ "type": "array",
235
+ "items": {"type": "string"},
236
+ "description": "Agents this agent can hand off to"
237
+ },
238
+ "triggers": {
239
+ "type": "array",
240
+ "items": {
241
+ "type": "object",
242
+ "properties": {
243
+ "condition": {"type": "string"},
244
+ "action": {"type": "string"}
245
+ }
246
+ },
247
+ "description": "Conditions that trigger specific actions"
248
+ }
249
+ }
250
+ },
251
+ "testing": {
252
+ "type": "object",
253
+ "description": "Testing configuration for the agent",
254
+ "properties": {
255
+ "test_cases": {
256
+ "type": "array",
257
+ "items": {
258
+ "type": "object",
259
+ "required": ["input", "expected_behavior"],
260
+ "properties": {
261
+ "name": {"type": "string"},
262
+ "input": {"type": "string"},
263
+ "expected_behavior": {"type": "string"},
264
+ "validation_criteria": {
265
+ "type": "array",
266
+ "items": {"type": "string"}
267
+ }
268
+ }
269
+ }
270
+ },
271
+ "performance_benchmarks": {
272
+ "type": "object",
273
+ "properties": {
274
+ "response_time": {"type": "integer"},
275
+ "token_usage": {"type": "integer"},
276
+ "success_rate": {"type": "number"}
277
+ }
278
+ }
279
+ }
280
+ },
281
+ "hooks": {
282
+ "type": "object",
283
+ "description": "Hook configurations for extensibility",
284
+ "properties": {
285
+ "pre_execution": {
286
+ "type": "array",
287
+ "items": {
288
+ "type": "object",
289
+ "properties": {
290
+ "name": {"type": "string"},
291
+ "enabled": {"type": "boolean"}
292
+ }
293
+ }
294
+ },
295
+ "post_execution": {
296
+ "type": "array",
297
+ "items": {
298
+ "type": "object",
299
+ "properties": {
300
+ "name": {"type": "string"},
301
+ "enabled": {"type": "boolean"}
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+ },
308
+ "additionalProperties": false,
309
+ "definitions": {
310
+ "resource_tier_limits": {
311
+ "intensive": {
312
+ "memory_limit": {"min": 4096, "max": 8192},
313
+ "cpu_limit": {"min": 60, "max": 100},
314
+ "timeout": {"min": 600, "max": 3600}
315
+ },
316
+ "standard": {
317
+ "memory_limit": {"min": 2048, "max": 4096},
318
+ "cpu_limit": {"min": 30, "max": 60},
319
+ "timeout": {"min": 300, "max": 1200}
320
+ },
321
+ "lightweight": {
322
+ "memory_limit": {"min": 512, "max": 2048},
323
+ "cpu_limit": {"min": 10, "max": 30},
324
+ "timeout": {"min": 30, "max": 600}
325
+ }
326
+ }
327
+ }
328
+ }
@@ -40,15 +40,15 @@ class AgentManager:
40
40
  Initialize AgentManager.
41
41
 
42
42
  Args:
43
- framework_dir: Path to framework agent-roles directory
43
+ framework_dir: Path to agents templates directory
44
44
  project_dir: Path to project-specific agents directory
45
45
  """
46
46
  # Use PathResolver for consistent path discovery
47
47
  if framework_dir is None:
48
48
  try:
49
- framework_root = PathResolver.get_framework_root()
50
- self.framework_dir = framework_root / "framework" / "agent-roles"
51
- except FileNotFoundError:
49
+ # Use agents templates directory
50
+ self.framework_dir = Path(__file__).parent.parent / "agents" / "templates"
51
+ except Exception:
52
52
  # Fallback to agents directory
53
53
  self.framework_dir = PathResolver.get_agents_dir()
54
54
  else:
@@ -118,7 +118,7 @@ class AgentProfileLoader(BaseService):
118
118
  self.tier_paths = {
119
119
  ProfileTier.PROJECT: self.working_directory / 'agents',
120
120
  ProfileTier.USER: self.user_home / '.claude-pm' / 'agents',
121
- ProfileTier.SYSTEM: self.framework_path / 'agent-roles' if self.framework_path else None
121
+ ProfileTier.SYSTEM: Path(__file__).parent.parent / 'agents' / 'templates'
122
122
  }
123
123
 
124
124
  # Remove None values
@@ -155,7 +155,6 @@ class AgentRegistry:
155
155
  # System-level agents - multiple possible locations
156
156
  system_paths = [
157
157
  Path(__file__).parent.parent / 'agents' / 'templates',
158
- Path(__file__).parent.parent / 'framework' / 'agent-roles',
159
158
  Path('/opt/claude-pm/agents'),
160
159
  Path('/usr/local/claude-pm/agents')
161
160
  ]
@@ -64,10 +64,10 @@ class BaseAgentStructure:
64
64
  class BaseAgentManager:
65
65
  """Manages base_agent.md with structured updates and validation."""
66
66
 
67
- def __init__(self, framework_dir: Optional[Path] = None):
67
+ def __init__(self, agents_dir: Optional[Path] = None):
68
68
  """Initialize BaseAgentManager."""
69
- self.framework_dir = framework_dir or Path(__file__).parent.parent.parent / "framework" / "agent-roles"
70
- self.base_agent_path = self.framework_dir / "base_agent.md"
69
+ self.agents_dir = agents_dir or Path(__file__).parent.parent / "agents"
70
+ self.base_agent_path = self.agents_dir / "BASE_AGENT_TEMPLATE.md"
71
71
  self.cache = SharedPromptCache.get_instance()
72
72
 
73
73
  def read_base_agent(self) -> Optional[BaseAgentStructure]:
@@ -0,0 +1,247 @@
1
+ """
2
+ Enhanced error handling utilities for claude-mpm.
3
+
4
+ Inspired by awesome-claude-code's comprehensive error handling approach.
5
+ """
6
+
7
+ import logging
8
+ import sys
9
+ from typing import Optional, Type, Callable, Any, Dict
10
+ from functools import wraps
11
+ import traceback
12
+ from datetime import datetime
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class MPMError(Exception):
18
+ """Base exception for claude-mpm errors."""
19
+
20
+ def __init__(self, message: str, details: Optional[Dict[str, Any]] = None,
21
+ suggestions: Optional[List[str]] = None):
22
+ """Initialize MPM error with details and suggestions."""
23
+ super().__init__(message)
24
+ self.details = details or {}
25
+ self.suggestions = suggestions or []
26
+ self.timestamp = datetime.now()
27
+
28
+ def get_user_friendly_message(self) -> str:
29
+ """Get a user-friendly error message."""
30
+ lines = [f"❌ Error: {str(self)}"]
31
+
32
+ if self.details:
33
+ lines.append("\nDetails:")
34
+ for key, value in self.details.items():
35
+ lines.append(f" {key}: {value}")
36
+
37
+ if self.suggestions:
38
+ lines.append("\n💡 Suggestions:")
39
+ for suggestion in self.suggestions:
40
+ lines.append(f" - {suggestion}")
41
+
42
+ return '\n'.join(lines)
43
+
44
+
45
+ class AgentLoadError(MPMError):
46
+ """Raised when agent loading fails."""
47
+ pass
48
+
49
+
50
+ class ValidationError(MPMError):
51
+ """Raised when validation fails."""
52
+ pass
53
+
54
+
55
+ class ExecutionError(MPMError):
56
+ """Raised when agent execution fails."""
57
+ pass
58
+
59
+
60
+ class ConfigurationError(MPMError):
61
+ """Raised when configuration is invalid."""
62
+ pass
63
+
64
+
65
+ def handle_errors(error_type: Type[Exception] = Exception,
66
+ fallback_value: Any = None,
67
+ log_level: int = logging.ERROR) -> Callable:
68
+ """
69
+ Decorator for handling errors with detailed logging and user feedback.
70
+
71
+ Args:
72
+ error_type: Type of exception to catch
73
+ fallback_value: Value to return on error
74
+ log_level: Logging level for errors
75
+ """
76
+ def decorator(func: Callable) -> Callable:
77
+ @wraps(func)
78
+ def wrapper(*args, **kwargs):
79
+ try:
80
+ return func(*args, **kwargs)
81
+ except error_type as e:
82
+ # Log the error with full traceback
83
+ logger.log(log_level, f"Error in {func.__name__}: {e}", exc_info=True)
84
+
85
+ # Provide user-friendly feedback
86
+ if isinstance(e, MPMError):
87
+ print(e.get_user_friendly_message(), file=sys.stderr)
88
+ else:
89
+ print(f"❌ Error: {e}", file=sys.stderr)
90
+
91
+ return fallback_value
92
+ except Exception as e:
93
+ # Catch unexpected errors
94
+ logger.critical(f"Unexpected error in {func.__name__}: {e}", exc_info=True)
95
+ print(f"❌ Unexpected error: {e}", file=sys.stderr)
96
+ print("💡 This might be a bug. Please report it.", file=sys.stderr)
97
+ return fallback_value
98
+
99
+ return wrapper
100
+ return decorator
101
+
102
+
103
+ class ErrorContext:
104
+ """Context manager for enhanced error reporting."""
105
+
106
+ def __init__(self, operation: str, details: Optional[Dict[str, Any]] = None):
107
+ """Initialize error context."""
108
+ self.operation = operation
109
+ self.details = details or {}
110
+
111
+ def __enter__(self):
112
+ """Enter the context."""
113
+ logger.debug(f"Starting operation: {self.operation}")
114
+ return self
115
+
116
+ def __exit__(self, exc_type, exc_val, exc_tb):
117
+ """Exit the context, handling any errors."""
118
+ if exc_type is None:
119
+ logger.debug(f"Completed operation: {self.operation}")
120
+ return
121
+
122
+ # Log the error with context
123
+ logger.error(
124
+ f"Error during {self.operation}: {exc_val}",
125
+ extra={'operation': self.operation, 'details': self.details},
126
+ exc_info=True
127
+ )
128
+
129
+ # Don't suppress the exception
130
+ return False
131
+
132
+
133
+ def retry_on_error(max_attempts: int = 3,
134
+ delay: float = 1.0,
135
+ backoff_factor: float = 2.0,
136
+ exceptions: tuple = (Exception,)) -> Callable:
137
+ """
138
+ Decorator for retrying operations on error.
139
+
140
+ Args:
141
+ max_attempts: Maximum number of attempts
142
+ delay: Initial delay between attempts
143
+ backoff_factor: Multiplier for delay after each failure
144
+ exceptions: Tuple of exceptions to retry on
145
+ """
146
+ def decorator(func: Callable) -> Callable:
147
+ @wraps(func)
148
+ async def async_wrapper(*args, **kwargs):
149
+ import asyncio
150
+
151
+ last_exception = None
152
+ current_delay = delay
153
+
154
+ for attempt in range(max_attempts):
155
+ try:
156
+ return await func(*args, **kwargs)
157
+ except exceptions as e:
158
+ last_exception = e
159
+ if attempt < max_attempts - 1:
160
+ logger.warning(
161
+ f"Attempt {attempt + 1}/{max_attempts} failed for {func.__name__}: {e}"
162
+ )
163
+ await asyncio.sleep(current_delay)
164
+ current_delay *= backoff_factor
165
+ else:
166
+ logger.error(
167
+ f"All {max_attempts} attempts failed for {func.__name__}"
168
+ )
169
+
170
+ raise last_exception
171
+
172
+ @wraps(func)
173
+ def sync_wrapper(*args, **kwargs):
174
+ import time
175
+
176
+ last_exception = None
177
+ current_delay = delay
178
+
179
+ for attempt in range(max_attempts):
180
+ try:
181
+ return func(*args, **kwargs)
182
+ except exceptions as e:
183
+ last_exception = e
184
+ if attempt < max_attempts - 1:
185
+ logger.warning(
186
+ f"Attempt {attempt + 1}/{max_attempts} failed for {func.__name__}: {e}"
187
+ )
188
+ time.sleep(current_delay)
189
+ current_delay *= backoff_factor
190
+ else:
191
+ logger.error(
192
+ f"All {max_attempts} attempts failed for {func.__name__}"
193
+ )
194
+
195
+ raise last_exception
196
+
197
+ # Return appropriate wrapper based on function type
198
+ import asyncio
199
+ if asyncio.iscoroutinefunction(func):
200
+ return async_wrapper
201
+ else:
202
+ return sync_wrapper
203
+
204
+ return decorator
205
+
206
+
207
+ def format_exception_chain(exc: Exception) -> str:
208
+ """Format an exception chain for display."""
209
+ lines = []
210
+ current = exc
211
+ level = 0
212
+
213
+ while current is not None:
214
+ indent = " " * level
215
+ lines.append(f"{indent}{'└─' if level > 0 else ''}{type(current).__name__}: {current}")
216
+
217
+ if hasattr(current, '__cause__'):
218
+ current = current.__cause__
219
+ level += 1
220
+ else:
221
+ break
222
+
223
+ return '\n'.join(lines)
224
+
225
+
226
+ # Setup patterns from awesome-claude-code
227
+ def suggest_setup_fix(error: Exception) -> List[str]:
228
+ """Suggest fixes for common setup errors."""
229
+ suggestions = []
230
+ error_msg = str(error).lower()
231
+
232
+ if 'git' in error_msg and 'not found' in error_msg:
233
+ suggestions.append("Install git from https://git-scm.com/downloads")
234
+
235
+ if 'python' in error_msg and 'module' in error_msg:
236
+ suggestions.append("Ensure you're in a virtual environment")
237
+ suggestions.append("Run: pip install -e .")
238
+
239
+ if 'permission' in error_msg:
240
+ suggestions.append("Check file permissions")
241
+ suggestions.append("You may need to run with appropriate privileges")
242
+
243
+ if 'config' in error_msg or 'configuration' in error_msg:
244
+ suggestions.append("Check your configuration files")
245
+ suggestions.append("Run: mpm validate-config")
246
+
247
+ return suggestions
@@ -0,0 +1,5 @@
1
+ """Validation framework for claude-mpm."""
2
+
3
+ from .agent_validator import AgentValidator, ValidationResult
4
+
5
+ __all__ = ['AgentValidator', 'ValidationResult']