Policies control what AI agents can do. The engine evaluates policies in priority order and returns the decision of the first matching policy. If no policy matches, the action is allowed.
Policy fields
| Field | Type | Description |
|---|
name | string | Human-readable label |
tool | string | github, linear, slack, notion, internal_api, mcp |
actionPattern | string | Glob-style match, e.g. pull_request.* or * |
resourceType | string | Optional resource type filter, e.g. pull_request |
riskLevel | enum | Optional exact risk level filter |
mode | enum | allow, block, or require_approval |
conditions | object | Optional structured conditions (see below) |
priority | integer | Lower number = evaluated first |
enabled | boolean | Disabled policies are skipped entirely |
toolName | string | MCP only: exact match on the tool name (e.g. create_issue) |
toolNamePattern | string | MCP only: prefix wildcard (e.g. delete_*) |
Priority ordering
Lower numbers win. Use these ranges as a convention:
| Range | Use |
|---|
| 1–9 | Emergency overrides |
| 10–49 | Specific allow rules |
| 50–99 | Specific require_approval rules |
| 100–499 | Specific block rules |
| 500–999 | Catch-all rules |
Action pattern matching
Patterns match the classified action string. Supported forms:
| Pattern | Matches |
|---|
* | Everything |
pull_request.create | Exact match |
pull_request.* | Any action starting with pull_request. |
issues.* | Any issue action |
For GitHub, actions are classified from the HTTP method and path. For MCP, the action is the tool name.
Risk level filtering
Use riskLevel on a policy to match only actions at that exact risk level. Use conditions.minRiskLevel and conditions.maxRiskLevel for range matching:
{
"name": "Require approval for high+ risk",
"tool": "github",
"actionPattern": "*",
"conditions": {
"minRiskLevel": "high"
},
"mode": "require_approval",
"priority": 50
}
Agent filtering
Allow or block specific agents by ID:
{
"name": "Block untrusted agents",
"tool": "github",
"actionPattern": "*",
"conditions": {
"blockedAgents": ["untrusted-bot", "experimental-agent"]
},
"mode": "block",
"priority": 5
}
{
"name": "Allow trusted agent full access",
"tool": "github",
"actionPattern": "*",
"conditions": {
"allowedAgents": ["trusted-deploy-agent"]
},
"mode": "allow",
"priority": 10
}
For MCP policies, use toolName for exact match or toolNamePattern for prefix wildcard:
{
"name": "Block all delete tools",
"tool": "mcp",
"actionPattern": "*",
"toolNamePattern": "delete_*",
"mode": "block",
"priority": 10
}
{
"name": "Require approval for create_pr",
"tool": "mcp",
"actionPattern": "*",
"toolName": "create_pr",
"mode": "require_approval",
"priority": 20
}
Complete workspace lockdown example
This setup blocks all writes by default and adds specific policies for approved operations:
[
{
"name": "Allow all read operations",
"tool": "github",
"actionPattern": "read",
"mode": "allow",
"priority": 10
},
{
"name": "Allow issue creation",
"tool": "github",
"actionPattern": "issues.create",
"mode": "allow",
"priority": 20
},
{
"name": "Require approval for PR creation",
"tool": "github",
"actionPattern": "pull_request.create",
"mode": "require_approval",
"priority": 30
},
{
"name": "Require approval for file writes",
"tool": "github",
"actionPattern": "file.write",
"mode": "require_approval",
"priority": 40
},
{
"name": "Block all critical operations",
"tool": "github",
"actionPattern": "*",
"conditions": { "minRiskLevel": "critical" },
"mode": "block",
"priority": 50
},
{
"name": "Block everything else",
"tool": "github",
"actionPattern": "*",
"mode": "block",
"priority": 999
}
]
Test your policies by checking the Audit Logs after a run. Every entry shows which policy matched (or null if the default allow fired). Use this to tune priority and patterns.
Conditions reference
interface PolicyConditions {
minRiskLevel?: "low" | "medium" | "high" | "critical";
maxRiskLevel?: "low" | "medium" | "high" | "critical";
allowedAgents?: string[]; // only these agents match
blockedAgents?: string[]; // these agents never match
allowedResourceTypes?: string[];
blockedResourceTypes?: string[];
customRules?: Record<string, unknown>; // reserved for future use
}