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_when | Ends when | Cost |
|---|---|---|
| (empty) | the router judges DONE each iteration | one model call per iteration, and it can misjudge |
queue-empty | an iteration finds nothing queued | none — the check runs before any model call |
marker:<TEXT> | a member emits <TEXT> alone on a line | none — 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 startclears 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 write | It used to mean |
|---|---|
--deadline 2026-12-31 | no deadline at all |
--max-iterations 0 | the default, 8 |
--trigger "cron:0 9 31 2 *" | never scheduled — February has no 31st |
--budget-usd -1 | no ceiling |
--done-when DONE | router 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, orfleet.autoruninconfig.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.