claude-mpm 5.4.14__py3-none-any.whl → 5.4.36__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (103) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT.md +164 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +363 -817
  7. claude_mpm/agents/WORKFLOW.md +5 -254
  8. claude_mpm/agents/agent_loader.py +1 -1
  9. claude_mpm/agents/base_agent.json +31 -0
  10. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  11. claude_mpm/cli/commands/agent_state_manager.py +10 -10
  12. claude_mpm/cli/commands/agents.py +9 -40
  13. claude_mpm/cli/commands/auto_configure.py +4 -4
  14. claude_mpm/cli/commands/configure.py +1 -1
  15. claude_mpm/cli/commands/postmortem.py +1 -1
  16. claude_mpm/cli/commands/skills.py +193 -187
  17. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  18. claude_mpm/cli/parsers/agents_parser.py +0 -9
  19. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  20. claude_mpm/cli/startup.py +330 -78
  21. claude_mpm/commands/mpm-config.md +1 -2
  22. claude_mpm/commands/mpm-help.md +14 -95
  23. claude_mpm/commands/mpm-organize.md +350 -153
  24. claude_mpm/core/config.py +2 -4
  25. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  26. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  27. claude_mpm/core/unified_agent_registry.py +1 -1
  28. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  29. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  30. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  31. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  32. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  33. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  34. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  35. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  36. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  37. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  38. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  39. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  40. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  41. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  42. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  43. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  44. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  45. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  46. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  47. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  48. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  49. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  50. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  51. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  52. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  53. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  54. claude_mpm/hooks/claude_hooks/event_handlers.py +5 -0
  55. claude_mpm/hooks/claude_hooks/hook_handler.py +149 -1
  56. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  57. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/services/connection_manager.py +26 -6
  63. claude_mpm/models/git_repository.py +3 -3
  64. claude_mpm/scripts/start_activity_logging.py +0 -0
  65. claude_mpm/services/agents/cache_git_manager.py +6 -6
  66. claude_mpm/services/agents/deployment/agent_deployment.py +7 -7
  67. claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -2
  68. claude_mpm/services/agents/deployment/agent_template_builder.py +2 -2
  69. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  70. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +20 -22
  71. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +55 -53
  72. claude_mpm/services/agents/git_source_manager.py +2 -2
  73. claude_mpm/services/agents/recommender.py +5 -3
  74. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  75. claude_mpm/services/agents/sources/git_source_sync_service.py +5 -5
  76. claude_mpm/services/agents/startup_sync.py +22 -2
  77. claude_mpm/services/command_deployment_service.py +10 -0
  78. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  79. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  80. claude_mpm/services/git/git_operations_service.py +8 -8
  81. claude_mpm/services/monitor/server.py +473 -3
  82. claude_mpm/services/skills/selective_skill_deployer.py +475 -1
  83. claude_mpm/services/skills_deployer.py +62 -6
  84. claude_mpm/services/socketio/dashboard_server.py +1 -0
  85. claude_mpm/services/socketio/event_normalizer.py +37 -6
  86. claude_mpm/services/socketio/server/core.py +262 -123
  87. claude_mpm/utils/agent_dependency_loader.py +14 -2
  88. claude_mpm/utils/agent_filters.py +1 -1
  89. claude_mpm/utils/migration.py +4 -4
  90. claude_mpm/utils/robust_installer.py +47 -3
  91. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/METADATA +5 -3
  92. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/RECORD +96 -66
  93. claude_mpm/cli/commands/agents_detect.py +0 -380
  94. claude_mpm/cli/commands/agents_recommend.py +0 -309
  95. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  96. claude_mpm/commands/mpm-agents-detect.md +0 -177
  97. claude_mpm/commands/mpm-agents-list.md +0 -131
  98. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  99. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/WHEEL +0 -0
  100. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/entry_points.txt +0 -0
  101. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE +0 -0
  102. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  103. {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,36 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
+
8
+ <link rel="modulepreload" href="/_app/immutable/entry/start.DzuEhzqh.js">
9
+ <link rel="modulepreload" href="/_app/immutable/chunks/CIXEwuWe.js">
10
+ <link rel="modulepreload" href="/_app/immutable/chunks/DjhvlsAc.js">
11
+ <link rel="modulepreload" href="/_app/immutable/entry/app.DTL5mJO-.js">
12
+ <link rel="modulepreload" href="/_app/immutable/chunks/DMkZpdF2.js">
13
+ <link rel="modulepreload" href="/_app/immutable/chunks/CWc5urbQ.js">
14
+ <link rel="modulepreload" href="/_app/immutable/chunks/BgChzWQ1.js">
15
+ </head>
16
+ <body data-sveltekit-preload-data="hover">
17
+ <div style="display: contents">
18
+ <script>
19
+ {
20
+ __sveltekit_16ujgvz = {
21
+ base: ""
22
+ };
23
+
24
+ const element = document.currentScript.parentElement;
25
+
26
+ Promise.all([
27
+ import("/_app/immutable/entry/start.DzuEhzqh.js"),
28
+ import("/_app/immutable/entry/app.DTL5mJO-.js")
29
+ ]).then(([kit, app]) => {
30
+ kit.start(app, element);
31
+ });
32
+ }
33
+ </script>
34
+ </div>
35
+ </body>
36
+ </html>
@@ -455,6 +455,11 @@ class EventHandlers:
455
455
  ),
456
456
  }
457
457
 
458
+ # Include full output for file operations (Read, Edit, Write)
459
+ # so frontend can display file content
460
+ if tool_name in ("Read", "Edit", "Write", "Grep", "Glob") and "output" in event:
461
+ post_tool_data["output"] = event["output"]
462
+
458
463
  # Add correlation_id if available for correlation with pre_tool
459
464
  if tool_call_id:
460
465
  post_tool_data["correlation_id"] = tool_call_id
@@ -394,6 +394,8 @@ class ClaudeHookHandler:
394
394
  Returns:
395
395
  Modified input for PreToolUse events (v2.0.30+), None otherwise
396
396
  """
397
+ import time
398
+
397
399
  # Try multiple field names for compatibility
398
400
  hook_type = (
399
401
  event.get("hook_event_name")
@@ -425,15 +427,40 @@ class ClaudeHookHandler:
425
427
  # Call appropriate handler if exists
426
428
  handler = event_handlers.get(hook_type)
427
429
  if handler:
430
+ # Track execution timing for hook emission
431
+ start_time = time.time()
432
+ success = False
433
+ error_message = None
434
+ result = None
435
+
428
436
  try:
429
437
  # Handlers can optionally return modified input
430
438
  result = handler(event)
439
+ success = True
431
440
  # Only PreToolUse handlers should return modified input
432
441
  if hook_type == "PreToolUse" and result is not None:
433
- return result
442
+ return_value = result
443
+ else:
444
+ return_value = None
434
445
  except Exception as e:
446
+ error_message = str(e)
447
+ return_value = None
435
448
  if DEBUG:
436
449
  print(f"Error handling {hook_type}: {e}", file=sys.stderr)
450
+ finally:
451
+ # Calculate duration
452
+ duration_ms = int((time.time() - start_time) * 1000)
453
+
454
+ # Emit hook execution event
455
+ self._emit_hook_execution_event(
456
+ hook_type=hook_type,
457
+ event=event,
458
+ success=success,
459
+ duration_ms=duration_ms,
460
+ error_message=error_message,
461
+ )
462
+
463
+ return return_value
437
464
 
438
465
  return None
439
466
 
@@ -478,6 +505,127 @@ class ClaudeHookHandler:
478
505
  """Generate event key through duplicate detector (backward compatibility)."""
479
506
  return self.duplicate_detector.generate_event_key(event)
480
507
 
508
+ def _emit_hook_execution_event(
509
+ self,
510
+ hook_type: str,
511
+ event: dict,
512
+ success: bool,
513
+ duration_ms: int,
514
+ error_message: Optional[str] = None,
515
+ ):
516
+ """Emit a structured JSON event for hook execution.
517
+
518
+ This emits a normalized event following the claude_event schema to provide
519
+ visibility into hook processing, timing, and success/failure status.
520
+
521
+ Args:
522
+ hook_type: The type of hook that executed (e.g., "UserPromptSubmit", "PreToolUse")
523
+ event: The original hook event data
524
+ success: Whether the hook executed successfully
525
+ duration_ms: How long the hook took to execute in milliseconds
526
+ error_message: Optional error message if the hook failed
527
+ """
528
+ # Generate a human-readable summary based on hook type
529
+ summary = self._generate_hook_summary(hook_type, event, success)
530
+
531
+ # Extract common fields
532
+ session_id = event.get("session_id", "")
533
+ working_dir = event.get("cwd", "")
534
+
535
+ # Build hook execution data
536
+ hook_data = {
537
+ "hook_name": hook_type,
538
+ "hook_type": hook_type,
539
+ "session_id": session_id,
540
+ "working_directory": working_dir,
541
+ "success": success,
542
+ "duration_ms": duration_ms,
543
+ "result_summary": summary,
544
+ "timestamp": datetime.now(timezone.utc).isoformat(),
545
+ }
546
+
547
+ # Add error information if present
548
+ if error_message:
549
+ hook_data["error_message"] = error_message
550
+
551
+ # Add hook-specific context
552
+ if hook_type == "PreToolUse":
553
+ hook_data["tool_name"] = event.get("tool_name", "")
554
+ elif hook_type == "PostToolUse":
555
+ hook_data["tool_name"] = event.get("tool_name", "")
556
+ hook_data["exit_code"] = event.get("exit_code", 0)
557
+ elif hook_type == "UserPromptSubmit":
558
+ prompt = event.get("prompt", "")
559
+ hook_data["prompt_preview"] = prompt[:100] if len(prompt) > 100 else prompt
560
+ hook_data["prompt_length"] = len(prompt)
561
+ elif hook_type == "SubagentStop":
562
+ hook_data["agent_type"] = event.get("agent_type", "unknown")
563
+ hook_data["reason"] = event.get("reason", "unknown")
564
+
565
+ # Emit through connection manager with proper structure
566
+ # This uses the existing event infrastructure
567
+ self._emit_socketio_event("", "hook_execution", hook_data)
568
+
569
+ if DEBUG:
570
+ print(
571
+ f"📊 Hook execution event: {hook_type} - {duration_ms}ms - {'✅' if success else '❌'}",
572
+ file=sys.stderr,
573
+ )
574
+
575
+ def _generate_hook_summary(self, hook_type: str, event: dict, success: bool) -> str:
576
+ """Generate a human-readable summary of what the hook did.
577
+
578
+ Args:
579
+ hook_type: The type of hook
580
+ event: The hook event data
581
+ success: Whether the hook executed successfully
582
+
583
+ Returns:
584
+ A brief description of what happened
585
+ """
586
+ if not success:
587
+ return f"Hook {hook_type} failed during processing"
588
+
589
+ # Generate hook-specific summaries
590
+ if hook_type == "UserPromptSubmit":
591
+ prompt = event.get("prompt", "")
592
+ if prompt.startswith("/"):
593
+ return f"Processed command: {prompt.split()[0]}"
594
+ return f"Processed user prompt ({len(prompt)} chars)"
595
+
596
+ if hook_type == "PreToolUse":
597
+ tool_name = event.get("tool_name", "unknown")
598
+ return f"Pre-processing tool call: {tool_name}"
599
+
600
+ if hook_type == "PostToolUse":
601
+ tool_name = event.get("tool_name", "unknown")
602
+ exit_code = event.get("exit_code", 0)
603
+ status = "success" if exit_code == 0 else "failed"
604
+ return f"Completed tool call: {tool_name} ({status})"
605
+
606
+ if hook_type == "SubagentStop":
607
+ agent_type = event.get("agent_type", "unknown")
608
+ reason = event.get("reason", "unknown")
609
+ return f"Subagent {agent_type} stopped: {reason}"
610
+
611
+ if hook_type == "SessionStart":
612
+ return "New session started"
613
+
614
+ if hook_type == "Stop":
615
+ reason = event.get("reason", "unknown")
616
+ return f"Session stopped: {reason}"
617
+
618
+ if hook_type == "Notification":
619
+ notification_type = event.get("notification_type", "unknown")
620
+ return f"Notification received: {notification_type}"
621
+
622
+ if hook_type == "AssistantResponse":
623
+ response_len = len(event.get("response", ""))
624
+ return f"Assistant response generated ({response_len} chars)"
625
+
626
+ # Default summary
627
+ return f"Hook {hook_type} processed successfully"
628
+
481
629
  def __del__(self):
482
630
  """Cleanup on handler destruction."""
483
631
  # Clean up connection manager if it exists
@@ -58,7 +58,7 @@ except ImportError:
58
58
  (),
59
59
  {
60
60
  "to_dict": lambda: {
61
- "event": "claude_event",
61
+ "event": "mpm_event",
62
62
  "type": event_data.get("type", "unknown"),
63
63
  "subtype": event_data.get("subtype", "generic"),
64
64
  "timestamp": event_data.get(
@@ -119,13 +119,33 @@ class ConnectionManagerService:
119
119
  tool_call_id = data.get("tool_call_id")
120
120
 
121
121
  # Create event data for normalization
122
+ # Extract session_id (try both camelCase and snake_case)
123
+ session_id = data.get("session_id") or data.get("sessionId")
124
+
125
+ # Extract working directory for project identification
126
+ # Try multiple field names for maximum compatibility
127
+ cwd = (
128
+ data.get("cwd")
129
+ or data.get("working_directory")
130
+ or data.get("workingDirectory")
131
+ )
132
+
133
+ # For hook_execution events, extract the actual hook type from data
134
+ # Otherwise use "hook" as the type
135
+ if event == "hook_execution":
136
+ hook_type = data.get("hook_type", "unknown")
137
+ event_type = hook_type
138
+ else:
139
+ event_type = "hook"
140
+
122
141
  raw_event = {
123
- "type": "hook",
124
- "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
142
+ "type": event_type, # Use actual hook type for hook_execution, "hook" otherwise
143
+ "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop", "execution"
125
144
  "timestamp": datetime.now(timezone.utc).isoformat(),
126
145
  "data": data,
127
- "source": "claude_hooks", # Identify the source
128
- "session_id": data.get("sessionId"), # Include session if available
146
+ "source": "mpm_hook", # Identify the source as mpm_hook
147
+ "session_id": session_id, # Include session if available (supports both naming conventions)
148
+ "cwd": cwd, # Add working directory at top level for easy frontend access
129
149
  "correlation_id": tool_call_id, # Set from tool_call_id for event correlation
130
150
  }
131
151
 
@@ -154,7 +174,7 @@ class ConnectionManagerService:
154
174
  if self.connection_pool:
155
175
  try:
156
176
  # Emit to Socket.IO server directly
157
- self.connection_pool.emit("claude_event", claude_event_data)
177
+ self.connection_pool.emit("mpm_event", claude_event_data)
158
178
  if DEBUG:
159
179
  print(f"✅ Emitted via connection pool: {event}", file=sys.stderr)
160
180
  return # Success - no need for fallback
@@ -34,7 +34,7 @@ class GitRepository:
34
34
  def cache_path(self) -> Path:
35
35
  """Return cache directory path for this repository.
36
36
 
37
- Cache structure: ~/.claude-mpm/cache/remote-agents/{owner}/{repo}/{subdirectory}/
37
+ Cache structure: ~/.claude-mpm/cache/agents/{owner}/{repo}/{subdirectory}/
38
38
 
39
39
  Returns:
40
40
  Absolute path to cache directory for this repository
@@ -45,10 +45,10 @@ class GitRepository:
45
45
  ... subdirectory="agents"
46
46
  ... )
47
47
  >>> repo.cache_path
48
- Path('/Users/user/.claude-mpm/cache/remote-agents/bobmatnyc/claude-mpm-agents/agents')
48
+ Path('/Users/user/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents')
49
49
  """
50
50
  home = Path.home()
51
- base_cache = home / ".claude-mpm" / "cache" / "remote-agents"
51
+ base_cache = home / ".claude-mpm" / "cache" / "agents"
52
52
 
53
53
  # Extract owner and repo from URL
54
54
  owner, repo = self._parse_github_url(self.url)
File without changes
@@ -29,7 +29,7 @@ Error Handling:
29
29
 
30
30
  Example:
31
31
  >>> from pathlib import Path
32
- >>> manager = CacheGitManager(Path.home() / ".claude-mpm/cache/remote-agents")
32
+ >>> manager = CacheGitManager(Path.home() / ".claude-mpm/cache/agents")
33
33
  >>> if manager.is_git_repo():
34
34
  ... status = manager.get_status()
35
35
  ... print(f"Branch: {status['branch']}, Uncommitted: {len(status['uncommitted'])}")
@@ -76,7 +76,7 @@ class CacheGitManager:
76
76
  timeout: Git command timeout in seconds (default: 30)
77
77
 
78
78
  Example:
79
- >>> cache_dir = Path.home() / ".claude-mpm/cache/remote-agents"
79
+ >>> cache_dir = Path.home() / ".claude-mpm/cache/agents"
80
80
  >>> manager = CacheGitManager(cache_dir)
81
81
  """
82
82
  self.cache_path = Path(cache_path)
@@ -105,12 +105,12 @@ class CacheGitManager:
105
105
 
106
106
  Example:
107
107
  >>> # Case 1: cache_path inside repo (searches upward)
108
- >>> # cache_path: ~/.claude-mpm/cache/remote-agents/bobmatnyc/claude-mpm-agents/agents
109
- >>> # Found at: ~/.claude-mpm/cache/remote-agents/bobmatnyc/claude-mpm-agents
108
+ >>> # cache_path: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents
109
+ >>> # Found at: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents
110
110
 
111
111
  >>> # Case 2: repo nested in cache_path (searches downward)
112
- >>> # cache_path: ~/.claude-mpm/cache/remote-agents
113
- >>> # Found at: ~/.claude-mpm/cache/remote-agents/bobmatnyc/claude-mpm-agents
112
+ >>> # cache_path: ~/.claude-mpm/cache/agents
113
+ >>> # Found at: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents
114
114
  """
115
115
  # Strategy 1: Search upward (cache_path is inside repo)
116
116
  current = self.cache_path
@@ -876,13 +876,13 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
876
876
  user_agents_dir = potential_user_dir
877
877
  self.logger.info(f"Found user agents at: {user_agents_dir}")
878
878
 
879
- # Check for remote agents (cached from GitHub)
880
- remote_agents_dir = None
879
+ # Check for agents cache (from Git sources)
880
+ agents_cache_dir = None
881
881
  cache_dir = user_home / ".claude-mpm" / "cache"
882
- potential_remote_dir = cache_dir / "remote-agents"
883
- if potential_remote_dir.exists():
884
- remote_agents_dir = potential_remote_dir
885
- self.logger.info(f"Found remote agents cache at: {remote_agents_dir}")
882
+ potential_cache_dir = cache_dir / "agents"
883
+ if potential_cache_dir.exists():
884
+ agents_cache_dir = potential_cache_dir
885
+ self.logger.info(f"Found agents cache at: {agents_cache_dir}")
886
886
 
887
887
  # Get agents with version comparison and cleanup (4-tier discovery)
888
888
  agents_to_deploy, agent_sources, cleanup_results = (
@@ -890,7 +890,7 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
890
890
  system_templates_dir=system_templates_dir,
891
891
  project_agents_dir=project_agents_dir,
892
892
  user_agents_dir=user_agents_dir,
893
- remote_agents_dir=remote_agents_dir, # NEW: 4th tier
893
+ agents_cache_dir=agents_cache_dir, # NEW: 4th tier
894
894
  working_directory=self.working_directory,
895
895
  excluded_agents=excluded_agents,
896
896
  config=config,
@@ -248,7 +248,7 @@ class AgentDiscoveryService:
248
248
  return agent_info
249
249
 
250
250
  except yaml.YAMLError as e:
251
- self.logger.error(f"Invalid YAML frontmatter in {template_file.name}: {e}")
251
+ self.logger.warning(f"Invalid YAML frontmatter in {template_file.name}: {e}")
252
252
  return None
253
253
  except Exception as e:
254
254
  self.logger.error(
@@ -431,7 +431,7 @@ class AgentDiscoveryService:
431
431
  return True
432
432
 
433
433
  except yaml.YAMLError:
434
- self.logger.error(
434
+ self.logger.warning(
435
435
  f"Invalid YAML frontmatter in template: {template_file.name}"
436
436
  )
437
437
  return False
@@ -135,8 +135,8 @@ class AgentTemplateBuilder:
135
135
  break
136
136
 
137
137
  # Stop at common repository root indicators (check AFTER finding BASE-AGENT.md)
138
- # This ensures we check the 'agents' directory before stopping at 'remote-agents'
139
- if current_dir.name in [".claude-mpm", "remote-agents", "cache"]:
138
+ # Stop at cache root or .claude-mpm directory
139
+ if current_dir.name in [".claude-mpm", "cache"]:
140
140
  self.logger.debug(
141
141
  f"Reached repository root indicator at: {current_dir}"
142
142
  )
@@ -8,7 +8,7 @@ DEPLOYMENT ARCHITECTURE:
8
8
 
9
9
  Agent Source Locations (Discovery):
10
10
  -----------------------------------
11
- 1. System Agents: ~/.claude-mpm/cache/remote-agents/bobmatnyc/claude-mpm-agents/
11
+ 1. System Agents: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/
12
12
  - Synced from GitHub repository
13
13
  - Read-only (managed by git pull)
14
14
  - 44+ agents organized by category
@@ -39,7 +39,7 @@ Why Project-Level Deployment?
39
39
  Example Flow:
40
40
  -------------
41
41
  1. User runs: claude-mpm agents deploy
42
- 2. Agents synced from GitHub → ~/.claude-mpm/cache/remote-agents/
42
+ 2. Agents synced from GitHub → ~/.claude-mpm/cache/agents/
43
43
  3. Agents deployed FROM cache → .claude/agents/
44
44
  4. Claude Code discovers agents FROM .claude/agents/
45
45
 
@@ -179,14 +179,14 @@ class MultiSourceAgentDeploymentService:
179
179
  system_templates_dir: Optional[Path] = None,
180
180
  project_agents_dir: Optional[Path] = None,
181
181
  user_agents_dir: Optional[Path] = None,
182
- remote_agents_dir: Optional[Path] = None,
182
+ agents_cache_dir: Optional[Path] = None,
183
183
  working_directory: Optional[Path] = None,
184
184
  ) -> Dict[str, List[Dict[str, Any]]]:
185
- """Discover agents from all 4 tiers (system, user, remote, project).
185
+ """Discover agents from all 4 tiers (system, user, cache, project).
186
186
 
187
187
  Priority hierarchy (highest to lowest):
188
188
  4. Project agents - Highest priority, project-specific customizations
189
- 3. Remote agents - GitHub-synced agents from cache
189
+ 3. Cached agents - GitHub-synced agents from cache
190
190
  2. User agents - DEPRECATED, user-level customizations
191
191
  1. System templates - Lowest priority, built-in agents
192
192
 
@@ -194,7 +194,7 @@ class MultiSourceAgentDeploymentService:
194
194
  system_templates_dir: Directory containing system agent templates
195
195
  project_agents_dir: Directory containing project-specific agents
196
196
  user_agents_dir: Directory containing user custom agents (DEPRECATED)
197
- remote_agents_dir: Directory containing cached remote agents
197
+ agents_cache_dir: Directory containing cached agents from Git sources
198
198
  working_directory: Current working directory for finding project agents
199
199
 
200
200
  Returns:
@@ -225,12 +225,12 @@ class MultiSourceAgentDeploymentService:
225
225
  if not user_agents_dir.exists():
226
226
  user_agents_dir = None
227
227
 
228
- if not remote_agents_dir:
229
- # Check for remote agents in cache directory
228
+ if not agents_cache_dir:
229
+ # Check for agents in cache directory
230
230
  cache_dir = Path.home() / ".claude-mpm" / "cache"
231
- remote_agents_dir = cache_dir / "remote-agents"
232
- if not remote_agents_dir.exists():
233
- remote_agents_dir = None
231
+ agents_cache_dir = cache_dir / "agents"
232
+ if not agents_cache_dir.exists():
233
+ agents_cache_dir = None
234
234
 
235
235
  # Discover agents from each source in priority order
236
236
  # Note: We process in reverse priority order (system first) and build up the dictionary
@@ -238,7 +238,7 @@ class MultiSourceAgentDeploymentService:
238
238
  sources = [
239
239
  ("system", system_templates_dir),
240
240
  ("user", user_agents_dir),
241
- ("remote", remote_agents_dir),
241
+ ("remote", agents_cache_dir),
242
242
  ("project", project_agents_dir),
243
243
  ]
244
244
 
@@ -323,7 +323,7 @@ class MultiSourceAgentDeploymentService:
323
323
  def get_agents_by_collection(
324
324
  self,
325
325
  collection_id: str,
326
- remote_agents_dir: Optional[Path] = None,
326
+ agents_cache_dir: Optional[Path] = None,
327
327
  ) -> List[Dict[str, Any]]:
328
328
  """Get all agents from a specific collection.
329
329
 
@@ -331,7 +331,7 @@ class MultiSourceAgentDeploymentService:
331
331
 
332
332
  Args:
333
333
  collection_id: Collection identifier (e.g., "bobmatnyc/claude-mpm-agents")
334
- remote_agents_dir: Directory containing remote agents cache
334
+ agents_cache_dir: Directory containing agents cache
335
335
 
336
336
  Returns:
337
337
  List of agent dictionaries from the specified collection
@@ -342,18 +342,16 @@ class MultiSourceAgentDeploymentService:
342
342
  >>> len(agents)
343
343
  45
344
344
  """
345
- if not remote_agents_dir:
345
+ if not agents_cache_dir:
346
346
  cache_dir = Path.home() / ".claude-mpm" / "cache"
347
- remote_agents_dir = cache_dir / "remote-agents"
347
+ agents_cache_dir = cache_dir / "agents"
348
348
 
349
- if not remote_agents_dir.exists():
350
- self.logger.warning(
351
- f"Remote agents directory not found: {remote_agents_dir}"
352
- )
349
+ if not agents_cache_dir.exists():
350
+ self.logger.warning(f"Agents cache directory not found: {agents_cache_dir}")
353
351
  return []
354
352
 
355
353
  # Use RemoteAgentDiscoveryService to get collection agents
356
- remote_service = RemoteAgentDiscoveryService(remote_agents_dir)
354
+ remote_service = RemoteAgentDiscoveryService(agents_cache_dir)
357
355
  collection_agents = remote_service.get_agents_by_collection(collection_id)
358
356
 
359
357
  self.logger.info(
@@ -470,7 +468,7 @@ class MultiSourceAgentDeploymentService:
470
468
  system_templates_dir: Optional[Path] = None,
471
469
  project_agents_dir: Optional[Path] = None,
472
470
  user_agents_dir: Optional[Path] = None,
473
- remote_agents_dir: Optional[Path] = None,
471
+ agents_cache_dir: Optional[Path] = None,
474
472
  working_directory: Optional[Path] = None,
475
473
  excluded_agents: Optional[List[str]] = None,
476
474
  config: Optional[Config] = None,
@@ -482,7 +480,7 @@ class MultiSourceAgentDeploymentService:
482
480
  system_templates_dir: Directory containing system agent templates
483
481
  project_agents_dir: Directory containing project-specific agents
484
482
  user_agents_dir: Directory containing user custom agents (DEPRECATED)
485
- remote_agents_dir: Directory containing cached remote agents
483
+ agents_cache_dir: Directory containing cached agents from Git sources
486
484
  working_directory: Current working directory for finding project agents
487
485
  excluded_agents: List of agent names to exclude from deployment
488
486
  config: Configuration object for additional filtering
@@ -499,7 +497,7 @@ class MultiSourceAgentDeploymentService:
499
497
  system_templates_dir=system_templates_dir,
500
498
  project_agents_dir=project_agents_dir,
501
499
  user_agents_dir=user_agents_dir,
502
- remote_agents_dir=remote_agents_dir,
500
+ agents_cache_dir=agents_cache_dir,
503
501
  working_directory=working_directory,
504
502
  )
505
503