claude-mpm 5.4.96__py3-none-any.whl → 5.6.17__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +44 -10
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +45 -5
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +32 -17
- claude_mpm/cli/parsers/base_parser.py +17 -0
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +124 -3
- claude_mpm/cli/startup_display.py +2 -1
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +111 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +49 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +594 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +143 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +337 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +8 -0
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/core/claude_runner.py +143 -0
- claude_mpm/core/config.py +32 -19
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/output_style_manager.py +49 -12
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +29 -30
- claude_mpm/hooks/claude_hooks/event_handlers.py +112 -99
- claude_mpm/hooks/claude_hooks/hook_handler.py +81 -88
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +116 -8
- claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
- claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +23 -28
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +47 -73
- claude_mpm/hooks/session_resume_hook.py +22 -18
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/scripts/claude-hook-handler.sh +43 -16
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/event_log.py +8 -0
- claude_mpm/services/pm_skills_deployer.py +84 -6
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +28 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/METADATA +22 -6
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/RECORD +213 -83
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.17.dist-info}/top_level.txt +0 -0
claude_mpm/skills/registry.py
CHANGED
|
@@ -14,35 +14,144 @@ logger = get_logger(__name__)
|
|
|
14
14
|
|
|
15
15
|
@dataclass
|
|
16
16
|
class Skill:
|
|
17
|
-
"""Represents a skill that can be used by agents.
|
|
18
|
-
|
|
17
|
+
"""Represents a skill that can be used by agents.
|
|
18
|
+
|
|
19
|
+
Supports agentskills.io specification with backward compatibility for legacy claude-mpm format.
|
|
20
|
+
|
|
21
|
+
Spec fields (agentskills.io):
|
|
22
|
+
- name: Required, 1-64 chars, lowercase alphanumeric + hyphens
|
|
23
|
+
- description: Required, 1-1024 chars
|
|
24
|
+
- license: Optional, license name or reference
|
|
25
|
+
- compatibility: Optional, max 500 chars, environment requirements
|
|
26
|
+
- metadata: Optional, key-value mapping for arbitrary data
|
|
27
|
+
- allowed_tools: Optional, list of pre-approved tools
|
|
28
|
+
|
|
29
|
+
Internal fields:
|
|
30
|
+
- path: Path to skill file
|
|
31
|
+
- content: Skill content (markdown)
|
|
32
|
+
- source: Origin of skill ('bundled', 'user', 'project', 'pm')
|
|
33
|
+
- version: Skill version (from metadata.version or top-level)
|
|
34
|
+
- skill_id: Internal ID (defaults to name)
|
|
35
|
+
- agent_types: Which agent types can use this skill
|
|
36
|
+
- updated_at: Last update timestamp (from metadata.updated)
|
|
37
|
+
- tags: Tags for discovery (from metadata.tags or top-level)
|
|
38
|
+
|
|
39
|
+
Claude-mpm extensions (preserved for backward compat):
|
|
40
|
+
- category: Skill category for organization
|
|
41
|
+
- toolchain: Associated toolchain (python, javascript, etc.)
|
|
42
|
+
- progressive_disclosure: Progressive disclosure configuration
|
|
43
|
+
- user_invocable: Whether skill can be manually invoked
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Core spec fields (agentskills.io)
|
|
19
47
|
name: str
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
48
|
+
description: str
|
|
49
|
+
license: Optional[str] = None
|
|
50
|
+
compatibility: Optional[str] = None
|
|
51
|
+
metadata: Dict[str, Any] = None
|
|
52
|
+
allowed_tools: List[str] = None
|
|
53
|
+
|
|
54
|
+
# Internal fields (not in frontmatter spec)
|
|
55
|
+
path: Path = None
|
|
56
|
+
content: str = ""
|
|
57
|
+
source: str = "bundled" # 'bundled', 'user', 'project', 'pm'
|
|
58
|
+
|
|
59
|
+
# Derived fields (from metadata or fallback)
|
|
60
|
+
version: str = "0.1.0" # From metadata.version or top-level
|
|
61
|
+
skill_id: str = "" # Internal ID (defaults to name)
|
|
30
62
|
agent_types: List[str] = None # Which agent types can use this skill
|
|
63
|
+
updated_at: Optional[str] = None # From metadata.updated
|
|
64
|
+
tags: List[str] = None # From metadata.tags or top-level
|
|
31
65
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
66
|
+
# Claude-mpm extensions (preserved for backward compat)
|
|
67
|
+
category: Optional[str] = None
|
|
68
|
+
toolchain: Optional[str] = None
|
|
69
|
+
progressive_disclosure: Optional[Dict[str, Any]] = None
|
|
70
|
+
user_invocable: bool = False
|
|
35
71
|
|
|
36
72
|
def __post_init__(self):
|
|
37
73
|
"""Initialize default values if not provided."""
|
|
74
|
+
if self.metadata is None:
|
|
75
|
+
self.metadata = {}
|
|
38
76
|
if self.agent_types is None:
|
|
39
77
|
self.agent_types = []
|
|
40
78
|
if self.tags is None:
|
|
41
79
|
self.tags = []
|
|
80
|
+
if self.allowed_tools is None:
|
|
81
|
+
self.allowed_tools = []
|
|
42
82
|
if not self.skill_id:
|
|
43
83
|
self.skill_id = self.name
|
|
44
84
|
|
|
45
85
|
|
|
86
|
+
def validate_agentskills_spec(skill: Skill) -> tuple[bool, List[str]]:
|
|
87
|
+
"""Validate skill against agentskills.io specification.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
skill: Skill object to validate
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Tuple of (is_valid, list_of_warnings)
|
|
94
|
+
- is_valid: True if skill meets spec requirements
|
|
95
|
+
- warnings: List of warning messages for spec violations
|
|
96
|
+
"""
|
|
97
|
+
warnings = []
|
|
98
|
+
|
|
99
|
+
# Validate name (required field)
|
|
100
|
+
if not skill.name:
|
|
101
|
+
warnings.append("Missing required field: name")
|
|
102
|
+
return False, warnings
|
|
103
|
+
|
|
104
|
+
# Validate name format: lowercase alphanumeric + hyphens, no leading/trailing hyphens
|
|
105
|
+
if not re.match(r"^[a-z0-9]+(-[a-z0-9]+)*$", skill.name):
|
|
106
|
+
warnings.append(
|
|
107
|
+
f"Invalid name format: '{skill.name}' (must be lowercase alphanumeric with hyphens, "
|
|
108
|
+
"no leading/trailing hyphens, no consecutive hyphens)"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Validate name length (max 64 chars)
|
|
112
|
+
if len(skill.name) > 64:
|
|
113
|
+
warnings.append(
|
|
114
|
+
f"Name too long: {len(skill.name)} chars (max 64 per agentskills.io spec)"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Validate description (required field)
|
|
118
|
+
if not skill.description:
|
|
119
|
+
warnings.append("Missing required field: description")
|
|
120
|
+
return False, warnings
|
|
121
|
+
|
|
122
|
+
# Validate description length (1-1024 chars)
|
|
123
|
+
desc_len = len(skill.description)
|
|
124
|
+
if desc_len < 1 or desc_len > 1024:
|
|
125
|
+
warnings.append(
|
|
126
|
+
f"Description length {desc_len} chars is outside spec range (1-1024 chars)"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Validate compatibility length (max 500 chars)
|
|
130
|
+
if skill.compatibility and len(skill.compatibility) > 500:
|
|
131
|
+
warnings.append(
|
|
132
|
+
f"Compatibility field too long: {len(skill.compatibility)} chars (max 500)"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Validate metadata is dict
|
|
136
|
+
if skill.metadata is not None and not isinstance(skill.metadata, dict):
|
|
137
|
+
warnings.append("Metadata must be a key-value mapping (dict)")
|
|
138
|
+
|
|
139
|
+
# Check for spec-compliant metadata structure
|
|
140
|
+
spec_metadata_fields = ["version", "author", "updated", "tags"]
|
|
141
|
+
for field in spec_metadata_fields:
|
|
142
|
+
if hasattr(skill, field):
|
|
143
|
+
field_value = getattr(skill, field)
|
|
144
|
+
if field_value and field not in skill.metadata:
|
|
145
|
+
warnings.append(
|
|
146
|
+
f"Field '{field}' should be in metadata block per agentskills.io spec "
|
|
147
|
+
f"(found as top-level field)"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Valid if no errors (only warnings allowed)
|
|
151
|
+
is_valid = len(warnings) == 0 or all("should be in metadata" in w for w in warnings)
|
|
152
|
+
return is_valid, warnings
|
|
153
|
+
|
|
154
|
+
|
|
46
155
|
class SkillsRegistry:
|
|
47
156
|
"""Registry for managing skills across all tiers."""
|
|
48
157
|
|
|
@@ -54,7 +163,10 @@ class SkillsRegistry:
|
|
|
54
163
|
self._load_project_skills()
|
|
55
164
|
|
|
56
165
|
def _parse_skill_frontmatter(self, content: str) -> Dict[str, Any]:
|
|
57
|
-
"""Parse YAML frontmatter from skill markdown file.
|
|
166
|
+
"""Parse YAML frontmatter from skill markdown file with spec validation.
|
|
167
|
+
|
|
168
|
+
Supports both agentskills.io spec format and legacy claude-mpm format
|
|
169
|
+
with automatic migration.
|
|
58
170
|
|
|
59
171
|
Returns:
|
|
60
172
|
Dict with frontmatter fields or empty dict if no frontmatter
|
|
@@ -70,11 +182,150 @@ class SkillsRegistry:
|
|
|
70
182
|
|
|
71
183
|
try:
|
|
72
184
|
frontmatter = yaml.safe_load(match.group(1))
|
|
73
|
-
|
|
185
|
+
if not frontmatter:
|
|
186
|
+
return {}
|
|
187
|
+
|
|
188
|
+
# Apply backward compatibility migration
|
|
189
|
+
return self._apply_backward_compatibility(frontmatter)
|
|
74
190
|
except yaml.YAMLError as e:
|
|
75
191
|
logger.warning(f"Failed to parse skill frontmatter: {e}")
|
|
76
192
|
return {}
|
|
77
193
|
|
|
194
|
+
def _apply_backward_compatibility(
|
|
195
|
+
self, frontmatter: Dict[str, Any]
|
|
196
|
+
) -> Dict[str, Any]:
|
|
197
|
+
"""Apply backward compatibility transformations to legacy frontmatter.
|
|
198
|
+
|
|
199
|
+
Auto-migrates legacy claude-mpm fields to agentskills.io spec format:
|
|
200
|
+
- version → metadata.version
|
|
201
|
+
- author → metadata.author
|
|
202
|
+
- updated → metadata.updated
|
|
203
|
+
- tags → metadata.tags (if not already present)
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
frontmatter: Parsed frontmatter dict
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Transformed frontmatter with spec-compliant structure
|
|
210
|
+
"""
|
|
211
|
+
# Initialize metadata if not present
|
|
212
|
+
if "metadata" not in frontmatter:
|
|
213
|
+
frontmatter["metadata"] = {}
|
|
214
|
+
|
|
215
|
+
metadata = frontmatter["metadata"]
|
|
216
|
+
|
|
217
|
+
# Auto-migrate version (top-level → metadata.version)
|
|
218
|
+
if "version" in frontmatter and "version" not in metadata:
|
|
219
|
+
metadata["version"] = frontmatter["version"]
|
|
220
|
+
logger.debug(
|
|
221
|
+
f"Auto-migrated 'version' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Auto-migrate author (top-level → metadata.author)
|
|
225
|
+
if "author" in frontmatter and "author" not in metadata:
|
|
226
|
+
metadata["author"] = frontmatter["author"]
|
|
227
|
+
logger.debug(
|
|
228
|
+
f"Auto-migrated 'author' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Auto-migrate updated (top-level → metadata.updated)
|
|
232
|
+
if "updated" in frontmatter and "updated" not in metadata:
|
|
233
|
+
metadata["updated"] = frontmatter["updated"]
|
|
234
|
+
logger.debug(
|
|
235
|
+
f"Auto-migrated 'updated' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# Auto-migrate tags (top-level → metadata.tags)
|
|
239
|
+
if "tags" in frontmatter and "tags" not in metadata:
|
|
240
|
+
metadata["tags"] = frontmatter["tags"]
|
|
241
|
+
logger.debug(
|
|
242
|
+
f"Auto-migrated 'tags' to metadata for skill '{frontmatter.get('name', 'unknown')}'"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
# Parse allowed-tools from space-delimited string to list
|
|
246
|
+
if "allowed-tools" in frontmatter:
|
|
247
|
+
allowed_tools = frontmatter["allowed-tools"]
|
|
248
|
+
if isinstance(allowed_tools, str):
|
|
249
|
+
frontmatter["allowed-tools"] = allowed_tools.split()
|
|
250
|
+
|
|
251
|
+
# Set default compatibility for claude-code if not present
|
|
252
|
+
if "compatibility" not in frontmatter:
|
|
253
|
+
frontmatter["compatibility"] = "claude-code"
|
|
254
|
+
|
|
255
|
+
return frontmatter
|
|
256
|
+
|
|
257
|
+
def _create_skill_from_frontmatter(
|
|
258
|
+
self, frontmatter: Dict[str, Any], path: Path, content: str, source: str
|
|
259
|
+
) -> Optional[Skill]:
|
|
260
|
+
"""Create Skill object from frontmatter with spec compliance.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
frontmatter: Parsed and migrated frontmatter dict
|
|
264
|
+
path: Path to skill file
|
|
265
|
+
content: Full skill content
|
|
266
|
+
source: Source type ('bundled', 'user', 'project', 'pm')
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Skill object or None if required fields missing
|
|
270
|
+
"""
|
|
271
|
+
# Extract spec fields (required)
|
|
272
|
+
name = frontmatter.get("name")
|
|
273
|
+
description = frontmatter.get("description", "")
|
|
274
|
+
|
|
275
|
+
# If name not in frontmatter, use filename stem
|
|
276
|
+
if not name:
|
|
277
|
+
name = path.stem
|
|
278
|
+
|
|
279
|
+
# If description not in frontmatter, extract from content
|
|
280
|
+
if not description:
|
|
281
|
+
description = self._extract_description(content)
|
|
282
|
+
|
|
283
|
+
# Validate required fields
|
|
284
|
+
if not name or not description:
|
|
285
|
+
logger.warning(
|
|
286
|
+
f"Skipping skill at {path}: missing required field (name or description)"
|
|
287
|
+
)
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
# Extract spec fields (optional)
|
|
291
|
+
license_field = frontmatter.get("license")
|
|
292
|
+
compatibility = frontmatter.get("compatibility", "claude-code")
|
|
293
|
+
metadata = frontmatter.get("metadata", {})
|
|
294
|
+
allowed_tools = frontmatter.get("allowed-tools", [])
|
|
295
|
+
|
|
296
|
+
# Extract derived fields from metadata or top-level
|
|
297
|
+
version = frontmatter.get("version") or metadata.get("version", "0.1.0")
|
|
298
|
+
skill_id = frontmatter.get("skill_id", name)
|
|
299
|
+
updated_at = frontmatter.get("updated_at") or metadata.get("updated")
|
|
300
|
+
tags = frontmatter.get("tags", []) or metadata.get("tags", [])
|
|
301
|
+
|
|
302
|
+
# Extract claude-mpm extensions
|
|
303
|
+
category = frontmatter.get("category")
|
|
304
|
+
toolchain = frontmatter.get("toolchain")
|
|
305
|
+
progressive_disclosure = frontmatter.get("progressive_disclosure")
|
|
306
|
+
user_invocable = frontmatter.get("user-invocable", False)
|
|
307
|
+
|
|
308
|
+
# Create skill object
|
|
309
|
+
return Skill(
|
|
310
|
+
name=name,
|
|
311
|
+
description=description,
|
|
312
|
+
license=license_field,
|
|
313
|
+
compatibility=compatibility,
|
|
314
|
+
metadata=metadata,
|
|
315
|
+
allowed_tools=allowed_tools,
|
|
316
|
+
path=path,
|
|
317
|
+
content=content,
|
|
318
|
+
source=source,
|
|
319
|
+
version=version,
|
|
320
|
+
skill_id=skill_id,
|
|
321
|
+
updated_at=updated_at,
|
|
322
|
+
tags=tags,
|
|
323
|
+
category=category,
|
|
324
|
+
toolchain=toolchain,
|
|
325
|
+
progressive_disclosure=progressive_disclosure,
|
|
326
|
+
user_invocable=user_invocable,
|
|
327
|
+
)
|
|
328
|
+
|
|
78
329
|
def _load_bundled_skills(self):
|
|
79
330
|
"""Load skills bundled with MPM."""
|
|
80
331
|
bundled_dir = Path(__file__).parent / "bundled"
|
|
@@ -88,32 +339,16 @@ class SkillsRegistry:
|
|
|
88
339
|
skill_name = skill_file.stem
|
|
89
340
|
content = skill_file.read_text(encoding="utf-8")
|
|
90
341
|
|
|
91
|
-
# Parse frontmatter
|
|
342
|
+
# Parse frontmatter with backward compatibility
|
|
92
343
|
frontmatter = self._parse_skill_frontmatter(content)
|
|
93
344
|
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
updated_at = frontmatter.get("updated_at")
|
|
98
|
-
tags = frontmatter.get("tags", [])
|
|
99
|
-
|
|
100
|
-
# Extract description (from frontmatter or fallback to content parsing)
|
|
101
|
-
description = frontmatter.get("description", "")
|
|
102
|
-
if not description:
|
|
103
|
-
description = self._extract_description(content)
|
|
104
|
-
|
|
105
|
-
self.skills[skill_name] = Skill(
|
|
106
|
-
name=skill_name,
|
|
107
|
-
path=skill_file,
|
|
108
|
-
content=content,
|
|
109
|
-
source="bundled",
|
|
110
|
-
version=version,
|
|
111
|
-
skill_id=skill_id,
|
|
112
|
-
description=description,
|
|
113
|
-
updated_at=updated_at,
|
|
114
|
-
tags=tags,
|
|
345
|
+
# Create skill from frontmatter
|
|
346
|
+
skill = self._create_skill_from_frontmatter(
|
|
347
|
+
frontmatter, skill_file, content, "bundled"
|
|
115
348
|
)
|
|
116
|
-
|
|
349
|
+
if skill:
|
|
350
|
+
self.skills[skill_name] = skill
|
|
351
|
+
skill_count += 1
|
|
117
352
|
except Exception as e:
|
|
118
353
|
logger.error(f"Error loading bundled skill {skill_file}: {e}")
|
|
119
354
|
|
|
@@ -130,36 +365,20 @@ class SkillsRegistry:
|
|
|
130
365
|
for skill_file in user_skills_dir.glob("*.md"):
|
|
131
366
|
try:
|
|
132
367
|
skill_name = skill_file.stem
|
|
133
|
-
# User skills override bundled skills
|
|
134
368
|
content = skill_file.read_text(encoding="utf-8")
|
|
135
369
|
|
|
136
|
-
# Parse frontmatter
|
|
370
|
+
# Parse frontmatter with backward compatibility
|
|
137
371
|
frontmatter = self._parse_skill_frontmatter(content)
|
|
138
372
|
|
|
139
|
-
#
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
updated_at = frontmatter.get("updated_at")
|
|
143
|
-
tags = frontmatter.get("tags", [])
|
|
144
|
-
|
|
145
|
-
# Extract description (from frontmatter or fallback to content parsing)
|
|
146
|
-
description = frontmatter.get("description", "")
|
|
147
|
-
if not description:
|
|
148
|
-
description = self._extract_description(content)
|
|
149
|
-
|
|
150
|
-
self.skills[skill_name] = Skill(
|
|
151
|
-
name=skill_name,
|
|
152
|
-
path=skill_file,
|
|
153
|
-
content=content,
|
|
154
|
-
source="user",
|
|
155
|
-
version=version,
|
|
156
|
-
skill_id=skill_id,
|
|
157
|
-
description=description,
|
|
158
|
-
updated_at=updated_at,
|
|
159
|
-
tags=tags,
|
|
373
|
+
# Create skill from frontmatter
|
|
374
|
+
skill = self._create_skill_from_frontmatter(
|
|
375
|
+
frontmatter, skill_file, content, "user"
|
|
160
376
|
)
|
|
161
|
-
|
|
162
|
-
|
|
377
|
+
if skill:
|
|
378
|
+
# User skills override bundled skills
|
|
379
|
+
self.skills[skill_name] = skill
|
|
380
|
+
skill_count += 1
|
|
381
|
+
logger.debug(f"User skill '{skill_name}' overrides bundled version")
|
|
163
382
|
except Exception as e:
|
|
164
383
|
logger.error(f"Error loading user skill {skill_file}: {e}")
|
|
165
384
|
|
|
@@ -177,36 +396,22 @@ class SkillsRegistry:
|
|
|
177
396
|
for skill_file in project_skills_dir.glob("*.md"):
|
|
178
397
|
try:
|
|
179
398
|
skill_name = skill_file.stem
|
|
180
|
-
# Project skills override both user and bundled skills
|
|
181
399
|
content = skill_file.read_text(encoding="utf-8")
|
|
182
400
|
|
|
183
|
-
# Parse frontmatter
|
|
401
|
+
# Parse frontmatter with backward compatibility
|
|
184
402
|
frontmatter = self._parse_skill_frontmatter(content)
|
|
185
403
|
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
updated_at = frontmatter.get("updated_at")
|
|
190
|
-
tags = frontmatter.get("tags", [])
|
|
191
|
-
|
|
192
|
-
# Extract description (from frontmatter or fallback to content parsing)
|
|
193
|
-
description = frontmatter.get("description", "")
|
|
194
|
-
if not description:
|
|
195
|
-
description = self._extract_description(content)
|
|
196
|
-
|
|
197
|
-
self.skills[skill_name] = Skill(
|
|
198
|
-
name=skill_name,
|
|
199
|
-
path=skill_file,
|
|
200
|
-
content=content,
|
|
201
|
-
source="project",
|
|
202
|
-
version=version,
|
|
203
|
-
skill_id=skill_id,
|
|
204
|
-
description=description,
|
|
205
|
-
updated_at=updated_at,
|
|
206
|
-
tags=tags,
|
|
404
|
+
# Create skill from frontmatter
|
|
405
|
+
skill = self._create_skill_from_frontmatter(
|
|
406
|
+
frontmatter, skill_file, content, "project"
|
|
207
407
|
)
|
|
208
|
-
|
|
209
|
-
|
|
408
|
+
if skill:
|
|
409
|
+
# Project skills override both user and bundled skills
|
|
410
|
+
self.skills[skill_name] = skill
|
|
411
|
+
skill_count += 1
|
|
412
|
+
logger.debug(
|
|
413
|
+
f"Project skill '{skill_name}' overrides other versions"
|
|
414
|
+
)
|
|
210
415
|
except Exception as e:
|
|
211
416
|
logger.error(f"Error loading project skill {skill_file}: {e}")
|
|
212
417
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-mpm
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.6.17
|
|
4
4
|
Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
|
|
5
5
|
Author-email: Bob Matsuoka <bob@matsuoka.com>
|
|
6
6
|
Maintainer: Claude MPM Team
|
|
@@ -23,7 +23,7 @@ License-File: LICENSE
|
|
|
23
23
|
License-File: LICENSE-FAQ.md
|
|
24
24
|
Requires-Dist: ai-trackdown-pytools>=1.4.0
|
|
25
25
|
Requires-Dist: pyyaml>=6.0
|
|
26
|
-
Requires-Dist: python-dotenv>=0.
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
27
27
|
Requires-Dist: click>=8.0.0
|
|
28
28
|
Requires-Dist: pexpect>=4.8.0
|
|
29
29
|
Requires-Dist: psutil>=5.9.0
|
|
@@ -49,6 +49,8 @@ Requires-Dist: rich>=13.0.0
|
|
|
49
49
|
Requires-Dist: questionary>=2.0.0
|
|
50
50
|
Requires-Dist: pyee>=13.0.0
|
|
51
51
|
Requires-Dist: pathspec>=0.11.0
|
|
52
|
+
Requires-Dist: fastapi>=0.100.0
|
|
53
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
52
54
|
Provides-Extra: mcp
|
|
53
55
|
Requires-Dist: mcp>=0.1.0; extra == "mcp"
|
|
54
56
|
Requires-Dist: mcp-vector-search>=0.1.0; extra == "mcp"
|
|
@@ -108,7 +110,7 @@ Dynamic: license-file
|
|
|
108
110
|
|
|
109
111
|
A powerful orchestration framework for **Claude Code (CLI)** that enables multi-agent workflows, session management, and real-time monitoring through a streamlined Rich-based interface.
|
|
110
112
|
|
|
111
|
-
> **⚠️ Important**: Claude MPM **requires Claude Code CLI** (v2.
|
|
113
|
+
> **⚠️ Important**: Claude MPM **requires Claude Code CLI** (v2.1.3+), not Claude Desktop (app). All MCP integrations work with Claude Code's CLI interface only.
|
|
112
114
|
>
|
|
113
115
|
> **Don't have Claude Code?** Install from: https://docs.anthropic.com/en/docs/claude-code
|
|
114
116
|
>
|
|
@@ -118,7 +120,7 @@ A powerful orchestration framework for **Claude Code (CLI)** that enables multi-
|
|
|
118
120
|
|
|
119
121
|
## Who Should Use Claude MPM?
|
|
120
122
|
|
|
121
|
-
- 👥 **[Non-Technical Users (Founders/PMs)](docs/usecases/non-technical-users.md)** -
|
|
123
|
+
- 👥 **[Non-Technical Users (Founders/PMs)](docs/usecases/non-technical-users.md)** - Research and understand codebases using Research Mode - no coding experience required
|
|
122
124
|
- 💻 **[Developers](docs/usecases/developers.md)** - Multi-agent development workflows with semantic code search and advanced features
|
|
123
125
|
- 🏢 **[Teams](docs/usecases/teams.md)** - Collaboration patterns, session management, and coordinated workflows
|
|
124
126
|
|
|
@@ -141,8 +143,10 @@ Claude MPM transforms Claude Code into a **multi-agent orchestration platform**
|
|
|
141
143
|
|
|
142
144
|
### Prerequisites
|
|
143
145
|
|
|
144
|
-
1. **Python 3.
|
|
145
|
-
2. **Claude Code CLI v2.
|
|
146
|
+
1. **Python 3.11+** (required - older versions will install outdated claude-mpm)
|
|
147
|
+
2. **Claude Code CLI v2.1.3+** (required!)
|
|
148
|
+
|
|
149
|
+
> ⚠️ **Python Version Note**: Claude MPM requires Python 3.11 or higher. If you have Python 3.9 or 3.10, you'll get an old version (4.x) that lacks current features. Check with `python3 --version` before installing.
|
|
146
150
|
|
|
147
151
|
```bash
|
|
148
152
|
# Verify Claude Code is installed
|
|
@@ -195,6 +199,8 @@ ls ~/.claude/agents/ # Should show 47+ agents
|
|
|
195
199
|
|
|
196
200
|
**💡 Recommended Partners**: Install [kuzu-memory](https://github.com/bobmatnyc/kuzu-memory) (persistent context) and [mcp-vector-search](https://github.com/bobmatnyc/mcp-vector-search) (semantic search) for enhanced capabilities.
|
|
197
201
|
|
|
202
|
+
**💡 Tool Version Management**: Use [ASDF version manager](docs/guides/asdf-tool-versions.md) to avoid Python/uv version conflicts across projects.
|
|
203
|
+
|
|
198
204
|
---
|
|
199
205
|
|
|
200
206
|
## Key Features
|
|
@@ -231,6 +237,16 @@ ls ~/.claude/agents/ # Should show 47+ agents
|
|
|
231
237
|
|
|
232
238
|
[→ Learn more: Developer Use Cases](docs/usecases/developers.md#semantic-code-search)
|
|
233
239
|
|
|
240
|
+
### 🧪 MPM Commander (ALPHA)
|
|
241
|
+
- **Multi-Project Orchestration** with autonomous AI coordination across codebases
|
|
242
|
+
- **Tmux Integration** for isolated project environments and session management
|
|
243
|
+
- **Event-Driven Architecture** with inbox system for cross-project communication
|
|
244
|
+
- **LLM-Powered Decisions** via OpenRouter for autonomous work queue processing
|
|
245
|
+
- **Real-Time Monitoring** with state tracking (IDLE, WORKING, BLOCKED, PAUSED, ERROR)
|
|
246
|
+
- ⚠️ **Experimental** - API and CLI interface subject to change
|
|
247
|
+
|
|
248
|
+
[→ Commander Documentation](docs/commander/usage-guide.md)
|
|
249
|
+
|
|
234
250
|
### 🔌 Advanced Integration
|
|
235
251
|
- **MCP Integration** with full Model Context Protocol support
|
|
236
252
|
- **Real-Time Monitoring** via `--monitor` flag and web dashboard
|