Constrain a session or a single run:
use Clutch\Laravel\ValueObjects\RunBudget;
$session = Clutch::agent(ResearchAgent::class)
->for($user)
->budget(new RunBudget(
maxSteps: 40,
maxToolCalls: 100,
maxTokens: 250_000,
maxCostUsd: 8.00,
maxDurationSeconds: 900,
))
->create();
Budgets layer: configuration defaults first, then the session, then the run. At each level the more restrictive limit wins, so a session can tighten a ceiling but never raise it.
A run that hits a hard limit moves to budget_exceeded, emits a terminal event naming the limit that ran out, and keeps its last safe checkpoint.
Usage carries across attempts, so a retry loop cannot spend the same budget three times. Reset it when you actually mean to:
$run->retry(resetBudget: true);
maxCostUsd needs prices to work against:
// config/clutch.php
'pricing' => [
'anthropic:claude-sonnet-4-5' => ['input' => 3.00, 'output' => 15.00],
'openai:gpt-5' => ['input' => 1.25, 'output' => 10.00],
],
An unpriced model contributes 0.00 rather than a guess. That shows up in the usage record, which beats a plausible number that happens to be wrong.