Wardrik.Ceiling (wardrik v0.1.0-rc.1)

Copy Markdown

A budget all of an org's agents share. Set ceilings in the org's Wardrik.OrgSettings:

ceilings: %{
  "spending-cap" => [usd: 20.00, per: :day],
  "free-allowance" => [usd: 5.00, per: :total, on_exhausted: :deny],
  "watch" => [tokens: 2_000_000, per: :month, on_exhausted: :continue]
}

A ceiling takes the same settings as WardrikPolicy.Budget, except per: :turn. It must set :usd, :tokens or both. Wardrik counts what the org's model and tool calls spend in each period.

Once the limit is reached, the next model call by any of the org's agents does what :on_exhausted says:

  • :ask - the default. The call waits on a ceiling_approval interrupt. Only a scope allowed ceiling.approve on the org's ceiling resource, such as acme/ceiling, may approve it. Owners can. Approving adds the budget's grant for every agent in the org, for that period.
  • :deny - the call is refused.
  • :continue - the call runs.

Every ceiling emits [:wardrik, :ceiling, :reached] when its limit is reached.

A ceiling in dollars refuses models with no price, unless it's :continue. Subagents' model calls count too, as part of the tool call that ran them.

Summary

Functions

Builds the ceiling name from budget settings, as a keyword list or a string-keyed map.

Returns what org's agents have spent against ceiling in the current period.

Types

t()

@type t() :: %Wardrik.Ceiling{
  budget: WardrikPolicy.Budget.t(),
  name: String.t(),
  on_exhausted: :ask | :deny | :continue
}

Functions

new(name, settings)

@spec new(String.t(), keyword() | map()) :: {:ok, t()} | {:error, String.t()}

Builds the ceiling name from budget settings, as a keyword list or a string-keyed map.

spent(wardrik, org, ceiling)

@spec spent(Wardrik.t(), String.t(), t()) :: map()

Returns what org's agents have spent against ceiling in the current period.

%{
  limit: %{usd: 20.0, tokens: nil},
  spent: %{usd: 3.5, tokens: 120_000},
  granted: %{},
  on_exhausted: :ask,
  per: :day,
  starts_over: ~D[2026-10-31]
}

:starts_over is nil for a per: :total ceiling.