# Set the policy

> Choose a template, set the action of each category and policy key, override single bots, and switch between log and enforce mode.

The policy has one [action](https://developers.openwaf.dev/ai-crawl-control/categories/#actions) per key: the six configurable [categories](https://developers.openwaf.dev/ai-crawl-control/categories/) and the five [extra keys](https://developers.openwaf.dev/ai-crawl-control/categories/#policy-keys). The decision for a request is the bot's own override if it has one; otherwise the strongest action among the keys that apply to it.

## Defaults

Every key is `log`, except `ai_search`, `ai_user_agent` and `search_engine`, which are `allow`. Humans are always allowed.

## Templates

A template replaces the **whole** policy. Mode, `spoofed_challenge` and bot overrides stay as they are. Policy keys sent in the same change apply on top of the template.

| Key | `search_ok_block_training` | `verified_only` | `block_unverified_automation` |
|---|---|---|---|
| Dashboard name | Allow search engines and AI search, block training | Verified only | Block all unverified automation |
| `ai_training` | block | allow | log |
| `ai_search` | allow | allow | allow |
| `ai_user_agent` | allow | allow | allow |
| `search_engine` | allow | allow | allow |
| `unverified_automation` | log | challenge | block |
| `spoofed` | challenge | block | block |
| `unverified_bot` | log | block | log |
| `trap_hit` | log | challenge | block |
| `secret_probe` | log | block | block |
| `robots_violation` | log | log | block |
| `agent_burst` | log | challenge | block |

## Change the policy

**Dashboard**

**AI Crawl Control → Overview → Settings**: **Templates → Apply**, then adjust **Action per category**. **Review and save** shows the diff before saving.
**CLI**

```sh
openwaf-cloud ctl zones set example.com ai_agents.template=search_ok_block_training ai_agents.policy.spoofed=block \
  --reason "Block training and fake crawlers"
```
**API**

`ai_agents` in `PATCH …/edge` is a JSON merge patch: objects merge (the policy key by key), lists are replaced whole, `null` puts a field back to its default. `template` is write-only.
```sh
curl -sS -X PATCH "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/edge" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Block training and fake crawlers" \
  -H "Content-Type: application/json" \
  -d '{"ai_agents": {"template": "search_ok_block_training", "policy": {"spoofed": "block"}}}'
```
**MCP**

`ai_agents_settings` with `{"zone": "example.com", "template": "search_ok_block_training", "patch": {"policy": {"spoofed": "block"}}, "reason": "…"}`. Without `patch` and `template` it only reads the settings.


## Per-bot overrides

`bot_overrides` (up to 100 `{bot_id, action}` entries) sets the action of one catalog bot, whatever its category. The list is replaced whole.

**Dashboard**

**Settings → Crawler overrides → Add crawler**, pick the crawler and its action.
**CLI**

`bot:action` pairs, separated by commas; `""` removes every override.
```sh
openwaf-cloud ctl zones set example.com ai_agents.bot_overrides=gptbot:block,ccbot:allow --reason "Per-bot policy"
```
**API**

```json
{"ai_agents": {"bot_overrides": [{"bot_id": "gptbot", "action": "block"}, {"bot_id": "ccbot", "action": "allow"}]}}
```
**MCP**

`ai_agents_settings` with `"patch": {"bot_overrides": [{"bot_id": "gptbot", "action": "block"}]}`.


## Log and enforce

| `mode` | Effect |
|---|---|
| `log` (default) | Decisions are computed and counted with `enforced: false`; traffic passes. Reports show them as "would". |
| `enforce` | Decisions are applied. |

The `tarpit` action needs `tarpit.enabled`; see [Trap and tarpit](https://developers.openwaf.dev/ai-crawl-control/trap-and-tarpit/).

## One name, its own policy

`hosts.<name>.ai_agents` replaces the zone's settings for that name as a whole; the first change to a name starts from the zone's settings. In the dashboard use **Applies to** in the settings; in MCP pass `host`; in the CLI use `--host`:

```sh
openwaf-cloud ctl zones set example.com --host shop.example.com ai_agents.mode=enforce --reason "Enforce on the shop"
```
