Skip to content

Autopilot — Letting gald3r Work the Queue Itself

Everything in task-bug-workflow.md can be driven by hand, one command at a time. This page covers the verbs that let gald3r claim, implement, and review work with progressively less manual intervention — from "do one step" to "run until the backlog is empty."

The escalation ladder

For headless startup, verdict-exit grace, and dirty-controller waits, see worker lifecycle and recovery.

Verb What it does Stops when
gald3r go Claim the next ready task, work it one step at a time You take back control after each step
gald3r go-code Implement a specific task through to awaiting-verification The implementation is done (never runs review itself)
gald3r go-review Review a task's acceptance criteria as a FRESH agent (never the implementer) A PASS/FAIL verdict is recorded
gald3r autoclaim Work through several pending tasks in a row, unattended The batch finishes, or nothing is left ready
gald3r swarm Split a batch of work across several parallel agents The swarm's defined session ends
gald3r autopilot Implement + review + repeat, continuously The backlog clears, or you call it off

gald3r go — one step

gald3r go claims the next eligible task itself; to see what it would pick without claiming anything, ask the queue directly first — gald3r task next is read-only:

gald3r task next
T2: Fix broken footer link
Status: pending
Priority: medium

Then run gald3r go for real to claim and work it. Useful flags: --subsystem <name> / --priority <level> to narrow which task gets picked; --backend dev-echo to run against the offline deterministic backend instead of a real provider (same flag run uses, see the quickstart).

gald3r go-code / gald3r go-review — the two-phase pipeline

This is the pattern behind every autopilot/swarm run under the hood: implementation and review are always separate agent sessions, never the same one. go-code never marks a task completed — only awaiting-verification. go-review is the fresh reviewer: it never runs against the same session that implemented the task, checks acceptance criteria one by one, and writes the actual task verify --pass/--fail verdict (a real DB-authoritative write, not just a status-history sentence describing one — see task-bug-workflow.md's verify section).

Review proof and release acceptance

autopilot loop --review-only supports ordinary task and bug review. Its lifecycle PASS is a review decision. Registered integration acceptance also preserves the original two-stage artifact, criterion evidence and exact source manifests, then tracks landing to an explicit completion ref.

The additive review_proof object appears in startup, per-item reviewer results, post-iteration and final summaries, in both text and JSON output:

Field Meaning
capability ordinary_lifecycle or registered_integration
registration_status absent, active, invalid, or unknown
acceptance_status absent, pending, accepted, or unknown
landing_status unproven, pending, landed, or unknown
items Exact task/bug identities observed in this run; each includes its current attempt/spec and native receipt digest when available
observed_item_count, accepted_count, landed_count, unknown_count Counts for observed identities and their proof; an observed item may have been refused before a reviewer started
next_action The supported step still needed

An ordinary PASS normally reports acceptance absent and landing unproven. An accepted registration starts active with acceptance/landing pending. accepted requires the matching canonical artifact and native receipt for the current item, attempt and specification. landed additionally requires matching promotion metadata, fenced queue receipt and verified ancestry to the completion ref. These observations are read-only and timestamped; they do not alter verdicts or certify all release gates. Read failures report unknown. Selected server authority currently reports unknown when a complete native receipt/landing read is unavailable; a local cache is never treated as authoritative evidence.

For a release cut, use --release-review together with --review-only and an accepted --integration-registration receipt. Both session and headless executors refuse missing, malformed, stale or mismatched registration before dispatch.

Prepare the registration through the CLI

From the intended integration checkout, save an input JSON document containing these explicit choices (replace each placeholder with the actual value):

{
  "operation_id": "UNIQUE_REGISTRATION_OPERATION_ID",
  "run_id": "ACTUAL_NEW_RUN_ID",
  "integration_ref": "refs/heads/ACTUAL_INTEGRATION_BRANCH",
  "completion_ref": "refs/heads/ACTUAL_COMPLETION_BRANCH",
  "base_sha": "FULL_BASE_COMMIT_SHA",
  "reason": "Why this run is collecting independent release acceptance"
}

Prepare the request, then submit it to the selected authority:

gald3r project-agent lifecycle integration registration-template --request-file INPUT.json
gald3r project-agent lifecycle integration register --request-file REQUEST.json

Save the first command's JSON output as REQUEST.json. The template observes the active project's authority/epoch, opaque repository identity and current full HEAD SHA; it checks the explicit branch/base/completion choices. It does not register a run, claim work, select an authority, or write a journal entry. Save the second command's accepted JSON receipt as RECEIPT.json. A template is an unaccepted request and cannot be used as the launch receipt.

Launch with actual selectors and routing (use --bugs BUG-ID,BUG-ID alongside or instead of --tasks as appropriate):

gald3r autopilot loop --executor session --review-only --release-review --integration-registration RECEIPT.json --tasks ID,ID --provider PROVIDER --model MODEL --max-iterations 5

Use the same flags with --executor headless for its supported execution path. The session executor must service the issued reviewer manifests as described by gald3r prompt get playbook.session_executor. Keep the original registration and manifest identities; the engine checks the original artifact before applying registered PASS and reports remaining integration work.

Earlier ordinary reviews

Keep historical PASS/FAIL receipts and failure counters. Use the supported task or bug lifecycle to create a fresh forward attempt, make the actual implementation ready for verification, and obtain a new independent registered review. Do not attach an invented artifact to an old receipt or create a cosmetic implementation commit. Existing source already on the target supports the registered no-op landing path. --resume preserves a release run's proof requirement and exact registration; an ordinary historical run cannot acquire a registration on resume.

gald3r autoclaim — sequential batch

gald3r autoclaim

Works through several pending tasks in a row without stopping to ask "what's next" between each one. --online extends the same claim logic across your whole team's shared board (multiple people/agents claiming from the same backlog without double-picking the same task).

gald3r swarm — parallel batch

gald3r swarm run <swarm.yaml>
gald3r swarm status

Splits a batch of work across several agents running concurrently, each in its own worktree so they never step on each other's uncommitted changes. gald3r swarm status lists active swarm sessions from the discoverable registry; gald3r swarm config <swarm.yaml> inspects a swarm definition without launching it.

gald3r autopilot — the continuous loop

gald3r autopilot enqueue         # add a task to the autopilot queue
gald3r autopilot run                 # start the service, drain the queue until empty
gald3r autopilot status              # current queue stats
gald3r autopilot stop                # finish the in-flight iteration, then exit gracefully
gald3r autopilot loop                # the outer-loop conductor (rolling implement+review cycles)
gald3r autopilot replay RUN_ID       # forensic reconstruction of a past run, from disk artifacts alone

autopilot loop is what keeps cycling implementation and review across the whole workspace until a hard stop condition (backlog empty, rate limit, or an explicit stop) — the automated version of manually alternating go-code then go-review for every task in sequence. Inside a supporting IDE this is the same thing as running /g-go-go (Claude Code) or @g-go-go (Cursor) — the CLI verb and the IDE command are the same implementation, just invoked from a different surface.

Attempt budgets are implementation-only. --budget N caps how many go-code/go-bug implement starts a run will make (0 = unlimited) — it is not a coordinator-iteration cap and it never counts against review turns. A task that keeps failing review gets a bounded number of re-implement passes before it's handed back to you as requires-user-attention rather than looping forever, but reviewing an item is always free: a slow reviewer queue never starves the implementer side, and a fresh review never "spends" budget.

Gauntlet mode (--gauntlet, engine / @g-go* surface). Off by default. Same flag dialect on gald3r autopilot loop and every @g-go* command including swarm aliases — @g-go-go --gauntlet passes the flag and its scoped knobs through to the compiled engine; it does not invent a second meaning. Requires an inspectable oracle bar (tests/benchmark/answer-key/golden, or --gauntlet-bar PATH) and refuses rather than inventing "good." Review-only runs replace (never blend with) the AC-checklist verifier. @g-go-bugs / -swarm refuse a bug that has no inspectable repro. Hard caps: --gauntlet-inner-round-cap (default 8), --gauntlet-max-spend-usd, --gauntlet-iteration-cost-ceiling-usd, --gauntlet-wall-clock-minutes, plus the existing --budget. Coordinator judgment: gald3r prompt get playbook.pipeline_gauntlet.

gald3r autopilot replay RUN_ID reconstructs exactly what happened during a past loop run from its durable event ledger and correlated logs alone — never a live process, never the database. It renders a per-lane timeline and flags anything the on-disk artifacts can't substantiate (a missing brief, a verdict with no matching reviewer spawn) as an invariant violation, so you can audit an unattended overnight run after the fact with the same rigor as watching it live. RUN_ID accepts the full timestamp or any unambiguous prefix of it.

Watching a run — event ledger, heartbeat, and the stall watchdog

A swarm must never run dark for hours. Every autopilot loop run writes a durable, append-only, versioned event ledger (event_schema: 1) alongside its run marker under .gald3r/logs/ — run_started, preflight_claimed, capacity_intended, bucket_spawned / bucket_completed / bucket_failed, merge_result, harvest_result, claim_released, breaker_tripped, provider_fallback, cost_update, heartbeat, stall_detected, stop_requested, and run_end. Every one of these also prints inline as an [AUTOPILOT][EVENT] ... line while the run is live, but the ledger's whole point is that it survives — and is readable — after the fact, or from a different terminal:

gald3r autopilot status                      # run marker + the SAME swarm-candidate board the loop itself sees
gald3r autopilot events --follow             # tail the active run's event ledger live, from another session
gald3r autopilot events --follow --json      # same, as raw NDJSON
gald3r autopilot events --run-id <stamp>     # replay a specific past run's ledger by its stamp

autopilot status and a live run's own startup line both compute the swarm-candidate count (open tasks + open bugs, floor-eligible) through the exact same function, and status names the floor it applied — so the two can never again disagree about whether there is work to do. --max-severity/--max-value (owner: "assigning work to a lower end model") are the ceiling twin of --min-severity/--min-value — default 10 (no ceiling), refused at the CLI when set below the floor, and named on the same status line whenever a run has one active.

Live view: watching what a bucket or coordinator is actually saying

The ledger above narrates lifecycle occurrences (a bucket spawned, a merge landed) — it does not carry a bucket agent's or the coordinator's own running commentary. That commentary used to be captured only for post-mortem (a 256 KiB in-memory tail plus a per-bucket .gald3r/logs/bucket_<id>_iter<N>_live.log, itself OVERWRITTEN on every poll tick), never teed anywhere live. Every implementer/reviewer bucket and every coordinator invocation now ALSO tees its own combined stdout+stderr, byte-for-byte, to an append-only stream file:

.gald3r/logs/bucket_<safe-id>_iter<N>_<stamp>.stream       # implementer bucket
.gald3r/logs/review_<safe-id>_iter<N>_<stamp>.stream       # reviewer bucket
.gald3r/logs/coordinator_iter<N>_<primary|fallback>_<run-id>.stream   # coordinator invocation

A bounded, THROTTLED stream_progress ledger event (kind/id/role/bytes/last_line/stream_path — never the raw stream content) is sampled at most once every ~10 seconds per stream, and only when new bytes actually arrived, so a busy or wedged bucket can never make the durable ledger grow unboundedly with run duration or verbosity — see gald3r_swarm/autopilot/stream_tee.go's own doc comment for the full bounded-ledger contract.

gald3r autopilot watch (from a second terminal) multiplexes the ledger AND every currently-live .stream file into one annotated view — the terminal equivalent of the Claude-harness agent panel:

gald3r autopilot watch                       # marker snapshot + ledger events + live agent lines, e.g. "[] agent: editing file foo.go"
gald3r autopilot watch --once                # one snapshot pass instead of following
gald3r autopilot watch --no-streams          # pre- marker-only behavior

autopilot events --follow (below) still exists for a ledger-only tail; watch is the one command that also shows what the swarm is actually doing while it does it.

Publishing events live to world_tree (opt-in)

autopilot events --follow above requires shell/file access to the machine running the loop. --publish-events (or the AGENT_CONFIG.md publish_run_events: true key) additionally pushes every ledger event through the Valkyrie world_tree channel as it happens, so a different session or a teammate can observe the SAME run remotely:

gald3r autopilot loop --budget 20 --publish-events   # opt in; --budget is attempt cap (0 = unlimited)

Publishing is a pure consumer of the ledger (never a second writer), bound to the run's own start/end, and never blocks or fails the run: when the connector is offline, events queue durably and flush automatically on the next reconnect. Under normal operation no event is ever lost — the one documented exception is abnormal: if the outbox directory itself becomes unwritable mid-run (disk full, permissions), that single event is logged and permanently dropped rather than retried, instead of silently vanishing.

Heartbeat

--heartbeat-minutes (default 15) now fires during a long-running coordinator invocation, not only between iterations — a run whose entire budget is spent inside one multi-hour coordinator call still narrates liveness (elapsed time, age of the last coordinator stream byte, last extracted thought, and claims-vs-buckets state) on schedule. claims 0/0 while stream bytes are growing means the coordinator CLI still owns in-session swarm work — that is expected on the old path, not an idle hang.

Deterministic dispatch is the default

Ready tasks/bugs already come back from the database in the correct status with dependencies cleared. The outer loop dispatches those implementers itself, directly from that queue — it does not wait for a coordinator CLI to pick the work first, which is what made an early version of this loop capable of sitting silently idle for tens of minutes per iteration. --no-deterministic-dispatch keeps the old coordinator-first path available as an explicit fallback, kept for compatibility rather than as the recommended path.

If a run still takes that fallback, the model's "thinking" stream is no longer invisible while you wait: a periodic wait line includes elapsed time, stream bytes, and the last extracted thought; .gald3r/logs/coordinator_thoughts/iter_N_live.log is a live thought tape; and gald3r logs tail sees the same thoughts as rows in the local logs database. A startup line names which dispatch path the run is using — if you see the loop invoking a fresh coordinator on an iteration with a non-empty ready queue, the binary on PATH is stale or you passed the fallback flag; reinstall, or drop --no-deterministic-dispatch.

Supervision: gates, breakers, and the liveness watchdog

A long unattended run needs more than a stall detector — it needs to notice when its own safety machinery has quietly stopped mattering, and it needs a way to tell a genuinely wedged worker from one that's just being quiet while it works. Three layers, all active by default:

  • A once-per-run inert-gate banner. If a safety gate can't actually evaluate under the current provider (no usable telemetry to check against), the run says so loudly exactly once — naming which gates are inert and why — instead of repeating the same warning on every single iteration until it becomes background noise nobody reads anymore.
  • Proxy breakers for telemetry-less providers. When a provider gives the loop nothing to measure cost or time against directly, three proxy ceilings still arm: a per-iteration wall-clock outlier ceiling, a fallback iteration ceiling (only when you haven't set --max-iterations yourself — it never overrides an explicit choice; -1 is an explicit deactivate that skips the proxy ceiling too), and a cumulative output-byte budget. Each one trips a real breaker and records which kind of signal armed it (measured, estimated, or proxy), so a post-run read of the log tells you how much to trust the number that stopped things.
  • A no-progress breaker. Twenty consecutive iterations with zero completions — no task or bug reaching a terminal or verified state, no commits — stops the run and names the top items that kept spinning without landing, instead of burning the rest of the budget on a run that's already stuck.

The per-bucket liveness watchdog reads gald3r's own side channel, not just raw process output. Some CLI backends stay byte-quiet on stdout while genuinely working, and some stay noisy while wedged — watching stdout alone can kill a healthy worker or miss a dead one. The watchdog instead arms a union of gald3r-owned signals as its primary evidence: database writes attributable to the bucket's own claimed item, and real worktree activity (git status changes, HEAD movement, file modification times), with stdout growth only as secondary corroboration. A kill from this watchdog specifically records a distinct watchdog_killed outcome rather than blending into an ordinary failure — so a post-run summary (or autopilot replay, above) can tell you exactly which items were killed for going quiet versus which ones genuinely failed.

Stall watchdog

Two more, simpler independent detectors, each of which kills the frozen invocation, releases any stranded preflight claims, retries once, and halts loudly (naming why) if the retry stalls too — never a silent multi-hour freeze:

  • Claims-to-buckets (--claims-window-minutes, default 10): a coordinator claimed tasks but no implementer bucket (worktree) ever started for any of them.
  • Stream-silence (--stream-silence-minutes, default 10): the coordinator subprocess is alive but has produced zero output for the whole window.

Disable both with --no-stall-watchdog (the heartbeat keeps running regardless).

Color on the human TTY

autopilot loop paints the live narration ([outer-loop], [AUTOPILOT][EVENT], swarm verbs, PASS/FAIL, task/bug keywords) with the same TEL regex engine as gald3r tel wrap. Color is display-only: the per-run log file, --json NDJSON, and anything sent to an agent stay plain. Disable with NO_COLOR=1 or GALD3R_TEL_DISABLE=1, or override the builtin narration class via gald3r tel class narration off / a rule file in ~/.gald3r/tel or .gald3r/tel.

Worktrees: isolating parallel agents

gald3r worktree create
gald3r worktree report

Every parallel agent (swarm bucket, or a standalone background implementer like the one that wrote this page) gets its own git worktree — a separate checkout sharing the same .git history, so N agents can have N different uncommitted change sets without colliding. Other worktree verbs worth knowing: checkpoint/resume (crash-safe continuity across a session restart), steer/queue (inject a follow-up instruction into a running worktree session without interrupting it — see gald3r steer / gald3r queue), merge (fast-forward-only integration back to main), janitor (auto-prune stale worktrees).

Branch discipline: the isolation tier

Worktrees are one of two isolation mechanisms, and the loop picks the cheaper one that still fits the run's shape. The tier, from lightest to heaviest:

  1. Default — direct commits, no extra branches. Out of the box the coordinator commits its checkpoint and housekeeping work straight onto whatever branch the project is checked out on, and parallel agents get worktrees. This basic mode is always the default; the modes below are opt-in flags that leave it byte-identical when off.
  2. Serial branch-in-place (--no-code-swarm --branch-in-place). A single sequential agent doesn't need a separate checkout directory at all — it runs on a short-lived feature branch cut in the primary checkout: create branch, implement, checkpoint-commit, merge back, return to the base branch. No worktree directory churn, no antivirus file-lock friction on Windows (swarm worktree remove now retries that same lock class instead of leaving remnant directories behind), cheaper for solo flows. It refuses to start on a dirty checkout, and if the agent crashes mid-run the loop rescue-commits anything dirty and returns the checkout to the base branch cleanly, leaving the bucket branch intact for recovery. Swarm (parallel) runs ignore this flag with a logged warning — N concurrent agents genuinely need N isolated directories, so they escalate to worktrees.
  3. Session branches (--session-branch [NAME]). Independent of the above: the coordinator's own writes — housekeeping commits, integration merges, checkpoint commits — land on a session branch (auto-named burn/YYYYMMDD-HHMM, or the name you give) cut from the current branch at run start, instead of directly on it. At run end the loop integrates the session branch back with a fast-forward (falling back to a merge commit, never a rebase); a real conflict leaves the session branch intact and reports exactly what to run to finish the merge by hand. The whole run becomes one reviewable, cleanly revertible unit.

Software-development projects default branch-first when solo and escalate to worktrees at swarm parallelism; both flags are advanced settings — leave them off and nothing changes.

Housekeeping during unattended runs

gald3r housekeep --orchestration-root <root> --mode preflight

Autonomous runs still need to write routine .gald3r/ coordination state (status updates, review-result commits) without stalling on a human to approve every single one. housekeep auto-commits ONLY paths it classifies as safe, routine controller coordination changes — anything it can't classify as safe stays blocked for a human, by design.

Completing a capped critical PASS

A reviewer PASS on a task/bug whose priority or severity score resolves to 8 or above (High/Critical on the 1-10 rubric) never auto-completes, even when the reviewer scored it a clean PASS. applyGoReviewVerdict/applyGoBugReviewVerdict (gald3r_cli/internal/commands/bug1140_close_cap.go) leave the item at awaiting-verification and append a note recording the reviewer's verdict plus the exact completion command — the item stays there until something outside the agent loop confirms it. This is deliberate (beta.36): an agent reviewer alone is not "outside the agent" for a critical item, so autopilot cannot self-certify its own critical closes.

The operator vocabulary that completes a capped item:

  • Tasks — gald3r task verify <id> --pass --summary "EXTERNAL-CONFIRMATION: <how you confirmed it>". The literal EXTERNAL-CONFIRMATION: prefix on --summary is the falsifiable marker the cap logic checks for (bug1140ExternalConfirmationToken in bug1140_close_cap.go) — nothing inside the autopilot loop ever emits that string, so its presence can only come from a human or an external system (CI result, runtime probe, operator ack) attaching it by hand.
  • Bugs — gald3r bug resolve <id> completes the bug directly; gald3r bug resolve carries no --summary flag. If you want the same durable EXTERNAL-CONFIRMATION record on the bug, append it as a note first (or after): gald3r bug update <id> --note "EXTERNAL-CONFIRMATION: <how you confirmed it>".

Read bug1140_close_cap.go's file-doc comment for the full rationale (the "WHY A LITERAL TOKEN" section) if you need to know why this is a fixed string and not a prose heuristic.

Evidence-based triage sweep

gald3r triage sweep [--kind all|task|bug] [--apply] [--json] [--dup-threshold 0.6]

Field evidence that motivated this: (a feature already landed via a later attempt), (implemented twice), (skipped as already_fixed on a reverted branch) — a 475-record board needed a hand-built 14-agent sweep to find the dead fraction. gald3r triage sweep walks every open task/bug and classifies each one already_done / duplicate / obsolete / leave_open, always with verified evidence:

  • duplicate — the record's normalized title shares enough significant tokens (--dup-threshold, default 0.6) with a strictly OLDER open record of the same kind. The older record is always the survivor.
  • already_done — either an automatically-discovered git citation (the own already-fixed-in-code detector, reused directly for bugs; generalized to tasks via the mandatory Task: #<id> commit trailer every task-related commit already carries — see g-rl-02), or an explicit citation you write into the record's own text: TRIAGE-EVIDENCE: already_done commit=<sha> TRIAGE-EVIDENCE: already_done file=<path> symbol=<name>
  • obsolete — an explicit citation naming what superseded it, verified against the board or git before it counts as evidence: TRIAGE-EVIDENCE: obsolete ref= TRIAGE-EVIDENCE: obsolete ref= TRIAGE-EVIDENCE: obsolete ref=path/to/file.go

An unverifiable citation — a commit that does not exist, a symbol absent from the named file, a T/BUG id that was never real — never counts as evidence; the record stays leave_open. This sweep never invents evidence, only checks it.

Report-only by default (g-skl-backlog-curate's own "never auto-cancel" discipline): sweep alone prints every actionable finding with its evidence and a DO NOT APPLY notice. Pass --apply to actually close the subset that is BOTH verified AND not capped.

The contract applies here too. A candidate carrying the literal -CAPPED-PASS marker (see the section above), or whose priority/severity score resolves to 8 or above (High/Critical), is never auto-closed by --apply — it is reported as HELD (capped) instead. This sweep never self-certifies a high-value close any more than a reviewer PASS does.

Loop integration: pass --triage-sweep to gald3r autopilot run/loop to run the same engine as a pre-dispatch phase, right after the own already-fixed preflight. A candidate the sweep both classifies AND verifies is closed before an implementer is ever spawned — no wasted worktree, no wasted turn — and the outcome is recorded triage_closed (never a failure, never an implement/review attempt, mirroring StatusAlreadyFixed's own contract). Default off; a capped or unverified finding is left in the dispatch queue exactly as if the flag were absent.

Pre-dispatch alignment gate

The prose-era g-go-code pipeline verified two things before dispatching an implementer at a candidate: that the work was still aligned with the code on main, and that it did not contradict another open backlog item. The Go loop restores both as a pre-dispatch gate that is on by default (--no-alignment-gate on autopilot loop and on standalone go-code is the operator opt-out):

  • Already-aligned (impact scan) — a conservative git grep for a backtick-quoted symbol named in the candidate's title. A hit never closes anything by itself: the item routes through the same merge-noop → awaiting-verification path the already-landed gate uses, so a human-grade review still confirms the verdict. Undecidable candidates dispatch normally.
  • Open-backlog contradiction — an explicit ALIGNMENT-CONFLICT: {kind} {id} marker in a candidate's body naming another item in the same batch parks both via requires-user-attention (the TODO[TASK-X→TASK-Y] explicit-annotation idiom, not fuzzy matching). Structurally a no-op for single-item go-code runs.

Verdicts are cached per item + HEAD SHA, so an unchanged main never pays the git shell-out twice. Dry-run previews never mutate state (the split).

Stranded-branch salvage sweep (autopilot reconcile)

Items parked requires-user-attention by the unmerged-prior-work gate used to re-park on every run with the same generic text — silently defeating rulings the owner had already given. gald3r autopilot reconcile [--kind all|task|bug] [--apply] [--json] ends that: each parked item's stranded branch is probed read-only via git merge-tree; a clean branch lands through the existing merge machinery and the item returns to awaiting-verification citing the landed SHA; a conflicted branch runs the triage engine's already-done evidence detector ( caps inherited — a capped item's evidence is reported, never self-certified); anything else receives a durable reconcile marker carrying the exact branch, conflict files, and a recommendation — and the park gate structurally skips marked items, so a reconciled needs-human item can never be re-parked. Report-only by default; --apply lands/closes/marks. Fail-closed: a land attempt that cannot complete leaves the branch and checkout untouched.

Where next

  • coordination.md — running autopilot across MULTIPLE related projects, not just one
  • troubleshooting.md — gald3r go-status for checking on a run without interrupting it, and what to do when a run looks stuck

Cost and auth: choosing how you loop

The three ways to run autonomous work have different cost profiles. Pick deliberately -- the wrong default can burn subscription quota or API dollars you did not intend to spend. (owner ruling 2026-08-11 -- see also gald3r autopilot loop --help and gald3r prompt get playbook.pipeline_route, which carry the same ladder for an agent to load at routing time.)

Option Auth it uses Cost profile Use when
/g-go, /g-go-code(-swarm), /g-go-bugs-swarm, /g-go-review(-swarm) (in-session engine pipelines) Your IDE session's own login (Cursor/Claude subscription OAuth) Cheapest. Runs inside the session you already pay for; subagents ride the IDE's included subagent tool (SendMessage/Handoff). No spawned CLI-agent processes, no extra auth. You are at the keyboard with a session open and want a bounded implement/review pass now.
/g-go-go, or gald3r autopilot loop/run invoked directly --executor session (the default): THIS session's own login. --executor headless: the same subscription logins, via spawned headless CLI sessions Cheap by default, middle tier opt-in. /g-go-go invokes this SAME deterministic Go outer loop. Under the default --executor session, the implementer AND reviewer roles never spawn a headless CLI-agent subprocess at all -- each bucket's brief is handed to THIS session's own subagent facility (SendMessage/Handoff) via a manifest/results sidecar handshake (gald3r autopilot session-dispatch peek/report; design: docs/design/t1205_in_session_executor_seam.md), billed to this session's OAuth2 login exactly like the cheapest tier above -- the loop's own gates/claims/triage/ledger/breakers stay 100% unchanged and Go-native either way. Only the coordinator role (when a coordinator-first dispatch actually runs) and --executor headless spawn real headless claude/cursor-agent sessions, drawing from the SAME included-usage subscription pool interactive use draws from as of today (: there is no currently-documented, Anthropic-confirmed separate quota split between headless and interactive Claude Code usage). --executor headless REFUSES a RED-classified role without --allow-usage-spend; the real per-role risk on that tier is not a separate pool -- it is an env-var auth-precedence footgun and an unresolved upstream gating defect; see "Billing surfaces and consent" below. /g-go-go, invoked from the live session you're already in, is still the right default for interactive "loop it"/"put it on autopilot" phrasing -- attended, judgment-loaded, stoppable with autopilot stop. Invoking the bare verb directly (bypassing /g-go-go) is reserved for detached/scheduled/headless contexts where no interactive session exists to act as the executor (--executor headless is required there), or when the user names the verb explicitly. Continuous multi-iteration autopilot work, from either surface.
gald3r autopilot loop with registry providers (anthropic, openai, gemini) or gald3r run Direct API keys (providers.yaml / env) Most expensive. Real per-token API billing on every turn, regardless of which surface dispatched it. You have API budget and want provider control, model pinning, or providers your IDE does not offer. local-compat (Ollama/LM Studio) is the zero-dollar exception in this tier.

Two facts worth knowing:

  • The in-session /g-go, /g-go-code(-swarm), /g-go-bugs-swarm, and /g-go-review(-swarm) pipelines never invoke gald3r autopilot underneath -- they are engine-backed playbooks your session executes itself via its own subagent tool. /g-go-go is the one exception: its own command doc names gald3r autopilot loop --executor session as exactly what it runs. As of that no longer means a per-role headless CLI-session cost by default -- the implementer and reviewer roles execute through /g-go-go's own session, the SAME way the fully in-session pipelines above do; only --executor headless (detached/scheduled contexts, or an explicit ask) restores the older per-role spawned-subprocess shape. /g-go-go remains the right interactive answer to "loop it" because it is attended and stoppable, not because it happens to be free -- but under its own default it now IS free of extra CLI-session spend, not merely "attended despite the cost."
  • Reviewer staffing under --executor session splits evidence-gathering from judgment (). A session-executor reviewer bucket's own turn used to spend its first several tool calls on mechanical git diff/file reads before doing any real review judgment. The driving agent now dispatches two cheap, parallel evidence-gathering subagent calls per reviewer bucket first (diff + full changed-file contents), then hands the assembled evidence plus the bucket's own review brief to a single judgment-only reviewer turn -- see playbook.session_executor.md (gald3r prompt get playbook.session_executor) §3a for the full contract and a real measured wave (reviewer-turn tool calls: 12 -> 0; reviewer-turn wall time: -92%). This is a driving-agent staffing optimization only, so it applies to --executor session (both /g-go-go and the bare verb); --executor headless's spawned go-review/go-bug-review subprocess already gathers its own evidence inside a single metered CLI-agent process rather than being staffed by a driving agent's own subagent facility, so this split has no seam to attach to there.
  • Local models (local-compat via Ollama or LM Studio) cost nothing per token in any tier and can serve implementer turns while a subscription CLI coordinates -- the cheapest fully-autonomous configuration on a machine with a capable GPU.
  • Coordinator provider matrix (local-fleet inversion). The coordinator used to be locked to claude/cursor-agent -- the one unavoidable paid/subscription seat in an otherwise-free local-fleet loop. Two additions close that gap:
  • --coordinator-provider codex and --coordinator-provider gemini-cli join claude/cursor-agent as real coordinator-CLI vocabulary (the same providerLaunchSpecs mechanism, gald3r_swarm/autopilot/role_routing.go) -- a host with OpenAI's codex or Google's gemini CLI installed and authenticated, but no Claude/Cursor subscription, can now coordinate at all, closing the "35+ platform support" gap for the flagship loop. The provider id is gemini-cli, not bare gemini -- that id names the SEPARATE gald3r_llm/providers registry vocabulary (see docs/providers_template.yaml's own gemini block) implementer/reviewer already accept; gemini-cli is the standalone agentic CLI tool.
  • --coordinator-provider gald3r --coordinator-model <providers.yaml spec> (e.g. local-compat:qwen2.5:7b-instruct, or an OpenRouter model) is the self-hosted registry route: the coordinator re-spawns gald3r's own binary (gald3r run --model <spec> --output-mode stream-json) instead of an external agent CLI, so a loop can coordinate against a fully local or OpenRouter model -- the zero-dollar-coordinator configuration the no-budget ruling asked for. autopilot loop's own startup banner prints a QUALITY WARNING whenever the resolved coordinator is this route (or any other non-frontier id): a registry model's own task-selection/dispatch judgment driving the full outer loop is meaningfully weaker than a frontier CLI agent's, which is exactly why deterministic dispatch (this loop's default) carries most of the fan-out -- see gald3r_swarm/autopilot/role_routing.go's IsFrontierCoordinatorProvider and /'s own design notes for the full rationale. This route does not (yet) get the richer provider-refusal/reset-time classification cloud CLI-vocab providers get -- a registry error still fails the iteration honestly via a non-zero exit code, just without that extra detail.
  • --provider cursor-agent model slugs (item 5): the cursor-agent vendor binary has no ls-models (or similar list-and-exit) subcommand -- passing an unrecognized --model/--*-model value does NOT error, it silently starts a real, billed conversational turn. Never guess a slug. claude-sonnet-5-medium is field-verified working as of beta.39 (see docs/field_reports/20260809_coordinator_provider_routing_apigard.md); the vendor's own current catalog (it changes with your Cursor plan) is authoritative -- see https://cursor.com/help/models-and-usage/available-models and cursor-agent --help.

Every /g-go* dispatch entry point (go, go-code, go-review, go-bug, go-bug-review) and autopilot loop/run now classifies and declares each resolved role's billing surface at launch, per the owner's binding color semantics:

  • GREEN -- rides the session/user's own OAuth2 subscription (claude, cursor-agent, codex on ChatGPT sign-in, gemini-cli on Google login, GitHub Copilot CLI, all by default).
  • BLUE -- external but zero-dollar: local endpoints (Ollama, LM Studio, Unsloth Studio), an OpenRouter :free-suffixed model, or a genuine free-tier API key. Still declared loudly -- never silently folded into GREEN.
  • RED -- spends real money beyond any subscription: a registry-vocab API key (anthropic, openai, sakana, ...), an OpenRouter paid model, or a claude/codex/gemini-cli spawn whose environment carries the vendor's own API-key env var alongside its subscription login.

Under --executor session (the default), the implementer and reviewer roles are declared with a synthetic GREEN session-executor surface instead of being classified against whatever --implementer-provider/--reviewer-provider happens to be configured -- classifying against a provider that will never actually be spawned for those two roles under this executor mode would be meaningless at best and a false RED/refusal at worst. GREEN never needs the --allow-usage-spend consent gate below, so a session-executor run never prompts or refuses on their account. --executor headless restores normal per-provider classification for both roles.

The full decision table (and the research this classifier compiles) lives in docs/20260826_113000_Claude_T1207_BILLING_SURFACE_SURVEY.md; the code is gald3r_swarm/autopilot/billing_surface.go.

Troubleshooting: unexpected API billing on a headless run

Symptom -- a headless claude -p run bills Console/Platform API dollars even though the account signed in has an active Claude subscription.

Cause -- claude -p (headless Claude Code) resolves credentials in a fixed precedence order every request, and its own docs state plainly: "ANTHROPIC_API_KEY ... In non-interactive mode, the key is always used when present" -- with zero interactive confirmation, unlike the one-time approval prompt an interactive session gets. If a shell that spawns claude -p also carries ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN (for example, left over from configuring the registry-vocab anthropic provider in the same shell), every headless claude turn silently bills those dollars instead of the included subscription.

What gald3r does about it -- the choke point every coordinator/implementer/reviewer CLI-vocab spawn passes through (buildCoordinatorEnv, coordinator_invoke.go) strips both vars from a claude-provider child's environment unless you have explicitly consented via --allow-usage-spend.

The --allow-usage-spend gate

A RED-classified role refuses to dispatch at all without --allow-usage-spend -- the refusal names the account, the provider, and the exact flag. With the flag:

  • In an interactive terminal, you still get a y/N intent-verification prompt naming the account and provider before the turn dispatches.
  • In a non-interactive context (a spawned bucket subprocess, a scheduled/ headless run), the flag itself is the consent -- no prompt is possible, so none is attempted; the loud RED banner and audible cue still fire.

Passing --allow-usage-spend on autopilot loop/run arms the GALD3R_ALLOW_USAGE_SPEND env var for the whole process, which every self-exec'd go-code/go-bug/go-review bucket subprocess inherits -- you do not need to pass the flag again per bucket.

Account identity and credential-swap detection

Where cheaply obtainable (claude auth status's email field today), the authenticated account identity is shown in every banner line -- never omitted, rendered as "unknown identity" when unavailable. The first time you consent to a RED surface, that account is recorded per-provider under ~/.gald3r/billing_trust/approved_accounts.json (a per-USER file, deliberately outside any project's .gald3r/). Every later launch compares the currently-authenticated identity against that record; a mismatch -- the exact incident this defends against: a claude login silently swapping the CLI's own credential store to a different account than the one an interactive session stayed on -- forces RED regardless of the provider's normal color and prints:

credential changed since last approval: was <old-account>, now <new-account> -- headless spawns will bill <new-account>

and requires fresh consent (which updates the record) before dispatching.

The audible cue

A RED banner plays an audible cue exactly once per launch (never repeating during the run): the owner-supplied sounds/coins.wav when it resolves (GALD3R_SPEND_SOUND_FILE, an AGENT_CONFIG spend_sound_file: key, or <project-root>/sounds/coins.wav, in that order -- GALD3R_SPEND_SOUND=0 disables sound entirely), falling back to a terminal bell when no sound file resolves (GALD3R_SPEND_BELL=0 disables the bell). Playback is best-effort and fire-and-forget on every platform (winmm PlaySoundW on Windows, afplay on macOS, paplay/aplay on Linux) -- it never crashes or delays launch if unavailable.

Global config layer and the verify-settings gate

Per-project .gald3r/config/AGENT_CONFIG.md overrides are easy to forget once you have not touched a project in a while -- and a stale implementer_model: or reviewer_provider: pin silently steers a whole run. Two things address that:

A global config layer. <gald3r home>/config/AGENT_CONFIG.md (the same per-user directory GALD3R_HOME already points at) is a NEW, optional second layer with the same "key: value" scalar shape as the project file. Resolution order for every provider/model key is `flags > project config > global config

engine defaults` -- a project's own override always wins, but a project with no override falls back to a sensible operator-wide default instead of a hardcoded one. View or edit either layer with:

gald3r config agent show              # every key set in either layer, with the winning source
gald3r config agent get KEY           # one key's resolved value + source (project|global|unset)
gald3r config agent set KEY VALUE --yes            # writes the PROJECT layer
gald3r config agent set --global KEY VALUE --yes   # writes the GLOBAL layer

gald3r providers explain also lints both layers now (not just the project file), including a "how many minor gald3r_rel_version releases behind this binary" distance when the two are comparable.

An opt-in verify-settings launch gate. autopilot loop --verify-settings prints the resolved provider/model/effort/lanes/budget receipt (the same information the launch banner already shows, plus any stale-config warnings) and requires an explicit y/N confirm in an interactive terminal, or --verify-settings-yes headless, before any claim/worktree/ spend happens. This is deliberately opt-in, not the default: autopilot loop already hard-refuses a run that omits explicit per-role --*-provider/--*-model flags, and flipping this gate to mandatory for every launch would break any existing headless script/wrapper that invokes it without --verify-settings-yes -- that default flip is a separate, deliberate decision for the owner, not something bundled into this change.

--stale-config-margin N (default 2) tunes how many minor gald3r_rel_version releases behind is tolerated before --verify-settings warns that a config file predates this binary. The same run also warns if a role resolved to the self-hosted gald3r provider with a <provider>:<model> registry spec whose model id is not (or no longer) in providers.yaml's roster for that provider.

A Throne surface for the same two layers. Settings > Agent Config (gald3r_throne/frontend/src/components/settings_pages/AgentConfigPage.tsx) renders the same merged view gald3r config agent show prints -- every key set in either layer, tagged with the layer that won -- and a small form to write a new key into either the loaded project's layer or the global layer. It calls straight into the same Go EffectiveAgentConfig/ SetAgentConfigScalar functions the CLI verbs call (gald3r_throne/internal/bindings/agentconfig), so the CLI receipt and the Throne view can never drift into two different readers/writers of AGENT_CONFIG.md. Read-only inspection works with no project loaded (global layer only); writing the project layer requires one.