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

# After Capability Policies

> Policies that run after a capability executes.

Run after the capability executes. Inspect and control the output before it is returned.

## Timing

An `after_capability` policy runs after the underlying function has completed and returned a result. The function has already executed. The policy inspects the output and decides whether to allow it through or block it.

```text theme={null}
agent calls capability
  -> Brane intercepts
  -> before_capability policies run -> allow
  -> function executes, returns output
  -> after-action record created with output
  -> after_capability policies run
    -> allow: output returned to caller
    -> deny: CapabilityDeniedError raised
```

<Warning>
  Side effects already occurred. Use before policies to prevent unwanted side effects. Use after policies to inspect outputs and detect violations after execution.
</Warning>

## Registration

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

## Accessing the Output

In an `after_capability` policy, `ctx.output` contains the function's return value.

```python theme={null}
@runtime.after_capability("execute_sql")
def check_result_size(ctx):
    output = ctx.output
    rows = output.get("rows", []) if isinstance(output, dict) else []
    if len(rows) > 1000:
        return Decision(type="deny", reason="Result set too large (>1000 rows)")
    return Decision(type="allow")
```

## Common Use Cases

Detect possible secret leakage:

```python theme={null}
@runtime.after_capability("call_model")
def check_for_secrets(ctx):
    output = str(ctx.output or "")
    secret_patterns = ["SECRET_KEY", "API_KEY", "password=", "token="]
    for pattern in secret_patterns:
        if pattern.lower() in output.lower():
            return Decision(type="deny", reason="Possible secret in model output")
    return Decision(type="allow")
```

Validate output shape:

```python theme={null}
@runtime.after_capability("get_customer_data")
def validate_customer_output(ctx):
    output = ctx.output
    if not isinstance(output, dict) or "customer_id" not in output:
        return Decision(type="deny", reason="Unexpected output shape")
    return Decision(type="allow")
```

Detect PII:

```python theme={null}
import re

SSN_PATTERN = re.compile(r"\b\d{3}-\d{2}-\d{4}\b")

@runtime.after_capability("*")
def detect_pii(ctx):
    output_str = str(ctx.output or "")
    if SSN_PATTERN.search(output_str):
        return Decision(type="deny", reason="SSN detected in output")
    return Decision(type="allow")
```

## Deny Behavior

When an after policy denies:

1. The function has already executed
2. `CapabilityDeniedError` is raised
3. The output is not returned to the caller

## Future Decision Types

* `redact`: strip or mask fields from the output before returning it
* `transform_output`: mutate the output before returning it
* `log_only`: allow the output through but flag the action for review

## Before vs. After

| Concern                             | Use before | Use after |
| ----------------------------------- | ---------- | --------- |
| Prevent unsafe input                | Yes        | No        |
| Prevent side effects from occurring | Yes        | No        |
| Enforce identity or tenant rules    | Yes        | No        |
| Inspect the actual output           | No         | Yes       |
| Detect PII or secrets in output     | No         | Yes       |
| Validate output schema              | No         | Yes       |
| Block oversized result sets         | No         | Yes       |
