- name
- auto-pilot
- description
- Run an autonomous triage-resolve-review-merge loop to auto-pilot the GitHub issue backlog, resolving everything until done with zero prompts. Don't use for single-issue work (/issue-resolver), triage (/issue-triage), or PR review (/issue-pr-review).
- license
- MIT
- compatibility
- Requires git and GitHub CLI (gh) with auth and push access. Requires merge permission for auto-merge. Requires issue-triage, issue-resolver, issue-analysis, and issue-pr-review to be installed from the same distribution. Optional: issue-creator for normalizing unstructured issues mid-loop.
- metadata
- {"version":"2.9.0","author":"Luong NGUYEN <luongnv89@gmail.com>","effort":"max"}
# /auto-pilot <!-- a:ap-skill-title -->
Fully autonomous development loop: triage, pick, resolve, review, fix, merge, repeat — zero user prompts.
It orchestrates the other IDD Stack skills over the backlog. It triages **once** at loop start (reusing a fresh `.gitissue/triage.json`, *Mode Detection*) and picks from that order; with `autopilot.max_parallel` above 1, independent issues resolve concurrently in isolated worktrees, but PRs are reviewed and merged one at a time. After each merge, update the cached order in place. *Merge Modes* decide which PRs merge; a critical issue with unresolved review problems stops the loop for the user.
## Autonomy Philosophy <!-- a:ap-autonomy -->
**Always proceed, never block on recoverable situations.** Every decision falls into one of two categories:
1. **Auto-decide** (99% of cases) — pick the best option and continue:
- Switching branches, stashing, syncing; choosing implementation approaches; skipping failed issues
- Retrying after transient failures (driver rule 5, `references/docs/platform-github.md`; loop: `references/preflight.md` → *Transient-failure retry*)
- Merging PRs that pass review, when `autopilot.mode` permits
- **PR blocked by an unmerged dependency** — a `Depends on #N` / `Blocked by #N` target is still open or unmerged: never merge out of order, never stop. Record `blocked_by_dependency`, leave the PR open, skip the issue for the session, and continue (off with `autopilot.respect_dependencies: false`).
2. **Confirm with user** (rare) — irreversible or dangerous actions only:
- Force-pushing to a shared branch, deleting remote branches others use, or changing repository settings or branch protection
- Any dangerous pattern: destructive ops, production deployment, package publishing
- **Critical issues with unresolved review problems** — an `autopilot.critical_labels` issue that exhausts its review cycles. This is the **only** documented stop-and-ask exception; everything else, a dependency-blocked merge included, is auto-decided.
When in doubt, skip rather than stop: a skipped issue can be retried.
**Delegated skills inherit the autonomy.** Every IDD Stack skill `/auto-pilot` invokes gets `--auto` **and** `IDD_AUTO_MODE=1` exported, every time (`references/docs/auto-mode.md`). **Never rely on the callee detecting auto-pilot provenance** — only the flag and the variable are checkable.
## Invocation
| Invocation | What happens |
|------------|--------------|
| `/auto-pilot` | Start the loop |
| `/auto-pilot --issues 5,10,12` | Process exactly these issues, in this order (no triage) |
| `/auto-pilot --limit N` | Process at most N issues |
| `/auto-pilot --dry-run` | Show the execution plan; resolve nothing |
| `/auto-pilot --skip N` | Skip issue #N this session |
| `/auto-pilot --resume` | Resume the run in `.gitissue/run-state.json` at its recorded phase |
| `/auto-pilot --fresh` | Ignore recorded run state (the default when none exists) |
| `/auto-pilot --force-unlock` | Reclaim a lock whose run is dead, then start |
**Combining flags:** `--issues` combines with `--dry-run` and `--skip`, not with `--limit` (the list is the limit). `--resume` cannot combine with `--dry-run` (a dry run mutates nothing) or with `--fresh`. The resume entry gate, the run lock, and the checkpoints live in `references/phases/phase-0-lock-resume.md` (*Step 1.0*) and `references/preflight.md` (*Run lock*).
## Prerequisites
**Stop rule** — for every stop before the loop starts:
1. Print the error block from `references/error-messages.md`: its `✗` line is the result and evidence, its `To fix:` line the next action.
2. Print the run-stats footer (`references/run-stats.md`); before the config load, `elapsed n/a`.
3. Stop. Only the rate-budget stop also prints a summary (`Result: RATE LIMITED`).
Run these checks in order:
1. Git repository: `git rev-parse --git-dir`
2. `gh` installed: `which gh`
3. Authenticated: `gh auth status`
4. GitHub remote: `git remote -v`
5. Required skills installed (*Dependency Preflight*)
6. Working tree state: `git status --porcelain` (dirty → auto-stash, below)
7. Current branch: `git rev-parse --abbrev-ref HEAD` (not default → auto-switch, below)
8. **Check the rate budget** (driver rule 4, `references/docs/platform-github.md`): `gh api rate_limit --jq '{remaining: .rate.remaining, reset: .rate.reset}'`. Below 500, read `references/preflight.md` (*Rate-limit pause*) first.
- 500 or more: proceed. 200–499: print the `⚠` variant and continue.
- Below 200, `reset` inside `autopilot.max_runtime_minutes`: pause until `reset`, then re-probe. The fit is measured from the clock here, and that clock is read **once**, at the first probe, so every consecutive pause shares one deadline instead of pushing it forward. There is **no run lock yet**.
- Below 200, `reset` past the budget or unknown: stop with `✗ Insufficient GitHub API rate budget for auto-pilot` (`Result: RATE LIMITED`).
9. **Confirm merge permission**: `gh repo view --json viewerPermission`. `ADMIN`, `MAINTAIN` or `WRITE`: proceed. `READ`, `TRIAGE` or `NONE`: print `⚠ Insufficient merge permission — running in no-merge mode`, skip Phase 5, and leave every PR open.
## Dependency Preflight (mandatory)
`/auto-pilot` invokes sibling IDD Stack skills from its own distribution. Verify them **before** the run lock or any mutation, with `SKILL_DIR` bound to this SKILL.md's dirname:
```bash
missing=""
for s in issue-triage issue-analysis issue-resolver issue-pr-review; do
[ -f "$SKILL_DIR/../$s/SKILL.md" ] || asm list -p claude --json 2>/dev/null | grep -q "\"$s\"" || missing="$missing $s"
done
if [ -n "$missing" ]; then echo "Missing required skill(s):$missing" >&2; exit 1; fi
```
If any are missing, apply the stop rule with the `✗ Missing required IDD Stack skill(s)` block from `references/preflight.md`. `issue-creator` is optional: on a miss, warn and skip mid-loop normalization. Invoke it with `--auto` and `IDD_AUTO_MODE=1` — its Normalize apply gate sits directly in the loop's path.
### Bundled dependency precheck
Verify these files exist relative to this SKILL.md's dirname. A missing one is a broken install: stop with the `✗ Missing bundled dependency` block from `references/preflight.md`.
- `references/phases.md`
- `references/phases/phase-0-lock-resume.md`
- `references/phases/phase-1-triage-pick.md`
- `references/phases/phase-2-resolve.md`
- `references/phases/phase-3-4-review.md`
- `references/phases/phase-5-merge.md`
- `references/subagent-prompts.md`
- `references/preflight.md`
- `references/orchestration.md`
- `references/explicit-list-mode.md`
- `references/run-log.md`
- `references/summary-format.md`
- `references/run-stats.md`
- `references/configuration.md`
- `references/error-messages.md`
- `references/examples.md`
- `references/docs/idd-methodology.md`
- `references/docs/sync-conventions.md`
- `references/docs/config-schema.md`
- `references/docs/run-log-schema.md`
- `references/docs/naming-conventions.md`
- `references/docs/platform-github.md`
- `references/docs/shared-agent-conventions.md`
- `references/docs/agent-model-effort.md`
- `references/docs/agent-overrides.md`
- `references/docs/terminal-style.md`
- `references/docs/auto-mode.md`
- `references/docs/post-merge-cleanup.md`
- `references/scripts/gi-config.py`
- `references/scripts/gi-runlog.py`
- `references/scripts/gi-deps.py`
- `references/scripts/gi-ci-wait.py`
- `references/scripts/gi-gh.py`
- `references/scripts/gi-issue.py`
- `references/scripts/gi-branch.py`
- `references/scripts/gi-triage-graph.py`
- `references/scripts/gi-state.py`
- `references/scripts/gi-postmerge.py` — post-merge cleanup: worktrees, branch, switch to the updated default branch
- `references/scripts/gi-ratelimit.py` — rate-limit verdict, chunked pause, transient-failure backoff, and the run's wall-clock budget
### Run lock and branch sync
**Acquire the run lock before the first mutation** (owner-pid and TTL rules: `references/preflight.md` → *Run lock*):
1. From the repo root, run `python3 references/scripts/gi-state.py --lock --pid "$PPID"`. Add `--resume` under `/auto-pilot --resume`, and `--dry-run` under `--dry-run` (reports the holder, acquires nothing).
2. Exit 0 (`acquired`, `reclaimed`, `reacquired`): this run holds the lock — evidence about the lock, never the run state.
3. Exit 3: another run holds it. Apply the stop rule with `✗ Another /auto-pilot run is in progress`.
4. No `python3`, exit 2, or exit 4: print `⚠ gi-state unavailable` and continue unlocked and un-resumable.
Then auto-stash a dirty tree and switch/rebase onto the default branch without confirmation (`references/preflight.md` → *Auto-stash and branch sync*); `git stash pop` after the run.
## Configuration
Load config once with `python3 references/scripts/gi-config.py`:
- **Working directory:** the repo root (elsewhere it reports `first_run: true` and discards the real config). **Script path:** relative to this SKILL.md, not the working directory.
- **Exit 0:** use the printed `config`; if `first_run` is `true`, print the `○ First run` line below.
- **Exit 3:** `.gitissue.yml` is invalid — apply the stop rule with *Invalid config*.
- **Script file absent:** a broken install and not a degrade — stop with `✗ Missing bundled dependency`.
- **Anything else:** print `⚠ gi-config unavailable — using the inline defaults below`, load `.gitissue.yml` once, and fill missing keys from the defaults below. With no `.gitissue.yml`, print:
```
○ First run — using default config. Run /init-gitissue to customize.
```
Never re-read the config. **The run clock is `run_state.started_at`**; the run-stats footer measures `elapsed` from it.
Defaults (rationale: `references/configuration.md`): `autopilot.mode: balanced` · `autopilot.merge_partial: false` · `autopilot.max_iterations: 10` · `autopilot.max_parallel: 1` · `autopilot.review_cycles: 3` · `autopilot.auto_merge: true` (legacy) · `autopilot.pause_on_failure: false` · `autopilot.skip_labels: ["wontfix", "blocked", "do-not-merge"]` · `autopilot.critical_labels: ["critical", "priority:critical"]` · `autopilot.respect_dependencies: true` · `autopilot.quarantine_after: 3` · `autopilot.quarantine_label: "auto-pilot-quarantined"` · `autopilot.max_runtime_minutes: 0` (unbounded). Sub-skills inherit `resolve.*` and `triage.*`. Then:
- **Validate `autopilot.max_parallel`** (integer `1..8`); anything else is invalid config. `1` takes the legacy sequential path.
- **Quarantine label:** append it to the effective `skip_labels` set as part of this config load, so the pick skips quarantined issues.
### Merge Modes
`autopilot.mode` controls when the loop may merge. Default install never merges a PR with unresolved fixable review issues; partial merge needs explicit opt-in. In every mode, a critical issue with unresolved review problems stops and asks the user.
| Mode | Clean PR | Partial PR (cycles exhausted, non-critical) |
|------|----------|---------------------------------------------|
| `conservative` | leave open | leave open + follow-up issue |
| `balanced` (default) | merge | leave open + follow-up issue |
| `aggressive` + `merge_partial: true` | merge | merge + follow-up issue (`partial_followup`) |
| `aggressive` + `merge_partial: false` | merge | leave open + follow-up issue (as `balanced`) |
**Resolution rules:**
- `autopilot.mode` set: it wins; legacy `autopilot.auto_merge` is ignored.
- Neither key in `.gitissue.yml`: `balanced`.
- Only `autopilot.auto_merge` **explicitly present**: `auto_merge: true` ≈ `aggressive` + `merge_partial: true`; `auto_merge: false` ≈ `conservative`.
Gate logic: `references/phases/phase-3-4-review.md` (partial) and `references/phases/phase-5-merge.md` (merge).
## Context Window Management
The main agent is a **lightweight orchestrator**; subagents with fresh context do the heavy work. **The main agent never reads source files, reads PR diffs, runs tests, or writes code.** Each iteration spawns a resolver then a PR reviewer (`/issue-pr-review --auto --no-merge`, so merging stays the main agent's Phase 5 job); explicit list mode adds a one-time analyzer; `max_parallel > 1` fans out resolver-only lanes, then drains them one at a time. Delegated skills size their shared agents per `references/docs/agent-model-effort.md` and `references/docs/shared-agent-conventions.md`. Lanes and ownership: `references/orchestration.md`. Read `references/subagent-prompts.md` once at skill start.
## Mode Detection
`--issues` selects explicit list mode; its comma-separated list fixes **which** issues run and **in what order**.
- **Triage mode** (default). Triages **once** at loop start (reusing `.gitissue/triage.json` when *Step 1.1a*'s cache gate reads `fresh`), then updates the cache in place after each merge (*Step 1.6*); it re-triages only on a pick miss or every `autopilot.retriage_every` iterations.
- **Explicit list mode** — an analysis pass that validates, deduplicates and orders the list replaces Phase 1 (`references/explicit-list-mode.md`).
## Loop Overview
Phase 0 once, then 5 phases per iteration until the backlog is done or a stop condition fires. Phases 3–5 always run once per lane, serially:
```
◆ Auto-Pilot
┄┄┄┄┄┄┄┄┄┄┄┄
Phase 0 — Run state once, before the loop: resume gate, then --init
Phase 1 — Triage/Pick (triage once at start; skipped in explicit list mode)
Phase 2 — Resolve 1 resolver, or bounded resolver-only fan-out
Phase 3+4 — Review-Fix serialized /issue-pr-review --auto --no-merge
Phase 5 — Merge serialized merge, log, cache update, lane cleanup
```
### Step completion reports
عرض على GitHub