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-iterationsyourself — 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:
- 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.
- 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. - 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-namedburn/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:
- Tasks —
gald3r task verify <id> --pass --summary "EXTERNAL-CONFIRMATION: <how you confirmed it>". The literalEXTERNAL-CONFIRMATION:prefix on--summaryis the falsifiable marker the cap logic checks for (bug1140ExternalConfirmationTokeninbug1140_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 resolvecarries no--summaryflag. 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 mandatoryTask: #<id>commit trailer every task-related commit already carries — seeg-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 grepfor 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 (theTODO[TASK-X→TASK-Y]explicit-annotation idiom, not fuzzy matching). Structurally a no-op for single-itemgo-coderuns.
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 onetroubleshooting.md—gald3r go-statusfor 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 invokegald3r autopilotunderneath -- they are engine-backed playbooks your session executes itself via its own subagent tool./g-go-gois the one exception: its own command doc namesgald3r autopilot loop --executor sessionas 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-goremains 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-compatvia 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-agentmodel slugs (BUG-1293 item 5): thecursor-agentvendor binary has nols-models(or similar list-and-exit) subcommand -- passing an unrecognized--model/--*-modelvalue does NOT error, it silently starts a real, billed conversational turn. Never guess a slug.claude-sonnet-5-mediumis field-verified working as of beta.39 (seedocs/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 andcursor-agent --help.
Billing surfaces and consent (T1206, EPIC T1204)¶
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,codexon ChatGPT sign-in,gemini-clion 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 aclaude/codex/gemini-clispawn 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.