LLM cost tracking and budget enforcement. Zero config — with budget(max_usd=1.00): run_agent(). Works with LangGraph, CrewAI, raw OpenAI/Anthropic.
Project description
shekel
LLM cost tracking and budget enforcement for Python. One line. Zero config.
with budget(max_usd=1.00):
run_my_agent() # raises BudgetExceededError if spend exceeds $1.00
I spent $47 debugging a LangGraph retry loop. The agent kept failing, LangGraph kept retrying, and OpenAI kept charging — all while I slept. I built shekel so you don't have to learn that lesson yourself.
Install
pip install shekel[openai] # OpenAI
pip install shekel[anthropic] # Anthropic
pip install shekel[all] # Both
pip install shekel[all-models] # Both + tokencost (400+ model pricing)
pip install shekel[cli] # CLI tools (shekel estimate, shekel models)
Usage
from shekel import budget, BudgetExceededError
# Enforce a hard cap
try:
with budget(max_usd=1.00, warn_at=0.8) as b:
run_my_agent()
print(f"Spent ${b.spent:.4f}")
except BudgetExceededError as e:
print(e)
# Fall back to a cheaper model instead of raising
with budget(max_usd=0.50, fallback="gpt-4o-mini") as b:
run_my_agent()
# Decorator
from shekel import with_budget
@with_budget(max_usd=0.10)
def call_llm():
...
# Track spend without enforcing a limit
with budget() as b:
run_my_agent()
print(f"Cost: ${b.spent:.4f}")
# Persistent budget across multiple runs
session = budget(max_usd=5.00, persistent=True)
with session:
run_step_1()
with session:
run_step_2()
print(f"Session total: ${session.spent:.4f}")
# Async
async with budget(max_usd=1.00) as b:
await run_my_async_agent()
# Spend summary
with budget(max_usd=2.00) as b:
run_my_agent()
print(b.summary())
Works with LangGraph, CrewAI, AutoGen, LlamaIndex, Haystack, and any framework that calls OpenAI or Anthropic under the hood. See examples/ for runnable demos.
CLI
pip install shekel[cli]
# Estimate cost before writing any code
shekel estimate --model gpt-4o --input-tokens 1000 --output-tokens 500
# Model: gpt-4o
# Input tokens: 1,000
# Output tokens: 500
# Estimated cost: $0.007500
# List all bundled models with pricing
shekel models
shekel models --provider openai
shekel models --provider anthropic
API reference
budget(...) / with_budget(...)
| Parameter | Type | Default | Description |
|---|---|---|---|
max_usd |
float | None |
None |
Hard spend cap in USD. None = track only. |
warn_at |
float | None |
None |
Fraction of limit (0.0–1.0) at which to warn. |
on_exceed |
Callable | None |
None |
Callback at warn_at threshold. Receives (spent, limit). |
price_per_1k_tokens |
dict | None |
None |
Override pricing: {"input": 0.001, "output": 0.003}. |
fallback |
str | None |
None |
Model to switch to when max_usd is hit. Same provider only. |
on_fallback |
Callable | None |
None |
Callback on fallback switch. Receives (spent, limit, fallback_model). |
hard_cap |
float | None |
max_usd * 2 |
Absolute ceiling when fallback is active. |
persistent |
bool |
False |
Accumulate spend across multiple with blocks. |
Properties
| Property | Type | Description |
|---|---|---|
b.spent |
float |
Total USD spent. |
b.remaining |
float | None |
USD remaining, or None in track-only mode. |
b.limit |
float | None |
Configured max_usd. |
b.model_switched |
bool |
True if fallback was activated. |
b.switched_at_usd |
float | None |
Spend level when fallback triggered. |
b.fallback_spent |
float |
Cost on the fallback model. |
BudgetExceededError
| Attribute | Description |
|---|---|
e.spent |
Total spend when limit was hit. |
e.limit |
The configured max_usd. |
e.model |
Model that triggered the error. |
e.tokens |
{"input": N, "output": N} from the last call. |
Supported models
| Model | Input / 1k | Output / 1k |
|---|---|---|
| gpt-4o | $0.00250 | $0.01000 |
| gpt-4o-mini | $0.000150 | $0.000600 |
| o1 | $0.01500 | $0.06000 |
| o1-mini | $0.00300 | $0.01200 |
| gpt-3.5-turbo | $0.000500 | $0.001500 |
| claude-3-5-sonnet-20241022 | $0.00300 | $0.01500 |
| claude-3-haiku-20240307 | $0.000250 | $0.001250 |
| claude-3-opus-20240229 | $0.01500 | $0.07500 |
| gemini-1.5-flash | $0.0000750 | $0.000300 |
| gemini-1.5-pro | $0.00125 | $0.00500 |
Versioned model names resolve automatically — gpt-4o-2024-08-06 maps to gpt-4o, gpt-4o-mini-2024-07-18 maps to gpt-4o-mini.
For unlisted models: pass price_per_1k_tokens or install shekel[all-models] for 400+ models via tokencost.
How it works
- Monkey-patching — wraps
openai.ChatCompletions.createandanthropic.Messages.createon context entry; restores originals on exit. - ContextVar isolation — each
budget()stores its counter in aContextVar; concurrent agents never share state. - Ref-counted patching — nested contexts patch only once.
- Zero config — no API keys, no external services.
Contributing
See CONTRIBUTING.md.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shekel-0.2.2.tar.gz.
File metadata
- Download URL: shekel-0.2.2.tar.gz
- Upload date:
- Size: 31.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19c9f612c3588a4a44a3494ba97585eeaf48b77615268a5b871356028294b50c
|
|
| MD5 |
d0f863be2908ef6637ed67bc55ff2adf
|
|
| BLAKE2b-256 |
fc976bf73533e1d4dac0a6b2b18d73acf56aa7a893d7127a8aa88d137e0ab9c6
|
Provenance
The following attestation bundles were made for shekel-0.2.2.tar.gz:
Publisher:
publish.yml on arieradle/shekel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shekel-0.2.2.tar.gz -
Subject digest:
19c9f612c3588a4a44a3494ba97585eeaf48b77615268a5b871356028294b50c - Sigstore transparency entry: 1065961527
- Sigstore integration time:
-
Permalink:
arieradle/shekel@f9f2345cd2744de7fe2bb53bb880360ab50635b0 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/arieradle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f9f2345cd2744de7fe2bb53bb880360ab50635b0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file shekel-0.2.2-py3-none-any.whl.
File metadata
- Download URL: shekel-0.2.2-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fbef6378e5778aeb97e9c5ba469a54cfe2fc6051e0fc7cf123328e820b37eaa
|
|
| MD5 |
ed8887de4c7ec24fbf47b49a5d16508a
|
|
| BLAKE2b-256 |
7f5c7e6b48dbb4ba4ca6cfd409e8a21eeca667c27c6a6471c88001e5bead5a70
|
Provenance
The following attestation bundles were made for shekel-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on arieradle/shekel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shekel-0.2.2-py3-none-any.whl -
Subject digest:
9fbef6378e5778aeb97e9c5ba469a54cfe2fc6051e0fc7cf123328e820b37eaa - Sigstore transparency entry: 1065961528
- Sigstore integration time:
-
Permalink:
arieradle/shekel@f9f2345cd2744de7fe2bb53bb880360ab50635b0 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/arieradle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f9f2345cd2744de7fe2bb53bb880360ab50635b0 -
Trigger Event:
push
-
Statement type: