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.

The policy author’s view of an AgentAction. The clean interface for writing real application policy.

Definition

PolicyContext is not the same thing as raw action data. It is what the policy author sees. The runtime has a large internal record: trace IDs, capability metadata, tenant metadata, workflow state, risk scores, and side effect metadata. The policy author should not have to navigate all of that directly. PolicyContext is the clean, stable interface that makes policy feel like natural application code.
def my_policy(ctx: PolicyContext) -> Decision:
    if ctx.is_prod and ctx.is_high_risk:
        return Decision(type="deny", reason="Requires approval in prod")
    return Decision(type="allow")

Raw Fields

  • action: the full AgentAction record
  • args: bound input arguments for the call
  • output: the function’s return value, only available in after_capability policies
  • runtime_metadata: metadata passed from the runtime to the policy engine

Convenience Properties

PropertyTypeDescription
capabilityCapabilityThe capability being attempted.
toolCapabilityAlias for capability.
agent_id`strNone`Agent identity from the action.
principal_id`strNone`Principal identity from the action.
tenant_id`strNone`Tenant from the action.
is_prodboolTrue if environment is prod.
is_high_riskboolTrue if capability risk is high or critical.
has_side_effectsboolTrue if capability has any side effects.
disableable_side_effectslist[SideEffect]Side effects that can be disabled via input transform. Planned.

Methods

ctx.arg(name, default=None)
Read an input argument by name.
ctx.arg("amount_usd")        # 249.0
ctx.arg("dry_run", False)   # False
ctx.agent_has_scope(scope)
Check whether the capability requires a given scope name. This is a name-match check against capability metadata, not a full agent grant check.

Common Policy Patterns

if ctx.is_prod:
    ...
amount = ctx.arg("amount_usd", 0)
if amount > 100:
    return Decision(type="deny", reason="Amount exceeds limit")
if ctx.is_high_risk and ctx.is_prod:
    return Decision(type="deny", reason="High-risk tool blocked in prod")
ALLOWED_TENANTS = {"tenant_acme", "tenant_globex"}
if ctx.tenant_id not in ALLOWED_TENANTS:
    return Decision(type="deny", reason="Tenant not authorized")
if not ctx.agent_has_scope("refunds:create"):
    return Decision(type="deny", reason="Missing refunds:create scope")
@runtime.after_capability("call_model")
def check_model_output(ctx):
    if ctx.output and "SECRET_KEY" in str(ctx.output):
        return Decision(type="deny", reason="Possible secret in model output")
    return Decision(type="allow")

What PolicyContext Does Not Have

PolicyContext surfaces a curated interface. It does not expose the full runtime internals. This is intentional: policy authors should not need to know about framework-specific metadata, internal trace systems, or deployment details. If you need additional context for your policies, use capability.metadata or action.metadata to pass custom data through. Future versions will add principal_has_scope(), tenant_has_feature(), has_grant(), and require_metadata().