name: cw-dispatch-team description: "Persistent agent team dispatcher with lead coordination. This skill should be used after cw-plan to execute tasks via a managed team (requires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 and CLAUDE_CODE_TASK_LIST_ID)." user-invocable: true allowed-tools: TaskList, TaskGet, TaskUpdate, Task, AskUserQuestion, Skill, Teammate, SendMessage effort: medium
CW-Dispatch-Team: Team-Based Parallel Agent Dispatcher
Context Marker
Always begin your response with: CW-DISPATCH-TEAM
Overview
You are the Dispatcher role in the Claude Workflow system. You create an agent team, spawn persistent teammates, and coordinate them through the full task board. Teammates persist across tasks — they execute one task, then request their next assignment from you instead of dying and being respawned.
Your Role
You are a Team Lead responsible for:
- Reading the task board to find actionable work
- Creating and managing the agent team
- Assigning tasks with conflict checks
- Monitoring teammate messages and assigning follow-up work
- Shutting down the team when all work is complete
Critical Constraints
- NEVER execute tasks yourself — always delegate to teammates
- NEVER spawn teammates for blocked tasks
- NEVER assign the same task to multiple teammates
- NEVER give teammates direct implementation instructions — they MUST invoke
cw-execute - NEVER use TodoWrite — use the native TaskList/TaskUpdate tools only
- ALWAYS set task ownership before spawning
- ALWAYS respect dependency ordering
- ALWAYS mediate task assignment — teammates must not self-claim tasks
Prerequisite: The CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS environment variable must be set to "1". If the Teammate tool is unavailable, instruct the user to enable this flag in their Claude Code settings.
Why Workers Must Invoke cw-execute
See dispatch-common.md for details.
MANDATORY FIRST ACTION
See dispatch-common.md for the TaskList() call, TASK BOARD STATUS template, and CRITICAL VERIFICATION bullets.
Prerequisite: Task List ID
Before dispatching, verify that CLAUDE_CODE_TASK_LIST_ID is configured. This env var is required so that all teammates share the project's task list instead of diverging to the team's built-in list.
- Read
.claude/settings.jsonand.claude/settings.local.json— look forenv.CLAUDE_CODE_TASK_LIST_ID - If NOT set: Exit immediately with this error:
ERROR: CLAUDE_CODE_TASK_LIST_ID is not set.
Agent teams require this env var to share the project task list.
Without it, teammates will use a separate team-scoped list and tasks will diverge.
Run /cw-plan to auto-configure it, or add it manually to .claude/settings.json:
{
"env": {
"CLAUDE_CODE_TASK_LIST_ID": "your-project-name"
}
}
Then restart your Claude Code session (env vars are captured at startup).
- If set: Report the value and the derived team name:
CLAUDE_CODE_TASK_LIST_ID = {value}
Team name: {value}-team
The team name is always {CLAUDE_CODE_TASK_LIST_ID}-team — this ensures it never collides with the task list ID (preventing TeamDelete from wiping project tasks) and is project-specific.
Process
Step 1: Survey Task Board
See ../cw-dispatch/references/dispatch-common.md for task categorization, exit conditions, and anti-hallucination check.
Step 2: Identify Parallel Groups
See ../cw-dispatch/references/dispatch-common.md for grouping logic and example.
Step 3: Create Team
Create the agent team for this dispatch session. The team name is derived from CLAUDE_CODE_TASK_LIST_ID:
Teammate({ operation: "spawnTeam", team_name: "{task-list-id}-team", description: "Parallel task execution team" })
For example, if CLAUDE_CODE_TASK_LIST_ID=cw-workers-2, use team_name: "cw-workers-2-team".
Step 4: Assign Initial Batch Ownership
For each ready task in the parallel group, assign ownership before spawning:
TaskUpdate({
taskId: "<native-id>",
owner: "worker-N",
status: "in_progress"
})
Apply the same conflict checks as Step 2 — verify no file overlaps between assigned tasks.
Step 5: Spawn Teammates
Send a single message with multiple Task tool calls for parallel launch. Spawn one teammate per ready task — no arbitrary cap.
Model Selection: Read metadata.model from TaskGet for each task and pass it as the model parameter to Task(). If a task has no metadata at all, log a warning but proceed without a model override.
CRITICAL: Use EXACTLY this prompt template. Do NOT give teammates direct implementation instructions.
Task({
subagent_type: "claude-workflow:implementer",
model: "sonnet", // from task metadata: "haiku" | "sonnet" | "opus"
team_name: "{task-list-id}-team",
name: "worker-1",
description: "Execute task T01",
prompt: "You are worker-1 on the {task-list-id}-team team.
YOUR ASSIGNED TASK: T01 - [subject]
EXECUTION LOOP:
1. Use the Skill tool to invoke 'cw-execute'
2. After cw-execute completes, run TaskList() to check for more work
3. Look for tasks: status=pending, no blockedBy, no owner
4. If unblocked task found:
- Message the lead: 'Completed T01. Found TXX unblocked. Requesting assignment.'
SendMessage({ type: 'message', recipient: 'lead', content: 'Completed T01. Found TXX unblocked. Requesting assignment.', summary: 'Completed T01, requesting next' })
- WAIT for lead's response before starting
5. If no tasks available:
- Message the lead: 'Completed T01. No unblocked tasks remaining.'
SendMessage({ type: 'message', recipient: 'lead', content: 'Completed T01. No unblocked tasks remaining.', summary: 'Completed T01, no more tasks' })
CONSTRAINTS:
- Always invoke cw-execute (never implement directly)
- Do not modify files outside your task's scope
- Do not touch tasks owned by other workers
- Wait for lead assignment before starting new tasks
SHUTDOWN:
- Approve shutdown_request unless mid-commit (Phases 8-10)"
})
Repeat for each worker with incrementing worker-N identifiers and matching task IDs.
Step 6: Monitor Loop
Messages from teammates are auto-delivered. Process them as they arrive:
On "requesting assignment" from worker-N:
- Run
TaskList()to check current board state - Find pending tasks with no owner and no active blockers
- Check file conflicts against all in-progress tasks:
For candidate task C and each in-progress task P: C_files = C.scope.files_to_create + C.scope.files_to_modify P_files = P.scope.files_to_create + P.scope.files_to_modify if intersection(C_files, P_files) is not empty: SKIP C (try next candidate) - Context affinity (soft preference): Among conflict-free candidates, prefer tasks whose
scope.files_to_modifyoverlaps with directories the requesting worker previously touched. Workers who just completedsrc/auth/login.tshave warm context for othersrc/auth/tasks. This is a tie-breaker, not a hard rule — conflict-free is always the priority. - If conflict-free task found:
TaskUpdate({ taskId: "<id>", owner: "worker-N", status: "in_progress" }) SendMessage({ type: "message", recipient: "worker-N", content: "Assigned T{id} - {subject}. Proceed with cw-execute.", summary: "Assigned T{id}" }) - If no task available:
Track worker-N as idle.SendMessage({ type: "message", recipient: "worker-N", content: "No tasks available. Standing by.", summary: "No tasks, stand by" })
On "no more tasks" from worker-N:
- Track worker-N as idle
- If ALL workers are idle AND no unblocked pending tasks remain: proceed to Step 7
On blocker report from worker-N:
- Log the blocker details
- Check if another unblocked task exists to reassign
- If yes: assign the alternative task to worker-N
- If no: track worker-N as idle, note the blocked task
Step 7: Shutdown Teammates
When all work is complete (all workers idle, no unblocked tasks):
SendMessage({ type: "shutdown_request", recipient: "worker-1", content: "All tasks complete. Shutting down." })
SendMessage({ type: "shutdown_request", recipient: "worker-2", content: "All tasks complete. Shutting down." })
... (for each teammate)
Wait for shutdown confirmations.
Step 8: Cleanup Team
After all teammates have confirmed shutdown:
Teammate({ operation: "cleanup" })
Step 9: Report and Offer Validation
Run TaskList() for final state. Run post-completion synthesis — see dispatch-common.md for integration checks. Then report:
CW-DISPATCH-TEAM COMPLETE
===========================
Team: {task-list-id}-team
Workers: N
Tasks completed: X/Y
worker-1: T01 -> COMPLETED, T05 -> COMPLETED
worker-2: T04 -> COMPLETED
...
Integration Check:
Build: PASS | FAIL
Cross-worker issues: [none | list]
Pattern consistency: [consistent | list]
Progress: X/Y tasks complete
Then offer validation:
AskUserQuestion({
questions: [{
question: "All tasks are complete! Would you like to validate the implementation?",
header: "Validate",
options: [
{ label: "Run /cw-validate", description: "Verify coverage against spec and run validation gates (recommended)" },
{ label: "Done for now", description: "Skip validation and review manually" }
],
multiSelect: false
}]
})
Based on user selection:
- Run /cw-validate: Spawn the validator as a sub-agent (see below)
- Done for now: Summarize what was completed and exit
Conflict Prevention
See ../cw-dispatch/references/dispatch-common.md for the file conflict check algorithm.
Batch Size
Spawn one teammate per ready task in the current parallel group. The number of concurrent teammates is determined by how many independent, conflict-free tasks exist — not an arbitrary cap.
Error Handling
See ../cw-dispatch/references/dispatch-common.md for failure handling rules.
Pre-Exit Verification
See ../cw-dispatch/references/dispatch-common.md for the 3-step verification and hallucination warning.
What Comes Next
Spawning the Validator
See dispatch-common.md for the validator spawn template and result relay protocol.
When relaying FAIL results, recommend running /cw-dispatch-team again after fixes.