Fleet Loops

A fleet runs its goal once with mur fleet run. With --loop it keeps going — and the interesting question becomes when does it stop?

mur fleet send builder "cargo nextest run -p mur-core"   # queue work
mur fleet run builder --loop --budget-usd 2              # drain it
mur fleet set-loop builder --done-when queue-empty       # persist the policy
mur fleet stop builder                                   # kill-switch

Three ways a loop ends

A loop needs to answer "is this done?" every iteration. There are three answers, and which one fits depends on what the fleet is for.

done_whenEnds whenCost
(empty)the router judges DONE each iterationone model call per iteration, and it can misjudge
queue-emptyan iteration finds nothing queuednone — the check runs before any model call
marker:<TEXT>a member emits <TEXT> alone on a linenone — plain string matching

queue-empty is the one to reach for when you feed a fleet with mur fleet send. Without it, a scheduled fleet that wakes to an empty queue re-sends its standing goal every iteration until the cap runs out. Stuck-detection does not catch that: a member replying "what should I run?" counts as activity, so the counter resets and the loop keeps paying.

marker: needs a second half. The marker only works if something taught an agent to emit that exact text — usually a line in the fleet's goal, or a skill a member loads. Set it in fleet.yaml alongside whatever does the teaching; the Hub deliberately will not author one for you, because it cannot write the other half.

Marker matching is whole-line, not substring. A member that mentions the marker in prose ("I'll print DONE when finished") does not converge the loop — stopping early on a false positive is worse than running one extra iteration.

The guards

Every loop is bounded whether or not it converges:

  • Iteration cap — --max-iterations, default 8.
  • Deadline — --deadline 30m, relative to when the loop started, not a calendar date. Checked between iterations, so it stops the loop starting another round rather than interrupting one mid-flight.
  • Budget — --budget-usd, from real per-token spend. Checked before an iteration it cannot afford, so the loop stops short rather than overshooting.
  • Stuck detection — two consecutive iterations with no new agent activity.
  • Kill-switch — mur fleet stop <name> writes a sentinel honored by the loop, the daemon, and manual runs alike. mur fleet start clears it.

Settings that used to mean something else

mur fleet set-loop refuses a value that would be silently reinterpreted. Each of these once looked configured and did nothing:

You writeIt used to mean
--deadline 2026-12-31no deadline at all
--max-iterations 0the default, 8
--trigger "cron:0 9 31 2 *"never scheduled — February has no 31st
--budget-usd -1no ceiling
--done-when DONErouter judgment — the marker: prefix is required

Validation reuses the same parsers execution uses, so what the check accepts and what the scheduler does cannot drift apart. Only the flags you pass are judged: a fleet already carrying a bad value from an older version still loads, and still accepts an unrelated edit.

Unattended runs

A fleet with a cron: or interval: trigger can be run by the daemon with nobody watching. That path is deliberately harder to reach than the manual one:

  • It is off by default. Set MUR_FLEET_AUTORUN=1, or fleet.autorun in config.yaml.
  • It requires a positive budget. A fleet with no spending ceiling never auto-runs, however valid its schedule.
  • It honors the kill-switch, and it fails closed: if governance state cannot be read, the fleet is treated as halted rather than as permitted.

Manual runs need none of this. mur fleet run and mur fleet run --loop work with no budget set — you are there to watch.

A loop that reaches a step needing human approval does not burn its window against an empty room: the request is parked, the step is reported blocked, and the loop stops with awaiting-approval rather than paying for an iteration that would ask again. Approve it whenever you get to it and the next run continues from there. See Unattended Approvals — including the hitl: policy block that lets a fleet state its own answer.

Watching a run

When a fleet is kicked off from chat, the murmur TUI shows the run live automatically: a per-member status rail plus milestone lines (delegations, member summaries, outcomes, approval gates) streamed from the fleet's signed channel. See Agent CLI → Live fleet progress.