Metadata-Version: 2.4
Name: breakerbox
Version: 1.0.0
Summary: Runtime spend enforcement for AI agents — trip, degrade, and stop, not just alert. Provable ceilings, loop detection, escrow, and security scanning.
Project-URL: Homepage, https://github.com/Amitcoh1/agentbreaker
Author-email: Amit Cohen <amit.cellebrite@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: agents,budget,circuit-breaker,cost,langgraph,llm
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.11
Requires-Dist: jinja2>=3.1
Requires-Dist: langchain-core>=0.3
Requires-Dist: langgraph>=0.2
Requires-Dist: pyyaml>=6
Requires-Dist: tiktoken>=0.7
Provides-Extra: dev
Requires-Dist: hypothesis>=6; extra == 'dev'
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: langchain1
Requires-Dist: langchain>=1; extra == 'langchain1'
Requires-Dist: langgraph>=1; extra == 'langchain1'
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.20; extra == 'otel'
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/brand/logo-dark.svg">
    <img alt="Breakerbox" src="docs/brand/logo-light.svg" width="360">
  </picture>
</p>

<p align="center"><strong>Runtime spend enforcement for AI agents — trip, degrade, and stop, not just alert.</strong></p>

<p align="center">A runaway retry loop that burns <code>$12.63</code> unguarded stops at <code>$0.82</code>.<br>In-process — no proxy, no gateway, no stored keys.</p>

<p align="center"><code>pip install breakerbox</code></p>

<p align="center">
  <a href="https://marketing-coral-eight.vercel.app/"><strong>🔗 Live site</strong></a>&nbsp;·&nbsp;<a href="#the-demo"><strong>The demo&nbsp;↓</strong></a>&nbsp;·&nbsp;<a href="#quickstart"><strong>Quickstart&nbsp;↓</strong></a>
</p>

<p align="center">
  <a href="https://github.com/Amitcoh1/agentbreaker/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Amitcoh1/agentbreaker/actions/workflows/ci.yml/badge.svg"></a>
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-1f2328.svg"></a>
  <img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%2B-1f2328.svg">
  <a href="https://github.com/Amitcoh1/agentbreaker/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/Amitcoh1/agentbreaker?color=b8860b"></a>
</p>

<p align="center">
  <img src="docs/brand/shots/demo.gif" alt="A guarded LangGraph run tripping at $0.82 of a $0.90 budget — next hop blocked, 0 side effects fired" width="820">
</p>

Wrap the compiled LangGraph app you already have in `guard()` and it **enforces** a spend policy
between every step. The one-line dollar cap is the hook — a 33-star side project reinvented that in
~400 lines. The part you can't build in an afternoon is everything else. In the
[bundled demo](#the-demo), a retry loop that burns **$12.63** unguarded stops at **$0.82**.
Enforcement lives *inside* your process — no proxy, no gateway, no server of ours ever sees your
keys or your data. What teams don't self-build:

1. **Enforce, don't just alert — and degrade before you die.** A *provable* worst-case cost ceiling
   *before* the run; semantic loop detection that catches the runaway your stop-condition misses;
   hierarchical budget escrow; a **degradation ladder** that swaps to a cheaper model and narrows
   tools at 80% before a graceful stop at 100%; and **shadow mode** to see what *would* trip before
   you enforce anything. Plus a security suite that scans the flow for embedded creds and audits MCP
   configs — findings you can prove, not just observe.
2. **In-process — nothing to compromise.** No proxy or gateway executes your flows; no provider
   key is ever stored or transmitted. (See [Why no Run button?](#why-no-run-button))
3. **Code you own.** The output is readable, hand-editable Python — scaffolding, not a walled
   garden. Prefer to start visually? A [drag-and-drop builder](#build-it-visually) writes this
   guarded Python for you.

> **Breakerbox** is the product; the Python package is **`breakerbox`** (`pip install
> breakerbox`). The import, CLI, and API names are unchanged.

## Contents

- [Capabilities at a glance](#capabilities-at-a-glance)
- [Quickstart](#quickstart)
- [The demo](#the-demo)
- [What it actually does](#what-it-actually-does)
- [Build it visually](#build-it-visually)
- [Gate cost in CI](#gate-cost-in-ci)
- [More than a budget: cost governance](#more-than-a-budget-cost-governance)
- [Why no Run button?](#why-no-run-button)
- [How it compares](#how-it-compares-facts-only)
- [Notes & limitations](#notes--limitations-read-before-you-rely-on-it)
- [Cloud dashboard (optional)](#cloud-dashboard-optional)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [License](#license)

## Capabilities at a glance

The whole surface on one screen — **[full catalog with maturity labels → `CAPABILITIES.md`](CAPABILITIES.md)**.
One enforcement core, three ways to attach it, and a static half that never runs your agent.

| Area | What you get |
|---|---|
| **Enforce at runtime** — `guard(...)` | Hard `budget_usd` · hierarchical `sub_budgets` · `max_hops` / `max_depth` / `ttl_seconds` · `velocity_usd_per_min` burn-rate · **8 trip reasons** |
| **Catch runaways** | `detect_loops=True` — semantic repeat detection, **no LLM** |
| **Degrade, don't die** | `ladder` — swap to a cheaper model + narrow tools at 80%, graceful stop at 100% |
| **Trip actions** | `on_trip="pause"` → checkpoint + `resume()`, or `"kill"` → lists side-effects that fired |
| **Try before you enforce** | `shadow=True` → logs what *would* trip; `breakerbox shadow-report` → "$ prevented" |
| **Explain every stop** | `TripDecision` (stable JSON) + single-file HTML **receipt** (per-hop cost, trip reason, blast radius) |
| **Prove cost before running** | `breakerbox ceiling` (or `UNBOUNDED`) · `lock --check` · `diff --fail-on-increase` · `policy` · `egress` |
| **Security suite** (0.11.0) | `breakerbox dow` (denial-of-wallet) · `flow` (Langflow creds) · `mcp` (server posture) · `baseline` (CI gate) · `capability_lock` |
| **Attach it 3 ways** | `guard()` (LangGraph) · `BreakerboxMiddleware` (LangChain 1.x) · `breakerbox claudecode init` (Claude Code) |
| **Observe** | `live` spend line · `alerts` · `otel` spans · `tags` for per-team attribution |
| **Build** | `breakerbox init` / `validate` / `build` · a drag-and-drop visual builder that emits the same guarded Python |
| **Optional cloud** | Live runs dashboard · remote pause/kill · shareable receipts — codegen/observe only, no keys stored |

## Quickstart

```bash
pip install breakerbox
```

Wrap the compiled LangGraph app you already have — the call site doesn't change:

```python
from breakerbox import guard

app = guard(
    my_langgraph_app,
    budget_usd=5.00,           # hard ceiling for the whole workflow DAG
    max_hops=50,               # total model/tool steps across all branches
    ttl_seconds=600,           # wall-clock limit
    velocity_usd_per_min=2.0,  # trip if the burn rate spikes
    on_trip="pause",           # "pause" | "kill"
)

result = app.invoke(inputs)    # the same call you already make
```

Every model and tool dispatch inside the graph — including sub-agents and subgraphs —
inherits one real-dollar budget. When a limit trips, the workflow stops **at the next hop
boundary** (never mid-call) and drops a shareable HTML receipt. No proxy, no Docker, no
gateway to run: enforcement lives *inside* your process, so there's no direct-call bypass.

Prefer to start on the canvas? Open the builder, draw the graph, and let it write this for you:

```bash
cd cloud/dashboard && npm install && npm run dev   # http://localhost:3000/builder
```

## The demo

A broken retry loop that never drops its context, so each hop costs more than the last
([`examples/runaway_demo`](examples/runaway_demo)) — no API keys required:

```
==============================================================
  UNGUARDED runaway : ran 60 hops, spent $12.63
  GUARDED           : killed early, spent $0.82  (budget $0.90)
  AVERTED           : $11.81
==============================================================
```

It stops **strictly under budget** — because the model declares a real `max_tokens`, the
reserve estimate is a true upper bound, so the call that would cross the line is blocked
before it runs. Every run also writes a self-contained `report.html`:

```
────────────────────────────────────────────────────────
 breakerbox receipt · killed (budget)
 stopped at $0.8157   budget $0.9000   hops 13
 projected (naive linear extrapolation, likely an underestimate): $3.13
────────────────────────────────────────────────────────
```

(See [`sample_receipt.html`](examples/runaway_demo/sample_receipt.html) for the full HTML.)

## What it actually does

- **Hierarchical budget escrow.** Not a flat session counter. A parent sub-allocates budget
  to child agents; a child can never spend beyond its allocation; a parent's remaining is
  `budget − Σ(child allocations) − own spend`. Accounting is reserve → execute → reconcile
  (a credit-card hold), so parallel branches can't race past the ceiling. Concurrency-safe
  and property-tested (`Σ spent + Σ reserved ≤ root budget`, always).
- **Graceful trip actions.**
  - `pause` — checkpoints via LangGraph's native checkpointer and raises `BudgetPaused`;
    `app.resume(checkpoint_id, extra_budget_usd=...)` continues from where it stopped.
  - `kill` — stops, finalizes the receipt, raises `BudgetKilled` listing which
    **side-effecting** tools already fired (so you can compensate).
- **Runaway protection (opt-in).** Catch a loop *before* the dollar budget pays for it.
  `detect_loops=True` trips when a node keeps re-firing with near-identical input — a no-LLM
  fuzzy-repeat detector (character-shingle similarity), so nudging an argument doesn't evade it.
  `live=True` streams a `$spent / $budget` counter to your terminal as each hop reconciles, so you
  watch it climb in real time instead of finding out from the invoice.
- **Self-metering.** Counts input tokens locally (tiktoken) and meters streamed output
  chunks, then reconciles against the provider's reported usage and flags discrepancies —
  never trusts a single `usage` field, never meters an unknown model as `$0`. If a call ran
  without `max_tokens` and the cap landed one hop late, the receipt flags that hop explicitly.
- **The receipt.** Terminal summary + single-file `report.html` (inline CSS/SVG, no JS, no
  external assets) + JSON. Leads with the indisputable number — **stopped at $Y, budget $Z** —
  with the projection as clearly-labelled fine print.

## Build it visually

<p align="center">
  <img src="docs/brand/shots/builder.png" alt="The Breakerbox builder: a graph canvas, a live Budget Tree, and guard config" width="820">
</p>

[`cloud/dashboard/app/builder`](cloud/dashboard/app/builder) is a drag-and-drop canvas
(model / tool / router / start / end nodes) with a live **Budget Tree** — root budget →
per-node allocations → unallocated remainder. Over-allocate and it turns red and **blocks
export**. Hit **Generate** and you get the guarded Python above, ready to copy or download.
Everything runs in your browser; the spec → Python codegen is shared with the `breakerbox
build spec.json` CLI and locked to it by golden-fixture tests (Python and TS, enforced in CI).

**Cost forecast (before you run).** The canvas forecasts a run's cost *while you design it* — a
**p50–p95 band** per node and for the whole graph, with a what-if loop slider and a per-node model
swap, all computed in the browser with no API calls. It's a labelled estimate and advisory-only:
it never changes the generated Python. Most builders show cost after a run; this shows it first.

**AI suggest (bring your own key).** Any model/tool/router node has an optional "Suggest code"
helper: describe the step, and it drafts a Python body for you to copy in. It calls the model
**directly from your browser with your own API key** — the key is stored only in your browser
and sent only to the provider, never to a Breakerbox server (there is no server in this path).
Anthropic supports browser-direct calls; OpenAI blocks browser CORS, so for OpenAI you point the
base URL at your own CORS-enabled proxy. The suggestion is copy-paste scaffolding — it's never
written into the saved graph, so codegen stays deterministic.

## Gate cost in CI

Make your agent's cost a unit test. The **provable cost ceiling** — every reachable hop at full
`max_tokens`, a loop charged `max_hops × the costliest hop` — is computed with **zero API calls**,
so it runs in CI and fails a pull request that pushes a graph past your budget:

```yaml
# .github/workflows/cost-ceiling.yml
- uses: actions/checkout@v4
- uses: Amitcoh1/agentbreaker@main    # pin a released tag (e.g. @v0.6.0) for reproducible CI
  with:
    spec: "specs/*.spec.json"
    max: "2.00"                       # red PR if any spec's ceiling exceeds $2.00 (or is unbounded)
```

Same check locally or in any pipeline — `breakerbox ceiling specs/*.spec.json --max 2.00` exits `1`
when over-limit or unbounded. See [CI budget gate](https://docs-rosy-sigma.vercel.app/docs/ci-gate).

> Needs `breakerbox >= 0.6.0` (the release that ships `breakerbox ceiling`).

## More than a budget: cost governance

Because cost is **static and deterministic**, Breakerbox can do things an observe-after-the-fact
dashboard or a gateway/proxy structurally can't. Everything here is local — no server, no stored
keys, no LLM in the loop.

**Prove & pin the cost**

- **`breakerbox ceiling`** — a *provable* worst-case dollar bound, computed with zero API calls, and
  baked into the header of the generated Python so the proof travels with the code.
- **`breakerbox lock` / `--check`** — pin the price table + each spec's ceiling to `breakerbox.lock`;
  CI fails on drift. `package-lock.json`, for dollars.
- **`breakerbox diff`** — the ceiling delta between two versions; `--fail-on-increase` reddens a PR
  that quietly raises your ceiling from $2 to $9.

**Catch runaways before the bill**

- **`detect_loops`** — trips on near-identical repeats *before* the budget (no LLM; paraphrase-resistant).
- **`live=True`** — a real-time `$spent / $budget` counter in your terminal, so you watch it climb
  instead of finding out from the invoice.
- **`max_depth`** — cap sub-agent nesting so a run can't spawn its way around its own cap.
- **`alerts`** — a graduated warn rail (50/80/95%) before the hard trip.

**Govern & attribute**

- **`breakerbox.yaml`** — policy-as-code the build **refuses to violate** (max ceiling, `max_hops`,
  banned models, no destructive tools). A precondition of the artifact, not removable server config.
- **`breakerbox egress`** — certify exactly which network endpoints the generated code can reach.
- **`tags={"team": ...}`** — per-team/customer/env chargeback on every receipt.
- **The receipt is an audit artifact** — who/what/how-much/when, plus a **blast-radius** compensation
  checklist of side-effecting tools that fired before a trip.
- **`otel=True`** — GenAI-semantic-convention spans into Phoenix / Arize / Langfuse.

## Why no Run button?

Server-side flow builders that run your graphs and hold your provider keys have been a
repeated remote-code-execution target. In Langflow (the category leader — 150k+ GitHub
stars, backed by DataStax, an IBM company) the pattern is well documented and public:

- **CVE-2025-3248** (CVSS 9.8) — unauthenticated RCE via the `/api/v1/validate/code`
  endpoint that passed user input to `exec()`; on CISA's KEV (added 2025-05-05), exploited
  by the Flodrix botnet.
- **CVE-2025-34291** (CVSS 9.4 v4.0 / 8.8 v3.1) — a CORS/CSRF account-takeover chain (a
  victim visits a malicious page) that **exfiltrates the API keys and tokens stored in a
  workspace**; on CISA KEV (added 2026-05-21). Reportedly used by the MuddyWater APT for
  initial access (Ctrl-Alt-Intel via The Hacker News; not confirmed by CISA).
- **CVE-2026-33017** (CVSS 9.8) — unauthenticated RCE via the public flow-build endpoint
  (`/api/v1/build_public_tmp/…`); on CISA KEV (added 2026-03-25), exploited within ~20 hours
  of disclosure (Sysdig) and separately used to drop Monero/XMRig cryptominers (Trend Micro).
- **CVE-2026-5027** (CVSS 8.8) — path-traversal arbitrary file write via `/api/v2/files`,
  escalatable to RCE; ~7,000 instances exposed (Censys, incl. historical scan data) with
  active exploitation observed (VulnCheck). Not on CISA KEV.

This isn't a knock on Langflow's product — it's an architectural fact: **a server that runs
your flows and holds your keys is a high-value target.** Breakerbox removes the target. The
canvas only ever produces a Python *string* you run yourself, and your API keys live in your
own environment — never in a dashboard, database, or edge function. There's no endpoint to
exploit because no endpoint executes anything. That's the trade: you give up one-click cloud
runs, and in exchange there is nothing to breach. **Prototype in a tool like Langflow if you
like; ship the production-safe version here.**

## How it compares (facts only)

| | Langflow | LiteLLM budgets | Breakerbox |
|---|:---:|:---:|:---:|
| Visual graph building | ✅ rich | — | ✅ budget-first |
| Server executes your flows | ✅ *(attack surface)* | n/a | ❌ by design |
| Stores your provider keys | ✅ | ✅ *(proxy)* | ❌ never |
| Hierarchical per-agent dollar escrow | — | — *(flat, per-key)* | ✅ |
| Graceful pause/resume at a hop boundary | — | — *(hard error)* | ✅ |
| Catches a runaway run *under* the org ceiling | — | — *(never fires)* | ✅ |
| Output is plain, editable Python | partial *(export)* | n/a | ✅ core promise |

LiteLLM/Portkey/Kong-style gateways solve a different layer (org-wide per-key spend) and
compose fine alongside this — the gateway caps the org, Breakerbox governs one workflow's
internal structure.

**Behind a gateway (LiteLLM / Portkey):** point your model at the gateway's base URL and wrap the
compiled app in `guard()`. Metering is a LangChain callback, not a network hook, so it composes
with any OpenAI-compatible proxy with no extra wiring:

```python
model = ChatOpenAI(model="openai/gpt-4o", base_url="http://localhost:4000", api_key="sk-litellm-…")
app = guard(compiled_app, budget_usd=5.00)  # gateway routes + holds the key; guard budgets the run
```

**The catch most gateway users miss:** a key limit has to sit high enough not to block real work,
so a single runaway run can burn **$180 while still *under* a $500 ceiling** — the key never fires
until the damage is already account-wide, and then it 429s everyone. Breakerbox trips that one run
at $2, at a hop boundary. *A key limit is the fuse box for the building; Breakerbox is the breaker on
this circuit.*

**vs LiteLLM / vs Langflow, in one line:** a gateway like **LiteLLM** guards the *key* — one flat
ceiling, blind to a single run's internal structure. A builder like **Langflow** *runs* your flow —
server-side, holding your keys. **Breakerbox guards the *workflow* and runs nothing:** a hierarchical
per-agent budget baked into plain Python you own. Prototype with either; ship the guarded version here.

Every claim above maps to a public, verifiable fact.

## Notes & limitations (read before you rely on it)

- **`on_trip="pause"` needs a checkpointer.** Compile your graph with one
  (`.compile(checkpointer=MemorySaver())`); `guard()` raises if it's missing.
- **The overshoot rule:** the guard never interrupts a call mid-flight. If your model has
  **no** `max_tokens`, the reserve estimate can under-count and the cap is enforced one hop
  late (overshoot bounded by a single call) — the receipt flags that hop. Set `max_tokens`
  and it stops strictly under budget.
- **Prices** (`prices.json`, ~2000 models) are sourced from LiteLLM's community-maintained
  price table. Refresh them any time with `breakerbox update-prices` (bundled table is the
  offline fallback). Still spot-check the models you care about. Override per-model or set
  `unknown_model="default_rate"` to meter unknown models at a conservative rate instead of
  failing.

## Cloud dashboard (optional)

**[→ Open the dashboard](https://agentbreaker-cyan.vercel.app/dashboard)** — watch runs stream live, and sign in to keep runs private to your account.

Everything above works with zero cloud. If you want a shared, **live** view of runs, point
the guard at a Supabase-backed dashboard:

```python
app = guard(my_app, budget_usd=5.00, report_to="https://YOUR_REF.functions.supabase.co/ingest")
```

Events stream to the dashboard as the run executes (best-effort and non-blocking — a cloud
outage never affects the run); each run gets a shareable, unlisted URL with a live timeline.

To keep runs **private to your account**, sign in to the dashboard, create a key under
**Settings → Your ingest key**, and set it where your agents run:

```bash
export BREAKERBOX_INGEST_KEY="abk_…"   # from the dashboard; runs become private to you
```

Without a personal key the legacy shared key still works and runs stay public (shareable link).
Deploy runbook and code in [`cloud/`](cloud) (Supabase + Next.js on Vercel).

## Roadmap

Where this is headed — horizons, what we will and won't build — is public in
[`ROADMAP.md`](ROADMAP.md). The codegen-only, no-stored-keys architecture is a permanent
constraint, not a phase.

## Contributing

Issues and PRs welcome. Good first stops: the open [issues](https://github.com/Amitcoh1/agentbreaker/issues)
and the [`ROADMAP.md`](ROADMAP.md) horizons. To work on it locally:

```bash
pip install -e ".[dev]"
pytest -q          # pricing, ledger (+ hypothesis), tripwire, meter, guard, report, sink
ruff check .
```

The dashboard (`cloud/dashboard`) has its own checks: `npm run typecheck`, `npm run lint`,
`npm test` (codegen + price-table parity), `npm run build`. CI runs both suites on every push.

## License

[MIT](LICENSE)
