Caps and budgets
Kraft stops a work item that runs too long or spends too much, and it hands the item to you instead of failing it. This page explains how those bounds fit together and why they work the way they do. For every key and its default, see policy.yaml. To raise a cap that stopped an item, see Raise a cap on a stopped item.
The default caps
These are the limits a fresh install runs under.
| Bound | Shipped value | Where it is set |
|---|---|---|
| Fix-loop attempts | 2 for verification, 3 for merge_request_feedback | max_attempts on the loop, in the chain |
| Fix-loop attempts, for a loop that sets none | 3 | default: attempts in policy.yaml |
| Fix-loop wall clock | 3600 seconds | default: wall_clock_s in policy.yaml |
| Work item dollar cap | 10 | budget.work_item_usd in policy.yaml |
| Daily dollar cap | 50 | budget.daily_usd in policy.yaml |
implementer task running time | 120 minutes | time_cap_minutes on the task, in library.yaml |
| Wait for CI | 90 minutes | total_time_cap_minutes on the wait task, in library.yaml |
| Wait for the automated review | 30 minutes | the same key |
| Wait for an external approval | 10080 minutes (7 days) | the same key |
| Wait for the post-merge pipeline | 90 minutes | the same key |
Cap per level of scope (time_cap_minutes, total_time_cap_minutes, token_budget, budget_usd) | none | defaults: in policy.yaml |
| Maximum per level of scope | none | maxima: in policy.yaml |
Whichever bound runs out first stops the item, and the stop names its scope.
The shipped policy.yaml has example per-level defaults, commented out. If you
uncomment them, the work item runs under 480 minutes, each node under 180, each
step under 120, and each task under 90, all at once.
Two kinds of bound
Kraft bounds work in two ways.
Loops bound repetition. A fix loop retries a node until it passes. Its
attempt limit is max_attempts in the chain (attempts under loops: and
default: in policy.yaml). Its wall clock is wall_clock_s there.
An external wait (a pipeline, an automated review, an approval, a merge
landing) is not a loop. Its timeout is its own task's total_time_cap_minutes.
Caps bound a scope's resources: time, tokens, and dollars. A scope is one of four, each inside the one before:
- the whole work item;
- one node, a stage of the item's chain;
- one step, a group of tasks inside a node that run in parallel (a node's steps run in order);
- one task, a single unit of work, such as one agent run or one command.
Only a person resets a loop's count. A retry from the board or from
kraft item retry starts the fix loops of the retried
span afresh. A retry that a worker, an MCP
assistant, an escalation turn, or a rate-limit relaunch asks for keeps
counting. An escalation turn is the
agent Kraft starts to help when an item stops and waits for you. See
Fallback and escalation.
Why loops: ships empty
A loops: key that names no live loop does nothing and warns nobody. A stale
cap would look live and bind nothing, so the shipped policy.yaml names none.
The default: entry covers every fix loop. A loop's own max_attempts in the
chain wins over default:. The shipped fix loops therefore take their attempts
from the chain and only their wall clock from default:.
Caps are set per level
You set the four caps (time_cap_minutes, total_time_cap_minutes,
token_budget, budget_usd) per level of scope: the work item, its nodes
(a gate is a node), its steps, and its tasks.
A level's default binds every scope of that kind that nothing set a value for.
Out of the box no level default is set. Only the caps the shipped tasks set on
themselves in library.yaml apply, alongside the budget: dollar caps.
A value set in the chain (on the chain, a node, a step, or a task) or by the item's own override replaces the defaults for that scope and for every scope under it that sets none. A node set to 240 minutes runs its steps and tasks under 240 too.
A default is not a ceiling. Any scope may set more, up to its level's
maximum. A narrower level's cap may not exceed a broader one's
(tasks <= steps <= nodes <= work_item), so a task cap of 20 minutes
inside a step capped at 10 is refused when the chain loads.
A cap in a repository's policy: (in repos.yaml) or in the chain's own
policy: is a cap on the work item as a whole.
How a policy resolves
A work item freezes its policy when you file it. Kraft layers it from the broadest source to the narrowest:
defaultsandmaximainpolicy.yaml.- The repository's
policy:inrepos.yaml. - The chain's
policy:. - Each node's, step's, and task's own
policy:. - Your item's own override, from
kraft item create --policyorkraft item set-policy.
At intake, Kraft refuses a layer that relaxes what it inherits, and names the scope. A bad policy therefore fails when you file the item, not hours into a run.
Your override comes last, so its operational values win over the template's.
A max_attempts or timeout_minutes on an execution node wins over its fix
loop's own max_attempts.
An override's safety values only ever tighten:
- An
allowed_toolslist intersects with what the scope already allows. - A
grantslist keeps only the grants the scope already holds. deny_toolsadds to the list.- A
sandboxmust match any already set.
The chain narrowing the same field first never causes a refusal.
Your override is the one layer that can change after filing. On a running or waiting item, a change takes effect from the next node entered and the next check of a wait.
A recovery plan inherits the task, step, or node that declares it. A fix loop,
its judge, a node's escalation task, and its conflict handler inherit their
node. A gate's auto_review inherits its gate.
Time caps
There are two clocks.
time_cap_minutescounts running time. Paused time, external waits, gates, and rate-limited time do not count.total_time_cap_minutescounts wall-clock time, including waits, gates, and rate limits, less only a manual pause. For a task other than a wait, it is the task's running time. For a wait, it is the wait's timeout.
Every clock counts from the scope's start in the current run. A person's
retry starts them all afresh. A rate-limit relaunch or a stuck escalation's
own retry does not.
A node's clock is its own, independent of its fix loop's timeout_minutes,
which bounds only the fix cycles. A node's cap covers everything that runs as
that node: its tasks, recovery, fix loop, a gate's automated review, and the
automatic stuck-escalation turn. Your own escalation chat is not the node
running, so it is not capped.
Hitting a cap stops the item and waits for you, with the reason "<scope> hit
its time cap of N minutes". The reason reads "total time cap" for
total_time_cap_minutes, and the scope reads "the work item" for the work item
itself.
A time cap is never treated as a code failure. It spends no recovery or
fix-loop attempt, and no stuck escalation answers it. A gate's own timeout
stops the item the same way, naming the gate, and the gate stays open for you
to approve or reject.
A work item's total_time_cap_minutes counts its gates and external waits, so
a cap of two days stops an item still waiting on a week-long approval. Size it
for the longest wait your chain allows.
Token and dollar budgets
A token or dollar cap refuses to start the next agent launch once its scope, or any scope around it, has reached its cap. Kraft checks before each launch, gate reviewers and escalation turns included. It cannot interrupt a running agent, so overshoot is bounded by one launch's cost.
While an agent is still running, its spend counts too. Kraft prices the
agent's known tokens against a shipped rate table and shows the result as an
estimate (~$4.20 (est.)) until the session exits and the agent's own
reported figure replaces it. A long session's spend can therefore trip a
dollar cap before the session finishes, not only after.
Three things follow.
- A finished launch whose harness reported no cost counts at an estimate from the same rate table. If Kraft cannot price it, the caps differ: see Harnesses that report no cost.
- Launches that start together in one scope, such as a parallel step's tasks, each pass the check before any of them has spent. A shared scope's cap can be overshot by up to their combined cost.
- A launch that resumes an earlier agent session counts only what it added.
budget.work_item_usd and budget.daily_usd in policy.yaml stay the outer
ceilings, above any per-scope budget_usd.
For which harnesses report no cost and how Kraft estimates what they spent, see Cost reporting.
Why a raise is bounded
You can raise the cap that stopped an item for that one item, and retry it. The
raise is bounded so that an item cannot pass the maxima you set for every item.
- An item's own cap may exceed the chain's, but only up to
maxima.work_item. - A cap on a node, step, or task may pass its level's default, up to its level's maximum, and never what an enclosing scope allows.
- A limit set outside the item, such as
budget.daily_usd, is not the item's to raise. - On spend a harness never reported, no higher number helps, because Kraft
still cannot show the scope is under the new cap. Only lifting the dollar cap
with
--usd nonepasses it.
The steps are in Raise a cap on a stopped item, and the command's refusals are in Raise a cap that stopped an item.
The shipped implementer cap
The implementer task, which both shipped chains run, sets
time_cap_minutes: 120. Successful implementer runs finish well inside that
time, so the cap binds only a run that has already gone wrong, for example a
worker stuck waiting on a test run it backgrounded.
A turn that ends with a background job still running fails the task: see Result file.
A long plan can need more than 120 minutes. Raise the item's own cap, or set a
larger one on the task in library.yaml. The task sets 120 minutes, above the
commented example's tasks default of 90, which a scope may do. A
maxima.tasks.time_cap_minutes (or a broader level's) below 120 makes Kraft
refuse both shipped chains at intake, so lower the task's cap to fit.
Why maxima start unset
A fresh install ships with defaults: and maxima: commented out. An
uncommented value is a real ceiling, and Kraft must not silently cap someone
who never chose a number.
A safety field listed only in maxima, such as allowed_tools, starts at its
maximum and can only be narrowed. That is why the reference example sets no
maxima.allowed_tools: a list there binds every agent task on every harness.
Not every harness can enforce a tool list. On claude, the harness every
shipped task uses, a list removes every built-in tool it does not name. Other
harnesses enforce it differently or refuse to launch under one. See
Permission gate for each harness, and
policy.yaml for the web tools codex and
cursor need in the list.
Related
- policy.yaml: every key and its default.
- Permission gate: how
allowed_toolsanddeny_toolsare enforced. - Vocabulary: what chain, node, step, and task mean.