Agent skill
worker-dispatch
Use to spawn isolated worker processes for autonomous issue work. Creates git worktrees, constructs worker prompts, and handles worker lifecycle.
Install this agent skill to your Project
npx add-skill https://github.com/troykelly/codex-skills/tree/main/skills/worker-dispatch
SKILL.md
Worker Dispatch
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]."
State Management
CRITICAL: Worker state is stored in GitHub. NO local state files for tracking.
| State | Location | Purpose |
|---|---|---|
| Worker assignment | Issue comment | Who is working on what |
| Worker status | Project Board | In Progress, Done, etc. |
| Process logs | Local (ephemeral) | Debugging only |
| Process PIDs | Local (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 Architecture
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)
Spawning a Worker
Step 1: Create Worktree
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"
}
Step 2: Register Worker in GitHub
Post worker assignment to the issue as a structured comment:
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"
}
Step 3: Construct Worker Prompt
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 ID:** $worker_id
- **Issue:** #$issue
- **Attempt:** $attempt
- **Orchestration:** $ORCHESTRATION_ID
## 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
## 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
## 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)
## Progress Reporting
Update the issue with comments as you work.
## On Completion
Post completion comment to the issue.
## 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)
## Begin
Start by reading issue #$issue to understand the requirements.
PROMPT
}
Step 4: Spawn Process
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"
}
Complete Spawn Function
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"
}
Tool Scoping
Standard Worker (Full Implementation)
--allowedTools "Bash,Read,Edit,Write,Grep,Glob,mcp__git__*,mcp__github__*,mcp__memory__*,WebFetch,WebSearch"
Research Worker (Read-Only)
--allowedTools "Read,Grep,Glob,WebFetch,WebSearch,mcp__memory__*,mcp__github__get_issue,mcp__github__get_pull_request"
Review Worker (No Edits)
--allowedTools "Read,Grep,Glob,Bash(pnpm test:*),Bash(pnpm lint:*)"
Checking Worker Status
Check both GitHub and local PID:
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
}
Worker Cleanup
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"
}
Replacement Worker (After Handover)
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"
}
Parallel Dispatch
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
}
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
Integration
This skill is used by:
autonomous-orchestration- Main orchestration loop
This skill uses:
worker-protocol- Behavior injected into promptsworker-handover- Handover context format
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
hook-development
Use when the user wants to create Codex workflow hooks (pre/post run gates, tool-use validators, stop checks) or needs guidance on hook scripts and hooks.json configuration.
sentry-setup-ai-monitoring
Setup Sentry AI Agent Monitoring in any project. Use this when asked to add AI monitoring, track LLM calls, monitor AI agents, or instrument OpenAI/Anthropic/Vercel AI/LangChain/Google GenAI. Automatically detects installed AI SDKs and configures the appropriate Sentry integration.
agent-development
Use when the user wants to design Codex agent equivalents (specialized workers/profiles/prompt files), define triggering conditions, or build reusable agent prompts and validation tools.
skill-development
Use when the user wants to create or refine Codex skills, improve skill descriptions, organize skill resources, or follow Codex skill best practices.
sentry-setup-logging
Setup Sentry Logging in any project. Use this when asked to add Sentry logs, enable structured logging, setup console log capture, or integrate logging with Sentry. Supports JavaScript, TypeScript, Python, Ruby, React, Next.js, and other frameworks.
frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Didn't find tool you were looking for?