Hard LLM spend enforcement for Python — pre-call budget checks and per-user metering.
Project description
noburn
Hard LLM spend enforcement for Python — pre-call budget checks and per-user metering.
Check a planned LLM call against project-, per-user-, and per-run budget caps before you make it, then record what it actually cost.
Install
pip install noburn
Requires Python ≥ 3.9. No third-party dependencies. Ships type hints (py.typed).
Quick start
import os
from noburn import NoburnGuard
guard = NoburnGuard(
api_key=os.environ["NOBURN_API_KEY"],
project_id=os.environ["NOBURN_PROJECT_ID"],
budget_cap_usd=10.0, # optional local fallback cap
on_error="allow", # "allow" (default, fail-open) | "block" (fail-closed)
)
decision = guard.check(
model="gpt-4o",
estimated_tokens_in=1000,
estimated_tokens_out=300,
end_user_id="user_123", # optional — enforces that user's cap
)
if decision.blocked:
raise RuntimeError(f"Blocked by noburn: {decision.block_reason}")
# ... make your LLM call ...
guard.record(
model="gpt-4o",
tokens_in=980,
tokens_out=290,
cost_usd=0.005,
was_blocked=False,
end_user_id="user_123",
)
record() is fire-and-forget — it returns immediately (delivery happens on a
background daemon thread) and never raises, so it adds no latency to your call
path.
Agent runs
Bound a single agent invocation with its own cap:
run = guard.start_run(budget_cap_usd=0.5)
decision = guard.check(
model="gpt-4o",
estimated_tokens_in=1000,
estimated_tokens_out=300,
run_id=run.run_id,
)
guard.record(model="gpt-4o", tokens_in=980, tokens_out=290,
cost_usd=0.005, was_blocked=False, run_id=run.run_id)
summary = guard.end_run(run.run_id) # EndRunResult(status=..., spend_usd=..., ...)
Behavior
check()never raises exceptNoburnAuthError(bad key). Every call asks the server for an authoritative decision; if the server is unreachable it falls back to a local in-memory check.on_errorcontrols that fallback when nothing local blocks the call:"allow"(default) fails open so a noburn outage never breaks your app;"block"fails closed (block_reason="noburn_unreachable").start_run()raises on network/auth error (NoburnTimeoutErroron timeout) — a run must be registered before you proceed.
Note:
check()/start_run()use blocking HTTP. In async apps, run them in a thread executor (e.g.await asyncio.to_thread(guard.check, ...)).
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 noburn-0.1.0.tar.gz.
File metadata
- Download URL: noburn-0.1.0.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c30dcc65d36b918aa24ed3c298de332f5ecf793cd22c80584b32cb0d0b76105e
|
|
| MD5 |
bdc926ef71cbbb93e66f52f329ae855a
|
|
| BLAKE2b-256 |
4025c99242eaac223ce4aed689de9119a0fa29b288f7f7666ebf02227cd0f40c
|
File details
Details for the file noburn-0.1.0-py3-none-any.whl.
File metadata
- Download URL: noburn-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88e59bf2f4ef4757cf7e1211264edd60af22142beebdbde7d72110911937f516
|
|
| MD5 |
1ae5ec5b9383cf56581d13ad598be46a
|
|
| BLAKE2b-256 |
4184ce65c5b64bfd6c24704f1933441e3fef1658f4f3eefd56329f22368a2403
|