claude-mpm 3.5.2__py3-none-any.whl → 3.5.6__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 (53) hide show
  1. claude_mpm/.claude-mpm/logs/hooks_20250728.log +10 -0
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/agents/INSTRUCTIONS.md +14 -13
  4. claude_mpm/agents/agent-template.yaml +83 -0
  5. claude_mpm/agents/agent_loader.py +109 -15
  6. claude_mpm/agents/base_agent.json +1 -1
  7. claude_mpm/agents/frontmatter_validator.py +448 -0
  8. claude_mpm/agents/templates/data_engineer.json +4 -3
  9. claude_mpm/agents/templates/documentation.json +4 -3
  10. claude_mpm/agents/templates/engineer.json +4 -3
  11. claude_mpm/agents/templates/ops.json +4 -3
  12. claude_mpm/agents/templates/pm.json +5 -4
  13. claude_mpm/agents/templates/qa.json +4 -3
  14. claude_mpm/agents/templates/research.json +8 -7
  15. claude_mpm/agents/templates/security.json +4 -3
  16. claude_mpm/agents/templates/test_integration.json +4 -3
  17. claude_mpm/agents/templates/version_control.json +4 -3
  18. claude_mpm/cli/README.md +108 -0
  19. claude_mpm/cli/commands/agents.py +373 -7
  20. claude_mpm/cli/commands/run.py +4 -11
  21. claude_mpm/cli/parser.py +36 -0
  22. claude_mpm/cli/utils.py +9 -1
  23. claude_mpm/cli_module/refactoring_guide.md +253 -0
  24. claude_mpm/config/async_logging_config.yaml +145 -0
  25. claude_mpm/constants.py +2 -0
  26. claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
  27. claude_mpm/core/agent_registry.py +4 -1
  28. claude_mpm/core/claude_runner.py +297 -20
  29. claude_mpm/core/config_paths.py +0 -1
  30. claude_mpm/core/factories.py +9 -3
  31. claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
  32. claude_mpm/dashboard/README.md +121 -0
  33. claude_mpm/dashboard/static/js/dashboard.js.backup +1973 -0
  34. claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
  35. claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
  36. claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
  37. claude_mpm/hooks/README.md +96 -0
  38. claude_mpm/init.py +83 -13
  39. claude_mpm/schemas/agent_schema.json +435 -0
  40. claude_mpm/services/agents/deployment/agent_deployment.py +204 -18
  41. claude_mpm/services/agents/management/agent_management_service.py +2 -1
  42. claude_mpm/services/agents/registry/agent_registry.py +22 -1
  43. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  44. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +3 -3
  45. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +2 -2
  46. claude_mpm/services/version_control/VERSION +1 -0
  47. claude_mpm/validation/agent_validator.py +56 -1
  48. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/METADATA +60 -3
  49. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/RECORD +53 -36
  50. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/WHEEL +0 -0
  51. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/entry_points.txt +0 -0
  52. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/licenses/LICENSE +0 -0
  53. {claude_mpm-3.5.2.dist-info → claude_mpm-3.5.6.dist-info}/top_level.txt +0 -0
@@ -74,8 +74,16 @@ class ClaudeRunner:
74
74
  self.logger.warning(f"Failed to initialize project logger: {e}")
75
75
 
76
76
  # Initialize services with proper error handling
77
+ # Determine the user's working directory from environment
78
+ user_working_dir = None
79
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
80
+ user_working_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
81
+ self.logger.info(f"Using user working directory from CLAUDE_MPM_USER_PWD: {user_working_dir}")
82
+
77
83
  try:
78
- self.deployment_service = AgentDeploymentService()
84
+ # Pass the user working directory to the deployment service
85
+ # This ensures agents are deployed to the correct user directory, not the framework directory
86
+ self.deployment_service = AgentDeploymentService(working_directory=user_working_dir)
79
87
  except ImportError as e:
80
88
  self.logger.error(f"Failed to import AgentDeploymentService: {e}")
81
89
  raise RuntimeError("Required module AgentDeploymentService not available. Please reinstall claude-mpm.") from e
@@ -110,6 +118,22 @@ class ClaudeRunner:
110
118
  self.logger.error(f"Failed to load configuration: {e}")
111
119
  raise RuntimeError(f"Configuration initialization failed: {e}") from e
112
120
 
121
+ # Initialize response logging if enabled
122
+ self.response_logger = None
123
+ response_config = self.config.get('response_logging', {})
124
+ if response_config.get('enabled', False):
125
+ try:
126
+ from claude_mpm.services.claude_session_logger import get_session_logger
127
+ self.response_logger = get_session_logger(self.config)
128
+ if self.project_logger:
129
+ self.project_logger.log_system(
130
+ "Response logging initialized",
131
+ level="INFO",
132
+ component="logging"
133
+ )
134
+ except Exception as e:
135
+ self.logger.warning(f"Failed to initialize response logger: {e}")
136
+
113
137
  # Initialize hook service
114
138
  try:
115
139
  self.hook_service = HookService(self.config)
@@ -199,7 +223,7 @@ class ClaudeRunner:
199
223
  return False
200
224
 
201
225
  except FileNotFoundError as e:
202
- error_msg = f"Agent templates not found: {e}"
226
+ error_msg = f"Agent files not found: {e}"
203
227
  self.logger.error(error_msg)
204
228
  print(f"❌ {error_msg}")
205
229
  print("💡 Ensure claude-mpm is properly installed")
@@ -228,16 +252,21 @@ class ClaudeRunner:
228
252
  def ensure_project_agents(self) -> bool:
229
253
  """Ensure system agents are available in the project directory.
230
254
 
231
- Deploys system agents to project's .claude-mpm/agents/ directory
232
- if they don't exist or are outdated. This enables project-level
233
- agent customization and ensures all agents are available locally.
255
+ Deploys system agents to project's .claude/agents/ directory
256
+ if they don't exist or are outdated. This ensures agents are
257
+ available for Claude Code to use. Project-specific JSON templates
258
+ should be placed in .claude-mpm/agents/.
234
259
 
235
260
  Returns:
236
261
  bool: True if agents are available, False on error
237
262
  """
238
263
  try:
239
- # Check if we're in a project directory
240
- project_dir = Path.cwd()
264
+ # Use the correct user directory, not the framework directory
265
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
266
+ project_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
267
+ else:
268
+ project_dir = Path.cwd()
269
+
241
270
  project_agents_dir = project_dir / ".claude-mpm" / "agents"
242
271
 
243
272
  # Create directory if it doesn't exist
@@ -250,10 +279,12 @@ class ClaudeRunner:
250
279
  component="deployment"
251
280
  )
252
281
 
253
- # Deploy agents to project directory with project deployment mode
282
+ # Deploy agents to project's .claude/agents directory (not .claude-mpm)
254
283
  # This ensures all system agents are deployed regardless of version
284
+ # .claude-mpm/agents/ should only contain JSON source templates
285
+ # .claude/agents/ should contain the built MD files for Claude Code
255
286
  results = self.deployment_service.deploy_agents(
256
- target_dir=project_dir / ".claude-mpm",
287
+ target_dir=project_dir / ".claude",
257
288
  force_rebuild=False,
258
289
  deployment_mode="project"
259
290
  )
@@ -286,8 +317,164 @@ class ClaudeRunner:
286
317
  )
287
318
  return False
288
319
 
320
+ def deploy_project_agents_to_claude(self) -> bool:
321
+ """Deploy project agents from .claude-mpm/agents/ to .claude/agents/.
322
+
323
+ This method handles the deployment of project-specific agents (JSON format)
324
+ from the project's agents directory to Claude's agent directory.
325
+ Project agents take precedence over system agents.
326
+
327
+ WHY: Project agents allow teams to define custom, project-specific agents
328
+ that override system agents. These are stored in JSON format in
329
+ .claude-mpm/agents/ and need to be deployed to .claude/agents/
330
+ as MD files for Claude to use them.
331
+
332
+ Returns:
333
+ bool: True if deployment successful or no agents to deploy, False on error
334
+ """
335
+ try:
336
+ # Use the correct user directory, not the framework directory
337
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
338
+ project_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
339
+ else:
340
+ project_dir = Path.cwd()
341
+
342
+ project_agents_dir = project_dir / ".claude-mpm" / "agents"
343
+ claude_agents_dir = project_dir / ".claude" / "agents"
344
+
345
+ # Check if project agents directory exists
346
+ if not project_agents_dir.exists():
347
+ self.logger.debug("No project agents directory found")
348
+ return True # Not an error - just no project agents
349
+
350
+ # Get JSON agent files from agents directory
351
+ json_files = list(project_agents_dir.glob("*.json"))
352
+ if not json_files:
353
+ self.logger.debug("No JSON agents in project")
354
+ return True
355
+
356
+ # Create .claude/agents directory if needed
357
+ claude_agents_dir.mkdir(parents=True, exist_ok=True)
358
+
359
+ self.logger.info(f"Deploying {len(json_files)} project agents to .claude/agents/")
360
+ if self.project_logger:
361
+ self.project_logger.log_system(
362
+ f"Deploying project agents from {project_agents_dir} to {claude_agents_dir}",
363
+ level="INFO",
364
+ component="deployment"
365
+ )
366
+
367
+ deployed_count = 0
368
+ updated_count = 0
369
+ errors = []
370
+
371
+ # Deploy each JSON agent
372
+ # CRITICAL: PM (Project Manager) must NEVER be deployed as it's the main Claude instance
373
+ EXCLUDED_AGENTS = {'pm', 'project_manager'}
374
+
375
+ # Initialize deployment service with proper base agent path
376
+ # Use the existing deployment service's base agent path if available
377
+ base_agent_path = project_agents_dir / "base_agent.json"
378
+ if not base_agent_path.exists():
379
+ # Fall back to system base agent
380
+ base_agent_path = self.deployment_service.base_agent_path
381
+
382
+ # Create a single deployment service instance for all agents
383
+ project_deployment = AgentDeploymentService(
384
+ templates_dir=project_agents_dir,
385
+ base_agent_path=base_agent_path,
386
+ working_directory=project_dir # Pass the project directory
387
+ )
388
+
389
+ # Load base agent data once
390
+ base_agent_data = {}
391
+ if base_agent_path and base_agent_path.exists():
392
+ try:
393
+ import json
394
+ base_agent_data = json.loads(base_agent_path.read_text())
395
+ except Exception as e:
396
+ self.logger.warning(f"Could not load base agent: {e}")
397
+
398
+ for json_file in json_files:
399
+ try:
400
+ agent_name = json_file.stem
401
+
402
+ # Skip PM agent - it's the main Claude instance, not a subagent
403
+ if agent_name.lower() in EXCLUDED_AGENTS:
404
+ self.logger.info(f"Skipping {agent_name} (PM is the main Claude instance)")
405
+ continue
406
+
407
+ target_file = claude_agents_dir / f"{agent_name}.md"
408
+
409
+ # Check if agent needs update
410
+ needs_update = True
411
+ if target_file.exists():
412
+ # Check if it's a project agent (has project marker)
413
+ existing_content = target_file.read_text()
414
+ if "author: claude-mpm-project" in existing_content or "source: project" in existing_content:
415
+ # Compare modification times
416
+ if target_file.stat().st_mtime >= json_file.stat().st_mtime:
417
+ needs_update = False
418
+ self.logger.debug(f"Project agent {agent_name} is up to date")
419
+
420
+ if needs_update:
421
+ # Build the agent markdown using the pre-initialized service and base agent data
422
+ agent_content = project_deployment._build_agent_markdown(
423
+ agent_name, json_file, base_agent_data
424
+ )
425
+
426
+ # Mark as project agent
427
+ agent_content = agent_content.replace(
428
+ "author: claude-mpm",
429
+ "author: claude-mpm-project"
430
+ )
431
+
432
+ # Write the agent file
433
+ is_update = target_file.exists()
434
+ target_file.write_text(agent_content)
435
+
436
+ if is_update:
437
+ updated_count += 1
438
+ self.logger.info(f"Updated project agent: {agent_name}")
439
+ else:
440
+ deployed_count += 1
441
+ self.logger.info(f"Deployed project agent: {agent_name}")
442
+
443
+ except Exception as e:
444
+ error_msg = f"Failed to deploy project agent {json_file.name}: {e}"
445
+ self.logger.error(error_msg)
446
+ errors.append(error_msg)
447
+
448
+ # Report results
449
+ if deployed_count > 0 or updated_count > 0:
450
+ print(f"✓ Deployed {deployed_count} project agents, updated {updated_count}")
451
+ if self.project_logger:
452
+ self.project_logger.log_system(
453
+ f"Project agent deployment: {deployed_count} deployed, {updated_count} updated",
454
+ level="INFO",
455
+ component="deployment"
456
+ )
457
+
458
+ if errors:
459
+ for error in errors:
460
+ print(f"⚠️ {error}")
461
+ return False
462
+
463
+ return True
464
+
465
+ except Exception as e:
466
+ error_msg = f"Failed to deploy project agents: {e}"
467
+ self.logger.error(error_msg)
468
+ print(f"⚠️ {error_msg}")
469
+ if self.project_logger:
470
+ self.project_logger.log_system(error_msg, level="ERROR", component="deployment")
471
+ return False
472
+
289
473
  def run_interactive(self, initial_context: Optional[str] = None):
290
474
  """Run Claude in interactive mode."""
475
+ # TODO: Add response logging for interactive mode
476
+ # This requires capturing stdout from the exec'd process or using subprocess with PTY
477
+
291
478
  # Connect to Socket.IO server if enabled
292
479
  if self.enable_websocket:
293
480
  try:
@@ -336,10 +523,13 @@ class ClaudeRunner:
336
523
  component="session"
337
524
  )
338
525
 
339
- # Setup agents
526
+ # Setup agents - first deploy system agents, then project agents
340
527
  if not self.setup_agents():
341
528
  print("Continuing without native agents...")
342
529
 
530
+ # Deploy project-specific agents if they exist
531
+ self.deploy_project_agents_to_claude()
532
+
343
533
  # Build command with system instructions
344
534
  cmd = [
345
535
  "claude",
@@ -587,10 +777,13 @@ class ClaudeRunner:
587
777
  component="session"
588
778
  )
589
779
 
590
- # Setup agents
780
+ # Setup agents - first deploy system agents, then project agents
591
781
  if not self.setup_agents():
592
782
  print("Continuing without native agents...")
593
783
 
784
+ # Deploy project-specific agents if they exist
785
+ self.deploy_project_agents_to_claude()
786
+
594
787
  # Combine context and prompt
595
788
  full_prompt = prompt
596
789
  if context:
@@ -671,6 +864,22 @@ class ClaudeRunner:
671
864
  response = result.stdout.strip()
672
865
  print(response)
673
866
 
867
+ # Log response if logging enabled
868
+ if self.response_logger and response:
869
+ execution_time = time.time() - start_time
870
+ response_summary = prompt[:200] + "..." if len(prompt) > 200 else prompt
871
+ self.response_logger.log_response(
872
+ request_summary=response_summary,
873
+ response_content=response,
874
+ metadata={
875
+ "mode": "oneshot",
876
+ "model": "opus",
877
+ "exit_code": result.returncode,
878
+ "execution_time": execution_time
879
+ },
880
+ agent="claude-direct"
881
+ )
882
+
674
883
  # Broadcast output to WebSocket clients
675
884
  if self.websocket_server and response:
676
885
  self.websocket_server.claude_output(response, "stdout")
@@ -884,17 +1093,46 @@ class ClaudeRunner:
884
1093
  def _load_system_instructions(self) -> Optional[str]:
885
1094
  """Load and process system instructions from agents/INSTRUCTIONS.md.
886
1095
 
887
- WHY: Process template variables like {{capabilities-list}} to include
888
- dynamic agent capabilities in the PM's system instructions.
1096
+ Implements project > framework precedence:
1097
+ 1. First check for project-specific instructions in .claude-mpm/agents/INSTRUCTIONS.md
1098
+ 2. If not found, fall back to framework instructions in src/claude_mpm/agents/INSTRUCTIONS.md
1099
+
1100
+ WHY: Allows projects to override the default PM instructions with project-specific
1101
+ guidance, while maintaining backward compatibility with the framework defaults.
1102
+
1103
+ DESIGN DECISION: Using CLAUDE_MPM_USER_PWD environment variable to locate the
1104
+ correct project directory, ensuring we check the right location even when
1105
+ claude-mpm is invoked from a different directory.
889
1106
  """
890
1107
  try:
891
- # Find the INSTRUCTIONS.md file
892
- module_path = Path(__file__).parent.parent
893
- instructions_path = module_path / "agents" / "INSTRUCTIONS.md"
1108
+ # Determine the user's project directory
1109
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
1110
+ project_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
1111
+ else:
1112
+ project_dir = Path.cwd()
894
1113
 
895
- if not instructions_path.exists():
896
- self.logger.warning(f"System instructions not found: {instructions_path}")
897
- return None
1114
+ # Check for project-specific INSTRUCTIONS.md first
1115
+ project_instructions_path = project_dir / ".claude-mpm" / "agents" / "INSTRUCTIONS.md"
1116
+
1117
+ instructions_path = None
1118
+ instructions_source = None
1119
+
1120
+ if project_instructions_path.exists():
1121
+ instructions_path = project_instructions_path
1122
+ instructions_source = "PROJECT"
1123
+ self.logger.info(f"Found project-specific INSTRUCTIONS.md: {instructions_path}")
1124
+ else:
1125
+ # Fall back to framework instructions
1126
+ module_path = Path(__file__).parent.parent
1127
+ framework_instructions_path = module_path / "agents" / "INSTRUCTIONS.md"
1128
+
1129
+ if framework_instructions_path.exists():
1130
+ instructions_path = framework_instructions_path
1131
+ instructions_source = "FRAMEWORK"
1132
+ self.logger.info(f"Using framework INSTRUCTIONS.md: {instructions_path}")
1133
+ else:
1134
+ self.logger.warning(f"No INSTRUCTIONS.md found in project or framework")
1135
+ return None
898
1136
 
899
1137
  # Read raw instructions
900
1138
  raw_instructions = instructions_path.read_text()
@@ -904,13 +1142,15 @@ class ClaudeRunner:
904
1142
  from claude_mpm.services.framework_claude_md_generator.content_assembler import ContentAssembler
905
1143
  assembler = ContentAssembler()
906
1144
  processed_instructions = assembler.apply_template_variables(raw_instructions)
907
- self.logger.info("Loaded and processed PM framework system instructions with dynamic capabilities")
1145
+ self.logger.info(f"Loaded and processed {instructions_source} PM instructions with dynamic capabilities")
908
1146
  return processed_instructions
909
1147
  except ImportError:
910
1148
  self.logger.warning("ContentAssembler not available, using raw instructions")
1149
+ self.logger.info(f"Loaded {instructions_source} PM instructions (raw)")
911
1150
  return raw_instructions
912
1151
  except Exception as e:
913
1152
  self.logger.warning(f"Failed to process template variables: {e}, using raw instructions")
1153
+ self.logger.info(f"Loaded {instructions_source} PM instructions (raw, processing failed)")
914
1154
  return raw_instructions
915
1155
 
916
1156
  except Exception as e:
@@ -1185,6 +1425,10 @@ class ClaudeRunner:
1185
1425
  import tty
1186
1426
  import signal
1187
1427
 
1428
+ # Collect output for response logging if enabled
1429
+ collected_output = [] if self.response_logger else None
1430
+ collected_input = [] if self.response_logger else None
1431
+
1188
1432
  # Save original terminal settings
1189
1433
  original_tty = None
1190
1434
  if sys.stdin.isatty():
@@ -1247,6 +1491,13 @@ class ClaudeRunner:
1247
1491
  data = os.read(master_fd, 4096)
1248
1492
  if data:
1249
1493
  os.write(sys.stdout.fileno(), data)
1494
+ # Collect output for response logging
1495
+ if collected_output is not None:
1496
+ try:
1497
+ output_text = data.decode('utf-8', errors='replace')
1498
+ collected_output.append(output_text)
1499
+ except Exception:
1500
+ pass
1250
1501
  # Broadcast output to WebSocket clients
1251
1502
  if self.websocket_server:
1252
1503
  try:
@@ -1265,12 +1516,38 @@ class ClaudeRunner:
1265
1516
  data = os.read(sys.stdin.fileno(), 4096)
1266
1517
  if data:
1267
1518
  os.write(master_fd, data)
1519
+ # Collect input for response logging
1520
+ if collected_input is not None:
1521
+ try:
1522
+ input_text = data.decode('utf-8', errors='replace')
1523
+ collected_input.append(input_text)
1524
+ except Exception:
1525
+ pass
1268
1526
  except OSError:
1269
1527
  break
1270
1528
 
1271
1529
  # Wait for process to complete
1272
1530
  process.wait()
1273
1531
 
1532
+ # Log the interactive session if response logging is enabled
1533
+ if self.response_logger and collected_output is not None and collected_output:
1534
+ try:
1535
+ full_output = ''.join(collected_output)
1536
+ full_input = ''.join(collected_input) if collected_input else "Interactive session"
1537
+ self.response_logger.log_response(
1538
+ request_summary=f"Interactive session: {full_input[:200]}..." if len(full_input) > 200 else f"Interactive session: {full_input}",
1539
+ response_content=full_output,
1540
+ metadata={
1541
+ "mode": "interactive-subprocess",
1542
+ "model": "opus",
1543
+ "exit_code": process.returncode,
1544
+ "session_type": "subprocess"
1545
+ },
1546
+ agent="claude-interactive"
1547
+ )
1548
+ except Exception as e:
1549
+ self.logger.debug(f"Failed to log interactive session: {e}")
1550
+
1274
1551
  if self.project_logger:
1275
1552
  self.project_logger.log_system(
1276
1553
  f"Claude subprocess exited with code {process.returncode}",
@@ -35,7 +35,6 @@ class ConfigPaths:
35
35
  RESPONSES_DIR = "responses"
36
36
 
37
37
  # Agent subdirectories
38
- AGENT_PROJECT_SPECIFIC = "project-specific"
39
38
  AGENT_USER_AGENTS = "user-agents"
40
39
  AGENT_USER_DEFINED = "user-defined"
41
40
  AGENT_SYSTEM = "templates"
@@ -57,14 +57,20 @@ class AgentServiceFactory(ServiceFactory):
57
57
  config = container.resolve(Config)
58
58
 
59
59
  # Get directories from config if not provided
60
+ import os
61
+
60
62
  if framework_dir is None:
61
63
  framework_dir = Path(config.get('framework.dir', 'framework'))
62
64
 
63
65
  if project_dir is None:
64
- project_dir = Path(config.get('project.dir', '.'))
66
+ # Check for user working directory from environment
67
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
68
+ project_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
69
+ else:
70
+ project_dir = Path(config.get('project.dir', '.'))
65
71
 
66
- # Create service with dependencies
67
- service = AgentDeploymentService()
72
+ # Create service with proper working directory
73
+ service = AgentDeploymentService(working_directory=project_dir)
68
74
 
69
75
  # Inject any required dependencies
70
76
  if hasattr(service, 'set_directories'):
@@ -0,0 +1,36 @@
1
+ # Agent Memory System
2
+
3
+ ## Purpose
4
+ Each agent maintains project-specific knowledge in these files. Agents read their memory file before tasks and update it when they learn something new.
5
+
6
+ ## Manual Editing
7
+ Feel free to edit these files to:
8
+ - Add project-specific guidelines
9
+ - Remove outdated information
10
+ - Reorganize for better clarity
11
+ - Add domain-specific knowledge
12
+
13
+ ## Memory Limits
14
+ - Max file size: 8KB (~2000 tokens)
15
+ - Max sections: 10
16
+ - Max items per section: 15
17
+ - Files auto-truncate when limits exceeded
18
+
19
+ ## File Format
20
+ Standard markdown with structured sections. Agents expect:
21
+ - Project Architecture
22
+ - Implementation Guidelines
23
+ - Common Mistakes to Avoid
24
+ - Current Technical Context
25
+
26
+ ## How It Works
27
+ 1. Agents read their memory file before starting tasks
28
+ 2. Agents add learnings during or after task completion
29
+ 3. Files automatically enforce size limits
30
+ 4. Developers can manually edit for accuracy
31
+
32
+ ## Memory File Lifecycle
33
+ - Created automatically when agent first runs
34
+ - Updated through hook system after delegations
35
+ - Manually editable by developers
36
+ - Version controlled with project
@@ -0,0 +1,121 @@
1
+ # Claude MPM Web Dashboard
2
+
3
+ This directory contains the modular web dashboard for Claude MPM monitoring and management.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ src/claude_mpm/dashboard/
9
+ ├── static/
10
+ │ ├── css/
11
+ │ │ └── dashboard.css # Main stylesheet
12
+ │ └── js/
13
+ │ ├── socket-client.js # Socket.IO connection management
14
+ │ ├── dashboard.js # Main dashboard application
15
+ │ └── components/
16
+ │ ├── event-viewer.js # Event display and filtering
17
+ │ ├── module-viewer.js # Event detail viewer
18
+ │ └── session-manager.js # Session management
19
+ ├── templates/
20
+ │ └── index.html # Main dashboard HTML
21
+ ├── index.html # Root index with redirect
22
+ ├── test_dashboard.html # Test version for verification
23
+ └── README.md # This file
24
+ ```
25
+
26
+ ## Components
27
+
28
+ ### SocketClient (`socket-client.js`)
29
+ - Manages WebSocket connections to the Claude MPM server
30
+ - Handles event reception and processing
31
+ - Provides callbacks for connection state changes
32
+ - Maintains event history and session tracking
33
+
34
+ ### EventViewer (`components/event-viewer.js`)
35
+ - Displays events in a filterable list
36
+ - Supports search, type filtering, and session filtering
37
+ - Handles event selection and keyboard navigation
38
+ - Updates metrics display (total events, events per minute, etc.)
39
+
40
+ ### ModuleViewer (`components/module-viewer.js`)
41
+ - Shows detailed information about selected events
42
+ - Provides structured views for different event types
43
+ - Displays raw JSON data for debugging
44
+ - Organizes events by class/category
45
+
46
+ ### SessionManager (`components/session-manager.js`)
47
+ - Manages session selection and filtering
48
+ - Updates session dropdown with available sessions
49
+ - Tracks current active session
50
+ - Updates footer information
51
+
52
+ ### Dashboard (`dashboard.js`)
53
+ - Main application coordinator
54
+ - Handles tab switching between Events, Agents, Tools, and Files
55
+ - Manages component interactions
56
+ - Provides global functions for backward compatibility
57
+
58
+ ## Features
59
+
60
+ ### File-Centric Files Tab
61
+ The Files tab now shows a file-centric view where:
62
+ - Each file appears only once in the list
63
+ - Files show read/write icons based on operations performed
64
+ - Most recently accessed files appear at the bottom
65
+ - Clicking a file shows all operations performed on it with timestamps and agent information
66
+
67
+ ### Tab Organization
68
+ - **Events**: All events with filtering and search
69
+ - **Agents**: Agent-specific events and operations
70
+ - **Tools**: Tool usage and parameters
71
+ - **Files**: File operations organized by file path
72
+
73
+ ### Enhanced Event Details
74
+ - Structured views for different event types
75
+ - Todo checklists with status indicators
76
+ - Agent and tool information
77
+ - Session tracking and filtering
78
+
79
+ ## Usage
80
+
81
+ ### Development
82
+ For development and testing, use `test_dashboard.html` which includes module verification.
83
+
84
+ ### Production
85
+ Use `templates/dashboard.html` as the main template, ensuring all static files are served correctly.
86
+
87
+ ### Integration
88
+ The dashboard can be integrated into a Flask/FastAPI application by serving the static files and using the template.
89
+
90
+ ## Migration from Original
91
+
92
+ The original monolithic `claude_mpm_socketio_dashboard.html` has been replaced with a modular structure:
93
+
94
+ 1. **CSS**: Extracted to `static/css/dashboard.css`
95
+ 2. **JavaScript**: Split into logical modules in `static/js/`
96
+ 3. **HTML**: Clean template in `templates/dashboard.html`
97
+
98
+ All original functionality has been preserved while improving:
99
+ - Code organization and maintainability
100
+ - Module reusability
101
+ - Easier debugging and development
102
+ - Better separation of concerns
103
+
104
+ ## Backward Compatibility
105
+
106
+ Global functions are maintained for compatibility:
107
+ - `connectSocket()`
108
+ - `disconnectSocket()`
109
+ - `clearEvents()`
110
+ - `exportEvents()`
111
+ - `clearSelection()`
112
+ - `switchTab(tabName)`
113
+
114
+ ## Browser Support
115
+
116
+ Requires modern browsers with support for:
117
+ - ES6 Classes
118
+ - Fetch API
119
+ - Custom Events
120
+ - CSS Grid/Flexbox
121
+ - Socket.IO 4.x