| name | autopilot |
| description | Carry a well-scoped GitHub issue through the full dev loop autonomously, stopping at a per-run tier boundary (PR-ready, or merge+deploy for small reversible changes). |
| argument-hint | [issue-number] [--to pr|merge] |
Autopilot
Drive a single GitHub issue through the project's full development loop with minimal supervision, stopping at a boundary you authorize up front. This composes the existing skills (/resolve-issue, /simplify, /create-pr, /verify, /walkthrough, and the built-in review) plus bin/ci — it does not reinvent them.
Use this when an issue is clear and well-specified and you want it carried to a review-ready PR (or, for small reversible changes, all the way to merge) without invoking each step by hand. For issues that need close collaboration, use the individual skills instead.
Arguments
$ARGUMENTS contains the issue number and an optional tier flag:
--to pr (default): run the full loop and stop at a review-ready PR. No merge, no deploy. This is the well-lit path — the human merge gate catches everything.
--to merge: run the full loop, then merge (which auto-deploys) only if the change passes the narrow-class gate in Step 8. Otherwise it degrades to --to pr and stops. Passing --to merge IS your per-run authorization to merge this one issue; it is not a standing capability.
Examples: /autopilot 754 (→ pr), /autopilot 754 --to pr, /autopilot 847 --to merge.
Parse the issue number and tier from $ARGUMENTS. If no tier is given, default to pr. If the tier is unrecognized, stop and ask.
Build model — reconcile against the issue's model: label
Repos that have adopted the per-issue model convention (~/.claude/docs/model-selection-strategy.md) carry a model: fable / model: opus / model: sonnet label recording the build tier chosen at triage. Read it as part of the announce:
gh issue view <n> --json labels --jq '[.labels[].name | select(startswith("model: "))] | first // "none"'
Autopilot cannot act on that label the way /autopilot-batch does — a running agent cannot switch its own model, so this skill still runs at whatever model invoked it. What it can do is reconcile before any work starts. Ladder, cheapest to most capable: Sonnet 5 → Opus 5 → Fable 5.
- No label — the common case, and never a reason to stop. Either the repo hasn't adopted the convention or triage hasn't reached this issue; fall back to the existing judgment (announce that you're proceeding on the invoking model) and run.
- Session model matches the label — say so in one line and proceed.
- Session model is below the labeled tier (e.g. Sonnet running a
model: opus issue) — stop and ask. This is an under-build, the direction that produces quietly wrong work, and the announce is the cheapest possible moment to catch it. Report the mismatch and recommend re-invoking at the labeled tier. Exception: if whoever invoked you states the lower tier was chosen deliberately — an /autopilot-batch override at its confirm gate is the usual case — the human gate already happened. Note the deliberate downgrade and proceed.
- Session model is above the labeled tier (e.g. Opus running a
model: sonnet issue) — note it once and proceed. Over-building costs plan-limit headroom, not correctness, and halting an authorized run over a consumption preference is the worse trade. Carry the note into the completion report so the pattern shows up if it repeats.
The label governs the build only. It never lowers a derived tier: the review tier in Step 6 and the --to merge gate in Step 8 are unaffected, and the merge go/no-go floor stays Fable regardless of any label — a model: sonnet issue does not get a cheaper merge decision. (In a batch run, /autopilot-batch enforces that floor by building every --merge issue with Fable, and applies the standing review floor — Opus or above, never below the build — to every --to pr PR.)
If the issue body opens with a model callout (a > 🤖 Recommended model: … blockquote), it names the watch-item or escalation trigger behind the tier choice — read it, treat it as part of the spec, and watch that specific thing during Step 1.
Escalation is the escape hatch, not a silent upgrade. If the work proves materially harder than the label assumed, stop, report what you hit, and recommend re-running at a higher tier — noting that the issue's label should be updated afterward so the record stays honest.
The "stop and ask" escape hatch (applies to every step)
Autopilot is autonomous, not reckless. Stop immediately, report what you found, and wait for the user if any of these arise — do not guess or push through:
- The
/resolve-issue planning checkpoint (Step 3 of that skill) judges the issue complex or ambiguous — multiple subsystems, real design choices, or unclear acceptance criteria.
- The issue's
model: label names a higher tier than the model you are running (see "Build model" above) — an under-build, caught before any work starts.
- A decision surfaces that the project's own guardrails reserve for the user: a new DB column not in the data model, a changed model association, an altered public URL, a new dependency, or a change to the event status lifecycle (see the project CLAUDE.md "Handling Ambiguity" table).
- Tests fail in a way you cannot confidently resolve, or a fix would require inventing scope beyond the issue.
- The spec conflicts with what you find in the code (three valid responses per global CLAUDE.md: implement as written, ask, or propose a change — the latter two mean stop).
- A permission prompt blocks progress and there is no compliant alternative path.
When you stop, post a concise summary: what's done, where you stopped, exactly what you need from the user, and the recommended next command.
Your task
Announce the run first: issue number, tier, the boundary ("will stop at review-ready PR" / "will merge + deploy if the narrow-class gate passes"), and the model reconciliation from the section above (the issue's model: label, the model you are running, and the verdict — match / no label / over-model note / stopping on an under-model). Confirm you are starting from an appropriate base (a clean main/master, or an existing worktree branch for this issue). Then work the loop:
Step 1 — Resolve
Invoke /resolve-issue <number> and let it run its 6 steps, with these autopilot overrides:
- Honor its planning checkpoint as the escape hatch above. Proceed autonomously for a small, well-scoped issue; stop and ask for a complex/ambiguous one.
- Override its Step 6 stop.
/resolve-issue ends by asking whether to create a PR — in autopilot, do not stop there; continue the loop.
- Commit protocol: follow the global CLAUDE.md file-based commit flow (write the message with the Write tool,
git commit -F .git_commit_msg, remove it). Never put $(...) or backticks in a commit command.
- AC checkboxes are best-effort and must never block the run. If
/resolve-issue checks off acceptance-criteria boxes, use gh issue edit <n> --body-file <file> (never --body "$(...)", which the auto-mode classifier flags). If the write still prompts or fails, skip it and note "AC boxes left for manual check-off" — the real issue↔PR link is Closes #N in the PR body, so the checkboxes are cosmetic.
Step 2 — Simplify
Invoke /simplify to review the changed code for reuse, simplification, and efficiency, and apply the fixes. Commit any resulting changes (file-based commit flow). This is quality-only; it does not hunt for bugs.
Step 3 — Create the PR
Invoke /create-pr. It infers the issue from the branch name and opens a ready-to-review PR with Closes #<number>. Capture the PR number for the next steps. (Per the project workflow, the PR is opened before verify/walkthrough by design — the diff is reviewable while those checks run.)
Steps 4–5 — Verify and Walkthrough (user-facing changes only)
Match the verification to the change's actual surface — don't reflexively invoke /verify:
-
Visible / interactive surface (a page, form, or flow a user drives): invoke /verify <PR> then /walkthrough <PR>. Both may report "not applicable" and exit — that's expected; skip them when they do.
-
Runtime behavior but no visible surface, fully test-covered (e.g. i18n key resolution under raise_on_missing_translations, a config value, a computed default): substitute a targeted inline verification for the browser /verify — run the specific test or exercise the behavior directly to confirm it resolves, and note what you checked in the debrief. A browser walkthrough adds nothing here, so skip it.
-
No runtime surface at all (docs, comments, a pure refactor with green tests): skip both.
-
QA is local-dev-only. The app is POST-LAUNCH (real distributor data). Never drive the production site — no walkthroughs, /verify, or data-mutating flows against live. Local dev only. (See project CLAUDE.md "QA Testing Policy".)
-
Start the app the headless-reliable way, never bin/dev (its Tailwind watcher exits without a TTY and foreman SIGTERMs the whole group, killing the server). Use:
bin/rails tailwindcss:build
bin/rails server
-
For 375px mobile checks use the chrome-devtools emulate tool (true viewport), not window resize. Assert window.innerWidth and no horizontal overflow.
-
Do not run /walkthrough --publish — publishing stays a human-gated action.
Step 6 — Code review
Spawn a review subagent — do not review your own work in-session. You built this diff; a self-review inherits every assumption that produced it. A fresh subagent starts from a clean context and reads the code as written rather than as intended, which is the bulk of what the review is buying.
Tell it in the prompt to report findings only — no edits, no commits, no pushes. That is a prompt constraint, not a sandbox: a general-purpose reviewer holds Edit and Write, so nothing enforces it but the instruction. You triage and fix what it reports, and Step 7's CI run happens in this session, so only one agent ever writes to the branch. (/autopilot-batch Step 4 deliberately inverts this — its reviewer owns its own worktree, so it fixes and pushes directly. Branch ownership is what differs, not the review standard.)
The subagent runs the built-in review <PR#> — the pull-request reviewer. Autopilot always has a PR number here; Step 3 captured it. It shares this session's working directory, already on the PR branch, so it needs no worktree and no gh pr checkout.
review takes a PR number and nothing else — there is no effort level. Depth is not an argument you pass; it is three things you choose:
| Lever | How you turn it up |
|---|
| Spawn tier | The model you spawn the reviewer at. You cannot switch your own model mid-run, but the Agent tool takes a model override, so a Sonnet session can and should spawn an Opus reviewer. Floor: Opus 5 or above, and never below the build — the same absolute floor /autopilot-batch applies, which is what keeps a model: sonnet issue from buying a cheaper review. Escalate above the floor for a higher-risk diff: tier --to merge (ships to prod with no human review before deploy), or a large / multi-subsystem / security- or data-sensitive change. |
| Reviewer fan-out | Spawn several reviewers with distinct adversarial lenses (correctness, security, does-the-test-actually-test-it) rather than one. Use for the same higher-risk diffs that justify a tier bump. For a security- or data-sensitive diff the built-in security-review is also model-invocable and is the sharper second lens — run it alongside review, not instead of it. Note the different scope: review takes a PR number, while security-review works off pending changes on the current branch, so its reviewer must actually be on the PR branch. |
| Verification method | Instruct the reviewer to mutation-test its key claims: delete or disable the feature and confirm the covering test actually fails. Make this the default, not an escalation — a test that passes with the feature removed is the failure mode a read-only review structurally cannot see. |
Two invocation constraints worth knowing, because they are not obvious and cost a run to rediscover:
/code-review is not available here. It is a built-in, user-triggered command for a working diff, not a model-invocable skill — there is no frontmatter to change and no file to edit. review is not a workaround for it; it is the correct tool, because autopilot is reviewing a pull request.
- Never reach for
/code-review ultra — a billed cloud review, user-invoked by design. Leave it for the user.
All three facts this step depends on were verified empirically on 2026-07-28, from inside a worktree-isolated general-purpose subagent — the same position a /autopilot-batch build agent occupies: review and security-review both appear in a subagent's skill listing and both invocations are accepted; code-review appears in no listing under any spelling; and a subagent can spawn a nested subagent, so this step works when /autopilot is itself running inside a batch build agent. That last one is default-dependent — the Explore and Plan agent types exclude the Agent tool, so spawn the reviewer as general-purpose (the default).
State the reviewer's tier and lens count in one line. Then triage the findings against the issue's spec:
- Fix real correctness bugs and clear quality wins; commit and push (updates the open PR).
- Adjacent cleanup that finishes the same change is allowed. If the review surfaces the same defect in a sibling spot (e.g. a duplicated helper the diff only half-updated), fix it too rather than leaving the job half-done — and flag the expansion in the debrief. Being blocked by "technically out of scope" defeats autopilot's purpose. (For
--to merge, the Step 8 narrow-class gate independently re-checks the final diff, so cleanup that escapes the whitelist safely degrades the run to --to pr rather than shipping unseen.)
- A finding flagged "speculative" may actually be AC-mandated — check the issue before dismissing it.
- If a finding needs a product decision, that's the escape hatch — stop and ask.
Step 7 — Local CI + sign-off
Run the project's CI command. If whoever invoked you supplied a specific CI command, run that one and never bare bin/ci — a batch run does exactly this, handing you a wrapper that carries test-database isolation and serial execution. Those settings are not yours to drop: bare bin/ci there would run against the shared test database and clobber a concurrent session. With no such instruction — the standalone case — run bin/ci.
CI runs the full pipeline and produces the gh signoff that is the required branch-protection gate. Re-run it after any review/walkthrough fix so the sign-off attaches to the commit that will merge. If it fails, stop and report (do not merge or leave a broken PR silently).
Step 8 — Boundary
Tier pr: Stop here. Post the debrief-style summary below. Do not merge. Recommend the user run /merge-pr <PR> after their review.
Tier merge: First run the narrow-class gate. Auto-merge proceeds only if all hold:
Inspect with git diff --stat <base>...HEAD and check the changed paths. If any check fails, do not merge — announce which check failed, degrade to tier pr (post the summary, recommend /merge-pr), and stop.
If all checks pass, merge (this mirrors /merge-pr, which stays user-gated by design; you merge here only because --to merge authorized this one issue):
- Confirm CI is green:
gh pr checks <PR> (hard gate — never merge on a failing check).
gh pr merge <PR> --squash (no --delete-branch; GitHub auto-deletes the remote branch).
- Update local state:
git switch <base> && git pull, then git branch -D <branch> (squash merges need force-delete).
- Post-deploy vigilance (merge auto-deploys to Fly): watch the deploy with
gh run watch (or gh run list), smoke-test prod once it's green (/up health check + a key route), and check/resolve any related Honeybadger fault. Report the deploy outcome.
Completion report (both tiers)
Post a debrief-style summary:
## Autopilot — issue #N ([--to pr | --to merge])
- PR: #M — <title> <url>
- Model: built on <model> — issue labeled <model: x | none> [<matched | ran above the label, consider the labeled tier next time>]
- Loop: resolve ✓ simplify ✓ create-pr ✓ verify [✓/n·a] walkthrough [✓/n·a] review ✓ (<tier>, <n> lens) CI ✓ (signed off)
- Files: <count> changed
- Notable decisions / cleanups: <one or two lines>
- AC checkboxes: <checked / left for manual>
- Boundary: <held at PR-ready | merged + deployed (deploy <status>, Honeybadger <status>)>
- Your call: <review + /merge-pr #M | nothing — shipped | I stopped because …>
Important
--to pr is the default and never merges or deploys. Only an explicit --to merge can, and only through the narrow-class gate.
- The
model: label sets the build tier only, and only ever advises this skill. A single agent can't switch its own model, so here the label is a reconciliation at announce time — it never lowers the Step 6 review tier or the Fable merge floor, and its absence changes nothing.
- The Step 6 reviewer is a subagent for independence, not just for tier. Even spawned at the same model as the build, a fresh context catches what a self-review cannot — the builder's blind spots and its assumptions about what the code does are exactly what a same-session review carries forward intact.
- The narrow-class gate is a hard filter, not advice. A mislabeled migration-bearing issue cannot ship unseen — worst case autopilot stops and asks.
/merge-pr, /walkthrough --publish, and deploy-on-merge stay human-gated. Autopilot's merge path is the single authorized exception, scoped to one issue by the --to merge flag.
- Prefer composing the real skills over re-implementing them so their improvements flow through. The only inlined logic is the Step 8 merge, because
/merge-pr is deliberately not model-invocable. A skill that turns out not to be invocable is a signal to find the right tool, never to hand-roll a substitute — a hand-rolled step that still reports as the real one is the worst outcome, because the report reads as though the gate held.
- Push resilience. A
git push can fail transiently with an SSH signing-agent error (sign_and_send_pubkey … communication with agent failed) — a self-healing round-trip hiccup with the SSH agent, not an auth denial (which would read agent refused operation). Retry with short backoff (~3 attempts) before treating a push as failed; only stop and report if it still fails after retries. Applies wherever autopilot pushes — the /create-pr push in Step 3 and any review-fix push in Step 6.
- An inherited CI command outranks this skill's default. When a caller hands you a specific CI command it is carrying constraints you cannot see from in here — under
/autopilot-batch it is test-database isolation and serial execution, and substituting bare bin/ci would run against the shared test database and clobber a concurrent session. This is the one place where composing skills leaks: the outer skill's environment does not reach you through the Bash tool, only through the instruction, so treat that instruction as binding.