Runtime decision layer for tool-using AI agents
Before your agent executes a supported tool or model call, the SDK asks the gate.
allow, block, or
require_approval — backed by tool patterns, budgets, rate limits, and human approvals.
pip install nullrunimport nullrun
nullrun.init()
@nullrun.protect
def refund_customer(order_id: str, amount_cents: int) -> str:
"""The gate answers before this body runs."""
return payments.refund(order_id, amount_cents)
Decorate the tool. The gate evaluates the call; your function
runs only if the decision is allow — and waits for a
human if the policy says require_approval.
How it fits together¶
flowchart LR
Agent["Your agent<br/>(Python SDK)"] -->|"@protect"| Gateway["NullRun gateway"]
Gateway -->|"budget pre-flight<br/>policy fetch"| Decision{"allow?"}
Decision -->|"yes"| Body["wrapped function runs"]
Decision -->|"no"| Block["raise NullRunBlockedException"]
Operator["operator"] -.->|"kill / pause"| Gateway
Gateway -.->|"control plane<br/>(WebSocket)"| Agent
What you get out of the box¶
@protect
call — no round-trip cost when the answer is "yes". Hard
blocks on overrun; soft mode allows a bounded overrun
when an active chain is present.
money_amount / tool_parameters).
Every approval is bound to the exact action payload via a
SHA-256 action_digest — the grant is refused
if the SDK then executes a different amount or
different arguments.
killed /
paused to every connected SDK. WorkflowKilledInterrupt
reaches the top of the agent loop, not a swallowed
except Exception.
mcp://payments/refund*,
bash, db.drop) decide which
canonical tool names are allowed. Always Hard:
fails closed on transport error, regardless of the budget's
enforcement_mode.
@protect call activates
auto-instrumentation for OpenAI, Anthropic, LangGraph,
OpenAI Agents, Mistral, Gemini, Cohere, Bedrock, LlamaIndex,
CrewAI, and AutoGen. Vendor SDKs are patched in place —
every LLM call goes through the gateway.
What one protected call looks like¶
sequenceDiagram
participant A as Your code
participant S as NullRun SDK
participant G as NullRun gateway
participant O as Operator
A->>S: run a protected call
S->>G: gate check (tool name, projected cost)
G-->>S: allow
S->>A: run the wrapped function
S->>G: track the actual cost
O->>G: kill or pause the workflow
G-->>S: state change over the control plane
S-->>A: raise WorkflowKilledInterrupt
End-to-end: the gate evaluation, cost accounting, and the kill path.
The Python SDK runs inside your own process and talks to the NullRun gateway over HTTPS. Every gate decision, budget reservation, and cost event travels over that connection — the SDK adds a network round-trip and nothing else to your deployment. Policies, workflows, approvals, and the operator controls live in the dashboard, which is where your team configures what the gate enforces.