Run a governed agent, get a receipt

Write the envelope, run a real agent inside it, read what it cost. The caps are enforced by the production gateway, and the receipt is the gateway's own document.

How this works, and who enforces what

Two actors. The agent is the workload: in production your code, here our fixed toy. The gateway is the enforcement layer underneath it. The spec is the contract between them, and it is what meters the work.

  1. agentTriage. A cheap model reads the ticket and labels it (billing, login, and so on). The gateway routes this call to whichever model tier your spec's triage block names.
  2. agentWork the ticket. A frontier model takes over, in turns. Each turn it either searches the knowledge base (several searches at once if it wants) or writes its answer. The gateway counts the turns against your max_iterations and the searches against your max_calls, and the worst case it quoted you charged for each search at your tool_budget_tokens.
  3. agentTwo endings the agent decides. A final reply to the customer becomes resolved. A ticket outside its authority (compensation, repairs, legal) becomes a handoff note for a human, escalated.
  4. gatewayTwo endings the gateway imposes. When a cap binds, the gateway refuses the next call and the run stops. Which cap bound decides how the unit closes: the metered cost reaching your unit_ceiling_usd closes it ceiling_exceeded, a step running out of max_iterations closes it escalated, because that is unfinished work handed to a human rather than a ceiling that was reached. On the last allowed turn the gateway warns the agent first, in the model's own context: tools are withdrawn, answer now with what you have. Caps arrive as signals the agent can read, never as a crash.
  5. gatewayEverything is metered. The gateway prices every model call at that moment's per-token rates and writes the receipt. This is the production gateway, not a copy of it: the playground is its first tenant.

1 What you are sending

The spec you are running under

spec.sm.yaml

Three ways to narrow the envelope. Each one edits a line below, and the gateway enforces it.

Everything the spec can meter
KnobWhat it governsStatus
steps.*.model_tierwhich tier serves a phase: a tier, never a model. Substitution inside the tier is ourslive here
steps.*.max_iterationsturns per phase, the loop bound behind the static worst caselive here
steps.*.max_output_tokensoutput cap per call. Tighten it and watch the computed worst case, and the price, droplive here
tools.*.tool_budget_tokenssize of each tool result fed back to the agentlive here
tools.*.max_callstotal tool calls per unit. Past it the gateway returns a budget-exhausted notice instead of results and tells the agent to answer from what it haslive here
unit_ceiling_usda hard dollar stop per unit, below the computed boundlive here
steps.*.last_turn_warningwhether the gateway warns the agent before the cap. Set it false and watch resolution rates falllive here
terminalthe allowed end states, and a unit must close as one of them. The gateway refuses a close in any state your spec does not declare. This toy reaches resolved and escalated, and closes ceiling_exceeded when the gateway stops it and your spec declares that statelive here
routing_constraintsdata residency and provider allow or deny lists that substitution must respectaccepted, not yet enforced

Unknown keys are rejected with the allowed grammar echoed back. Every knob that narrows the envelope lowers the computed worst case, the ceiling the gateway enforces, and the number a quote is written against. A tighter spec buys a better price.

The ticket it works

medium

One fixed price covers a whole queue of these. Write your own and watch the same price meet a very different bill.

Runs spend our tokens, so each visitor gets a small budget.

2 This runevery call metered against the ceiling you declared

spent $0.0000ceiling $0.1200

Nothing spent yet. Run the agent and this fills with the real calls, one segment each, priced at the moment they were made. If a cap binds, the run stops here and the signal that stopped it is spelled out underneath.

3 The bookone unit is an anecdote, the distribution is the product

Try it, then try breaking it. Out-of-range and unknown keys are refused, not quietly rewritten, and the message you get back is the production grammar's own.

Here the agent self-reports resolved by declaring its answer final, and this route closes the unit with it. In production, terminal states are closed by your system (sm.close(unit, state)), not asserted by the model. Auditing that gap is part of the contract design.

The toy agent searches a 12-topic policy knowledge base (refunds, shipping, warranty, billing, account). A search that misses returns the list of covered topics, so the agent knows what it can and cannot answer.