> For the complete documentation index, see [llms.txt](https://docs.interactive.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.interactive.ai/agents/guides/authoring-policies.md).

# Authoring policies

> **Context** — This guide assumes the [Policies](/agents/concepts/policies.md) concept page. It's organised as: when to reach for a policy, writing conditions, writing actions, choosing knobs, patterns, anti-patterns, checklist.
>
> YAML examples follow **manifest schema 6.1.1**. Manifest and content shapes are schema-versioned and differ across runtime versions — see [Versioning & compatibility](/agents/operations/versioning.md).

## When to create a policy

Reach for a policy when a rule is **cross-cutting** — it should hold across many processes, regardless of which routine (if any) is active. Policies are the agent's standing rules; they're matched on every turn and layered on top of whatever flow is running.

Create a policy when the rule is:

* **A behaviour that spans routines** — "always answer in the customer's language", "never reveal another customer's data", "quote prices in EUR". You don't want to copy this into every routine; state it once as a policy.
* **A safety / compliance / escalation trigger** that can fire at any point — "if the user reports an accident, hand off to a human" — independent of where the conversation is.
* **A reaction to a condition**, not a sequence of steps — one situation, one response.

Reach for a [routine](/agents/guides/authoring-routines.md) instead when the behaviour is a **procedure**: an ordered, multi-step flow (collect → look up → branch → respond) with its own state. A rule that "happens to need three steps" is a routine wearing a policy's clothes — see the [one-action rule](#writing-actions-that-do-what-you-meant) below.

## Writing conditions that match correctly

The condition is read by the policy matcher every turn and answered as a yes/no: *does this apply to the conversation right now?* Write it for that reader:

**Be concrete about triggers.** Name the phrasings, not just the abstract category:

```yaml
condition: >
  The user mentions a driver who is under 21 years old, or asks whether
  someone under 21 can rent.
```

beats `condition: "The driver age requirement is relevant."` — abstractions make the matcher guess.

**Include the negative space when a sibling rule exists.** If two policies could plausibly both match, carve the boundary into the conditions themselves ("…but NOT when the user is asking about an existing booking").

**Reference state explicitly.** Conditions can read [variables](/agents/concepts/memory-and-state.md#variables-vs-metadata) and tool results from the conversation: `"player_info is not available AND the customer's full name and date of birth are present"` is a perfectly good condition.

## Writing actions that do what you meant

The action is a binding instruction for the turn. Three rules:

1. **Say what to do, then what not to do.** Models follow positive instructions better; reserve prohibitions for the genuinely dangerous part:

   ```yaml
   action: >
     State plainly that the minimum driver age at DriveAway is 21, so the
     booking cannot proceed for that driver. If there is another adult in
     the party who is 21 or older, offer to book under that person's name
     instead. Do not invoke the booking tool with an under-age driver.
   ```
2. **One policy, one rule.** An action that handles four unrelated cases should be four policies — each gets its own condition, criticality, and trace visibility.
3. **Tool + speech is fine — but it must be one action.** Unlike routine nodes, a policy action may call a tool *and* address the customer in one turn:

   ```yaml
   id: auth-on-identity
   name: Authenticate On Identity
   condition: >
     The customer is not yet authenticated and has provided their full
     name and full date of birth.
   action: >
     Call crm:authenticate_customer with the full name as a single string
     and the date of birth, then confirm to the customer that they're
     verified.
   tools:
     - crm:authenticate_customer
   reevaluate_after:
     - crm:authenticate_customer
   ```

   The catch is **single action**. "Call a tool and tell the customer the outcome" is one action. But if the action is really *two* — e.g. *ask the customer for their credentials* **and then** *authenticate them* — that's a sequence with a customer turn in the middle, which a single policy can't reliably drive. Reconsider it as:

   * a [**routine**](/agents/guides/authoring-routines.md) (ask → authenticate is a two-node flow with a customer reply between them), or
   * **two policies** (one that prompts for credentials when they're missing; one that authenticates once they're present, gated by `reevaluate_after` so it fires in the same turn the credentials arrive).

   If you can't phrase a policy's action as a single sentence without an "and then", it's a procedure — author it as a routine.

## Choosing the knobs

| Knob                                                                  | Set it when                                                                                                                                                    |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `criticality: HIGH`                                                   | Safety, compliance, money — anything that must win attention when several policies match.                                                                      |
| `criticality: MEDIUM` (default) / `LOW`                               | Ordinary business rules / style preferences that may yield under pressure.                                                                                     |
| `always_match: true`                                                  | The rule must hold even if the matcher would judge it irrelevant — regulatory disclaimers, absolute prohibitions. Costs prompt space every turn; budget these. |
| `reevaluate_after: [tool]`                                            | The policy's relevance flips when that tool succeeds (auth, account status) — the match is re-run after the tool executes.                                     |
| `metadata`                                                            | Anything your team's tooling wants to read off traces (severity, owner, ticket).                                                                               |
| Routine-scoped (`policies:` inside a routine, explicit `id` required) | The rule only makes sense mid-flow of that routine.                                                                                                            |

When a policy must categorically beat routines or other policies, declare it in [priorities](/agents/concepts/priorities.md) — criticality alone is a weight, not a guarantee.

## Patterns

**The guard** — block a specific dangerous action:

```yaml
id: no-pii-in-chat
name: Never Read Back Secrets
condition: >
  The user asks the agent to read back, confirm, or repeat a full card
  number, password, or other secret.
action: >
  Refuse clearly and briefly: explain you can never display full card
  numbers or passwords, and point the user to the secure account page
  for anything credential-related.
criticality: HIGH
```

**The redirector** — keep the agent in its lane (see `stay-on-topic` in the [Quickstart](/agents/guides/quickstart.md#policy)).

**The escalator** — hand off when out of depth:

```yaml
id: incident-handoff
name: Incident Handoff
condition: >
  The user reports an accident, injury, breakdown, theft, or any
  emergency involving a rental car.
action: >
  Express concern first. Provide the emergency assistance line
  (+800 5555 0199, 24/7) and offer to connect them to a human agent
  immediately. Do not attempt to assess fault or give legal advice.
criticality: HIGH
```

**The state-gated authenticator** — see `auth-on-identity` above: fires only while unauthenticated, self-disarms via `reevaluate_after`.

**The disclaimer** — `always_match: true` plus a short action that appends required wording when quoting prices/terms.

## Anti-patterns

| Anti-pattern                                                                                                  | Why it fails                                                                                              | Instead                                                                         |
| ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **A procedure in an action** ("first ask X, then call Y, then confirm Z")                                     | Policies have no step state; the model gets the whole script every turn and improvises its position in it | Make it a [routine](/agents/guides/authoring-routines.md)                       |
| **Condition that needs the action's result** ("the lookup shows the account is locked" before any lookup ran) | The matcher reads the conversation as-is                                                                  | Split: one policy/node calls the tool; another conditions on its result         |
| **Mirror-image pairs** ("if X do A" + "if not-X do B")                                                        | Doubles matcher load; the negative usually belongs in the system prompt or the first policy's action      | One policy with both arms in the action                                         |
| **Everything `always_match`**                                                                                 | Burns prompt space; dilutes the genuinely critical                                                        | Trust the matcher for conditional rules                                         |
| **Vague meta-conditions** ("the conversation is going badly")                                                 | Unanchorable judgement → erratic matching                                                                 | Name observable triggers (user swears, repeats a question 3×, asks for a human) |

## Versioning workflow

Policies are versioned documents; the manifest pins exact versions. The working loop:

1. Publish the new policy version to the platform catalog.
2. Bump the pin in the manifest (`context.policies[].version`).
3. Deploy. The trace snapshot records which versions were live for every turn, so you can correlate behaviour changes with policy changes — see [Observability](/agents/guides/observability.md).

## Review checklist

* [ ] Condition names concrete triggers (phrases, observable state), not categories
* [ ] Condition carves boundaries against sibling policies that could co-match
* [ ] Action says what to do first, prohibitions second
* [ ] One rule per policy
* [ ] Tools listed under `tools:` if the action calls them
* [ ] `reevaluate_after` set if a tool flips this policy's relevance
* [ ] `always_match` only for must-always-hold rules
* [ ] Conflicts with routines resolved via [priorities](/agents/concepts/priorities.md), not hope


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.interactive.ai/agents/guides/authoring-policies.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
