| name | autonomous-orchestration |
| description | Use when user requests autonomous operation across multiple issues. Orchestrates parallel workers, monitors progress, handles SLEEP/WAKE cycles, and works until scope is complete without user intervention. |
Autonomous Orchestration
Overview
Orchestrates long-running autonomous work across multiple issues, spawning parallel workers, monitoring CI, and persisting state across sessions.
Core principle: GitHub is the source of truth. Workers are disposable. State survives restarts.
Announce at start: "I'm using autonomous-orchestration to work through [SCOPE]. Starting autonomous operation now."
Prerequisites
worker-dispatchskill for spawning workersworker-protocolskill for worker behaviorci-monitorskill for CI/WAKE handling- Git worktrees support (workers use isolated worktrees)
- GitHub CLI (
gh) authenticated
Immediate Start (User Consent Implied)
The user's request for autonomous operation IS their consent. No additional confirmation is required.
When the user requests autonomous work:
- Identify scope - Parse user request for milestone, epic, specific issues, or "all"
- Announce intent - Briefly state what you're about to do
- Start immediately - Begin orchestration without waiting for additional input
## Starting Autonomous Operation
**Scope:** [MILESTONE/EPIC/ISSUES or "all open issues"]
**Workers:** Up to 5 parallel
**Mode:** Continuous until complete
Beginning work now...
Do NOT ask for "PROCEED" or any confirmation. The user asked for autonomous operation - that is the confirmation.
Automatic Scope Detection
When the user requests autonomous operation without specifying a scope:
Priority Order
- User-specified scope - If user mentions specific issues, epics, or milestones, use those
- Urgent/High Priority standalone issues - Issues with
priority:urgentorpriority:highlabels that are NOT part of an epic - Epic-based sequential work - Work through epics in order, completing all issues within each epic before moving to the next
- Remaining standalone issues - Any issues not part of an epic
Scope Detection Logic
detect_work_scope() {
# 1. Check for urgent/high priority standalone issues first
PRIORITY_ISSUES=$(gh issue list --state open \
--label "priority:urgent,priority:high" \
--json number,labels \
--jq '[.[] | select(.labels | map(.name) | any(startswith("epic-")) | not)] | .[].number')
if [ -n "$PRIORITY_ISSUES" ]; then
echo "priority_standalone"
echo "$PRIORITY_ISSUES"
return
fi
# 2. Get epics in order (by creation date or specified priority)
EPICS=$(gh issue list --state open --label "type:epic" \
--json number,title,createdAt \
--jq 'sort_by(.createdAt) | .[].number')
if [ -n "$EPICS" ]; then
echo "epics"
echo "$EPICS"
return
fi
# 3. Fall back to all open issues
ALL_ISSUES=$(gh issue list --state open --json number --jq '.[].number')
echo "all_issues"
echo "$ALL_ISSUES"
}
Working Through Epics
When working through epics sequentially:
- Select first incomplete epic - Find the epic with the earliest creation date that still has open child issues
- Get all epic issues - Query for issues with that epic's label
- Work until epic complete - All issues in the epic are closed
- Move to next epic - Repeat until all epics are complete
- Then standalone issues - Finally address any non-epic issues
get_next_epic_scope() {
# Find first epic with open issues
for epic_num in $(gh issue list --state open --label "type:epic" \
--json number,createdAt --jq 'sort_by(.createdAt) | .[].number'); do
# Get epic label
EPIC_LABEL=$(gh issue view "$epic_num" --json labels \
--jq '.labels[] | select(.name | startswith("epic-")) | .name')
# Check if epic has open issues
OPEN_COUNT=$(gh issue list --state open --label "$EPIC_LABEL" \
--json number --jq 'length')
if [ "$OPEN_COUNT" -gt 0 ]; then
echo "$EPIC_LABEL"
return
fi
done
echo "" # No epics with open issues
}
Continuous Operation Until Complete
Autonomous operation continues until ALL of:
- No open issues remain in scope
- No open PRs awaiting merge
- No issues in "In Progress" or "In Review" status
The operation does NOT pause for:
- Progress updates
- Confirmation between issues
- Switching between epics
- Any user input (unless blocked by a fatal error)
State Management (Project Board is THE Source of Truth)
Core principle: The GitHub Project Board is the ONLY source of truth for work state. NOT labels. NOT comments. The project board.
State is tracked via:
- GitHub Project Board Status Field - THE source of truth for all state
- GitHub Issue Comments - Activity log and context (supplementary)
- Labels - Only for lineage tracking, NOT for state
Project Board Status Field (THE Source of Truth)
| Status | Description | Transition From |
|---|---|---|
| Backlog | Not ready for work | (initial) |
| Ready | Ready for work, pending assignment | Backlog |
| In Progress | Worker assigned and working | Ready, Blocked |
| In Review | PR created, awaiting merge | In Progress |
| Blocked | Cannot proceed | Any |
| Done | Completed | In Review |
Labels (Supplementary Only - NOT for State)
| Label | Purpose | NOT Used For |
|---|---|---|
review-finding |
Origin tracking | State |
spawned-from:#N |
Lineage tracking | State |
depth:N |
Recursion limit | State |
epic-[name] |
Epic grouping | State |
CRITICAL: Do NOT use labels like status:pending or status:in-progress. Use the project board.
State Queries via Project Board
# Get pending issues in scope (Status = Ready)
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "Ready") | .content.number'
# Get in-progress issues (Status = In Progress)
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "In Progress") | .content.number'
# Get blocked issues (Status = Blocked)
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "Blocked") | .content.number'
# Get issues in review (Status = In Review)
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "In Review") | .content.number'
# Count by status
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq '[.items[] | select(.status.name == "In Progress")] | length'
# Get child issues via label (lineage only, not state)
gh issue list --label "spawned-from:#123" --json number,state --jq '.'
State Updates via Project Board
# Helper function to update project board status
update_project_status() {
local issue=$1
local new_status=$2 # Ready, In Progress, In Review, Blocked, Done
# Get item ID
ITEM_ID=$(gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r ".items[] | select(.content.number == $issue) | .id")
if [ -z "$ITEM_ID" ] || [ "$ITEM_ID" = "null" ]; then
echo "ERROR: Issue #$issue not in project board. Add it first."
return 1
fi
# Get project and field IDs
PROJECT_ID=$(gh project list --owner "$GH_PROJECT_OWNER" --format json | \
jq -r ".projects[] | select(.number == $GITHUB_PROJECT_NUM) | .id")
STATUS_FIELD_ID=$(gh project field-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.fields[] | select(.name == "Status") | .id')
OPTION_ID=$(gh project field-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r ".fields[] | select(.name == \"Status\") | .options[] | select(.name == \"$new_status\") | .id")
# Update status
gh project item-edit --project-id "$PROJECT_ID" --id "$ITEM_ID" \
--field-id "$STATUS_FIELD_ID" --single-select-option-id "$OPTION_ID"
# Verify update
ACTUAL=$(gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r ".items[] | select(.content.number == $issue) | .status.name")
if [ "$ACTUAL" != "$new_status" ]; then
echo "ERROR: Status update failed. Expected $new_status, got $ACTUAL"
return 1
fi
echo "Updated issue #$issue status to $new_status"
return 0
}
### Orchestration Comment Template
Post to milestone/epic tracking issue:
```markdown
## Orchestration Status
**ID:** orch-[TIMESTAMP]
**Scope:** [MILESTONE/EPIC]
**Started:** [ISO_TIMESTAMP]
**Last Update:** [ISO_TIMESTAMP]
### Queue Status
| Status | Count | Issues |
|--------|-------|--------|
| Pending | [N] | #1, #2, #3 |
| In Progress | [N] | #4, #5 |
| Awaiting Dependencies | [N] | #6 (→ #7, #8) |
| Completed | [N] | #9, #10 |
| Blocked | [N] | #11 |
### Active Workers
| Worker | Issue | Started | Status |
|--------|-------|---------|--------|
| worker-001 | #4 | [TIME] | Implementing |
| worker-002 | #5 | [TIME] | In Review |
### Deviation Tracking
Issues requiring return after child completion:
| Parent | Status | Children | Return When |
|--------|--------|----------|-------------|
| #6 | Awaiting | #7, #8 | All children closed |
---
*Updated: [TIMESTAMP]*
Deviation Handling
When a worker creates child issues (e.g., deferred review findings):
- Mark parent with
status:awaiting-dependencies - Add
spawned-from:#PARENTlabel to children - Add
depth:Nlabel (N = parent_depth + 1) - Post deviation comment to parent issue:
## Deviation: Awaiting Child Issues
**Status:** `awaiting-dependencies`
**Return When:** All children closed
### Child Issues Created
| # | Title | Created From | Status |
|---|-------|--------------|--------|
| #7 | [Title] | Review finding | Open |
| #8 | [Title] | Review finding | Open |
**Process:** Children follow full `issue-driven-development` workflow.
When all children are closed, this issue will be resumed.
---
*Worker: [WORKER_ID]*
Child Issue Lifecycle
CRITICAL: Child issues (from review findings) MUST follow the FULL issue-driven-development process:
- They get their own workers
- They go through all 13 steps
- They have their own code reviews
- Their findings create grandchildren if needed
- They cannot skip any workflow step
The depth:N label tracks lineage to prevent infinite loops (max depth: 5).
Deviation Resolution
When monitoring for deviation resolution:
# Check if all children of #123 are closed
OPEN_CHILDREN=$(gh issue list --label "spawned-from:#123" --state open --json number --jq 'length')
if [ "$OPEN_CHILDREN" = "0" ]; then
# All children closed, resume parent
gh issue edit 123 --remove-label "status:awaiting-dependencies" --add-label "status:pending"
gh issue comment 123 --body "## Deviation Resolved
All child issues are now closed. This issue is ready to resume.
**Children Completed:**
$(gh issue list --label "spawned-from:#123" --state closed --json number,title --jq '.[] | "- #\(.number): \(.title)"')
---
*Orchestrator: [ORCHESTRATION_ID]*"
fi
Orchestration Loop
┌─────────────────────────────────────────────────────────────────────────────┐
│ MAIN LOOP │
└─────────────────────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────────────┼─────────────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ CHECK WORKERS │ │ CHECK CI/PRs │ │ SPAWN/MANAGE │
│ │ │ │ │ │
│ - Still alive?│ │ - CI status? │ │ - Capacity? │
│ - Completed? │ │ - Ready merge?│ │ - Next issue? │
│ - Handover? │ │ - Failed? │ │ - Spawn worker│
│ - Failed? │ │ │ │ │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└───────────────────────────────┼───────────────────────────────┘
│
▼
┌───────────────────┐
│ EVALUATE STATE │
│ │
│ All done? → Exit │
│ All waiting? → │
│ SLEEP │
│ Work to do? → │
│ Continue │
└───────────────────┘
Loop Implementation (Project Board-Native)
# Helper functions using PROJECT BOARD as state store (NOT labels)
get_pending_issues() {
# Query project board for Status = Ready
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "Ready") | .content.number'
}
get_in_progress_issues() {
# Query project board for Status = In Progress
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "In Progress") | .content.number'
}
get_blocked_issues() {
# Query project board for Status = Blocked
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "Blocked") | .content.number'
}
get_in_review_issues() {
# Query project board for Status = In Review
gh project item-list "$GITHUB_PROJECT_NUM" --owner "$GH_PROJECT_OWNER" \
--format json | jq -r '.items[] | select(.status.name == "In Review") | .content.number'
}
check_deviation_resolution() {
local issue=$1
# Check if all children (via label) are closed
local open_children=$(gh issue list --label "spawned-from:#$issue" --state open --json number --jq 'length')
if [ "$open_children" = "0" ]; then
# All children closed, resume parent via PROJECT BOARD (not labels)
update_project_status "$issue" "Ready"
gh issue comment "$issue" --body "## Deviation Resolved
All child issues are now closed. Ready to resume.
**Project Status:** Ready (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
return 0
fi
return 1
}
mark_issue_in_progress() {
local issue=$1
local worker=$2
# Update PROJECT BOARD status (not labels)
update_project_status "$issue" "In Progress"
gh issue comment "$issue" --body "## Worker Assigned
**Worker:** \`$worker\`
**Started:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
**Project Status:** In Progress (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
}
mark_issue_in_review() {
local issue=$1
local pr=$2
# Update PROJECT BOARD status
update_project_status "$issue" "In Review"
gh issue comment "$issue" --body "## PR Created
**PR:** #$pr
**Project Status:** In Review (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
}
mark_issue_blocked() {
local issue=$1
local reason=$2
# Update PROJECT BOARD status
update_project_status "$issue" "Blocked"
gh issue comment "$issue" --body "## Issue Blocked
**Reason:** $reason
**Project Status:** Blocked (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
}
mark_issue_done() {
local issue=$1
# Update PROJECT BOARD status
update_project_status "$issue" "Done"
gh issue comment "$issue" --body "## Issue Complete
**Project Status:** Done (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
}
# Main orchestration loop
while true; do
# Post status update to tracking issue
post_orchestration_status
# ─────────────────────────────────────────────────────────────
# 1. CHECK FOR ISSUES NEEDING STATUS SYNC
# ─────────────────────────────────────────────────────────────
# Check if any issues with open children need to be resumed
for issue in $(gh issue list --label "spawned-from:" --state closed --json number --jq '.[].number' 2>/dev/null | sort -u); do
parent=$(gh issue view "$issue" --json labels --jq '.labels[] | select(.name | startswith("spawned-from:")) | .name' | sed 's/spawned-from:#//')
if [ -n "$parent" ]; then
check_deviation_resolution "$parent"
fi
done
# ─────────────────────────────────────────────────────────────
# 2. CHECK CI/PRs (with review verification)
# ─────────────────────────────────────────────────────────────
for pr in $(gh pr list --json number --jq '.[].number'); do
ci_status=$(gh pr checks "$pr" --json state --jq '.[].state' | sort -u)
if echo "$ci_status" | grep -q "SUCCESS"; then
# Verify review artifact exists before merge
ISSUE=$(gh pr view "$pr" --json body --jq '.body' | grep -oE 'Closes #[0-9]+' | grep -oE '[0-9]+')
REVIEW_EXISTS=$(gh api "/repos/$OWNER/$REPO/issues/$ISSUE/comments" \
--jq '[.[] | select(.body | contains("<!-- REVIEW:START -->"))] | length' 2>/dev/null || echo "0")
if [ "$REVIEW_EXISTS" = "0" ]; then
gh pr comment "$pr" --body "⚠️ **Merge Blocked:** No review artifact found in issue #$ISSUE.
Complete \`comprehensive-review\` and post artifact to issue before merge."
continue
fi
if [ "$AUTO_MERGE" = "true" ]; then
gh pr merge "$pr" --squash --auto
# Update project board status to Done
mark_issue_done "$ISSUE"
gh issue comment "$ISSUE" --body "## PR Merged
PR #$pr merged automatically after CI passed.
**Project Status:** Done (updated in project board)
---
*Orchestrator: $ORCHESTRATION_ID*"
fi
elif echo "$ci_status" | grep -q "FAILURE"; then
handle_ci_failure "$pr"
fi
done
# ─────────────────────────────────────────────────────────────
# 3. SPAWN NEW WORKERS (respecting capacity)
# ─────────────────────────────────────────────────────────────
# Count via PROJECT BOARD (not labels)
active_count=$(get_in_progress_issues | wc -l | tr -d ' ')
while [ "$active_count" -lt 5 ]; do
# Get next issue from PROJECT BOARD (not labels)
next_issue=$(get_pending_issues | head -1)
if [ -z "$next_issue" ]; then
break # No more issues to work
fi
worker_id="worker-$(date +%s)-$next_issue"
# Update PROJECT BOARD status before spawning
mark_issue_in_progress "$next_issue" "$worker_id"
spawn_worker "$next_issue" "$worker_id"
active_count=$((active_count + 1))
done
# ─────────────────────────────────────────────────────────────
# 4. EVALUATE STATE (via PROJECT BOARD)
# ─────────────────────────────────────────────────────────────
# All counts come from PROJECT BOARD, not labels
pending=$(get_pending_issues | wc -l | tr -d ' ')
in_progress=$(get_in_progress_issues | wc -l | tr -d ' ')
in_review=$(get_in_review_issues | wc -l | tr -d ' ')
blocked=$(get_blocked_issues | wc -l | tr -d ' ')
open_prs=$(gh pr list --json number --jq 'length')
if [ "$pending" -eq 0 ] && [ "$in_progress" -eq 0 ] && [ "$in_review" -eq 0 ] && [ "$open_prs" -eq 0 ]; then
# All done!
complete_orchestration
exit 0
fi
if [ "$in_progress" -eq 0 ] && [ "$pending" -eq 0 ] && [ "$open_prs" -gt 0 ]; then
# Nothing to do but wait for CI
enter_sleep "waiting_for_ci"
exit 0 # Will be woken by wake mechanism
fi
if [ "$in_progress" -eq 0 ] && [ "$pending" -eq 0 ] && [ "$blocked" -gt 0 ]; then
# All remaining work is blocked
enter_sleep "all_remaining_blocked"
exit 0
fi
# ─────────────────────────────────────────────────────────────
# 5. BRIEF PAUSE BEFORE NEXT ITERATION
# ─────────────────────────────────────────────────────────────
sleep 30 # Check every 30 seconds when active
done
Scope Types
Milestone
# Get issues in milestone
gh issue list --milestone "v1.0.0" --state open --json number --jq '.[].number'
Epic
# Get issues with epic label
gh issue list --label "epic-dark-mode" --state open --json number --jq '.[].number'
Issue List
# Explicit list
ISSUES="123 124 125 126"
Unbounded (All Open Issues)
When user requests autonomous work without specifying scope, or explicitly asks to work on "everything" or "all issues":
## Starting Unbounded Autonomous Operation
**Scope:** All open issues in repository
**Workers:** Up to 5 parallel
**Mode:** Continuous until all issues resolved or blocked
Beginning with priority/urgent issues, then working through epics sequentially...
Do NOT ask for "UNBOUNDED" confirmation. The user's request is their consent.
# All open issues
gh issue list --state open --json number --jq '.[].number'
Failure Handling
Retry with Research
Workers that fail do NOT immediately become blocked. The cycle is:
Attempt 1 (Failed)
│
▼
Research Cycle 1 (via research-after-failure skill)
│
▼
Attempt 2 (Failed)
│
▼
Research Cycle 2 (deeper research)
│
▼
Attempt 3 (Failed)
│
▼
Research Cycle 3 (exhaustive research)
│
▼
Attempt 4 (Failed)
│
▼
ONLY NOW: Mark as Blocked
Research Cycle Implementation
trigger_research_cycle() {
worker=$1
issue=$(get_worker_issue "$worker")
cycle=$(get_research_cycle_count "$issue")
# Spawn research worker (read-only tools)
claude -p "$(cat <<PROMPT
You are a research agent investigating why issue #$issue is failing.
## Research Cycle: $((cycle + 1))
## Previous Attempts
$(get_attempt_history "$issue")
## Your Task
1. Analyze the failure logs
2. Research the problem thoroughly
3. Document findings in issue #$issue
4. Propose a new approach
## Constraints
- You are READ-ONLY - do not modify code
- Focus on understanding, not fixing
- Be thorough - this is attempt $((cycle + 1))
Begin by reading the worker logs and issue comments.
PROMPT
)" \
--allowedTools "Read,Grep,Glob,WebFetch,WebSearch,mcp__memory__*" \
--max-turns 50 \
--output-format json \
> ".orchestrator/logs/research-$issue-$cycle.log" 2>&1
# After research, spawn new worker with research context
increment_research_cycle "$issue"
spawn_worker "$issue" --with-research-context
}
Blocked Determination
An issue is only marked blocked when:
- Multiple research cycles completed (3+)
- Research concludes "impossible without external input"
- Examples of true blockers:
- Missing API credentials
- Requires decision from human
- External service unavailable
- Dependency on unreleased feature
mark_issue_blocked() {
issue=$1
reason=$2
gh issue comment "$issue" --body "## 🚫 Issue Blocked
**Reason:** $reason
**Attempts:** $(get_attempt_count "$issue")
**Research Cycles:** $(get_research_cycle_count "$issue")
**Why Blocked:**
This issue cannot proceed without external intervention.
**Required Action:**
$reason
---
*Orchestration ID: $ORCHESTRATION_ID*"
gh issue edit "$issue" --add-label "blocked"
update_queue_blocked "$issue"
}
Git Worktree Isolation
Workers use separate git worktrees to avoid conflicts:
# Create worktree for worker
create_worker_worktree() {
issue=$1
worker_id=$2
branch="feature/$issue-$(slugify_issue_title "$issue")"
worktree_path="../$(basename $PWD)-worker-$issue"
# Create branch if not exists
git branch "$branch" 2>/dev/null || true
# Create worktree
git worktree add "$worktree_path" "$branch"
echo "$worktree_path"
}
# Cleanup worktree after worker done
cleanup_worker_worktree() {
worktree_path=$1
# Remove worktree
git worktree remove "$worktree_path" --force
# Prune worktree references
git worktree prune
}
SLEEP/WAKE
Entering SLEEP
enter_sleep() {
reason=$1
# Post sleep status to tracking issue (GitHub-native)
TRACKING_ISSUE=$(gh issue list --label "orchestration-tracking" --json number --jq '.[0].number')
WAITING_PRS=$(gh pr list --json number --jq '[.[].number] | join(", ")')
WAITING_CHILDREN=$(gh issue list --label "status:awaiting-dependencies" --json number --jq '[.[].number] | join(", ")')
gh issue comment "$TRACKING_ISSUE" --body "## Orchestration Sleeping
**Reason:** $reason
**Since:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
### Waiting On
| Type | Items |
|------|-------|
| PRs in CI | $WAITING_PRS |
| Child Issues | $WAITING_CHILDREN |
### Wake Mechanisms
- **Polling:** Every 5 minutes
- **Manual:** \`claude --resume $RESUME_SESSION\`
---
*Orchestrator: $ORCHESTRATION_ID*"
# Report to user
echo "## Orchestration Sleeping"
echo ""
echo "**Reason:** $reason"
echo "**Waiting on PRs:** $WAITING_PRS"
echo "**Waiting on children:** $WAITING_CHILDREN"
echo ""
echo "Wake mechanisms active:"
echo "- Polling: Every 5 minutes"
echo "- Manual: claude --resume $RESUME_SESSION"
}
WAKE Mechanisms
See ci-monitor skill for detailed WAKE implementations:
- Polling script
- SessionStart hook
- Webhook server (with port safety)
Status Reporting (GitHub-Native)
Status is posted as a comment on the tracking issue:
post_orchestration_status() {
TRACKING_ISSUE=$(gh issue list --label "orchestration-tracking" --json number --jq '.[0].number')
# Query all state from GitHub
PENDING=$(gh issue list --milestone "$MILESTONE" --label "status:pending" --json number --jq '[.[].number] | join(", ")')
IN_PROGRESS=$(gh issue list --milestone "$MILESTONE" --label "status:in-progress" --json number,title --jq '.[] | "| #\(.number) | \(.title) |"')
AWAITING=$(gh issue list --milestone "$MILESTONE" --label "status:awaiting-dependencies" --json number --jq '[.[].number] | join(", ")')
BLOCKED=$(gh issue list --milestone "$MILESTONE" --label "status:blocked" --json number --jq '[.[].number] | join(", ")')
COMPLETED=$(gh issue list --milestone "$MILESTONE" --state closed --json number --jq '[.[].number] | join(", ")')
OPEN_PRS=$(gh pr list --json number,title,statusCheckRollup --jq '.[] | "| #\(.number) | \(.title) | \(.statusCheckRollup | map(.state) | unique | join(",")) |"')
gh issue comment "$TRACKING_ISSUE" --body "## Orchestration Status
**ID:** $ORCHESTRATION_ID
**Scope:** $MILESTONE
**Updated:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
### Issue Status
| Status | Issues |
|--------|--------|
| Pending | $PENDING |
| In Progress | (see below) |
| Awaiting Dependencies | $AWAITING |
| Blocked | $BLOCKED |
| Completed | $COMPLETED |
### Active Workers
| Issue | Title |
|-------|-------|
$IN_PROGRESS
### Open PRs
| PR | Title | CI Status |
|----|-------|-----------|
$OPEN_PRS
### Deviation Tracking
Issues waiting on children:
\`\`\`
$(for issue in $(gh issue list --label "status:awaiting-dependencies" --json number --jq '.[].number'); do
children=$(gh issue list --label "spawned-from:#$issue" --state open --json number --jq '[.[].number] | join(", ")')
echo "#$issue → waiting on: $children"
done)
\`\`\`
---
*Updated automatically by orchestrator*"
}
Progress Display (Posted to Tracking Issue)
## Orchestration Status
**ID:** orch-2025-12-02-001
**Scope:** Milestone v1.0.0
**Updated:** 2025-12-02T14:30:00Z
### Issue Status
| Status | Issues |
|--------|--------|
| Pending | #149, #150, #151 |
| In Progress | (see below) |
| Awaiting Dependencies | #146 |
| Blocked | #148 |
| Completed | #135, #136, #137, #138, #139, #140, #141, #147 |
### Active Workers
| Issue | Title |
|-------|-------|
| #142 | Add dark mode toggle |
| #143 | Export functionality |
| #144 | Settings page redesign |
| #145 | API rate limiting |
### Open PRs
| PR | Title | CI Status |
|----|-------|-----------|
| #201 | feat: Dark mode (#142) | PENDING |
| #202 | feat: Export (#143) | SUCCESS |
### Deviation Tracking
Issues waiting on children:
#146 → waiting on: #152, #153
---
*Updated automatically by orchestrator*
Abort Handling
User: STOP
## Aborting Orchestration
1. Signaling workers to save state and exit...
2. Workers completing current operation (max 60s)...
3. Saving orchestration state...
4. Preserving worktrees for inspection...
**State Saved**
Resume: `claude --resume [SESSION_ID]`
Clean up worktrees: `git worktree prune`
**Worker states at abort:**
| Worker | Issue | Status | Can Resume |
|--------|-------|--------|------------|
| w-012 | #142 | Mid-implementation | Yes |
| w-013 | #143 | Testing | Yes |
Rollback (Safety Net)
Auto-merge is enabled with git rollback as the safety net:
rollback_pr() {
pr=$1
merge_commit=$(gh pr view "$pr" --json mergeCommit --jq '.mergeCommit.oid')
if [ -n "$merge_commit" ]; then
git revert "$merge_commit" --no-edit
git push
gh issue comment "$(get_pr_issue "$pr")" --body "## ⚠️ PR Reverted
PR #$pr was automatically reverted due to post-merge issues.
**Reverted commit:** $merge_commit
**Reason:** [REASON]
Issue will be re-queued for another attempt."
requeue_issue "$(get_pr_issue "$pr")"
fi
}
Checklist
Before starting orchestration:
- User requested autonomous operation (no additional confirmation needed)
- Scope identified (explicit from user, or defaulting to priority/urgent then epics)
- Scope validated (issues exist and are actionable)
- Git worktrees available (
git worktree list) - GitHub CLI authenticated (
gh auth status) - No uncommitted changes in main worktree
- Required labels created (
scripts/create-labels.sh) - Tracking issue created with
orchestration-trackinglabel
During orchestration:
- Workers spawned with worktree isolation
- Worker status tracked via GitHub labels
- CI status monitored
- Review artifacts verified before PR merge
- Failed workers trigger research cycles
- Handovers happen at turn limit
- SLEEP entered when only waiting on CI or children
- Deviation resolution checked each loop
- Child issues follow full
issue-driven-developmentprocess - Status posted to tracking issue
Review Enforcement
CRITICAL: The orchestrator verifies review compliance:
Before allowing PR merge:
- Review artifact exists in issue comments
- Review status is COMPLETE
- Unaddressed findings = 0
Child issues (from deferred findings):
- Follow full
issue-driven-developmentprocess - Have their own code reviews
- Cannot skip workflow steps
- Track via
spawned-from:#Nlabel
- Follow full
Deviation handling:
- Parent marked
status:awaiting-dependencies - Resumes only when all children closed
- Orchestrator monitors deviation resolution
- Parent marked
Integration
This skill coordinates:
worker-dispatch- Spawning workersworker-protocol- Worker behavior (includes review gate)worker-handover- Context passingci-monitor- CI and WAKE handlingresearch-after-failure- Research cyclesissue-driven-development- Worker follows this (all 13 steps)comprehensive-review- Workers must complete before PRapply-all-findings- All findings addresseddeferred-finding- Child issue creationreview-gate- PR creation verificationproject-board-enforcement- ALL state queries and updates
This skill uses PROJECT BOARD as the source of truth:
- Project Board Status field - THE source of truth for all state
- Issue comments for activity log (supplementary)
spawned-from:#Nlabels for lineage (supplementary, NOT for state)depth:Nlabels for recursion limit (supplementary)- Tracking issue for orchestration status
CRITICAL: Do NOT use labels for state tracking. Use project board.