# Built-in Rules Reference

**What you'll learn:** All 26 built-in rule functions, grouped by category, with their parameters and applicable scopes.

***

The engine ships with 26 built-in rules grouped into six categories. Each rule is a pure function: `rule(data, params, context) -> bool`. Returns `True` to pass, `False` to violate.

## Field rules

Applicable to `agent_registration` and `step_execution`.

| Rule                  | What it checks                          | Parameters                        |
| --------------------- | --------------------------------------- | --------------------------------- |
| `field_not_empty`     | Named field has a non-empty value.      | `field: str`                      |
| `field_in_list`       | Named field's value is in an allowlist. | `field: str`, `values: list[str]` |
| `field_matches_regex` | Named field matches a regex pattern.    | `field: str`, `pattern: str`      |

## Path rules

Require task history. `step_execution` only.

| Rule                                   | What it checks                                                                                                | Parameters                                                                                       |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `step_directly_preceded_by`            | Previous step in history has a given type.                                                                    | `required_step_type: str`                                                                        |
| `step_requires_predecessor`            | Some earlier step in history has a given type.                                                                | `required_step_type: str`                                                                        |
| `step_preceded_by_without_intervening` | A required predecessor exists with no forbidden steps between.                                                | `required_step_type: str`, `forbidden_step_types: list[str]`                                     |
| `step_requires_dedicated_predecessor`  | Immediate predecessor matches type and property filter.                                                       | `required_step_type: str`, `property_filter: dict`                                               |
| `step_requires_gate`                   | A `step.gate` precedes this step. The gate may be any distance earlier in history (no freshness enforcement). | `target_step_types: list[str]`, `target_verb: str` (optional), `gate_check_type: str` (optional) |
| `sequence_forbidden`                   | A forbidden ordered sequence has not occurred.                                                                | `sequence: list[str]`                                                                            |
| `step_not_after`                       | This step type is forbidden once a specified predecessor has occurred (permanently tainted).                  | `predecessor_step_type: str`, `predecessor_property_filter: dict` (optional)                     |
| `history_contains`                     | The history contains a step matching type + optional verb + optional property filter.                         | `step_type: str`, `verb: str` (optional), `property_filter: dict` (optional)                     |
| `current_is`                           | The intended behaviour matches type + optional verb + optional property filter.                               | `step_type: str`, `verb: str` (optional), `property_filter: dict` (optional)                     |

## Count rules

| Rule                         | What it checks                                                                                               | Scopes           | Parameters                                                                                     |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------- |
| `execution_max_steps`        | Task has not exceeded a maximum step count.                                                                  | `step_execution` | `step_type: str` (optional), `max_steps: int`                                                  |
| `max_consecutive_same_type`  | No run of the same step type exceeds a limit.                                                                | `step_execution` | `step_type: str`, `max_consecutive: int`                                                       |
| `cross_execution_rate_limit` | Agent has not exceeded N of this step\_type in the last M minutes across tasks.                              | `step_execution` | `step_type: str`, `max_count: int`, `window_minutes: int`, `attribute_filter: dict` (optional) |
| `usage_budget`               | Cumulative usage metric across task history has not exceeded budget. The first occurrence is always allowed. | `step_execution` | `step_type: str`, `property_path: str`, `budget: float`                                        |

## Classification rules

| Rule                                | What it checks                                                                          | Scopes           | Parameters                                                                  |
| ----------------------------------- | --------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------------------------------------- |
| `step_forbidden_for_classification` | This step type is not permitted for the agent's risk classification.                    | `step_execution` | `step_type: str`, `forbidden_classifications: list[str]`                    |
| `working_hours_only`                | Current time is within a permitted window. Supports overnight wraparound and timezones. | `step_execution` | `start_hour: int`, `end_hour: int`, `timezone: str` (optional, default UTC) |
| `step_name_in_allowlist`            | This step's name is in the agent's declared tool allowlist.                             | `step_execution` | `agent_field: str`                                                          |

## Content rules

| Rule               | What it checks                                                                                                                                                            | Scopes           | Parameters                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ---------------------------- |
| `pii_in_request`   | Step input does not contain PII matching configured regex patterns. Patterns are required; no defaults. Input is serialised via `json.dumps` so nested dicts are scanned. | `step_execution` | `patterns: list[str]`        |
| `domain_allowlist` | Step's target domain is in an allowlist.                                                                                                                                  | `step_execution` | `allowed_domains: list[str]` |

## Flow rules

| Rule                             | What it checks                                                                       | Scopes           | Parameters                                               |
| -------------------------------- | ------------------------------------------------------------------------------------ | ---------------- | -------------------------------------------------------- |
| `conditional_successor_required` | If a condition held at some prior step, a specific successor must eventually follow. | `step_execution` | `trigger_step_type: str`, `required_successor_type: str` |
| `tainted_path_block`             | If any prior step is tainted, certain downstream steps are forbidden.                | `step_execution` | `taint_step_type: str`, `blocked_step_types: list[str]`  |
| `all_of`                         | Compound: passes iff all sub-conditions pass.                                        | Both             | `conditions: list[condition]`                            |
| `any_of`                         | Compound: passes iff any sub-condition passes.                                       | Both             | `conditions: list[condition]`                            |
| `not`                            | Compound: passes iff the sub-condition fails.                                        | Both             | `condition: condition`                                   |

Each sub-condition in compound rules is a dict with `rule_type` and `params` keys.

## Programmatic discovery

Rules are self-documenting. To list all rules programmatically:

```python
from kyvvu_engine import PolicyRule

# All rules for a given scope
rules = PolicyRule.get_all_rules(scope="step_execution")
# → {"field_not_empty": {"description": "...", "scopes": [...], "params_schema": {...}}, ...}

# Validate a rule exists
valid, error = PolicyRule.validate_rule_params("pii_in_request", {"patterns": ["\\d{3}-\\d{2}-\\d{4}"]})
```

The platform dashboard uses this metadata to render dynamic forms when creating policies.

***

## Next steps

* [Creating Policies](/policy-authoring/creating.md) — use these rules to author policies
* [Compound Policies](/policy-authoring/compound.md) — combine rules with `all_of`, `any_of`, `not`
* [OWASP Default Template](/policy-authoring/owasp-default.md) — see 8 of these rules in action


---

# Agent Instructions: 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.kyvvu.com/policy-authoring/rules-reference.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.
