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

# Policy Examples

> Real-world policy patterns for common access control scenarios.

Copy and adapt these patterns for your own Devctrl policies. Each example includes the scenario, the CEL expression, and what it allows and blocks.

<Note>
  Tool names are namespaced as `serverName__toolName` (e.g., `github__list_issues`) to avoid collisions between MCP servers. The examples below use short names for readability — replace them with your actual namespaced tool names.
</Note>

## Restrict tools by team

Only the engineering team can use deployment tools.

```cel theme={null}
// Allow rule
identity.labels.team == "engineering"
```

| Request                                  | Result                            |
| ---------------------------------------- | --------------------------------- |
| Engineering agent calls `deploy_service` | Allowed                           |
| Support agent calls `deploy_service`     | Denied                            |
| Support agent calls `get_ticket`         | Denied (doesn't match allow rule) |

<Note>
  This rule alone is restrictive — it only allows engineering agents. Combine it with other rules for a complete policy. For example, add a separate allow rule for support tools.
</Note>

## Allow specific tools per task

Different tasks get access to different tools.

```cel theme={null}
// Allow rule
(task.name == "resolve-ticket"
  && request.tool.name in ["get_issue", "add_comment", "update_status"])
|| (task.name == "generate-report"
  && request.tool.name in ["query_database", "export_csv"])
```

| Task            | Tool             | Result  |
| --------------- | ---------------- | ------- |
| resolve-ticket  | `get_issue`      | Allowed |
| resolve-ticket  | `query_database` | Denied  |
| generate-report | `export_csv`     | Allowed |
| generate-report | `add_comment`    | Denied  |

## Scope data to current task context

The agent can only access the customer referenced in the current task.

```cel theme={null}
// Allow rule
task.context.customer_id == request.tool.args.customer_id
```

| Task context              | Tool call                               | Result  |
| ------------------------- | --------------------------------------- | ------- |
| `customer_id: "cust_123"` | `get_customer(customer_id: "cust_123")` | Allowed |
| `customer_id: "cust_123"` | `get_customer(customer_id: "cust_456")` | Denied  |

This is the core of TBAC — access scoped to exactly what the task needs.

## Block dangerous operations

Prevent destructive operations regardless of who's calling.

```cel theme={null}
// Deny rule — checked before allow rules
request.tool.name in ["delete_customer", "drop_table", "purge_data"]
|| request.tool.name.startsWith("admin_")
```

| Tool                   | Result                                           |
| ---------------------- | ------------------------------------------------ |
| `delete_customer`      | Denied (matches deny list)                       |
| `admin_reset_password` | Denied (starts with "admin\_")                   |
| `get_customer`         | Passes this rule (evaluated by other rules next) |

<Warning>
  Deny rules take priority over allow rules. A request blocked by a deny rule stays blocked, even if an allow rule would permit it.
</Warning>

## Combine identity and task checks

Support agents can only use support tools, and only for their assigned customer.

```cel theme={null}
// Allow rule
identity.labels.team == "support"
  && request.tool.name in ["get_issue", "get_customer", "add_comment", "update_status"]
  && task.context.customer_id == request.tool.args.customer_id
```

This single expression enforces three things:

1. Only support team agents
2. Only approved support tools
3. Only the customer in the current task

## Read-only access for analysts

Data analysts can query but never modify.

```cel theme={null}
// Allow rule
identity.labels.role == "analyst"
  && (request.tool.name.startsWith("get_")
    || request.tool.name.startsWith("list_")
    || request.tool.name.startsWith("query_"))
```

Any tool that starts with `get_`, `list_`, or `query_` is allowed. Tools like `create_`, `update_`, `delete_` are blocked.

## Multi-agent collaboration

Different agents in the same project get different access levels.

**Policy 1 — Deny rule (block billing for non-finance):**

```cel theme={null}
!has(identity.labels.team) || identity.labels.team != "finance"
  ? request.tool.name in ["process_payment", "issue_refund", "update_billing"]
  : false
```

**Policy 2 — Allow rule (allow everything else for authenticated agents):**

```cel theme={null}
has(identity.labels.team)
```

| Agent         | Tool              | Result                                        |
| ------------- | ----------------- | --------------------------------------------- |
| Finance agent | `process_payment` | Allowed (deny rule doesn't match for finance) |
| Support agent | `process_payment` | Denied (deny rule blocks non-finance billing) |
| Support agent | `get_ticket`      | Allowed (passes deny rule, passes allow rule) |

## Environment-based restrictions

Only allow production tools for production-labeled agents.

```cel theme={null}
// Allow rule
(has(request.tool.args.environment) && request.tool.args.environment == "production")
  ? identity.labels.env == "production"
  : true
```

This lets staging agents use staging tools freely, but requires a `production` label to touch production resources.

## Next steps

<CardGroup cols={2}>
  <Card title="CEL reference" icon="code" href="/policies/cel-expressions">
    Full syntax reference for CEL expressions.
  </Card>

  <Card title="RBAC vs TBAC" icon="scale-balanced" href="/policies/rbac-vs-tbac">
    Understand why task-based access control matters for AI agents.
  </Card>
</CardGroup>
