> For the complete documentation index, see [llms.txt](https://docs.kyvvu.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kyvvu.com/policy-authoring/rules-reference.md).

# Built-in Rules Reference

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

***

The engine ships with 27 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`            | The immediately preceding step in history is the required type.                                                                                                                                    | `required_step_type: str`, `target_step_types: list[str]` (optional), `target_verb: str` (optional), `target_property_filter: dict` (optional)                          |
| `step_requires_predecessor`            | Some earlier step in history has the required type.                                                                                                                                                | `required_step_type: str`, `target_step_types: list[str]`, `target_verb: str` (optional), `target_property_filter: dict` (optional)                                     |
| `step_preceded_by_without_intervening` | A required predecessor exists with no forbidden steps between.                                                                                                                                     | `required_step_type: str`, `forbidden_intervening: list[str]`, `target_step_types: list[str]`, `target_verb: str` (optional), `target_property_filter: dict` (optional) |
| `step_requires_dedicated_predecessor`  | Each target step has its own unconsumed predecessor — one predecessor cannot authorise two target steps.                                                                                           | `required_step_type: str`, `target_step_types: list[str]`, `target_verb: str` (optional), `target_property_filter: dict` (optional)                                     |
| `step_requires_gate`                   | A matching `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), `gate_result: str` (optional, default `pass`)                         |
| `sequence_forbidden`                   | A forbidden ordered sequence (subsequence over history + current step) has not occurred.                                                                                                           | `forbidden_sequence: list[str]`                                                                                                                                         |
| `step_not_after`                       | This step type is forbidden once a forbidden predecessor type has occurred (permanently tainted).                                                                                                  | `target_step_types: list[str]`, `forbidden_predecessor_step_types: list[str]`, `target_verb: str` (optional)                                                            |
| `path_within_root`                     | Allowlist containment: the target path resolves at or under the session `project_root`. Lexical only — `..` is collapsed but symlinks are not resolved; fails open when `project_root` is unknown. | `field: str` (optional, default `target.host`), `target_step_types: list[str]` (optional), `target_verb: str` (optional), `target_verbs: list[str]` (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                                                                                               | Enforcement points | Parameters                                                                                    |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------ | --------------------------------------------------------------------------------------------- |
| `execution_max_steps`        | Task has not exceeded a maximum count of the given step type.                                                | `step_execution`   | `step_type: str`, `max_steps: int`, `verb: str` (optional)                                    |
| `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`, `property_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                                                                          | Enforcement points | Parameters                                                                                                                                       |
| ----------------------------------- | --------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `step_forbidden_for_classification` | This step type is not permitted for the agent's risk classification.                    | `step_execution`   | `forbidden_step_type: str`, `agent_risk_classifications: list[str]`, `forbidden_verb: str` (optional), `target_property_filter: dict` (optional) |
| `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`, `target_step_types: list[str]` (optional)                                                                                    |

## Content rules

| Rule               | What it checks                                                                                                                                                            | Enforcement points | 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                                                                                                  | Enforcement points | Parameters                                                                                                                                                    |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `conditional_successor_required` | If the previous step matches a trigger type and condition, the current step must satisfy successor constraints. | `step_execution`   | `trigger_step_types: list[str]`, `trigger_condition: dict`, `required_step_type: str` (optional), `forbidden_step_types: list[str]` (optional)                |
| `tainted_path_block`             | If any prior step matches the taint pattern, certain downstream steps are blocked.                              | `step_execution`   | `taint_step_type: str`, `target_step_types: list[str]`, `taint_verb: str` (optional), `taint_property_filter: dict` (optional), `target_verb: str` (optional) |
| `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 enforcement point
rules = PolicyRule.get_all_rules(enforcement_point="step_execution")
# → {"field_not_empty": {"description": "...", "enforcement_points": [...], "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
