Budget controls for coding agents in CI: caps that actually hold
Updated 2026-07-15
A coding agent running unattended in CI needs three stacked controls: a turn cap on the agent process, a wall-clock timeout on the job, and a hard spend limit on the API key it uses. Any single layer leaks, because retries, matrix fan-out, and agent loops each slip past one control. With all three set, a runaway run costs cents instead of a month of budget.
Quick answer: cap the turns, cap the clock, cap the key.
An interactive coding session has a natural budget control: a human who gets bored, suspicious, or done. A coding agent in CI has none of that. It runs at 3 a.m., it retries when it fails, and it spends the same dollars on the hundredth identical failure as on the first. The bill arrives at the end of the month with no story attached to it. The fix is not one control, it is three, stacked so that each catches what the others miss. First, cap the agent loop itself with a maximum turn count, so a single run can only make so many model calls before it must stop and report. Second, cap the job with a wall-clock timeout and a concurrency group, so runs cannot hang forever or stack on top of each other. Third, cap the key: give each pipeline its own API key with a hard spend ceiling, so even a cap you misconfigured cannot spend past the number you wrote down in the key settings. Sized correctly, the layers fire in order. The turn cap ends normal runs, the timeout ends abnormal ones, and the key ceiling is the backstop that turns a config mistake into a failed job instead of an incident. The rest of this page is the detail: where the tokens go, what a realistic run costs, which layer fails in which way, and the exact configuration that wires all of it in.
Where the money goes when nobody is watching.
Two properties of agent traffic set the shape of the bill. First, context is re-billed: every call includes everything the run has accumulated so far, which means the last calls of a run are several times more expensive than the first ones. A run that reads five source files and dumps two test logs into its window is paying for all of that on every subsequent call, whether or not the current step needs it. Second, the loop is autonomous. The number of model calls in a run is decided by the model's own judgment about whether it is finished, not by you. Interactive users interrupt bad judgment within seconds. CI does not, and an agent that has talked itself into a wrong theory about a failing test will happily spend twenty more calls proving it. Every stop condition an unattended run will ever respect is one you configured before the run started.
- Every model call re-sends the full accumulated context: system prompt, tool schemas, every file read so far, and all prior test output.
- One instruction like "make the tests pass" typically expands into 10 to 40 model calls before the agent reports back.
- Test logs are token-dense. A failing suite that prints stack traces can add tens of thousands of tokens to the window in a single tool call.
- CI containers start clean. There is no warm session to resume, so each run rebuilds its context from zero and pays for it.
- The run ends when the agent decides it is done, hits a cap, or dies. Only the cap is yours to set ahead of time.
Worked example: a test-fixing agent on every labeled PR.
Model a concrete job instead of guessing. A PR labeled agent-fix triggers an agent that runs the test suite, reads the failing files, edits, and re-runs until green or capped. With a turn cap of 25, an average context window around 60K tokens per call is typical once a few files and some test output have accumulated. That is roughly 1.5M input tokens per run, plus about 20K output tokens, and input dominates the cost by a wide margin. The table prices that identical profile at official list rates. The per-run numbers look harmless. The monthly numbers do not: a team that labels 200 PRs a month is spending close to a thousand dollars on a flagship model for this one workflow, which is exactly the kind of figure that shows up unannounced on a card statement. Treat the profile as an estimate and re-run the arithmetic with your own turn cap and window size; the shape of the conclusion survives.
| Model (official list rates) | In / out per 1M | Cost per run | Per month, 200 runs |
|---|---|---|---|
| claude-sonnet-4-6 | $3.00 / $15.00 | ~$4.80 | ~$960 |
| claude-haiku-4-5 | $1.00 / $5.00 | ~$1.60 | ~$320 |
| gpt-5.4-mini | $0.75 / $4.50 | ~$1.22 | ~$243 |
| deepseek-v4-pro | $0.435 / $0.87 | ~$0.67 | ~$134 |
| deepseek-v4-flash | $0.14 / $0.28 | ~$0.22 | ~$43 |
Why CI agent bills surprise teams.
Half of these are one-time fixes: pin the model, split the keys, turn off retries for agent jobs. The other half are structural, which is why the caps in the next section exist. The common thread is that CI amplifies everything. A pattern that costs an interactive user one annoyed minute costs an unattended pipeline the same amount, multiplied by every run, every branch, and every night it goes unnoticed.
- No one watches the loop. An engineer kills a flailing interactive session in seconds; a CI agent flails until a cap fires, and with no cap, until the CI provider ceiling ends the job for you.
- Retries multiply runs, not requests. A retry policy of two attempts on a failing agent job triples the whole 1.5M-token bill, and a deterministic failure usually fails again on the retry.
- Fan-out is silent. Matrix builds, monorepo path triggers, and bot-created PRs can turn one push into five parallel agent runs without anyone explicitly deciding that.
- Fresh containers mean cold caches. Provider prompt caches are short-lived and keyed to an exact prefix, so runs spaced hours apart start cold and pay full input rates while each run rebuilds its own cache.
- Shared keys hide attribution. When developers and pipelines bill through the same key, nobody can say which workflow spent the money, so nobody owns the fix.
- Model defaults drift. Agent CLIs inherit new default models on upgrade; if the model is not pinned in config, an update can raise your unit price mid-month with no change in your repo.
Where to enforce the budget: five layers compared.
The question is not which control is best, it is where each one binds and how it fails. Client-side caps are precise but only apply where the config is loaded; billing-side caps are absolute but blunt. Run all five layers and size them so the client-side caps fire first, the key ceiling second, and the alerts exist only to tell you the story afterwards. A budget system where the hard stop is also the first stop is a system that fails jobs mid-edit on normal days.
| Layer | What it caps | Where it leaks | Where you set it |
|---|---|---|---|
| Agent turn cap | Model calls in one run | Says nothing about window size; a bloated window still bills millions of input tokens inside the cap | Agent flag, e.g. --max-turns |
| Job timeout + concurrency group | Wall clock and stacked runs | A fast loop out-spends the clock, and CI retries restart it | CI workflow config |
| Per-key spend cap | Dollars per pipeline | Stops the job mid-edit when it trips; useless if every pipeline shares one key | API or gateway key settings |
| Prepaid balance | Absolute worst case across everything | Blunt: one runaway pipeline can drain the balance every other job depends on | Billing level |
| Spend alerts and per-key logs | Nothing; visibility only | Alerts lag by hours and page no one by default | Provider dashboard or your log pipeline |
Seven controls that hold in practice.
The last two levers compound with the first five. The ladder below prices the worked profile from earlier at gateway catalog rates: the capped job that costs about $4.80 at flagship list pricing runs at $3.84 on the same model, $1.28 on claude-haiku-4-5, and under a quarter on deepseek-v4-flash. Budget controls stop disasters; routing and unit rates decide what a normal month costs. Most teams end up with a two-model setup, a budget tier as the daily driver for mechanical jobs and a mid or flagship tier gated behind an explicit label.
- Cap turns hard and low. If the job cannot fix the tests in 20 to 25 turns, more turns rarely save it. Fail the run, post the transcript on the PR, and page a human.
- One key per pipeline, none of them personal. Named keys with individual spend ceilings turn the invoice into a per-workflow report and make revocation surgical instead of company-wide.
- Set timeout-minutes and a concurrency group with cancel-in-progress. Force-push storms and label spam should replace in-flight runs, not stack new ones behind them.
- Turn CI auto-retry off for agent jobs. Retrying a deterministic failure re-bills the entire run for the same result; let the job fail once and surface.
- Shrink what enters the window. Shallow-clone, point the prompt at the failing test files by name, and keep lockfiles, build output, and vendored code out of the agent's reach.
- Route by job type. Commit messages, changelog entries, and lint fixes do not need a flagship model; reserve the expensive tier for jobs a human explicitly labels.
- Cut the unit price underneath the caps. The same turn cap protects a smaller number when the per-token rate is lower. One option is APIsRouter, an OpenAI-compatible gateway with pay-as-you-go billing and no subscription: global models priced 20% below official list, Chinese models below their official rates, and a first top-up that adds +100% balance.
| Model ID | In / out $ per 1M | Worked profile per run | Fits |
|---|---|---|---|
| claude-sonnet-4-6 | $2.40 / $12.00 | ~$3.84 | Human-labeled hard jobs |
| claude-haiku-4-5 | $0.80 / $4.00 | ~$1.28 | Default test-fixing driver |
| gpt-5.4-mini | $0.60 / $3.60 | ~$0.97 | PR summaries, review notes |
| glm-5 | $0.514 / $2.314 | ~$0.82 | Routine edits and refactors |
| deepseek-v4-pro | $0.3915 / $0.783 | ~$0.60 | Lint fixes, codemods |
| deepseek-v4-flash | $0.126 / $0.252 | ~$0.19 | Commit messages, triage |
Config: a capped agent job, end to end.
The workflow below wires all three layers into one job: a turn cap on the agent invocation, a timeout and a concurrency group on the job, and a dedicated key injected from repository secrets. The base URL is a single environment variable, so where the tokens are billed is a configuration choice rather than a code change, and the model is pinned explicitly so a CLI upgrade cannot change the unit price without a diff in this file. Before any pipeline depends on the key, smoke-test it with the cheapest model in the catalog. The curl below costs a fraction of a cent and verifies the endpoint, the key, and the model ID in one shot. Put it in the job as a first step if you want key failures to surface as a fast, cheap error instead of a 15-minute timeout:
name: agent-fix
on:
pull_request:
types: [labeled]
concurrency:
group: agent-fix-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
fix-tests:
if: github.event.label.name == 'agent-fix'
runs-on: ubuntu-latest
timeout-minutes: 15
env:
ANTHROPIC_BASE_URL: https://api.apisrouter.com
ANTHROPIC_AUTH_TOKEN: ${{ secrets.AGENT_FIX_KEY }}
ANTHROPIC_MODEL: claude-haiku-4-5
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- run: npm ci
- name: Run the agent with a hard turn cap
run: |
npx -y @anthropic-ai/claude-code -p \
"Run npm test, fix only the failing tests, do not touch unrelated files." \
--max-turns 25 --permission-mode acceptEditsFAQ
How do I stop a coding agent from looping forever in CI?
Stack three caps. Put a turn limit on the agent invocation (for example --max-turns 25 in Claude Code headless mode), set timeout-minutes plus a cancel-in-progress concurrency group on the CI job, and give the pipeline its own API key with a spend ceiling. The turn cap catches loops, the timeout catches hangs, and the key cap catches whatever the first two miss.
How much does a coding agent run in CI cost?
It scales with the context window, not the prompt length. A test-fixing run of about 25 model calls on a mid-size repo moves roughly 1.5M input tokens. At official list rates that prices between about $0.22 on a budget model and $4.80 on a flagship per run, and monthly cost is that figure multiplied by however many PRs trigger the job.
Should CI agents share an API key with developers?
No. Give every pipeline its own named key with its own spend cap. Shared keys make the invoice unattributable, force a company-wide rotation when anything leaks, and let one runaway workflow exhaust the balance every other consumer depends on. Per-pipeline keys turn the bill into a per-workflow report.
Does prompt caching make CI agent runs cheaper?
Less than it helps interactive work. Provider prompt caches are short-lived and keyed to an exact prefix, so runs spaced hours apart in fresh containers start cold and pay full input rates while each run rebuilds its own cache. Within a single run the repeated prefix does cache, which is one more argument for fewer, longer, capped runs over many small ones.
Does a turn cap limit token spend directly?
No. A turn cap limits how many model calls a run can make, but each call bills the entire current window, so 25 turns on a bloated 200K-token window still moves millions of input tokens. Pair the turn cap with a small window: shallow clones, prompts scoped to the failing files, and no build artifacts in the repo the agent can read.
What is the cheapest way to run coding agents in CI?
Cap every run, route mechanical jobs to budget models, and lower the per-token rate itself. APIsRouter is an OpenAI-compatible gateway with pay-as-you-go billing and no subscription: global models are priced 20% below official list, Chinese models sit below their official rates, the first top-up adds +100% balance, and the /topup checkout takes payment first and emails the key.