Skip to content

LangChain

Install

pip install "scopebound[langchain]"

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 scopeboundpypi.org/project/scopebound