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

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 T123 Implement a specific task through to awaiting-verification The implementation is done (never runs review itself)
gald3r go-review T123 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).

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 T123        # 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 T123 then go-review T123 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.

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.

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

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. Before T806, that commentary was 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. "[T123] agent: editing file foo.go"
gald3r autopilot watch --once                # one snapshot pass instead of following
gald3r autopilot watch --no-streams          # pre-T806 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), 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, 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 (BUG-1140)

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 (BUG-1140, 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:

  • Tasksgald3r 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.
  • Bugsgald3r 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 (T1155)

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

Field evidence that motivated this: T737 (a feature already landed via a later attempt), T950 (implemented twice), BUG-864 (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 (BUG-1105's 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=T123 TRIAGE-EVIDENCE: obsolete ref=BUG-45 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 BUG-1140 contract applies here too. A candidate carrying the literal BUG-1140-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 BUG-1105's 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 (T1156)

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 BUG-1043 split).

Stranded-branch salvage sweep (autopilot reconcile, BUG-1173)

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 (BUG-1140 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.mdgald3r 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. (T740, 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, T1204/T1205): 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 (T630). 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 (T1207: 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 (T1206); 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 T1205 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."
  • 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.
  • --provider cursor-agent model slugs (BUG-1293 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 (T1205, 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 T1207 research this classifier compiles) lives in docs/20260826_113000_Claude_T1207_BILLING_SURFACE_SURVEY.md; the code is gald3r_swarm/autopilot/billing_surface.go.

The env-var leak this closes

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 Console/Platform API dollars instead of the included subscription. The choke point every coordinator/implementer/reviewer CLI-vocab spawn passes through (buildCoordinatorEnv, coordinator_invoke.go) now 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.