Skip to content

Autopilot — autonomous agent runs

import { Aside } from ‘@astrojs/starlight/components’;

Autopilot lets warden run a goal-directed, long-lived agent loop over your codebase. You describe what you want in a plan file, enable autopilot, and warden takes care of the rest: spawning a manager agent that breaks the goal into tasks, delegates each task to worker agents in isolated worktrees, gates their branches through CI, and lands them into an integration branch — healing itself when stuck, and escalating to cheaper backends when rate-limited.

A run is a small fleet with separated jobs:

  • Manager (role autopilot) — the long-lived agent that drives the whole run.
  • Worker (role worker) — one per task by default, owning it end-to-end (implement → self-review → PR → CI green → merge) and reporting back to the manager. A large task may instead get a pipeline of implementer/reviewer/auto-merger agents.
  • Resolver (role brain) — spawned on demand to unblock a stuck worker or make an ad-hoc design call, without human interaction.

A daemon-internal overwatch backstop keeps the fleet moving: it nudges the manager to tend workers that fall idle or wait on input. It is fully automatic — no user action needed — and its cadences are generous (a backstop, not a pacer).

For the underlying design — manager/worker/resolver topology, overwatch, ledger, guardian, cost-tier ladder — see Autopilot concepts.


Before enabling autopilot, make sure:

  • warden daemon is running and healthy (warden doctor)
  • At least one agent backend is authenticated (claude --version for the default Claude backend; or configure an alternative in ~/.warden/config.yaml)
  • Your repository has a main branch and GitHub Actions CI (or a local CI configured in .warden/check.yml) — the gated step verifies the gate before landing
  • gh is authenticated (gh auth status) — autopilot opens PRs and checks CI status via the GitHub CLI

Step 1 — scaffold with warden autopilot init

Section titled “Step 1 — scaffold with warden autopilot init”

Run init inside the repo you want autopilot to drive:

Terminal window
cd /path/to/my-repo
warden autopilot init

This creates two files (without overwriting either if they already exist):

autopilot.plan.yaml — edit this to describe your goal:

version: 1
goal: "Describe your goal here"
constraints:
- "keep all changes behind a feature flag"
tasks: [] # leave empty to let the manager decompose the goal automatically

~/.warden/config.yaml — updated with an autopilot block:

autopilot:
enabled: false
plan_file: /path/to/my-repo/autopilot.plan.yaml
integration_branch: autopilot/integration
gate_mode: ci # ci | local | auto (default: auto picks ci when available)

Commit autopilot.plan.yaml to your repo so the manager can read it from its worktree.


Open autopilot.plan.yaml and fill in the goal. The manager decomposes the goal into tasks automatically if you leave the tasks: list empty. Or provide coarse tasks yourself to guide decomposition:

version: 1
goal: "Ship the notifications feature end-to-end"
constraints:
- "all changes behind a feature flag named NOTIFICATIONS_ENABLED"
- "every PR must pass lint and tests"
tasks:
- id: api
prompt: "Implement the notifications REST API per docs/specs/notify.md"
- id: ui
prompt: "Implement the notification bell and dropdown UI"
after: [api]
- id: e2e
prompt: "Write E2E tests covering the notifications happy path"
after: [ui]

The plan file is owner-editable mid-flight — the manager re-reads it on each planning tick. You can add tasks or change constraints while a run is active.


Step 3 — configure the cost tier (optional)

Section titled “Step 3 — configure the cost tier (optional)”

By default, the manager picks the cheapest available backend. To explicitly configure which backends autopilot may use, edit ~/.warden/config.yaml:

autopilot:
# allow_tiers controls which cost tiers the manager may use.
# Values: free, subscription, gated_ppu (pay-per-use — requires explicit opt-in)
allow_tiers: [free, subscription] # default: [free, subscription]
# backend_preference: explicitly order the backends to try (optional)
# backend_preference: [antigravity, claude, codex]
TierBackendsNotes
freeantigravityGoogle-hosted free tier; no billing
subscriptionclaude, codexYour existing plan
gated_ppuAPI-billed backendsRequires explicit opt-in

If you only want the manager to use the free tier (e.g. to test autopilot at zero additional cost), set allow_tiers: [free].


The switch is per-repository. Run inside the repo you want to drive:

Terminal window
warden autopilot on

This enables only the current repository (other repos are unaffected) and runs a preflight check before enabling. Add --repo <root> to target a different repository. The preflight surfaces every problem that would stall an unattended run — now, while you’re present — and prints actionable errors if anything is missing:

✗ plan file not found: autopilot.plan.yaml
✗ integration branch does not exist: autopilot/integration
✗ no authenticated backend available
hint: run `warden autopilot init` to scaffold a plan file and config block

Fix any reported issues and re-run warden autopilot on. When the preflight passes, the manager is spawned and the run enters active state, and the repo is persisted as enabled — so it comes back up automatically if the daemon restarts. Enable more repos the same way; each is tracked independently.


Terminal window
warden autopilot status # enabled repos + run state, manager id, task counts
warden ls # shows the manager + all worker agents
warden status <manager-id> # full manager detail + events
warden tail <manager-id> # recent manager output
warden audit log # full append-only audit trail of every action

The TUI cockpit (warden tui) shows the manager and its workers as a nested sub-tree under the run. The web dashboard shows an Autopilot panel when a run is active. The TUI header has a status badge (press ctrl+a to toggle autopilot on/off without leaving the cockpit).


The manager calls warden land automatically when a worker finishes and its PR is gate-green. You can also call it manually to land a specific worker (e.g. to bypass a stuck gate, or to pre-land a branch you’ve already reviewed):

Terminal window
warden land <agent-id> # land by agent id
warden land <branch-name> # land by branch name

The land operation is idempotent — landing the same branch twice is a no-op. It fails with an error if:

  • The branch is not autopilot-owned (ownership guard)
  • The configured gate is not green (--gate-mode=local bypasses CI and uses the local .warden/check.yml checks instead)

Over MCP: land { ticket: "<agent-or-branch>" }.


When the manager has verified the plan’s done_when criteria, it marks the run complete: the daemon writes an in-place status: complete marker (plus a completed_at timestamp) into your plan file — preserving your other keys, ordering, and comments — tears down the manager (in-flight workers keep running), and retains the ledger. A plan carrying status: complete is skipped by preflight, so a finished run is never re-run by mistake on a future enable or daemon restart. To re-run it, remove the status: complete line (or point the config at a fresh plan file).

The integration branch (autopilot/integration by default) holds all the merged worker branches — one merge commit per landed task.

Review the branch, then fast-forward main when you’re satisfied:

Terminal window
git log autopilot/integration --oneline # inspect landed commits
git diff main..autopilot/integration # full diff
# fast-forward main (after your review)
git checkout main
git merge --ff-only autopilot/integration
git push

The integration branch is never merged to main automatically. That step always belongs to the operator.


Terminal window
warden autopilot off # disable the current repo
warden autopilot off --repo <root> # disable a specific repo

Disables the current repository (or --repo <root>); other enabled repos keep running. Effective immediately, at any state:

  • The Controller stops spawning new workers and landing new branches
  • In-flight workers keep running to completion (they are not terminated)
  • The manager is terminated gracefully
  • The ledger is retained — warden autopilot on continues from where the run left off

Use the kill switch any time you want to pause the run, inspect what workers are doing, or abort a run that is heading in the wrong direction.


CommandWhat it does
warden autopilot initScaffold autopilot.plan.yaml + config block
warden autopilot on [--repo <root>]Enable autopilot for this repo (runs preflight first)
warden autopilot off [--repo <root>]Disable autopilot for this repo — the kill switch
warden autopilot statusShow enabled repos + each run’s state, manager id, task summary
warden land <agent-or-branch>Land a worker branch into the integration branch
ToolWhat it does
set_autopilot { enabled: true|false, repo? }Enable or disable autopilot for a repo (the kill switch); repo defaults to the daemon’s working directory
autopilot_statusReturn enabled repos + each run’s state, manager id, task counts
autopilot_completeManager-only: declare the caller’s run complete once done_when is met (writes the in-place status: complete marker, tears down the manager)
land { ticket: "<agent-or-branch>" }Land a worker branch

The autopilot config block hot-reloads with no daemon restart — edit ~/.warden/config.yaml and the plan/manager/merge template, backend cost ladder, and guardian heal thresholds re-apply on the next tick, with the per-repo enabled set left untouched. Adding a plans[] entry starts it; removing one tears down its run. Only the guardian tick interval still needs a restart. A syntactically bad edit keeps the last-good config and alerts you. This applies to warden’s whole config file — see Configuration.


  • Rate-limit resume and auto-restart are global config toggles (rate_limit.auto_resume, auto_restart), not per-run overrides via autopilot — configure them in ~/.warden/config.yaml for the backends your manager uses.
  • Rotate (guardian stage 3) requires more than one free-tier backend to exercise meaningfully. With only antigravity in the free tier, the guardian falls back directly to backoff after a restart fails.
  • The manager picks worker backends itself based on the plan; Controller.SelectWorkerBackend is exposed but the manager is not required to use it.