Scopes

Understanding permission scopes in AgentSudo.

Scopes define what actions an agent can perform. They follow a simple, hierarchical format.

Scope Format

Scopes use a colon-separated format:

action:resource:qualifier

Examples:

  • read:orders - Read orders
  • write:refunds - Create refunds
  • admin:users:delete - Delete users (admin)

Hierarchical Scopes

Scopes can be hierarchical, allowing fine-grained control:

# Specific scope
"write:refunds:small"      # Only small refunds
"write:refunds:large"      # Only large refunds

# Parent scope (includes children)
"write:refunds"            # All refunds

# Top-level scope
"write"                    # All write operations

Wildcard Scopes

Use * for wildcard matching:

# Match all read operations
"read:*"

# Match all operations on orders
"*:orders"

# Full access (superuser)
"*"
⚠️

Use wildcard scopes sparingly. Prefer specific scopes for better security.

Using the @sudo Decorator

Protect functions with the @sudo decorator:

from agentsudo import sudo

@sudo(scope="read:orders")
def get_order(order_id: str):
    return {"id": order_id}

@sudo(scope="write:orders")
def update_order(order_id: str, data: dict):
    pass

@sudo(scope="delete:orders")
def delete_order(order_id: str):
    pass

Multiple Scopes

Require multiple scopes with scopes:

@sudo(scopes=["read:orders", "read:customers"])
def get_order_with_customer(order_id: str):
    # Requires BOTH scopes
    pass

Any Scope

Require any one of multiple scopes:

@sudo(scopes=["admin:orders", "write:orders"], require_all=False)
def modify_order(order_id: str):
    # Requires at least ONE scope
    pass

Common Scope Patterns

CRUD Operations

# Create
@sudo(scope="create:products")
def create_product(data): pass

# Read
@sudo(scope="read:products")
def get_product(id): pass

# Update
@sudo(scope="update:products")
def update_product(id, data): pass

# Delete
@sudo(scope="delete:products")
def delete_product(id): pass

Role-Based Access

# Support tier
support_scopes = [
    "read:orders",
    "read:customers",
    "write:tickets",
    "write:refunds:small"
]

# Manager tier
manager_scopes = [
    *support_scopes,
    "write:refunds:large",
    "read:analytics"
]

# Admin tier
admin_scopes = ["*"]

Resource-Specific Access

# Access to specific resources
"read:orders:own"           # Only own orders
"read:orders:team"          # Team's orders
"read:orders:all"           # All orders

# Implementation
@sudo(scope="read:orders:own")
def get_my_orders(user_id: str):
    pass

Scope Matching Rules

  1. Exact match: read:orders matches read:orders
  2. Wildcard match: read:* matches read:orders, read:customers
  3. Hierarchical match: write:refunds matches write:refunds:small
  4. Superuser: * matches everything

Examples

Agent ScopeRequired ScopeResult
read:ordersread:orders✅ Allowed
read:*read:orders✅ Allowed
write:refundswrite:refunds:small✅ Allowed
*admin:delete✅ Allowed
read:orderswrite:orders❌ Denied
write:refunds:smallwrite:refunds:large❌ Denied

Best Practices

1. Be Specific

# ✅ Good
scopes = ["read:orders", "write:tickets"]

# ❌ Bad
scopes = ["*"]

2. Use Consistent Naming

# ✅ Good - consistent pattern
"read:orders"
"write:orders"
"delete:orders"

# ❌ Bad - inconsistent
"get_orders"
"orders:write"
"remove-orders"

3. Document Your Scopes

# Define scopes in a central location
class Scopes:
    """Application permission scopes."""
    
    # Order scopes
    READ_ORDERS = "read:orders"
    WRITE_ORDERS = "write:orders"
    DELETE_ORDERS = "delete:orders"
    
    # Refund scopes
    REFUND_SMALL = "write:refunds:small"    # Up to $50
    REFUND_MEDIUM = "write:refunds:medium"  # Up to $500
    REFUND_LARGE = "write:refunds:large"    # Unlimited
# Define scope groups for common roles
SUPPORT_SCOPES = [
    Scopes.READ_ORDERS,
    Scopes.REFUND_SMALL,
]

MANAGER_SCOPES = [
    *SUPPORT_SCOPES,
    Scopes.REFUND_MEDIUM,
    Scopes.REFUND_LARGE,
]