Expand description
Execution limits: the one limits: block every scope carries (spec
2026-09-12 execution-limits §3.1), its duration grammar, the built-in
defaults (§3.3) and the resolver that says what is in force and where it
came from (§3.9).
Three knobs, no more: deadline (wall clock for the unit of work),
stuck (minutes of no progress before a stop, or off) and cost_usd
(only meaningful on a metered model — applicability is the caller’s call,
this module resolves the number). Inner scopes REPLACE a key; nothing here
adds two caps together, because the product of caps is the problem the
spec exists to remove.
Structs§
- Global
Limits - Limits
- The block as written in YAML. Every key optional; an absent key means
“inherit”, never “unlimited” —
stuck: offis the explicit opt-out. - Resolved
- Resolved
Limits
Enums§
- Global
Source - Which file the global scope was read from.
- Scope
- Which built-in deadline applies when no scope sets one.
- Source
- Where a resolved value came from — the half of
mur limitsthat makes it worth running. - Stuck
- The stuck detector’s setting once resolved.
Constants§
- DEFAULT_
DEADLINE_ FLEET - DEFAULT_
DEADLINE_ TASK - DEFAULT_
STUCK - §3.3 — the constants
mur limitsprints as(built-in default). - GLOBAL_
LIMITS_ DIR - Directory under
mur_homeholding the global scope. Granted read-only to sealed agents as a directory, so edits that replace the file stay visible. - GLOBAL_
LIMITS_ FILE - The global scope’s file inside
GLOBAL_LIMITS_DIR: a bareLimitsmapping, nolimits:wrapper. - LEGACY_
CONFIG_ FILE - The user config that carried the global scope before #1794.
Functions§
- global_
limits_ dir - global_
limits_ path - legacy_
block_ present - Whether
config.yamlstill carries a non-emptylimits:block. Doctor uses it to say the block is ignored once the new file exists; MUR never removes it — that file is the user’s. - legacy_
config_ path - load_
global - The global scope for CLI readers. The new file is strict; the legacy
fallback keeps the old lenient
Config::load_or_defaultbehaviour, so aconfig.yamlbroken somewhere unrelated still reads as “no global limits” exactly as before #1794. - load_
global_ strict - The global scope for a reader that already holds a good copy and must not trade it for defaults (the agent runtime’s hot reload): both files strict.
- parse_
duration 30s,5m,2h,1d,1h30m, or a bare integer (seconds).Noneon anything else — the caller turns that into a load error naming the key.- read_
global_ file - The new file alone.
Ok(None)when it does not exist; an empty file is an empty scope (it still shadows the legacy block). A file that is present and does not parse is an error, never the defaults. - resolve
- The resolver. Precedence, narrowest wins: flag > agent > fleet > global >
built-in. Each key is resolved on its own; a scope that sets only
stuckleavesdeadlineto the next scope out. - validate
- §4: an unparsable value is an error naming the key, never a silent default.