Skip to content

Budgets and spending caps

View Markdown

Nodus enforces two kinds of spending limits. Both are checked before any paid work starts and again every few minutes while it runs, so a limit always stops spend instead of reporting it afterwards.

  • A Budget limits what matching work across your org can spend in a month or in total.
  • maxCostUSD caps one object: a Job, Pipeline, Sweep, TrainingJob, Sandbox, Workspace, Function, Agent or InferenceEndpoint. A cap on a Pipeline or Sweep is shared by every run it creates.
apiVersion: nodus.dev/v1
kind: Budget
metadata:
name: research-monthly
spec:
limitUSD: "500.00"
period: Monthly # a UTC calendar month; Total counts from creation
scope:
project: research # leave out for the whole org
selector:
matchLabels: {team: nlp}
action: Block # Notify only sends notices
thresholds: [50, 80, 100]
notify:
emails: [research-leads@example.com]
Terminal window
nodus apply -f budget.yaml
nodus get budget research-monthly

nodus get budget shows what is spent, what is held for running work, what remains and the thresholds already notified this period. An org can have up to 50 Budgets.

A Budget counts every hold and charge of work in its project whose labels matched the selector when the work was created. Changing a running Job’s labels does not move it out of a Budget. A Budget you create while work is already running starts covering that work within 5 minutes.

With action: Block:

  • New work in scope is refused with 402 BudgetExceeded, naming the Budget, what is left and what the work needs:

    budget "research-monthly" has $0.40 left of $500.00 this month; job "train-a" needs $3.20.
    fix: raise spec.limitUSD on budget/research-monthly, or wait until 2026-11-01
  • Running work in scope stops gracefully, as described in When money runs out, with Funded=False and reason BudgetExceeded.

  • Raising spec.limitUSD, switching to Notify, deleting the Budget or the start of the next month resumes it.

With action: Notify, nothing is refused; you only get the notices.

Each threshold is sent once per period as a BudgetThreshold Event, a budget.threshold webhook and an email to the billing email, org owners and admins, and the addresses in spec.notify.emails. Reaching a Block limit also sends BudgetExceeded (webhook budget.exceeded).

kind: Job
spec:
maxCostUSD: "25.00"

A Job never holds more than its cap. When its spend reaches the cap, it checkpoints and becomes Suspended with reason MaxCostReached; raising maxCostUSD resumes it from the checkpoint. You can raise a cap at any time, but not lower it.

A Pipeline, Sweep or TrainingJob shares its cap with the Jobs it creates. Each child must fit both its own cap and its parent’s remaining cap, along with every matching Budget. A dry-run reports an insufficient spending limit in status.estimate.blockingReasons without reserving funds.