LangChain
Install
Integration
from scopebound import ScopeboundSDK, enforce
from langchain_core.tools import BaseTool
sb = ScopeboundSDK()
@enforce(sb, role="invoice-processor")
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
return get_invoices(status)
The @enforce decorator wraps _run(). Scopebound intercepts every call before the method body executes.
Deny example
from scopebound.exceptions import ScopeboundDenyError
@enforce(sb, role="invoice-processor")
class DeleteInvoiceTool(BaseTool):
name: str = "delete_invoice"
description: str = "Delete an invoice"
def _run(self, invoice_id: str) -> str:
return f"Invoice {invoice_id} deleted."
try:
tool = DeleteInvoiceTool()
tool._run(invoice_id="INV-003")
except ScopeboundDenyError as e:
print(e.deny_code) # SCOPE_VIOLATION
print(e.severity) # medium
print(e.reason) # tool not in allowed_tools
Role names vs IDs
You can pass either the role name or UUID to @enforce:
@enforce(sb, role="invoice-processor") # name — resolved automatically
@enforce(sb, role="a1b2c3d4-...") # UUID — used directly
Name resolution is cached per SDK instance.
More info
pip install scopebound — pypi.org/project/scopebound