Cost · MIT

Keep an agent inside a budget

Hold an agent, job or run inside a hard dollar budget using the per-call cost the Gateway returns, and handle the 402 when an allowance runs out.

Installing a skill

Version 1.0.0 · 148 lines

When an agent loads it

What the file covers.

Use when building an autonomous loop, when asked to cap spend on a task, or when a Gateway call returns 402 Payment Required.

  1. 01

    The pattern

  2. 02

    Where you stand, before you start

  3. 03

    When the allowance runs out: 402

  4. 04

    Two behaviours worth knowing before you rely on them

  5. 05

    Structural caps beat runtime caps

  6. 06

    Do not

The file

The whole SKILL.md, and where it goes.

In Lobstack, open Skills › Add a skill and paste it. In Claude Code, make the folder and paste it in, then start a new session.

shell
mkdir -p .claude/skills/lobstack-spend-budget
# paste SKILL.md into .claude/skills/lobstack-spend-budget/SKILL.md
lobstack-spend-budget/SKILL.md148 lines
---name: lobstack-spend-budgetdescription: "Hold an agent, job or run inside a hard dollar budget using the per-call cost the Gateway returns, and handle the 402 when an allowance runs out. Use when building an autonomous loop, when asked to cap spend on a task, or when a Gateway call returns 402 Payment Required."license: MITmetadata:  title: "Keep an agent inside a budget"  version: 1.0.0  author: lobstack  category: cost  tags: [cost, budget, agents, quota]--- # Keep an agent inside a budget An agent loop with no spend bound is a while-loop attached to a credit card. Thefix is not an estimate before the call; it is a measurement after each one, and astop condition that trusts it. ## The pattern Measure after, not estimate before. A pre-flight estimate has to guess the outputlength, which is the term that dominates the cost and the one thing you cannotknow. The receipt is exact and it arrives in time to stop the *next* call. ```tsclass Budget {  private spent = 0;  private unpriced = 0;   constructor(private readonly limitUsd: number) {}   /** Call before every model call. */  assertHeadroom(reserveUsd: number) {    if (this.spent + reserveUsd > this.limitUsd) {      throw new BudgetExhausted(this.spent, this.limitUsd, this.unpriced);    }  }   /** Call after every model call, with the receipt. */  record(costUsd: number | null) {    if (costUsd === null) {      // Unknown cost is not zero cost. Charge the reserve against the budget so      // an unpriced model cannot run forever for free.      this.unpriced += 1;      this.spent += this.reserveUsd;      return;    }    this.spent += costUsd;  }   private readonly reserveUsd = 0.05;   // your own pessimistic per-call figure}``` Three properties make this work and each one is a bug if you drop it: 1. The check is before the call and uses a reserve, because a call you have   not made yet has no cost. Set the reserve to something you would be unhappy   but not ruined to spend once — the point is that the loop cannot overshoot by   more than one call.2. `null` is charged, not ignored. cost_usd is null for a model the   Gateway cannot price. Treating that as 0 gives an unpriced model an   unlimited budget, which is precisely backwards.3. The exhaustion carries the numbers. "Budget exhausted" is not actionable;   "$4.98 of $5.00 across 212 calls, 3 unpriced" is. Cap turns as well as dollars. A loop that stalls on a cheap model burns wallclock and context without ever tripping a dollar limit. ## Where you stand, before you start The quota headers ride on every response, success or failure, so a long jobcan check its own headroom without a second API call: ```x-lobstack-quota-meter: spend                # spend | requests | legacyx-lobstack-quota-allowance-usd: 10.000000x-lobstack-quota-spent-usd: 4.113200x-lobstack-quota-remaining-usd: 5.886800x-lobstack-quota-resets: 2026-10-01T00:00:00.000Z``` On a request-metered plan (the BYOK plan, no longer sold) the same three facts arrive asx-lobstack-quota-limit, -used and -remaining as integers, plus-credits when purchased balance remains. Read -meter first and branch;the counted headers are absent on a spend meter and vice versa, deliberately, soa client cannot read a missing header as "no allowance". ## When the allowance runs out: 402 ```json{ "error": { "message": "monthly allowance exhausted: this month's included usage and your credit are used up. Top up any amount in Console › Settings › Billing (credit does not expire), upgrade the plan, or wait for the month to reset.",             "type": "quota", "code": 402,             "request_id": "8f2b1e0c-4d5a-4b91-9c3e-6a7f0d2b5c41" } }``` Do not retry a 402. retry-after is present and is computed from the periodreset, so it is usually days rather than seconds. It means "this will not clear onits own before then", not "back off and try again". The resolutions are a top-up,a plan upgrade, or the period rolling over. On Free the 402 carries error_code: "FREE_CREDIT_USED" and noretry-after: the one-time trial credit is used, nothing resets, and Freecannot top up. The message: "Your free credit is used. Keep going free with your own provider key or GitHub Copilot in the Lobstack app; for Gateway API calls, pick a paid plan for managed usage or add an organization provider key in Console › Settings › Provider keys: https://www.lobstack.ai/pricing" A paid plan's own provider keys are the exception: with the allowance spent,calls to providers the organization holds a key for still go through, becausethey spend no allowance. auto then routes only among those providers. A 429 is the other member of the quota class and is the opposite advice:that one is a rate limit — the Gateway's own (120 requests a minute per API key,error_code: "RATE_LIMITED") or the provider's, passed through with itsstatus. Back off exponentially with jitter and retry, honouring retry-after. ## Two behaviours worth knowing before you rely on them Every credential is enforced. API keys and legacy agent credentials alike geta 402 once the allowance is spent. A client tag with a monthly budget and a hardstop gets its own 402, error_code: "CLIENT_BUDGET_EXHAUSTED", once thatclient's spend reaches the budget. Errors accrue no spend. A failed round writes a ledger row with zero tokens,and a request that failed at the provider does not consume a request allowance.An outage does not eat your month. ## Structural caps beat runtime caps Two levers cost nothing to set and cannot be forgotten at a call site: - The tier ceiling on the plan. The router never exceeds it, so the worst  case per call is bounded by configuration rather than by review. See  lobstack-model-tier.- `max_tokens`. Output is priced several times input across the registry, so  a bounded output is the single most effective per-call cap available. Set it to  what the answer actually needs. Verified routed savings (both models priced, the row not an error, on a managedkey, the baseline strictly above the actual cost) are reported on the receipt andthe ledger. They do not currently extend an allowance; do not model them as adiscount. ## Do not - Do not estimate cost before the call and call it a budget.- Do not treat null cost as free.- Do not retry a 402.- Do not bound dollars without also bounding turns.
More for developers

More SKILL.md files, from Cost first.

Cost on its own shelf, or every developer skill.