Scopebound sits inside your agent framework and intercepts every tool call before it executes. OPA policies, scoped JWTs, <5ms enforcement, tamper-evident audit log.
Works with the frameworks you already use
Every major framework ships with zero enforcement between the LLM's decision and the tool's execution. When an agent decides to call a tool, nothing checks whether it's allowed.
When an agent calls a tool, it executes immediately. There's no check that the agent is allowed to call that tool — trust is implicit.
You have no tamper-evident record of what your agents actually called. If something goes wrong, you find out in the next reconciliation run.
If a compromised agent starts behaving anomalously — rapid external calls, unusual patterns — nothing detects or stops it.
Teams add guards inside each tool's implementation. That logic is scattered, inconsistent, and doesn't survive framework migrations.
Scopebound sits between the LLM's decision and the tool's execution — the only point where enforcement is both reliable and sub-millisecond.
Your agent runs normally. The LLM produces a tool call decision as part of its reasoning loop.
The @enforce decorator intercepts the call before _run() is invoked. OPA evaluates your Rego policy against the agent's scoped JWT.
Allowed calls execute normally. Denied calls raise ScopeboundDenyError before the tool runs. Every decision is written to the tamper-evident audit log.
Add enforcement to any existing agent tool. Nothing else in your codebase changes.
from scopebound import ScopeboundSDK, enforce from langchain_core.tools import BaseTool sb = ScopeboundSDK() # reads SCOPEBOUND_BASE_URL + SCOPEBOUND_API_KEY from env @enforce(sb, role="invoice-processor") # ← this is the entire integration class ReadInvoicesTool(BaseTool): name: str = "read_invoices" description: str = "Read pending invoices from the database" def _run(self, status: str = "pending") -> str: # your existing tool logic — unchanged ...
from scopebound import ScopeboundSDK from scopebound.adapters.autogen import enforce_autogen sb = ScopeboundSDK() @enforce_autogen(sb, role="invoice-processor") def read_invoices(limit: int = 10) -> str: # on deny, returns structured error dict instead of raising ...
from scopebound import ScopeboundSDK from scopebound.adapters.crewai import CrewEnforcer sb = ScopeboundSDK() enforcer = CrewEnforcer(sb, roles={ "researcher": "read-only-analyst", "writer": "email-sender", }) @enforcer.enforce_tool(agent_name="researcher") def search_web(query: str) -> str: ...
from scopebound import ScopeboundSDK from scopebound.adapters.semantic_kernel import enforce_sk sb = ScopeboundSDK() class InvoicePlugin: @enforce_sk(sb, role="invoice-processor") async def read_invoices(self, limit: int = 10) -> str: ... # sync and async both supported
from claude_agent_sdk import ClaudeAgentOptions, query from scopebound import ScopeboundSDK from scopebound.exceptions import ScopeboundDenyError sb = ScopeboundSDK() def scopebound_hook(tool_name: str, tool_input: dict): try: sb.enforce(role_id="invoice-processor", tool_name=tool_name) except ScopeboundDenyError as e: raise PermissionError(f"[{e.deny_code}] {e.reason}") options = ClaudeAgentOptions(hooks={"PreToolUse": scopebound_hook}) async for message in query("Process pending invoices", options=options): print(message)
OPA/Rego evaluation on the enforce path adds under 5ms. p99 under 10ms in production load.
Every agent session gets a scoped JWT. Role, allowed tools, delegation depth, and TTL baked into the token.
Append-only JSONL log with SHA-256 hash chain. Every allow and deny recorded. Chain violation halts the server.
Statistical baseline + Isolation Forest. Anomaly score above threshold triggers automatic session revocation.
OPA/Rego policies version-controlled alongside your agent code. Hot-reloads without restart.
Adapters for LangChain, OpenAI Assistants, CrewAI, AutoGen, Semantic Kernel, and Claude Agent SDK.
Or pip install scopebound and explore the SDK.