claude-mpm 5.4.64__py3-none-any.whl → 5.4.96__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (163) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md +405 -0
  3. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +107 -1928
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +82 -686
  6. claude_mpm/cli/__init__.py +5 -1
  7. claude_mpm/cli/commands/agents.py +2 -4
  8. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  9. claude_mpm/cli/commands/autotodos.py +526 -0
  10. claude_mpm/cli/commands/configure.py +620 -21
  11. claude_mpm/cli/commands/monitor.py +2 -2
  12. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  13. claude_mpm/cli/commands/skills.py +166 -14
  14. claude_mpm/cli/executor.py +89 -0
  15. claude_mpm/cli/interactive/__init__.py +10 -0
  16. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  17. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  18. claude_mpm/cli/interactive/skill_selector.py +481 -0
  19. claude_mpm/cli/parsers/base_parser.py +59 -1
  20. claude_mpm/cli/startup.py +202 -367
  21. claude_mpm/cli/startup_display.py +72 -5
  22. claude_mpm/cli/startup_logging.py +2 -2
  23. claude_mpm/commands/mpm-session-resume.md +1 -1
  24. claude_mpm/constants.py +1 -0
  25. claude_mpm/core/claude_runner.py +2 -2
  26. claude_mpm/core/hook_manager.py +51 -3
  27. claude_mpm/core/interactive_session.py +7 -7
  28. claude_mpm/core/output_style_manager.py +21 -13
  29. claude_mpm/core/unified_config.py +50 -8
  30. claude_mpm/core/unified_paths.py +30 -13
  31. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  32. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  33. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  34. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  35. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  36. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  37. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  38. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  39. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  40. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  41. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  42. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  43. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  44. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  45. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  46. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  47. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  48. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  49. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  50. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  51. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  52. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  53. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  54. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  55. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  56. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  57. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  58. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  59. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  60. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  61. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  73. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  74. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  75. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  76. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  77. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  78. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  79. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  80. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  81. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  82. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  83. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  84. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  85. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  86. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  87. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  88. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  89. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  90. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  91. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  92. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  93. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +486 -0
  97. claude_mpm/hooks/claude_hooks/event_handlers.py +216 -11
  98. claude_mpm/hooks/claude_hooks/hook_handler.py +28 -4
  99. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
  100. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  101. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  102. claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
  103. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
  104. claude_mpm/hooks/session_resume_hook.py +85 -1
  105. claude_mpm/init.py +1 -1
  106. claude_mpm/services/agents/cache_git_manager.py +1 -1
  107. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  108. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  109. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  110. claude_mpm/services/agents/startup_sync.py +5 -2
  111. claude_mpm/services/cli/__init__.py +3 -0
  112. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  113. claude_mpm/services/cli/session_resume_helper.py +10 -2
  114. claude_mpm/services/delegation_detector.py +175 -0
  115. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  116. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  117. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  118. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  119. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  120. claude_mpm/services/diagnostics/models.py +14 -1
  121. claude_mpm/services/event_log.py +317 -0
  122. claude_mpm/services/infrastructure/__init__.py +4 -0
  123. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  124. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  125. claude_mpm/services/monitor/daemon_manager.py +15 -4
  126. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  127. claude_mpm/services/monitor/server.py +106 -16
  128. claude_mpm/services/pm_skills_deployer.py +177 -83
  129. claude_mpm/services/skills/git_skill_source_manager.py +5 -1
  130. claude_mpm/services/skills/selective_skill_deployer.py +114 -26
  131. claude_mpm/services/socketio/handlers/hook.py +14 -7
  132. claude_mpm/services/socketio/server/main.py +12 -4
  133. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  134. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  135. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  136. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  137. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  138. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  139. claude_mpm/skills/skill_manager.py +4 -4
  140. claude_mpm/utils/agent_dependency_loader.py +103 -4
  141. claude_mpm/utils/robust_installer.py +45 -24
  142. claude_mpm-5.4.96.dist-info/METADATA +377 -0
  143. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/RECORD +153 -131
  144. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  145. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  146. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  147. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  148. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  149. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  150. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  151. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  152. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  153. claude_mpm-5.4.64.dist-info/METADATA +0 -999
  154. /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
  155. /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
  156. /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
  157. /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
  158. /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
  159. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/WHEEL +0 -0
  160. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/entry_points.txt +0 -0
  161. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/licenses/LICENSE +0 -0
  162. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  163. {claude_mpm-5.4.64.dist-info → claude_mpm-5.4.96.dist-info}/top_level.txt +0 -0
@@ -1,27 +1,30 @@
1
1
  """PM Skills Deployer Service - Deploy bundled PM skills to projects.
2
2
 
3
- WHY: PM agents require specific templates and skills for proper operation.
3
+ WHY: PM agents require specific framework management skills for proper operation.
4
4
  This service manages deployment of bundled PM skills from the claude-mpm
5
- package to individual project .claude-mpm directories with version tracking.
5
+ package to the Claude Code skills directory with version tracking.
6
6
 
7
7
  DESIGN DECISIONS:
8
- - Deploys from src/claude_mpm/skills/bundled/pm/ to .claude-mpm/skills/pm/
8
+ - Deploys from src/claude_mpm/skills/bundled/pm/ to .claude/skills/
9
+ - Skills named mpm-* (framework management skills)
10
+ - Direct deployment (no intermediate .claude-mpm/skills/pm/ step)
9
11
  - Uses package-relative paths (works for both installed and dev mode)
10
- - Supports two skill formats:
11
- 1. Directory structure: pm-skill-name/SKILL.md (new format)
12
- 2. Flat files: skill-name.md (legacy format in .claude-mpm/templates/)
13
- - Per-project deployment (NOT global like Claude Code skills)
12
+ - Supports directory structure: mpm-skill-name/SKILL.md
13
+ - Per-project deployment to .claude/skills/ (Claude Code location)
14
14
  - Version tracking via .claude-mpm/pm_skills_registry.yaml
15
15
  - Checksum validation for integrity verification
16
+ - Conflict resolution: mpm-* skills from src WIN (overwrite existing)
17
+ - Non-mpm-* skills in .claude/skills/ are untouched (user/git managed)
16
18
  - Non-blocking verification (returns warnings, doesn't halt execution)
17
19
  - Force flag to redeploy even if versions match
18
20
 
19
21
  ARCHITECTURE:
20
22
  1. Discovery: Find bundled PM skills in package (skills/bundled/pm/)
21
- 2. Deployment: Copy SKILL.md files to .claude-mpm/skills/pm/{name}.md
22
- 3. Registry: Track deployed versions and checksums
23
- 4. Verification: Check deployment status (non-blocking)
24
- 5. Updates: Compare bundled vs deployed versions
23
+ 2. Deployment: Copy SKILL.md files to .claude/skills/{name}/SKILL.md
24
+ 3. Conflict Check: Overwrite mpm-* skills, preserve non-mpm-* skills
25
+ 4. Registry: Track deployed versions and checksums
26
+ 5. Verification: Check deployment status (non-blocking)
27
+ 6. Updates: Compare bundled vs deployed versions
25
28
 
26
29
  PATH RESOLUTION:
27
30
  - Installed package: Uses __file__ to find skills/bundled/pm/
@@ -47,6 +50,22 @@ from claude_mpm.core.mixins import LoggerMixin
47
50
  # Security constants
48
51
  MAX_YAML_SIZE = 10 * 1024 * 1024 # 10MB limit to prevent YAML bombs
49
52
 
53
+ # Required PM skills that MUST be deployed for PM agent to function properly
54
+ # These are framework management skills that PM uses for orchestration
55
+ REQUIRED_PM_SKILLS = [
56
+ "mpm-git-file-tracking",
57
+ "mpm-pr-workflow",
58
+ "mpm-ticketing-integration",
59
+ "mpm-delegation-patterns",
60
+ "mpm-verification-protocols",
61
+ "mpm-bug-reporting",
62
+ "mpm-teaching-mode",
63
+ "mpm-agent-update-workflow",
64
+ "mpm-circuit-breaker-enforcement",
65
+ "mpm-tool-usage-guide",
66
+ "mpm-session-management",
67
+ ]
68
+
50
69
 
51
70
  @dataclass
52
71
  class PMSkillInfo:
@@ -96,6 +115,7 @@ class VerificationResult:
96
115
  verified: Whether all skills are properly deployed
97
116
  warnings: List of warning messages
98
117
  missing_skills: List of missing skill names
118
+ corrupted_skills: List of corrupted skill names (checksum mismatch)
99
119
  outdated_skills: List of outdated skill names
100
120
  message: Summary message
101
121
  skill_count: Total number of deployed skills
@@ -104,6 +124,7 @@ class VerificationResult:
104
124
  verified: bool
105
125
  warnings: List[str]
106
126
  missing_skills: List[str]
127
+ corrupted_skills: List[str]
107
128
  outdated_skills: List[str]
108
129
  message: str
109
130
  skill_count: int = 0
@@ -130,8 +151,9 @@ class PMSkillsDeployerService(LoggerMixin):
130
151
  """Deploy and manage PM skills from bundled sources to projects.
131
152
 
132
153
  This service provides:
133
- - Discovery of bundled PM skills (templates)
134
- - Deployment to .claude-mpm/skills/pm/
154
+ - Discovery of bundled PM skills (mpm-* framework management skills)
155
+ - Deployment to .claude/skills/ (Claude Code location)
156
+ - Conflict resolution (mpm-* skills from src WIN)
135
157
  - Version tracking via pm_skills_registry.yaml
136
158
  - Checksum validation for integrity
137
159
  - Non-blocking verification (warnings only)
@@ -140,7 +162,7 @@ class PMSkillsDeployerService(LoggerMixin):
140
162
  Example:
141
163
  >>> deployer = PMSkillsDeployerService()
142
164
  >>> result = deployer.deploy_pm_skills(Path("/project/root"))
143
- >>> print(f"Deployed {len(result.deployed)} skills")
165
+ >>> print(f"Deployed {len(result.deployed)} skills to .claude/skills/")
144
166
  >>>
145
167
  >>> verify_result = deployer.verify_pm_skills(Path("/project/root"))
146
168
  >>> if not verify_result.verified:
@@ -246,9 +268,9 @@ class PMSkillsDeployerService(LoggerMixin):
246
268
  project_dir: Project root directory
247
269
 
248
270
  Returns:
249
- Path to .claude-mpm/skills/pm/
271
+ Path to .claude/skills/
250
272
  """
251
- return project_dir / ".claude-mpm" / "skills" / "pm"
273
+ return project_dir / ".claude" / "skills"
252
274
 
253
275
  def _load_registry(self, project_dir: Path) -> Dict[str, Any]:
254
276
  """Load PM skills registry with security checks.
@@ -322,14 +344,12 @@ class PMSkillsDeployerService(LoggerMixin):
322
344
  def _discover_bundled_pm_skills(self) -> List[Dict[str, Any]]:
323
345
  """Discover all PM skills in bundled templates directory.
324
346
 
325
- PM skills can be in two formats:
326
- 1. Directory structure: pm-skill-name/SKILL.md (new format)
327
- 2. Flat files: skill-name.md (legacy format for .claude-mpm/templates/)
347
+ PM skills follow mpm-skill-name/SKILL.md structure.
328
348
 
329
349
  Returns:
330
350
  List of skill dictionaries containing:
331
- - name: Skill name (directory/filename without extension)
332
- - path: Full path to skill file (SKILL.md or .md file)
351
+ - name: Skill name (directory name, e.g., mpm-git-file-tracking)
352
+ - path: Full path to skill file (SKILL.md)
333
353
  - type: File type (always 'md')
334
354
  """
335
355
  skills = []
@@ -340,11 +360,16 @@ class PMSkillsDeployerService(LoggerMixin):
340
360
  )
341
361
  return skills
342
362
 
343
- # Scan for skill directories containing SKILL.md (new format)
363
+ # Scan for skill directories containing SKILL.md
344
364
  for skill_dir in self.bundled_pm_skills_path.iterdir():
345
365
  if not skill_dir.is_dir() or skill_dir.name.startswith("."):
346
366
  continue
347
367
 
368
+ # Only process mpm-* skills (framework management)
369
+ if not skill_dir.name.startswith("mpm-"):
370
+ self.logger.debug(f"Skipping non-mpm skill: {skill_dir.name}")
371
+ continue
372
+
348
373
  skill_file = skill_dir / "SKILL.md"
349
374
  if skill_file.exists():
350
375
  skills.append(
@@ -355,19 +380,6 @@ class PMSkillsDeployerService(LoggerMixin):
355
380
  }
356
381
  )
357
382
 
358
- # Fallback: Scan for .md files directly (legacy format)
359
- for skill_file in self.bundled_pm_skills_path.glob("*.md"):
360
- if skill_file.name.startswith("."):
361
- continue
362
-
363
- skills.append(
364
- {
365
- "name": skill_file.stem,
366
- "path": skill_file,
367
- "type": "md",
368
- }
369
- )
370
-
371
383
  self.logger.info(f"Discovered {len(skills)} bundled PM skills")
372
384
  return skills
373
385
 
@@ -379,9 +391,13 @@ class PMSkillsDeployerService(LoggerMixin):
379
391
  ) -> DeploymentResult:
380
392
  """Deploy bundled PM skills to project directory.
381
393
 
382
- Copies PM skills from bundled templates to .claude-mpm/skills/pm/
394
+ Copies PM skills from bundled templates to .claude/skills/{name}/SKILL.md
383
395
  and updates registry with version and checksum information.
384
396
 
397
+ Conflict Resolution:
398
+ - mpm-* skills from src WIN (overwrite existing)
399
+ - Non-mpm-* skills in .claude/skills/ are untouched
400
+
385
401
  Args:
386
402
  project_dir: Project root directory
387
403
  force: If True, redeploy even if skill already exists
@@ -392,7 +408,7 @@ class PMSkillsDeployerService(LoggerMixin):
392
408
 
393
409
  Example:
394
410
  >>> result = deployer.deploy_pm_skills(Path("/project"), force=True)
395
- >>> print(f"Deployed: {len(result.deployed)}")
411
+ >>> print(f"Deployed: {len(result.deployed)} to .claude/skills/")
396
412
  """
397
413
  skills = self._discover_bundled_pm_skills()
398
414
  deployed = []
@@ -447,8 +463,12 @@ class PMSkillsDeployerService(LoggerMixin):
447
463
  if progress_callback:
448
464
  progress_callback(skill_name, idx + 1, total_skills)
449
465
 
450
- # Use skill name for target file (e.g., pm-delegation-patterns.md)
451
- target_path = deployment_dir / f"{skill_name}.md"
466
+ # Create skill directory: .claude/skills/{skill_name}/
467
+ skill_dir = deployment_dir / skill_name
468
+ skill_dir.mkdir(parents=True, exist_ok=True)
469
+
470
+ # Target path: .claude/skills/{skill_name}/SKILL.md
471
+ target_path = skill_dir / "SKILL.md"
452
472
 
453
473
  # SECURITY: Validate target path
454
474
  if not self._validate_safe_path(deployment_dir, target_path):
@@ -468,7 +488,7 @@ class PMSkillsDeployerService(LoggerMixin):
468
488
  )
469
489
  continue
470
490
 
471
- # Deploy skill
491
+ # Deploy skill (overwrites if exists - mpm-* skills WIN)
472
492
  shutil.copy2(source_path, target_path)
473
493
 
474
494
  # Add to deployed list
@@ -520,76 +540,107 @@ class PMSkillsDeployerService(LoggerMixin):
520
540
  message=message,
521
541
  )
522
542
 
523
- def verify_pm_skills(self, project_dir: Path) -> VerificationResult:
524
- """Verify PM skills are properly deployed (non-blocking).
543
+ def verify_pm_skills(
544
+ self, project_dir: Path, auto_repair: bool = True
545
+ ) -> VerificationResult:
546
+ """Verify PM skills are properly deployed with enhanced validation.
547
+
548
+ Checks ALL required PM skills for:
549
+ - Existence in deployment directory
550
+ - File integrity (non-empty, valid checksums)
551
+ - Version currency (compared to bundled source)
525
552
 
526
- Checks deployment status and returns warnings without halting execution.
527
- This allows graceful degradation if PM skills are missing.
553
+ Auto-repair logic:
554
+ - If auto_repair=True (default), automatically deploys missing/corrupted skills
555
+ - Reports what was fixed in the result
528
556
 
529
557
  Args:
530
558
  project_dir: Project root directory
559
+ auto_repair: If True, auto-deploy missing/corrupted skills (default: True)
531
560
 
532
561
  Returns:
533
- VerificationResult with verification status and warnings
562
+ VerificationResult with detailed verification status:
563
+ - verified: True if all required skills are deployed and valid
564
+ - missing_skills: List of required skills not deployed
565
+ - corrupted_skills: List of skills with checksum mismatches
566
+ - warnings: List of warning messages
567
+ - skill_count: Total number of deployed skills
534
568
 
535
569
  Example:
536
570
  >>> result = deployer.verify_pm_skills(Path("/project"))
537
571
  >>> if not result.verified:
538
- ... for warning in result.warnings:
539
- ... print(f"WARNING: {warning}")
572
+ ... print(f"Missing: {result.missing_skills}")
573
+ ... print(f"Corrupted: {result.corrupted_skills}")
540
574
  """
541
575
  warnings = []
542
576
  missing_skills = []
577
+ corrupted_skills = []
543
578
  outdated_skills = []
544
579
 
545
580
  # Check if registry exists
546
581
  registry = self._load_registry(project_dir)
547
- if not registry:
548
- warnings.append("PM skills registry not found or invalid")
549
- missing_skills.append("all")
550
- return VerificationResult(
551
- verified=False,
552
- warnings=warnings,
553
- missing_skills=missing_skills,
554
- outdated_skills=outdated_skills,
555
- message="PM skills not deployed. Run 'claude-mpm init' to deploy.",
556
- skill_count=0,
557
- )
558
-
559
- # Check each registered skill exists
560
582
  deployment_dir = self._get_deployment_dir(project_dir)
561
- deployed_skills = registry.get("skills", [])
583
+ deployed_skills_data = registry.get("skills", []) if registry else []
562
584
 
563
- for skill in deployed_skills:
564
- skill_name = skill["name"]
565
- skill_file = deployment_dir / f"{skill_name}.md"
585
+ # Build lookup for deployed skills
586
+ deployed_lookup = {skill["name"]: skill for skill in deployed_skills_data}
566
587
 
588
+ # Check ALL required PM skills
589
+ for required_skill in REQUIRED_PM_SKILLS:
590
+ # Check if skill is in registry
591
+ if required_skill not in deployed_lookup:
592
+ warnings.append(f"Required PM skill missing: {required_skill}")
593
+ missing_skills.append(required_skill)
594
+ continue
595
+
596
+ # Check if skill file exists
597
+ skill_file = deployment_dir / required_skill / "SKILL.md"
567
598
  if not skill_file.exists():
568
- warnings.append(f"Deployed skill file missing: {skill_name}")
569
- missing_skills.append(skill_name)
599
+ warnings.append(
600
+ f"Required PM skill file missing: {required_skill}/SKILL.md"
601
+ )
602
+ missing_skills.append(required_skill)
603
+ continue
604
+
605
+ # Check if skill file is empty/corrupted
606
+ try:
607
+ file_size = skill_file.stat().st_size
608
+ if file_size == 0:
609
+ warnings.append(
610
+ f"Required PM skill file is empty: {required_skill}/SKILL.md"
611
+ )
612
+ corrupted_skills.append(required_skill)
613
+ continue
614
+ except OSError as e:
615
+ warnings.append(
616
+ f"Cannot read required PM skill file: {required_skill}/SKILL.md - {e}"
617
+ )
618
+ corrupted_skills.append(required_skill)
570
619
  continue
571
620
 
572
621
  # Verify checksum
622
+ deployed_skill = deployed_lookup[required_skill]
573
623
  current_checksum = self._compute_checksum(skill_file)
574
- expected_checksum = skill.get("checksum", "")
624
+ expected_checksum = deployed_skill.get("checksum", "")
575
625
 
576
626
  if current_checksum != expected_checksum:
577
627
  warnings.append(
578
- f"Skill checksum mismatch: {skill_name} (file may be corrupted)"
628
+ f"Required PM skill checksum mismatch: {required_skill} (file may be corrupted)"
579
629
  )
580
- outdated_skills.append(skill_name)
630
+ corrupted_skills.append(required_skill)
581
631
 
582
- # Check for available updates
632
+ # Check for available updates (bundled skills newer than deployed)
583
633
  bundled_skills = {s["name"]: s for s in self._discover_bundled_pm_skills()}
584
634
  for skill_name, bundled_skill in bundled_skills.items():
635
+ # Skip non-required skills
636
+ if skill_name not in REQUIRED_PM_SKILLS:
637
+ continue
638
+
585
639
  # Find corresponding deployed skill
586
- deployed_skill = next(
587
- (s for s in deployed_skills if s["name"] == skill_name), None
588
- )
640
+ deployed_skill = deployed_lookup.get(skill_name)
589
641
 
590
642
  if not deployed_skill:
591
- warnings.append(f"New PM skill available: {skill_name}")
592
- missing_skills.append(skill_name)
643
+ # Already tracked as missing
593
644
  continue
594
645
 
595
646
  # Check if checksums differ
@@ -597,23 +648,66 @@ class PMSkillsDeployerService(LoggerMixin):
597
648
  deployed_checksum = deployed_skill.get("checksum", "")
598
649
 
599
650
  if bundled_checksum != deployed_checksum:
600
- warnings.append(f"PM skill update available: {skill_name}")
601
- outdated_skills.append(skill_name)
651
+ # Don't add to outdated_skills if already in corrupted_skills
652
+ if skill_name not in corrupted_skills:
653
+ warnings.append(f"PM skill update available: {skill_name}")
654
+ outdated_skills.append(skill_name)
655
+
656
+ # Auto-repair if enabled and issues found
657
+ repaired_skills = []
658
+ if auto_repair and (missing_skills or corrupted_skills):
659
+ self.logger.info(
660
+ f"Auto-repairing PM skills: {len(missing_skills)} missing, "
661
+ f"{len(corrupted_skills)} corrupted"
662
+ )
663
+
664
+ # Deploy missing and corrupted skills
665
+ repair_result = self.deploy_pm_skills(project_dir, force=True)
602
666
 
603
- verified = len(warnings) == 0
667
+ if repair_result.success:
668
+ repaired_skills = repair_result.deployed
669
+ self.logger.info(f"Auto-repaired {len(repaired_skills)} PM skills")
604
670
 
671
+ # Remove repaired skills from missing/corrupted lists
672
+ missing_skills = [s for s in missing_skills if s not in repaired_skills]
673
+ corrupted_skills = [
674
+ s for s in corrupted_skills if s not in repaired_skills
675
+ ]
676
+
677
+ # Update warnings
678
+ if repaired_skills:
679
+ warnings.append(
680
+ f"Auto-repaired {len(repaired_skills)} PM skills: {', '.join(repaired_skills)}"
681
+ )
682
+ else:
683
+ warnings.append(
684
+ f"Auto-repair failed: {len(repair_result.errors)} errors"
685
+ )
686
+ self.logger.error(
687
+ f"Auto-repair failed with errors: {repair_result.errors}"
688
+ )
689
+
690
+ # Determine verification status
691
+ verified = len(missing_skills) == 0 and len(corrupted_skills) == 0
692
+
693
+ # Build message
605
694
  if verified:
606
- message = "All PM skills verified and up-to-date"
695
+ if repaired_skills:
696
+ message = f"All PM skills verified (auto-repaired {len(repaired_skills)} skills)"
697
+ else:
698
+ message = "All PM skills verified and up-to-date"
607
699
  else:
608
- message = f"{len(warnings)} verification warnings found"
700
+ issue_count = len(missing_skills) + len(corrupted_skills)
701
+ message = f"{issue_count} PM skill issues found"
609
702
 
610
703
  return VerificationResult(
611
704
  verified=verified,
612
705
  warnings=warnings,
613
706
  missing_skills=missing_skills,
707
+ corrupted_skills=corrupted_skills,
614
708
  outdated_skills=outdated_skills,
615
709
  message=message,
616
- skill_count=len(deployed_skills),
710
+ skill_count=len(deployed_skills_data),
617
711
  )
618
712
 
619
713
  def get_deployed_skills(self, project_dir: Path) -> List[PMSkillInfo]:
@@ -636,10 +730,10 @@ class PMSkillsDeployerService(LoggerMixin):
636
730
  skills = []
637
731
  for skill_data in registry.get("skills", []):
638
732
  skill_name = skill_data["name"]
639
- deployed_path = deployment_dir / f"{skill_name}.md"
733
+ deployed_path = deployment_dir / skill_name / "SKILL.md"
640
734
 
641
735
  # Find source path (may not exist if bundled skills changed)
642
- source_path = self.bundled_pm_skills_path / f"{skill_name}.md"
736
+ source_path = self.bundled_pm_skills_path / skill_name / "SKILL.md"
643
737
 
644
738
  skills.append(
645
739
  PMSkillInfo(
@@ -1095,7 +1095,11 @@ class GitSkillSourceManager:
1095
1095
  if removed_skills:
1096
1096
  self.logger.info(
1097
1097
  f"Removed {len(removed_skills)} orphaned skills not referenced by agents: {removed_skills[:10]}"
1098
- + (f" (and {len(removed_skills) - 10} more)" if len(removed_skills) > 10 else "")
1098
+ + (
1099
+ f" (and {len(removed_skills) - 10} more)"
1100
+ if len(removed_skills) > 10
1101
+ else ""
1102
+ )
1099
1103
  )
1100
1104
 
1101
1105
  self.logger.info(