worker-dispatch

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Worker Dispatch

Worker调度

Overview

概述

Spawns and manages worker Codex processes in isolated git worktrees. Workers are disposable - if they fail, spawn another.
Core principle: Workers are isolated, scoped, and expendable. State lives in GitHub, not in workers.
Announce at start: "I'm using worker-dispatch to spawn a worker for issue #[N]."
在独立的Git工作树中生成并管理Worker Codex进程。Worker是可丢弃的——如果它们运行失败,就重新生成一个。
核心原则:Worker是独立的、有作用域的且可消耗的。状态存储在GitHub中,而非Worker内部。
启动时声明:"我正在使用worker-dispatch为#[N]号任务生成一个Worker。"

State Management

状态管理

CRITICAL: Worker state is stored in GitHub. NO local state files for tracking.
StateLocationPurpose
Worker assignmentIssue commentWho is working on what
Worker statusProject BoardIn Progress, Done, etc.
Process logsLocal (ephemeral)Debugging only
Process PIDsLocal (ephemeral)Process management only
Local files (logs, PIDs) are ephemeral - they exist only for the current orchestration session. All persistent state is in GitHub.
关键注意事项:Worker状态存储在GitHub中,不使用本地状态文件进行追踪。
状态存储位置用途
Worker分配信息任务评论区记录谁在处理什么任务
Worker状态项目看板标记进行中、已完成等状态
进程日志本地(临时)仅用于调试
进程PID本地(临时)仅用于进程管理
本地文件(日志、PID)是临时的——仅在当前编排会话期间存在。所有持久化状态均存储在GitHub中。

Worker Architecture

Worker架构

Main Repository (./)
└── Worktrees (parallel directories)
    ├── ../project-worker-123/    ← Worker for issue #123
    │   └── (full repo copy on feature/123-* branch)
    ├── ../project-worker-124/    ← Worker for issue #124
    │   └── (full repo copy on feature/124-* branch)
    └── ../project-worker-125/    ← Worker for issue #125
        └── (full repo copy on feature/125-* branch)
主仓库 (./)
└── 工作树(并行目录)
    ├── ../project-worker-123/    ← 用于#123号任务的Worker
    │   └── (feature/123-*分支上的完整仓库副本)
    ├── ../project-worker-124/    ← 用于#124号任务的Worker
    │   └── (feature/124-*分支上的完整仓库副本)
    └── ../project-worker-125/    ← 用于#125号任务的Worker
        └── (feature/125-*分支上的完整仓库副本)

Spawning a Worker

生成Worker

Step 1: Create Worktree

步骤1:创建工作树

bash
spawn_worker() {
  issue=$1
  context_file=$2  # Optional: handover context

  worker_id="worker-$(date +%s)-$issue"

  issue_title=$(gh issue view "$issue" --json title --jq '.title' | \
    tr '[:upper:]' '[:lower:]' | \
    sed 's/[^a-z0-9]/-/g' | \
    cut -c1-40)

  branch="feature/$issue-$issue_title"
  worktree_path="../$(basename $PWD)-worker-$issue"

  git fetch origin main
  git branch "$branch" origin/main 2>/dev/null || true
  git worktree add "$worktree_path" "$branch"

  echo "Created worktree: $worktree_path on branch $branch"
}
bash
spawn_worker() {
  issue=$1
  context_file=$2  # 可选:移交上下文

  worker_id="worker-$(date +%s)-$issue"

  issue_title=$(gh issue view "$issue" --json title --jq '.title' | \
    tr '[:upper:]' '[:lower:]' | \
    sed 's/[^a-z0-9]/-/g' | \
    cut -c1-40)

  branch="feature/$issue-$issue_title"
  worktree_path="../$(basename $PWD)-worker-$issue"

  git fetch origin main
  git branch "$branch" origin/main 2>/dev/null || true
  git worktree add "$worktree_path" "$branch"

  echo "Created worktree: $worktree_path on branch $branch"
}

Step 2: Register Worker in GitHub

步骤2:在GitHub中注册Worker

Post worker assignment to the issue as a structured comment:
bash
register_worker() {
  worker_id=$1
  issue=$2
  worktree=$3

  # Post assignment comment with structured marker
  gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
\`\`\`json
{
  \"assigned\": true,
  \"worker_id\": \"$worker_id\",
  \"assigned_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
  \"worktree\": \"$worktree\"
}
\`\`\`
<!-- /WORKER:ASSIGNED -->

**Worker Assigned**
- **Worker ID:** \`$worker_id\`
- **Started:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
- **Worktree:** \`$worktree\`

---
*Orchestrator: $ORCHESTRATION_ID*"

  # Update project board status
  update_project_status "$issue" "In Progress"
}
将Worker分配信息以结构化评论的形式发布到任务中:
bash
register_worker() {
  worker_id=$1
  issue=$2
  worktree=$3

  # 发布带结构化标记的分配评论
  gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
\`\`\`json
{
  \"assigned\": true,
  \"worker_id\": \"$worker_id\",
  \"assigned_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
  \"worktree\": \"$worktree\"
}
\`\`\`
<!-- /WORKER:ASSIGNED -->

**Worker已分配**
- **Worker ID:** \`$worker_id\`
- **启动时间:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
- **工作树:** \`$worktree\`

---
*编排器:$ORCHESTRATION_ID*"

  # 更新项目看板状态
  update_project_status "$issue" "进行中"
}

Step 3: Construct Worker Prompt

步骤3:构建Worker提示词

bash
construct_worker_prompt() {
  issue=$1
  worker_id=$2
  context_file=$3
  attempt=$4
  research_context=$5

  cat <<PROMPT
You are a worker agent. Your ONLY task is to complete GitHub issue #$issue.
bash
construct_worker_prompt() {
  issue=$1
  worker_id=$2
  context_file=$3
  attempt=$4
  research_context=$5

  cat <<PROMPT
You are a worker agent. Your ONLY task is to complete GitHub issue #$issue.

Worker Identity

Worker Identity

  • Worker ID: $worker_id
  • Issue: #$issue
  • Attempt: $attempt
  • Orchestration: $ORCHESTRATION_ID
  • Worker ID: $worker_id
  • Issue: #$issue
  • Attempt: $attempt
  • Orchestration: $ORCHESTRATION_ID

Your Mission

Your Mission

Complete issue #$issue by following the issue-driven-development workflow:
  1. Read and understand the issue completely
  2. Create/verify you're on the correct branch
  3. Implement the solution with TDD
  4. Run all tests
  5. Create a PR when complete
  6. Update issue with progress comments throughout
Complete issue #$issue by following the issue-driven-development workflow:
  1. Read and understand the issue completely
  2. Create/verify you're on the correct branch
  3. Implement the solution with TDD
  4. Run all tests
  5. Create a PR when complete
  6. Update issue with progress comments throughout

Constraints

Constraints

  • Work ONLY on issue #$issue - no other issues
  • Do NOT modify unrelated code
  • Do NOT start other work
  • Follow all project skills (strict-typing, ipv6-first, etc.)
  • Maximum 100 turns - if approaching limit, prepare handover
  • Work ONLY on issue #$issue - no other issues
  • Do NOT modify unrelated code
  • Do NOT start other work
  • Follow all project skills (strict-typing, ipv6-first, etc.)
  • Maximum 100 turns - if approaching limit, prepare handover

Exit Conditions

Exit Conditions

Exit when ANY of these occur:
  1. PR Created - Your work is complete
  2. Blocked - You cannot proceed without external input
  3. Turns Exhausted - Approaching 100 turns, handover needed
  4. Failed - Tests fail after good-faith effort (triggers research)
Exit when ANY of these occur:
  1. PR Created - Your work is complete
  2. Blocked - You cannot proceed without external input
  3. Turns Exhausted - Approaching 100 turns, handover needed
  4. Failed - Tests fail after good-faith effort (triggers research)

Progress Reporting

Progress Reporting

Update the issue with comments as you work.
Update the issue with comments as you work.

On Completion

On Completion

Post completion comment to the issue.
Post completion comment to the issue.

On Handover Needed

On Handover Needed

Post handover context to the issue comment (NOT local file).
$(if [ -n "$context_file" ] && [ -f "$context_file" ]; then echo "## Context from Previous Worker" cat "$context_file" fi)
$(if [ -n "$research_context" ]; then echo "## Research Context (Previous Failures)" echo "$research_context" fi)
Post handover context to the issue comment (NOT local file).
$(if [ -n "$context_file" ] && [ -f "$context_file" ]; then echo "## Context from Previous Worker" cat "$context_file" fi)
$(if [ -n "$research_context" ]; then echo "## Research Context (Previous Failures)" echo "$research_context" fi)

Begin

Begin

Start by reading issue #$issue to understand the requirements. PROMPT }
undefined
Start by reading issue #$issue to understand the requirements. PROMPT }
undefined

Step 4: Spawn Process

步骤4:生成进程

bash
spawn_worker_process() {
  issue=$1
  worker_id=$2
  worktree_path=$3
  prompt=$4

  # Create local ephemeral directories
  mkdir -p ".codex/logs" ".codex/pids"
  log_file=".codex/logs/$worker_id.log"
  pid_file=".codex/pids/$worker_id.pid"

  (
    cd "$worktree_path"
    codex exec --dangerously-bypass-approvals-and-sandbox --json -C "$worktree_path" "$prompt" 2>&1
  ) > "$log_file" &

  worker_pid=$!
  echo "$worker_pid" > "$pid_file"

  echo "Spawned worker $worker_id (PID: $worker_pid) for issue #$issue"
}
bash
spawn_worker_process() {
  issue=$1
  worker_id=$2
  worktree_path=$3
  prompt=$4

  # 创建本地临时目录
  mkdir -p ".codex/logs" ".codex/pids"
  log_file=".codex/logs/$worker_id.log"
  pid_file=".codex/pids/$worker_id.pid"

  (
    cd "$worktree_path"
    codex exec --dangerously-bypass-approvals-and-sandbox --json -C "$worktree_path" "$prompt" 2>&1
  ) > "$log_file" &

  worker_pid=$!
  echo "$worker_pid" > "$pid_file"

  echo "Spawned worker $worker_id (PID: $worker_pid) for issue #$issue"
}

Complete Spawn Function

完整的生成函数

bash
spawn_worker() {
  issue=$1
  context_file=${2:-""}
  attempt=${3:-1}
  research_context=${4:-""}

  worker_id="worker-$(date +%s)-$issue"
  worktree_path=$(create_worktree "$issue" "$worker_id")
  prompt=$(construct_worker_prompt "$issue" "$worker_id" "$context_file" "$attempt" "$research_context")

  # Register in GitHub BEFORE spawning
  register_worker "$worker_id" "$issue" "$worktree_path"

  # Spawn process
  spawn_worker_process "$issue" "$worker_id" "$worktree_path" "$prompt"

  log_activity "worker_spawned" "$worker_id" "$issue"
}
bash
spawn_worker() {
  issue=$1
  context_file=${2:-""}
  attempt=${3:-1}
  research_context=${4:-""}

  worker_id="worker-$(date +%s)-$issue"
  worktree_path=$(create_worktree "$issue" "$worker_id")
  prompt=$(construct_worker_prompt "$issue" "$worker_id" "$context_file" "$attempt" "$research_context")

  # 生成进程前先在GitHub注册
  register_worker "$worker_id" "$issue" "$worktree_path"

  # 生成进程
  spawn_worker_process "$issue" "$worker_id" "$worktree_path" "$prompt"

  log_activity "worker_spawned" "$worker_id" "$issue"
}

Tool Scoping

工具范围

Standard Worker (Full Implementation)

标准Worker(完整实现)

bash
--allowedTools "Bash,Read,Edit,Write,Grep,Glob,mcp__git__*,mcp__github__*,mcp__memory__*,WebFetch,WebSearch"
bash
--allowedTools "Bash,Read,Edit,Write,Grep,Glob,mcp__git__*,mcp__github__*,mcp__memory__*,WebFetch,WebSearch"

Research Worker (Read-Only)

研究型Worker(只读)

bash
--allowedTools "Read,Grep,Glob,WebFetch,WebSearch,mcp__memory__*,mcp__github__get_issue,mcp__github__get_pull_request"
bash
--allowedTools "Read,Grep,Glob,WebFetch,WebSearch,mcp__memory__*,mcp__github__get_issue,mcp__github__get_pull_request"

Review Worker (No Edits)

评审型Worker(禁止编辑)

bash
--allowedTools "Read,Grep,Glob,Bash(pnpm test:*),Bash(pnpm lint:*)"
bash
--allowedTools "Read,Grep,Glob,Bash(pnpm test:*),Bash(pnpm lint:*)"

Checking Worker Status

检查Worker状态

Check both GitHub and local PID:
bash
check_worker_status() {
  worker_id=$1
  issue=$2

  pid_file=".codex/pids/$worker_id.pid"

  if [ ! -f "$pid_file" ]; then
    echo "unknown"
    return
  fi

  pid=$(cat "$pid_file")

  if ! kill -0 "$pid" 2>/dev/null; then
    # Process exited - check GitHub for status
    pr_exists=$(gh pr list --head "feature/$issue-*" --json number --jq 'length')

    if [ "$pr_exists" -gt 0 ]; then
      echo "completed"
    else
      # Check issue comments for status
      log_file=".codex/logs/$worker_id.log"
      if [ -f "$log_file" ]; then
        if grep -q 'handover' "$log_file"; then
          echo "handover_needed"
        elif grep -q 'blocked' "$log_file"; then
          echo "blocked"
        else
          echo "failed"
        fi
      else
        echo "unknown"
      fi
    fi
  else
    echo "running"
  fi
}
同时检查GitHub和本地PID:
bash
check_worker_status() {
  worker_id=$1
  issue=$2

  pid_file=".codex/pids/$worker_id.pid"

  if [ ! -f "$pid_file" ]; then
    echo "unknown"
    return
  fi

  pid=$(cat "$pid_file")

  if ! kill -0 "$pid" 2>/dev/null; then
    # 进程已退出 - 检查GitHub状态
    pr_exists=$(gh pr list --head "feature/$issue-*" --json number --jq 'length')

    if [ "$pr_exists" -gt 0 ]; then
      echo "completed"
    else
      # 检查任务评论获取状态
      log_file=".codex/logs/$worker_id.log"
      if [ -f "$log_file" ]; then
        if grep -q 'handover' "$log_file"; then
          echo "handover_needed"
        elif grep -q 'blocked' "$log_file"; then
          echo "blocked"
        else
          echo "failed"
        fi
      else
        echo "unknown"
      fi
    fi
  else
    echo "running"
  fi
}

Worker Cleanup

Worker清理

bash
cleanup_worker() {
  worker_id=$1
  issue=$2
  keep_worktree=${3:-false}

  worktree="../$(basename $PWD)-worker-$issue"

  # Remove worktree (unless keeping for inspection)
  if [ "$keep_worktree" = "false" ] && [ -d "$worktree" ]; then
    git worktree remove "$worktree" --force 2>/dev/null || true
    git worktree prune
  fi

  # Clean up local ephemeral files
  rm -f ".codex/pids/$worker_id.pid"

  # Post cleanup comment to issue
  gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
\`\`\`json
{\"assigned\": false, \"cleared_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}
\`\`\`
<!-- /WORKER:ASSIGNED -->

**Worker Cleaned Up**
- **Worker ID:** \`$worker_id\`
- **Cleared:** $(date -u +%Y-%m-%dT%H:%M:%SZ)

---
*Orchestrator: $ORCHESTRATION_ID*"

  log_activity "worker_cleaned" "$worker_id" "$issue"
}
bash
cleanup_worker() {
  worker_id=$1
  issue=$2
  keep_worktree=${3:-false}

  worktree="../$(basename $PWD)-worker-$issue"

  # 移除工作树(除非需要保留用于检查)
  if [ "$keep_worktree" = "false" ] && [ -d "$worktree" ]; then
    git worktree remove "$worktree" --force 2>/dev/null || true
    git worktree prune
  fi

  # 清理本地临时文件
  rm -f ".codex/pids/$worker_id.pid"

  # 在任务中发布清理完成的评论
  gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
\`\`\`json
{\"assigned\": false, \"cleared_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}
\`\`\`
<!-- /WORKER:ASSIGNED -->

**Worker已清理**
- **Worker ID:** \`$worker_id\`
- **清理时间:** $(date -u +%Y-%m-%dT%H:%M:%SZ)

---
*编排器:$ORCHESTRATION_ID*"

  log_activity "worker_cleaned" "$worker_id" "$issue"
}

Replacement Worker (After Handover)

替换Worker(移交后)

bash
spawn_replacement_worker() {
  old_worker_id=$1
  issue=$2
  worktree=$3

  # Get handover context from issue comments
  handover_context=$(gh api "/repos/$OWNER/$REPO/issues/$issue/comments" \
    --jq '[.[] | select(.body | contains("<!-- HANDOVER:START -->"))] | last | .body' 2>/dev/null || echo "")

  # Cleanup old worker but KEEP worktree
  cleanup_worker "$old_worker_id" "$issue" true

  # Spawn replacement with handover context
  new_worker_id="worker-$(date +%s)-$issue"
  attempt=$(($(get_attempt_count "$issue") + 1))

  prompt=$(construct_worker_prompt "$issue" "$new_worker_id" "" "$attempt" "$handover_context")
  register_worker "$new_worker_id" "$issue" "$worktree"
  spawn_worker_process "$issue" "$new_worker_id" "$worktree" "$prompt"

  log_activity "worker_replacement" "$new_worker_id" "$issue" "$old_worker_id"
}
bash
spawn_replacement_worker() {
  old_worker_id=$1
  issue=$2
  worktree=$3

  # 从任务评论中获取移交上下文
  handover_context=$(gh api "/repos/$OWNER/$REPO/issues/$issue/comments" \
    --jq '[.[] | select(.body | contains("<!-- HANDOVER:START -->"))] | last | .body' 2>/dev/null || echo "")

  # 清理旧Worker但保留工作树
  cleanup_worker "$old_worker_id" "$issue" true

  # 使用移交上下文生成新Worker
  new_worker_id="worker-$(date +%s)-$issue"
  attempt=$(($(get_attempt_count "$issue") + 1))

  prompt=$(construct_worker_prompt "$issue" "$new_worker_id" "" "$attempt" "$handover_context")
  register_worker "$new_worker_id" "$issue" "$worktree"
  spawn_worker_process "$issue" "$new_worker_id" "$worktree" "$prompt"

  log_activity "worker_replacement" "$new_worker_id" "$issue" "$old_worker_id"
}

Parallel Dispatch

并行调度

bash
dispatch_available_slots() {
  max_workers=5

  # Count current workers from project board (In Progress status)
  current=$(gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
    --format json | jq '[.items[] | select(.status.name == "In Progress")] | length')

  available=$((max_workers - current))

  if [ "$available" -le 0 ]; then
    echo "No worker slots available ($current/$max_workers active)"
    return
  fi

  echo "Dispatching up to $available workers..."

  for i in $(seq 1 $available); do
    next_issue=$(get_next_pending_issue)

    if [ -z "$next_issue" ]; then
      echo "No more pending issues"
      break
    fi

    spawn_worker "$next_issue"
  done
}
bash
dispatch_available_slots() {
  max_workers=5

  # 统计项目看板中当前的Worker数量(状态为进行中)
  current=$(gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
    --format json | jq '[.items[] | select(.status.name == "In Progress")] | length')

  available=$((max_workers - current))

  if [ "$available" -le 0 ]; then
    echo "No worker slots available ($current/$max_workers active)"
    return
  fi

  echo "Dispatching up to $available workers..."

  for i in $(seq 1 $available); do
    next_issue=$(get_next_pending_issue)

    if [ -z "$next_issue" ]; then
      echo "No more pending issues"
      break
    fi

    spawn_worker "$next_issue"
  done
}

Checklist

检查清单

When spawning a worker:
  • Worktree created successfully
  • Branch created/checked out
  • Worker registered in GitHub (issue comment)
  • Project board status updated to In Progress
  • Worker prompt constructed with all context
  • Appropriate tool scoping applied
  • Process spawned in background
  • Activity logged
When cleaning up:
  • Worker process terminated (or already exited)
  • Worktree removed (unless keeping for inspection)
  • Cleanup comment posted to issue
  • Activity logged
生成Worker时:
  • 工作树创建成功
  • 分支已创建/检出
  • Worker已在GitHub注册(任务评论)
  • 项目看板状态已更新为“进行中”
  • Worker提示词已包含所有上下文信息
  • 已应用合适的工具范围
  • 进程已在后台生成
  • 活动已记录
清理Worker时:
  • Worker进程已终止(或已自行退出)
  • 工作树已移除(除非保留用于检查)
  • 任务中已发布清理完成的评论
  • 活动已记录

Integration

集成

This skill is used by:
  • autonomous-orchestration
    - Main orchestration loop
This skill uses:
  • worker-protocol
    - Behavior injected into prompts
  • worker-handover
    - Handover context format
本技能被以下工具使用:
  • autonomous-orchestration
    - 主编排循环
本技能依赖以下工具:
  • worker-protocol
    - 注入到提示词中的行为规范
  • worker-handover
    - 移交上下文格式