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.
- claude_team_mcp/__init__.py +24 -0
- claude_team_mcp/__main__.py +8 -0
- claude_team_mcp/cli_backends/__init__.py +44 -0
- claude_team_mcp/cli_backends/base.py +132 -0
- claude_team_mcp/cli_backends/claude.py +110 -0
- claude_team_mcp/cli_backends/codex.py +110 -0
- claude_team_mcp/colors.py +108 -0
- claude_team_mcp/formatting.py +120 -0
- claude_team_mcp/idle_detection.py +488 -0
- claude_team_mcp/iterm_utils.py +1119 -0
- claude_team_mcp/names.py +427 -0
- claude_team_mcp/profile.py +364 -0
- claude_team_mcp/registry.py +426 -0
- claude_team_mcp/schemas/__init__.py +5 -0
- claude_team_mcp/schemas/codex.py +267 -0
- claude_team_mcp/server.py +390 -0
- claude_team_mcp/session_state.py +1058 -0
- claude_team_mcp/subprocess_cache.py +119 -0
- claude_team_mcp/tools/__init__.py +52 -0
- claude_team_mcp/tools/adopt_worker.py +122 -0
- claude_team_mcp/tools/annotate_worker.py +57 -0
- claude_team_mcp/tools/bd_help.py +42 -0
- claude_team_mcp/tools/check_idle_workers.py +98 -0
- claude_team_mcp/tools/close_workers.py +194 -0
- claude_team_mcp/tools/discover_workers.py +129 -0
- claude_team_mcp/tools/examine_worker.py +56 -0
- claude_team_mcp/tools/list_workers.py +76 -0
- claude_team_mcp/tools/list_worktrees.py +106 -0
- claude_team_mcp/tools/message_workers.py +311 -0
- claude_team_mcp/tools/read_worker_logs.py +158 -0
- claude_team_mcp/tools/spawn_workers.py +634 -0
- claude_team_mcp/tools/wait_idle_workers.py +148 -0
- claude_team_mcp/utils/__init__.py +17 -0
- claude_team_mcp/utils/constants.py +87 -0
- claude_team_mcp/utils/errors.py +87 -0
- claude_team_mcp/utils/worktree_detection.py +79 -0
- claude_team_mcp/worker_prompt.py +350 -0
- claude_team_mcp/worktree.py +532 -0
- claude_team_mcp-0.4.0.dist-info/METADATA +414 -0
- claude_team_mcp-0.4.0.dist-info/RECORD +42 -0
- claude_team_mcp-0.4.0.dist-info/WHEEL +4 -0
- 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
|
+
"""
|