Skip to main content

Cost ceiling, audit log, and kill switch for LLM agents.

Project description

llm-leash

The cost ceiling, audit log, and kill switch your LLM agent should never run without.

PyPI License: MIT Tests Coverage

llm-leash is a 5-line runtime firewall for LLM agents. It enforces hard USD budgets, writes an immutable audit log, and gives you a kill switch and human-in-the-loop hook — without locking you into any agent framework.

Status: v1.0.0 — stable public API. See CHANGELOG.md.

Why

You shipped an agent. Then:

  • A retry loop spent $2,387 in 14 minutes.
  • A vague user message coaxed it into DROP TABLE users.
  • Compliance asked "show me every action this agent took for customer X last month" — you can't.

llm-leash solves the boring B2B half of agent safety that nobody else owns: money, paperwork, panic button. It works alongside the content-safety scanners (LlamaFirewall, Invariant, Prompt-Guard) — not against them.

Quickstart

from llm_leash import Firewall, LeashKilled
from anthropic import Anthropic

fw = Firewall(budget_usd=10.00, audit_log="audit.jsonl")
client = fw.wrap(Anthropic())

try:
    while True:
        client.messages.create(model="claude-opus-4-7", max_tokens=200,
                               messages=[{"role": "user", "content": "..."}])
except LeashKilled as e:
    print(f"Saved you the rest. Reason: {e.reason}")

Three things happen on every call:

  1. Budget tracked — cumulative cost per session, raises LeashKilled when the cap is hit.
  2. Audit logged — every model call appends one hash-chained JSONL line. Tamper-evident: llm-leash verify audit.jsonl.
  3. Kill switchawait fw.kill("reason") stops the session immediately; the next call raises LeashKilled.

Run the offline demo (no API key needed):

python demo.py
llm-leash verify audit.jsonl

Adapters — one wrap, every framework

from llm_leash import Firewall
fw = Firewall(budget_usd=10.00, audit_log="audit.jsonl")
Framework Client class Example
Anthropic anthropic.Anthropic fw.wrap(Anthropic()).messages.create(...)
OpenAI openai.OpenAI fw.wrap(OpenAI()).chat.completions.create(...)
LangChain / LangGraph ChatAnthropic, ChatOpenAI fw.wrap(ChatAnthropic(model="…")).invoke([…])
CrewAI crewai.LLM fw.wrap(LLM(model="openai/gpt-4o")).call([…])
OpenHands openhands.llm.LLM fw.wrap(LLM(config)).completion(messages=[…])
Pydantic-AI pydantic_ai.models.* await fw.wrap(OpenAIModel(...)).request([…])
MCP mcp.ClientSession await fw.wrap(session).call_tool("read_file", {…})

All adapters are duck-typed — no SDK imports at module level, no version pinning. The wrapped client preserves every attribute of the original; only the call surface is intercepted.

# LangGraph example: drop the firewall into your existing graph
from langchain_anthropic import ChatAnthropic
from langgraph.graph import StateGraph

chat = fw.wrap(ChatAnthropic(model="claude-haiku-4-5"))
graph = StateGraph(MyState)
graph.add_node("llm", lambda state: {"reply": chat.invoke(state["messages"])})
# CrewAI example: pass the wrapped LLM to your Agent
from crewai import Agent, Crew, Task, LLM
llm = fw.wrap(LLM(model="anthropic/claude-haiku-4-5"))
agent = Agent(role="researcher", llm=llm, goal="...")
result = Crew(agents=[agent], tasks=[Task(...)]).kickoff()
# MCP example: every tool call is audited; dangerous tools can require HITL
async with ClientSession(read, write) as session:
    wrapped = fw.wrap(session)
    await wrapped.call_tool("read_file", {"path": "/etc/hosts"})

SOC 2 evidence pack

Generate a complete SOC 2 evidence package from any audit.jsonl log:

llm-leash soc2 /var/log/agent-audit.jsonl \
  --out ./evidence-2026-Q2/ \
  --period-start 2026-04-01T00:00:00Z \
  --period-end   2026-06-30T23:59:59Z \
  --org "Acme Inc"

Produces six artefacts an auditor can attach to their evidence binder directly: executive-summary.html, cc6_access_control.csv, cc7_monitoring.csv, cc7_integrity.json, anomalies.csv, and bom.json. Each file is sha256-hashed and listed in the bill of materials. See docs/SOC2.md for the Trust Service Criteria mapping.

Persistent state for multi-worker prod

from llm_leash import Firewall, SQLiteBudgetStore, SQLiteKillRegistry

fw = Firewall(
    budget_usd=100.0,
    audit_log="/var/log/agent-audit.jsonl",
    kill_registry=SQLiteKillRegistry("/var/lib/myapp/kill.db"),
)
fw._budget._store = SQLiteBudgetStore("/var/lib/myapp/budget.db")

Redis variants (RedisBudgetStore / RedisKillRegistry) accept any duck-typed client.

What it does

  • Hard USD budget per session. Soft cap warns. Hard cap kills.
  • Append-only JSONL audit log, hash-chained, optionally HMAC-signed. jq-able. SOC 2 / EU AI Act Article 12 evidence-shaped.
  • Kill switch. Stop a runaway agent from CLI, HTTP, or Redis. Sub-300ms propagation.
  • Human-in-the-loop webhook for high-stakes tool calls. Default-deny on timeout.
  • Tool ACL with regex / SQL-AST / shell-AST patterns.
  • PII redaction before tool dispatch and before audit write.
  • Adapters for Anthropic, OpenAI, LangGraph, CrewAI, OpenHands, Pydantic-AI, MCP.

What it does NOT do

You want Use this instead
Prompt-injection classifier Prompt-Guard (call from a rule)
Content guardrails (DSL) NeMo Guardrails / Guardrails AI
Tool-arg pattern catalog Invariant Labs (import their .rules from a policy)
Eval framework PromptFoo / DeepEval
Observability dashboard Langfuse / LangSmith (ship JSONL into them)
Model router LiteLLM / OpenRouter

llm-leash is the layer beneath all of them. It does enforcement and evidence. Everything else is a rule you can plug in.

Documents

  • PRODUCT.md — what this is, who buys it, what it is not.
  • ARCHITECTURE.md — modules, data flow, performance budget.
  • API.md — public surface, CLI, JSONL schema, custom rules.
  • docs/adr/ — architecture decisions (in progress).

Install (when published)

pip install llm-leash                  # core, zero deps
pip install llm-leash[anthropic]       # + Anthropic adapter
pip install llm-leash[all]             # everything

Roadmap

Version Status What
v0.1 Core firewall + Anthropic adapter + audit chain + CLI verify
v0.2 PolicyEngine + PII redactor
v0.3 BlockedSql + BlockedShell rules
v0.4 Redis transports for budget + kill
v0.5 HITL gates (InMemory + Webhook) + HitlThreshold
v0.6 LangGraph + CrewAI + MCP adapters + acceptance gate
v0.7 audit replay/export + SQLite stores + extended CLI
v1.0 Stable public API · semver lock · PyPI release · per-adapter examples
v1.1 OpenHands + Pydantic-AI adapters · LlamaFirewall / Presidio rule wrappers
v1.2 Durable HITL queue (SQLite/InMemory) · HTTP kill transport · CLI hitl ops
v1.3 SOC 2 evidence pack generator · CLI soc2 · TSC mapping
v1.4 planned TypeScript port of the core
v1.5 planned OPA/Rego policy backend

License

MIT — see LICENSE.

The OSS firewall is and always will be free. The hosted audit-log service (forthcoming) is the only thing that costs money — and you never need it. JSONL is yours.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llm_leash-1.3.0.tar.gz (128.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llm_leash-1.3.0-py3-none-any.whl (61.4 kB view details)

Uploaded Python 3

File details

Details for the file llm_leash-1.3.0.tar.gz.

File metadata

  • Download URL: llm_leash-1.3.0.tar.gz
  • Upload date:
  • Size: 128.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for llm_leash-1.3.0.tar.gz
Algorithm Hash digest
SHA256 f32e279606f423c8a760ec64c63626173c895b912ff5a1ec8f4721c50fa975c7
MD5 8bda942cd5782cba2cba77a9553168e2
BLAKE2b-256 90d5a227f5bdd77a1fd5a26e66b5cb40b3f42dbc9f6f3b878e04994c56343b33

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_leash-1.3.0.tar.gz:

Publisher: publish.yml on avelikiy/llm-leash

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file llm_leash-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: llm_leash-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 61.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for llm_leash-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7f116aee9c46b8b0d3ed1c130dbbe64b2dbba6b57c0fdcaf95af032e2cf64659
MD5 a35486e417dc1c59566d2751cd37b2e2
BLAKE2b-256 0e1f5ffc35d8f27adb234d6ed74f0fc69ac496b04b86cdf9b86269745daa8ba4

See more details on using hashes here.

Provenance

The following attestation bundles were made for llm_leash-1.3.0-py3-none-any.whl:

Publisher: publish.yml on avelikiy/llm-leash

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page