claude-team-mcp 0.4.0__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.
Files changed (42) hide show
  1. claude_team_mcp/__init__.py +24 -0
  2. claude_team_mcp/__main__.py +8 -0
  3. claude_team_mcp/cli_backends/__init__.py +44 -0
  4. claude_team_mcp/cli_backends/base.py +132 -0
  5. claude_team_mcp/cli_backends/claude.py +110 -0
  6. claude_team_mcp/cli_backends/codex.py +110 -0
  7. claude_team_mcp/colors.py +108 -0
  8. claude_team_mcp/formatting.py +120 -0
  9. claude_team_mcp/idle_detection.py +488 -0
  10. claude_team_mcp/iterm_utils.py +1119 -0
  11. claude_team_mcp/names.py +427 -0
  12. claude_team_mcp/profile.py +364 -0
  13. claude_team_mcp/registry.py +426 -0
  14. claude_team_mcp/schemas/__init__.py +5 -0
  15. claude_team_mcp/schemas/codex.py +267 -0
  16. claude_team_mcp/server.py +390 -0
  17. claude_team_mcp/session_state.py +1058 -0
  18. claude_team_mcp/subprocess_cache.py +119 -0
  19. claude_team_mcp/tools/__init__.py +52 -0
  20. claude_team_mcp/tools/adopt_worker.py +122 -0
  21. claude_team_mcp/tools/annotate_worker.py +57 -0
  22. claude_team_mcp/tools/bd_help.py +42 -0
  23. claude_team_mcp/tools/check_idle_workers.py +98 -0
  24. claude_team_mcp/tools/close_workers.py +194 -0
  25. claude_team_mcp/tools/discover_workers.py +129 -0
  26. claude_team_mcp/tools/examine_worker.py +56 -0
  27. claude_team_mcp/tools/list_workers.py +76 -0
  28. claude_team_mcp/tools/list_worktrees.py +106 -0
  29. claude_team_mcp/tools/message_workers.py +311 -0
  30. claude_team_mcp/tools/read_worker_logs.py +158 -0
  31. claude_team_mcp/tools/spawn_workers.py +634 -0
  32. claude_team_mcp/tools/wait_idle_workers.py +148 -0
  33. claude_team_mcp/utils/__init__.py +17 -0
  34. claude_team_mcp/utils/constants.py +87 -0
  35. claude_team_mcp/utils/errors.py +87 -0
  36. claude_team_mcp/utils/worktree_detection.py +79 -0
  37. claude_team_mcp/worker_prompt.py +350 -0
  38. claude_team_mcp/worktree.py +532 -0
  39. claude_team_mcp-0.4.0.dist-info/METADATA +414 -0
  40. claude_team_mcp-0.4.0.dist-info/RECORD +42 -0
  41. claude_team_mcp-0.4.0.dist-info/WHEEL +4 -0
  42. claude_team_mcp-0.4.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,350 @@
1
+ """Worker pre-prompt generation for coordinated team sessions."""
2
+
3
+ from typing import Literal, Optional
4
+
5
+ # Valid agent types for prompt generation
6
+ AgentType = Literal["claude", "codex"]
7
+
8
+
9
+ def generate_worker_prompt(
10
+ session_id: str,
11
+ name: str,
12
+ *,
13
+ agent_type: AgentType = "claude",
14
+ use_worktree: bool = False,
15
+ bead: Optional[str] = None,
16
+ custom_prompt: Optional[str] = None,
17
+ ) -> str:
18
+ """Generate the pre-prompt text for a worker session.
19
+
20
+ Args:
21
+ session_id: The unique identifier for this worker session
22
+ name: The friendly name assigned to this worker
23
+ agent_type: The type of agent CLI ("claude" or "codex")
24
+ use_worktree: Whether this worker is in an isolated worktree
25
+ bead: Optional beads issue ID (if provided, this is the assignment)
26
+ custom_prompt: Optional additional instructions from the coordinator
27
+
28
+ Returns:
29
+ The formatted pre-prompt string to inject into the worker session
30
+
31
+ Note:
32
+ The iTerm-specific marker for session recovery is emitted separately
33
+ via generate_marker_message() in session_state.py, which is called
34
+ before the worker prompt is sent. This marker is only used for Claude
35
+ workers since Codex doesn't parse JSONL markers.
36
+ """
37
+ if agent_type == "codex":
38
+ return _generate_codex_worker_prompt(
39
+ session_id=session_id,
40
+ name=name,
41
+ use_worktree=use_worktree,
42
+ bead=bead,
43
+ custom_prompt=custom_prompt,
44
+ )
45
+ # Default to Claude prompt for unknown agent types to maintain backward compatibility
46
+ return _generate_claude_worker_prompt(
47
+ session_id=session_id,
48
+ name=name,
49
+ use_worktree=use_worktree,
50
+ bead=bead,
51
+ custom_prompt=custom_prompt,
52
+ )
53
+
54
+
55
+ def _generate_claude_worker_prompt(
56
+ session_id: str,
57
+ name: str,
58
+ use_worktree: bool = False,
59
+ bead: Optional[str] = None,
60
+ custom_prompt: Optional[str] = None,
61
+ ) -> str:
62
+ """Generate the pre-prompt for a Claude Code worker session.
63
+
64
+ Claude Code workers have access to:
65
+ - claude-team MCP markers for session recovery
66
+ - Stop hook idle detection
67
+ - Full MCP tool ecosystem
68
+
69
+ Args:
70
+ session_id: The unique identifier for this worker session
71
+ name: The friendly name assigned to this worker
72
+ use_worktree: Whether this worker is in an isolated worktree
73
+ bead: Optional beads issue ID
74
+ custom_prompt: Optional additional instructions
75
+
76
+ Returns:
77
+ Formatted pre-prompt for Claude worker
78
+ """
79
+ # Build optional sections with dynamic numbering
80
+ next_step = 4
81
+ extra_sections = ""
82
+
83
+ # Beads section (if bead provided)
84
+ if bead:
85
+ beads_section = f"""
86
+ {next_step}. **Beads workflow.** You're working on `{bead}`. Follow this workflow:
87
+ - Mark in progress: `bd --no-db update {bead} --status in_progress`
88
+ - Implement the changes
89
+ - Close issue: `bd --no-db close {bead}`
90
+ - Commit with issue reference: `git add -A && git commit -m "{bead}: <summary>"`
91
+
92
+ Use `bd --no-db` for all beads commands (required in worktrees).
93
+ """
94
+ extra_sections += beads_section
95
+ next_step += 1
96
+
97
+ # Commit section (if worktree but beads section didn't already cover commit)
98
+ if use_worktree and not bead:
99
+ commit_section = f"""
100
+ {next_step}. **Commit when done.** You're in an isolated worktree branch — commit your
101
+ completed work so it can be easily cherry-picked or merged. Use a clear
102
+ commit message summarizing what you did. Don't push; the coordinator
103
+ handles that.
104
+ """
105
+ extra_sections += commit_section
106
+
107
+ # Closing/assignment section - 4 cases based on bead and custom_prompt
108
+ if bead and custom_prompt:
109
+ # Case 2: bead + custom instructions
110
+ closing = f"""=== YOUR ASSIGNMENT ===
111
+
112
+ The coordinator assigned you `{bead}` (use `bd show {bead}` for details) and included
113
+ the following instructions:
114
+
115
+ {custom_prompt}
116
+
117
+ Get to work!"""
118
+ elif bead:
119
+ # Case 1: bead only
120
+ closing = f"""=== YOUR ASSIGNMENT ===
121
+
122
+ Your assignment is `{bead}`. Use `bd show {bead}` for details. Get to work!"""
123
+ elif custom_prompt:
124
+ # Case 3: custom instructions only
125
+ closing = f"""=== YOUR ASSIGNMENT ===
126
+
127
+ The coordinator assigned you the following task:
128
+
129
+ {custom_prompt}
130
+
131
+ Get to work!"""
132
+ else:
133
+ # Case 4: no bead, no instructions - coordinator will message shortly
134
+ closing = "Alright, you're all set. The coordinator will send your first task shortly."
135
+
136
+ return f'''Hey {name}! Welcome to the team.
137
+
138
+ You're part of a coordinated `claude-team` session. Your coordinator has tasks
139
+ for you. Do your best to complete the work you've been assigned autonomously.
140
+ However, if you have questions/comments/concerns for your coordinator, you can
141
+ ask a question in chat and end your turn. `claude-team` will automatically report
142
+ your session as idle to the coordinator so they can respond.
143
+
144
+ === THE DEAL ===
145
+
146
+ 1. **Do the work fully.** Either complete it or explain what's blocking you in
147
+ your response. The coordinator reads your output to understand what happened.
148
+
149
+ 2. **When you're done,** leave a clear summary in your response. Your completion
150
+ wil be detected automatically — just finish your work and the system handles the rest.
151
+
152
+ 3. **If blocked,** explain what you need in your response. The coordinator will
153
+ read your conversation history and address it.
154
+ {extra_sections}
155
+ {closing}
156
+ '''
157
+
158
+
159
+ def _generate_codex_worker_prompt(
160
+ session_id: str,
161
+ name: str,
162
+ use_worktree: bool = False,
163
+ bead: Optional[str] = None,
164
+ custom_prompt: Optional[str] = None,
165
+ ) -> str:
166
+ """Generate the pre-prompt for an OpenAI Codex worker session.
167
+
168
+ Codex workers differ from Claude:
169
+ - No claude-team MCP markers (Codex doesn't parse JSONL markers)
170
+ - No Stop hook idle detection (uses output pattern matching or timeouts)
171
+ - Runs with --full-auto instead of --dangerously-skip-permissions
172
+
173
+ Args:
174
+ session_id: The unique identifier for this worker session
175
+ name: The friendly name assigned to this worker
176
+ use_worktree: Whether this worker is in an isolated worktree
177
+ bead: Optional beads issue ID
178
+ custom_prompt: Optional additional instructions
179
+
180
+ Returns:
181
+ Formatted pre-prompt for Codex worker
182
+ """
183
+ # Build optional sections with dynamic numbering
184
+ next_step = 4
185
+ extra_sections = ""
186
+
187
+ # Beads section (if bead provided) - same workflow as Claude
188
+ if bead:
189
+ beads_section = f"""
190
+ {next_step}. **Beads workflow.** You're working on `{bead}`. Follow this workflow:
191
+ - Mark in progress: `bd --no-db update {bead} --status in_progress`
192
+ - Implement the changes
193
+ - Close issue: `bd --no-db close {bead}`
194
+ - Commit with issue reference: `git add -A && git commit -m "{bead}: <summary>"`
195
+
196
+ Use `bd --no-db` for all beads commands (required in worktrees).
197
+ """
198
+ extra_sections += beads_section
199
+ next_step += 1
200
+
201
+ # Commit section (if worktree but beads section didn't already cover commit)
202
+ if use_worktree and not bead:
203
+ commit_section = f"""
204
+ {next_step}. **Commit when done.** You're in an isolated worktree branch — commit your
205
+ completed work so it can be easily cherry-picked or merged. Use a clear
206
+ commit message summarizing what you did. Don't push; the coordinator
207
+ handles that.
208
+ """
209
+ extra_sections += commit_section
210
+
211
+ # Closing/assignment section - 4 cases based on bead and custom_prompt
212
+ if bead and custom_prompt:
213
+ closing = f"""=== YOUR ASSIGNMENT ===
214
+
215
+ The coordinator assigned you `{bead}` (use `bd show {bead}` for details) and included
216
+ the following instructions:
217
+
218
+ {custom_prompt}
219
+
220
+ Get to work!"""
221
+ elif bead:
222
+ closing = f"""=== YOUR ASSIGNMENT ===
223
+
224
+ Your assignment is `{bead}`. Use `bd show {bead}` for details. Get to work!"""
225
+ elif custom_prompt:
226
+ closing = f"""=== YOUR ASSIGNMENT ===
227
+
228
+ The coordinator assigned you the following task:
229
+
230
+ {custom_prompt}
231
+
232
+ Get to work!"""
233
+ else:
234
+ closing = "Alright, you're all set. The coordinator will send your first task shortly."
235
+
236
+ # Codex prompt differs from Claude in key ways:
237
+ # - No reference to claude-team MCP markers
238
+ # - No "automatically report your session as idle" - Codex doesn't use stop hooks
239
+ # - Simpler coordination model (output-based status checking)
240
+ return f'''Hey {name}! Welcome to the team.
241
+
242
+ You're part of a coordinated multi-agent team. Your coordinator has tasks for you.
243
+ Do your best to complete the work you've been assigned autonomously.
244
+
245
+ If you have questions or concerns, clearly state them at the end of your response
246
+ and wait for further instructions. The coordinator will check your progress periodically.
247
+
248
+ === THE DEAL ===
249
+
250
+ 1. **Do the work fully.** Either complete it or explain what's blocking you.
251
+ The coordinator reads your output to understand what happened.
252
+
253
+ 2. **When you're done,** leave a clear summary of what you accomplished.
254
+ End your response with "COMPLETED" or "BLOCKED: <reason>" so the coordinator
255
+ can easily assess your status.
256
+
257
+ 3. **If blocked,** explain what you need. The coordinator will read your output
258
+ and address it.
259
+ {extra_sections}
260
+ {closing}
261
+ '''
262
+
263
+
264
+ def get_coordinator_guidance(
265
+ worker_summaries: list[dict],
266
+ ) -> str:
267
+ """Get the coordinator guidance text to include in spawn_workers response.
268
+
269
+ Args:
270
+ worker_summaries: List of dicts with keys:
271
+ - name: Worker name
272
+ - agent_type: Agent type ("claude" or "codex")
273
+ - bead: Optional bead ID
274
+ - custom_prompt: Optional custom instructions (truncated for display)
275
+ - awaiting_task: True if worker has no bead and no prompt
276
+
277
+ Returns:
278
+ Formatted coordinator guidance string
279
+ """
280
+ # Check if we have a mixed team
281
+ agent_types = {w.get("agent_type", "claude") for w in worker_summaries}
282
+ is_mixed_team = len(agent_types) > 1
283
+
284
+ # Build per-worker summary lines
285
+ worker_lines = []
286
+ for w in worker_summaries:
287
+ name = w["name"]
288
+ agent_type = w.get("agent_type", "claude")
289
+ bead = w.get("bead")
290
+ custom_prompt = w.get("custom_prompt")
291
+ awaiting = w.get("awaiting_task", False)
292
+
293
+ # Add agent type indicator if mixed team
294
+ type_indicator = f" [{agent_type}]" if is_mixed_team else ""
295
+
296
+ if awaiting:
297
+ worker_lines.append(
298
+ f"- **{name}**{type_indicator}: "
299
+ "AWAITING TASK - send them instructions now"
300
+ )
301
+ elif bead and custom_prompt:
302
+ # Truncate custom prompt for display
303
+ short_prompt = (
304
+ custom_prompt[:50] + "..." if len(custom_prompt) > 50 else custom_prompt
305
+ )
306
+ worker_lines.append(
307
+ f"- **{name}**{type_indicator}: `{bead}` + custom: \"{short_prompt}\""
308
+ )
309
+ elif bead:
310
+ worker_lines.append(
311
+ f"- **{name}**{type_indicator}: `{bead}` "
312
+ "(beads workflow: mark in_progress -> implement -> close -> commit)"
313
+ )
314
+ elif custom_prompt:
315
+ short_prompt = (
316
+ custom_prompt[:50] + "..." if len(custom_prompt) > 50 else custom_prompt
317
+ )
318
+ worker_lines.append(
319
+ f"- **{name}**{type_indicator}: custom task: \"{short_prompt}\""
320
+ )
321
+
322
+ workers_section = "\n".join(worker_lines)
323
+
324
+ # Build mixed team guidance if applicable
325
+ mixed_team_section = ""
326
+ if is_mixed_team:
327
+ mixed_team_section = """
328
+ **Mixed team note:** You have both Claude and Codex workers:
329
+ - **Claude workers**: Idle detection via Stop hooks (automatic)
330
+ - **Codex workers**: Check status by reading their output for "COMPLETED" or "BLOCKED"
331
+ """
332
+
333
+ return f"""=== TEAM DISPATCHED ===
334
+
335
+ {workers_section}
336
+ {mixed_team_section}
337
+ Workers will do the work and explain their output. If blocked, they'll say so.
338
+ You review everything before it's considered done.
339
+
340
+ **Coordination style reminder:** Match your approach to the task. Hands-off for exploratory
341
+ work (check in when asked), autonomous for pipelines (wait for completion, read logs, continue).
342
+
343
+ **WORKTREE LIFECYCLE** — Workers with worktrees commit to ephemeral branches.
344
+ When you close workers:
345
+ 1. Worktree directories are removed, but branches (and commits) are preserved
346
+ 2. Review commits on worker branches before merging
347
+ 3. Merge or cherry-pick to main, then delete the worker branch
348
+
349
+ Branches persist until explicitly deleted with `git branch -d <branch>`.
350
+ """