claude-mpm 5.4.96__py3-none-any.whl → 5.6.10__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 (191) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +44 -10
  4. claude_mpm/agents/WORKFLOW.md +2 -0
  5. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  6. claude_mpm/cli/commands/autotodos.py +45 -5
  7. claude_mpm/cli/commands/commander.py +46 -0
  8. claude_mpm/cli/commands/hook_errors.py +60 -60
  9. claude_mpm/cli/commands/run.py +35 -3
  10. claude_mpm/cli/commands/skill_source.py +51 -2
  11. claude_mpm/cli/commands/skills.py +5 -3
  12. claude_mpm/cli/executor.py +32 -17
  13. claude_mpm/cli/parsers/base_parser.py +17 -0
  14. claude_mpm/cli/parsers/commander_parser.py +83 -0
  15. claude_mpm/cli/parsers/run_parser.py +10 -0
  16. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  17. claude_mpm/cli/parsers/skills_parser.py +5 -0
  18. claude_mpm/cli/startup.py +20 -2
  19. claude_mpm/cli/utils.py +7 -3
  20. claude_mpm/commander/__init__.py +72 -0
  21. claude_mpm/commander/adapters/__init__.py +31 -0
  22. claude_mpm/commander/adapters/base.py +191 -0
  23. claude_mpm/commander/adapters/claude_code.py +361 -0
  24. claude_mpm/commander/adapters/communication.py +366 -0
  25. claude_mpm/commander/api/__init__.py +16 -0
  26. claude_mpm/commander/api/app.py +105 -0
  27. claude_mpm/commander/api/errors.py +133 -0
  28. claude_mpm/commander/api/routes/__init__.py +8 -0
  29. claude_mpm/commander/api/routes/events.py +184 -0
  30. claude_mpm/commander/api/routes/inbox.py +171 -0
  31. claude_mpm/commander/api/routes/messages.py +148 -0
  32. claude_mpm/commander/api/routes/projects.py +271 -0
  33. claude_mpm/commander/api/routes/sessions.py +228 -0
  34. claude_mpm/commander/api/routes/work.py +260 -0
  35. claude_mpm/commander/api/schemas.py +182 -0
  36. claude_mpm/commander/chat/__init__.py +7 -0
  37. claude_mpm/commander/chat/cli.py +107 -0
  38. claude_mpm/commander/chat/commands.py +96 -0
  39. claude_mpm/commander/chat/repl.py +310 -0
  40. claude_mpm/commander/config.py +49 -0
  41. claude_mpm/commander/config_loader.py +115 -0
  42. claude_mpm/commander/daemon.py +398 -0
  43. claude_mpm/commander/events/__init__.py +26 -0
  44. claude_mpm/commander/events/manager.py +332 -0
  45. claude_mpm/commander/frameworks/__init__.py +12 -0
  46. claude_mpm/commander/frameworks/base.py +143 -0
  47. claude_mpm/commander/frameworks/claude_code.py +58 -0
  48. claude_mpm/commander/frameworks/mpm.py +62 -0
  49. claude_mpm/commander/inbox/__init__.py +16 -0
  50. claude_mpm/commander/inbox/dedup.py +128 -0
  51. claude_mpm/commander/inbox/inbox.py +224 -0
  52. claude_mpm/commander/inbox/models.py +70 -0
  53. claude_mpm/commander/instance_manager.py +337 -0
  54. claude_mpm/commander/llm/__init__.py +6 -0
  55. claude_mpm/commander/llm/openrouter_client.py +167 -0
  56. claude_mpm/commander/llm/summarizer.py +70 -0
  57. claude_mpm/commander/models/__init__.py +18 -0
  58. claude_mpm/commander/models/events.py +121 -0
  59. claude_mpm/commander/models/project.py +162 -0
  60. claude_mpm/commander/models/work.py +214 -0
  61. claude_mpm/commander/parsing/__init__.py +20 -0
  62. claude_mpm/commander/parsing/extractor.py +132 -0
  63. claude_mpm/commander/parsing/output_parser.py +270 -0
  64. claude_mpm/commander/parsing/patterns.py +100 -0
  65. claude_mpm/commander/persistence/__init__.py +11 -0
  66. claude_mpm/commander/persistence/event_store.py +274 -0
  67. claude_mpm/commander/persistence/state_store.py +309 -0
  68. claude_mpm/commander/persistence/work_store.py +164 -0
  69. claude_mpm/commander/polling/__init__.py +13 -0
  70. claude_mpm/commander/polling/event_detector.py +104 -0
  71. claude_mpm/commander/polling/output_buffer.py +49 -0
  72. claude_mpm/commander/polling/output_poller.py +153 -0
  73. claude_mpm/commander/project_session.py +268 -0
  74. claude_mpm/commander/proxy/__init__.py +12 -0
  75. claude_mpm/commander/proxy/formatter.py +89 -0
  76. claude_mpm/commander/proxy/output_handler.py +191 -0
  77. claude_mpm/commander/proxy/relay.py +155 -0
  78. claude_mpm/commander/registry.py +404 -0
  79. claude_mpm/commander/runtime/__init__.py +10 -0
  80. claude_mpm/commander/runtime/executor.py +191 -0
  81. claude_mpm/commander/runtime/monitor.py +316 -0
  82. claude_mpm/commander/session/__init__.py +6 -0
  83. claude_mpm/commander/session/context.py +81 -0
  84. claude_mpm/commander/session/manager.py +59 -0
  85. claude_mpm/commander/tmux_orchestrator.py +361 -0
  86. claude_mpm/commander/web/__init__.py +1 -0
  87. claude_mpm/commander/work/__init__.py +30 -0
  88. claude_mpm/commander/work/executor.py +189 -0
  89. claude_mpm/commander/work/queue.py +405 -0
  90. claude_mpm/commander/workflow/__init__.py +27 -0
  91. claude_mpm/commander/workflow/event_handler.py +219 -0
  92. claude_mpm/commander/workflow/notifier.py +146 -0
  93. claude_mpm/commands/mpm-config.md +8 -0
  94. claude_mpm/commands/mpm-doctor.md +8 -0
  95. claude_mpm/commands/mpm-help.md +8 -0
  96. claude_mpm/commands/mpm-init.md +8 -0
  97. claude_mpm/commands/mpm-monitor.md +8 -0
  98. claude_mpm/commands/mpm-organize.md +8 -0
  99. claude_mpm/commands/mpm-postmortem.md +8 -0
  100. claude_mpm/commands/mpm-session-resume.md +8 -0
  101. claude_mpm/commands/mpm-status.md +8 -0
  102. claude_mpm/commands/mpm-ticket-view.md +8 -0
  103. claude_mpm/commands/mpm-version.md +8 -0
  104. claude_mpm/commands/mpm.md +8 -0
  105. claude_mpm/config/agent_presets.py +8 -7
  106. claude_mpm/config/skill_sources.py +16 -0
  107. claude_mpm/core/config.py +32 -19
  108. claude_mpm/core/logger.py +26 -9
  109. claude_mpm/core/logging_utils.py +35 -11
  110. claude_mpm/core/output_style_manager.py +15 -5
  111. claude_mpm/core/unified_config.py +10 -6
  112. claude_mpm/core/unified_paths.py +68 -80
  113. claude_mpm/experimental/cli_enhancements.py +2 -1
  114. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
  115. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  116. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  117. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
  118. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
  119. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  120. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  121. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
  122. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  123. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  124. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
  125. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  126. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  127. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  128. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  129. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
  130. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  131. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  132. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
  133. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
  134. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
  135. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +29 -30
  136. claude_mpm/hooks/claude_hooks/event_handlers.py +90 -99
  137. claude_mpm/hooks/claude_hooks/hook_handler.py +81 -88
  138. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  139. claude_mpm/hooks/claude_hooks/installer.py +116 -8
  140. claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
  141. claude_mpm/hooks/claude_hooks/response_tracking.py +39 -58
  142. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
  143. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
  144. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  145. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  146. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  151. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  152. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  153. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  154. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
  155. claude_mpm/hooks/claude_hooks/services/connection_manager.py +23 -28
  156. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
  157. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  158. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +47 -73
  159. claude_mpm/hooks/session_resume_hook.py +22 -18
  160. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  161. claude_mpm/scripts/claude-hook-handler.sh +43 -16
  162. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  163. claude_mpm/services/agents/agent_selection_service.py +2 -2
  164. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  165. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  166. claude_mpm/services/event_log.py +8 -0
  167. claude_mpm/services/pm_skills_deployer.py +84 -6
  168. claude_mpm/services/skills/git_skill_source_manager.py +130 -10
  169. claude_mpm/services/skills/selective_skill_deployer.py +28 -0
  170. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  171. claude_mpm/services/skills_deployer.py +31 -5
  172. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  173. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  174. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  175. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  176. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  177. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  178. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  179. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  180. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  181. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  182. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  183. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  184. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/METADATA +18 -4
  185. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/RECORD +190 -79
  186. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  187. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/WHEEL +0 -0
  188. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/entry_points.txt +0 -0
  189. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE +0 -0
  190. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  191. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.10.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,7 @@ DESIGN DECISIONS:
13
13
  - Support multiple output formats (json, yaml, table, text)
14
14
  """
15
15
 
16
- import subprocess
16
+ import subprocess # nosec B404 - required for process management
17
17
  import sys
18
18
  from datetime import datetime, timezone
19
19
  from typing import Optional
@@ -489,6 +489,18 @@ class RunCommand(BaseCommand):
489
489
  if hasattr(args, "claude_args") and args.claude_args:
490
490
  claude_args.extend(args.claude_args)
491
491
 
492
+ # Add --resume if flag is set
493
+ if getattr(args, "resume", False) and "--resume" not in claude_args:
494
+ claude_args.insert(0, "--resume")
495
+
496
+ # Add --chrome if flag is set
497
+ if getattr(args, "chrome", False) and "--chrome" not in claude_args:
498
+ claude_args.insert(0, "--chrome")
499
+
500
+ # Add --no-chrome if flag is set
501
+ if getattr(args, "no_chrome", False) and "--no-chrome" not in claude_args:
502
+ claude_args.insert(0, "--no-chrome")
503
+
492
504
  # Create runner
493
505
  runner = ClaudeRunner(
494
506
  enable_tickets=enable_tickets,
@@ -553,7 +565,7 @@ class RunCommand(BaseCommand):
553
565
  wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
554
566
  if wrapper_path.exists():
555
567
  print("Starting interactive session with command interception...")
556
- subprocess.run([sys.executable, str(wrapper_path)], check=False)
568
+ subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
557
569
  else:
558
570
  self.logger.warning(
559
571
  "Interactive wrapper not found, falling back to normal mode"
@@ -907,6 +919,26 @@ def run_session_legacy(args):
907
919
  else:
908
920
  logger.info("[INFO]️ --resume already in claude_args")
909
921
 
922
+ # Add --chrome to claude_args if the flag is set
923
+ chrome_flag_present = getattr(args, "chrome", False)
924
+ if chrome_flag_present:
925
+ logger.info("📌 --chrome flag detected in args")
926
+ if "--chrome" not in raw_claude_args:
927
+ raw_claude_args = ["--chrome", *raw_claude_args]
928
+ logger.info("✅ Added --chrome to claude_args")
929
+ else:
930
+ logger.info("ℹ️ --chrome already in claude_args")
931
+
932
+ # Add --no-chrome to claude_args if the flag is set
933
+ no_chrome_flag_present = getattr(args, "no_chrome", False)
934
+ if no_chrome_flag_present:
935
+ logger.info("📌 --no-chrome flag detected in args")
936
+ if "--no-chrome" not in raw_claude_args:
937
+ raw_claude_args = ["--no-chrome", *raw_claude_args]
938
+ logger.info("✅ Added --no-chrome to claude_args")
939
+ else:
940
+ logger.info("ℹ️ --no-chrome already in claude_args")
941
+
910
942
  # Filter out claude-mpm specific flags before passing to Claude CLI
911
943
  logger.debug(f"Pre-filter claude_args: {raw_claude_args}")
912
944
  claude_args = filter_claude_mpm_args(raw_claude_args)
@@ -1044,7 +1076,7 @@ def run_session_legacy(args):
1044
1076
  wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
1045
1077
  if wrapper_path.exists():
1046
1078
  print("Starting interactive session with command interception...")
1047
- subprocess.run([sys.executable, str(wrapper_path)], check=False)
1079
+ subprocess.run([sys.executable, str(wrapper_path)], check=False) # nosec B603 - trusted internal paths
1048
1080
  else:
1049
1081
  logger.warning("Interactive wrapper not found, falling back to normal mode")
1050
1082
  runner.run_interactive(context)
@@ -11,6 +11,7 @@ for better UX. Handles errors gracefully with actionable messages.
11
11
 
12
12
  import json
13
13
  import logging
14
+ import os
14
15
  import re
15
16
 
16
17
  from ...config.skill_sources import SkillSource, SkillSourceConfiguration
@@ -20,6 +21,33 @@ from ...services.skills.skill_discovery_service import SkillDiscoveryService
20
21
  logger = logging.getLogger(__name__)
21
22
 
22
23
 
24
+ def _get_github_token(source: SkillSource | None = None) -> str | None:
25
+ """Get GitHub token with source-specific override support.
26
+
27
+ Priority: source.token > GITHUB_TOKEN > GH_TOKEN
28
+
29
+ Args:
30
+ source: Optional SkillSource to check for per-source token
31
+
32
+ Returns:
33
+ GitHub token if found, None otherwise
34
+
35
+ Security Note:
36
+ Token is never logged or printed to avoid exposure.
37
+ """
38
+ # Priority 1: Per-source token (env var reference or direct)
39
+ if source and source.token:
40
+ if source.token.startswith("$"):
41
+ # Env var reference: $VAR_NAME -> os.environ.get("VAR_NAME")
42
+ env_var_name = source.token[1:]
43
+ return os.environ.get(env_var_name)
44
+ # Direct token (not recommended but supported)
45
+ return source.token
46
+
47
+ # Priority 2-3: Global environment variables
48
+ return os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
49
+
50
+
23
51
  def _test_skill_repository_access(source: SkillSource) -> dict:
24
52
  """Test if skill repository is accessible via GitHub API.
25
53
 
@@ -58,7 +86,13 @@ def _test_skill_repository_access(source: SkillSource) -> dict:
58
86
  # Test GitHub API access
59
87
  api_url = f"https://api.github.com/repos/{owner_repo}"
60
88
 
61
- response = requests.get(api_url, timeout=10)
89
+ # Build headers with authentication if token available
90
+ headers = {"Accept": "application/vnd.github+json"}
91
+ token = _get_github_token(source)
92
+ if token:
93
+ headers["Authorization"] = f"token {token}"
94
+
95
+ response = requests.get(api_url, headers=headers, timeout=10)
62
96
 
63
97
  if response.status_code == 200:
64
98
  return {"accessible": True, "error": None}
@@ -68,9 +102,14 @@ def _test_skill_repository_access(source: SkillSource) -> dict:
68
102
  "error": f"Repository not found: {owner_repo}",
69
103
  }
70
104
  if response.status_code == 403:
105
+ error_msg = "Access denied (private repository or rate limit)"
106
+ if not token:
107
+ error_msg += (
108
+ ". Try setting GITHUB_TOKEN environment variable for private repos"
109
+ )
71
110
  return {
72
111
  "accessible": False,
73
- "error": "Access denied (private repository or rate limit)",
112
+ "error": error_msg,
74
113
  }
75
114
  return {
76
115
  "accessible": False,
@@ -263,6 +302,15 @@ def handle_add_skill_source(args) -> int:
263
302
 
264
303
  # Create new source
265
304
  enabled = not args.disabled
305
+ token = getattr(args, "token", None)
306
+
307
+ # Security warning for direct tokens
308
+ if token and not token.startswith("$"):
309
+ print("⚠️ Warning: Direct token values in config are not recommended")
310
+ print(" Consider using environment variable reference instead:")
311
+ print(" --token $MY_PRIVATE_TOKEN")
312
+ print()
313
+
266
314
  source = SkillSource(
267
315
  id=source_id,
268
316
  type="git",
@@ -270,6 +318,7 @@ def handle_add_skill_source(args) -> int:
270
318
  branch=args.branch,
271
319
  priority=args.priority,
272
320
  enabled=enabled,
321
+ token=token,
273
322
  )
274
323
 
275
324
  # Determine if we should test
@@ -538,6 +538,7 @@ class SkillsManagementCommand(BaseCommand):
538
538
  toolchain = getattr(args, "toolchain", None)
539
539
  categories = getattr(args, "categories", None)
540
540
  force = getattr(args, "force", False)
541
+ deploy_all = getattr(args, "all", False)
541
542
 
542
543
  if collection:
543
544
  console.print(
@@ -548,14 +549,15 @@ class SkillsManagementCommand(BaseCommand):
548
549
  "\n[bold cyan]Deploying skills from default collection...[/bold cyan]\n"
549
550
  )
550
551
 
551
- # Selective deployment is ALWAYS enabled (deploy only agent-referenced skills)
552
- # This ensures only skills linked to deployed agents are deployed
552
+ # Use selective deployment unless --all flag is provided
553
+ # Selective mode deploys only agent-referenced skills
554
+ # --all mode deploys all available skills from the collection
553
555
  result = self.skills_deployer.deploy_skills(
554
556
  collection=collection,
555
557
  toolchain=toolchain,
556
558
  categories=categories,
557
559
  force=force,
558
- selective=True, # Always use selective deployment
560
+ selective=not deploy_all,
559
561
  )
560
562
 
561
563
  # Display results
@@ -127,6 +127,14 @@ def execute_command(command: str, args) -> int:
127
127
  result = handle_verify(args)
128
128
  return result if result is not None else 0
129
129
 
130
+ # Handle commander command with lazy import
131
+ if command == "commander":
132
+ # Lazy import to avoid loading unless needed
133
+ from .commands.commander import handle_commander_command
134
+
135
+ result = handle_commander_command(args)
136
+ return result if result is not None else 0
137
+
130
138
  # Handle skill-source command with lazy import
131
139
  if command == "skill-source":
132
140
  # Lazy import to avoid loading unless needed
@@ -206,27 +214,33 @@ def execute_command(command: str, args) -> int:
206
214
  "status": show_status,
207
215
  }
208
216
 
209
- # Get handler and invoke
217
+ # Get handler and call it with argument list (same pattern as autotodos)
210
218
  handler = handlers.get(subcommand)
211
219
  if handler:
212
- # Build Click context programmatically
213
- import click
214
-
215
- ctx = click.Context(command=handler)
220
+ try:
221
+ # Build argument list for Click command based on subcommand
222
+ click_args = []
216
223
 
217
- # Prepare keyword arguments from args
218
- kwargs = {}
219
- if hasattr(args, "format"):
220
- kwargs["format"] = args.format
221
- if hasattr(args, "hook_type"):
222
- kwargs["hook_type"] = args.hook_type
223
- if hasattr(args, "yes"):
224
- kwargs["yes"] = args.yes
224
+ # list command: --format, --hook-type
225
+ if subcommand == "list":
226
+ if hasattr(args, "format") and args.format:
227
+ click_args.extend(["--format", args.format])
228
+ if hasattr(args, "hook_type") and args.hook_type:
229
+ click_args.extend(["--hook-type", args.hook_type])
230
+ # clear command: --hook-type, -y
231
+ elif subcommand == "clear":
232
+ if hasattr(args, "hook_type") and args.hook_type:
233
+ click_args.extend(["--hook-type", args.hook_type])
234
+ if hasattr(args, "yes") and args.yes:
235
+ click_args.append("-y")
236
+ # diagnose command: hook_type (positional argument)
237
+ elif subcommand == "diagnose":
238
+ if hasattr(args, "hook_type") and args.hook_type:
239
+ click_args.append(args.hook_type)
240
+ # status and summary commands: no options
225
241
 
226
- try:
227
- # Invoke handler with arguments
228
- with ctx:
229
- handler.invoke(ctx, **kwargs)
242
+ # Call Click command with argument list and standalone_mode=False
243
+ handler(click_args, standalone_mode=False)
230
244
  return 0
231
245
  except SystemExit as e:
232
246
  return e.code if e.code is not None else 0
@@ -346,6 +360,7 @@ def execute_command(command: str, args) -> int:
346
360
  CLICommands.SKILLS.value: manage_skills,
347
361
  "debug": manage_debug, # Add debug command
348
362
  "mpm-init": None, # Will be handled separately with lazy import
363
+ "commander": None, # Will be handled separately with lazy import
349
364
  }
350
365
 
351
366
  # Execute command if found
@@ -297,6 +297,16 @@ def add_top_level_run_arguments(parser: argparse.ArgumentParser) -> None:
297
297
  action="store_true",
298
298
  help="Force refresh agents and skills from remote repos, bypassing ETag cache",
299
299
  )
300
+ run_group.add_argument(
301
+ "--chrome",
302
+ action="store_true",
303
+ help="Enable Claude in Chrome integration (passed to Claude Code)",
304
+ )
305
+ run_group.add_argument(
306
+ "--no-chrome",
307
+ action="store_true",
308
+ help="Disable Claude in Chrome integration (passed to Claude Code)",
309
+ )
300
310
 
301
311
  # Dependency checking options (for backward compatibility at top level)
302
312
  dep_group_top = parser.add_argument_group(
@@ -492,6 +502,13 @@ def create_parser(
492
502
  except ImportError:
493
503
  pass
494
504
 
505
+ try:
506
+ from .commander_parser import add_commander_subparser
507
+
508
+ add_commander_subparser(subparsers)
509
+ except ImportError:
510
+ pass
511
+
495
512
  # Add uninstall command parser
496
513
  try:
497
514
  from ..commands.uninstall import add_uninstall_parser
@@ -0,0 +1,83 @@
1
+ """
2
+ Commander parser module for claude-mpm CLI.
3
+
4
+ WHY: This module provides the commander subcommand for interactive instance management
5
+ and chat interface.
6
+
7
+ DESIGN DECISION: Uses subparser pattern consistent with other commands (run, agents, etc.)
8
+ to provide a clean interface for Commander mode.
9
+ """
10
+
11
+ import argparse
12
+ from pathlib import Path
13
+
14
+
15
+ def add_commander_subparser(subparsers: argparse._SubParsersAction) -> None:
16
+ """
17
+ Add commander subcommand parser.
18
+
19
+ WHY: Provides interactive mode for managing and chatting with multiple Claude instances.
20
+
21
+ Args:
22
+ subparsers: The subparsers object to add the commander parser to
23
+ """
24
+ commander_parser = subparsers.add_parser(
25
+ "commander",
26
+ help="Interactive Commander mode for managing multiple Claude instances",
27
+ description="""
28
+ Commander Mode - Interactive Instance Management
29
+
30
+ Commander provides an interactive REPL interface for:
31
+ - Starting and stopping Claude Code/MPM instances in tmux
32
+ - Connecting to instances and sending natural language commands
33
+ - Managing multiple concurrent projects
34
+ - Viewing instance status and output
35
+
36
+ Commands:
37
+ list, ls, instances List active instances
38
+ start <path> Start new instance at path
39
+ --framework <cc|mpm> Specify framework (default: cc)
40
+ --name <name> Specify instance name (default: dir name)
41
+ stop <name> Stop an instance
42
+ connect <name> Connect to an instance
43
+ disconnect Disconnect from current instance
44
+ status Show current session status
45
+ help Show help message
46
+ exit, quit, q Exit Commander
47
+
48
+ Natural Language:
49
+ When connected to an instance, any input that is not a built-in
50
+ command will be sent to the connected instance as a message.
51
+
52
+ Examples:
53
+ claude-mpm commander
54
+ > start ~/myproject --framework cc --name myapp
55
+ > connect myapp
56
+ > Fix the authentication bug in login.py
57
+ > disconnect
58
+ > exit
59
+ """,
60
+ formatter_class=argparse.RawDescriptionHelpFormatter,
61
+ )
62
+
63
+ # Optional: Port for internal services
64
+ commander_parser.add_argument(
65
+ "--port",
66
+ type=int,
67
+ default=8765,
68
+ help="Port for internal services (default: 8765)",
69
+ )
70
+
71
+ # Optional: State directory
72
+ commander_parser.add_argument(
73
+ "--state-dir",
74
+ type=Path,
75
+ help="Directory for state persistence (optional)",
76
+ )
77
+
78
+ # Debug mode
79
+ commander_parser.add_argument(
80
+ "--debug",
81
+ action="store_true",
82
+ help="Enable debug logging",
83
+ )
@@ -85,6 +85,16 @@ def add_run_arguments(parser: argparse.ArgumentParser) -> None:
85
85
  action="store_true",
86
86
  help="Pass --resume flag to Claude Code to resume the last conversation",
87
87
  )
88
+ run_group.add_argument(
89
+ "--chrome",
90
+ action="store_true",
91
+ help="Enable Claude in Chrome integration (passed to Claude Code)",
92
+ )
93
+ run_group.add_argument(
94
+ "--no-chrome",
95
+ action="store_true",
96
+ help="Disable Claude in Chrome integration (passed to Claude Code)",
97
+ )
88
98
 
89
99
  # Dependency checking options
90
100
  dep_group = parser.add_argument_group("dependency options")
@@ -76,6 +76,10 @@ def add_skill_source_subparser(subparsers) -> argparse.ArgumentParser:
76
76
  dest="skip_test",
77
77
  help="Skip immediate testing (not recommended)",
78
78
  )
79
+ add_parser.add_argument(
80
+ "--token",
81
+ help="GitHub token or env var reference (e.g., ghp_xxx or $PRIVATE_TOKEN)",
82
+ )
79
83
 
80
84
  # Remove repository
81
85
  remove_parser = skill_source_subparsers.add_parser(
@@ -167,6 +167,11 @@ def add_skills_subparser(subparsers) -> argparse.ArgumentParser:
167
167
  action="store_true",
168
168
  help="Force redeployment of already deployed skills",
169
169
  )
170
+ deploy_github_parser.add_argument(
171
+ "--all",
172
+ action="store_true",
173
+ help="Deploy all available skills, not just agent-referenced ones",
174
+ )
170
175
 
171
176
  # List available GitHub skills
172
177
  list_available_parser = skills_subparsers.add_parser(
claude_mpm/cli/startup.py CHANGED
@@ -161,7 +161,25 @@ def setup_early_environment(argv):
161
161
  # CRITICAL: Suppress ALL logging by default
162
162
  # This catches all loggers (claude_mpm.*, service.*, framework_loader, etc.)
163
163
  # This will be overridden by setup_mcp_server_logging() based on user preference
164
- logging.getLogger().setLevel(logging.CRITICAL + 1) # Root logger catches everything
164
+ root_logger = logging.getLogger()
165
+ root_logger.setLevel(logging.CRITICAL + 1) # Root logger catches everything
166
+ root_logger.handlers = [] # Remove any handlers
167
+
168
+ # Also suppress common module loggers explicitly to prevent handler leakage
169
+ for logger_name in [
170
+ "claude_mpm",
171
+ "path_resolver",
172
+ "file_loader",
173
+ "framework_loader",
174
+ "service",
175
+ "instruction_loader",
176
+ "agent_loader",
177
+ "startup",
178
+ ]:
179
+ module_logger = logging.getLogger(logger_name)
180
+ module_logger.setLevel(logging.CRITICAL + 1)
181
+ module_logger.handlers = []
182
+ module_logger.propagate = False
165
183
 
166
184
  # Process argv
167
185
  if argv is None:
@@ -316,7 +334,7 @@ def deploy_output_style_on_startup():
316
334
  Deploys all styles:
317
335
  - claude-mpm.md (professional mode)
318
336
  - claude-mpm-teacher.md (teaching mode)
319
- - claude-mpm-founders.md (founders mode)
337
+ - claude-mpm-research.md (research mode - for codebase analysis)
320
338
  """
321
339
  try:
322
340
  from ..core.output_style_manager import OutputStyleManager
claude_mpm/cli/utils.py CHANGED
@@ -107,7 +107,7 @@ def get_agent_versions_display() -> Optional[str]:
107
107
  base_version_tuple
108
108
  )
109
109
  output_lines.append(f"\n Base Agent Version: {base_version_str}")
110
- except Exception:
110
+ except Exception: # nosec B110 - intentional: version display is optional
111
111
  pass
112
112
 
113
113
  # Check for agents needing migration
@@ -173,8 +173,12 @@ def setup_logging(args) -> object:
173
173
  if not hasattr(args, "logging") or args.logging is None:
174
174
  args.logging = LogLevel.OFF.value
175
175
 
176
+ # Handle deprecated --verbose flag
177
+ if hasattr(args, "verbose") and args.verbose and args.logging == LogLevel.OFF.value:
178
+ args.logging = LogLevel.INFO.value
179
+
176
180
  # Handle deprecated --debug flag
177
- if hasattr(args, "debug") and args.debug and args.logging == LogLevel.INFO.value:
181
+ if hasattr(args, "debug") and args.debug:
178
182
  args.logging = LogLevel.DEBUG.value
179
183
 
180
184
  # Only setup logging if not OFF
@@ -204,7 +208,7 @@ def ensure_directories() -> None:
204
208
  from ..init import ensure_directories as init_ensure_directories
205
209
 
206
210
  init_ensure_directories()
207
- except Exception:
211
+ except Exception: # nosec B110
208
212
  # Continue even if initialization fails
209
213
  # The individual commands will handle missing directories as needed
210
214
  pass
@@ -0,0 +1,72 @@
1
+ """MPM Commander - Multi-Project Orchestration.
2
+
3
+ This module provides the core infrastructure for managing multiple projects
4
+ with isolated state, work queues, and tool sessions.
5
+
6
+ Key Components:
7
+ - ProjectRegistry: Thread-safe project management
8
+ - Project models: Data structures for state and sessions
9
+ - TmuxOrchestrator: Tmux session and pane management
10
+ - Config loading: .claude-mpm/ directory configuration
11
+ - CommanderDaemon: Main daemon process for orchestration
12
+ - ProjectSession: Per-project lifecycle management
13
+ - InstanceManager: Framework selection and instance lifecycle
14
+ - Frameworks: Claude Code, MPM framework abstractions
15
+
16
+ Example:
17
+ >>> from claude_mpm.commander import ProjectRegistry
18
+ >>> registry = ProjectRegistry()
19
+ >>> project = registry.register("/path/to/project")
20
+ >>> registry.update_state(project.id, ProjectState.WORKING)
21
+ """
22
+
23
+ from claude_mpm.commander.config import DaemonConfig
24
+ from claude_mpm.commander.config_loader import load_project_config
25
+ from claude_mpm.commander.daemon import CommanderDaemon
26
+ from claude_mpm.commander.frameworks import (
27
+ BaseFramework,
28
+ ClaudeCodeFramework,
29
+ InstanceInfo,
30
+ MPMFramework,
31
+ )
32
+ from claude_mpm.commander.instance_manager import (
33
+ FrameworkNotFoundError,
34
+ InstanceAlreadyExistsError,
35
+ InstanceManager,
36
+ InstanceNotFoundError,
37
+ )
38
+ from claude_mpm.commander.models import (
39
+ Project,
40
+ ProjectState,
41
+ ThreadMessage,
42
+ ToolSession,
43
+ )
44
+ from claude_mpm.commander.project_session import ProjectSession, SessionState
45
+ from claude_mpm.commander.registry import ProjectRegistry
46
+ from claude_mpm.commander.tmux_orchestrator import (
47
+ TmuxNotFoundError,
48
+ TmuxOrchestrator,
49
+ )
50
+
51
+ __all__ = [
52
+ "BaseFramework",
53
+ "ClaudeCodeFramework",
54
+ "CommanderDaemon",
55
+ "DaemonConfig",
56
+ "FrameworkNotFoundError",
57
+ "InstanceAlreadyExistsError",
58
+ "InstanceInfo",
59
+ "InstanceManager",
60
+ "InstanceNotFoundError",
61
+ "MPMFramework",
62
+ "Project",
63
+ "ProjectRegistry",
64
+ "ProjectSession",
65
+ "ProjectState",
66
+ "SessionState",
67
+ "ThreadMessage",
68
+ "TmuxNotFoundError",
69
+ "TmuxOrchestrator",
70
+ "ToolSession",
71
+ "load_project_config",
72
+ ]
@@ -0,0 +1,31 @@
1
+ """Runtime adapters for MPM Commander.
2
+
3
+ This package provides adapters for different AI coding tools, allowing
4
+ the TmuxOrchestrator to interface with various runtimes in a uniform way.
5
+
6
+ Two types of adapters:
7
+ - RuntimeAdapter: Synchronous parsing and state detection
8
+ - CommunicationAdapter: Async I/O and state management
9
+ """
10
+
11
+ from .base import Capability, ParsedResponse, RuntimeAdapter
12
+ from .claude_code import ClaudeCodeAdapter
13
+ from .communication import (
14
+ AdapterResponse,
15
+ AdapterState,
16
+ BaseCommunicationAdapter,
17
+ ClaudeCodeCommunicationAdapter,
18
+ )
19
+
20
+ __all__ = [
21
+ # Communication adapters (async I/O)
22
+ "AdapterResponse",
23
+ "AdapterState",
24
+ "BaseCommunicationAdapter",
25
+ # Runtime adapters (parsing)
26
+ "Capability",
27
+ "ClaudeCodeAdapter",
28
+ "ClaudeCodeCommunicationAdapter",
29
+ "ParsedResponse",
30
+ "RuntimeAdapter",
31
+ ]