claude-mpm 3.3.0__py3-none-any.whl → 3.4.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 (58) hide show
  1. claude_mpm/agents/templates/data_engineer.json +1 -1
  2. claude_mpm/agents/templates/documentation.json +1 -1
  3. claude_mpm/agents/templates/engineer.json +1 -1
  4. claude_mpm/agents/templates/ops.json +1 -1
  5. claude_mpm/agents/templates/pm.json +1 -1
  6. claude_mpm/agents/templates/qa.json +1 -1
  7. claude_mpm/agents/templates/research.json +1 -1
  8. claude_mpm/agents/templates/security.json +1 -1
  9. claude_mpm/agents/templates/test_integration.json +112 -0
  10. claude_mpm/agents/templates/version_control.json +1 -1
  11. claude_mpm/cli/commands/memory.py +749 -26
  12. claude_mpm/cli/commands/run.py +115 -14
  13. claude_mpm/cli/parser.py +89 -1
  14. claude_mpm/constants.py +6 -0
  15. claude_mpm/core/claude_runner.py +74 -11
  16. claude_mpm/core/config.py +1 -1
  17. claude_mpm/core/session_manager.py +46 -0
  18. claude_mpm/core/simple_runner.py +74 -11
  19. claude_mpm/hooks/builtin/mpm_command_hook.py +5 -5
  20. claude_mpm/hooks/claude_hooks/hook_handler.py +213 -30
  21. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +9 -2
  22. claude_mpm/hooks/memory_integration_hook.py +51 -5
  23. claude_mpm/services/__init__.py +23 -5
  24. claude_mpm/services/agent_memory_manager.py +800 -71
  25. claude_mpm/services/memory_builder.py +823 -0
  26. claude_mpm/services/memory_optimizer.py +619 -0
  27. claude_mpm/services/memory_router.py +445 -0
  28. claude_mpm/services/project_analyzer.py +771 -0
  29. claude_mpm/services/socketio_server.py +649 -45
  30. claude_mpm/services/version_control/git_operations.py +26 -0
  31. claude_mpm-3.4.0.dist-info/METADATA +183 -0
  32. {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/RECORD +36 -52
  33. claude_mpm/agents/agent-template.yaml +0 -83
  34. claude_mpm/agents/templates/test-integration-agent.md +0 -34
  35. claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +0 -6
  36. claude_mpm/cli/README.md +0 -109
  37. claude_mpm/cli_module/refactoring_guide.md +0 -253
  38. claude_mpm/core/agent_registry.py.bak +0 -312
  39. claude_mpm/core/base_service.py.bak +0 -406
  40. claude_mpm/core/websocket_handler.py +0 -233
  41. claude_mpm/hooks/README.md +0 -97
  42. claude_mpm/orchestration/SUBPROCESS_DESIGN.md +0 -66
  43. claude_mpm/schemas/README_SECURITY.md +0 -92
  44. claude_mpm/schemas/agent_schema.json +0 -395
  45. claude_mpm/schemas/agent_schema_documentation.md +0 -181
  46. claude_mpm/schemas/agent_schema_security_notes.md +0 -165
  47. claude_mpm/schemas/examples/standard_workflow.json +0 -505
  48. claude_mpm/schemas/ticket_workflow_documentation.md +0 -482
  49. claude_mpm/schemas/ticket_workflow_schema.json +0 -590
  50. claude_mpm/services/framework_claude_md_generator/README.md +0 -92
  51. claude_mpm/services/parent_directory_manager/README.md +0 -83
  52. claude_mpm/services/version_control/VERSION +0 -1
  53. claude_mpm/services/websocket_server.py +0 -376
  54. claude_mpm-3.3.0.dist-info/METADATA +0 -432
  55. {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/WHEEL +0 -0
  56. {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/entry_points.txt +0 -0
  57. {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/licenses/LICENSE +0 -0
  58. {claude_mpm-3.3.0.dist-info → claude_mpm-3.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,445 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Memory Router Service
4
+ ====================
5
+
6
+ Routes memory commands to appropriate agents based on content analysis.
7
+
8
+ This service provides:
9
+ - Content analysis to determine target agent
10
+ - Support for "remember", "memorize", "add to memory" commands
11
+ - Routing decision with reasoning
12
+ - Context-aware agent selection
13
+
14
+ WHY: When users say "remember this for next time", the system needs to determine
15
+ which agent should store the information. This service analyzes content to make
16
+ intelligent routing decisions for PM delegation.
17
+
18
+ DESIGN DECISION: Uses keyword matching and context analysis rather than ML models
19
+ for simplicity and transparency. Routing decisions include reasoning to help
20
+ users understand why content was assigned to specific agents.
21
+ """
22
+
23
+ import re
24
+ from typing import Dict, List, Optional, Any, Tuple
25
+ from datetime import datetime
26
+
27
+ from claude_mpm.core import LoggerMixin
28
+ from claude_mpm.core.config import Config
29
+
30
+
31
+ class MemoryRouter(LoggerMixin):
32
+ """Routes memory commands to appropriate agents based on content analysis.
33
+
34
+ WHY: Different types of learnings belong to different agents. Engineering
35
+ insights should go to the engineer agent, while research findings should
36
+ go to the research agent. This service provides intelligent routing.
37
+
38
+ DESIGN DECISION: Uses explicit keyword patterns and rules rather than ML
39
+ to ensure predictable, transparent routing decisions that users can understand.
40
+ """
41
+
42
+ # Agent routing patterns - keywords that indicate agent specialization
43
+ AGENT_PATTERNS = {
44
+ 'engineer': {
45
+ 'keywords': [
46
+ 'implementation', 'code', 'coding', 'programming', 'function', 'method',
47
+ 'class', 'module', 'import', 'dependency', 'build', 'compile', 'deploy',
48
+ 'refactor', 'optimize', 'performance', 'algorithm', 'data structure',
49
+ 'design pattern', 'architecture', 'api', 'interface', 'library',
50
+ 'framework', 'testing', 'unit test', 'integration test', 'debug',
51
+ 'error handling', 'exception'
52
+ ],
53
+ 'sections': [
54
+ 'Coding Patterns Learned', 'Implementation Guidelines',
55
+ 'Performance Considerations', 'Integration Points'
56
+ ]
57
+ },
58
+ 'research': {
59
+ 'keywords': [
60
+ 'research', 'analysis', 'investigate', 'explore', 'study', 'examine',
61
+ 'findings', 'discovery', 'insights', 'documentation', 'specification',
62
+ 'requirements', 'use case', 'user story', 'business logic',
63
+ 'domain knowledge', 'best practices', 'standards', 'compliance',
64
+ 'security', 'vulnerability', 'threat', 'risk'
65
+ ],
66
+ 'sections': [
67
+ 'Domain-Specific Knowledge', 'Research Findings',
68
+ 'Security Considerations', 'Compliance Requirements'
69
+ ]
70
+ },
71
+ 'qa': {
72
+ 'keywords': [
73
+ 'test', 'testing', 'quality', 'bug', 'defect', 'issue', 'validation',
74
+ 'verification', 'quality assurance', 'test case', 'test plan',
75
+ 'coverage', 'automation', 'regression', 'smoke test', 'acceptance',
76
+ 'criteria', 'checklist', 'review', 'audit', 'compliance',
77
+ 'standards', 'metrics', 'measurement'
78
+ ],
79
+ 'sections': [
80
+ 'Quality Standards', 'Testing Strategies',
81
+ 'Common Issues Found', 'Verification Patterns'
82
+ ]
83
+ },
84
+ 'documentation': {
85
+ 'keywords': [
86
+ 'document', 'documentation', 'readme', 'guide', 'manual', 'help',
87
+ 'instructions', 'tutorial', 'explanation', 'description', 'overview',
88
+ 'summary', 'specification', 'reference', 'glossary', 'faq',
89
+ 'examples', 'usage', 'howto', 'walkthrough'
90
+ ],
91
+ 'sections': [
92
+ 'Documentation Patterns', 'User Guide Standards',
93
+ 'Content Organization', 'Writing Guidelines'
94
+ ]
95
+ },
96
+ 'security': {
97
+ 'keywords': [
98
+ 'security', 'authentication', 'authorization', 'encryption', 'decrypt',
99
+ 'password', 'token', 'certificate', 'ssl', 'tls', 'vulnerability',
100
+ 'exploit', 'attack', 'malware', 'virus', 'firewall', 'access control',
101
+ 'permissions', 'privilege', 'audit', 'compliance', 'privacy',
102
+ 'data protection', 'gdpr', 'sensitive data'
103
+ ],
104
+ 'sections': [
105
+ 'Security Patterns', 'Threat Analysis',
106
+ 'Compliance Requirements', 'Access Control Patterns'
107
+ ]
108
+ },
109
+ 'pm': {
110
+ 'keywords': [
111
+ 'project', 'management', 'coordination', 'planning', 'schedule',
112
+ 'timeline', 'milestone', 'deliverable', 'stakeholder', 'requirement',
113
+ 'priority', 'resource', 'allocation', 'budget', 'scope', 'risk',
114
+ 'communication', 'meeting', 'status', 'progress', 'workflow',
115
+ 'process', 'methodology', 'agile', 'scrum', 'kanban'
116
+ ],
117
+ 'sections': [
118
+ 'Project Coordination', 'Team Communication',
119
+ 'Process Improvements', 'Risk Management'
120
+ ]
121
+ }
122
+ }
123
+
124
+ # Default agent for unmatched content
125
+ DEFAULT_AGENT = 'pm'
126
+
127
+ def __init__(self, config: Optional[Config] = None):
128
+ """Initialize the memory router.
129
+
130
+ Args:
131
+ config: Optional Config object
132
+ """
133
+ super().__init__()
134
+ self.config = config or Config()
135
+
136
+ def analyze_and_route(self, content: str, context: Optional[Dict] = None) -> Dict[str, Any]:
137
+ """Analyze content and determine target agent for memory storage.
138
+
139
+ WHY: Different types of information belong to different agents. This method
140
+ analyzes content using keyword patterns and context to make intelligent
141
+ routing decisions.
142
+
143
+ Args:
144
+ content: The content to be remembered
145
+ context: Optional context for routing decisions
146
+
147
+ Returns:
148
+ Dict containing routing decision and reasoning
149
+ """
150
+ try:
151
+ # Clean and normalize content for analysis
152
+ normalized_content = self._normalize_content(content)
153
+
154
+ # Analyze content for agent patterns
155
+ agent_scores = self._calculate_agent_scores(normalized_content)
156
+
157
+ # Apply context-based adjustments
158
+ if context:
159
+ agent_scores = self._apply_context_adjustments(agent_scores, context)
160
+
161
+ # Select target agent
162
+ target_agent, confidence = self._select_target_agent(agent_scores)
163
+
164
+ # Determine appropriate section
165
+ section = self._determine_section(target_agent, normalized_content)
166
+
167
+ # Build reasoning
168
+ reasoning = self._build_reasoning(target_agent, agent_scores, section, context)
169
+
170
+ result = {
171
+ "target_agent": target_agent,
172
+ "section": section,
173
+ "confidence": confidence,
174
+ "reasoning": reasoning,
175
+ "agent_scores": agent_scores,
176
+ "timestamp": datetime.now().isoformat(),
177
+ "content_length": len(content)
178
+ }
179
+
180
+ self.logger.debug(f"Routed content to {target_agent} with confidence {confidence}")
181
+ return result
182
+
183
+ except Exception as e:
184
+ self.logger.error(f"Error analyzing content for routing: {e}")
185
+ return {
186
+ "target_agent": self.DEFAULT_AGENT,
187
+ "section": "Recent Learnings",
188
+ "confidence": 0.1,
189
+ "reasoning": f"Error during analysis, defaulting to {self.DEFAULT_AGENT}",
190
+ "error": str(e)
191
+ }
192
+
193
+ def test_routing_patterns(self, test_cases: List[Dict[str, str]]) -> List[Dict[str, Any]]:
194
+ """Test routing logic with provided test cases.
195
+
196
+ WHY: Routing patterns need validation to ensure they work correctly.
197
+ This method allows testing of routing logic with known inputs.
198
+
199
+ Args:
200
+ test_cases: List of test cases with 'content' and optional 'expected_agent'
201
+
202
+ Returns:
203
+ List of routing results for each test case
204
+ """
205
+ results = []
206
+
207
+ for i, test_case in enumerate(test_cases):
208
+ content = test_case.get('content', '')
209
+ expected = test_case.get('expected_agent')
210
+
211
+ routing_result = self.analyze_and_route(content)
212
+
213
+ test_result = {
214
+ "test_case": i + 1,
215
+ "content": content[:100] + "..." if len(content) > 100 else content,
216
+ "expected_agent": expected,
217
+ "actual_agent": routing_result['target_agent'],
218
+ "confidence": routing_result['confidence'],
219
+ "correct": expected == routing_result['target_agent'] if expected else None,
220
+ "reasoning": routing_result['reasoning']
221
+ }
222
+
223
+ results.append(test_result)
224
+
225
+ return results
226
+
227
+ def get_routing_patterns(self) -> Dict[str, Any]:
228
+ """Get current routing patterns and statistics.
229
+
230
+ WHY: Users and developers need to understand how routing works and
231
+ potentially customize patterns for their specific use cases.
232
+
233
+ Returns:
234
+ Dict containing routing patterns and statistics
235
+ """
236
+ return {
237
+ "agents": list(self.AGENT_PATTERNS.keys()),
238
+ "default_agent": self.DEFAULT_AGENT,
239
+ "patterns": {
240
+ agent: {
241
+ "keyword_count": len(patterns['keywords']),
242
+ "section_count": len(patterns['sections']),
243
+ "keywords": patterns['keywords'][:10], # Show first 10
244
+ "sections": patterns['sections']
245
+ }
246
+ for agent, patterns in self.AGENT_PATTERNS.items()
247
+ },
248
+ "total_keywords": sum(len(p['keywords']) for p in self.AGENT_PATTERNS.values())
249
+ }
250
+
251
+ def _normalize_content(self, content: str) -> str:
252
+ """Normalize content for analysis.
253
+
254
+ Args:
255
+ content: Raw content
256
+
257
+ Returns:
258
+ Normalized content string
259
+ """
260
+ # Convert to lowercase and remove extra whitespace
261
+ normalized = re.sub(r'\s+', ' ', content.lower().strip())
262
+
263
+ # Remove common noise words that don't help with routing
264
+ noise_words = ['the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by']
265
+ words = normalized.split()
266
+ filtered_words = [w for w in words if w not in noise_words and len(w) > 2]
267
+
268
+ return ' '.join(filtered_words)
269
+
270
+ def _calculate_agent_scores(self, content: str) -> Dict[str, float]:
271
+ """Calculate relevance scores for each agent.
272
+
273
+ Args:
274
+ content: Normalized content
275
+
276
+ Returns:
277
+ Dict mapping agent names to relevance scores
278
+ """
279
+ scores = {}
280
+
281
+ for agent, patterns in self.AGENT_PATTERNS.items():
282
+ score = 0.0
283
+ matched_keywords = []
284
+
285
+ for keyword in patterns['keywords']:
286
+ # Exact keyword match
287
+ if keyword in content:
288
+ score += 1.0
289
+ matched_keywords.append(keyword)
290
+ # Partial match (word contains keyword)
291
+ elif any(keyword in word for word in content.split()):
292
+ score += 0.5
293
+
294
+ # Normalize score by number of keywords for this agent
295
+ if patterns['keywords']:
296
+ score = score / len(patterns['keywords'])
297
+
298
+ scores[agent] = {
299
+ 'score': score,
300
+ 'matched_keywords': matched_keywords[:5], # Limit for readability
301
+ 'match_count': len(matched_keywords)
302
+ }
303
+
304
+ return scores
305
+
306
+ def _apply_context_adjustments(self, agent_scores: Dict[str, Any], context: Dict) -> Dict[str, Any]:
307
+ """Apply context-based adjustments to agent scores.
308
+
309
+ Args:
310
+ agent_scores: Current agent scores
311
+ context: Context information
312
+
313
+ Returns:
314
+ Adjusted agent scores
315
+ """
316
+ # Context hints for routing
317
+ if 'agent_hint' in context:
318
+ hint = context['agent_hint'].lower()
319
+ if hint in agent_scores:
320
+ agent_scores[hint]['score'] += 0.3
321
+ agent_scores[hint]['context_boost'] = True
322
+
323
+ # Task type hints
324
+ if 'task_type' in context:
325
+ task_type = context['task_type'].lower()
326
+ task_mappings = {
327
+ 'implementation': 'engineer',
328
+ 'coding': 'engineer',
329
+ 'analysis': 'research',
330
+ 'testing': 'qa',
331
+ 'documentation': 'documentation',
332
+ 'security': 'security',
333
+ 'planning': 'pm'
334
+ }
335
+
336
+ if task_type in task_mappings:
337
+ target_agent = task_mappings[task_type]
338
+ if target_agent in agent_scores:
339
+ agent_scores[target_agent]['score'] += 0.2
340
+ agent_scores[target_agent]['task_type_boost'] = True
341
+
342
+ return agent_scores
343
+
344
+ def _select_target_agent(self, agent_scores: Dict[str, Any]) -> Tuple[str, float]:
345
+ """Select target agent based on scores.
346
+
347
+ Args:
348
+ agent_scores: Agent relevance scores
349
+
350
+ Returns:
351
+ Tuple of (target_agent, confidence)
352
+ """
353
+ # Find agent with highest score
354
+ best_agent = self.DEFAULT_AGENT
355
+ best_score = 0.0
356
+
357
+ for agent, score_data in agent_scores.items():
358
+ score = score_data['score']
359
+ if score > best_score:
360
+ best_score = score
361
+ best_agent = agent
362
+
363
+ # If no clear winner, use default
364
+ if best_score < 0.1:
365
+ return self.DEFAULT_AGENT, 0.1
366
+
367
+ # Convert score to confidence (0.0 to 1.0)
368
+ confidence = min(1.0, best_score * 2) # Scale up for better confidence values
369
+
370
+ return best_agent, confidence
371
+
372
+ def _determine_section(self, agent: str, content: str) -> str:
373
+ """Determine appropriate section for the content.
374
+
375
+ Args:
376
+ agent: Target agent
377
+ content: Normalized content
378
+
379
+ Returns:
380
+ Section name for memory storage
381
+ """
382
+ if agent not in self.AGENT_PATTERNS:
383
+ return "Recent Learnings"
384
+
385
+ sections = self.AGENT_PATTERNS[agent]['sections']
386
+
387
+ # Simple heuristics for section selection
388
+ if 'mistake' in content or 'error' in content or 'avoid' in content:
389
+ return 'Common Mistakes to Avoid'
390
+ elif 'pattern' in content or 'architecture' in content:
391
+ return sections[0] if sections else 'Recent Learnings' # First section is usually patterns
392
+ elif 'guideline' in content or 'standard' in content:
393
+ return 'Implementation Guidelines'
394
+ elif 'context' in content or 'current' in content:
395
+ return 'Current Technical Context'
396
+ else:
397
+ # Default to first available section or Recent Learnings
398
+ return sections[0] if sections else 'Recent Learnings'
399
+
400
+ def _build_reasoning(self, target_agent: str, agent_scores: Dict[str, Any],
401
+ section: str, context: Optional[Dict]) -> str:
402
+ """Build human-readable reasoning for routing decision.
403
+
404
+ Args:
405
+ target_agent: Selected target agent
406
+ agent_scores: All agent scores
407
+ section: Selected section
408
+ context: Optional context
409
+
410
+ Returns:
411
+ Human-readable reasoning string
412
+ """
413
+ if target_agent not in agent_scores:
414
+ return f"Defaulted to {target_agent} agent due to analysis error"
415
+
416
+ score_data = agent_scores[target_agent]
417
+ score = score_data['score']
418
+ matched_keywords = score_data.get('matched_keywords', [])
419
+
420
+ reasoning_parts = []
421
+
422
+ # Primary reasoning
423
+ if score > 0.3:
424
+ reasoning_parts.append(f"Strong match for {target_agent} agent")
425
+ elif score > 0.1:
426
+ reasoning_parts.append(f"Moderate match for {target_agent} agent")
427
+ else:
428
+ reasoning_parts.append(f"Weak match, defaulting to {target_agent} agent")
429
+
430
+ # Keyword evidence
431
+ if matched_keywords:
432
+ keyword_str = ", ".join(matched_keywords)
433
+ reasoning_parts.append(f"matched keywords: {keyword_str}")
434
+
435
+ # Context boosts
436
+ if score_data.get('context_boost'):
437
+ reasoning_parts.append("boosted by context hint")
438
+ if score_data.get('task_type_boost'):
439
+ reasoning_parts.append("boosted by task type")
440
+
441
+ # Section selection
442
+ if section != "Recent Learnings":
443
+ reasoning_parts.append(f"assigned to '{section}' section")
444
+
445
+ return "; ".join(reasoning_parts).capitalize()