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

# Mental Model

> Capability + AgentAction + PolicyContext -> Decision. The Brane control loop.

One formula covers every capability, every policy, every integration.

## The Formula

```text theme={null}
Capability + AgentAction + PolicyContext -> Policy -> Decision
```

A **[Capability](/concepts/capability)** is anything an agent can use: a tool, a model, a memory store, a database, an MCP server, a secret, another agent.

An **[AgentAction](/concepts/agent-action)** is one attempted use of that capability, capturing identity, environment, input, and trace context.

A **[PolicyContext](/concepts/policy-context)** is the clean interface the policy author uses to inspect the action.

A **Policy** is a function that takes a PolicyContext and returns a Decision.

A **[Decision](/concepts/decision)** is what the runtime enforces.

## The Lifecycle

1. Capability is invoked: a function call, tool use, or API call
2. Brane intercepts the invocation before the function executes
3. Brane creates an AgentAction record capturing who, what, where, and with what
4. Brane builds a PolicyContext, the clean developer-facing view of the action
5. Matching `before_capability` policies evaluate the context in priority order
6. Policy returns a Decision: allow or deny, with more types planned
7. If denied, Brane raises `CapabilityDeniedError`; the function never executes
8. If allowed, the original function executes and returns output
9. Brane creates an after-action record with the output included
10. Matching `after_capability` policies evaluate; they can inspect the output
11. If an after policy denies, Brane raises `CapabilityDeniedError` after execution
12. If after policy allows, Brane returns the output to the caller

## Developer Example

```python theme={null}
from brane import Decision, Runtime

runtime = Runtime(agent_id="support-agent", environment="prod", tenant_id="acme")

@runtime.capability(name="refund_customer", type="tool", risk="high")
def refund_customer(customer_id: str, amount_usd: float):
    return {"refunded": True, "amount": amount_usd}

@runtime.before_capability("refund_customer")
def limit_refund_amount(ctx):
    amount = ctx.arg("amount_usd", 0)
    if amount > 100:
        return Decision(type="deny", reason=f"Refund ${amount} exceeds $100 limit")
    return Decision(type="allow")

refund_customer("cust_123", 50.00)   # allowed
refund_customer("cust_456", 250.00)  # denied
```

At the `refund_customer("cust_456", 250.00)` call, Brane:

1. Intercepts before the function runs
2. Creates an `AgentAction` for `support-agent` in `prod` using `refund_customer` with `amount_usd=250`
3. Builds a `PolicyContext` wrapping that action
4. Finds `limit_refund_amount`, which matches `refund_customer`
5. Calls the policy; `ctx.arg("amount_usd")` returns `250`, which is over the limit
6. Returns `Decision(type="deny")`
7. Raises `CapabilityDeniedError`. The actual refund function never runs.

## Security Team Example

```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 is not allowed in prod without an approved workflow",
        )
    return Decision(type="allow")
```

`ctx.is_prod` checks the runtime environment. `ctx.is_high_risk` checks the capability's `risk` field. Neither requires knowing which specific capability was called; the policy works across the entire governed surface.

## Why This Is The Right Boundary

The control boundary for agent systems is not the text they produce. It is the capabilities they use.

Policy on prompts and outputs leaves a gap: the agent can still call a tool, write a file, or query a database before the output is inspected. Policy on capability use catches the action at the right moment, before the consequence occurs.

The formula works the same regardless of the agent framework. LangGraph tools, CrewAI tools, OpenAI Agents SDK function tools, and MCP tool calls all reduce to the same `AgentAction` against the same capability. One policy runtime governs all of them.
