claude-mpm 5.4.85__py3-none-any.whl → 5.6.1__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/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +101 -703
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +46 -0
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +2 -2
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/executor.py +119 -16
- claude_mpm/cli/parsers/base_parser.py +71 -1
- claude_mpm/cli/parsers/commander_parser.py +83 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/startup.py +54 -16
- claude_mpm/cli/startup_display.py +72 -5
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +72 -0
- claude_mpm/commander/adapters/__init__.py +31 -0
- claude_mpm/commander/adapters/base.py +191 -0
- claude_mpm/commander/adapters/claude_code.py +361 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +105 -0
- claude_mpm/commander/api/errors.py +112 -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 +215 -0
- claude_mpm/commander/api/routes/work.py +260 -0
- claude_mpm/commander/api/schemas.py +182 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +107 -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/daemon.py +398 -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/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 +404 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +316 -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 +189 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +219 -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 +9 -1
- 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/core/config.py +5 -0
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/logger.py +10 -7
- claude_mpm/core/logging_utils.py +4 -2
- claude_mpm/core/output_style_manager.py +15 -5
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +250 -11
- claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +69 -5
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
- claude_mpm/hooks/session_resume_hook.py +85 -1
- claude_mpm/init.py +1 -1
- claude_mpm/scripts/claude-hook-handler.sh +36 -10
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +259 -87
- claude_mpm/services/skills/git_skill_source_manager.py +51 -2
- claude_mpm/services/skills/selective_skill_deployer.py +114 -16
- claude_mpm/services/skills/skill_discovery_service.py +57 -3
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -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-management/SKILL.md +312 -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/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm-5.6.1.dist-info/METADATA +391 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/RECORD +244 -145
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.85.dist-info/METADATA +0 -1023
- /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.1.dist-info}/top_level.txt +0 -0
|
@@ -214,18 +214,90 @@ def get_skills_from_mapping(agent_ids: List[str]) -> Set[str]:
|
|
|
214
214
|
return set()
|
|
215
215
|
|
|
216
216
|
|
|
217
|
+
def extract_skills_from_content(agent_file: Path) -> Set[str]:
|
|
218
|
+
"""Extract skill names from [SKILL: skill-name] markers in agent file content.
|
|
219
|
+
|
|
220
|
+
This function complements frontmatter skill extraction by finding inline
|
|
221
|
+
skill references in the agent's markdown content body.
|
|
222
|
+
|
|
223
|
+
Supports multiple formats:
|
|
224
|
+
- Bold marker: **[SKILL: skill-name]**
|
|
225
|
+
- Plain marker: [SKILL: skill-name]
|
|
226
|
+
- Backtick list: - `skill-name` - Description
|
|
227
|
+
- With spaces: [SKILL: skill-name ]
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
agent_file: Path to agent markdown file
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Set of skill names found in content body
|
|
234
|
+
|
|
235
|
+
Example:
|
|
236
|
+
>>> skills = extract_skills_from_content(Path("pm.md"))
|
|
237
|
+
>>> # Finds skills from markers like **[SKILL: mpm-delegation-patterns]**
|
|
238
|
+
>>> # Also finds from lists like - `mpm-teaching-mode` - Description
|
|
239
|
+
>>> print(f"Found {len(skills)} skills in content")
|
|
240
|
+
"""
|
|
241
|
+
try:
|
|
242
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
243
|
+
except Exception as e:
|
|
244
|
+
logger.warning(f"Failed to read {agent_file}: {e}")
|
|
245
|
+
return set()
|
|
246
|
+
|
|
247
|
+
skills = set()
|
|
248
|
+
|
|
249
|
+
# Pattern 1: [SKILL: skill-name] markers (with optional markdown bold)
|
|
250
|
+
# Handles: **[SKILL: skill-name]** or [SKILL: skill-name]
|
|
251
|
+
# Pattern breakdown:
|
|
252
|
+
# - \*{0,2}: Optional bold markdown (0-2 asterisks)
|
|
253
|
+
# - \[SKILL:\s*: Opening bracket with optional whitespace
|
|
254
|
+
# - ([a-zA-Z0-9_-]+): Skill name (capture group)
|
|
255
|
+
# - \s*\]: Closing bracket with optional whitespace
|
|
256
|
+
# - \*{0,2}: Optional closing bold markdown
|
|
257
|
+
pattern1 = r"\*{0,2}\[SKILL:\s*([a-zA-Z0-9_-]+)\s*\]\*{0,2}"
|
|
258
|
+
matches1 = re.findall(pattern1, content, re.IGNORECASE)
|
|
259
|
+
skills.update(matches1)
|
|
260
|
+
|
|
261
|
+
# Pattern 2: Backtick list items with mpm-* or toolchains-* skills
|
|
262
|
+
# Handles: - `mpm-skill-name` - Description
|
|
263
|
+
# Pattern breakdown:
|
|
264
|
+
# - ^-\s+: Start with dash and whitespace (list item)
|
|
265
|
+
# - `: Opening backtick
|
|
266
|
+
# - ((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+): Skill name starting with prefix
|
|
267
|
+
# - `: Closing backtick
|
|
268
|
+
# - \s+-: Followed by whitespace and dash (description separator)
|
|
269
|
+
pattern2 = r"^-\s+`((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+)`\s+-"
|
|
270
|
+
matches2 = re.findall(pattern2, content, re.MULTILINE | re.IGNORECASE)
|
|
271
|
+
skills.update(matches2)
|
|
272
|
+
|
|
273
|
+
if skills:
|
|
274
|
+
logger.debug(
|
|
275
|
+
f"Found {len(skills)} skills from content markers in {agent_file.name}"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
return skills
|
|
279
|
+
|
|
280
|
+
|
|
217
281
|
def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
|
|
218
282
|
"""Extract all skills referenced by deployed agents.
|
|
219
283
|
|
|
220
|
-
MAJOR CHANGE (Phase 3): Now
|
|
284
|
+
MAJOR CHANGE (Phase 3): Now uses TWO sources for skill discovery:
|
|
285
|
+
1. Frontmatter-declared skills (skills: field)
|
|
286
|
+
2. Content body markers ([SKILL: skill-name])
|
|
287
|
+
|
|
221
288
|
The static skill_to_agent_mapping.yaml is DEPRECATED. Each agent must
|
|
222
|
-
declare its skills
|
|
289
|
+
declare its skills via frontmatter OR inline markers.
|
|
223
290
|
|
|
224
291
|
This change:
|
|
225
292
|
- Eliminates dual-source complexity (frontmatter + mapping)
|
|
226
293
|
- Makes skill requirements explicit per agent
|
|
227
|
-
- Enables per-agent customization via frontmatter
|
|
294
|
+
- Enables per-agent customization via frontmatter or inline markers
|
|
228
295
|
- Removes dependency on static YAML mapping
|
|
296
|
+
- Fixes PM skills being removed as orphaned (they use inline markers)
|
|
297
|
+
|
|
298
|
+
Special handling for PM_INSTRUCTIONS.md:
|
|
299
|
+
- Also scans .claude-mpm/PM_INSTRUCTIONS.md for skill markers
|
|
300
|
+
- PM instructions are not in agents_dir but contain [SKILL: ...] references
|
|
229
301
|
|
|
230
302
|
Args:
|
|
231
303
|
agents_dir: Path to deployed agents directory (e.g., .claude/agents/)
|
|
@@ -244,37 +316,63 @@ def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
|
|
|
244
316
|
|
|
245
317
|
# Scan all agent markdown files
|
|
246
318
|
agent_files = list(agents_dir.glob("*.md"))
|
|
247
|
-
logger.debug(f"Scanning {len(agent_files)} agent files in {agents_dir}")
|
|
248
319
|
|
|
249
|
-
#
|
|
320
|
+
# Special case: Add PM_INSTRUCTIONS.md if it exists
|
|
321
|
+
# PM instructions live in .claude-mpm/ not .claude/agents/
|
|
322
|
+
pm_instructions = agents_dir.parent.parent / ".claude-mpm" / "PM_INSTRUCTIONS.md"
|
|
323
|
+
if pm_instructions.exists():
|
|
324
|
+
agent_files.append(pm_instructions)
|
|
325
|
+
logger.debug("Added PM_INSTRUCTIONS.md for skill scanning")
|
|
326
|
+
|
|
327
|
+
logger.debug(f"Scanning {len(agent_files)} agent files (including PM instructions)")
|
|
328
|
+
|
|
329
|
+
# Use TWO sources: frontmatter AND content markers
|
|
250
330
|
frontmatter_skills = set()
|
|
331
|
+
content_skills = set()
|
|
251
332
|
|
|
252
333
|
for agent_file in agent_files:
|
|
253
334
|
agent_id = agent_file.stem
|
|
254
335
|
|
|
336
|
+
# Source 1: Extract from frontmatter
|
|
255
337
|
frontmatter = parse_agent_frontmatter(agent_file)
|
|
256
|
-
|
|
338
|
+
agent_fm_skills = get_skills_from_agent(frontmatter)
|
|
257
339
|
|
|
258
|
-
if
|
|
259
|
-
frontmatter_skills.update(
|
|
340
|
+
if agent_fm_skills:
|
|
341
|
+
frontmatter_skills.update(agent_fm_skills)
|
|
260
342
|
logger.debug(
|
|
261
|
-
f"Agent {agent_id}: {len(
|
|
343
|
+
f"Agent {agent_id}: {len(agent_fm_skills)} skills from frontmatter"
|
|
262
344
|
)
|
|
263
|
-
|
|
264
|
-
|
|
345
|
+
|
|
346
|
+
# Source 2: Extract from content body [SKILL: ...] markers
|
|
347
|
+
agent_content_skills = extract_skills_from_content(agent_file)
|
|
348
|
+
|
|
349
|
+
if agent_content_skills:
|
|
350
|
+
content_skills.update(agent_content_skills)
|
|
351
|
+
logger.debug(
|
|
352
|
+
f"Agent {agent_id}: {len(agent_content_skills)} skills from content markers"
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if not agent_fm_skills and not agent_content_skills:
|
|
356
|
+
logger.debug(
|
|
357
|
+
f"Agent {agent_id}: No skills declared (checked frontmatter + content)"
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
# Combine both sources
|
|
361
|
+
all_skills = frontmatter_skills | content_skills
|
|
265
362
|
|
|
266
363
|
logger.info(
|
|
267
|
-
f"Found {len(
|
|
268
|
-
f"(
|
|
364
|
+
f"Found {len(all_skills)} unique skills "
|
|
365
|
+
f"({len(frontmatter_skills)} from frontmatter, "
|
|
366
|
+
f"{len(content_skills)} from content markers)"
|
|
269
367
|
)
|
|
270
368
|
|
|
271
369
|
# Normalize skill paths: convert slashes to dashes for compatibility with deployment
|
|
272
370
|
# Some skills may use slash format, normalize to dashes
|
|
273
|
-
normalized_skills = {skill.replace("/", "-") for skill in
|
|
371
|
+
normalized_skills = {skill.replace("/", "-") for skill in all_skills}
|
|
274
372
|
|
|
275
|
-
if normalized_skills !=
|
|
373
|
+
if normalized_skills != all_skills:
|
|
276
374
|
logger.debug(
|
|
277
|
-
f"Normalized {len(
|
|
375
|
+
f"Normalized {len(all_skills)} skills to {len(normalized_skills)} "
|
|
278
376
|
"(converted slashes to dashes)"
|
|
279
377
|
)
|
|
280
378
|
|
|
@@ -163,10 +163,22 @@ class SkillDiscoveryService:
|
|
|
163
163
|
skill_md_files = list(self.skills_dir.rglob("SKILL.md"))
|
|
164
164
|
|
|
165
165
|
# Also find legacy *.md files in top-level directory for backward compatibility
|
|
166
|
+
# Exclude common non-skill documentation files
|
|
167
|
+
excluded_filenames = {
|
|
168
|
+
"skill.md", # Case variations of SKILL.md
|
|
169
|
+
"readme.md",
|
|
170
|
+
"claude.md",
|
|
171
|
+
"contributing.md",
|
|
172
|
+
"changelog.md",
|
|
173
|
+
"license.md",
|
|
174
|
+
"authors.md",
|
|
175
|
+
"code_of_conduct.md",
|
|
176
|
+
}
|
|
177
|
+
|
|
166
178
|
legacy_md_files = [
|
|
167
179
|
f
|
|
168
180
|
for f in self.skills_dir.glob("*.md")
|
|
169
|
-
if f.name
|
|
181
|
+
if f.name.lower() not in excluded_filenames
|
|
170
182
|
]
|
|
171
183
|
|
|
172
184
|
all_skill_files = skill_md_files + legacy_md_files
|
|
@@ -255,7 +267,35 @@ class SkillDiscoveryService:
|
|
|
255
267
|
try:
|
|
256
268
|
frontmatter, body = self._extract_frontmatter(content)
|
|
257
269
|
except Exception as e:
|
|
258
|
-
|
|
270
|
+
# Only log as debug for documentation files to reduce noise
|
|
271
|
+
# Common documentation files (CLAUDE.md, README.md) are expected to lack skill frontmatter
|
|
272
|
+
relative_path = (
|
|
273
|
+
skill_file.relative_to(self.skills_dir)
|
|
274
|
+
if skill_file.is_relative_to(self.skills_dir)
|
|
275
|
+
else skill_file
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Check if this looks like a documentation file
|
|
279
|
+
is_documentation = any(
|
|
280
|
+
doc_pattern in skill_file.name.lower()
|
|
281
|
+
for doc_pattern in [
|
|
282
|
+
"readme",
|
|
283
|
+
"claude",
|
|
284
|
+
"contributing",
|
|
285
|
+
"changelog",
|
|
286
|
+
"license",
|
|
287
|
+
]
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
if is_documentation:
|
|
291
|
+
self.logger.debug(
|
|
292
|
+
f"Skipping documentation file {relative_path} (no skill frontmatter): {e}"
|
|
293
|
+
)
|
|
294
|
+
else:
|
|
295
|
+
# For actual skill files with invalid YAML, use warning level
|
|
296
|
+
self.logger.warning(
|
|
297
|
+
f"Failed to parse skill frontmatter in {relative_path}: {e}"
|
|
298
|
+
)
|
|
259
299
|
return None
|
|
260
300
|
|
|
261
301
|
# Validate required fields
|
|
@@ -354,10 +394,24 @@ class SkillDiscoveryService:
|
|
|
354
394
|
frontmatter_text = match.group(1)
|
|
355
395
|
body = match.group(2)
|
|
356
396
|
|
|
357
|
-
# Parse YAML
|
|
397
|
+
# Parse YAML with improved error handling
|
|
358
398
|
try:
|
|
359
399
|
frontmatter = yaml.safe_load(frontmatter_text)
|
|
360
400
|
except yaml.YAMLError as e:
|
|
401
|
+
# Provide more specific error message with context
|
|
402
|
+
error_line = getattr(e, "problem_mark", None)
|
|
403
|
+
if error_line:
|
|
404
|
+
line_num = error_line.line + 1
|
|
405
|
+
col_num = error_line.column + 1
|
|
406
|
+
# Extract problematic line for context
|
|
407
|
+
lines = frontmatter_text.split("\n")
|
|
408
|
+
problem_line = (
|
|
409
|
+
lines[error_line.line] if error_line.line < len(lines) else ""
|
|
410
|
+
)
|
|
411
|
+
raise ValueError(
|
|
412
|
+
f"Invalid YAML in frontmatter at line {line_num}, column {col_num}: {e.problem}\n"
|
|
413
|
+
f" Problematic line: {problem_line.strip()}"
|
|
414
|
+
) from e
|
|
361
415
|
raise ValueError(f"Invalid YAML in frontmatter: {e}") from e
|
|
362
416
|
|
|
363
417
|
if not isinstance(frontmatter, dict):
|
|
@@ -118,7 +118,8 @@ class HookEventHandler(BaseEventHandler):
|
|
|
118
118
|
self.server.active_sessions[session_id] = {
|
|
119
119
|
"session_id": session_id,
|
|
120
120
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
121
|
-
"
|
|
121
|
+
"current_agent": agent_type, # Current active agent
|
|
122
|
+
"agents": [agent_type], # All agents used in this session
|
|
122
123
|
"status": ServiceState.RUNNING,
|
|
123
124
|
"prompt": data.get("prompt", "")[:100], # First 100 chars
|
|
124
125
|
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
@@ -169,7 +170,8 @@ class HookEventHandler(BaseEventHandler):
|
|
|
169
170
|
self.server.active_sessions[session_id] = {
|
|
170
171
|
"session_id": session_id,
|
|
171
172
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
172
|
-
"
|
|
173
|
+
"current_agent": "pm", # Current active agent
|
|
174
|
+
"agents": ["pm"], # All agents used in this session
|
|
173
175
|
"status": ServiceState.RUNNING,
|
|
174
176
|
"prompt": data.get("prompt_text", "")[:100],
|
|
175
177
|
"working_directory": data.get("working_directory", ""),
|
|
@@ -200,11 +202,16 @@ class HookEventHandler(BaseEventHandler):
|
|
|
200
202
|
# Update session with new agent
|
|
201
203
|
if hasattr(self.server, "active_sessions"):
|
|
202
204
|
if session_id in self.server.active_sessions:
|
|
203
|
-
self.server.active_sessions[session_id]
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
session = self.server.active_sessions[session_id]
|
|
206
|
+
session["current_agent"] = agent_type
|
|
207
|
+
session["status"] = "delegated"
|
|
208
|
+
session["last_activity"] = datetime.now(timezone.utc).isoformat()
|
|
209
|
+
|
|
210
|
+
# Add to agents list if not already present
|
|
211
|
+
if "agents" not in session:
|
|
212
|
+
session["agents"] = []
|
|
213
|
+
if agent_type not in session["agents"]:
|
|
214
|
+
session["agents"].append(agent_type)
|
|
208
215
|
|
|
209
216
|
self.logger.debug(
|
|
210
217
|
f"Updated session delegation: session={session_id[:8]}..., agent={agent_type}"
|
|
@@ -383,7 +383,8 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
383
383
|
self.active_sessions[session_id] = {
|
|
384
384
|
"session_id": session_id,
|
|
385
385
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
386
|
-
"
|
|
386
|
+
"current_agent": "pm", # Current active agent
|
|
387
|
+
"agents": ["pm"], # All agents used in this session
|
|
387
388
|
"status": ServiceState.RUNNING,
|
|
388
389
|
"launch_method": launch_method,
|
|
389
390
|
"working_dir": working_dir,
|
|
@@ -419,8 +420,15 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
419
420
|
"""Notify agent delegation."""
|
|
420
421
|
# Update active session with current agent
|
|
421
422
|
if self.session_id and self.session_id in self.active_sessions:
|
|
422
|
-
self.active_sessions[self.session_id]
|
|
423
|
-
|
|
423
|
+
session = self.active_sessions[self.session_id]
|
|
424
|
+
session["current_agent"] = agent
|
|
425
|
+
session["status"] = status
|
|
426
|
+
|
|
427
|
+
# Add to agents list if not already present
|
|
428
|
+
if "agents" not in session:
|
|
429
|
+
session["agents"] = []
|
|
430
|
+
if agent not in session["agents"]:
|
|
431
|
+
session["agents"].append(agent)
|
|
424
432
|
|
|
425
433
|
if self.broadcaster:
|
|
426
434
|
self.broadcaster.agent_delegated(agent, task, status)
|
|
@@ -480,7 +488,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
480
488
|
start_time = datetime.fromisoformat(session_data["start_time"])
|
|
481
489
|
if start_time.timestamp() < cutoff_time:
|
|
482
490
|
sessions_to_remove.append(session_id)
|
|
483
|
-
except Exception:
|
|
491
|
+
except Exception: # nosec B110 - Silently skip malformed timestamps
|
|
484
492
|
pass
|
|
485
493
|
|
|
486
494
|
for session_id in sessions_to_remove:
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mpm
|
|
3
|
+
description: Access Claude MPM functionality and manage multi-agent orchestration
|
|
4
|
+
user-invocable: true
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
category: mpm-command
|
|
7
|
+
tags: [mpm-command, system, pm-required]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /mpm
|
|
11
|
+
|
|
12
|
+
Access Claude MPM functionality and manage your multi-agent orchestration.
|
|
13
|
+
|
|
14
|
+
## Available MPM Commands
|
|
15
|
+
|
|
16
|
+
- `/mpm-agents` - Show available agents and versions
|
|
17
|
+
- `/mpm-doctor` - Run diagnostic checks
|
|
18
|
+
- `/mpm-help` - Show command help
|
|
19
|
+
- `/mpm-status` - Show MPM status
|
|
20
|
+
- `/mpm-ticket` - Ticketing workflow management (organize, proceed, status, update, project)
|
|
21
|
+
- `/mpm-config` - Manage configuration
|
|
22
|
+
- `/mpm-resume` - Create session resume files
|
|
23
|
+
- `/mpm-version` - Display version information for project, agents, and skills
|
|
24
|
+
|
|
25
|
+
## What is Claude MPM?
|
|
26
|
+
|
|
27
|
+
Claude MPM extends Claude Code with:
|
|
28
|
+
- **Multi-agent orchestration** - Delegate work to specialized agents
|
|
29
|
+
- **Project-specific PM instructions** - Tailored guidance for your project
|
|
30
|
+
- **Agent memory management** - Context-aware agent interactions
|
|
31
|
+
- **WebSocket monitoring** - Real-time system monitoring
|
|
32
|
+
- **Hook system for automation** - Automate workflows and tasks
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
Use `/mpm-help` to explore commands or `/mpm-status` to check system health.
|
|
37
|
+
|
|
38
|
+
For more information, use `/mpm-help [command]` for specific command details.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# PM Skill: Agent Update Workflow
|
|
2
|
+
|
|
3
|
+
## Trigger Patterns
|
|
4
|
+
- "update agent", "fix agent", "improve agent", "modify agent"
|
|
5
|
+
- "change {agent-name} agent", "edit agent instructions"
|
|
6
|
+
- Any request to modify agent behavior
|
|
7
|
+
|
|
8
|
+
## FUNDAMENTAL RULE: Official vs Custom Agents
|
|
9
|
+
|
|
10
|
+
### Official MPM Agents (NEVER edit deployed copies)
|
|
11
|
+
**Source**: `~/.claude-mpm/cache/agents/` (from bobmatnyc/claude-mpm-agents repo)
|
|
12
|
+
**Deployed**: `.claude/agents/` - READ-ONLY for official agents
|
|
13
|
+
|
|
14
|
+
**Detection**: Check if agent exists in `~/.claude-mpm/cache/agents/`
|
|
15
|
+
- If YES → Official agent → Follow Official Agent Workflow
|
|
16
|
+
- If NO → Custom agent → Can edit `.claude/agents/` directly
|
|
17
|
+
|
|
18
|
+
### Custom/Localized Agents
|
|
19
|
+
- Created specifically for project
|
|
20
|
+
- Can be edited directly in `.claude/agents/`
|
|
21
|
+
- Not part of official MPM agent set
|
|
22
|
+
|
|
23
|
+
## Official Agent Update Workflow
|
|
24
|
+
|
|
25
|
+
### Step 1: Identify Agent Source
|
|
26
|
+
```bash
|
|
27
|
+
ls ~/.claude-mpm/cache/agents/ # Find the source file
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Step 2: Update Source
|
|
31
|
+
Edit the agent source in `~/.claude-mpm/cache/agents/{agent-name}.md`
|
|
32
|
+
(or appropriate path based on agent structure)
|
|
33
|
+
|
|
34
|
+
### Step 3: Rebuild and Redeploy
|
|
35
|
+
Use MPM deployment tools:
|
|
36
|
+
```bash
|
|
37
|
+
# Redeploy specific agent
|
|
38
|
+
mpm agents deploy {agent-name}
|
|
39
|
+
|
|
40
|
+
# Or redeploy all agents
|
|
41
|
+
mpm agents deploy --all
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Step 4: Validate (claude-mpm project only)
|
|
45
|
+
When working in the claude-mpm project itself:
|
|
46
|
+
```bash
|
|
47
|
+
# Run deepeval against deployed agent instructions
|
|
48
|
+
deepeval test --agent {agent-name}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Circuit Breaker
|
|
52
|
+
|
|
53
|
+
**BLOCK** if attempting to edit `.claude/agents/{official-agent}.md` directly:
|
|
54
|
+
- Official agents in deployed location are BUILD OUTPUTS
|
|
55
|
+
- Must update source → rebuild → redeploy
|
|
56
|
+
- Violation = architectural breach
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### ❌ WRONG (Editing deployed official agent)
|
|
61
|
+
```
|
|
62
|
+
Edit: .claude/agents/web-qa.md # VIOLATION - this is a built output
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### ✅ CORRECT (Updating source and redeploying)
|
|
66
|
+
```
|
|
67
|
+
1. Edit: ~/.claude-mpm/cache/agents/web-qa.md # Update source
|
|
68
|
+
2. Run: mpm agents deploy web-qa # Rebuild/redeploy
|
|
69
|
+
3. Validate: deepeval test --agent web-qa # (in claude-mpm project)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### ✅ CORRECT (Custom agent - can edit directly)
|
|
73
|
+
```
|
|
74
|
+
Edit: .claude/agents/my-custom-agent.md # OK - not an official agent
|
|
75
|
+
```
|