name: auto
description: Autonomous execution (/auto 123). Runs spec (when needed)→code→review→merge→verify in sequence. XL Issues use sub-issue dependency graph with parallel execution. Size auto-detection with --patch/--pr and --review=light/--review=full overrides. Issues without phase/* labels start from issue triage. --batch N processes N backlog XS/S Issues; --batch N1 N2 ... processes the explicitly listed Issues in order (assigns a BATCH_ID for parallel-safe checkpointing). --resume N resumes a single Issue (restores verify counter from checkpoint); --batch --resume resumes an interrupted batch using list_active_batches to identify the target session.
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh:, gh issue view:, gh issue list:, gh issue close:, gh issue comment:, gh issue create:, gh pr list:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-code.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-review.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-merge.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/get-sub-issue-graph.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-auto-sub.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-spec.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/run-issue.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/gh-label-transition.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/detect-wrapper-anomaly.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/validate-recovery-plan.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/observation-trigger.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/auto-events-rollup.sh:, ${CLAUDE_PLUGIN_ROOT}/scripts/gh-issue-edit.sh:), Read, Edit, Glob, Grep, Write, Skill, Task, TaskCreate, TaskUpdate, TaskList, TaskGet
Autonomous Execution
Receive an Issue number and run spec (when needed)→code→review→merge→verify in sequence using Size-based routing. code/review/merge phases run via run-*.sh using claude -p --dangerously-skip-permissions for a fresh context with full permission bypass. verify runs as a Skill invocation in the parent session (enabling AskUserQuestion for manual AC confirmation).
If ARGUMENTS contains --help, Read ${CLAUDE_PLUGIN_ROOT}/modules/skill-help.md and follow the "Processing Steps" section to output help, then stop.
Route-Phase Matrix
| Route | Target Size | Phase sequence |
|---|---|---|
| patch (XS/S) | XS, S | spec (when needed) → code(--patch) → verify |
| pr (M) | M | spec (when needed) → code → review(--light) → merge → verify |
| pr (L) | L | spec (when needed) → code → review(--full) → merge → verify |
| XL | XL | Sub-issue dependency graph with parallel execution (spec auto-runs per sub-issue) |
- Size not set: default to pr route (safe fallback since AskUserQuestion is unavailable in non-interactive mode)
Steps
Step 1: Extract Issue Number
Extract the Issue number from ARGUMENTS. Examples: ARGUMENTS = "279" → NUMBER = 279; ARGUMENTS = "279 --patch" → NUMBER = 279, ROUTE_FLAG = --patch
AUTO_SESSION_ID generation (run before all route detection):
Generate a session identifier and record it in a pointer file so sub-processes spawned by run-auto-sub.sh can read it:
- Generate
SESSION_IDand create the pointer file:mkdir -p .tmp SESSION_ID="$$-$(date +%s)" printf '%s\n' "$SESSION_ID" > .tmp/auto-session-current - Write
.tmp/auto-session-${SESSION_ID}.jsonusing the Write tool with session metadata:
Substitute the actual{"session_id": "<SESSION_ID>", "session_start": "<current UTC timestamp in ISO8601>"}SESSION_IDvalue and current timestamp before writing. - Set
AUTO_SESSION_ID="$SESSION_ID"in the current Bash context (does not persist across separate Bash tool calls; sub-processes read from the pointer file instead):export AUTO_SESSION_ID="$SESSION_ID"
--resume detection (single-Issue resume):
If ARGUMENTS contains --resume but NOT --batch: record RESUME_MODE=true and extract the numeric token following --resume as NUMBER. Output a log line: "Resume mode: restoring checkpoint for issue #$NUMBER". Proceed to Step 2 as normal (checkpoint restoration happens in Step 4 before the verify loop).
--batch detection:
If --batch flag is present:
- If
--resumeis present AND no numeric tokens follow--batch(i.e.,ARGUMENTS = "--batch --resume"or similar with no numbers after--batch): recordRESUME_BATCH=trueand branch to### Resume mode (--batch --resume)in the "Batch Mode (--batch)" section (skip Steps 2–6) - Else: collect all consecutive numeric tokens following
--batch, stopping at any non-numeric token or ARGUMENTS end.- If exactly 1 numeric token collected (e.g.,
ARGUMENTS = "--batch 5"): recordBATCH_SIZE = 5(Count mode) and branch to### Count mode (--batch N)in the "Batch Mode (--batch)" section (skip Steps 2–6) - If 2 or more numeric tokens collected (e.g.,
ARGUMENTS = "--batch 123 124 125"): recordBATCH_LIST = [123, 124, 125](List mode) and branch to### List mode (--batch N1 N2 ...)in the "Batch Mode (--batch)" section (skip Steps 2–6)
- If exactly 1 numeric token collected (e.g.,
No Issue number needed for batch mode.
Read ${CLAUDE_PLUGIN_ROOT}/modules/phase-banner.md and display the start banner with ENTITY_TYPE="issue", ENTITY_NUMBER=$NUMBER, SKILL_NAME="auto".
Step 2: Route Detection and Base Branch
Detect --patch/--pr, --review=full/--review=light, and --base {branch} flags from ARGUMENTS.
If --base {branch} is present, record as BASE_BRANCH. If --base is not specified, default to BASE_BRANCH=main.
| Flag | Route | Phase sequence |
|---|---|---|
--patch |
patch | code(--patch) → verify |
--pr |
pr | code → review → merge → verify |
--pr --review=full |
pr | code → review(--full) → merge → verify |
--pr --review=light |
pr | code → review(--light) → merge → verify |
--base {branch} |
(no route change) | Specify base branch; propagates to all phases |
| none | auto-detect | Determine route from Size label |
If no flags, fetch Size to auto-detect route:
${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh "$NUMBER" 2>/dev/null
Set REVIEW_DEPTH from flags or Size (used unchanged in Step 4 unless Step 3a refreshes it):
| Condition | REVIEW_DEPTH |
|---|---|
--review=full flag present |
--full |
--review=light flag present |
--light |
--patch flag present |
(not applicable — patch route) |
Auto-detect or --pr without --review=...: Size M |
--light |
Auto-detect or --pr without --review=...: Size L |
--full |
Auto-detect or --pr without --review=...: other/unset |
--light (safe fallback) |
Step 3: phase/ready Label Check
Fetch labels with gh issue view $NUMBER --json labels -q '.labels[].name' and branch based on label state:
phase/readylabel present: proceed to the next stepphase/issuelabel present (nophase/ready):- Size is XS: Spec not needed — skip spec and proceed to Step 4
- Size is
L: run${CLAUDE_PLUGIN_ROOT}/scripts/run-spec.sh $NUMBER --opus(run spec with Opus model) - Size is neither XS nor L: run
${CLAUDE_PLUGIN_ROOT}/scripts/run-spec.sh $NUMBER - On spec success, proceed to Step 4
- On spec failure, go to Step 6 (error report)
- No
phase/*labels (issue triage not done):- Run
${CLAUDE_PLUGIN_ROOT}/scripts/run-issue.sh $NUMBER(issue triage → Size setting/requirement shaping) - After success, re-fetch Size (
${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh $NUMBER). Update route if Size is now set. - Re-fetch labels:
gh issue view $NUMBER --json labels -q '.labels[].name' - If re-fetched labels have
phase/ready: proceed to Step 4 - If re-fetched labels have
phase/issue(nophase/ready):- Size is XS: skip spec, proceed to Step 4
- Size is
L: run${CLAUDE_PLUGIN_ROOT}/scripts/run-spec.sh $NUMBER --opus - Size is neither XS nor L: run
${CLAUDE_PLUGIN_ROOT}/scripts/run-spec.sh $NUMBER - On spec success, proceed to Step 4
- On spec failure, go to Step 6 (error report)
- If expected
phase/*label state is not reached after re-fetch, go to Step 6 (error report) - On issue failure, go to Step 6 (error report)
- Run
Step 3a: Post-Spec Size Refresh
Run only when run-spec.sh was called and succeeded in Step 3 (i.e., spec was executed — not when phase/ready was already set at Step 3 entry, and not when Size was XS which skips spec). Also skip if --patch, --pr, or --review=... flag is present in ARGUMENTS (preserve explicit-flag priority behavior).
Re-fetch Size to detect updates made by the spec phase:
${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh --no-cache "$NUMBER" 2>/dev/null
Update ROUTE and REVIEW_DEPTH based on the refreshed Size:
| Refreshed Size | Route | Review depth |
|---|---|---|
| XS or S | patch | — |
| M | pr | --light |
| L | pr | --full |
| XL | sub_issue | — |
| unset | pr | (safe fallback) |
If route changed from Step 2, output a log line: "Post-spec Size refresh: Size updated to {NEW_SIZE}, route re-determined as {NEW_ROUTE}."
Route demotion (pr → patch only):
If ROUTE changed from pr to patch (i.e., the prior ROUTE was pr and the refreshed ROUTE is patch):
- Output: "Post-spec route demotion: pr → patch, remaining phases re-planned"
- In Step 4, use the patch route sequence instead of the pr route sequence: run
code --patchthenverify(skipreviewandmerge)
Proceed to Step 4 using the updated ROUTE and REVIEW_DEPTH.
Step 4: Autonomous Execution (run-*.sh)
Select the route section below based on the current ROUTE value (set in Step 2 and potentially overridden by Step 3a's route demotion logic).
Run each phase via run-*.sh. Each script launches an independent process with claude -p --dangerously-skip-permissions for a fresh context and full permission bypass.
Execution pattern:
- Each
run-*.shruns as a blocking call (timeout: 600000) in sequence - PR number extraction is run by the parent session with
gh pr list(included inallowed-tools)
VERIFY_ITERATION_COUNT initialization (single-Issue routes only — skip for batch modes):
Before running any phase, initialize VERIFY_ITERATION_COUNT:
- If
RESUME_MODE=true: call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh read_single $NUMBERand setVERIFY_ITERATION_COUNTto the returned value. Output: "Restored verify_iteration_count=$VERIFY_ITERATION_COUNT from checkpoint."- After restoring, also perform a label conflict check: fetch live labels with
gh issue view $NUMBER --json labels -q '.labels[].name'. If the issue is already atphase/done(labelphase/donepresent), the checkpoint is stale — call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_single $NUMBER, setVERIFY_ITERATION_COUNT=0, and output: "Checkpoint discarded: live labels show phase/done."
- After restoring, also perform a label conflict check: fetch live labels with
- If
RESUME_MODEis not set (normal mode): setVERIFY_ITERATION_COUNT=0
XL route: sub-issue dependency graph with parallel execution (run-auto-sub.sh checks each sub-issue's phase/ready and auto-runs spec if not set):
Read ${CLAUDE_PLUGIN_ROOT}/modules/detect-config-markers.md and follow the "Processing Steps" section. Retain AUTO_MAX_CONCURRENT (maximum concurrent sub-issue executions; default: 5).
Fetch dependency graph:
${CLAUDE_PLUGIN_ROOT}/scripts/get-sub-issue-graph.sh $NUMBERParse the result JSON and extract
execution_order(array of sub-issue numbers per level).Run levels in order, in parallel: Process each level in
execution_ordersequentially.Run each level's sub-issues in parallel via Bash background (
&) with concurrency capped atAUTO_MAX_CONCURRENT, then wait for all to complete:# For each level (in execution_order order): Skip sub-issues that depend on failed issues, then run non-skipped sub-issues with concurrency cap using AUTO_MAX_CONCURRENT: RUNNING=0 PIDS=() for each SUB in non-skipped sub-issues: ${CLAUDE_PLUGIN_ROOT}/scripts/run-auto-sub.sh $SUB_NUMBER & PIDS+=($!) RUNNING=$((RUNNING + 1)) if [ $RUNNING -ge $AUTO_MAX_CONCURRENT ]; then # bash 4.3+: wait -n waits for any one child to finish # bash 3.2 fallback (macOS): kill -0 polling if (( BASH_VERSINFO[0] > 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3) )); then wait -n else while true; do for pid in "${PIDS[@]}"; do if ! kill -0 "$pid" 2>/dev/null; then break 2; fi done sleep 1 done fi RUNNING=$((RUNNING - 1)) fi done Wait for all processes with `wait`, check each process exit codeAfter
waitcompletes, aggregate-update parent phase (run after each level completes):- Fetch each sub-issue's current phase label with
gh issue view $SUB_NUMBER --json labels - Determine parent phase based on aggregation rules:
- 1+ children at
phase/codeor later (code/review/verify/done) → parent becomesphase/code - All children at
phase/verifyor later (verify/done) → parent becomesphase/verify - All children at
phase/done→ handled by close flow judgment (Step 4c); do not aggregate-update here
- 1+ children at
- Update parent with
${CLAUDE_PLUGIN_ROOT}/scripts/gh-label-transition.sh $NUMBER <aggregated phase>
After aggregate-update, cross-cutting condition pre-verification (best-effort): When a level completes, proactively check the parent XL Issue's cross-cutting Acceptance Criteria:
- Fetch parent Issue body:
gh issue view $NUMBER --json body -q '.body' - Extract
<!-- verify: ... -->commands from the Acceptance Criteria sections (pre-merge and post-merge) - Read
${CLAUDE_PLUGIN_ROOT}/modules/verify-executor.mdand execute each verify command in full mode - For each FAIL result: output a warning and continue (best-effort cross-cutting condition detection)
Format: "Warning: cross-cutting condition failed: [condition text]. Run
/verify $NUMBERto confirm." - Continue to the next level regardless of results (authoritative verification is done by
/verify $NUMBER)
- Fetch each sub-issue's current phase label with
On failure:
- Add failed sub-issue numbers to the failure set
- In subsequent levels, skip sub-issues that depend on (have
blocked_bycontaining) a number in the failure set - Continue processing sub-issues that do not depend on failed issues
- To determine skip: check
blocked_byinget-sub-issue-graph.shoutput and mark any sub-issue containing a failed Issue number as skip target
Completion report: After all levels complete, report results (success/failure/skip) for each sub-issue.
Auto retrospective: See "Step 4a: Auto Retrospective" section.
patch route XS/S (2 phases):
Each phase follows the Observe → Diagnose → Act pattern (same as pr route; see above).
- Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh code-patch $NUMBER --check-precondition --warn-only - code phase: run
${CLAUDE_PLUGIN_ROOT}/scripts/run-code.sh $NUMBER --patch [--base {branch}]via Bash (timeout: 600000) - Unconditional completion check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh code-patch $NUMBER --check-completion— runs unconditionally regardless of exit code; ifmatches_expected: false(including exit 0), go to Step 6; if code exited non-zero butmatches_expected: true, override to success - XS only: transcribe issue retrospective to Spec (see Step 4b)
- Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh verify $NUMBER --check-precondition --warn-only - Increment counter:
VERIFY_ITERATION_COUNT=$((VERIFY_ITERATION_COUNT + 1)) - Save checkpoint:
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh write_single $NUMBER $VERIFY_ITERATION_COUNT - verify phase: invoke
Skill(skill="wholework:verify", args="$NUMBER")in the parent session (enables AskUserQuestion for manual AC confirmation) - Based on verify result, proceed to Step 5 or Step 6
- If verify output contains
MAX_ITERATIONS_REACHED: max iterations has been reached; delete checkpoint (${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_single $NUMBER); stop chained execution and proceed to Step 5 (human judgment required — do not re-run verify automatically) - On verify success: delete checkpoint (
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_single $NUMBER) and proceed to Step 5
- If verify output contains
pr route (4 phases):
Phase transition output format: output [N/M] phase_name before each phase, and [N/M] phase_name → done (details) after success. Example:
[1/4] code
(run-code.sh output)
[1/4] code → done (PR #125)
[2/4] review
...
Each phase follows the Observe → Diagnose → Act pattern:
- Observe (precondition):
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh <phase> <issue> --check-precondition --warn-only— mismatch outputs a stderr warning but does not block execution (stage-1 gradual rollout) - Act: run
<run-*.sh> - Diagnose (completion):
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh <phase> <issue> --check-completion; parse JSON output — ifmatches_expected: true, continue; ifmatches_expected: false, treat as mismatch and go to Step 6
Full phase sequence:
- Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh code-pr $NUMBER --check-precondition --warn-only - Output
[1/4] code, then run${CLAUDE_PLUGIN_ROOT}/scripts/run-code.sh $NUMBER --pr [--base {branch}]via Bash (timeout: 600000) - Unconditional completion check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh code-pr $NUMBER --check-completion— runs unconditionally regardless of exit code; ifmatches_expected: false(including exit 0), go to Step 6; ifmatches_expected: true, output[1/4] code → done (PR #N)and continue - Extract PR number via exact-match filter (matches SSoT branch name worktree-code+issue-N established by #310):
gh pr list --json number,headRefName | jq -r ".[] | select(.headRefName == \"worktree-code+issue-$NUMBER\") | .number" | head -1 - If PR number cannot be fetched: report error and go to Step 6
- Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh review $NUMBER --pr $PR_NUMBER --check-precondition --warn-only - Output
[2/4] review, then run${CLAUDE_PLUGIN_ROOT}/scripts/run-review.sh $PR_NUMBER $REVIEW_DEPTHvia Bash (timeout: 600000) (REVIEW_DEPTH set in Step 2, refreshed by Step 3a if applicable); on success output[2/4] review → done - If review fails: completion check
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh review $NUMBER --pr $PR_NUMBER --check-completion— ifmatches_expected: true, override to success; otherwise go to Step 6 - Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh merge $NUMBER --pr $PR_NUMBER --check-precondition --warn-only - Output
[3/4] merge, then run${CLAUDE_PLUGIN_ROOT}/scripts/run-merge.sh $PR_NUMBERvia Bash (timeout: 600000); on success output[3/4] merge → done - If merge fails: completion check
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh merge $NUMBER --pr $PR_NUMBER --check-completion— ifmatches_expected: true, override to success; otherwise go to Step 6 - Precondition check:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh verify $NUMBER --check-precondition --warn-only - Increment counter:
VERIFY_ITERATION_COUNT=$((VERIFY_ITERATION_COUNT + 1)) - Save checkpoint:
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh write_single $NUMBER $VERIFY_ITERATION_COUNT - Output
[4/4] verify, then invokeSkill(skill="wholework:verify", args="$NUMBER")in the parent session (enables AskUserQuestion for manual AC confirmation); on success output[4/4] verify → done - Based on verify result, proceed to Step 5 or Step 6
- If verify output contains
MAX_ITERATIONS_REACHED: max iterations has been reached; delete checkpoint (${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_single $NUMBER); stop chained execution and proceed to Step 5 (human judgment required — do not re-run verify automatically) - On verify success: delete checkpoint (
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_single $NUMBER) and proceed to Step 5
- If verify output contains
Step 4b: Issue Retrospective Transcription (XS patch route only)
Skip this step for all routes other than XS patch.
The XS patch route does not go through the /spec phase, so no Spec file exists. To allow the /verify improvement proposal pipeline to collect the issue retrospective, create a Spec file and transcribe it using the following steps.
Read ${CLAUDE_PLUGIN_ROOT}/modules/detect-config-markers.md and follow the "Processing Steps" section. Retain SPEC_PATH for use in subsequent steps.
Check for issue retrospective in Issue comments:
- Fetch all Issue comments:
gh issue view "$NUMBER" --json comments -q '.comments[].body' - Search for comments containing a
## Issue Retrospectivesection - If not found: skip this entire step (no transcription needed if no issue retrospective)
- Fetch all Issue comments:
Determine Spec file path:
$SPEC_PATH/issue-$NUMBER-<short-title>.md- Generate
short-titleas English kebab-case from Issue title (e.g.,xs-patch-retro) - If an existing Spec file is found, use it
- Generate
Create (or update) Spec file and append issue retrospective:
- For new files: include a
# Issue #$NUMBER: $TITLEheading at the top - Append
## Issue Retrospectivesection at the end of the Spec file (naturally referenced by/verify's Spec reading)
- For new files: include a
Commit and push:
git add $SPEC_PATH/issue-$NUMBER-*.md git commit -s -m "Add issue retrospective for issue #$NUMBER
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com" git push origin main
### Step 4a: Auto Retrospective
**Conditions to run this step:**
- **XL route**: always run — record orchestration results for all sub-issues
- **M/L/patch route**: run only when the parent session detects **any** of the following orchestration anomalies; skip if no anomalies are detected:
- (a) A shell wrapper (`run-code.sh`, `run-auto-sub.sh`, etc.) exited non-zero, but subsequent state was manually recovered
- (b) A phase that should have transitioned automatically was manually invoked by the parent session
- (c) `/auto` completed with behavior that differs from the original spec
If no anomalies are detected (M/L/patch route), skip this step — do not record an empty section.
Read `${CLAUDE_PLUGIN_ROOT}/modules/detect-config-markers.md` and follow the "Processing Steps" section. Retain `SPEC_PATH` for use in subsequent steps.
1. **Determine Spec file path**: `$SPEC_PATH/issue-$NUMBER-<short-title>.md`
- Generate `short-title` as English kebab-case from Issue title (e.g., `xl-orchestration-retrospective`)
- If an existing Spec file is found, use it and append `## Auto Retrospective` section
- **If Spec file does not exist** (e.g., XS patch route without spec phase): create a new Spec file with `# Issue #$NUMBER: $TITLE` header, then append `## Auto Retrospective` section
2. **Create (or update) Spec file**:
**XL route** — record full sub-issue summary:
```markdown
# Issue #$NUMBER: $TITLE
## Auto Retrospective
### Execution Summary
| # | Title | Route | Result | Notes |
|---|-------|--------|--------|-------|
(list result for each sub-issue)
### Parallel Execution Issues
- (conflicts, race conditions, recovery history. "None" if no issues)
### Improvement Proposals
- (structural issues and fixes. "N/A" if no proposals)
- Result column criteria: exit code 0 →
SUCCESS, non-zero exit code →FAILED (exit code N), dependency skip →SKIPPED (blocked by #X) - Improvement proposal guidance: document structural issues from parallel execution (conflicts, PR extraction failures, verify chain FAILs, etc.) and their fixes.
/verify's Step 13 reads### Improvement Proposalsand creates Issues from them
M/L/patch route — append orchestration anomaly record (append to existing Spec; create new Spec with header if none exists):
## Auto Retrospective
### Execution Summary
| Phase | Route | Result | Notes |
|-------|-------|--------|-------|
| code | pr | SUCCESS (manual PR extract fallback) | run-auto-sub.sh exit 1 but PR #N already created |
| review | pr | SUCCESS | manual invocation after wrapper failure |
| merge | pr | SUCCESS | manual invocation |
| verify | - | SUCCESS | |
### Orchestration Anomalies
- (describe each anomaly: which script, what exit code, what state, how manually recovered)
### Improvement Proposals
- (list structural improvements to prevent recurrence. "N/A" if none)
Fetch issue retrospective from Issue comments and transcribe to Spec (XL route only):
- Fetch all Issue comments:
gh issue view "$NUMBER" --json comments -q '.comments[].body' - Search for comments containing
## Issue Retrospective - If found: append
## Issue Retrospectivesection at end of Spec file (naturally referenced by/verify's Spec reading) - If not found: skip (XL Issues not going through
/issuemay not have this)
- Fetch all Issue comments:
Append recovery events to orchestration-recoveries.md (before Spec retrospective commit):
Read
${CLAUDE_PLUGIN_ROOT}/modules/detect-config-markers.mdto confirmSPEC_PATH(already retained from step 1 of this section).Determine whether any of the following sources contributed recovery events during this run:
Source When to append Dependency Source 1: fallback-catalogA catalog entry in orchestration-fallbacks.mdwas applied during Tier 2 recoveryAvailable (#315 shipped) Source 2: recovery-sub-agentThe orchestration-recoverysub-agent produced a successful recovery plan during Tier 3 recoveryAvailable (#617 shipped) Source 3: wrapper-anomaly-detectordetect-wrapper-anomaly.shdetected a known failure pattern during Tier 2 recoveryAvailable (#313 shipped) Source 2 detection — single-Issue parent session only: Check if
TIER3_RECOVERY_PHASEis set (retained in Step 6 after Tier 3 succeeds). If set, use retainedTIER3_RECOVERY_*variables to build the entry and prepend it. For batch/XL routes,spawn-recovery-subagent.shwrites directly toorchestration-recoveries.md, so Source 2 here covers only single-Issue parent sessions (M/L/patch).run-auto-sub.shcommits and pushesdocs/reports/orchestration-recoveries.mdimmediately after Tier 3 success to prevent dirty-file conflicts at/verifyinvocation (see #677).For each applicable source, prepend a new entry block to
docs/reports/orchestration-recoveries.md(after the header comment line<!-- Log entries appear below, newest first. -->). Use the Write/Edit tool. Entry format:## YYYY-MM-DD HH:MM UTC: <symptom-short> ### Context - Issue #N, phase: <phase> - Source: <fallback-catalog|recovery-sub-agent|wrapper-anomaly-detector> - Wrapper: <run-*.sh name>, exit code: <N> - Log tail: "<last relevant log line>" ### Diagnosis - <observed state and root cause> ### Recovery Applied - <catalog anchor or sub-agent plan excerpt or manual steps> ### Outcome - <success|partial|failed> ### Improvement Candidate - <未起票|起票済み #NNN|N/A (resolved by known catalog)>If no sources contributed recovery events, skip the append (do not create an empty entry).
Add
docs/reports/orchestration-recoveries.mdto the samegit addin the next step.Commit and push:
git add $SPEC_PATH/issue-$NUMBER-*.md docs/reports/orchestration-recoveries.md git commit -s -m "Add auto retrospective for issue #$NUMBER
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com" git push origin main
If no recovery events were appended, omit `docs/reports/orchestration-recoveries.md` from `git add` (only add it when it was actually modified).
6. **Collect and create Improvement Proposal Issues**: Read `${CLAUDE_PLUGIN_ROOT}/modules/retro-proposals.md` and follow the "Processing Steps" section. Use `SPEC_PATH` and `HAS_SKILL_PROPOSALS` already retained from this step's `detect-config-markers.md` call. If the shared module returns no proposals, skip silently.
### Step 4d: XL Sub-issue Verify (XL route only)
**Skip this step for all routes other than XL.**
Run after all sub-issue levels complete (after Step 4a Auto Retrospective) and before Step 4c close flow.
Collect all sub-issue numbers from `get-sub-issue-graph.sh` output (all sub-issues that reached `phase/done` or `phase/verify`), then append the parent issue number: `[sub_issue_1, sub_issue_2, ..., $NUMBER]`.
For each issue number in this list, **serially** in the parent session:
Skill(skill="wholework:verify", args="$N")
This runs verify in the parent context, enabling AskUserQuestion for manual AC confirmation on each issue.
**Skip any sub-issue that**:
- was skipped due to a dependency failure (in the failure set from Step 4 execution)
- already has `phase/done` label (already verified and closed in a prior run)
Continue to the next issue even if one verify invocation ends in FAIL or MAX_ITERATIONS_REACHED — the close flow in Step 4c will assess the final state.
### Step 4c: XL Parent Issue Close Flow (XL route only)
**Skip this step for all routes other than XL.**
Determine the close flow for the parent Issue based on all sub-issue execution results.
1. **Confirm all sub-issues succeeded (`phase/done`)**:
- If any sub-issue failed or was skipped: skip close flow and leave parent phase as-is (do not close)
2. **If all children are `phase/done`**: check for unchecked (`- [ ]`) conditions in the post-merge section of the parent Issue body:
- Fetch post-merge section with `gh issue view $NUMBER --json body`
- Check if any unchecked `- [ ]` conditions remain
3. **No unchecked cross-cutting conditions**: auto-close the parent:
```bash
${CLAUDE_PLUGIN_ROOT}/scripts/gh-label-transition.sh $NUMBER done
gh issue close $NUMBER
- Unchecked cross-cutting conditions remain: transition to
phase/verifyand post a notification comment:
Leave the parent Issue open. The user runs${CLAUDE_PLUGIN_ROOT}/scripts/gh-label-transition.sh $NUMBER verify gh issue comment $NUMBER --body "All sub-issues are complete. The parent Issue has remaining manual acceptance conditions. Run \`/verify $NUMBER\` after reviewing."/verify $NUMBERfor final confirmation before closing.
Step 5: Completion Report
If all phases succeeded:
Check for opportunistic pending state: Run
gh issue view $NUMBER --json labels --jq '.labels[].name'CI FAIL/recovery scan (build Notes before result table):
Scan the run-*.sh output captured in the LLM context during Step 4 for CI check failures and auto-recovery events in each phase:
- CI check failure:
gh pr checks-style output lines containingfailorFAILED(e.g.,Run bats / bats (push) fail) - Review auto-fix: phrases such as
MUST issue resolved/MUST issue auto-resolved, or commit messages beginning withFix:added as follow-up commits in the review phase
For each phase where a CI failure or auto-fix is detected, record a concise one-line Notes value for the result table:
- Example:
1 CI fail → fixed in abc1234 - Example:
1 MUST issue auto-resolved - Example:
2 CI fails → fixed; 1 MUST issue resolved(multiple events in one phase)
If nothing is detected for a phase, leave Notes as
—.- CI check failure:
If output from step 1 contains
phase/verify(opportunistic pending): output the partial success — opportunistic pending banner:/auto #N partial success — opportunistic pending TITLE URLFollowed by a result table (one row per phase with status, Notes from step 2).
Then enumerate unchecked post-merge conditions from the Issue body:
- Fetch Issue body:
gh issue view $NUMBER --json body -q '.body' - Locate the post-merge section (lines after
### Post-mergeor## Post-mergeheading, up to the next##heading or end of file) - Extract all lines matching
- [ ]within that section - For each extracted line, strip the
- [ ]prefix and remove any<!-- verify: ... -->HTML comment substrings, then trim whitespace to produce human-readable condition text - Display the conditions:
- If 1–5 conditions: list each on its own line, prefixed with
- - If 6 or more: list the first 5 with
-prefix, then output... and N more(where N is the total count minus 5) - If 0 conditions: omit the list (output nothing after the result table)
- If 1–5 conditions: list each on its own line, prefixed with
After the list (or result table if no conditions), output: "Run `/verify $NUMBER` after confirming them manually."
- Fetch Issue body:
If output from step 1 does not contain
phase/verify: output the completion banner:/auto #N complete TITLE URLFollowed by a result table (one row per phase with status, Notes from step 2).
If an Auto Retrospective was recorded in the Spec (XL routes: always; M/L/patch routes: when orchestration anomalies were detected), also output "Auto retrospective recorded in Spec".
Then read ${CLAUDE_PLUGIN_ROOT}/modules/next-action-guide.md and follow the "Processing Steps" section with:
SKILL_NAME=autoISSUE_NUMBER=$NUMBERRESULT=success
Event-based observation scan (auto-run event, runs after Completion Report regardless of success/failure):
Run ${CLAUDE_PLUGIN_ROOT}/scripts/observation-trigger.sh --event auto-run
Daily rollup (best-effort, runs after observation scan regardless of success/failure):
Run ${CLAUDE_PLUGIN_ROOT}/scripts/auto-events-rollup.sh. If the command fails, output "Warning: auto-events-rollup failed. Session will continue." and proceed without blocking.
Step 6: On Failure: 3-Tier Recovery
If any phase exits with a non-zero exit code, apply the following 3-tier recovery hierarchy before stopping.
Always first: Write the failed phase's output to .tmp/wrapper-out-$NUMBER-$PHASE.log using the Write tool (needed by Tier 2 anomaly detector).
Tier 1 (Observe): State Reconciliation
Run the completion check for the failed phase:
${CLAUDE_PLUGIN_ROOT}/scripts/reconcile-phase-state.sh <phase> $NUMBER --check-completion
Parse the JSON output. If matches_expected: true: the phase actually succeeded despite wrapper exit non-zero — override to success and continue to the next phase (skip Tier 2 and Tier 3).
If matches_expected: false: proceed to Tier 2.
Tier 2 (Known pattern): Anomaly Detector + Fallback Catalog
Run the anomaly detector:
${CLAUDE_PLUGIN_ROOT}/scripts/detect-wrapper-anomaly.sh --log .tmp/wrapper-out-$NUMBER-$PHASE.log --exit-code $EXIT_CODE --issue $NUMBER --phase $PHASE
If detector output is non-empty (known pattern matched):
- Read
${CLAUDE_PLUGIN_ROOT}/modules/detect-config-markers.mdto getSPEC_PATH - Append the detector output to the Spec file (
$SPEC_PATH/issue-$NUMBER-*.md) under## Auto Retrospective, and commit and push - Read
${CLAUDE_PLUGIN_ROOT}/modules/orchestration-fallbacks.mdand follow the catalog entry matching the detected pattern to apply the recovery steps mid-run-api-errorpattern: runreconcile-phase-state.sh <phase> $NUMBER --check-completion; ifmatches_expected: trueoverride to success; ifmatches_expected: falseinspecthint_*fields inactualJSON to restore the phase label, then retry the failed phase once via the correspondingrun-*.shscript- If the catalog's recovery succeeds, continue to the next phase (skip Tier 3)
- If the catalog's recovery fails, proceed to Tier 3
If detector output is empty (unknown pattern): proceed to Tier 3.
Tier 3 (Unknown): Recovery Sub-Agent
Spawn the orchestration-recovery sub-agent via Task to diagnose the unknown failure and produce a recovery plan:
Collect inputs:
phase: the failed phase name (e.g.,code-pr,review,merge,verify)exit_code: wrapper exit codelog_tail: last 200 lines of.tmp/wrapper-out-$NUMBER-$PHASE.logreconcile_snapshot: JSON output from the Tier 1reconcile-phase-state.sh --check-completioncallissue_number:$NUMBERissue_labels: output ofgh issue view $NUMBER --json labels -q '.labels[].name'pr_number:$PR_NUMBERif available, otherwise empty stringbranch: current worktree branch if available
Spawn the sub-agent:
Task: agents/orchestration-recovery.md Prompt: (pass all inputs from step 1)Write the sub-agent's output (the raw JSON) to
.tmp/recovery-plan-$NUMBER-$PHASE.jsonusing the Write tool.Safety guard — validate the recovery plan:
${CLAUDE_PLUGIN_ROOT}/scripts/validate-recovery-plan.sh .tmp/recovery-plan-$NUMBER-$PHASE.json- Validation checks: JSON parseable, required keys (
action,rationale,steps) present,actionin{retry, skip, recover, abort},stepslength ≤ 5, no forbidden ops (force_push,reset_hard,close_issue,merge_pr,direct_push_main) - If validation fails (exit non-zero): fall back to stop-and-report (see below)
- Validation checks: JSON parseable, required keys (
Act on recovery plan:
action=retry: re-run the failed phase once (samerun-*.shcall with same arguments); if it fails again, fall back to stop-and-reportaction=skip: treat the phase as complete and continue to the next phaseaction=recover: executestepssequentially; if all steps succeed, continue to the next phase; if any step fails, fall back to stop-and-reportaction=abort: fall back to stop-and-report immediately
5b. Retain recovery state (on successful recovery — action is not abort):
Retain the following as in-context variables for use in Step 4a Source 2:
TIER3_RECOVERY_PHASE=$PHASETIER3_RECOVERY_ACTION=$action(the action that succeeded)TIER3_RECOVERY_RATIONALE:rationalefield from the recovery plan JSONTIER3_RECOVERY_STEPS_COUNT: number of steps in the plan (0 for retry/skip)TIER3_RECOVERY_EXIT_CODE=$EXIT_CODETIER3_RECOVERY_LOG_TAIL: last line of.tmp/wrapper-out-$NUMBER-$PHASE.log
- Clean up:
rm -f .tmp/recovery-plan-$NUMBER-$PHASE.json .tmp/wrapper-out-$NUMBER-$PHASE.log
Stop-and-Report Fallback
If all tiers are exhausted without recovery, stop processing and output the stopped banner:
/auto #N stopped at PHASE
TITLE
URL
Followed by a result table (one row per phase; use - for unexecuted phases).
Do not invoke subsequent phases.
- code phase failure: error in branch creation, implementation, tests, or PR creation
- review phase failure: review wait timeout, fix failure, retry limit reached
- merge phase failure: invalid PR state (not approved, CI failure), conflict resolution failure
- verify phase failure: acceptance condition FAIL, Issue reopened
Manual recovery hand-off: If the parent session manually recovers and continues to subsequent phases instead of stopping here, complete the remaining phases via manual recovery first, then follow Step 4a (after all phases are done) to append anomaly details and improvement proposals to the Spec's ## Auto Retrospective > ### Orchestration Anomalies and ### Improvement Proposals sections, then proceed to Step 5. Note: if the Tier 2 anomaly detector already appended a known pattern, skip the ### Orchestration Anomalies / ### Improvement Proposals append in Step 4a to avoid duplicate entries.
Then read ${CLAUDE_PLUGIN_ROOT}/modules/next-action-guide.md and follow the "Processing Steps" section with:
SKILL_NAME=autoISSUE_NUMBER=$NUMBERRESULT=fail
Batch Mode (--batch)
When --batch is detected in Step 1, process Issues sequentially (skip Steps 2–6).
Two modes:
- Count mode (
--batch N): selects the N most recent XS/S Issues from the backlog - List mode (
--batch N1 N2 ...): processes the explicitly listed Issues in the user-specified order (任意の Issue 番号を空白区切りで指定)
Count mode (--batch N)
既存の --batch N の挙動は変更せず後方互換で維持する。
Fetch Batch Candidates
gh issue list --state open --label triaged --json number,title,labels,createdAt --limit 200
Filtering criteria
For each candidate, call ${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh $NUMBER;
exclude Issues where Size is M, L, or XL (Projects V2 field first, label fallback).
Sort by createdAt descending (newest first) and select the top N. Targets: Issues with no Size set, XS, or S.
Process Each Issue
Process the selected N Issues sequentially (serially):
- Check Issue labels:
gh issue view $NUMBER --json labels -q '.labels[].name' - If no
phase/*labels: run${CLAUDE_PLUGIN_ROOT}/scripts/run-issue.sh $NUMBER(issue triage → Size setting →phase/readyassignment)- On failure: output a warning and skip to the next Issue (do not abort the entire batch)
- Re-check Size: call
${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh $NUMBER; if Size is M, L, or XL: output a warning and skip to the next Issue (do not abort the entire batch) - Run
${CLAUDE_PLUGIN_ROOT}/scripts/run-auto-sub.sh $NUMBER(all phases spec→code→review→merge→verify, auto-starting from the currentphase/*state)- On failure: output a warning and skip to the next Issue (do not abort the entire batch)
List mode (--batch N1 N2 ...)
BATCH_LIST に記録された Issue 番号を、ユーザが渡した順序(指定順)で順次処理する(並び替えなし)。
候補取得(Fetch Batch Candidates)および createdAt ソートは List mode では行わない。
許容 Size: XS/S/M/L。ユーザが明示指定した以上、その意思は heuristic より強いシグナルのため Size 制限を緩和する。XL のみ例外で、警告を出して当該 Issue を skip し、残りの Issue は継続処理する(XL はサブ Issue 依存グラフによる並列実行経路を持ち、batch の直列処理と噛み合わないため)。
Batch checkpoint initialization (List mode only):
At the start of List mode, generate a BATCH_ID and write the full batch state:
BATCH_ID="${PPID}-$(date +%s)"
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh write_batch "$BATCH_ID" "N1 N2 N3" "" ""
(BATCH_ID is used for all subsequent checkpoint calls in this batch session; first list arg: space-separated full list in double quotes — quoting is required when the list contains spaces; remaining args: empty strings for completed and failed)
Process each Issue in BATCH_LIST in order:
- Check Issue labels:
gh issue view $NUMBER --json labels -q '.labels[].name' - If no
phase/*labels: run${CLAUDE_PLUGIN_ROOT}/scripts/run-issue.sh $NUMBER(issue triage → Size setting →phase/readyassignment)- On failure: output a warning; call
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER fail; skip to the next Issue (do not abort the entire batch)
- On failure: output a warning; call
- Re-check Size: call
${CLAUDE_PLUGIN_ROOT}/scripts/get-issue-size.sh $NUMBER; if Size is XL: output a warning; call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER fail; skip to the next Issue (do not abort the entire batch) - Blocked-by check: Extract blocker numbers from the Issue body:
gh issue view $NUMBER --json body -q '.body' | grep -ioE "blocked by #[0-9]+" | grep -oE "[0-9]+"- If no blockers found: skip to step 5
- For each blocker
$BLOCKER:gh issue view $BLOCKER --json state,labels -q '{state: .state, phases: [.labels[].name | select(startswith("phase/"))]}'- If
stateis"CLOSED"orphasescontains"phase/done": gate released — continue to next blocker - Otherwise: extract
$BLOCKER_PHASE(firstphase/*label of blocker, or"OPEN"if nophase/*label); output warning and skip$NUMBER(do NOT callupdate_batch— keeps$NUMBERinremainingfor/auto --batch --resume):Warning: #$NUMBER blocked by #$BLOCKER which is $BLOCKER_PHASE (manual post-merge pending). Skipping #$NUMBER. After completing #$BLOCKER manually, resume with /auto --batch --resume.
- If
- Run
${CLAUDE_PLUGIN_ROOT}/scripts/run-auto-sub.sh $NUMBER(all phases spec→code→review→merge→verify, auto-starting from the currentphase/*state)- On success: proceed to step 6
- On failure: output a warning; call
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER fail; skip to the next Issue (do not abort the entire batch)
- Verify orchestration (after run-auto-sub.sh success):
- Re-fetch current labels:
gh issue view $NUMBER --json labels -q '.labels[].name' - If
phase/verifyis present in labels:- If
--non-interactiveis NOT in ARGUMENTS: invokeSkill(skill="wholework:verify", args="$NUMBER")in the parent session- On success: call
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER complete - On failure or output contains
MAX_ITERATIONS_REACHED: output a warning; call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER fail; skip to the next Issue
- On success: call
- If
--non-interactiveIS in ARGUMENTS: output "Skipping verify for #$NUMBER (non-interactive mode); phase/verify remains"; call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER complete
- If
- If
phase/verifyis NOT in labels: call${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh update_batch "$BATCH_ID" $NUMBER complete
- Re-fetch current labels:
After all Issues are processed, delete the batch checkpoint:
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh delete_batch "$BATCH_ID"
Resume mode (--batch --resume)
Entered from Step 1 when --batch --resume is detected with no numeric tokens after --batch.
- Call
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh list_active_batchesand capture the output asACTIVE_BATCH_IDS(newline-separated list).- If
ACTIVE_BATCH_IDSis non-empty:- In interactive mode: present candidates to user via AskUserQuestion to select a BATCH_ID
- In non-interactive mode: use the last line (most recent entry) as
BATCH_ID
- If
ACTIVE_BATCH_IDSis empty: fall back toBATCH_ID="default"(handles pre-BATCH_ID migration case where.tmp/auto-batch-state.jsonmay exist from an older run)
- If
- Call
${CLAUDE_PLUGIN_ROOT}/scripts/auto-checkpoint.sh read_batch "$BATCH_ID"and capture the output asREMAINING. - If
REMAININGis empty: output "No resume target found. Run/auto --batch N1 N2 ...to start a new batch." and exit. - Output a log line: "Resuming batch: batch_id=$BATCH_ID, remaining issues = $REMAINING"
- Treat
REMAININGasBATCH_LISTand process each Issue following the same steps as### List mode (--batch N1 N2 ...).- Note: do NOT call
write_batchagain at the start (the existing batch state file is the live state); only callupdate_batch "$BATCH_ID"anddelete_batch "$BATCH_ID"as per List mode.
- Note: do NOT call
Batch Completion Report
After all Issues are processed, report results (success/skip/failure) for each Issue.
Then read ${CLAUDE_PLUGIN_ROOT}/modules/next-action-guide.md and follow the "Processing Steps" section with:
SKILL_NAME=autoRESULT=success- (omit
ISSUE_NUMBER— batch run with multiple issues, guide will be omitted per module logic)
Notes
- Run after
/issueis complete (spec is auto-run if not yet complete) - Detailed logic for each phase (review comment handling, conflict resolution, etc.) is delegated to each skill
autoitself does not post Issue comments (posted individually within each phase)- Skills are installed via the plugin marketplace and referenced through
${CLAUDE_PLUGIN_ROOT}at runtime
Checkpoint Design
reconciler-first / checkpoint-as-hint
/auto --resume N resumes a single Issue after interruption. The authority for the current phase is GitHub labels + reconcile-phase-state.sh — the checkpoint is a hint only.
| Information | Authority source (SSoT) | Checkpoint role |
|---|---|---|
| Current phase | GitHub labels (phase/*) + reconcile-phase-state.sh |
Not consulted (labels take priority) |
| PR number | gh pr list (live query) |
Not stored |
| Route (patch/pr/XL) | Derived from Size | Not stored |
| verify iteration_count | None (in-run variable only) | Persisted (cross-run limit management) |
| Batch remaining list | None | Persisted (incomplete Issue list) |
When checkpoint and labels conflict, labels win and the checkpoint is discarded (stale).
Checkpoint file schemas (JSON v1)
// .tmp/auto-state-NUMBER.json (single Issue)
{
"schema_version": "v1",
"issue_number": 317,
"verify_iteration_count": 2,
"last_update": "2026-04-22T16:10:05Z"
}
// .tmp/auto-batch-state-${BATCH_ID}.json (batch, per-session)
// BATCH_ID="default" -> .tmp/auto-batch-state.json (backward compat)
// BATCH_ID="12345-1718336400" -> .tmp/auto-batch-state-12345-1718336400.json
{
"schema_version": "v1",
"mode": "list",
"remaining": [104, 105],
"completed": [101, 102],
"failed": [103],
"last_update": "2026-04-22T16:10:05Z"
}
// .tmp/auto-batch-active.json (active batch index)
{
"schema_version": "v1",
"active_batch_ids": ["12345-1718336400", "67890-1718336500"],
"last_update": "2026-04-22T16:10:05Z"
}
BATCH_IDformat:${PPID}-$(date +%s)(parent PID + Unix timestamp; bash 3.2+ compatible)"default"BATCH_ID maps to.tmp/auto-batch-state.jsonand is not tracked in the active index- Parallel
/auto --batchsessions each use a distinct BATCH_ID, so their state files do not collide
Writes are atomic: write to *.json.tmp then mv to the target path to prevent corrupt reads on interruption.
Stale checkpoint detection
A checkpoint is considered stale and must be discarded when either of the following holds:
- issue_number mismatch: the
issue_numberfield in.tmp/auto-state-NUMBER.jsondoes not matchNUMBER(handled byauto-checkpoint.sh read_single— returns 0 and exits 0) - Label conflict: live GitHub labels show
phase/donefor the issue while a checkpoint exists (handled by/autoStep 4 initialization — callsdelete_singleand resets count to 0)
In both cases, the label + reconciler state is the authority and the checkpoint is dropped.
Checkpoint cleanup triggers
| Event | Cleanup action |
|---|---|
| Verify loop succeeds | delete_single $NUMBER |
MAX_ITERATIONS_REACHED |
delete_single $NUMBER |
Issue CLOSED / phase/done detected at resume |
delete_single $NUMBER (stale label conflict path) |
| Batch fully processed | delete_batch "$BATCH_ID" (also removes from active index) |
.tmp/ files are gitignored and are not committed.
Scope
XL route checkpoint (sub-issue dependency graph + parallel worktree state) is out of scope for this implementation. XL sub-issues can each be individually resumed with /auto --resume N on their sub-issue numbers.