Each coding agent has its own meter. Claude Code reports dollars and can stop itself with --max-budget-usd. Codex and Antigravity CLI report only tokens and have no budget flag, so a script that mixes them can burn through every budget overnight. This loadout puts one standard-library guard in front of every headless run. It refuses the run once the shared daily or monthly cap or the run count is reached, and gives Claude Code a budget no bigger than what is left. It prices Codex and Antigravity tokens from prices you set, and writes one ledger line per run. It also lists the provider-side limits that hold when something bypasses the guard, including keeping Antigravity's useG1Credits off. The verifier drives the guard with stubs that print each agent's documented JSON and checks the arithmetic and the refusal.
What's in it
- One daily, monthly and run-count cap across three agents
- Claude Code: --max-budget-usd shrinks to what is left; total_cost_usd recorded
- Codex and Antigravity: documented token usage priced from your own price table
- Exit 3 means stop the loop; agents never raise caps or buy credits
- Provider-side limits listed, including Antigravity's useG1Credits
You'll need
- Tools:
python3
Verification
| Check | Result | What we found |
|---|---|---|
| Listinglisting.yaml matches the schema and declares every file in the folder. | Pass | Schema valid; 7 files declared, none missing or extra
|
| Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. | Pass | All 7 files parse; front matter valid |
| AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. | Pass | CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
|
| Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. | Pass | Correct paths for all 6 agents; layouts re-discovered
|
| MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. | Not applicable | No MCP servers in this loadout |
| Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. | Pass | Clean: no credentials, risky shell or hidden text
|
| ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. | Pass | 2 references between files resolve for every agent |
| Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. | Pass | 7 files, 15.8 KB total; largest skills/spend-cap/scripts/spend_guard.py 8.3 KB
|
| LicenceA recognised SPDX licence, with the licence text available. | Pass | MIT, by Agent Loadout; text in the repository LICENSE |
| Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. | Pass | The spend-cap skill's guard runs stubbed Claude Code, Codex and Antigravity CLI commands that print each agent's documented JSON. It reads Claude's dollar cost, prices Codex and Antigravity tokens from caps.json, shrinks Claude's --max-budget-usd to what is left, refuses the run past the daily cap,
|
What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.
Install
Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.
Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/CLAUDE.md curl -fsSL --create-dirs -o .claude/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .claude/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .claude/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .claude/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
CLAUDE.md | CLAUDE.md |
skills/spend-cap/SKILL.md | .claude/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .claude/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .claude/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .claude/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Codex CLI reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/spend-cap/SKILL.md | .agents/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .agents/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .agents/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .agents/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Cursor reads AGENTS.md + .cursor/rules/*.mdc and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/spend-cap/SKILL.md | .agents/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .agents/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .agents/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .agents/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Gemini CLI reads GEMINI.md (imports AGENTS.md with @./AGENTS.md) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o GEMINI.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/GEMINI.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
GEMINI.md | GEMINI.md |
skills/spend-cap/SKILL.md | .agents/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .agents/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .agents/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .agents/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Antigravity CLI reads AGENTS.md (read natively; GEMINI.md is also read) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/spend-cap/SKILL.md | .agents/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .agents/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .agents/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .agents/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
GitHub Copilot reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/SKILL.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/SKILL.md curl -fsSL --create-dirs -o .agents/skills/spend-cap/scripts/spend_guard.py https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/scripts/spend_guard.py curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/caps.example.json https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/caps.example.json curl -fsSL --create-dirs -o .agents/skills/spend-cap/references/provider-limits.md https://loadout.jnw-it.com/raw/agent-spend-cap/1.0.0/skills/spend-cap/references/provider-limits.md
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/spend-cap/SKILL.md | .agents/skills/spend-cap/SKILL.md |
skills/spend-cap/scripts/spend_guard.py | .agents/skills/spend-cap/scripts/spend_guard.py |
skills/spend-cap/references/caps.example.json | .agents/skills/spend-cap/references/caps.example.json |
skills/spend-cap/references/provider-limits.md | .agents/skills/spend-cap/references/provider-limits.md |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Files
Rules AGENTS.md Rules for running coding agents headless under one shared spend cap. 21 lines
# AGENTS.md: shared spend cap for coding agents
This repository runs coding agents headless (scripts, loops, CI): Claude Code, Codex and Antigravity CLI. Every
headless run goes through one spend guard with a shared daily and monthly cap. The user sets the caps; agents never
change them.
## Rules
- Run headless agents only through the `spend-cap` skill's guard:
`python3 spend_guard.py run --agent <claude|codex|agy> --task <name> -- <agent command>`.
- Use the machine-readable output each agent documents (`--output-format json` for Claude Code and Antigravity,
`--json` for Codex) so the guard can read cost or tokens.
- Exit 3 from the guard means a cap is reached. Stop, report the totals from `spend_guard.py report`, and wait for
the user. Do not retry, and do not call the agent directly instead.
- Never raise caps, buy credits, change plans, turn on overage or usage credits, or set Antigravity's
`useG1Credits` to `true`.
- Keep each run small: one task, scoped files, a clear stop condition. Prefer one agent per task to fan-outs.
- Report spend as an estimate, and say that interactive sessions are not in the ledger.
## Done means
- The ledger has a line for every headless run, and `spend_guard.py report` is under the caps. Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 11 lines
# CLAUDE.md
@AGENTS.md
## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `spend-cap`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From the Agent Loadout "One spend cap across Claude Code, Codex and Antigravity" v1.0.0 — https://loadout.jnw-it.com/loadouts/agent-spend-cap/ --> Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 11 lines
# GEMINI.md
@./AGENTS.md
## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `spend-cap`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From the Agent Loadout "One spend cap across Claude Code, Codex and Antigravity" v1.0.0 — https://loadout.jnw-it.com/loadouts/agent-spend-cap/ --> Skill skills/spend-cap/SKILL.md Set caps, run agents through the guard, read the ledger. 57 lines
---
name: spend-cap
description: Put one daily and monthly spend cap across headless Claude Code, Codex and Antigravity CLI runs, with a per-run budget and a ledger, and set the provider-side limits that are the real hard stop. Use when scripting agent runs, running agents in loops or CI, or when someone asks what the agents cost.
---
# One spend cap across agents
Each agent has its own meter. Claude Code reports dollars (`total_cost_usd` in `--output-format json`) and can stop
itself (`--max-budget-usd`). Codex (`codex exec --json`) and Antigravity (`agy -p --output-format json`) report
tokens only, and neither has a budget flag. A loop that mixes them can spend all three budgets before anyone looks.
`scripts/spend_guard.py` puts one ledger and one cap in front of all of them.
## Set up
```bash
mkdir -p .agent-spend
cp <this skill>/references/caps.example.json .agent-spend/caps.json
echo ".agent-spend/" >> .gitignore
```
Edit `caps.json` with the user: `daily_usd`, `monthly_usd`, `per_run_usd` and `max_runs_per_day`. Add `prices` for
Codex and Antigravity in USD per million tokens, taken from the provider's current price page for the model in use.
Never guess a price. With zero prices those agents count towards `max_runs_per_day` only.
## Run every headless agent through it
```bash
python3 spend_guard.py run --agent claude --task fix-tests -- claude -p "Fix the failing tests" --output-format json
python3 spend_guard.py run --agent codex --task triage -- codex exec --json "Triage open issues"
python3 spend_guard.py run --agent agy --task docs -- agy -p "Update the README" --output-format json
python3 spend_guard.py report
```
- Before the run it refuses with exit 3 if today's or this month's cap is reached, if what is left is under
`min_run_usd`, or if `max_runs_per_day` is used up. Treat exit 3 as "stop the loop", not "retry".
- For Claude Code it appends `--max-budget-usd` set to the smaller of `per_run_usd` and what is left today, so the
agent stops itself.
- Codex and Antigravity cannot be stopped mid-run. Their cost is estimated from tokens afterwards, and a run can
overshoot by up to one run. Keep `per_run_usd` small and the prompts scoped.
- Exit 4 means no cost or usage was found in the output (wrong flags, or a crash). Look before running again.
- The ledger is `.agent-spend/ledger.jsonl`: one line per run with agent, task, exit code, cost and token usage.
Days and months use the machine's time zone.
## Provider-side limits are the hard stop
The guard only sees runs that go through it. Set the provider's own limit as well, and read
`references/provider-limits.md` for where each one lives. Antigravity's `useG1Credits` setting must stay `false`
unless the user decides to pay for credits after the plan quota runs out.
## Rules
- Never raise a cap, add credits, change a plan or turn on overage billing yourself. Report the refusal and the
ledger totals, and let the user decide.
- Never route around the guard by calling an agent directly in a loop.
- Interactive sessions are outside the ledger. Say so when you report spend.
- Costs here are estimates. The provider's bill is the truth. Skill file skills/spend-cap/scripts/spend_guard.py Shared cap, per-run budget and ledger for three agents. 217 lines
#!/usr/bin/env python3
"""Shared spend cap for headless agent runs (Claude Code, Codex, Antigravity CLI).
spend_guard.py run --agent claude --task fix-tests -- claude -p "..." --output-format json
spend_guard.py run --agent codex --task triage -- codex exec --json "..."
spend_guard.py run --agent agy --task docs -- agy -p "..." --output-format json
spend_guard.py report
Before a run it refuses (exit 3) when today's or this month's spend has reached the cap, or
when what is left is less than one run's budget. For Claude Code it adds --max-budget-usd so
the agent itself stops at the smaller of the per-run cap and what is left. Codex and
Antigravity report tokens, not money, so their cost comes from the prices you set in
caps.json, and they cannot be stopped mid-run: the provider-side limit is the hard stop.
Config: .agent-spend/caps.json (or SPEND_DIR). Ledger: .agent-spend/ledger.jsonl.
Standard library only. Costs are estimates; the provider's bill is the truth.
"""
import argparse
import datetime as dt
import fcntl
import json
import os
import subprocess
import sys
from pathlib import Path
SPEND_DIR = Path(os.environ.get("SPEND_DIR", ".agent-spend"))
CAPS = SPEND_DIR / "caps.json"
LEDGER = SPEND_DIR / "ledger.jsonl"
REFUSED = 3
def load_caps():
if not CAPS.exists():
sys.exit(f"spend_guard: {CAPS} not found; copy the spend-cap skill's caps.example.json there")
caps = json.loads(CAPS.read_text())
for key in ("daily_usd", "monthly_usd", "per_run_usd"):
if not isinstance(caps.get(key), (int, float)) or caps[key] <= 0:
sys.exit(f"spend_guard: caps.json needs a positive {key}")
return caps
def now():
return dt.datetime.now().astimezone()
def totals(at):
"""Spend today, spend this month and runs today, in the local time zone."""
day = month = 0.0
runs = 0
if LEDGER.exists():
for line in LEDGER.read_text().splitlines():
if not line.strip():
continue
rec = json.loads(line)
ts = dt.datetime.fromisoformat(rec["ts"]).astimezone(at.tzinfo)
cost = rec.get("cost_usd") or 0.0
if (ts.year, ts.month) == (at.year, at.month):
month += cost
if ts.date() == at.date():
day += cost
runs += 1
return round(day, 4), round(month, 4), runs
def price(caps, agent, usage):
p = (caps.get("prices") or {}).get(agent)
if not p:
return None
mtok = 1_000_000
cached = usage.get("cached_input_tokens", usage.get("cache_read_tokens", 0))
fresh_input = max(usage.get("input_tokens", 0) - cached, 0)
output = usage.get("output_tokens", 0) + usage.get("reasoning_output_tokens", usage.get("thinking_tokens", 0))
cost = (
fresh_input * p["input_per_mtok"]
+ cached * p.get("cached_input_per_mtok", p["input_per_mtok"])
+ output * p["output_per_mtok"]
) / mtok
return round(cost, 6)
def parse(agent, stdout):
"""Return (cost_usd or None, usage dict) from the agent's documented JSON output."""
usage, cost = {}, None
lines = [ln for ln in stdout.splitlines() if ln.strip().startswith("{")]
if agent == "claude":
for ln in reversed(lines):
obj = json.loads(ln)
if "total_cost_usd" in obj:
return float(obj["total_cost_usd"]), obj.get("usage", {})
elif agent == "codex":
for ln in lines:
obj = json.loads(ln)
if obj.get("type") == "turn.completed":
for k, v in obj.get("usage", {}).items():
usage[k] = usage.get(k, 0) + v
elif agent == "agy":
for ln in reversed(lines):
obj = json.loads(ln)
result = obj.get("result", obj) if obj.get("event") in (None, "result") else None
if result and "usage" in result:
usage = result["usage"]
break
return cost, usage
def required_output_flags(agent, cmd):
if agent == "claude" and "--output-format" not in cmd:
return "add --output-format json (or stream-json) so the cost can be read"
if agent == "codex" and "--json" not in cmd:
return "add --json so token usage can be read"
if agent == "agy" and "--output-format" not in cmd:
return "add --output-format json (or stream-json) so token usage can be read"
return None
def run(args):
caps = load_caps()
cmd = args.cmd[1:] if args.cmd and args.cmd[0] == "--" else args.cmd
if not cmd:
sys.exit("spend_guard: give the agent command after --")
problem = required_output_flags(args.agent, cmd)
if problem:
sys.exit(f"spend_guard: {problem}")
if args.agent in ("codex", "agy") and not (caps.get("prices") or {}).get(args.agent):
sys.exit(f"spend_guard: no prices for {args.agent} in caps.json, so its spend cannot be capped")
SPEND_DIR.mkdir(parents=True, exist_ok=True)
lock = open(SPEND_DIR / ".lock", "w")
fcntl.flock(lock, fcntl.LOCK_EX)
at = now()
day, month, runs = totals(at)
left = min(caps["daily_usd"] - day, caps["monthly_usd"] - month)
budget = round(min(caps["per_run_usd"], left), 2)
max_runs = caps.get("max_runs_per_day")
if max_runs is not None and runs >= max_runs:
print(f"spend_guard: REFUSED {args.agent}/{args.task}: {runs} runs today, cap {max_runs}", file=sys.stderr)
return REFUSED
if left <= 0 or budget < caps.get("min_run_usd", 0.05):
print(
f"spend_guard: REFUSED {args.agent}/{args.task}: today ${day:.2f} of ${caps['daily_usd']:.2f}, "
f"month ${month:.2f} of ${caps['monthly_usd']:.2f}",
file=sys.stderr,
)
return REFUSED
if args.agent == "claude" and "--max-budget-usd" not in cmd:
cmd = cmd + ["--max-budget-usd", f"{budget:.2f}"]
print(f"spend_guard: {args.agent}/{args.task} budget ${budget:.2f} (left today ${left:.2f})", file=sys.stderr)
fcntl.flock(lock, fcntl.LOCK_UN)
proc = subprocess.run(cmd, stdout=subprocess.PIPE, text=True)
sys.stdout.write(proc.stdout)
cost, usage = parse(args.agent, proc.stdout)
if cost is None:
cost = price(caps, args.agent, usage)
rec = {
"ts": now().isoformat(timespec="seconds"),
"agent": args.agent,
"task": args.task,
"exit": proc.returncode,
"cost_usd": cost,
"estimated_from_tokens": args.agent != "claude",
"usage": usage,
}
if cost is None:
rec["note"] = "no cost or usage found in the output; recorded as unknown"
fcntl.flock(lock, fcntl.LOCK_EX)
with LEDGER.open("a") as f:
f.write(json.dumps(rec) + "\n")
fcntl.flock(lock, fcntl.LOCK_UN)
shown = "unknown" if cost is None else f"${cost:.4f}"
print(f"spend_guard: recorded {args.agent}/{args.task} {shown}", file=sys.stderr)
if cost is None:
return 4
if cost > budget:
print(f"spend_guard: WARNING run cost {shown} exceeded its ${budget:.2f} budget", file=sys.stderr)
return proc.returncode
def report(_args):
caps = load_caps()
at = now()
day, month, runs = totals(at)
by_agent = {}
if LEDGER.exists():
for line in LEDGER.read_text().splitlines():
if line.strip():
rec = json.loads(line)
ts = dt.datetime.fromisoformat(rec["ts"]).astimezone(at.tzinfo)
if (ts.year, ts.month) == (at.year, at.month):
a = by_agent.setdefault(rec["agent"], [0, 0.0])
a[0] += 1
a[1] += rec.get("cost_usd") or 0.0
print(f"today ${day:.2f} of ${caps['daily_usd']:.2f} ({runs} run(s))")
print(f"month ${month:.2f} of ${caps['monthly_usd']:.2f}")
for agent, (runs, cost) in sorted(by_agent.items()):
print(f"{agent:<7}{runs} run(s) ${cost:.2f} this month")
return 0
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
sub = ap.add_subparsers(dest="command", required=True)
r = sub.add_parser("run")
r.add_argument("--agent", required=True, choices=["claude", "codex", "agy"])
r.add_argument("--task", required=True)
r.add_argument("cmd", nargs=argparse.REMAINDER)
r.set_defaults(func=run)
sub.add_parser("report").set_defaults(func=report)
args = ap.parse_args()
sys.exit(args.func(args))
if __name__ == "__main__":
main() Skill file skills/spend-cap/references/caps.example.json Caps and price table to copy into .agent-spend/. 13 lines
{
"daily_usd": 5.0,
"monthly_usd": 60.0,
"per_run_usd": 1.0,
"min_run_usd": 0.05,
"max_runs_per_day": 40,
"prices": {
"codex": { "input_per_mtok": 0.0, "cached_input_per_mtok": 0.0, "output_per_mtok": 0.0 },
"agy": { "input_per_mtok": 0.0, "cached_input_per_mtok": 0.0, "output_per_mtok": 0.0 }
},
"_note": "Fill prices from your provider's current price page for the model you run (USD per million tokens). Zero prices mean those agents count towards max_runs_per_day but not money."
} Skill file skills/spend-cap/references/provider-limits.md Where each provider's own limit lives. 37 lines
# Provider-side spend limits
The guard is a soft cap in front of headless runs. These are the limits that hold even when something bypasses it.
Check each against the provider's current docs before relying on it.
## Claude Code
- Per run: `claude -p ... --max-budget-usd <amount>` (print mode only). With `--output-format json` the result
includes `total_cost_usd`, a client-side estimate.
- Claude Console (API key): set workspace spend limits on the "Claude Code" workspace. Usage and cost reporting is in
the Console.
- Pro and Max with usage credits: set a monthly spend limit under Settings > Usage on claude.ai. `/usage` shows spend
against it.
- Team and Enterprise: admins set spend limits for the organisation, groups or individual members.
- Amazon Bedrock, Google Cloud or Microsoft Foundry: use that cloud's budget controls.
Source: https://code.claude.com/docs/en/costs and https://code.claude.com/docs/en/headless
## Codex
- `codex exec --json` emits `turn.completed` events with `usage` (`input_tokens`, `cached_input_tokens`,
`output_tokens`, `reasoning_output_tokens`). There is no money figure and no budget flag.
- Cap spend through your OpenAI plan or API project settings, and check which of them your account actually enforces.
Source: https://developers.openai.com/codex/noninteractive and the Codex SDK event types
(https://github.com/openai/codex/blob/main/sdk/typescript/src/events.ts)
## Antigravity CLI
- `agy -p ... --output-format json` returns `usage` (`input_tokens`, `output_tokens`, `thinking_tokens`,
`cache_read_tokens`, `total_tokens`). There is no money figure and no budget flag. `--print-timeout` bounds time,
not tokens.
- `useG1Credits` (default `false`) lets the CLI spend personal AI credits once plan quotas are exhausted. Keep it
`false`. `/credits` shows the remaining credits and `/usage` the model quota.
Source: https://antigravity.google/docs/cli/headless and https://antigravity.google/docs/cli/reference All files: source zip · Licence MIT · By Agent Loadout · First listed
Credits
Public work that inspired this loadout. The wording here is our own; follow the links for the originals.
Installing and testing
How do I install One spend cap across Claude Code, Codex and Antigravity in Claude Code?
From your project root, put AGENTS.md, CLAUDE.md, skills/spend-cap/SKILL.md at .claude/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .claude/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .claude/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .claude/skills/spend-cap/references/provider-limits.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install One spend cap across Claude Code, Codex and Antigravity in Codex CLI?
From your project root, put AGENTS.md, skills/spend-cap/SKILL.md at .agents/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .agents/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .agents/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .agents/skills/spend-cap/references/provider-limits.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install One spend cap across Claude Code, Codex and Antigravity in Cursor?
From your project root, put AGENTS.md, skills/spend-cap/SKILL.md at .agents/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .agents/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .agents/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .agents/skills/spend-cap/references/provider-limits.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install One spend cap across Claude Code, Codex and Antigravity in Gemini CLI?
From your project root, put AGENTS.md, GEMINI.md, skills/spend-cap/SKILL.md at .agents/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .agents/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .agents/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .agents/skills/spend-cap/references/provider-limits.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install One spend cap across Claude Code, Codex and Antigravity in Antigravity CLI?
From your project root, put AGENTS.md, skills/spend-cap/SKILL.md at .agents/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .agents/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .agents/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .agents/skills/spend-cap/references/provider-limits.md. The "Antigravity CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install One spend cap across Claude Code, Codex and Antigravity in GitHub Copilot?
From your project root, put AGENTS.md, skills/spend-cap/SKILL.md at .agents/skills/spend-cap/SKILL.md, skills/spend-cap/scripts/spend_guard.py at .agents/skills/spend-cap/scripts/spend_guard.py, skills/spend-cap/references/caps.example.json at .agents/skills/spend-cap/references/caps.example.json, skills/spend-cap/references/provider-limits.md at .agents/skills/spend-cap/references/provider-limits.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/agent-spend-cap/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
Has One spend cap across Claude Code, Codex and Antigravity been tested?
It passed the Level 1 automated install checks on 2026-10-17: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.
More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.