claude-mpm 4.0.19__py3-none-any.whl → 4.0.22__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.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +4 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +38 -2
- claude_mpm/agents/INSTRUCTIONS.md +74 -0
- claude_mpm/agents/OUTPUT_STYLE.md +84 -0
- claude_mpm/agents/WORKFLOW.md +308 -4
- claude_mpm/agents/agents_metadata.py +52 -0
- claude_mpm/agents/base_agent_loader.py +75 -19
- claude_mpm/agents/templates/__init__.py +4 -0
- claude_mpm/agents/templates/api_qa.json +206 -0
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +24 -16
- claude_mpm/agents/templates/ticketing.json +18 -5
- claude_mpm/agents/templates/vercel_ops_agent.json +281 -0
- claude_mpm/agents/templates/vercel_ops_instructions.md +582 -0
- claude_mpm/cli/__init__.py +23 -1
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/commands/mcp_command_router.py +87 -1
- claude_mpm/cli/commands/mcp_install_commands.py +207 -26
- claude_mpm/cli/commands/memory.py +32 -5
- claude_mpm/cli/commands/run.py +33 -6
- claude_mpm/cli/parsers/base_parser.py +5 -0
- claude_mpm/cli/parsers/mcp_parser.py +23 -0
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/utils.py +17 -4
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +8 -2
- claude_mpm/core/config.py +122 -32
- claude_mpm/core/framework_loader.py +385 -34
- claude_mpm/core/interactive_session.py +77 -12
- claude_mpm/core/oneshot_session.py +7 -1
- claude_mpm/core/output_style_manager.py +468 -0
- claude_mpm/core/unified_paths.py +190 -21
- claude_mpm/hooks/claude_hooks/hook_handler.py +91 -16
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +3 -0
- claude_mpm/init.py +1 -0
- claude_mpm/scripts/socketio_daemon.py +67 -7
- claude_mpm/scripts/socketio_daemon_hardened.py +897 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +216 -10
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +65 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +441 -0
- claude_mpm/services/agents/memory/__init__.py +0 -2
- claude_mpm/services/agents/memory/agent_memory_manager.py +577 -44
- claude_mpm/services/agents/memory/content_manager.py +144 -14
- claude_mpm/services/agents/memory/template_generator.py +7 -354
- claude_mpm/services/mcp_gateway/server/stdio_server.py +61 -169
- claude_mpm/services/memory_hook_service.py +62 -4
- claude_mpm/services/runner_configuration_service.py +5 -9
- claude_mpm/services/socketio/server/broadcaster.py +32 -1
- claude_mpm/services/socketio/server/core.py +4 -0
- claude_mpm/services/socketio/server/main.py +23 -4
- claude_mpm/services/subprocess_launcher_service.py +5 -0
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/METADATA +1 -1
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/RECORD +60 -54
- claude_mpm/services/agents/memory/analyzer.py +0 -430
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.19.dist-info → claude_mpm-4.0.22.dist-info}/top_level.txt +0 -0
|
@@ -32,7 +32,7 @@ import os
|
|
|
32
32
|
import shutil
|
|
33
33
|
import time
|
|
34
34
|
from pathlib import Path
|
|
35
|
-
from typing import Any, Dict, List, Optional
|
|
35
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
36
36
|
|
|
37
37
|
from claude_mpm.config.paths import paths
|
|
38
38
|
from claude_mpm.constants import AgentMetadata, EnvironmentVars, Paths
|
|
@@ -55,6 +55,7 @@ from .agent_metrics_collector import AgentMetricsCollector
|
|
|
55
55
|
from .agent_template_builder import AgentTemplateBuilder
|
|
56
56
|
from .agent_validator import AgentValidator
|
|
57
57
|
from .agent_version_manager import AgentVersionManager
|
|
58
|
+
from .multi_source_deployment_service import MultiSourceAgentDeploymentService
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
class AgentDeploymentService(AgentDeploymentInterface):
|
|
@@ -161,13 +162,16 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
161
162
|
|
|
162
163
|
# Initialize discovery service (after templates_dir is set)
|
|
163
164
|
self.discovery_service = AgentDiscoveryService(self.templates_dir)
|
|
165
|
+
|
|
166
|
+
# Initialize multi-source deployment service for version comparison
|
|
167
|
+
self.multi_source_service = MultiSourceAgentDeploymentService()
|
|
164
168
|
|
|
165
|
-
# Find base agent file
|
|
169
|
+
# Find base agent file with priority-based search
|
|
166
170
|
if base_agent_path:
|
|
167
171
|
self.base_agent_path = Path(base_agent_path)
|
|
168
172
|
else:
|
|
169
|
-
#
|
|
170
|
-
self.base_agent_path =
|
|
173
|
+
# Priority-based search for base_agent.json
|
|
174
|
+
self.base_agent_path = self._find_base_agent_file()
|
|
171
175
|
|
|
172
176
|
# Initialize configuration manager (after base_agent_path is set)
|
|
173
177
|
self.configuration_manager = AgentConfigurationManager(self.base_agent_path)
|
|
@@ -177,6 +181,68 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
177
181
|
|
|
178
182
|
self.logger.info(f"Templates directory: {self.templates_dir}")
|
|
179
183
|
self.logger.info(f"Base agent path: {self.base_agent_path}")
|
|
184
|
+
|
|
185
|
+
def _find_base_agent_file(self) -> Path:
|
|
186
|
+
"""Find base agent file with priority-based search.
|
|
187
|
+
|
|
188
|
+
Priority order:
|
|
189
|
+
1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
|
|
190
|
+
2. Current working directory (for local development)
|
|
191
|
+
3. Known development locations
|
|
192
|
+
4. User override location (~/.claude/agents/)
|
|
193
|
+
5. Framework agents directory (from paths)
|
|
194
|
+
"""
|
|
195
|
+
# Priority 0: Check environment variable override
|
|
196
|
+
env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
|
|
197
|
+
if env_path:
|
|
198
|
+
env_base_agent = Path(env_path)
|
|
199
|
+
if env_base_agent.exists():
|
|
200
|
+
self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
|
|
201
|
+
return env_base_agent
|
|
202
|
+
else:
|
|
203
|
+
self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
|
|
204
|
+
|
|
205
|
+
# Priority 1: Check current working directory for local development
|
|
206
|
+
cwd = Path.cwd()
|
|
207
|
+
cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
|
|
208
|
+
if cwd_base_agent.exists():
|
|
209
|
+
self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
|
|
210
|
+
return cwd_base_agent
|
|
211
|
+
|
|
212
|
+
# Priority 2: Check known development locations
|
|
213
|
+
known_dev_paths = [
|
|
214
|
+
Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
|
|
215
|
+
Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
216
|
+
Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
for dev_path in known_dev_paths:
|
|
220
|
+
if dev_path.exists():
|
|
221
|
+
self.logger.info(f"Using development base_agent: {dev_path}")
|
|
222
|
+
return dev_path
|
|
223
|
+
|
|
224
|
+
# Priority 3: Check user override location
|
|
225
|
+
user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
|
|
226
|
+
if user_base_agent.exists():
|
|
227
|
+
self.logger.info(f"Using user override base_agent: {user_base_agent}")
|
|
228
|
+
return user_base_agent
|
|
229
|
+
|
|
230
|
+
# Priority 4: Use framework agents directory (fallback)
|
|
231
|
+
framework_base_agent = paths.agents_dir / "base_agent.json"
|
|
232
|
+
if framework_base_agent.exists():
|
|
233
|
+
self.logger.info(f"Using framework base_agent: {framework_base_agent}")
|
|
234
|
+
return framework_base_agent
|
|
235
|
+
|
|
236
|
+
# If still not found, log all searched locations and raise error
|
|
237
|
+
self.logger.error("Base agent file not found in any location:")
|
|
238
|
+
self.logger.error(f" 1. CWD: {cwd_base_agent}")
|
|
239
|
+
self.logger.error(f" 2. Dev paths: {known_dev_paths}")
|
|
240
|
+
self.logger.error(f" 3. User: {user_base_agent}")
|
|
241
|
+
self.logger.error(f" 4. Framework: {framework_base_agent}")
|
|
242
|
+
|
|
243
|
+
# Final fallback to framework path even if it doesn't exist
|
|
244
|
+
# (will fail later with better error message)
|
|
245
|
+
return framework_base_agent
|
|
180
246
|
|
|
181
247
|
def deploy_agents(
|
|
182
248
|
self,
|
|
@@ -310,20 +376,40 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
310
376
|
# Load base agent content
|
|
311
377
|
base_agent_data, base_agent_version = self._load_base_agent()
|
|
312
378
|
|
|
313
|
-
#
|
|
314
|
-
|
|
315
|
-
|
|
379
|
+
# Check if we should use multi-source deployment
|
|
380
|
+
use_multi_source = self._should_use_multi_source_deployment(deployment_mode)
|
|
381
|
+
|
|
382
|
+
if use_multi_source:
|
|
383
|
+
# Use multi-source deployment to get highest version agents
|
|
384
|
+
template_files, agent_sources = self._get_multi_source_templates(
|
|
385
|
+
excluded_agents, config, agents_dir
|
|
386
|
+
)
|
|
387
|
+
results["total"] = len(template_files)
|
|
388
|
+
results["multi_source"] = True
|
|
389
|
+
results["agent_sources"] = agent_sources
|
|
390
|
+
else:
|
|
391
|
+
# Get and filter template files from single source
|
|
392
|
+
template_files = self._get_filtered_templates(excluded_agents, config)
|
|
393
|
+
results["total"] = len(template_files)
|
|
394
|
+
agent_sources = {}
|
|
316
395
|
|
|
317
396
|
# Deploy each agent template
|
|
318
397
|
for template_file in template_files:
|
|
398
|
+
template_file_path = template_file if isinstance(template_file, Path) else Path(template_file)
|
|
399
|
+
agent_name = template_file_path.stem
|
|
400
|
+
|
|
401
|
+
# Get source info for this agent (agent_sources now uses file stems as keys)
|
|
402
|
+
source_info = agent_sources.get(agent_name, "unknown") if agent_sources else "single"
|
|
403
|
+
|
|
319
404
|
self._deploy_single_agent(
|
|
320
|
-
template_file=
|
|
405
|
+
template_file=template_file_path,
|
|
321
406
|
agents_dir=agents_dir,
|
|
322
407
|
base_agent_data=base_agent_data,
|
|
323
408
|
base_agent_version=base_agent_version,
|
|
324
409
|
force_rebuild=force_rebuild,
|
|
325
410
|
deployment_mode=deployment_mode,
|
|
326
411
|
results=results,
|
|
412
|
+
source_info=source_info,
|
|
327
413
|
)
|
|
328
414
|
|
|
329
415
|
# Deploy system instructions and framework files
|
|
@@ -467,8 +553,10 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
467
553
|
self.logger.warning(f"Could not load base agent: {e}")
|
|
468
554
|
|
|
469
555
|
# Build the agent markdown
|
|
556
|
+
# For single agent deployment, determine source from template location
|
|
557
|
+
source_info = self._determine_agent_source(template_file)
|
|
470
558
|
agent_content = self.template_builder.build_agent_markdown(
|
|
471
|
-
agent_name, template_file, base_agent_data
|
|
559
|
+
agent_name, template_file, base_agent_data, source_info
|
|
472
560
|
)
|
|
473
561
|
if not agent_content:
|
|
474
562
|
self.logger.error(f"Failed to build agent content for {agent_name}")
|
|
@@ -718,6 +806,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
718
806
|
force_rebuild: bool,
|
|
719
807
|
deployment_mode: str,
|
|
720
808
|
results: Dict[str, Any],
|
|
809
|
+
source_info: str = "unknown",
|
|
721
810
|
) -> None:
|
|
722
811
|
"""
|
|
723
812
|
Deploy a single agent template.
|
|
@@ -733,6 +822,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
733
822
|
force_rebuild: Whether to force rebuild
|
|
734
823
|
deployment_mode: Deployment mode (update/project)
|
|
735
824
|
results: Results dictionary to update
|
|
825
|
+
source_info: Source of the agent (system/project/user)
|
|
736
826
|
"""
|
|
737
827
|
try:
|
|
738
828
|
# METRICS: Track individual agent deployment time
|
|
@@ -762,7 +852,7 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
762
852
|
|
|
763
853
|
# Build the agent file as markdown with YAML frontmatter
|
|
764
854
|
agent_content = self.template_builder.build_agent_markdown(
|
|
765
|
-
agent_name, template_file, base_agent_data
|
|
855
|
+
agent_name, template_file, base_agent_data, source_info
|
|
766
856
|
)
|
|
767
857
|
|
|
768
858
|
# Write the agent file
|
|
@@ -912,6 +1002,122 @@ class AgentDeploymentService(AgentDeploymentInterface):
|
|
|
912
1002
|
|
|
913
1003
|
validator = AgentFrontmatterValidator(self.logger)
|
|
914
1004
|
return validator.validate_and_repair_existing_agents(agents_dir)
|
|
1005
|
+
|
|
1006
|
+
def _determine_agent_source(self, template_path: Path) -> str:
|
|
1007
|
+
"""Determine the source of an agent from its template path.
|
|
1008
|
+
|
|
1009
|
+
WHY: When deploying single agents, we need to track their source
|
|
1010
|
+
for proper version management and debugging.
|
|
1011
|
+
|
|
1012
|
+
Args:
|
|
1013
|
+
template_path: Path to the agent template
|
|
1014
|
+
|
|
1015
|
+
Returns:
|
|
1016
|
+
Source string (system/project/user/unknown)
|
|
1017
|
+
"""
|
|
1018
|
+
template_str = str(template_path.resolve())
|
|
1019
|
+
|
|
1020
|
+
# Check if it's a system template
|
|
1021
|
+
if "/claude_mpm/agents/templates/" in template_str or "/src/claude_mpm/agents/templates/" in template_str:
|
|
1022
|
+
return "system"
|
|
1023
|
+
|
|
1024
|
+
# Check if it's a project agent
|
|
1025
|
+
if "/.claude-mpm/agents/" in template_str:
|
|
1026
|
+
# Check if it's in the current working directory
|
|
1027
|
+
if str(self.working_directory) in template_str:
|
|
1028
|
+
return "project"
|
|
1029
|
+
# Check if it's in user home
|
|
1030
|
+
elif str(Path.home()) in template_str:
|
|
1031
|
+
return "user"
|
|
1032
|
+
|
|
1033
|
+
return "unknown"
|
|
1034
|
+
|
|
1035
|
+
def _should_use_multi_source_deployment(self, deployment_mode: str) -> bool:
|
|
1036
|
+
"""Determine if multi-source deployment should be used.
|
|
1037
|
+
|
|
1038
|
+
WHY: Multi-source deployment ensures the highest version wins,
|
|
1039
|
+
but we may want to preserve backward compatibility in some modes.
|
|
1040
|
+
|
|
1041
|
+
Args:
|
|
1042
|
+
deployment_mode: Current deployment mode
|
|
1043
|
+
|
|
1044
|
+
Returns:
|
|
1045
|
+
True if multi-source deployment should be used
|
|
1046
|
+
"""
|
|
1047
|
+
# Always use multi-source for update mode to get highest versions
|
|
1048
|
+
if deployment_mode == "update":
|
|
1049
|
+
return True
|
|
1050
|
+
|
|
1051
|
+
# For project mode, also use multi-source to ensure highest version wins
|
|
1052
|
+
# This is the key change - project mode should also compare versions
|
|
1053
|
+
if deployment_mode == "project":
|
|
1054
|
+
return True
|
|
1055
|
+
|
|
1056
|
+
return False
|
|
1057
|
+
|
|
1058
|
+
def _get_multi_source_templates(
|
|
1059
|
+
self, excluded_agents: List[str], config: Config, agents_dir: Path
|
|
1060
|
+
) -> Tuple[List[Path], Dict[str, str]]:
|
|
1061
|
+
"""Get agent templates from multiple sources with version comparison.
|
|
1062
|
+
|
|
1063
|
+
WHY: This method uses the multi-source service to discover agents
|
|
1064
|
+
from all available sources and select the highest version of each.
|
|
1065
|
+
|
|
1066
|
+
Args:
|
|
1067
|
+
excluded_agents: List of agents to exclude
|
|
1068
|
+
config: Configuration object
|
|
1069
|
+
agents_dir: Target deployment directory
|
|
1070
|
+
|
|
1071
|
+
Returns:
|
|
1072
|
+
Tuple of (template_files, agent_sources)
|
|
1073
|
+
"""
|
|
1074
|
+
# Determine source directories
|
|
1075
|
+
system_templates_dir = self.templates_dir
|
|
1076
|
+
project_agents_dir = None
|
|
1077
|
+
user_agents_dir = None
|
|
1078
|
+
|
|
1079
|
+
# Check for project agents
|
|
1080
|
+
if self.working_directory:
|
|
1081
|
+
potential_project_dir = self.working_directory / ".claude-mpm" / "agents"
|
|
1082
|
+
if potential_project_dir.exists():
|
|
1083
|
+
project_agents_dir = potential_project_dir
|
|
1084
|
+
self.logger.info(f"Found project agents at: {project_agents_dir}")
|
|
1085
|
+
|
|
1086
|
+
# Check for user agents
|
|
1087
|
+
user_home = Path.home()
|
|
1088
|
+
potential_user_dir = user_home / ".claude-mpm" / "agents"
|
|
1089
|
+
if potential_user_dir.exists():
|
|
1090
|
+
user_agents_dir = potential_user_dir
|
|
1091
|
+
self.logger.info(f"Found user agents at: {user_agents_dir}")
|
|
1092
|
+
|
|
1093
|
+
# Get agents with version comparison
|
|
1094
|
+
agents_to_deploy, agent_sources = self.multi_source_service.get_agents_for_deployment(
|
|
1095
|
+
system_templates_dir=system_templates_dir,
|
|
1096
|
+
project_agents_dir=project_agents_dir,
|
|
1097
|
+
user_agents_dir=user_agents_dir,
|
|
1098
|
+
working_directory=self.working_directory,
|
|
1099
|
+
excluded_agents=excluded_agents,
|
|
1100
|
+
config=config
|
|
1101
|
+
)
|
|
1102
|
+
|
|
1103
|
+
# Compare with deployed versions if agents directory exists
|
|
1104
|
+
if agents_dir.exists():
|
|
1105
|
+
comparison_results = self.multi_source_service.compare_deployed_versions(
|
|
1106
|
+
deployed_agents_dir=agents_dir,
|
|
1107
|
+
agents_to_deploy=agents_to_deploy,
|
|
1108
|
+
agent_sources=agent_sources
|
|
1109
|
+
)
|
|
1110
|
+
|
|
1111
|
+
# Log version upgrades and source changes
|
|
1112
|
+
if comparison_results.get("version_upgrades"):
|
|
1113
|
+
self.logger.info(f"Version upgrades available for {len(comparison_results['version_upgrades'])} agents")
|
|
1114
|
+
if comparison_results.get("source_changes"):
|
|
1115
|
+
self.logger.info(f"Source changes for {len(comparison_results['source_changes'])} agents")
|
|
1116
|
+
|
|
1117
|
+
# Convert to list of Path objects
|
|
1118
|
+
template_files = list(agents_to_deploy.values())
|
|
1119
|
+
|
|
1120
|
+
return template_files, agent_sources
|
|
915
1121
|
|
|
916
1122
|
# ================================================================================
|
|
917
1123
|
# Interface Adapter Methods
|
|
@@ -31,7 +31,7 @@ class AgentTemplateBuilder:
|
|
|
31
31
|
self.logger = get_logger(__name__)
|
|
32
32
|
|
|
33
33
|
def build_agent_markdown(
|
|
34
|
-
self, agent_name: str, template_path: Path, base_agent_data: dict
|
|
34
|
+
self, agent_name: str, template_path: Path, base_agent_data: dict, source_info: str = "unknown"
|
|
35
35
|
) -> str:
|
|
36
36
|
"""
|
|
37
37
|
Build a complete agent markdown file with YAML frontmatter.
|
|
@@ -40,6 +40,7 @@ class AgentTemplateBuilder:
|
|
|
40
40
|
agent_name: Name of the agent
|
|
41
41
|
template_path: Path to the agent template JSON file
|
|
42
42
|
base_agent_data: Base agent configuration data
|
|
43
|
+
source_info: Source of the agent (system/project/user)
|
|
43
44
|
|
|
44
45
|
Returns:
|
|
45
46
|
Complete markdown content with YAML frontmatter
|
|
@@ -197,6 +198,8 @@ class AgentTemplateBuilder:
|
|
|
197
198
|
f"color: {color}",
|
|
198
199
|
f"version: {agent_version}",
|
|
199
200
|
f"type: {agent_type}",
|
|
201
|
+
f"source: {source_info}", # Track which source provided this agent
|
|
202
|
+
"author: claude-mpm", # Mark as system-managed agent
|
|
200
203
|
"---",
|
|
201
204
|
"",
|
|
202
205
|
]
|
|
@@ -211,6 +214,39 @@ class AgentTemplateBuilder:
|
|
|
211
214
|
or base_agent_data.get("instructions")
|
|
212
215
|
or "# Agent Instructions\n\nThis agent provides specialized assistance."
|
|
213
216
|
)
|
|
217
|
+
|
|
218
|
+
# Add memory update instructions if not already present
|
|
219
|
+
if "memory-update" not in content and "Remember" not in content:
|
|
220
|
+
memory_instructions = """
|
|
221
|
+
|
|
222
|
+
## Memory Updates
|
|
223
|
+
|
|
224
|
+
When you learn something important about this project that would be useful for future tasks, include it in your response JSON block:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"memory-update": {
|
|
229
|
+
"Project Architecture": ["Key architectural patterns or structures"],
|
|
230
|
+
"Implementation Guidelines": ["Important coding standards or practices"],
|
|
231
|
+
"Current Technical Context": ["Project-specific technical details"]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Or use the simpler "remember" field for general learnings:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"remember": ["Learning 1", "Learning 2"]
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Only include memories that are:
|
|
245
|
+
- Project-specific (not generic programming knowledge)
|
|
246
|
+
- Likely to be useful in future tasks
|
|
247
|
+
- Not already documented elsewhere
|
|
248
|
+
"""
|
|
249
|
+
content = content + memory_instructions
|
|
214
250
|
|
|
215
251
|
return frontmatter + content
|
|
216
252
|
|
|
@@ -83,7 +83,8 @@ class AsyncAgentDeploymentService:
|
|
|
83
83
|
if base_agent_path:
|
|
84
84
|
self.base_agent_path = Path(base_agent_path)
|
|
85
85
|
else:
|
|
86
|
-
|
|
86
|
+
# Use priority-based search for base_agent.json
|
|
87
|
+
self.base_agent_path = self._find_base_agent_file()
|
|
87
88
|
|
|
88
89
|
# Thread pool for CPU-bound JSON parsing
|
|
89
90
|
self.executor = ThreadPoolExecutor(max_workers=4)
|
|
@@ -94,6 +95,69 @@ class AsyncAgentDeploymentService:
|
|
|
94
95
|
"parallel_files_processed": 0,
|
|
95
96
|
"time_saved_ms": 0.0,
|
|
96
97
|
}
|
|
98
|
+
|
|
99
|
+
self.logger.info(f"Base agent path: {self.base_agent_path}")
|
|
100
|
+
|
|
101
|
+
def _find_base_agent_file(self) -> Path:
|
|
102
|
+
"""Find base agent file with priority-based search.
|
|
103
|
+
|
|
104
|
+
Priority order:
|
|
105
|
+
1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
|
|
106
|
+
2. Current working directory (for local development)
|
|
107
|
+
3. Known development locations
|
|
108
|
+
4. User override location (~/.claude/agents/)
|
|
109
|
+
5. Framework agents directory (from paths)
|
|
110
|
+
"""
|
|
111
|
+
# Priority 0: Check environment variable override
|
|
112
|
+
env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
|
|
113
|
+
if env_path:
|
|
114
|
+
env_base_agent = Path(env_path)
|
|
115
|
+
if env_base_agent.exists():
|
|
116
|
+
self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
|
|
117
|
+
return env_base_agent
|
|
118
|
+
else:
|
|
119
|
+
self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
|
|
120
|
+
|
|
121
|
+
# Priority 1: Check current working directory for local development
|
|
122
|
+
cwd = Path.cwd()
|
|
123
|
+
cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
|
|
124
|
+
if cwd_base_agent.exists():
|
|
125
|
+
self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
|
|
126
|
+
return cwd_base_agent
|
|
127
|
+
|
|
128
|
+
# Priority 2: Check known development locations
|
|
129
|
+
known_dev_paths = [
|
|
130
|
+
Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
|
|
131
|
+
Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
132
|
+
Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
for dev_path in known_dev_paths:
|
|
136
|
+
if dev_path.exists():
|
|
137
|
+
self.logger.info(f"Using development base_agent: {dev_path}")
|
|
138
|
+
return dev_path
|
|
139
|
+
|
|
140
|
+
# Priority 3: Check user override location
|
|
141
|
+
user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
|
|
142
|
+
if user_base_agent.exists():
|
|
143
|
+
self.logger.info(f"Using user override base_agent: {user_base_agent}")
|
|
144
|
+
return user_base_agent
|
|
145
|
+
|
|
146
|
+
# Priority 4: Use framework agents directory (fallback)
|
|
147
|
+
framework_base_agent = paths.agents_dir / "base_agent.json"
|
|
148
|
+
if framework_base_agent.exists():
|
|
149
|
+
self.logger.info(f"Using framework base_agent: {framework_base_agent}")
|
|
150
|
+
return framework_base_agent
|
|
151
|
+
|
|
152
|
+
# If still not found, log all searched locations
|
|
153
|
+
self.logger.warning("Base agent file not found in any location:")
|
|
154
|
+
self.logger.warning(f" 1. CWD: {cwd_base_agent}")
|
|
155
|
+
self.logger.warning(f" 2. Dev paths: {known_dev_paths}")
|
|
156
|
+
self.logger.warning(f" 3. User: {user_base_agent}")
|
|
157
|
+
self.logger.warning(f" 4. Framework: {framework_base_agent}")
|
|
158
|
+
|
|
159
|
+
# Final fallback to framework path even if it doesn't exist
|
|
160
|
+
return framework_base_agent
|
|
97
161
|
|
|
98
162
|
async def discover_agents_async(
|
|
99
163
|
self, directories: List[Path]
|