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,392 @@
1
+ """Skill preset configurations for common development scenarios.
2
+
3
+ This module defines preset bundles of skills for typical development workflows.
4
+ Presets enable users to deploy entire skill stacks with a single command like:
5
+ claude-mpm skills deploy --preset python-min
6
+ claude-mpm skills deploy --preset python-max
7
+
8
+ Design Decision: Presets use skill IDs from skill manifest format.
9
+
10
+ Architecture:
11
+ - MIN presets: Essential skills only (faster startup, lower resource usage)
12
+ - MAX presets: Full skill toolkit with specialized capabilities (comprehensive coverage)
13
+ - All presets include: skill-creator for extending capabilities
14
+
15
+ Trade-offs:
16
+ - Simplicity: Static lists are easy to maintain
17
+ - Flexibility: Dynamic functions allow auto-detection (future enhancement)
18
+ - Discoverability: Presets shown in CLI help and error messages
19
+ """
20
+
21
+ from typing import Any, Callable, Dict, List, Union
22
+
23
+ # Type for preset resolver (can be static list or dynamic function)
24
+ PresetResolver = Union[List[str], Callable[[], List[str]]]
25
+
26
+ # Core skills included in ALL presets (MIN and MAX)
27
+ CORE_SKILLS = [
28
+ "universal-main-skill-creator", # Skill creation and management
29
+ ]
30
+
31
+ PRESETS: Dict[str, Dict[str, Any]] = {
32
+ # ========================================
33
+ # Universal Minimal Preset
34
+ # ========================================
35
+ "minimal": {
36
+ "description": "Core skills only - universal starter kit",
37
+ "skills": CORE_SKILLS,
38
+ "use_cases": ["Any project type", "Quick start", "Learning"],
39
+ },
40
+ # ========================================
41
+ # Python Toolchain Presets
42
+ # ========================================
43
+ "python-min": {
44
+ "description": "Python essentials (4 skills)",
45
+ "skills": CORE_SKILLS
46
+ + [
47
+ "toolchains-python-testing-pytest",
48
+ "toolchains-python-async-asyncio",
49
+ "toolchains-python-tooling-mypy",
50
+ ],
51
+ "use_cases": [
52
+ "Python scripts",
53
+ "Small Python projects",
54
+ "FastAPI microservices",
55
+ ],
56
+ },
57
+ "python-max": {
58
+ "description": "Full Python skill stack (8+ skills)",
59
+ "skills": CORE_SKILLS
60
+ + [
61
+ "toolchains-python-frameworks-flask",
62
+ "toolchains-python-testing-pytest",
63
+ "toolchains-python-async-asyncio",
64
+ "toolchains-python-tooling-mypy",
65
+ "universal-testing-testing-anti-patterns",
66
+ "universal-testing-condition-based-waiting",
67
+ "universal-debugging-verification-before-completion",
68
+ ],
69
+ "use_cases": ["FastAPI production", "Django projects", "Python APIs at scale"],
70
+ },
71
+ # ========================================
72
+ # JavaScript/TypeScript Toolchain Presets
73
+ # ========================================
74
+ "javascript-min": {
75
+ "description": "Node.js essentials (3 skills)",
76
+ "skills": CORE_SKILLS
77
+ + [
78
+ "toolchains-javascript-frameworks-react",
79
+ "toolchains-javascript-tooling-biome",
80
+ ],
81
+ "use_cases": ["Express.js", "Node.js scripts", "Backend microservices"],
82
+ },
83
+ "javascript-max": {
84
+ "description": "Full Node.js skill stack (7+ skills)",
85
+ "skills": CORE_SKILLS
86
+ + [
87
+ "toolchains-javascript-frameworks-react",
88
+ "toolchains-javascript-frameworks-vue",
89
+ "toolchains-javascript-tooling-biome",
90
+ "toolchains-typescript-testing-vitest",
91
+ "toolchains-typescript-testing-jest",
92
+ "universal-testing-testing-anti-patterns",
93
+ ],
94
+ "use_cases": ["Express.js production", "Fastify", "Koa", "Enterprise Node.js"],
95
+ },
96
+ # ========================================
97
+ # React Toolchain Presets
98
+ # ========================================
99
+ "react-min": {
100
+ "description": "React essentials (3 skills)",
101
+ "skills": CORE_SKILLS
102
+ + [
103
+ "toolchains-javascript-frameworks-react",
104
+ "toolchains-typescript-core",
105
+ ],
106
+ "use_cases": ["React SPAs", "Component libraries", "Quick prototypes"],
107
+ },
108
+ "react-max": {
109
+ "description": "Full React skill stack (8+ skills)",
110
+ "skills": CORE_SKILLS
111
+ + [
112
+ "toolchains-javascript-frameworks-react",
113
+ "toolchains-javascript-frameworks-react-state-machine",
114
+ "toolchains-typescript-core",
115
+ "toolchains-typescript-testing-vitest",
116
+ "toolchains-ui-components-headlessui",
117
+ "universal-testing-testing-anti-patterns",
118
+ "universal-architecture-software-patterns",
119
+ ],
120
+ "use_cases": [
121
+ "React production apps",
122
+ "Component systems",
123
+ "Frontend at scale",
124
+ ],
125
+ },
126
+ # ========================================
127
+ # Next.js Toolchain Presets
128
+ # ========================================
129
+ "nextjs-min": {
130
+ "description": "Next.js essentials (4 skills)",
131
+ "skills": CORE_SKILLS
132
+ + [
133
+ "toolchains-nextjs-core",
134
+ "toolchains-javascript-frameworks-react",
135
+ "toolchains-typescript-core",
136
+ ],
137
+ "use_cases": ["Next.js apps", "Vercel deployment", "Full-stack TypeScript"],
138
+ },
139
+ "nextjs-max": {
140
+ "description": "Full Next.js skill stack (10+ skills)",
141
+ "skills": CORE_SKILLS
142
+ + [
143
+ "toolchains-nextjs-core",
144
+ "toolchains-nextjs-v16",
145
+ "toolchains-javascript-frameworks-react",
146
+ "toolchains-javascript-frameworks-react-state-machine",
147
+ "toolchains-typescript-core",
148
+ "toolchains-typescript-data-prisma",
149
+ "toolchains-typescript-data-drizzle",
150
+ "toolchains-typescript-testing-vitest",
151
+ "universal-architecture-software-patterns",
152
+ ],
153
+ "use_cases": ["Next.js production", "Enterprise apps", "Full-stack at scale"],
154
+ },
155
+ # ========================================
156
+ # TypeScript/Data Toolchain Presets
157
+ # ========================================
158
+ "typescript-min": {
159
+ "description": "TypeScript essentials (3 skills)",
160
+ "skills": CORE_SKILLS
161
+ + [
162
+ "toolchains-typescript-core",
163
+ "toolchains-typescript-testing-vitest",
164
+ ],
165
+ "use_cases": ["Type-safe apps", "TypeScript projects", "Node.js with types"],
166
+ },
167
+ "typescript-max": {
168
+ "description": "Full TypeScript skill stack (8+ skills)",
169
+ "skills": CORE_SKILLS
170
+ + [
171
+ "toolchains-typescript-core",
172
+ "toolchains-typescript-testing-vitest",
173
+ "toolchains-typescript-testing-jest",
174
+ "toolchains-typescript-data-prisma",
175
+ "toolchains-typescript-data-drizzle",
176
+ "toolchains-typescript-data-kysely",
177
+ "universal-architecture-software-patterns",
178
+ ],
179
+ "use_cases": ["Enterprise TypeScript", "Full-stack apps", "Type-safe APIs"],
180
+ },
181
+ # ========================================
182
+ # Rust Toolchain Presets
183
+ # ========================================
184
+ "rust-min": {
185
+ "description": "Rust essentials (2 skills)",
186
+ "skills": CORE_SKILLS
187
+ + [
188
+ "toolchains-rust-desktop-applications",
189
+ ],
190
+ "use_cases": ["Rust CLI tools", "Systems programming", "WebAssembly"],
191
+ },
192
+ "rust-max": {
193
+ "description": "Full Rust skill stack (4+ skills)",
194
+ "skills": CORE_SKILLS
195
+ + [
196
+ "toolchains-rust-desktop-applications",
197
+ "toolchains-rust-frameworks-tauri",
198
+ "universal-architecture-software-patterns",
199
+ ],
200
+ "use_cases": [
201
+ "Rust production systems",
202
+ "Performance-critical apps",
203
+ "Safe systems",
204
+ ],
205
+ },
206
+ # ========================================
207
+ # WordPress Toolchain Presets
208
+ # ========================================
209
+ "wordpress-min": {
210
+ "description": "WordPress essentials (2 skills)",
211
+ "skills": CORE_SKILLS
212
+ + [
213
+ "toolchains-php-frameworks-wordpress-plugin-fundamentals",
214
+ ],
215
+ "use_cases": [
216
+ "WordPress plugins",
217
+ "Theme customization",
218
+ "Quick WordPress dev",
219
+ ],
220
+ },
221
+ "wordpress-max": {
222
+ "description": "Full WordPress skill stack (3+ skills)",
223
+ "skills": CORE_SKILLS
224
+ + [
225
+ "toolchains-php-frameworks-wordpress-plugin-fundamentals",
226
+ "toolchains-php-frameworks-wordpress-block-editor",
227
+ "toolchains-php-frameworks-espocrm",
228
+ ],
229
+ "use_cases": ["WordPress production", "Block themes", "Custom blocks", "FSE"],
230
+ },
231
+ # ========================================
232
+ # AI/MCP Toolchain Presets
233
+ # ========================================
234
+ "ai-min": {
235
+ "description": "AI essentials (2 skills)",
236
+ "skills": CORE_SKILLS
237
+ + [
238
+ "toolchains-ai-protocols-mcp",
239
+ ],
240
+ "use_cases": ["MCP servers", "Claude integrations", "AI tools"],
241
+ },
242
+ "ai-max": {
243
+ "description": "Full AI skill stack (3+ skills)",
244
+ "skills": CORE_SKILLS
245
+ + [
246
+ "toolchains-ai-protocols-mcp",
247
+ "toolchains-ai-services-openrouter",
248
+ "universal-main-artifacts-builder",
249
+ ],
250
+ "use_cases": ["Multi-model AI apps", "Claude Desktop extensions", "AI tooling"],
251
+ },
252
+ # ========================================
253
+ # Svelte Toolchain Presets
254
+ # ========================================
255
+ "svelte-min": {
256
+ "description": "Svelte essentials (2 skills)",
257
+ "skills": CORE_SKILLS
258
+ + [
259
+ "toolchains-javascript-frameworks-svelte",
260
+ ],
261
+ "use_cases": ["Svelte apps", "Reactive UIs", "Minimal JavaScript"],
262
+ },
263
+ "svelte-max": {
264
+ "description": "Full Svelte skill stack (3+ skills)",
265
+ "skills": CORE_SKILLS
266
+ + [
267
+ "toolchains-javascript-frameworks-svelte",
268
+ "toolchains-javascript-frameworks-sveltekit",
269
+ "toolchains-typescript-core",
270
+ ],
271
+ "use_cases": ["SvelteKit production", "Full-stack Svelte", "SSR/SSG apps"],
272
+ },
273
+ # ========================================
274
+ # Universal/Testing Toolchain Presets
275
+ # ========================================
276
+ "testing-min": {
277
+ "description": "Testing essentials (3 skills)",
278
+ "skills": CORE_SKILLS
279
+ + [
280
+ "universal-testing-testing-anti-patterns",
281
+ "universal-testing-condition-based-waiting",
282
+ ],
283
+ "use_cases": ["Test quality", "Async testing", "Test improvement"],
284
+ },
285
+ "testing-max": {
286
+ "description": "Full testing skill stack (6+ skills)",
287
+ "skills": CORE_SKILLS
288
+ + [
289
+ "universal-testing-testing-anti-patterns",
290
+ "universal-testing-condition-based-waiting",
291
+ "universal-debugging-verification-before-completion",
292
+ "toolchains-typescript-testing-vitest",
293
+ "toolchains-typescript-testing-jest",
294
+ "toolchains-python-testing-pytest",
295
+ ],
296
+ "use_cases": ["Comprehensive testing", "Test automation", "Quality assurance"],
297
+ },
298
+ # ========================================
299
+ # Collaboration Toolchain Presets
300
+ # ========================================
301
+ "collaboration-min": {
302
+ "description": "Collaboration essentials (2 skills)",
303
+ "skills": CORE_SKILLS
304
+ + [
305
+ "universal-collaboration-brainstorming",
306
+ ],
307
+ "use_cases": ["Idea refinement", "Design thinking", "Feature planning"],
308
+ },
309
+ "collaboration-max": {
310
+ "description": "Full collaboration skill stack (4+ skills)",
311
+ "skills": CORE_SKILLS
312
+ + [
313
+ "universal-collaboration-brainstorming",
314
+ "universal-collaboration-writing-plans",
315
+ "universal-collaboration-requesting-code-review",
316
+ "universal-collaboration-dispatching-parallel-agents",
317
+ ],
318
+ "use_cases": ["Team coordination", "Code reviews", "Planning", "Parallel work"],
319
+ },
320
+ }
321
+
322
+
323
+ def get_preset_names() -> List[str]:
324
+ """Get list of all available preset names.
325
+
326
+ Returns:
327
+ List of preset names (e.g., ['minimal', 'python-min', 'python-max', ...])
328
+
329
+ Example:
330
+ >>> names = get_preset_names()
331
+ >>> 'python-min' in names
332
+ True
333
+ """
334
+ return list(PRESETS.keys())
335
+
336
+
337
+ def get_preset_info(preset_name: str) -> Dict[str, Any]:
338
+ """Get preset metadata (description, use cases, skill count).
339
+
340
+ Args:
341
+ preset_name: Name of preset (e.g., 'python-min')
342
+
343
+ Returns:
344
+ Dict with keys:
345
+ - name: Preset name
346
+ - description: Human-readable description
347
+ - skill_count: Number of skills in preset
348
+ - use_cases: List of use case strings
349
+
350
+ Raises:
351
+ ValueError: If preset name is invalid
352
+
353
+ Example:
354
+ >>> info = get_preset_info('python-min')
355
+ >>> info['skill_count']
356
+ 4
357
+ """
358
+ if preset_name not in PRESETS:
359
+ raise ValueError(f"Unknown preset: {preset_name}")
360
+
361
+ preset = PRESETS[preset_name]
362
+ return {
363
+ "name": preset_name,
364
+ "description": preset["description"],
365
+ "skill_count": len(preset["skills"]),
366
+ "use_cases": preset["use_cases"],
367
+ }
368
+
369
+
370
+ def get_preset_skills(preset_name: str) -> List[str]:
371
+ """Get skill list for preset.
372
+
373
+ Args:
374
+ preset_name: Name of preset (e.g., 'python-min')
375
+
376
+ Returns:
377
+ List of skill IDs (e.g., ["universal-main-skill-creator", ...])
378
+
379
+ Raises:
380
+ ValueError: If preset name is invalid
381
+
382
+ Example:
383
+ >>> skills = get_preset_skills('python-min')
384
+ >>> len(skills)
385
+ 4
386
+ >>> 'universal-main-skill-creator' in skills
387
+ True
388
+ """
389
+ if preset_name not in PRESETS:
390
+ raise ValueError(f"Unknown preset: {preset_name}")
391
+
392
+ return PRESETS[preset_name]["skills"]
claude_mpm/constants.py CHANGED
@@ -168,6 +168,7 @@ class SkillsCommands(str, Enum):
168
168
  UPDATE = "update"
169
169
  INFO = "info"
170
170
  CONFIG = "config"
171
+ CONFIGURE = "configure" # Interactive skills selection (like agents configure)
171
172
  # GitHub deployment commands
172
173
  DEPLOY_FROM_GITHUB = "deploy-github"
173
174
  LIST_AVAILABLE = "list-available"
@@ -802,31 +802,8 @@ Use these agents to delegate specialized work via the Task tool.
802
802
  raise RuntimeError("Subprocess launcher service not available")
803
803
 
804
804
 
805
- def create_simple_context() -> str:
806
- """Create basic context for Claude."""
807
- return """You are Claude Code running in Claude MPM (Multi-Agent Project Manager).
808
-
809
- You have access to native subagents via the Task tool with subagent_type parameter:
810
- - engineer: For coding, implementation, and technical tasks
811
- - qa: For testing, validation, and quality assurance
812
- - documentation: For docs, guides, and explanations
813
- - research: For investigation and analysis
814
- - security: For security-related tasks
815
- - ops: For deployment and infrastructure
816
- - version-control: For git and version management
817
- - data-engineer: For data processing and APIs
818
-
819
- Use these agents by calling: Task(description="task description", subagent_type="agent_name")
820
-
821
- IMPORTANT: The Task tool accepts both naming formats:
822
- - Capitalized format: "Research", "Engineer", "QA", "Version Control", "Data Engineer"
823
- - Lowercase format: "research", "engineer", "qa", "version-control", "data-engineer"
824
-
825
- Both formats work correctly. When you see capitalized names (matching TodoWrite prefixes),
826
- automatically normalize them to lowercase-hyphenated format for the Task tool.
827
-
828
- Work efficiently and delegate appropriately to subagents when needed."""
829
-
805
+ # Moved to claude_mpm.core.system_context to avoid circular imports
806
+ from claude_mpm.core.system_context import create_simple_context
830
807
 
831
808
  # Backward compatibility alias
832
809
  SimpleClaudeRunner = ClaudeRunner
@@ -66,6 +66,53 @@ class FileLoader:
66
66
  if "INSTRUCTIONS.md" in str(file_path):
67
67
  self.framework_last_modified = timestamp
68
68
 
69
+ def _load_tier_file(
70
+ self,
71
+ filename: str,
72
+ current_dir: Path,
73
+ framework_path: Optional[Path] = None,
74
+ include_system: bool = False,
75
+ ) -> tuple[Optional[str], Optional[str]]:
76
+ """Load file with tier precedence: project → user → system.
77
+
78
+ Args:
79
+ filename: Name of file to load (e.g., "INSTRUCTIONS.md")
80
+ current_dir: Current working directory for project-level
81
+ framework_path: Path to framework installation for system-level
82
+ include_system: Whether to check system-level path
83
+
84
+ Returns:
85
+ Tuple of (content, level) where level is 'project', 'user', 'system', or None
86
+ """
87
+ # Check project-level (highest priority)
88
+ project_path = current_dir / ".claude-mpm" / filename
89
+ if project_path.exists():
90
+ loaded_content = self.try_load_file(
91
+ project_path, f"project-specific {filename}"
92
+ )
93
+ if loaded_content:
94
+ self.logger.info(f"Using project-specific {filename} from .claude-mpm/")
95
+ return loaded_content, "project"
96
+
97
+ # Check user-level (medium priority)
98
+ user_path = Path.home() / ".claude-mpm" / filename
99
+ if user_path.exists():
100
+ loaded_content = self.try_load_file(user_path, f"user-specific {filename}")
101
+ if loaded_content:
102
+ self.logger.info(f"Using user-specific {filename} from ~/.claude-mpm/")
103
+ return loaded_content, "user"
104
+
105
+ # Check system-level (lowest priority)
106
+ if include_system and framework_path and framework_path != Path("__PACKAGED__"):
107
+ system_path = framework_path / "src" / "claude_mpm" / "agents" / filename
108
+ if system_path.exists():
109
+ loaded_content = self.try_load_file(system_path, f"system {filename}")
110
+ if loaded_content:
111
+ self.logger.info(f"Using system {filename}")
112
+ return loaded_content, "system"
113
+
114
+ return None, None
115
+
69
116
  def load_instructions_file(
70
117
  self, current_dir: Path
71
118
  ) -> tuple[Optional[str], Optional[str]]:
@@ -82,31 +129,7 @@ class FileLoader:
82
129
  Returns:
83
130
  Tuple of (content, level) where level is 'project', 'user', or None
84
131
  """
85
- # Check for project-specific INSTRUCTIONS.md first
86
- project_instructions_path = current_dir / ".claude-mpm" / "INSTRUCTIONS.md"
87
- if project_instructions_path.exists():
88
- loaded_content = self.try_load_file(
89
- project_instructions_path, "project-specific INSTRUCTIONS.md"
90
- )
91
- if loaded_content:
92
- self.logger.info(
93
- "Using project-specific PM instructions from .claude-mpm/INSTRUCTIONS.md"
94
- )
95
- return loaded_content, "project"
96
-
97
- # Check for user-specific INSTRUCTIONS.md
98
- user_instructions_path = Path.home() / ".claude-mpm" / "INSTRUCTIONS.md"
99
- if user_instructions_path.exists():
100
- loaded_content = self.try_load_file(
101
- user_instructions_path, "user-specific INSTRUCTIONS.md"
102
- )
103
- if loaded_content:
104
- self.logger.info(
105
- "Using user-specific PM instructions from ~/.claude-mpm/INSTRUCTIONS.md"
106
- )
107
- return loaded_content, "user"
108
-
109
- return None, None
132
+ return self._load_tier_file("INSTRUCTIONS.md", current_dir)
110
133
 
111
134
  def load_workflow_file(
112
135
  self, current_dir: Path, framework_path: Path
@@ -126,44 +149,9 @@ class FileLoader:
126
149
  Returns:
127
150
  Tuple of (content, level) where level is 'project', 'user', 'system', or None
128
151
  """
129
- # Check for project-specific WORKFLOW.md first (highest priority)
130
- project_workflow_path = current_dir / ".claude-mpm" / "WORKFLOW.md"
131
- if project_workflow_path.exists():
132
- loaded_content = self.try_load_file(
133
- project_workflow_path, "project-specific WORKFLOW.md"
134
- )
135
- if loaded_content:
136
- self.logger.info(
137
- "Using project-specific workflow instructions from .claude-mpm/WORKFLOW.md"
138
- )
139
- return loaded_content, "project"
140
-
141
- # Check for user-specific WORKFLOW.md (medium priority)
142
- user_workflow_path = Path.home() / ".claude-mpm" / "WORKFLOW.md"
143
- if user_workflow_path.exists():
144
- loaded_content = self.try_load_file(
145
- user_workflow_path, "user-specific WORKFLOW.md"
146
- )
147
- if loaded_content:
148
- self.logger.info(
149
- "Using user-specific workflow instructions from ~/.claude-mpm/WORKFLOW.md"
150
- )
151
- return loaded_content, "user"
152
-
153
- # Fall back to system workflow (lowest priority)
154
- if framework_path and framework_path != Path("__PACKAGED__"):
155
- system_workflow_path = (
156
- framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
157
- )
158
- if system_workflow_path.exists():
159
- loaded_content = self.try_load_file(
160
- system_workflow_path, "system WORKFLOW.md"
161
- )
162
- if loaded_content:
163
- self.logger.info("Using system workflow instructions")
164
- return loaded_content, "system"
165
-
166
- return None, None
152
+ return self._load_tier_file(
153
+ "WORKFLOW.md", current_dir, framework_path, include_system=True
154
+ )
167
155
 
168
156
  def load_memory_file(
169
157
  self, current_dir: Path, framework_path: Path
@@ -183,41 +171,6 @@ class FileLoader:
183
171
  Returns:
184
172
  Tuple of (content, level) where level is 'project', 'user', 'system', or None
185
173
  """
186
- # Check for project-specific MEMORY.md first (highest priority)
187
- project_memory_path = current_dir / ".claude-mpm" / "MEMORY.md"
188
- if project_memory_path.exists():
189
- loaded_content = self.try_load_file(
190
- project_memory_path, "project-specific MEMORY.md"
191
- )
192
- if loaded_content:
193
- self.logger.info(
194
- "Using project-specific memory instructions from .claude-mpm/MEMORY.md"
195
- )
196
- return loaded_content, "project"
197
-
198
- # Check for user-specific MEMORY.md (medium priority)
199
- user_memory_path = Path.home() / ".claude-mpm" / "MEMORY.md"
200
- if user_memory_path.exists():
201
- loaded_content = self.try_load_file(
202
- user_memory_path, "user-specific MEMORY.md"
203
- )
204
- if loaded_content:
205
- self.logger.info(
206
- "Using user-specific memory instructions from ~/.claude-mpm/MEMORY.md"
207
- )
208
- return loaded_content, "user"
209
-
210
- # Fall back to system memory instructions (lowest priority)
211
- if framework_path and framework_path != Path("__PACKAGED__"):
212
- system_memory_path = (
213
- framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
214
- )
215
- if system_memory_path.exists():
216
- loaded_content = self.try_load_file(
217
- system_memory_path, "system MEMORY.md"
218
- )
219
- if loaded_content:
220
- self.logger.info("Using system memory instructions")
221
- return loaded_content, "system"
222
-
223
- return None, None
174
+ return self._load_tier_file(
175
+ "MEMORY.md", current_dir, framework_path, include_system=True
176
+ )
@@ -2,6 +2,12 @@
2
2
 
3
3
  This module provides the InteractiveSession class that manages Claude's interactive mode
4
4
  with proper separation of concerns and reduced complexity.
5
+
6
+ DEPENDENCY INJECTION:
7
+ This module uses protocol-based dependency injection to break circular imports.
8
+ Instead of importing ClaudeRunner directly, it uses ClaudeRunnerProtocol which
9
+ defines the interface it needs. This allows ClaudeRunner to create instances
10
+ of InteractiveSession without circular dependency issues.
5
11
  """
6
12
 
7
13
  import contextlib
@@ -9,11 +15,18 @@ import os
9
15
  import subprocess
10
16
  import uuid
11
17
  from pathlib import Path
12
- from typing import Any, Dict, Optional, Tuple
18
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
13
19
 
14
20
  from claude_mpm.core.enums import ServiceState
15
21
  from claude_mpm.core.logger import get_logger
16
22
 
23
+ # Protocol imports for type checking without circular dependencies
24
+ if TYPE_CHECKING:
25
+ from claude_mpm.core.protocols import ClaudeRunnerProtocol
26
+ else:
27
+ # At runtime, accept any object with matching interface
28
+ ClaudeRunnerProtocol = Any
29
+
17
30
 
18
31
  class InteractiveSession:
19
32
  """
@@ -28,13 +41,14 @@ class InteractiveSession:
28
41
  and makes testing easier while preserving all original functionality.
29
42
  """
30
43
 
31
- def __init__(self, runner):
44
+ def __init__(self, runner: "ClaudeRunnerProtocol"):
32
45
  """Initialize interactive session handler.
33
46
 
34
47
  Args:
35
- runner: ClaudeRunner instance with all necessary services
48
+ runner: ClaudeRunner instance (or any object matching ClaudeRunnerProtocol)
49
+ with all necessary services
36
50
  """
37
- self.runner = runner
51
+ self.runner: ClaudeRunnerProtocol = runner
38
52
  self.logger = get_logger("interactive_session")
39
53
  self.session_id = None
40
54
  self.original_cwd = Path.cwd()
@@ -397,7 +411,7 @@ class InteractiveSession:
397
411
  self.logger.info("✓ Native agents mode: Using --agents CLI flag")
398
412
 
399
413
  # Add system instructions with file-based caching
400
- from claude_mpm.core.claude_runner import create_simple_context
414
+ from claude_mpm.core.system_context import create_simple_context
401
415
  from claude_mpm.services.instructions.instruction_cache_service import (
402
416
  InstructionCacheService,
403
417
  )