Agents & automation
Bodega Loops (Automations)
Bodega Loops runs agent tasks on a schedule - on your machine, with your models, at no per-run cost. Every run executes in an isolated git worktree and lands as a reviewable diff with a QEL verification score. Nothing touches your project unless you apply it or explicitly opt a loop into auto-apply. The dashboard is a Code-mode sidebar panel, opened from a loop's row in Runs (Open in Loops); loops are managed in Settings → Automations → Loops & nightly re-check.
What a Loop is
A Loop is a named agent task with a trigger and an apply policy:
- Task prompt - what the agent does each run (e.g. "Sync inline docs with the current implementation").
- Trigger - when it fires: a cron schedule, a fixed interval, or Bodega Map staleness.
- Apply policy - what happens to the changes: park for review (default), auto-apply when QEL passes, or dry run.
Each run is a normal headless agent session: it appears in your session history, respects your permission mode and tool allowlists, inherits air-gap mode, and counts against your cloud spend caps if it uses a cloud model. Local models run free.
Enable Loops and create one
- The quickest way is the composer: type the task, open Send as… (the ▾ beside Send) and choose Make this a loop…, or use New → Loop… in the Runs header. The short form takes a name, the task, a schedule (or a comment keyword), what happens to the changes and whether to run the first pass now; All settings… opens the full dialog described below. Or go to Settings → Automations → Loops & nightly re-check (or click + New in the Bodega Loops sidebar panel).
- Turn on Enable Loops. The scheduler is dormant while this is off - nothing fires, including Run now. Flipping it takes effect within a minute; no restart.
- Click New loop. Give it a name, a task prompt, and a project path - the project must be a git repository (scheduled runs require worktree isolation).
- Choose what it runs with (see below), pick a trigger and an apply policy, then Create loop.
- Use Run now on any loop to test it immediately and watch the result land in its History.
Loop committed to the repo? Click Import from file next to New loop. It reads .bodega/loop.md from the open project and creates the loop, or updates the existing loop with the same name - the same thing bodega loops import does in the CLI.
Run with - pick a custom agent or a specific model
Each loop chooses its own brain, the same way a heterogeneous Fleet does - so you can point cheap, small jobs at a fast local model and reserve a cloud model for the heavy ones.
- Default agent (pick a model): leave it on the default agent and choose a provider + model from the picker (the same grouped picker the chat composer uses - it only lists models you've actually set up). Leave the model blank to inherit your default code model.
- A custom agent: pick one of your custom agents (Settings → Agent → Custom agents). The loop then runs as that agent - its system prompt, tool allowlist, read-only setting, and pinned model all apply. A custom agent pinned to a cloud model routes to that cloud provider even when your active provider is local.
Either way the model drives the provider automatically; a loop never runs the wrong model on the wrong provider.
Triggers
| Trigger | How it works |
|---|---|
| Schedule (cron) | Presets (hourly, daily 02:00, nightly 01:30, weekdays 06:30, weekly) or a custom 5-field cron expression, evaluated in local time. Invalid expressions are rejected when you save - not silently never-fired. |
| Fixed interval | Every N minutes (minimum 1). |
| Bodega Map staleness | Checks every 15 minutes whether at least N of your Map's module summaries have gone stale (the code changed under them). Pair it with a task prompt that refreshes documentation or re-explains changed modules - a self-maintaining codebase map. |
| Comment trigger (watch mode) | Watches the loop's project folder and fires when you save a file containing an inline directive - the bare // fix this AI! form (always recognized) or // <pattern>: using watch.trigger_pattern (default bodega, e.g. // bodega: ...). Requires both Loops enabled AND Settings → Automations → Loops & nightly re-check → Watch for comment triggers (watch.comment_triggers_enabled, off by default). The watcher only runs while Bodega is open. |
Loops fire while Bodega is open - the scheduler is in-process. Runs missed while the app was closed are not replayed. A loop can also be driven by inline code comments (the comment-trigger watch mode above).
Apply policies and the QEL gate
The apply decision is made by the QEL verification gate, never by the agent grading its own work:
- Park for review (default) - every run lands as a reviewable diff with its QEL score. Nothing is applied, ever. Review and apply from the run's session like any Fleet session.
- Auto-apply when QEL passes - changes merge back automatically ONLY when the run's QEL score clears the threshold. Failing runs park as
qel_failedwith the diff preserved. Opt into this per loop once you've seen consistent scores you trust. - Dry run - the agent runs in its isolated worktree and reports a score; the diff is kept for inspection but never applied.
The optional QEL threshold (0–100) sets the bar for auto-apply. Leave it empty to use the verifier's model-tier default; set it explicitly and your number is authoritative - stricter or looser.
The dashboard, run history, and Runs
The Bodega Loops panel - reached from a loop's row in Runs (right-click → Open in Loops), and still a panel in your layout - is the dashboard: every loop with its trigger, a live running dot, Run now, and expandable run history. The same history also lives under each loop in Settings.
Each loop's History shows every run: status (applied, parked, qel_failed, no_changes, failed, cancelled), duration, files changed, iterations, and the QEL score. Expand a run to read the full QEL trace - file checks, pattern checks, proof gates, and the score breakdown.
Runs replaced the top-bar Loops pill. A running loop is a row under Working; a run that parked for review shows under Needs you as Loop parked; a loop run that finished while you were away shows under Done with its verification chip. A loop can never fail silently: a run that failed, or finished below its verification bar, stays in Needs you (Loop failed, Below the bar) until a newer run of that loop replaces it or you archive or delete its session.
Notifications: when a run parks, applies, or fails, its row in Runs is the in-app notification (nothing pops up), and Bodega also sends an OS notification if you enabled it, with the loop name, outcome, files changed, and QEL score ("Nightly docs sync: parked for review - 3 files, QEL 82%"). These share the Fleet notification and quiet-hours settings.
Next-run countdown (beta.28): interval and Map-staleness loops show a live "next in 14 min" countdown on their rows, so you never wonder whether a loop is about to fire.
Run now: each loop has a Run now button in the Loops panel. Runs that need a person - parked for review, failed, or below their QEL bar - are in Needs you in Runs, alongside Fleet lanes waiting on approval or apply.
Stop a running loop: a working loop has a Stop in the Loops panel, and S or Stop in its Runs row. Stopping cancels the run mid-flight: the agent halts at its next checkpoint, the run is marked cancelled, and any partial work is left in its isolated worktree for review, never auto-applied.
Safety and limits
- Scheduled runs require worktree isolation. If the project isn't a git repo (or isolation is unavailable), a scheduled run refuses and records
failedrather than writing to your working copy. Run now keeps a warned in-place fallback for deliberate, watched runs. - Concurrency cap - at most
loops.max_concurrentruns at once (default 1); extra triggers skip and retry on their next natural firing. - Spend caps apply. A loop on a BYOK cloud model is refused with the same "spend cap reached" behavior as a foreground chat once your daily/monthly cap is hit. Local models are never gated.
- Air-gap is inherited. Under air-gap, a loop that needs the network is blocked exactly like a foreground run.
- Iteration cap - each loop has its own max-iterations (clamped to your global
agent.max_iterations_ceiling). - A crash mid-run can't wedge the scheduler: orphaned runs are marked failed on the next launch.
Good first loops
- Nightly doc sync - cron
0 2 * * *, prompt: "Sync inline docs and README sections with the current implementation. Do not change behavior." - Map self-maintenance - Map staleness ≥ 3, prompt: "Refresh the Bodega Map summaries for modules whose code changed."
- Dead-code sweep - weekly, dry-run policy first: "List and remove unused exports and dead files. Be conservative."
Start with park for review. Graduate a loop to auto-apply after its scores have earned it.
Things that aren't obvious
- Loops are off until you turn them on, and the toggle is global.
loops.enableddefaults to off. While it's off the scheduler is fully dormant - even Run now does nothing. If a loop you created has never fired, check this first. - The concurrency default is 1.
loops.max_concurrentdefaults to 1 (max 5). Two loops scheduled at the same minute will not both run; the second skips and waits for its next natural firing rather than queueing. Stagger your cron times if you have several. - Comment triggers need two switches, not one. Watch mode requires
loops.enabledandwatch.comment_triggers_enabled(off by default). The bare// fix this AI!form always works once watch mode is on; the// bodega: ...form uses whateverwatch.trigger_patternis set to. - A missed run is gone, not deferred. The scheduler runs inside the app. Nothing fires while Bodega is closed, and nothing is replayed when you reopen it. A nightly loop only runs on nights you left the app open.
- Judge the loop by its history, not its last run. Each custom agent also has a History view (Settings → Agent → Custom agents → History on the card) that aggregates every loop and automation run that used it - the right place to look before promoting anything to auto-apply.
- A loop's output is reviewed exactly like a Fleet session. Parked runs land in the same Needs you section of Runs as Fleet lanes waiting on you, and are applied through the same diff-and-conflict-check flow.
In the CLI
The loops command family manages the same backend-side loops: bodega loops list [--output json], loops create --name N --prompt "..." --cron "0 3 * * *" [--project P] [--disabled], loops enable|disable|delete <name-or-id>, loops runs [name-or-id] [--follow] (or --follow to stream loop_run_status live), loops run <name-or-id>, and loops import [path]. It fails soft against an older backend that doesn't support loops. The /loops REPL slash command covers list and run/cancel from an interactive session.
This page mirrors the in-app docs hub for app version 1.0.0-beta.46. Found something unclear or out of date? Tell us on Discord. New here? Download the free beta and follow along.