Claude-corps auto-run
Autonomous dispatch-reconcile loop for batch task processing. Use with /auto-run --through <id> to execute tasks unattended. Requires Linear MCP or tasks to exist. Supports --resume for checkpoint recovery and --skip-milestone-review.
git clone https://github.com/josephneumann/claude-corps
T=$(mktemp -d) && git clone --depth=1 https://github.com/josephneumann/claude-corps "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/auto-run" ~/.claude/skills/josephneumann-claude-corps-auto-run && rm -rf "$T"
skills/auto-run/SKILL.mdAutonomous Orchestrator Loop: $ARGUMENTS
You are an autonomous orchestrator. You dispatch workers, handle their completions, reconcile results, and dispatch newly unblocked tasks — repeating until all work is done or limits are reached.
Workers run in isolated git worktrees via the Agent tool. Each worker gets its own filesystem — no conflicts possible.
Section 1: Argument Parsing
Arguments:
$ARGUMENTS
Parse the following flags:
— Stop after N dispatch rounds (default: unlimited)--max-batches N
— Stop after H hours (default: unlimited)--max-hours H
— Max parallel workers per batch (default: 3)--max-concurrent N
— Execute tasks one at a time directly on the current branch (no worktrees, no PRs per task). Use for dependent/sequential tasks. Passes--sequential
to--sequential
./dispatch
— Show what would be dispatched without acting--dry-run
— Resume from checkpoint (skip orient)--resume
— Skip the milestone review phase after tasks complete--skip-milestone-review
— Max milestone review iterations (default: 5)--milestone-review-iterations N
— Complete everything needed to finish this task, then stop--through <task-id>
— Complete all tasks within this epic, then stop--epic <epic-id>
— Only dispatch these specific tasks (and their blockers)--only <id1> <id2> ...
Section 2: Initial Setup
Check for Checkpoint
Read checkpoint at
docs/auto-run-checkpoint.json (resolve from main repo root via git worktree list | head -1 | awk '{print $1}').
If
AND checkpoint exists with status "running":--resume
- Read checkpoint state (including scope config)
- Log resumption context: batch number, completed list, in-progress list, scope
- Check if any previously in-progress tasks have since completed — look for session summaries:
ls docs/session_summaries/<task-id>*.txt 2>/dev/null - If summaries found → reconcile them first:
Call
via Skill tool/reconcile-summary --yes - Skip orient, proceed to dispatch loop (Section 3)
If fresh start (no checkpoint or no
):--resume
- Run
via Skill tool/orient - Resolve scope (see Section 2.1)
- Write initial checkpoint
Write checkpoint JSON to
docs/auto-run-checkpoint.json with:
: 2version
: "running"status
: current ISO8601 timestampstart_time
: parsed flags (max_batches, max_hours, max_concurrent)config
: resolved scope (see 2.1)scope
: 0batch_number
: { completed: [], failed: [], in_progress: [] }tasks
: { total_dispatched: 0, total_completed: 0, total_failed: 0, total_batches: 0 }stats
2.1 Resolve Scope
Determine which tasks are in-scope for this auto-run:
If
:
Walk the dependency graph backward from --through <task-id>
<task-id> to find all transitive blockers. Call get_issue(id=<task-id>, includeRelations=true) and recursively resolve each blockedBy entry's own blockers.
Build a set of all task IDs that must complete for
<task-id> to be unblocked and completable. Include <task-id> itself. Store as scope.task_ids in checkpoint. Set scope.mode to "through" and scope.target to <task-id>.
If
:
List all tasks in this project by calling --epic <project-name>
list_issues(project=<project-name>).
Store all issue IDs as
scope.task_ids. Set scope.mode to "epic" and scope.target to <project-name>.
If
:
Use exactly those task IDs. Also resolve their transitive blockers (tasks that must complete first) and include those in scope. Store as --only <id1> <id2> ...
scope.task_ids. Set scope.mode to "only".
If no scope flags:
scope.task_ids = null (all ready tasks are in scope). Set scope.mode to "all".
Log the resolved scope:
Auto-run scope: N tasks [list IDs]. Target: <task-id or epic-id or "all">
First Dispatch
- Query ready tasks: call
, then for each calllist_issues(state=Todo)
and filter to those with emptyget_issue(includeRelations=true)
arraysblockedBy - Filter ready tasks to only those in
(if set; if null, use all)scope.task_ids - If no in-scope ready tasks:
- Check if target task is already closed → exit with completion report
- Otherwise report "No ready tasks in scope" and exit
- If ready tasks exist:
- Calculate count = min(ready_count, max_concurrent)
- If
: Call--sequential
via Skill tool. This dispatches tasks one at a time in foreground (no worktrees). The orchestrator blocks until each task completes./dispatch --sequential <specific-task-ids> --no-plan --yes - If parallel (default): Call
via Skill tool, passing only in-scope task IDs/dispatch <specific-task-ids> --count <count> --no-plan --yes
- Update checkpoint: add dispatched tasks to
, setin_progressbatch_number: 1
Section 3: Main Loop
If
: The loop is synchronous. Each --sequential
/dispatch --sequential call blocks until all tasks in that batch complete. After completion, proceed directly to Step B (Reconcile) → Step B.5 (Pull) → Step D (Dispatch Next). No background notifications needed.
If parallel (default): The loop is driven by background agent completion notifications. When a worker finishes (you are notified of its completion), process the result:
Step A — Identify Completion
When notified of a worker's completion, extract the task ID from the worker's name or result. Check for session summary:
ls docs/session_summaries/<task-id>*.txt 2>/dev/null
Step B — Reconcile
If summary exists: Call
/reconcile-summary <task-id> --yes via Skill tool.
After reconciliation, check if the completed task touched frontend files:
# Check the session summary for frontend file extensions grep -E '\.(tsx|jsx|vue|svelte|html|css|scss)' docs/session_summaries/<task-id>*.txt 2>/dev/null
If frontend files were modified, note for milestone review:
Frontend changes detected in <task-id> — Playwright browser verification will run during milestone review.
If no summary (worker may have failed):
- Check the worker's return value for error information
- Mark as failed
- If Linear MCP is available, create investigation task with quality gate:
After creation, run post-write validation:save_issue( title="Investigate: <task-id> failed", team=<team>, priority=1, project=<project>, labels=["Bug"], description="## Problem\n<what the worker was attempting and how it failed>\n\n## Approach\nInvestigate root cause: check worker logs, git state, and error output.\n\n## Acceptance Criteria\n- [ ] Root cause identified\n- [ ] Fix applied or follow-up task created\n\n## Target Files\n- <files the failed task was working on>" )
— check for formatting artifacts and rewrite if needed.get_issue(id=<created-id>)
Update checkpoint: move task from
in_progress to completed (or failed).
Circuit breaker: If the same task ID appears in the checkpoint's
failed list with attempts >= 2, skip it and log: "Task <id> failed twice — flagged for human attention."
Step B.5 — Pull and Clean Up
After reconciliation, pull changes so subsequent dispatches see the latest code:
If
: No worktree prune needed (no worktrees created). Workers already committed directly to this branch, so --sequential
git pull may not be necessary — but run it to sync with any remote changes:
git pull origin $(git branch --show-current) --rebase 2>/dev/null || true
If parallel (default): Prune completed worktrees and pull the worker's merged changes:
git worktree prune git pull origin $(git branch --show-current)
Step C — Check Limits
- If
reached → write checkpoint with--max-batches
, report "Auto-run paused. N tasks remain.", exit.status: "paused" - If
elapsed (compare current time to--max-hours
in checkpoint) → same.start_time
Step D — Dispatch Next Batch
- Query ready tasks (same pattern as First Dispatch: list_issues + get_issue filter)
- Filter to in-scope tasks only (if
is set in checkpoint)scope.task_ids - Calculate
available_slots = max_concurrent - current_in_progress_count
If in-scope ready tasks AND available_slots > 0:
- If
: Call--sequential
via Skill tool. This blocks until all tasks complete./dispatch --sequential <specific-task-ids> --no-plan --yes - If parallel (default): Call
via Skill tool (pass only in-scope IDs, limited to available_slots)/dispatch <specific-task-ids> --no-plan --yes - Increment
in checkpointbatch_number - Add dispatched tasks to
in checkpointin_progress
Completion checks:
- If
target task is now closed → all done → go to Section 4 (Completion)--through - If
and all epic children closed → all done → go to Section 4--epic - If no in-scope ready AND no in-progress → all done → go to Section 4
- If no in-scope ready BUT tasks still in-progress → wait for more completions (background agents will notify you when they finish; in
mode this does not apply since dispatch blocks)--sequential
Step E — Context Self-Monitoring
After every 3 reconciliation cycles, assess context health. If you notice degradation (losing track of state, responses feeling truncated, difficulty recalling earlier context):
- Write checkpoint with
(preserving all current state)status: "running" - Log: "Context limit approaching. Exiting for wrapper restart."
- Exit gracefully — the wrapper script (if running) will restart with
--resume
Section 4: Completion
When no ready tasks AND no in-progress tasks (all work done):
- Final reconciliation: Call
via Skill tool/reconcile-summary --yes
Step 1.5: Milestone Review Phase
After reconciliation, run an iterative review-fix pass on accumulated branch changes:
-
If
was passed: skip, log "Milestone review skipped by flag"--skip-milestone-review -
Detect milestone branch:
git branch -r --list 'origin/milestone/*' | sort -V | tail -1 -
If no milestone branch found: skip, log "No milestone branch found — skipping milestone review"
-
Update checkpoint:
milestone_review.status: "in_progress" -
Dispatch a review worker using Agent tool:
isolation: "worktree"mode: "bypassPermissions"- Prompt: Check out the milestone branch, run
(use/milestone-review --max-iterations <N> --base-branch main
value or default 5)--milestone-review-iterations - The worker pushes fixes directly to the milestone branch (no separate PR — the milestone-to-main PR is the human review checkpoint)
-
Wait for worker completion
-
Read the worker's report/session summary
-
Update checkpoint:
with stats from the worker's reportmilestone_review.status: "completed" -
Write checkpoint with
and final statsstatus: "completed" -
Final report:
═══════════════════════════════════════════ AUTO-RUN COMPLETE ═══════════════════════════════════════════ Duration: <elapsed time> Batches: <count> Completed: <count> tasks Failed: <count> tasks MILESTONE REVIEW: - Status: <completed|skipped|N/A> - Iterations: <count> - Findings fixed: <count> - Findings deferred: <count> (needs human decision) COMPLETED: - <task-id>: <title> - ... FAILED: - <task-id>: <title> — <reason> - ... REMAINING (if any): - <task-id>: <title> - ... ═══════════════════════════════════════════
- If Linear MCP is available, call
to show final board state.list_issues
Checkpoint Schema
File:
docs/auto-run-checkpoint.json
{ "version": 2, "status": "running|completed|paused|errored", "start_time": "ISO8601", "last_updated": "ISO8601", "config": { "max_batches": null, "max_hours": null, "max_concurrent": 3, "execution_mode": "parallel|sequential" }, "scope": { "mode": "all|through|epic|only", "target": "INT-14", "task_ids": ["INT-12", "INT-13", "INT-14"] }, "batch_number": 2, "session_count": 1, "tasks": { "completed": [{ "id": "INT-12", "title": "...", "completed_at": "...", "batch": 1 }], "failed": [{ "id": "INT-14", "title": "...", "reason": "...", "attempts": 1 }], "in_progress": [{ "id": "INT-13", "title": "...", "dispatched_at": "...", "batch": 2 }] }, "stats": { "total_dispatched": 4, "total_completed": 1, "total_failed": 0, "total_batches": 2 }, "milestone_review": { "status": "pending|in_progress|completed|skipped", "iterations": 0, "findings_fixed": 0, "findings_deferred": 0 } }
Error Handling
- Failed tasks: If Linear MCP available, create investigation issues; otherwise log and continue
- Circuit breaker: Same task failing twice → skip and flag for human attention
- No task tracker: If Linear MCP is not available, exit with "No task tracker configured. Connect Linear MCP or use /dispatch manually."
- Checkpoint corruption: If checkpoint can't be parsed, start fresh (warn user)