Skip to main content

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:
  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

ConcernUse beforeUse after
Prevent unsafe inputYesNo
Prevent side effects from occurringYesNo
Enforce identity or tenant rulesYesNo
Inspect the actual outputNoYes
Detect PII or secrets in outputNoYes
Validate output schemaNoYes
Block oversized result setsNoYes