> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meshai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Policies

> Create and manage governance policies evaluated against agent activity across the proxy and OTLP ingest

Policies are governance rules made up of a `rules` object plus optional `conditions` that scope when the policy applies. Policies are evaluated against every LLM request that flows through the MeshAI proxy, and post-hoc as evidence against OTLP-ingested agent activity that never touches the proxy.

## Policy Types

| Type                   | Description                                       | Example                                                                                 |
| ---------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `model_allowlist`      | Restrict which models an agent can use            | Only allow `gpt-4o` and `claude-sonnet-4-6`                                             |
| `budget_limit`         | Enforce a monthly spend cap (USD)                 | \$500/month per agent                                                                   |
| `require_approval`     | Require HITL approval before the request proceeds | All production agents need approval                                                     |
| `block_provider`       | Block an entire LLM provider                      | Block all requests to `openai`                                                          |
| `rate_limit`           | Throttle requests per hour                        | 1,000 requests/hour                                                                     |
| `require_human_review` | Flag the agent for periodic human review          | High-risk agents reviewed quarterly                                                     |
| `prompt_injection`     | Prompt injection scanning                         | Always-on at the proxy - see [Prompt Injection Detection](/governance/prompt-injection) |
| `pii_filter`           | Redact, block, or observe PII in LLM responses    | See [PII Filter](/governance/pii-filter) for actions and pattern set                    |

## Enforcement Model

Policy types are not all enforced the same way. Be precise about what each one actually does today:

| Policy type            | Proxy enforcement                                                                                                           | Evidence recording                                                                    |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `model_allowlist`      | Inline - blocks the request with `403`                                                                                      | Recorded                                                                              |
| `block_provider`       | Inline - blocks the request with `403`                                                                                      | Recorded                                                                              |
| `require_approval`     | Inline - blocks the request with `403` until approved                                                                       | Recorded                                                                              |
| `budget_limit`         | Enforced separately, at the proxy-key/team level (not by the policy engine) - returns `429`                                 | Recorded by the policy engine as evidence only                                        |
| `rate_limit`           | Enforced separately, at the proxy-key/team level (not by the policy engine) - returns `429`                                 | Recorded by the policy engine as evidence only                                        |
| `require_human_review` | Not enforced inline - always passes                                                                                         | Recorded as evidence (observe-only)                                                   |
| `pii_filter`           | Enforced on proxy responses (redact / block / observe)                                                                      | Detections recorded in the Eval Log; OTLP path records a pass row (deferred to proxy) |
| `prompt_injection`     | Always-on scanning at the proxy, independent of any policy - see [Prompt Injection Detection](/governance/prompt-injection) | N/A                                                                                   |

The kill switch (agent block/unblock) is a separate, always-inline `403` mechanism that sits outside the policy engine - see [Agent Kill Switch](/governance/kill-switch).

For agent activity ingested via OTLP (never routed through the proxy), MeshAI evaluates enabled policies post-hoc against each span and records the result to the Eval Log as evidence. This is observe-only: it populates the audit/evidence trail for OTel-native tenants but cannot block or require approval for an action that has already happened.

## Conditions

Every policy accepts an optional `conditions` object that scopes when it applies. Conditions are evaluated with AND semantics - every key present must match.

| Key            | Type                                                 | Matches when                                                 |
| -------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| `agent_ids`    | list of agent ULIDs                                  | The request's agent is in the list                           |
| `team_ids`     | list of team ids                                     | The request's team is in the list                            |
| `environments` | list of strings                                      | The request's environment (e.g. `production`) is in the list |
| `risk_levels`  | list of `minimal`\|`limited`\|`high`\|`unacceptable` | The agent's current risk classification is in the list       |

If a key is omitted (or `null`), that dimension imposes no constraint. If `conditions` is omitted entirely, the policy applies to all agents, teams, and environments.

<Warning>
  An unclassified agent (no risk classification on record) never matches a `risk_levels`-scoped policy, even if the list is broad. Classify an agent first if you need risk-scoped policies to apply to it.
</Warning>

## Create a Policy

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "production-model-allowlist",
      "policy_type": "model_allowlist",
      "rules": {
        "allowed_models": ["gpt-4o", "claude-sonnet-4-6", "gemini-2.0-flash"]
      },
      "conditions": {
        "environments": ["production"]
      },
      "priority": 100,
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  from meshai import MeshAI

  client = MeshAI(api_key="msh_...")

  policy = client.create_policy(
      name="production-model-allowlist",
      policy_type="model_allowlist",
      rules={
          "allowed_models": ["gpt-4o", "claude-sonnet-4-6", "gemini-2.0-flash"]
      },
      conditions={"environments": ["production"]},
      priority=100,
      enabled=True,
  )
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "data": {
      "id": 42,
      "name": "production-model-allowlist",
      "policy_type": "model_allowlist",
      "enabled": true,
      "priority": 100,
      "conditions": {
        "agent_ids": null,
        "team_ids": null,
        "risk_levels": null,
        "environments": ["production"]
      },
      "rules": {
        "allowed_models": ["gpt-4o", "claude-sonnet-4-6", "gemini-2.0-flash"]
      },
      "created_at": "2026-03-17T10:00:00Z",
      "updated_at": "2026-03-17T10:00:00Z"
    }
  }
  ```
</ResponseExample>

`rules` is a required, non-empty object whose shape depends on `policy_type` (see the examples below). `priority` is an integer from 1 to 1000 (default 100) - lower numbers are evaluated first, and the first matching policy that fails stops evaluation.

## Policy Examples

### Block a Provider

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "block-openai",
      "policy_type": "block_provider",
      "rules": { "blocked_providers": ["openai"] },
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  client.create_policy(
      name="block-openai",
      policy_type="block_provider",
      rules={"blocked_providers": ["openai"]},
      enabled=True,
  )
  ```
</CodeGroup>

### Require Approval (HITL)

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "production-approval",
      "policy_type": "require_approval",
      "rules": { "reason": "All production requests need sign-off" },
      "conditions": { "environments": ["production"] },
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  client.create_policy(
      name="production-approval",
      policy_type="require_approval",
      rules={"reason": "All production requests need sign-off"},
      conditions={"environments": ["production"]},
      enabled=True,
  )
  ```
</CodeGroup>

### Budget Limit

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "agent-budget-cap",
      "policy_type": "budget_limit",
      "rules": { "max_budget_usd": 500, "period": "monthly" },
      "conditions": { "agent_ids": ["01ARZ3NDEKTSV4RRFFQ69G5FAV"] },
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  client.create_policy(
      name="agent-budget-cap",
      policy_type="budget_limit",
      rules={"max_budget_usd": 500, "period": "monthly"},
      conditions={"agent_ids": ["01ARZ3NDEKTSV4RRFFQ69G5FAV"]},
      enabled=True,
  )
  ```
</CodeGroup>

<Note>
  `budget_limit` policies are recorded by the policy engine as evidence, but the actual spend cap is enforced separately at the proxy key / team level (see [Usage Limits](/billing/usage-limits)).
</Note>

### Rate Limit

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "api-rate-limit",
      "policy_type": "rate_limit",
      "rules": { "max_requests_per_hour": 1000 },
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  client.create_policy(
      name="api-rate-limit",
      policy_type="rate_limit",
      rules={"max_requests_per_hour": 1000},
      enabled=True,
  )
  ```
</CodeGroup>

### Require Human Review

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "high-risk-review",
      "policy_type": "require_human_review",
      "rules": { "review_interval_days": 90 },
      "conditions": { "risk_levels": ["high", "unacceptable"] },
      "enabled": true
    }'
  ```

  ```python SDK theme={null}
  client.create_policy(
      name="high-risk-review",
      policy_type="require_human_review",
      rules={"review_interval_days": 90},
      conditions={"risk_levels": ["high", "unacceptable"]},
      enabled=True,
  )
  ```
</CodeGroup>

## List Policies

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.meshai.dev/api/v1/policies \
    -H "Authorization: Bearer msh_YOUR_API_KEY"
  ```

  ```python SDK theme={null}
  policies = client.list_policies()
  ```
</CodeGroup>

## Update a Policy

<CodeGroup>
  ```bash curl theme={null}
  curl -X PATCH https://api.meshai.dev/api/v1/policies/42 \
    -H "Authorization: Bearer msh_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "enabled": false }'
  ```

  ```python SDK theme={null}
  client.update_policy(42, enabled=False)
  ```
</CodeGroup>

## Delete a Policy

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE https://api.meshai.dev/api/v1/policies/42 \
    -H "Authorization: Bearer msh_YOUR_API_KEY"
  ```

  ```python SDK theme={null}
  client.delete_policy(42)
  ```
</CodeGroup>

## What Happens When a Policy Is Violated

When a proxy request violates an inline-enforced policy (`model_allowlist`, `block_provider`, `require_approval`), the agent receives a `403`:

```json theme={null}
{
  "error": "Policy 'production-model-allowlist': model 'gpt-3.5-turbo' not in allowlist"
}
```

`require_approval` violations receive a distinct body - see [HITL Approvals](/governance/approvals).

Each policy create, update, and delete emits an audit event (`policy.created`, `policy.updated`, `policy.deleted`). There is no `policy.violated` audit event today - a rejected request is reflected in the proxy's `403` response and, where applicable, in `GET /policy-evaluations`, not as a separate audit-trail entry.
