Documentation Index
Fetch the complete documentation index at: https://docs.brane.membranelabs.org/llms.txt
Use this file to discover all available pages before exploring further.
Allow small refunds automatically. Block large refunds until approval is implemented.
Problem
A support agent can issue refunds to customers. You want to:
- Allow refunds up to a tenant-specific limit automatically
- Block refunds above that limit until human approval exists
- Never allow refunds in non-production environments
Complete Example
from brane import CapabilityDeniedError, Decision, Effect, Runtime
TENANT_LIMITS = {
"tenant_acme": 100.0,
"tenant_globex": 250.0,
"tenant_initech": 50.0,
}
DEFAULT_LIMIT = 100.0
runtime = Runtime(
agent_id="support-agent",
environment="prod",
tenant_id="tenant_acme",
)
@runtime.capability(
name="refund_customer",
type="tool",
risk="high",
effect=Effect(
type="financial",
reversible=False,
external=True,
description="Issues a payment refund",
),
data_namespace="billing.refunds",
owner="payments-team",
)
def refund_customer(customer_id: str, amount_usd: float, reason: str = ""):
return {"refunded": True, "customer_id": customer_id, "amount": amount_usd}
@runtime.before_capability(
"refund_customer",
name="refund_require_prod",
version="1.0",
priority=200,
)
def require_prod_for_refunds(ctx):
if not ctx.is_prod:
return Decision(
type="deny",
reason="Refunds can only be issued in the production environment",
)
return Decision(type="allow")
@runtime.before_capability(
"refund_customer",
name="refund_amount_limit",
version="1.0",
priority=100,
)
def refund_amount_limit(ctx):
amount = ctx.arg("amount_usd", 0)
limit = TENANT_LIMITS.get(ctx.tenant_id, DEFAULT_LIMIT)
if amount <= 0:
return Decision(type="deny", reason="Refund amount must be positive")
if amount > limit:
return Decision(
type="deny",
reason=(
f"Refund of ${amount:.2f} exceeds the ${limit:.2f} limit "
f"for tenant {ctx.tenant_id}. Human approval is required."
),
)
return Decision(type="allow")
try:
result = refund_customer("cust_123", 75.00, reason="Duplicate charge")
print(result)
refund_customer("cust_456", 349.00, reason="Defective product")
except CapabilityDeniedError as e:
print(f"Blocked: {e.reason}")
print(f"Action ID: {e.action_id}")
How It Works
Two policies protect the refund_customer capability, running in priority order:
require_prod_for_refunds runs first and blocks the refund if the environment is not prod.
refund_amount_limit checks the refund amount against the tenant-specific limit.
Both policies must allow for the refund to proceed. Either can deny.
Adding a Third Policy: Scope Check
@runtime.before_capability(
"refund_customer",
name="refund_scope_check",
version="1.0",
priority=150,
)
def require_refund_scope(ctx):
if not ctx.agent_has_scope("refunds:create"):
return Decision(
type="deny",
reason="Agent requires refunds:create scope to issue refunds",
)
return Decision(type="allow")
Future: Approval Instead of Deny
Once approval_required decisions are implemented, the limit policy can pause rather than block:
if amount > limit:
return Decision(
type="approval_required",
reason=f"Refund of ${amount:.2f} requires human approval",
approval={
"approver_group": "finance-ops",
"expiration_minutes": 60,
"context": {
"customer_id": ctx.arg("customer_id"),
"amount": amount,
"tenant": ctx.tenant_id,
},
},
)
The runtime will pause the action, send the approval request, and resume when a human approves or deny automatically when they reject or the request expires.
Production Notes
- The policy runs before the refund API call. If the policy denies, no refund is issued.
- Store tenant limits in your configuration or database, not hardcoded.
- Use
action_id from CapabilityDeniedError to correlate the denial with your request logs.
- When audit sinks are available, every allowed and denied refund attempt will produce an audit event.