> ## 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.

# Before Capability Policies

> Policies that run before a capability executes.

Run before the capability executes. This is the most important policy stage.

## Timing

A `before_capability` policy runs after the call is intercepted but before the underlying function executes. If the policy denies, `CapabilityDeniedError` is raised and the function never runs. The consequence does not occur.

```text theme={null}
agent calls capability
  -> Brane intercepts
  -> AgentAction created
  -> PolicyContext built
  -> before_capability policies run
    -> allow: function executes
    -> deny: CapabilityDeniedError raised, function does not run
```

## Registration

```python theme={null}
@runtime.before_capability("capability_name")
def my_policy(ctx):
    return Decision(type="allow")
```

## What Is Available

In a `before_capability` policy, `ctx.output` is always `None`; the function has not run yet.

* `ctx.capability`
* `ctx.arg("name")`
* `ctx.agent_id`, `ctx.principal_id`, `ctx.tenant_id`
* `ctx.is_prod`, `ctx.is_high_risk`
* `ctx.agent_has_scope("scope")`

## Common Use Cases

Block unsafe SQL input:

```python theme={null}
@runtime.before_capability("execute_sql")
def read_only_sql(ctx):
    query = ctx.arg("query", "").lower().strip()
    if not query.startswith("select"):
        return Decision(type="deny", reason="Only SELECT queries are allowed")
    return Decision(type="allow")
```

Block high-risk tools in production:

```python theme={null}
@runtime.before_capability("*")
def block_high_risk_in_prod(ctx):
    if ctx.is_prod and ctx.is_high_risk:
        return Decision(
            type="deny",
            reason="High-risk capability use requires an approved workflow in prod",
        )
    return Decision(type="allow")
```

Enforce a financial limit:

```python theme={null}
@runtime.before_capability("refund_customer")
def refund_amount_limit(ctx):
    amount = ctx.arg("amount_usd", 0)
    limit = get_tenant_limit(ctx.tenant_id)
    if amount > limit:
        return Decision(type="deny", reason=f"Refund ${amount} exceeds limit of ${limit}")
    return Decision(type="allow")
```

Check scopes:

```python theme={null}
@runtime.before_capability("refund_customer")
def require_refund_scope(ctx):
    if not ctx.agent_has_scope("refunds:create"):
        return Decision(type="deny", reason="Agent requires refunds:create scope")
    return Decision(type="allow")
```

## Deny Behavior

When any before policy returns `Decision(type="deny")`:

1. The runtime stops evaluating remaining before policies
2. The underlying function is not called
3. `CapabilityDeniedError` is raised with the denial reason

```python theme={null}
from brane import CapabilityDeniedError

try:
    execute_sql("delete from customers")
except CapabilityDeniedError as e:
    print(e.reason)
    print(e.policy_name)
    print(e.action_id)
```

## Policy Order

Multiple before policies on the same capability run in descending priority order. Deny wins: if any policy denies, the action is blocked regardless of other policies.

Wildcard policies (`"*"`) run alongside exact-match policies.

## Future Decision Types

* `approval_required`: pause until a human approves
* `transform_input`: mutate the input before execution
* `route`: redirect to a different capability or provider
* `sandbox`: execute with restricted access
* `log_only`: allow but flag for review
