Skip to main content

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 token set.

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)

Source distribution for runbound 0.10.0
File Size Uploaded
runbound-0.10.0.tar.gz 929.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for runbound 0.10.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page