claude-team-mcp 0.5.0__py3-none-any.whl → 0.6.1__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.
@@ -22,7 +22,7 @@ class CodexCLI(AgentCLI):
22
22
 
23
23
  Codex CLI characteristics:
24
24
  - Uses `codex` command
25
- - Has --full-auto flag for non-interactive mode
25
+ - Has --dangerously-bypass-approvals-and-sandbox flag for non-interactive mode
26
26
  - No known Stop hook equivalent (may need JSONL streaming or timeouts)
27
27
  """
28
28
 
@@ -50,7 +50,7 @@ class CodexCLI(AgentCLI):
50
50
  Build Codex CLI arguments for interactive mode.
51
51
 
52
52
  Args:
53
- dangerously_skip_permissions: Maps to --full-auto for Codex
53
+ dangerously_skip_permissions: Maps to --dangerously-bypass-approvals-and-sandbox for Codex
54
54
  settings_file: Ignored - Codex doesn't support settings injection
55
55
 
56
56
  Returns:
@@ -58,8 +58,7 @@ class CodexCLI(AgentCLI):
58
58
  """
59
59
  args: list[str] = []
60
60
 
61
- # Codex uses --dangerously-bypass-approvals-and-sandbox for autonomous operation
62
- # (--full-auto doesn't work through happy wrapper)
61
+ # Codex uses --dangerously-bypass-approvals-and-sandbox for autonomous operation.
63
62
  if dangerously_skip_permissions:
64
63
  args.append("--dangerously-bypass-approvals-and-sandbox")
65
64
 
@@ -0,0 +1,132 @@
1
+ """
2
+ Issue tracker abstraction module.
3
+
4
+ Defines a protocol and backend implementations for issue tracker commands.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import os
11
+ from dataclasses import dataclass, field
12
+ from typing import Protocol, runtime_checkable
13
+
14
+ logger = logging.getLogger("claude-team-mcp")
15
+
16
+
17
+ @runtime_checkable
18
+ class IssueTrackerBackend(Protocol):
19
+ """
20
+ Protocol defining the issue tracker backend interface.
21
+
22
+ Backends provide a name, CLI command, marker directory, and command templates.
23
+ """
24
+
25
+ name: str
26
+ cli: str
27
+ marker_dir: str
28
+ commands: dict[str, str]
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class BeadsBackend:
33
+ """Beads issue tracker backend."""
34
+
35
+ name: str = "beads"
36
+ cli: str = "bd"
37
+ marker_dir: str = ".beads"
38
+ commands: dict[str, str] = field(
39
+ default_factory=lambda: {
40
+ "list": "bd --no-db list",
41
+ "ready": "bd --no-db ready",
42
+ "show": "bd --no-db show {issue_id}",
43
+ "update": "bd --no-db update {issue_id} --status {status}",
44
+ "close": "bd --no-db close {issue_id}",
45
+ "create": (
46
+ "bd --no-db create --title \"{title}\" --type {type} "
47
+ "--priority {priority} --description \"{description}\""
48
+ ),
49
+ "comment": "bd --no-db comment {issue_id} \"{comment}\"",
50
+ "dep_add": "bd --no-db dep add {issue_id} {dependency_id}",
51
+ "dep_tree": "bd --no-db dep tree {issue_id}",
52
+ }
53
+ )
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class PebblesBackend:
58
+ """Pebbles issue tracker backend."""
59
+
60
+ name: str = "pebbles"
61
+ cli: str = "pb"
62
+ marker_dir: str = ".pebbles"
63
+ commands: dict[str, str] = field(
64
+ default_factory=lambda: {
65
+ "list": "pb list",
66
+ "ready": "pb ready",
67
+ "show": "pb show {issue_id}",
68
+ "update": "pb update {issue_id} -status {status}",
69
+ "close": "pb close {issue_id}",
70
+ "create": (
71
+ "pb create -title \"{title}\" -type {type} -priority {priority} "
72
+ "-description \"{description}\""
73
+ ),
74
+ "comment": "pb comment {issue_id} -body \"{comment}\"",
75
+ "dep_add": "pb dep add {issue_id} {dependency_id}",
76
+ "dep_tree": "pb dep tree {issue_id}",
77
+ }
78
+ )
79
+
80
+
81
+ BEADS_BACKEND = BeadsBackend()
82
+ PEBBLES_BACKEND = PebblesBackend()
83
+ BACKEND_REGISTRY: dict[str, IssueTrackerBackend] = {
84
+ BEADS_BACKEND.name: BEADS_BACKEND,
85
+ PEBBLES_BACKEND.name: PEBBLES_BACKEND,
86
+ }
87
+
88
+
89
+ def detect_issue_tracker(project_path: str) -> IssueTrackerBackend | None:
90
+ """
91
+ Detect the issue tracker backend for the given project path.
92
+
93
+ Args:
94
+ project_path: Absolute or relative path to the project root.
95
+
96
+ Returns:
97
+ The detected IssueTrackerBackend, or None if no markers are present.
98
+ """
99
+ beads_marker = os.path.join(project_path, BEADS_BACKEND.marker_dir)
100
+ pebbles_marker = os.path.join(project_path, PEBBLES_BACKEND.marker_dir)
101
+
102
+ # Check marker directories in the project root.
103
+ beads_present = os.path.isdir(beads_marker)
104
+ pebbles_present = os.path.isdir(pebbles_marker)
105
+
106
+ # Resolve the deterministic backend when both markers exist.
107
+ if beads_present and pebbles_present:
108
+ logger.warning(
109
+ "Both .beads and .pebbles found in %s; defaulting to pebbles",
110
+ project_path,
111
+ )
112
+ return PEBBLES_BACKEND
113
+
114
+ # Return the matching backend if only one marker exists.
115
+ if pebbles_present:
116
+ return PEBBLES_BACKEND
117
+
118
+ if beads_present:
119
+ return BEADS_BACKEND
120
+
121
+ return None
122
+
123
+
124
+ __all__ = [
125
+ "IssueTrackerBackend",
126
+ "BeadsBackend",
127
+ "PebblesBackend",
128
+ "BEADS_BACKEND",
129
+ "PEBBLES_BACKEND",
130
+ "BACKEND_REGISTRY",
131
+ "detect_issue_tracker",
132
+ ]
@@ -8,7 +8,7 @@ from mcp.server.fastmcp import FastMCP
8
8
 
9
9
  from . import adopt_worker
10
10
  from . import annotate_worker
11
- from . import bd_help
11
+ from . import issue_tracker_help
12
12
  from . import check_idle_workers
13
13
  from . import close_workers
14
14
  from . import discover_workers
@@ -31,7 +31,7 @@ def register_all_tools(mcp: FastMCP, ensure_connection) -> None:
31
31
  """
32
32
  # Tools that don't need ensure_connection
33
33
  annotate_worker.register_tools(mcp)
34
- bd_help.register_tools(mcp)
34
+ issue_tracker_help.register_tools(mcp)
35
35
  check_idle_workers.register_tools(mcp)
36
36
  close_workers.register_tools(mcp)
37
37
  examine_worker.register_tools(mcp)
@@ -0,0 +1,50 @@
1
+ """
2
+ Issue tracker help tool.
3
+
4
+ Provides issue_tracker_help for quick reference on issue tracking commands.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ from mcp.server.fastmcp import FastMCP
10
+
11
+ from ..issue_tracker import BACKEND_REGISTRY, detect_issue_tracker
12
+ from ..utils import build_issue_tracker_help_text, build_issue_tracker_quick_commands
13
+
14
+
15
+ def register_tools(mcp: FastMCP) -> None:
16
+ """Register issue_tracker_help tool on the MCP server."""
17
+
18
+ @mcp.tool()
19
+ async def issue_tracker_help() -> dict:
20
+ """
21
+ Get a quick reference guide for using issue tracking.
22
+
23
+ Returns condensed documentation on tracker commands, workflow patterns,
24
+ and best practices for worker sessions. Call this tool when you need
25
+ guidance on tracking progress, adding comments, or managing issues.
26
+
27
+ Returns:
28
+ Dict with help text and key command examples
29
+ """
30
+ project_path = str(Path.cwd())
31
+ backend = detect_issue_tracker(project_path)
32
+ help_text = build_issue_tracker_help_text(backend)
33
+ quick_commands = build_issue_tracker_quick_commands(backend)
34
+
35
+ response = {
36
+ "help": help_text,
37
+ "quick_commands": quick_commands,
38
+ "worker_tip": (
39
+ "As a worker, add comments to track progress rather than closing issues. "
40
+ "The coordinator will close issues after reviewing your work."
41
+ ),
42
+ }
43
+
44
+ if backend is None:
45
+ response["supported_trackers"] = sorted(BACKEND_REGISTRY.keys())
46
+ else:
47
+ response["tracker"] = backend.name
48
+ response["cli"] = backend.cli
49
+
50
+ return response
@@ -19,9 +19,10 @@ from ..idle_detection import (
19
19
  wait_for_any_idle as wait_for_any_idle_impl,
20
20
  SessionInfo,
21
21
  )
22
+ from ..issue_tracker import detect_issue_tracker
22
23
  from ..iterm_utils import send_prompt_for_agent
23
24
  from ..registry import SessionStatus
24
- from ..utils import error_response, HINTS, WORKER_MESSAGE_HINT
25
+ from ..utils import build_worker_message_hint, error_response, HINTS
25
26
 
26
27
  logger = logging.getLogger("claude-team-mcp")
27
28
 
@@ -187,8 +188,14 @@ def register_tools(mcp: FastMCP) -> None:
187
188
  # Update status to busy
188
189
  registry.update_status(sid, SessionStatus.BUSY)
189
190
 
190
- # Append hint about bd_help tool to help workers understand beads
191
- message_with_hint = message + WORKER_MESSAGE_HINT
191
+ # Append tracker-specific hint so workers know how to log progress.
192
+ tracker_path = (
193
+ str(session.main_repo_path)
194
+ if session.main_repo_path is not None
195
+ else session.project_path
196
+ )
197
+ tracker_backend = detect_issue_tracker(tracker_path)
198
+ message_with_hint = message + build_worker_message_hint(tracker_backend)
192
199
 
193
200
  # Send the message using agent-specific input handling.
194
201
  # Codex needs a longer pre-Enter delay than Claude.
@@ -23,6 +23,7 @@ from ..iterm_utils import (
23
23
  MAX_PANES_PER_TAB,
24
24
  create_multi_pane_layout,
25
25
  find_available_window,
26
+ get_window_for_session,
26
27
  send_prompt,
27
28
  send_prompt_for_agent,
28
29
  split_pane,
@@ -32,7 +33,7 @@ from ..iterm_utils import (
32
33
  from ..names import pick_names_for_count
33
34
  from ..profile import apply_appearance_colors
34
35
  from ..registry import SessionStatus
35
- from ..utils import HINTS, error_response, get_worktree_beads_dir
36
+ from ..utils import HINTS, error_response, get_worktree_tracker_dir
36
37
  from ..worker_prompt import generate_worker_prompt, get_coordinator_guidance
37
38
  from ..worktree import WorktreeError, create_local_worktree
38
39
 
@@ -324,76 +325,140 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
324
325
  if layout == "auto":
325
326
  # Try to find an existing window where the ENTIRE batch fits.
326
327
  # This keeps spawn batches together rather than spreading across windows.
327
- managed_iterm_ids: set[str] = {
328
- s.iterm_session.session_id
329
- for s in registry.list_all()
330
- if s.iterm_session is not None
331
- }
332
-
333
- # Find a window with enough space for ALL workers
334
- result = await find_available_window(
335
- app,
336
- max_panes=MAX_PANES_PER_TAB,
337
- managed_session_ids=managed_iterm_ids,
338
- )
339
-
340
328
  target_tab = None
341
329
  initial_pane_count = 0
342
330
  first_session = None # Session to split from
343
331
 
344
- if result:
345
- window, tab, existing_session = result
346
- initial_pane_count = len(tab.sessions)
347
- available_slots = MAX_PANES_PER_TAB - initial_pane_count
348
-
349
- if worker_count <= available_slots:
350
- # Entire batch fits in this window
351
- target_tab = tab
352
- first_session = existing_session
353
- logger.debug(
354
- f"Batch of {worker_count} fits in existing window "
355
- f"({initial_pane_count} panes, {available_slots} slots)"
332
+ # Prefer the coordinator's window when running inside iTerm2.
333
+ # ITERM_SESSION_ID format is "wXtYpZ:UUID" - extract just the UUID.
334
+ iterm_session_env = os.environ.get("ITERM_SESSION_ID")
335
+ coordinator_session_id = None
336
+ if iterm_session_env and ":" in iterm_session_env:
337
+ coordinator_session_id = iterm_session_env.split(":", 1)[1]
338
+ if coordinator_session_id:
339
+ coordinator_session = None
340
+ coordinator_tab = None
341
+
342
+ for window in app.terminal_windows:
343
+ for tab in window.tabs:
344
+ for session in tab.sessions:
345
+ if session.session_id == coordinator_session_id:
346
+ coordinator_session = session
347
+ coordinator_tab = tab
348
+ break
349
+ if coordinator_session:
350
+ break
351
+ if coordinator_session:
352
+ break
353
+
354
+ if coordinator_session and coordinator_tab:
355
+ coordinator_window = await get_window_for_session(
356
+ app, coordinator_session
356
357
  )
358
+ if coordinator_window is not None:
359
+ initial_pane_count = len(coordinator_tab.sessions)
360
+ available_slots = MAX_PANES_PER_TAB - initial_pane_count
361
+ if worker_count <= available_slots:
362
+ target_tab = coordinator_tab
363
+ first_session = coordinator_session
364
+ logger.debug(
365
+ "Using coordinator window "
366
+ f"({initial_pane_count} panes, {available_slots} slots)"
367
+ )
368
+
369
+ if target_tab is None:
370
+ managed_iterm_ids: set[str] = {
371
+ s.iterm_session.session_id
372
+ for s in registry.list_all()
373
+ if s.iterm_session is not None
374
+ }
375
+
376
+ # Find a window with enough space for ALL workers
377
+ result = await find_available_window(
378
+ app,
379
+ max_panes=MAX_PANES_PER_TAB,
380
+ managed_session_ids=managed_iterm_ids,
381
+ )
382
+
383
+ if result:
384
+ window, tab, existing_session = result
385
+ initial_pane_count = len(tab.sessions)
386
+ available_slots = MAX_PANES_PER_TAB - initial_pane_count
387
+
388
+ if worker_count <= available_slots:
389
+ # Entire batch fits in this window
390
+ target_tab = tab
391
+ first_session = existing_session
392
+ logger.debug(
393
+ f"Batch of {worker_count} fits in existing window "
394
+ f"({initial_pane_count} panes, {available_slots} slots)"
395
+ )
357
396
 
358
397
  if target_tab:
359
398
  # Reuse existing window - track pane count locally (iTerm objects stale)
360
399
  local_pane_count = initial_pane_count
361
- # Track created sessions for quad splitting
400
+ final_pane_count = initial_pane_count + worker_count
401
+ # Track created sessions for splitting
362
402
  created_sessions: list = []
363
403
 
364
404
  for i in range(worker_count):
365
- # Determine split direction based on local_pane_count
366
- # Incremental quad: TL→TR(vsplit)→BL(hsplit)→BR(hsplit)
367
- if local_pane_count == 1:
368
- # First split: vertical (left/right)
369
- new_session = await split_pane(
370
- first_session,
371
- vertical=True,
372
- before=False,
373
- profile=None,
374
- profile_customizations=profile_customizations[i],
375
- )
376
- elif local_pane_count == 2:
377
- # Second split: horizontal from left pane (creates bottom-left)
378
- # Use first_session (the original TL pane)
379
- new_session = await split_pane(
380
- first_session,
381
- vertical=False,
382
- before=False,
383
- profile=None,
384
- profile_customizations=profile_customizations[i],
385
- )
386
- else: # local_pane_count == 3
387
- # Third split: horizontal from right pane (creates bottom-right)
388
- # The TR pane is the first one we created
389
- tr_session = created_sessions[0] if created_sessions else first_session
390
- new_session = await split_pane(
391
- tr_session,
392
- vertical=False,
393
- before=False,
394
- profile=None,
395
- profile_customizations=profile_customizations[i],
396
- )
405
+ # Choose layout strategy based on final pane count:
406
+ # - 3 panes: coordinator full left, workers stacked right
407
+ # - 4 panes: quad (TL→TR→BL→BR)
408
+ if final_pane_count == 3:
409
+ # Layout: coordinator | worker1
410
+ # |--------
411
+ # | worker2
412
+ if local_pane_count == 1:
413
+ # First split: vertical from coordinator
414
+ new_session = await split_pane(
415
+ first_session,
416
+ vertical=True,
417
+ before=False,
418
+ profile=None,
419
+ profile_customizations=profile_customizations[i],
420
+ )
421
+ else:
422
+ # Second split: horizontal from first worker (stack on right)
423
+ new_session = await split_pane(
424
+ created_sessions[0],
425
+ vertical=False,
426
+ before=False,
427
+ profile=None,
428
+ profile_customizations=profile_customizations[i],
429
+ )
430
+ else:
431
+ # Quad pattern: TL→TR(vsplit)→BL(hsplit)→BR(hsplit)
432
+ if local_pane_count == 1:
433
+ # First split: vertical (left/right)
434
+ new_session = await split_pane(
435
+ first_session,
436
+ vertical=True,
437
+ before=False,
438
+ profile=None,
439
+ profile_customizations=profile_customizations[i],
440
+ )
441
+ elif local_pane_count == 2:
442
+ # Second split: horizontal from left pane (bottom-left)
443
+ new_session = await split_pane(
444
+ first_session,
445
+ vertical=False,
446
+ before=False,
447
+ profile=None,
448
+ profile_customizations=profile_customizations[i],
449
+ )
450
+ else: # local_pane_count == 3
451
+ # Third split: horizontal from right pane (bottom-right)
452
+ tr_session = (
453
+ created_sessions[0] if created_sessions else first_session
454
+ )
455
+ new_session = await split_pane(
456
+ tr_session,
457
+ vertical=False,
458
+ before=False,
459
+ profile=None,
460
+ profile_customizations=profile_customizations[i],
461
+ )
397
462
 
398
463
  pane_sessions.append(new_session)
399
464
  created_sessions.append(new_session)
@@ -476,9 +541,13 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
476
541
  marker_id = session_ids[index]
477
542
  agent_type = agent_types[index]
478
543
 
479
- # Check for worktree and set BEADS_DIR if needed
480
- beads_dir = get_worktree_beads_dir(project_path)
481
- env = {"BEADS_DIR": beads_dir} if beads_dir else None
544
+ # Check for worktree and set tracker env var if needed.
545
+ tracker_info = get_worktree_tracker_dir(project_path)
546
+ if tracker_info:
547
+ env_var, tracker_dir = tracker_info
548
+ env = {env_var: tracker_dir}
549
+ else:
550
+ env = None
482
551
 
483
552
  if agent_type == "codex":
484
553
  # Start Codex in interactive mode using start_agent_in_session
@@ -560,12 +629,18 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
560
629
  if not bead and not custom_prompt:
561
630
  workers_awaiting_task.append(managed.name)
562
631
 
632
+ tracker_path = (
633
+ str(managed.main_repo_path)
634
+ if managed.main_repo_path is not None
635
+ else managed.project_path
636
+ )
563
637
  worker_prompt = generate_worker_prompt(
564
638
  managed.session_id,
565
639
  resolved_names[i],
566
640
  agent_type=managed.agent_type,
567
641
  use_worktree=use_worktree,
568
642
  bead=bead,
643
+ project_path=tracker_path,
569
644
  custom_prompt=custom_prompt,
570
645
  )
571
646
 
@@ -2,16 +2,24 @@
2
2
  Shared utilities for Claude Team MCP tools.
3
3
  """
4
4
 
5
- from .constants import BEADS_HELP_TEXT, CONVERSATION_PAGE_SIZE, WORKER_MESSAGE_HINT
5
+ from .constants import (
6
+ CONVERSATION_PAGE_SIZE,
7
+ ISSUE_TRACKER_HELP_TOOL,
8
+ build_issue_tracker_help_text,
9
+ build_issue_tracker_quick_commands,
10
+ build_worker_message_hint,
11
+ )
6
12
  from .errors import error_response, HINTS, get_session_or_error
7
- from .worktree_detection import get_worktree_beads_dir
13
+ from .worktree_detection import get_worktree_tracker_dir
8
14
 
9
15
  __all__ = [
10
- "BEADS_HELP_TEXT",
11
16
  "CONVERSATION_PAGE_SIZE",
12
- "WORKER_MESSAGE_HINT",
17
+ "ISSUE_TRACKER_HELP_TOOL",
18
+ "build_issue_tracker_help_text",
19
+ "build_issue_tracker_quick_commands",
20
+ "build_worker_message_hint",
13
21
  "error_response",
14
22
  "HINTS",
15
23
  "get_session_or_error",
16
- "get_worktree_beads_dir",
24
+ "get_worktree_tracker_dir",
17
25
  ]
@@ -4,6 +4,8 @@ Shared constants for Claude Team MCP tools.
4
4
 
5
5
  from pathlib import Path
6
6
 
7
+ from ..issue_tracker import BACKEND_REGISTRY, IssueTrackerBackend
8
+
7
9
  # Default page size for conversation history pagination
8
10
  CONVERSATION_PAGE_SIZE = 5
9
11
 
@@ -11,23 +13,109 @@ CONVERSATION_PAGE_SIZE = 5
11
13
  # Codex streams JSONL to stdout; we pipe it through tee to this directory
12
14
  CODEX_JSONL_DIR = Path.home() / ".claude-team" / "codex"
13
15
 
14
- # Hint appended to messages sent to workers
15
- WORKER_MESSAGE_HINT = "\n\n---\n(Note: Use the `bd_help` tool for guidance on using beads to track progress and add comments.)"
16
-
17
- # Condensed beads help text for workers
18
- BEADS_HELP_TEXT = """# Beads Quick Reference
19
-
20
- Beads is a lightweight issue tracker. Use it to track progress and communicate with the coordinator.
16
+ # Tool name used for issue tracker help
17
+ ISSUE_TRACKER_HELP_TOOL = "issue_tracker_help"
18
+
19
+
20
+ def _format_tracker_command(
21
+ backend: IssueTrackerBackend,
22
+ command: str,
23
+ **kwargs: str,
24
+ ) -> str | None:
25
+ """Format a tracker command template with the provided arguments."""
26
+ template = backend.commands.get(command)
27
+ if not template:
28
+ return None
29
+ return template.format(**kwargs)
30
+
31
+
32
+ def _supported_trackers_summary() -> str:
33
+ """Return a comma-separated summary of known issue trackers."""
34
+ return ", ".join(sorted(BACKEND_REGISTRY.keys()))
35
+
36
+
37
+ def build_issue_tracker_help_text(backend: IssueTrackerBackend | None) -> str:
38
+ """Build issue tracker help text for the detected backend."""
39
+ if backend is None:
40
+ supported = _supported_trackers_summary()
41
+ return (
42
+ "# Issue Tracker Quick Reference\n\n"
43
+ "No issue tracker detected for this project. "
44
+ f"Supported trackers: {supported}.\n"
45
+ )
46
+
47
+ # Prepare command examples from the backend templates.
48
+ list_cmd = _format_tracker_command(backend, "list") or ""
49
+ ready_cmd = _format_tracker_command(backend, "ready") or ""
50
+ show_cmd = _format_tracker_command(backend, "show", issue_id="<issue-id>") or ""
51
+ update_cmd = (
52
+ _format_tracker_command(
53
+ backend,
54
+ "update",
55
+ issue_id="<issue-id>",
56
+ status="in_progress",
57
+ )
58
+ or ""
59
+ )
60
+ # Worker-focused examples reuse the comment command template.
61
+ comment_cmd = (
62
+ _format_tracker_command(
63
+ backend,
64
+ "comment",
65
+ issue_id="<issue-id>",
66
+ comment="progress message",
67
+ )
68
+ or ""
69
+ )
70
+ comment_progress_cmd = (
71
+ _format_tracker_command(
72
+ backend,
73
+ "comment",
74
+ issue_id="<issue-id>",
75
+ comment="Completed the API endpoint, now working on tests",
76
+ )
77
+ or ""
78
+ )
79
+ comment_final_cmd = (
80
+ _format_tracker_command(
81
+ backend,
82
+ "comment",
83
+ issue_id="<issue-id>",
84
+ comment=(
85
+ "COMPLETE: Implemented feature X. Changes in src/foo.py and "
86
+ "tests/test_foo.py. Ready for review."
87
+ ),
88
+ )
89
+ or ""
90
+ )
91
+ # Closing and creation examples round out the workflow guidance.
92
+ close_cmd = _format_tracker_command(backend, "close", issue_id="<issue-id>") or ""
93
+ create_cmd = (
94
+ _format_tracker_command(
95
+ backend,
96
+ "create",
97
+ title="Bug: X doesn't work",
98
+ type="bug",
99
+ priority="P1",
100
+ description="Details...",
101
+ )
102
+ or ""
103
+ )
104
+
105
+ # Compose the full help text with backend-specific examples.
106
+ return f"""# Issue Tracker Quick Reference
107
+
108
+ Your project uses the `{backend.name}` issue tracker. Use it to track progress and communicate with the coordinator.
21
109
 
22
110
  ## Essential Commands
23
111
 
24
112
  ```bash
25
- bd list # List all issues
26
- bd ready # Show unblocked work
27
- bd show <issue-id> # Show issue details
28
- bd update <id> --status in_progress # Mark as in-progress
29
- bd comment <id> "message" # Add progress note (IMPORTANT!)
30
- bd close <id> # Close when complete
113
+ {list_cmd}
114
+ {ready_cmd}
115
+ {show_cmd}
116
+ {update_cmd}
117
+ {comment_cmd}
118
+ {close_cmd}
31
119
  ```
32
120
 
33
121
  ## Status Values
@@ -50,38 +138,72 @@ bd close <id> # Close when complete
50
138
 
51
139
  ## As a Worker
52
140
 
53
- **IMPORTANT**: You should NOT close beads unless explicitly told to. Instead:
54
-
55
141
  1. Mark your issue as in-progress when starting:
56
142
  ```bash
57
- bd update <issue-id> --status in_progress
143
+ {update_cmd}
58
144
  ```
59
145
 
60
146
  2. Add comments to document your progress:
61
147
  ```bash
62
- bd comment <issue-id> "Completed the API endpoint, now working on tests"
63
- bd comment <issue-id> "Found edge case - handling null values in response"
148
+ {comment_progress_cmd}
64
149
  ```
65
150
 
66
151
  3. When finished, add a final summary comment:
67
152
  ```bash
68
- bd comment <issue-id> "COMPLETE: Implemented feature X. Changes in src/foo.py and tests/test_foo.py. Ready for review."
153
+ {comment_final_cmd}
69
154
  ```
70
155
 
71
- 4. The coordinator will review and close the bead.
156
+ 4. The coordinator will review and close the issue.
72
157
 
73
158
  ## Creating New Issues (if needed)
74
159
 
75
160
  ```bash
76
- bd create --title "Bug: X doesn't work" --type bug --priority P1 --description "Details..."
161
+ {create_cmd}
77
162
  ```
163
+ """
78
164
 
79
- ## Searching
80
165
 
81
- ```bash
82
- bd search "keyword" # Search by text
83
- bd list --status open # Filter by status
84
- bd list --type bug # Filter by type
85
- bd blocked # Show blocked issues
86
- ```
87
- """
166
+ def build_issue_tracker_quick_commands(
167
+ backend: IssueTrackerBackend | None,
168
+ ) -> dict[str, str]:
169
+ """Return quick command examples for the detected backend."""
170
+ if backend is None:
171
+ return {}
172
+
173
+ # Map common actions to backend templates for quick reference.
174
+ commands = {
175
+ "list_issues": _format_tracker_command(backend, "list"),
176
+ "show_ready": _format_tracker_command(backend, "ready"),
177
+ "show_issue": _format_tracker_command(backend, "show", issue_id="<issue-id>"),
178
+ "start_work": _format_tracker_command(
179
+ backend,
180
+ "update",
181
+ issue_id="<issue-id>",
182
+ status="in_progress",
183
+ ),
184
+ "add_comment": _format_tracker_command(
185
+ backend,
186
+ "comment",
187
+ issue_id="<issue-id>",
188
+ comment="progress message",
189
+ ),
190
+ "close_issue": _format_tracker_command(backend, "close", issue_id="<issue-id>"),
191
+ }
192
+ return {key: value for key, value in commands.items() if value}
193
+
194
+
195
+ def build_worker_message_hint(backend: IssueTrackerBackend | None) -> str:
196
+ """Return the issue tracker hint appended to worker messages."""
197
+ if backend is None:
198
+ supported = _supported_trackers_summary()
199
+ return (
200
+ "\n\n---\n"
201
+ f"(Note: Use the `{ISSUE_TRACKER_HELP_TOOL}` tool for guidance on the "
202
+ f"configured issue tracker. Supported trackers: {supported}.)"
203
+ )
204
+
205
+ return (
206
+ "\n\n---\n"
207
+ f"(Note: Use the `{ISSUE_TRACKER_HELP_TOOL}` tool for guidance on "
208
+ f"{backend.name} commands (CLI: `{backend.cli}`).)"
209
+ )
@@ -2,19 +2,25 @@
2
2
  Git worktree detection utilities.
3
3
 
4
4
  Detects if a project path is a git worktree and locates the main repo's
5
- beads directory for proper issue tracking.
5
+ issue tracker marker directory for proper issue tracking.
6
6
  """
7
7
 
8
8
  import logging
9
9
  import os
10
10
  import subprocess
11
11
 
12
+ from claude_team_mcp.issue_tracker import (
13
+ BEADS_BACKEND,
14
+ PEBBLES_BACKEND,
15
+ detect_issue_tracker,
16
+ )
17
+
12
18
  logger = logging.getLogger("claude-team-mcp")
13
19
 
14
20
 
15
- def get_worktree_beads_dir(project_path: str) -> str | None:
21
+ def get_worktree_tracker_dir(project_path: str) -> tuple[str, str] | None:
16
22
  """
17
- Detect if project_path is a git worktree and return the main repo's .beads dir.
23
+ Detect if project_path is a git worktree and return tracker env var + dir.
18
24
 
19
25
  Git worktrees have .git as a file (not a directory) pointing to the main repo.
20
26
  The `git rev-parse --git-common-dir` command returns the path to the shared
@@ -24,9 +30,9 @@ def get_worktree_beads_dir(project_path: str) -> str | None:
24
30
  project_path: Absolute path to the project directory
25
31
 
26
32
  Returns:
27
- Path to the main repo's .beads directory if:
33
+ (env_var, tracker_dir) if:
28
34
  - project_path is a git worktree
29
- - The main repo has a .beads directory
35
+ - The main repo has a tracker marker (.beads or .pebbles)
30
36
  Otherwise returns None.
31
37
  """
32
38
  try:
@@ -45,7 +51,7 @@ def get_worktree_beads_dir(project_path: str) -> str | None:
45
51
 
46
52
  git_common_dir = result.stdout.strip()
47
53
 
48
- # If the result is just ".git", this is the main repo (not a worktree)
54
+ # If the result is just ".git", this is the main repo (not a worktree).
49
55
  if git_common_dir == ".git":
50
56
  return None
51
57
 
@@ -57,19 +63,35 @@ def get_worktree_beads_dir(project_path: str) -> str | None:
57
63
 
58
64
  git_common_dir = os.path.normpath(git_common_dir)
59
65
 
60
- # Main repo is the parent directory of .git
66
+ # Main repo is the parent directory of .git.
61
67
  main_repo = os.path.dirname(git_common_dir)
62
68
 
63
- # Check if the main repo has a .beads directory
64
- beads_dir = os.path.join(main_repo, ".beads")
65
- if os.path.isdir(beads_dir):
66
- logger.info(
67
- f"Detected git worktree. Setting BEADS_DIR={beads_dir} "
68
- f"for project {project_path}"
69
+ # Identify which tracker is present in the main repo.
70
+ tracker_backend = detect_issue_tracker(main_repo)
71
+ if tracker_backend is None:
72
+ return None
73
+
74
+ # Map the detected tracker to its env var and marker directory.
75
+ if tracker_backend is BEADS_BACKEND:
76
+ env_var = "BEADS_DIR"
77
+ elif tracker_backend is PEBBLES_BACKEND:
78
+ env_var = "PEBBLES_DIR"
79
+ else:
80
+ logger.warning(
81
+ "Unknown issue tracker backend %s for %s",
82
+ tracker_backend.name,
83
+ main_repo,
69
84
  )
70
- return beads_dir
85
+ return None
71
86
 
72
- return None
87
+ tracker_dir = os.path.join(main_repo, tracker_backend.marker_dir)
88
+ logger.info(
89
+ "Detected git worktree. Setting %s=%s for project %s",
90
+ env_var,
91
+ tracker_dir,
92
+ project_path,
93
+ )
94
+ return env_var, tracker_dir
73
95
 
74
96
  except subprocess.TimeoutExpired:
75
97
  logger.warning(f"Timeout checking git worktree status for {project_path}")
@@ -2,10 +2,84 @@
2
2
 
3
3
  from typing import Literal, Optional
4
4
 
5
+ from .issue_tracker import BACKEND_REGISTRY, IssueTrackerBackend, detect_issue_tracker
6
+ from .utils.constants import ISSUE_TRACKER_HELP_TOOL
7
+
5
8
  # Valid agent types for prompt generation
6
9
  AgentType = Literal["claude", "codex"]
7
10
 
8
11
 
12
+ def _resolve_issue_tracker_backend(
13
+ project_path: Optional[str],
14
+ ) -> IssueTrackerBackend | None:
15
+ """Detect the issue tracker backend for a project path."""
16
+ if not project_path:
17
+ return None
18
+ return detect_issue_tracker(project_path)
19
+
20
+
21
+ def _format_tracker_command(
22
+ backend: IssueTrackerBackend,
23
+ command: str,
24
+ **kwargs: str,
25
+ ) -> str:
26
+ """Format a tracker command template with the provided arguments."""
27
+ template = backend.commands.get(command)
28
+ if not template:
29
+ return ""
30
+ return template.format(**kwargs)
31
+
32
+
33
+ def _supported_tracker_list() -> str:
34
+ """Return a readable list of supported issue trackers."""
35
+ return ", ".join(sorted(BACKEND_REGISTRY.keys()))
36
+
37
+
38
+ def _build_tracker_workflow_section(
39
+ issue_id: str,
40
+ backend: IssueTrackerBackend | None,
41
+ step_number: int,
42
+ ) -> tuple[str, str | None]:
43
+ """Build the issue tracker workflow section and show command hint."""
44
+ if backend:
45
+ update_cmd = _format_tracker_command(
46
+ backend,
47
+ "update",
48
+ issue_id=issue_id,
49
+ status="in_progress",
50
+ )
51
+ close_cmd = _format_tracker_command(
52
+ backend,
53
+ "close",
54
+ issue_id=issue_id,
55
+ )
56
+ show_cmd = _format_tracker_command(backend, "show", issue_id=issue_id) or None
57
+ # Provide backend-specific commands when a tracker is detected.
58
+ section = f"""
59
+ {step_number}. **Issue tracker workflow.** You're working on `{issue_id}`. Follow this workflow:
60
+ - Mark in progress: `{update_cmd}`
61
+ - Implement the changes
62
+ - Close issue: `{close_cmd}`
63
+ - Commit with issue reference: `git add -A && git commit -m "{issue_id}: <summary>"`
64
+
65
+ Use the {backend.name} CLI (`{backend.cli}`) for issue tracker commands.
66
+ """
67
+ return section, show_cmd
68
+
69
+ supported = _supported_tracker_list()
70
+ # Fall back to generic instructions when no tracker is detected.
71
+ section = f"""
72
+ {step_number}. **Issue tracker workflow.** You're working on `{issue_id}`. Follow this workflow:
73
+ - Mark in progress in the issue tracker
74
+ - Implement the changes
75
+ - Close the issue when done
76
+ - Commit with issue reference: `git add -A && git commit -m "{issue_id}: <summary>"`
77
+
78
+ No issue tracker detected. Supported trackers: {supported}. Use `{ISSUE_TRACKER_HELP_TOOL}` for guidance.
79
+ """
80
+ return section, None
81
+
82
+
9
83
  def generate_worker_prompt(
10
84
  session_id: str,
11
85
  name: str,
@@ -13,6 +87,7 @@ def generate_worker_prompt(
13
87
  agent_type: AgentType = "claude",
14
88
  use_worktree: bool = False,
15
89
  bead: Optional[str] = None,
90
+ project_path: Optional[str] = None,
16
91
  custom_prompt: Optional[str] = None,
17
92
  ) -> str:
18
93
  """Generate the pre-prompt text for a worker session.
@@ -22,7 +97,8 @@ def generate_worker_prompt(
22
97
  name: The friendly name assigned to this worker
23
98
  agent_type: The type of agent CLI ("claude" or "codex")
24
99
  use_worktree: Whether this worker is in an isolated worktree
25
- bead: Optional beads issue ID (if provided, this is the assignment)
100
+ bead: Optional issue tracker ID (if provided, this is the assignment)
101
+ project_path: Optional project path for issue tracker detection
26
102
  custom_prompt: Optional additional instructions from the coordinator
27
103
 
28
104
  Returns:
@@ -40,6 +116,7 @@ def generate_worker_prompt(
40
116
  name=name,
41
117
  use_worktree=use_worktree,
42
118
  bead=bead,
119
+ project_path=project_path,
43
120
  custom_prompt=custom_prompt,
44
121
  )
45
122
  # Default to Claude prompt for unknown agent types to maintain backward compatibility
@@ -48,6 +125,7 @@ def generate_worker_prompt(
48
125
  name=name,
49
126
  use_worktree=use_worktree,
50
127
  bead=bead,
128
+ project_path=project_path,
51
129
  custom_prompt=custom_prompt,
52
130
  )
53
131
 
@@ -57,6 +135,7 @@ def _generate_claude_worker_prompt(
57
135
  name: str,
58
136
  use_worktree: bool = False,
59
137
  bead: Optional[str] = None,
138
+ project_path: Optional[str] = None,
60
139
  custom_prompt: Optional[str] = None,
61
140
  ) -> str:
62
141
  """Generate the pre-prompt for a Claude Code worker session.
@@ -70,31 +149,31 @@ def _generate_claude_worker_prompt(
70
149
  session_id: The unique identifier for this worker session
71
150
  name: The friendly name assigned to this worker
72
151
  use_worktree: Whether this worker is in an isolated worktree
73
- bead: Optional beads issue ID
152
+ bead: Optional issue tracker ID
153
+ project_path: Optional project path for issue tracker detection
74
154
  custom_prompt: Optional additional instructions
75
155
 
76
156
  Returns:
77
157
  Formatted pre-prompt for Claude worker
78
158
  """
159
+ # Detect issue tracker backend so we can use the right commands.
160
+ tracker_backend = _resolve_issue_tracker_backend(project_path)
161
+
79
162
  # Build optional sections with dynamic numbering
80
163
  next_step = 4
81
164
  extra_sections = ""
82
165
 
83
- # Beads section (if bead provided)
166
+ # Issue tracker section (if issue ID provided)
84
167
  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
168
+ tracker_section, show_cmd = _build_tracker_workflow_section(
169
+ issue_id=bead,
170
+ backend=tracker_backend,
171
+ step_number=next_step,
172
+ )
173
+ extra_sections += tracker_section
95
174
  next_step += 1
96
175
 
97
- # Commit section (if worktree but beads section didn't already cover commit)
176
+ # Commit section (if worktree but issue tracker section didn't already cover commit)
98
177
  if use_worktree and not bead:
99
178
  commit_section = f"""
100
179
  {next_step}. **Commit when done.** You're in an isolated worktree branch — commit your
@@ -107,9 +186,12 @@ def _generate_claude_worker_prompt(
107
186
  # Closing/assignment section - 4 cases based on bead and custom_prompt
108
187
  if bead and custom_prompt:
109
188
  # Case 2: bead + custom instructions
189
+ show_hint = (
190
+ f"Use `{show_cmd}` for details." if show_cmd else "Use your issue tracker for details."
191
+ )
110
192
  closing = f"""=== YOUR ASSIGNMENT ===
111
193
 
112
- The coordinator assigned you `{bead}` (use `bd show {bead}` for details) and included
194
+ The coordinator assigned you `{bead}` ({show_hint}) and included
113
195
  the following instructions:
114
196
 
115
197
  {custom_prompt}
@@ -117,9 +199,12 @@ the following instructions:
117
199
  Get to work!"""
118
200
  elif bead:
119
201
  # Case 1: bead only
202
+ show_hint = (
203
+ f"Use `{show_cmd}` for details." if show_cmd else "Use your issue tracker for details."
204
+ )
120
205
  closing = f"""=== YOUR ASSIGNMENT ===
121
206
 
122
- Your assignment is `{bead}`. Use `bd show {bead}` for details. Get to work!"""
207
+ Your assignment is `{bead}`. {show_hint} Get to work!"""
123
208
  elif custom_prompt:
124
209
  # Case 3: custom instructions only
125
210
  closing = f"""=== YOUR ASSIGNMENT ===
@@ -161,6 +246,7 @@ def _generate_codex_worker_prompt(
161
246
  name: str,
162
247
  use_worktree: bool = False,
163
248
  bead: Optional[str] = None,
249
+ project_path: Optional[str] = None,
164
250
  custom_prompt: Optional[str] = None,
165
251
  ) -> str:
166
252
  """Generate the pre-prompt for an OpenAI Codex worker session.
@@ -168,37 +254,37 @@ def _generate_codex_worker_prompt(
168
254
  Codex workers differ from Claude:
169
255
  - No claude-team MCP markers (Codex doesn't parse JSONL markers)
170
256
  - No Stop hook idle detection (uses output pattern matching or timeouts)
171
- - Runs with --full-auto instead of --dangerously-skip-permissions
257
+ - Runs with --dangerously-bypass-approvals-and-sandbox instead of --dangerously-skip-permissions
172
258
 
173
259
  Args:
174
260
  session_id: The unique identifier for this worker session
175
261
  name: The friendly name assigned to this worker
176
262
  use_worktree: Whether this worker is in an isolated worktree
177
- bead: Optional beads issue ID
263
+ bead: Optional issue tracker ID
264
+ project_path: Optional project path for issue tracker detection
178
265
  custom_prompt: Optional additional instructions
179
266
 
180
267
  Returns:
181
268
  Formatted pre-prompt for Codex worker
182
269
  """
270
+ # Detect issue tracker backend so we can use the right commands.
271
+ tracker_backend = _resolve_issue_tracker_backend(project_path)
272
+
183
273
  # Build optional sections with dynamic numbering
184
274
  next_step = 4
185
275
  extra_sections = ""
186
276
 
187
- # Beads section (if bead provided) - same workflow as Claude
277
+ # Issue tracker section (if issue ID provided) - same workflow as Claude
188
278
  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
279
+ tracker_section, show_cmd = _build_tracker_workflow_section(
280
+ issue_id=bead,
281
+ backend=tracker_backend,
282
+ step_number=next_step,
283
+ )
284
+ extra_sections += tracker_section
199
285
  next_step += 1
200
286
 
201
- # Commit section (if worktree but beads section didn't already cover commit)
287
+ # Commit section (if worktree but issue tracker section didn't already cover commit)
202
288
  if use_worktree and not bead:
203
289
  commit_section = f"""
204
290
  {next_step}. **Commit when done.** You're in an isolated worktree branch — commit your
@@ -212,7 +298,7 @@ def _generate_codex_worker_prompt(
212
298
  if bead and custom_prompt:
213
299
  closing = f"""=== YOUR ASSIGNMENT ===
214
300
 
215
- The coordinator assigned you `{bead}` (use `bd show {bead}` for details) and included
301
+ The coordinator assigned you `{bead}` ({f"Use `{show_cmd}` for details." if show_cmd else "Use your issue tracker for details."}) and included
216
302
  the following instructions:
217
303
 
218
304
  {custom_prompt}
@@ -221,7 +307,7 @@ Get to work!"""
221
307
  elif bead:
222
308
  closing = f"""=== YOUR ASSIGNMENT ===
223
309
 
224
- Your assignment is `{bead}`. Use `bd show {bead}` for details. Get to work!"""
310
+ Your assignment is `{bead}`. {f"Use `{show_cmd}` for details." if show_cmd else "Use your issue tracker for details."} Get to work!"""
225
311
  elif custom_prompt:
226
312
  closing = f"""=== YOUR ASSIGNMENT ===
227
313
 
@@ -270,7 +356,7 @@ def get_coordinator_guidance(
270
356
  worker_summaries: List of dicts with keys:
271
357
  - name: Worker name
272
358
  - agent_type: Agent type ("claude" or "codex")
273
- - bead: Optional bead ID
359
+ - bead: Optional issue tracker ID
274
360
  - custom_prompt: Optional custom instructions (truncated for display)
275
361
  - awaiting_task: True if worker has no bead and no prompt
276
362
 
@@ -309,7 +395,7 @@ def get_coordinator_guidance(
309
395
  elif bead:
310
396
  worker_lines.append(
311
397
  f"- **{name}**{type_indicator}: `{bead}` "
312
- "(beads workflow: mark in_progress -> implement -> close -> commit)"
398
+ "(issue tracker workflow: mark in_progress -> implement -> close -> commit)"
313
399
  )
314
400
  elif custom_prompt:
315
401
  short_prompt = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-team-mcp
3
- Version: 0.5.0
3
+ Version: 0.6.1
4
4
  Summary: MCP server for managing multiple Claude Code sessions via iTerm2
5
5
  Project-URL: Homepage, https://github.com/Martian-Engineering/claude-team
6
6
  Project-URL: Repository, https://github.com/Martian-Engineering/claude-team
@@ -192,7 +192,7 @@ export CLAUDE_TEAM_CODEX_COMMAND="happy codex"
192
192
  | Tool | Description |
193
193
  |------|-------------|
194
194
  | `list_worktrees` | List git worktrees created by claude-team for a repository |
195
- | `bd_help` | Get a quick reference guide for using Beads issue tracking |
195
+ | `bd_help` | Beads quick reference (use `pb help` for Pebbles projects) |
196
196
 
197
197
  ### Worker Identification
198
198
 
@@ -214,7 +214,6 @@ Arguments:
214
214
  skip_permissions: bool - If True, start Claude with --dangerously-skip-permissions
215
215
  custom_names: list[str] - Override automatic themed name selection
216
216
  custom_prompt: str - Custom prompt instead of standard worker pre-prompt
217
- include_beads_instructions: bool - Append beads guidance to custom prompt (default: True)
218
217
  use_worktrees: bool - Create isolated git worktree for each worker
219
218
 
220
219
  Returns:
@@ -269,6 +268,20 @@ make install-commands
269
268
  | `/merge-worker` | Directly merge a worker's branch back to parent (for internal changes) |
270
269
  | `/pr-worker` | Create a pull request from a worker's branch |
271
270
  | `/team-summary` | Generate end-of-session summary of all worker activity |
271
+
272
+ ## Issue Tracker Support
273
+
274
+ `claude-team` supports both Pebbles (`pb`) and Beads (`bd --no-db`).
275
+ The tracker is auto-detected by marker directories in the project root:
276
+
277
+ - `.pebbles` → Pebbles
278
+ - `.beads` → Beads
279
+
280
+ If both markers exist, Pebbles is selected by default. Worker prompts and
281
+ coordination guidance use the detected tracker commands. For quick references:
282
+
283
+ - Pebbles: `pb help`
284
+ - Beads: `bd_help` tool
272
285
  | `/cleanup-worktrees` | Remove worktrees for merged branches |
273
286
 
274
287
  ## Usage Patterns
@@ -10,33 +10,34 @@ claude_team_mcp/registry.py,sha256=y14ggF7qCia-xYYWJZhTsUAnBn5fFEkS7LspfEwhGQI,1
10
10
  claude_team_mcp/server.py,sha256=oOYWVJo0-P0izs1wyxeouK1MJP16-P5djRZH8trSrqM,12726
11
11
  claude_team_mcp/session_state.py,sha256=OcViByS05afdiCrBNRLR9qKrAn77H-2ALTe7yHfUUDs,34837
12
12
  claude_team_mcp/subprocess_cache.py,sha256=6Q1NIMn2X5_75S4s_a9iPBka-UCz6RW0EMxPSPEaLxo,3612
13
- claude_team_mcp/worker_prompt.py,sha256=Cz6yByWKVLg74_Y4DiwfO1oUel0-gkHvC8RK7h1JwzM,12594
13
+ claude_team_mcp/worker_prompt.py,sha256=NvzUrR6Zqjp8HuL-xOeAncdvACHbyN7O0nISWyySHq4,15771
14
14
  claude_team_mcp/worktree.py,sha256=s5X4mePVb4AlPzYsTklLGKgLD-4GJX1iokpsF6WwrdU,17015
15
15
  claude_team_mcp/cli_backends/__init__.py,sha256=9lpklc5lGWn-AdHoVqFMHau3UgzsN276grC1istHI2k,1038
16
16
  claude_team_mcp/cli_backends/base.py,sha256=dArm2Yqjzs3smN0JpSGR79e9I_kQYJFgQ8gYpNrmS-o,3923
17
17
  claude_team_mcp/cli_backends/claude.py,sha256=5axMph_IX-wX-DMulq0B_xQ3mVbhlwZjIi_WqjQwyL4,3268
18
- claude_team_mcp/cli_backends/codex.py,sha256=P-pj7vBJeVQTt12UdOSw9RQlRmvP4bnYNPY0kleX91I,3404
18
+ claude_team_mcp/cli_backends/codex.py,sha256=OTTAw9P4EKBggGmKK32-BYQkF7jpfZSOiIfa77wxG1Q,3408
19
+ claude_team_mcp/issue_tracker/__init__.py,sha256=JYcVEdXkqDKXd9BAUoz3emYyZ9bvVRsuTB7Vxfw3jhU,3792
19
20
  claude_team_mcp/schemas/__init__.py,sha256=IingbdgdQx9C0ZLBOhZ-doqIJRbO7aeAQjuCHMuVA84,99
20
21
  claude_team_mcp/schemas/codex.py,sha256=KwUkTmD70kQLZvzl366tHAsuwKbtsk86ySTOW6b9wDk,5949
21
- claude_team_mcp/tools/__init__.py,sha256=_s6RJPIpzpm3eWr6stZdkvvDCISCz__tbc5MHgVl6tA,1484
22
+ claude_team_mcp/tools/__init__.py,sha256=qILDACyNju45dX19QOmtCnVlRWCfGx7y96h5aJ_J5OU,1506
22
23
  claude_team_mcp/tools/adopt_worker.py,sha256=oWSamOzOqnLPWADWb4tk7qSPHroxIhQXkFDnhy_EOkw,4560
23
24
  claude_team_mcp/tools/annotate_worker.py,sha256=mBo4YMaaaNQxQBduYK1DPA-Ioift-ZQ9tYlBM6S15t8,1639
24
- claude_team_mcp/tools/bd_help.py,sha256=kA3DnMGG48ruIt7L-tcUPfevy_l-Yy22pa3I20DZU2A,1402
25
25
  claude_team_mcp/tools/check_idle_workers.py,sha256=IjDNDeal9M7lTONWjKZrt8bXu7O277ossHz_2oyLRcY,3374
26
26
  claude_team_mcp/tools/close_workers.py,sha256=glVUNM5Q32z8DyzvNKpxExN9pDR16rzjuyzEjI-eInM,6633
27
27
  claude_team_mcp/tools/discover_workers.py,sha256=PkdnURZBex_y0kFx_pv-EgWrEbtQtsg5TjqycNs7BJI,5437
28
28
  claude_team_mcp/tools/examine_worker.py,sha256=7Nd3EOdsGVDjMJ8ov9NhmcrjN8K9IE4i_noXHOP1uI8,1620
29
+ claude_team_mcp/tools/issue_tracker_help.py,sha256=KxgjFhXp3NCUDjqTl3UnIiFV-Y5DM80C1EoZXfA82QM,1668
29
30
  claude_team_mcp/tools/list_workers.py,sha256=6cvsgHOYtakkSgoZdYez4VEQ3I8aWAKaGWhfiZyPf2c,2390
30
31
  claude_team_mcp/tools/list_worktrees.py,sha256=_EIwpwoCMLaQh4dHws-jO53MS-E-L7hC7oPT7xC26lw,3665
31
- claude_team_mcp/tools/message_workers.py,sha256=L9d_EE_qLqJ6Uiebux72LJ5X8wFFO3Tyyb4RFvJ6ofA,11868
32
+ claude_team_mcp/tools/message_workers.py,sha256=02XAE2EsJkkcZdmjaxQRiyUhAFTN4uB8kYzSkOwbxk0,12220
32
33
  claude_team_mcp/tools/read_worker_logs.py,sha256=9gccM6MSaoxu97Xjsk7nUalLEU8XHV7r3SKggBRpNww,5913
33
- claude_team_mcp/tools/spawn_workers.py,sha256=4vvoy_jwLPWNPuVZ-r_E6JeIL0aV46H77SVXmzTJSHo,28280
34
+ claude_team_mcp/tools/spawn_workers.py,sha256=A08erciMM-q0TCPaFeVn6KvtVerIWdlbm6bH7P_E5G8,32366
34
35
  claude_team_mcp/tools/wait_idle_workers.py,sha256=ITnhBiJYCgkz-DGJaYouAyTDh6cPIL_9RrptqC_xHu0,5232
35
- claude_team_mcp/utils/__init__.py,sha256=_O-de711DxfMdjCAHHoifyOtzdllciE9FFV-tZ5m2Y8,444
36
- claude_team_mcp/utils/constants.py,sha256=R5BRg50hAkbsZFNRZye7O8bCqsCkzMGz-re_PK14USE,2465
36
+ claude_team_mcp/utils/__init__.py,sha256=Jyc-N1RXZnMdXLjSgRBB2ih04v-h0woUzZcVYYfc7wQ,647
37
+ claude_team_mcp/utils/constants.py,sha256=FGDHeo0reZ89365fuXJGIl2Y5MFQAoKfWtmYr7UQzhQ,5815
37
38
  claude_team_mcp/utils/errors.py,sha256=9uPFHp7UJYB5t3p7P_5Sh3PVpYh4_vj_RLzX5GcJPEU,2738
38
- claude_team_mcp/utils/worktree_detection.py,sha256=NfEK8c_toFiz8dqF2ht1FJzW9a9VstVm7Y5SNXvwAD8,2564
39
- claude_team_mcp-0.5.0.dist-info/METADATA,sha256=_hmIf5fWm2Zm-LVyuYqkoiIayPbQlb0bMPT_kCl7aJo,15697
40
- claude_team_mcp-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
41
- claude_team_mcp-0.5.0.dist-info/entry_points.txt,sha256=cmk5dmK50RVquExT-k_J72akl3qKIerPpVqfit7kQtQ,53
42
- claude_team_mcp-0.5.0.dist-info/RECORD,,
39
+ claude_team_mcp/utils/worktree_detection.py,sha256=oMGcb7p1jvr7qWs06sxUMTAV8jRialcVqziCTCdW7XU,3251
40
+ claude_team_mcp-0.6.1.dist-info/METADATA,sha256=Au4mhF7eDsGIyGSCerEJUjPPR3fSj_1brDFL9CoC4O8,16020
41
+ claude_team_mcp-0.6.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
42
+ claude_team_mcp-0.6.1.dist-info/entry_points.txt,sha256=cmk5dmK50RVquExT-k_J72akl3qKIerPpVqfit7kQtQ,53
43
+ claude_team_mcp-0.6.1.dist-info/RECORD,,
@@ -1,42 +0,0 @@
1
- """
2
- Beads help tool.
3
-
4
- Provides bd_help for quick reference on beads issue tracking.
5
- """
6
-
7
- from mcp.server.fastmcp import FastMCP
8
-
9
- from ..utils import BEADS_HELP_TEXT
10
-
11
-
12
- def register_tools(mcp: FastMCP) -> None:
13
- """Register bd_help tool on the MCP server."""
14
-
15
- @mcp.tool()
16
- async def bd_help() -> dict:
17
- """
18
- Get a quick reference guide for using Beads issue tracking.
19
-
20
- Returns condensed documentation on beads commands, workflow patterns,
21
- and best practices for worker sessions. Call this tool when you need
22
- guidance on tracking progress, adding comments, or managing issues.
23
-
24
- Returns:
25
- Dict with help text and key command examples
26
- """
27
- return {
28
- "help": BEADS_HELP_TEXT,
29
- "quick_commands": {
30
- "list_issues": "bd list",
31
- "show_ready": "bd ready",
32
- "show_issue": "bd show <issue-id>",
33
- "start_work": "bd update <id> --status in_progress",
34
- "add_comment": 'bd comment <id> "progress message"',
35
- "close_issue": "bd close <id>",
36
- "search": "bd search <query>",
37
- },
38
- "worker_tip": (
39
- "As a worker, add comments to track progress rather than closing issues. "
40
- "The coordinator will close issues after reviewing your work."
41
- ),
42
- }