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.
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.
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
Side effects already occurred. Use before policies to prevent unwanted side effects. Use after policies to inspect outputs and detect violations after execution.
Registration
@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.
@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:
@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:
@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:
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:
- The function has already executed
CapabilityDeniedError is raised
- 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 |