runbound
Runbound is an execution control plane for autonomous AI: it decides what an agent may consume, how far it may run, and what it may do, and enforces those boundaries across the fleet. The open-source SDK is the runtime for that — free forever, no account required.
Add one initialization line. No agent rewrites, decorators, or policy code required. runbound counts, times, hashes and prices what an agent does; it never reads a prompt or a reply, puts no gateway in your hot path, and never speaks to your users — when it refuses something, it hands control straight back to your own code.
Install
pip install runbound
See the whole core loop in thirty seconds — no clone, no key, no network:
python -m runbound.demo
There are no runtime dependencies — stdlib only. LangChain support is the one
extra: pip install "runbound[langchain]".
Quick start
import runbound
runbound.init(budget_usd=5.0, max_steps=50, on_anomaly="raise")
runbound.record_call("gpt-4o", tokens_in=1_000, tokens_out=500) # guarded; needs no provider package
With a provider SDK (pip install openai), runbound.init() wraps the client
for you, automatic for a client built after init():
from openai import OpenAI
client = OpenAI() # wrapped: every call below is counted, priced and limited
Give it a user key when a limit should follow that person across requests instead of resetting every call — a run budget that starts fresh on every entry, checked side by side with the key's own daily total:
runbound.init(run_budget_usd=1.0, budget_usd=20.0, budget_window="day")
with runbound.session(f"user:{user_id}"):
client.chat.completions.create(...) # refused by whichever budget is tighter
Decorate the two or three tools that matter and runbound refuses a call before its body runs:
@runbound.tool(max_calls=1)
def issue_refund(user: str, amount: float): ...
The five-minute version — wiring every limit, checking what's actually guarded, and handling a refusal — is in Getting started, which also shows the graded loop and a runaway, start to finish.
Not a Python agent? Which door covers the gateway (change one base URL) and the action API (one HTTP call before an action).
Three levels of protection
Level 1: runtime limits. Two lines. runbound.init() wraps the OpenAI
and Anthropic clients for you — wrap is automatic for a client built after
init(), or call runbound.wrap(client) yourself for one built earlier or
shaped like a gateway. From then on every model call is counted, timed and
priced with no network call and no account:
- dollar limits
- token limits
- per-call caps
- run and event limits
- run timeouts
- error storms
- provider circuits
- loop detection from the tool calls a model asks for
- spike detection
- local safe mode
- local enforcement
Two honest limits, in the same breath: this level only sees what a wrapped
client or @runbound.tool reports it, so an action's own body is only
governed once that tool carries @runbound.tool, and a raw or unsupported
provider path is not guarded at all — runbound.coverage() is how you find
out which one you're in.
Level 2: identity limits. One line per unit of work,
runbound.session(key) — the key is any id you already have: a run, a job,
a tenant, a customer. Every limit above becomes per key instead of per
process, so one caller's run stops without touching anyone else's.
Level 3: capability limits. Decorate the tools that are irreversible or
reach the outside world with @runbound.tool, state a rule (deny, a call
cap, an approval, a predicate over the arguments), and the call is refused
before its body runs. Narrowing a run's posture — restricted,
read_only, stopped — denies a whole class of actions at once without
ending the run.
When Runbound refuses
There is no fake success. A refusal is a typed ExecutionRefused — never a
swallowed error, never an answer made up to look normal — carrying reason,
retryable and provider_called, so your own code decides what happens
next: retry, queue, fall back, or tell the caller. See
Handling refusals.
Content-independent enforcement
Every decision above is made from counts, hashes, timings and prices — never from reading what an agent said or what a model answered:
- Prompts and model replies are never read, stored, or sent.
- Tool arguments are sha256-hashed before storage, salted per process; raw arguments never leave your process.
- A session key reaches a connected plane as a hash, never in the clear. That hash is unsalted, so the same caller is recognisable across your workers.
- No network calls except the ones you configure — no telemetry, no
phone-home, nothing sent anywhere with no
tokenset.
Full accounting: What the SDK actually sees and Boundaries — what runbound deliberately does not do, and what to use instead.
Open-source runtime. Cloud control plane.
Everything above is free forever, in the open-source SDK, configurable in code, with no account. A connected control plane adds what one process cannot give itself: coordination across every worker in your fleet, state that survives a restart, central policy and posture, and durable evidence. See Free SDK, connected plane.
Documentation
The manual lives in docs/; it is also published, with
executed snippets, at runbound.co/docs.
- Getting started — install, the core loop, and checking what is actually guarded.
- Concepts — the three levels, boundaries, and the free SDK / connected plane split.
- Guides — keyed runs, action policy, handling refusals, async and streaming.
- Reference — every configuration field, the detectors, and the guarantees.
Roadmap is what is shipped, what is still open, and what is explicitly out of scope.
Getting help
Something not working, or a question? Open an issue at github.com/runboundai/runbound/issues, or email runboundai@gmail.com if it is not something you can post in public.
import runbound
print(runbound.__version__)
print(runbound.coverage()) # after init() and your first guarded call
coverage() shows at a glance whether runbound can see your traffic at all —
the most common cause of "it isn't catching anything." Never paste an API
key, a control-plane token, a prompt, a reply, or a real session key into an
issue. Security issues go to email, not to an issue — see
SECURITY.md.
License
MIT — see LICENSE. Release history is in CHANGELOG.md. The promises above, stated as bounds with the tests that assert them, are in INVARIANTS.md.
Metadata
Release files for runbound 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| runbound-0.10.0.tar.gz | 929.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| runbound-0.10.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / runbound-0.10.0.tar.gz
| Download URL | runbound-0.10.0.tar.gz |
|---|---|
| Size | 929.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c28104cd0655aca14557968362e5eb24b5fd05d4b9ea25e640a290000244f5ec
|
|
BLAKE2b-256 checksum How to use checksums |
5b3298b1eb494becb6329b4bc18de883bd8c67dcad629523acb1b71c703423eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / runbound-0.10.0-py3-none-any.whl
| Download URL | runbound-0.10.0-py3-none-any.whl |
|---|---|
| Size | 363.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ee0b1fed3e44e4afcd2891afa23043cb86386b8267ecfea641d626bd99de0ac
|
|
BLAKE2b-256 checksum How to use checksums |
f37b0c33eaaddb6b62475d9426a6343402587c0bba0efb71a88181f877ac43e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log