claude-mpm 5.0.2__py3-none-any.whl → 5.1.9__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 (76) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +1176 -909
  4. claude_mpm/agents/base_agent_loader.py +10 -35
  5. claude_mpm/agents/frontmatter_validator.py +68 -0
  6. claude_mpm/agents/templates/circuit-breakers.md +293 -44
  7. claude_mpm/cli/__init__.py +0 -1
  8. claude_mpm/cli/commands/__init__.py +2 -0
  9. claude_mpm/cli/commands/agent_state_manager.py +64 -11
  10. claude_mpm/cli/commands/agents.py +446 -25
  11. claude_mpm/cli/commands/auto_configure.py +535 -233
  12. claude_mpm/cli/commands/configure.py +545 -89
  13. claude_mpm/cli/commands/postmortem.py +401 -0
  14. claude_mpm/cli/commands/run.py +1 -39
  15. claude_mpm/cli/commands/skills.py +322 -19
  16. claude_mpm/cli/interactive/agent_wizard.py +302 -195
  17. claude_mpm/cli/parsers/agents_parser.py +137 -0
  18. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  19. claude_mpm/cli/parsers/base_parser.py +4 -0
  20. claude_mpm/cli/parsers/skills_parser.py +7 -0
  21. claude_mpm/cli/startup.py +73 -32
  22. claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
  23. claude_mpm/commands/mpm-agents-list.md +2 -2
  24. claude_mpm/commands/mpm-config-view.md +2 -2
  25. claude_mpm/commands/mpm-help.md +3 -0
  26. claude_mpm/commands/mpm-postmortem.md +123 -0
  27. claude_mpm/commands/mpm-session-resume.md +2 -2
  28. claude_mpm/commands/mpm-ticket-organize.md +2 -2
  29. claude_mpm/commands/mpm-ticket-view.md +2 -2
  30. claude_mpm/config/agent_presets.py +312 -82
  31. claude_mpm/config/skill_presets.py +392 -0
  32. claude_mpm/constants.py +1 -0
  33. claude_mpm/core/claude_runner.py +2 -25
  34. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  35. claude_mpm/core/interactive_session.py +19 -5
  36. claude_mpm/core/oneshot_session.py +16 -4
  37. claude_mpm/core/output_style_manager.py +173 -43
  38. claude_mpm/core/protocols/__init__.py +23 -0
  39. claude_mpm/core/protocols/runner_protocol.py +103 -0
  40. claude_mpm/core/protocols/session_protocol.py +131 -0
  41. claude_mpm/core/shared/singleton_manager.py +11 -4
  42. claude_mpm/core/system_context.py +38 -0
  43. claude_mpm/core/unified_agent_registry.py +129 -1
  44. claude_mpm/core/unified_config.py +22 -0
  45. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  46. claude_mpm/models/agent_definition.py +7 -0
  47. claude_mpm/services/agents/cache_git_manager.py +621 -0
  48. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
  49. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +195 -1
  50. claude_mpm/services/agents/sources/git_source_sync_service.py +37 -5
  51. claude_mpm/services/analysis/__init__.py +25 -0
  52. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  53. claude_mpm/services/analysis/postmortem_service.py +765 -0
  54. claude_mpm/services/command_deployment_service.py +108 -5
  55. claude_mpm/services/core/base.py +7 -2
  56. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  57. claude_mpm/services/git/git_operations_service.py +8 -8
  58. claude_mpm/services/mcp_config_manager.py +75 -145
  59. claude_mpm/services/mcp_gateway/core/process_pool.py +22 -16
  60. claude_mpm/services/mcp_service_verifier.py +6 -3
  61. claude_mpm/services/monitor/daemon.py +28 -8
  62. claude_mpm/services/monitor/daemon_manager.py +96 -19
  63. claude_mpm/services/project/project_organizer.py +4 -0
  64. claude_mpm/services/runner_configuration_service.py +16 -3
  65. claude_mpm/services/session_management_service.py +16 -4
  66. claude_mpm/utils/agent_filters.py +288 -0
  67. claude_mpm/utils/gitignore.py +3 -0
  68. claude_mpm/utils/migration.py +372 -0
  69. claude_mpm/utils/progress.py +5 -1
  70. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/METADATA +69 -8
  71. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/RECORD +76 -62
  72. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  73. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/WHEEL +0 -0
  74. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/entry_points.txt +0 -0
  75. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/licenses/LICENSE +0 -0
  76. {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,372 @@
1
+ """Migration utilities for transitioning to new directory structure.
2
+
3
+ WHY: Phase 3 of 1M-486 requires migrating from old single-tier deployment
4
+ (~/.claude/agents/, ~/.claude/skills/) to new two-phase architecture:
5
+ - Cache: ~/.claude-mpm/cache/remote-agents/, ~/.claude-mpm/cache/skills/
6
+ - Deployment: .claude-mpm/agents/, .claude-mpm/skills/
7
+
8
+ DESIGN DECISIONS:
9
+ - Optional migration: Users can continue using old paths (fallback support)
10
+ - User confirmation: Prevents accidental data movement
11
+ - Non-destructive: Creates copies, doesn't delete originals immediately
12
+ - Deprecation warnings: Guides users toward new structure
13
+
14
+ MIGRATION PATH:
15
+ 1. Detect old locations (if they exist)
16
+ 2. Prompt user for confirmation
17
+ 3. Copy to new cache location (not deployment, as that's project-specific)
18
+ 4. Show deprecation warning with cleanup instructions
19
+ 5. Provide fallback support for unmigrated systems
20
+ """
21
+
22
+ import logging
23
+ import shutil
24
+ from pathlib import Path
25
+ from typing import Dict, Optional
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class MigrationUtility:
31
+ """Handles migration from old to new directory structure.
32
+
33
+ Trade-offs:
34
+ - Safety: Non-destructive copies vs. automatic moves
35
+ - User experience: Manual confirmation vs. automatic migration
36
+ - Compatibility: Fallback support adds complexity but ensures smooth transition
37
+ """
38
+
39
+ def __init__(self):
40
+ """Initialize migration utility with old and new paths."""
41
+ self.old_agent_dir = Path.home() / ".claude" / "agents"
42
+ self.old_skill_dir = Path.home() / ".claude" / "skills"
43
+
44
+ self.new_agent_cache = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
45
+ self.new_skill_cache = Path.home() / ".claude-mpm" / "cache" / "skills"
46
+
47
+ def detect_old_locations(self) -> Dict[str, bool]:
48
+ """Detect if old directory locations exist and contain files.
49
+
50
+ Returns:
51
+ Dictionary with 'agents' and 'skills' keys indicating presence
52
+ """
53
+ results = {
54
+ "agents_exists": False,
55
+ "agents_count": 0,
56
+ "skills_exists": False,
57
+ "skills_count": 0,
58
+ }
59
+
60
+ # Check agents
61
+ if self.old_agent_dir.exists():
62
+ agent_files = list(self.old_agent_dir.glob("*.md")) + list(
63
+ self.old_agent_dir.glob("*.json")
64
+ )
65
+ results["agents_exists"] = len(agent_files) > 0
66
+ results["agents_count"] = len(agent_files)
67
+
68
+ # Check skills
69
+ if self.old_skill_dir.exists():
70
+ skill_dirs = [
71
+ d
72
+ for d in self.old_skill_dir.iterdir()
73
+ if d.is_dir() and (d / "SKILL.md").exists()
74
+ ]
75
+ results["skills_exists"] = len(skill_dirs) > 0
76
+ results["skills_count"] = len(skill_dirs)
77
+
78
+ return results
79
+
80
+ def migrate_agents(
81
+ self, dry_run: bool = False, auto_confirm: bool = False
82
+ ) -> Dict[str, any]:
83
+ """Migrate agents from ~/.claude/agents/ to ~/.claude-mpm/cache/remote-agents/.
84
+
85
+ Args:
86
+ dry_run: Preview migration without making changes
87
+ auto_confirm: Skip confirmation prompt (use with caution)
88
+
89
+ Returns:
90
+ Dictionary with migration results:
91
+ {
92
+ "migrated_count": 5,
93
+ "migrated_files": ["engineer.md", ...],
94
+ "skipped_count": 2,
95
+ "errors": []
96
+ }
97
+ """
98
+ if not self.old_agent_dir.exists():
99
+ return {
100
+ "migrated_count": 0,
101
+ "migrated_files": [],
102
+ "skipped_count": 0,
103
+ "errors": [],
104
+ "message": "No old agent directory found",
105
+ }
106
+
107
+ # Find agent files
108
+ agent_files = list(self.old_agent_dir.glob("*.md")) + list(
109
+ self.old_agent_dir.glob("*.json")
110
+ )
111
+
112
+ if not agent_files:
113
+ return {
114
+ "migrated_count": 0,
115
+ "migrated_files": [],
116
+ "skipped_count": 0,
117
+ "errors": [],
118
+ "message": "No agent files found in old directory",
119
+ }
120
+
121
+ # Dry run mode
122
+ if dry_run:
123
+ return {
124
+ "migrated_count": len(agent_files),
125
+ "migrated_files": [f.name for f in agent_files],
126
+ "skipped_count": 0,
127
+ "errors": [],
128
+ "dry_run": True,
129
+ "message": f"Would migrate {len(agent_files)} agent files",
130
+ }
131
+
132
+ # Confirmation prompt (unless auto_confirm)
133
+ if not auto_confirm:
134
+ logger.info(
135
+ f"Migration will copy {len(agent_files)} agents from:\n"
136
+ f" {self.old_agent_dir}\n"
137
+ f" → {self.new_agent_cache}"
138
+ )
139
+ # In CLI context, this would show interactive prompt
140
+ # For now, we assume confirmation through function parameter
141
+
142
+ # Create cache directory
143
+ try:
144
+ self.new_agent_cache.mkdir(parents=True, exist_ok=True)
145
+ except PermissionError as e:
146
+ return {
147
+ "migrated_count": 0,
148
+ "migrated_files": [],
149
+ "skipped_count": 0,
150
+ "errors": [f"Permission denied creating cache directory: {e}"],
151
+ }
152
+
153
+ # Copy files
154
+ results = {
155
+ "migrated_count": 0,
156
+ "migrated_files": [],
157
+ "skipped_count": 0,
158
+ "errors": [],
159
+ }
160
+
161
+ for agent_file in agent_files:
162
+ target_file = self.new_agent_cache / agent_file.name
163
+
164
+ try:
165
+ # Skip if already exists and is identical
166
+ if target_file.exists():
167
+ if self._files_identical(agent_file, target_file):
168
+ results["skipped_count"] += 1
169
+ logger.debug(f"Skipped (identical): {agent_file.name}")
170
+ continue
171
+
172
+ # Copy to cache
173
+ shutil.copy2(agent_file, target_file)
174
+ results["migrated_count"] += 1
175
+ results["migrated_files"].append(agent_file.name)
176
+ logger.info(f"Migrated: {agent_file.name}")
177
+
178
+ except Exception as e:
179
+ error_msg = f"Failed to migrate {agent_file.name}: {e}"
180
+ results["errors"].append(error_msg)
181
+ logger.error(error_msg)
182
+
183
+ results["message"] = (
184
+ f"Migrated {results['migrated_count']} agents to cache. "
185
+ f"Old directory: {self.old_agent_dir}"
186
+ )
187
+
188
+ return results
189
+
190
+ def migrate_skills(
191
+ self, dry_run: bool = False, auto_confirm: bool = False
192
+ ) -> Dict[str, any]:
193
+ """Migrate skills from ~/.claude/skills/ to ~/.claude-mpm/cache/skills/.
194
+
195
+ Args:
196
+ dry_run: Preview migration without making changes
197
+ auto_confirm: Skip confirmation prompt
198
+
199
+ Returns:
200
+ Dictionary with migration results
201
+ """
202
+ if not self.old_skill_dir.exists():
203
+ return {
204
+ "migrated_count": 0,
205
+ "migrated_skills": [],
206
+ "skipped_count": 0,
207
+ "errors": [],
208
+ "message": "No old skill directory found",
209
+ }
210
+
211
+ # Find skill directories
212
+ skill_dirs = [
213
+ d
214
+ for d in self.old_skill_dir.iterdir()
215
+ if d.is_dir() and (d / "SKILL.md").exists()
216
+ ]
217
+
218
+ if not skill_dirs:
219
+ return {
220
+ "migrated_count": 0,
221
+ "migrated_skills": [],
222
+ "skipped_count": 0,
223
+ "errors": [],
224
+ "message": "No skill directories found",
225
+ }
226
+
227
+ # Dry run mode
228
+ if dry_run:
229
+ return {
230
+ "migrated_count": len(skill_dirs),
231
+ "migrated_skills": [d.name for d in skill_dirs],
232
+ "skipped_count": 0,
233
+ "errors": [],
234
+ "dry_run": True,
235
+ "message": f"Would migrate {len(skill_dirs)} skill directories",
236
+ }
237
+
238
+ # Create cache directory
239
+ try:
240
+ self.new_skill_cache.mkdir(parents=True, exist_ok=True)
241
+ except PermissionError as e:
242
+ return {
243
+ "migrated_count": 0,
244
+ "migrated_skills": [],
245
+ "skipped_count": 0,
246
+ "errors": [f"Permission denied creating cache directory: {e}"],
247
+ }
248
+
249
+ # Copy skill directories
250
+ results = {
251
+ "migrated_count": 0,
252
+ "migrated_skills": [],
253
+ "skipped_count": 0,
254
+ "errors": [],
255
+ }
256
+
257
+ for skill_dir in skill_dirs:
258
+ target_dir = self.new_skill_cache / skill_dir.name
259
+
260
+ try:
261
+ # Skip if already exists
262
+ if target_dir.exists():
263
+ results["skipped_count"] += 1
264
+ logger.debug(f"Skipped (exists): {skill_dir.name}")
265
+ continue
266
+
267
+ # Copy entire skill directory
268
+ shutil.copytree(skill_dir, target_dir)
269
+ results["migrated_count"] += 1
270
+ results["migrated_skills"].append(skill_dir.name)
271
+ logger.info(f"Migrated: {skill_dir.name}")
272
+
273
+ except Exception as e:
274
+ error_msg = f"Failed to migrate {skill_dir.name}: {e}"
275
+ results["errors"].append(error_msg)
276
+ logger.error(error_msg)
277
+
278
+ results["message"] = (
279
+ f"Migrated {results['migrated_count']} skills to cache. "
280
+ f"Old directory: {self.old_skill_dir}"
281
+ )
282
+
283
+ return results
284
+
285
+ def migrate_all(
286
+ self, dry_run: bool = False, auto_confirm: bool = False
287
+ ) -> Dict[str, any]:
288
+ """Migrate both agents and skills.
289
+
290
+ Args:
291
+ dry_run: Preview migration without making changes
292
+ auto_confirm: Skip confirmation prompts
293
+
294
+ Returns:
295
+ Combined migration results for agents and skills
296
+ """
297
+ agent_results = self.migrate_agents(dry_run=dry_run, auto_confirm=auto_confirm)
298
+ skill_results = self.migrate_skills(dry_run=dry_run, auto_confirm=auto_confirm)
299
+
300
+ return {
301
+ "agents": agent_results,
302
+ "skills": skill_results,
303
+ "total_migrated": agent_results["migrated_count"]
304
+ + skill_results["migrated_count"],
305
+ "dry_run": dry_run,
306
+ }
307
+
308
+ def show_deprecation_warning(self) -> str:
309
+ """Generate deprecation warning message for old paths.
310
+
311
+ Returns:
312
+ Formatted warning message for display to user
313
+ """
314
+ detection = self.detect_old_locations()
315
+
316
+ if not detection["agents_exists"] and not detection["skills_exists"]:
317
+ return ""
318
+
319
+ warning = "\n⚠️ DEPRECATION WARNING ⚠️\n\n"
320
+ warning += "Old directory structure detected:\n\n"
321
+
322
+ if detection["agents_exists"]:
323
+ warning += f" • {self.old_agent_dir}\n"
324
+ warning += f" ({detection['agents_count']} agent files)\n"
325
+
326
+ if detection["skills_exists"]:
327
+ warning += f" • {self.old_skill_dir}\n"
328
+ warning += f" ({detection['skills_count']} skill directories)\n"
329
+
330
+ warning += "\nThe deployment architecture has changed:\n"
331
+ warning += " OLD: ~/.claude/agents/ (single-tier, global)\n"
332
+ warning += " NEW: ~/.claude-mpm/cache/remote-agents/ → .claude-mpm/agents/ (two-phase, per-project)\n\n"
333
+
334
+ warning += "To migrate:\n"
335
+ warning += " claude-mpm migrate\n\n"
336
+
337
+ warning += "Or to continue using old paths (not recommended):\n"
338
+ warning += " # Fallback support is enabled automatically\n\n"
339
+
340
+ return warning
341
+
342
+ def _files_identical(self, file1: Path, file2: Path) -> bool:
343
+ """Check if two files have identical content.
344
+
345
+ Args:
346
+ file1: First file path
347
+ file2: Second file path
348
+
349
+ Returns:
350
+ True if files are byte-for-byte identical
351
+ """
352
+ try:
353
+ return file1.read_bytes() == file2.read_bytes()
354
+ except Exception:
355
+ return False
356
+
357
+ def get_fallback_paths(self) -> Dict[str, Optional[Path]]:
358
+ """Get fallback paths for old directory structure.
359
+
360
+ Used when migration hasn't been performed and old paths still exist.
361
+
362
+ Returns:
363
+ Dictionary with fallback paths:
364
+ {
365
+ "agent_dir": Path to old agents (or None),
366
+ "skill_dir": Path to old skills (or None)
367
+ }
368
+ """
369
+ return {
370
+ "agent_dir": self.old_agent_dir if self.old_agent_dir.exists() else None,
371
+ "skill_dir": self.old_skill_dir if self.old_skill_dir.exists() else None,
372
+ }
@@ -270,8 +270,12 @@ class ProgressBar:
270
270
  truncate_at = max_width - 3 # Leave room for "..."
271
271
  output = output[:truncate_at] + "..."
272
272
 
273
+ # Pad output to terminal width to clear previous longer text
274
+ # This prevents text artifacts when current message is shorter than previous
275
+ padded_output = output.ljust(max_width)
276
+
273
277
  # Write to stdout with carriage return (overwrite current line)
274
- sys.stdout.write(f"\r{output}")
278
+ sys.stdout.write(f"\r{padded_output}")
275
279
  sys.stdout.flush()
276
280
 
277
281
  def finish(self, message: str = "Complete") -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 5.0.2
3
+ Version: 5.1.9
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
@@ -13,12 +13,10 @@ Keywords: claude,orchestration,multi-agent,ticket-management
13
13
  Classifier: Development Status :: 3 - Alpha
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
16
  Classifier: Programming Language :: Python :: 3.11
20
17
  Classifier: Programming Language :: Python :: 3.12
21
- Requires-Python: >=3.8
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Requires-Python: >=3.11
22
20
  Description-Content-Type: text/markdown
23
21
  License-File: LICENSE
24
22
  Requires-Dist: ai-trackdown-pytools>=1.4.0
@@ -48,7 +46,6 @@ Requires-Dist: pydantic-settings>=2.0.0
48
46
  Requires-Dist: rich>=13.0.0
49
47
  Requires-Dist: questionary>=2.0.0
50
48
  Requires-Dist: pyee>=13.0.0
51
- Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
52
49
  Requires-Dist: pathspec>=0.11.0
53
50
  Requires-Dist: kuzu-memory>=1.1.5
54
51
  Provides-Extra: mcp
@@ -66,6 +63,12 @@ Requires-Dist: pre-commit; extra == "dev"
66
63
  Requires-Dist: mypy>=1.0.0; extra == "dev"
67
64
  Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
68
65
  Requires-Dist: types-requests>=2.25.0; extra == "dev"
66
+ Requires-Dist: twine>=4.0.0; extra == "dev"
67
+ Provides-Extra: eval
68
+ Requires-Dist: deepeval>=1.0.0; extra == "eval"
69
+ Requires-Dist: pytest>=7.4.0; extra == "eval"
70
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "eval"
71
+ Requires-Dist: pytest-timeout>=2.1.0; extra == "eval"
69
72
  Provides-Extra: docs
70
73
  Requires-Dist: sphinx>=7.2.0; extra == "docs"
71
74
  Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
@@ -121,7 +124,6 @@ Requires-Dist: prometheus-client>=0.19.0; extra == "agents"
121
124
  Requires-Dist: psycopg2-binary>=2.9.0; extra == "agents"
122
125
  Requires-Dist: pyarrow>=14.0.0; extra == "agents"
123
126
  Requires-Dist: pydantic>=2.6.0; extra == "agents"
124
- Requires-Dist: pydoc-markdown>=4.8.0; extra == "agents"
125
127
  Requires-Dist: pydriller>=2.5.0; extra == "agents"
126
128
  Requires-Dist: pygments>=2.17.0; extra == "agents"
127
129
  Requires-Dist: pyjwt>=2.8.0; extra == "agents"
@@ -302,7 +304,7 @@ See [docs/features/hierarchical-base-agents.md](docs/features/hierarchical-base-
302
304
 
303
305
  **Before installing Claude MPM**, ensure you have:
304
306
 
305
- 1. **Python 3.8+** (3.11+ recommended)
307
+ 1. **Python 3.11+** (required for kuzu-memory dependency)
306
308
  2. **Claude Code CLI v1.0.92+** (required!)
307
309
 
308
310
  ```bash
@@ -439,6 +441,65 @@ claude-mpm verify
439
441
 
440
442
  **That's it!** See [docs/user/getting-started.md](docs/user/getting-started.md) for immediate usage.
441
443
 
444
+ ## Cache Management
445
+
446
+ Claude MPM maintains a local cache of agent templates at `~/.claude-mpm/cache/remote-agents/`.
447
+
448
+ ### Cache Structure
449
+
450
+ ```
451
+ ~/.claude-mpm/cache/remote-agents/
452
+ └── bobmatnyc/
453
+ └── claude-mpm-agents/
454
+ ├── .git/ # Git repository
455
+ ├── agents/ # 45+ agent templates
456
+ └── docs/
457
+ ```
458
+
459
+ ### Git Workflow (Optional)
460
+
461
+ If your cache is a git repository, you can manage agents with git operations:
462
+
463
+ ```bash
464
+ # Check cache status
465
+ claude-mpm agents cache-status
466
+
467
+ # Pull latest agents
468
+ claude-mpm agents cache-pull
469
+
470
+ # Commit local changes
471
+ claude-mpm agents cache-commit --message "feat: update agents"
472
+
473
+ # Push changes
474
+ claude-mpm agents cache-push
475
+
476
+ # Full sync workflow
477
+ claude-mpm agents cache-sync
478
+ ```
479
+
480
+ **Or use Makefile targets:**
481
+
482
+ ```bash
483
+ make agents-cache-status # Show git status
484
+ make agents-cache-pull # Pull latest
485
+ make agents-cache-sync # Full sync (pull + commit + push)
486
+ make deploy-agents # Deploy with auto-pull
487
+ ```
488
+
489
+ ### HTTP Sync Fallback
490
+
491
+ If cache is not a git repository, Claude MPM automatically falls back to HTTP sync with GitHub API.
492
+
493
+ ### Migration from Legacy Cache
494
+
495
+ If you have an old `cache/agents/` directory, run the migration script:
496
+
497
+ ```bash
498
+ python scripts/migrate_cache_to_remote_agents.py
499
+ ```
500
+
501
+ **See also:** [docs/CACHE_MANAGEMENT.md](docs/CACHE_MANAGEMENT.md) for comprehensive cache management guide.
502
+
442
503
  ## Quick Usage
443
504
 
444
505
  ```bash