worker-dispatch — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited worker-dispatch (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Spawns and manages worker Claude agents using the Task tool with `run_in_background: true`. Workers run as parallel background agents monitored via TaskOutput.
Core principle: Workers are isolated, scoped, and expendable. State lives in GitHub, not in workers.
Key optimization: Pre-extract issue context BEFORE spawning. Workers receive focused context, not raw issues.
CRITICAL: Every worker MUST have its own git worktree. Workers NEVER operate in the main repository.
Main Repository (./) ← Orchestrator only
│
└── Worktrees (isolated)
├── ../project-worker-123/ ← Worker for #123
├── ../project-worker-124/ ← Worker for #124
└── ../project-worker-125/ ← Worker for #125Orchestrator responsibility: Create worktree BEFORE spawning worker. Worker responsibility: Verify isolation BEFORE any work (see worker-protocol).
This prevents file clobbering between parallel workers.
| Type | Subagent | Purpose | When to Use |
|---|---|---|---|
| Implementation | general-purpose | Full feature work | Standard issue work |
| Research | Explore | Read-only investigation | Pre-implementation analysis, debugging |
| PR Resolution | general-purpose | Fix CI, merge PRs | Existing PR cleanup |
Extract issue context BEFORE spawning. Workers should not spend tokens re-reading issues.
extract_issue_context() {
local issue=$1
# Single API call to get everything
ISSUE_JSON=$(gh issue view "$issue" --json title,body,labels,comments,assignees)
TITLE=$(echo "$ISSUE_JSON" | jq -r '.title')
BODY=$(echo "$ISSUE_JSON" | jq -r '.body')
LABELS=$(echo "$ISSUE_JSON" | jq -r '[.labels[].name] | join(", ")')
# Extract acceptance criteria if present
ACCEPTANCE=$(echo "$BODY" | sed -n '/## Acceptance Criteria/,/^## /p' | head -20)
[ -z "$ACCEPTANCE" ] && ACCEPTANCE=$(echo "$BODY" | sed -n '/- \[/p' | head -10)
# Get latest handover if exists
HANDOVER=$(echo "$ISSUE_JSON" | jq -r '
[.comments[] | select(.body | contains("<!-- HANDOVER:START -->"))] | last | .body // ""
')
# Get recent progress comments
PROGRESS=$(echo "$ISSUE_JSON" | jq -r '
[.comments[-3:][].body] | join("\n---\n")
' | head -50)
}spawn_implementation_worker() {
local issue=$1
local attempt=${2:-1}
# Pre-extract context
extract_issue_context "$issue"
worker_id="worker-$(date +%s)-$issue"
issue_slug=$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | cut -c1-40)
branch="feature/$issue-$issue_slug"
worktree_path="../$(basename $PWD)-worker-$issue"
# Create worktree
git fetch origin main
git branch "$branch" origin/main 2>/dev/null || true
git worktree add "$worktree_path" "$branch"
}register_worker() {
local issue=$1 worker_id=$2 worktree=$3
gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
{\"worker_id\": \"$worker_id\", \"assigned_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}
<!-- /WORKER:ASSIGNED -->
**Worker Assigned:** \`$worker_id\` at $(date -u +%H:%M:%S)Z"
update_project_status "$issue" "In Progress"
}~50 lines with pre-extracted context:
construct_worker_prompt() {
local issue=$1 worker_id=$2 attempt=$3
# Uses pre-extracted: TITLE, ACCEPTANCE, HANDOVER, PROGRESS
cat <<PROMPT
Worker $worker_id | Issue #$issue | Attempt $attempt
## Task
$TITLE
## Requirements
$ACCEPTANCE
## Constraints
- Work ONLY on issue #$issue
- TDD: write tests first
- All tests must pass before PR
- Complete code review before PR (post artifact to issue)
- Max 100 turns - handover at 90+
## Exit Conditions
Return JSON when done:
\`\`\`json
{"status": "COMPLETED|BLOCKED|HANDOVER", "pr": null, "summary": "..."}
\`\`\`
| Status | Meaning |
|--------|---------|
| COMPLETED | PR created, tests pass |
| BLOCKED | Cannot proceed without external input |
| HANDOVER | Turn limit approaching, context posted |
## Progress Protocol
Post brief updates to issue. On handover, post full context with <!-- HANDOVER:START --> markers.
$([ -n "$HANDOVER" ] && echo "## Previous Handover
$HANDOVER")
$([ -n "$PROGRESS" ] && echo "## Recent Activity
$PROGRESS")
Begin implementation now.
PROMPT
}Task(
description: "Issue #[ISSUE] worker",
prompt: [FOCUSED_PROMPT],
subagent_type: "general-purpose",
run_in_background: true
)Returns: task_id for monitoring.
Use Explore subagent for read-only investigation before implementation:
construct_research_prompt() {
local issue=$1 question=$2
cat <<PROMPT
Research for issue #$issue: $TITLE
## Question
$question
## Scope
Investigate codebase to answer the question. Return structured findings.
## Output Format
\`\`\`json
{
"findings": ["key finding 1", "key finding 2"],
"relevant_files": ["path/to/file.ts"],
"patterns": ["existing pattern to follow"],
"concerns": ["potential issue to address"],
"recommendation": "summary recommendation"
}
\`\`\`
Do NOT modify any files. Research only.
PROMPT
}Task(
description: "Research for #[ISSUE]",
prompt: [RESEARCH_PROMPT],
subagent_type: "Explore",
run_in_background: true
)Use cases:
Spawn multiple workers in ONE message for concurrent execution:
## Dispatching 3 Workers
1. Extract context for each issue (sequential)
2. Invoke all Task tools in SAME message (parallel):
Task(description: "Issue #123 worker", prompt: [...], subagent_type: "general-purpose", run_in_background: true)
Task(description: "Issue #124 worker", prompt: [...], subagent_type: "general-purpose", run_in_background: true)
Task(description: "Issue #125 worker", prompt: [...], subagent_type: "general-purpose", run_in_background: true)
3. Store all returned task_idsTaskOutput(task_id: "[ID]", block: false, timeout: 1000)| Result | Meaning | Action |
|---|---|---|
| "Task is still running..." | Worker active | Continue monitoring |
| JSON with status | Worker complete | Parse result, update GitHub |
| Error | Worker failed | Check GitHub for context |
Parse completion:
RESULT=$(echo "$OUTPUT" | grep -oP '\{.*\}' | jq -r '.status')
PR=$(echo "$OUTPUT" | grep -oP '\{.*\}' | jq -r '.pr // empty')Resolve existing PRs (CI failures, missing reviews, merge):
construct_pr_worker_prompt() {
local pr=$1 worker_id=$2
cat <<PROMPT
PR Worker $worker_id | PR #$pr
## Mission
1. Check CI: \`gh pr checks $pr\`
2. If failing: investigate, fix, push
3. Verify review artifact exists on linked issue
4. If mergeable: \`gh pr merge $pr --squash --delete-branch\`
## Output
\`\`\`json
{"status": "MERGED|BLOCKED|HANDOVER", "summary": "..."}
\`\`\`
## Constraints
- Only fix CI-related issues
- Push to existing branch only
- Check for do-not-merge label
Begin with: \`gh pr checks $pr\`
PROMPT
}On completion (detected via TaskOutput):
cleanup_worker() {
local issue=$1 task_id=$2 result=$3
gh issue comment "$issue" --body "<!-- WORKER:ASSIGNED -->
{\"assigned\": false, \"cleared_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}
<!-- /WORKER:ASSIGNED -->
**Worker Complete:** $result"
case "$result" in
COMPLETED) update_project_status "$issue" "In Review" ;;
BLOCKED) update_project_status "$issue" "Blocked" ;;
HANDOVER) ;; # Keep In Progress, spawn replacement
esac
}When worker returns HANDOVER:
extract_issue_context (includes HANDOVER variable)Before spawning:
Prompt includes:
On completion:
Used by: autonomous-orchestration, claude-autonomous --pr
Uses: worker-protocol (behavior contract), worker-handover (context format), ci-monitoring (PR workers)
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.