> 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/core-concepts/behaviours.md).

# Atomic Behaviours

**What you'll learn:** The 12 behaviour types that form Kyvvu's canonical vocabulary, how `step_type + verb` classifies them, and where properties fit in.

***

## The vocabulary

Kyvvu's vocabulary contains 12 atomic behaviour types in the `step.*` namespace. Four mark the boundaries of a task; the other eight describe what the agent does inside one. Together with an HTTP-style **verb** (`GET`, `POST`, `PATCH`, `DELETE`, or none), they form the vocabulary the engine operates on.

Each task-boundary behaviour follows the step lifecycle: it is emitted through the normal step path, evaluated at `step_execution`, and matched by `step_type`. The SDK exports the four task-boundary types as `TASK_BOUNDARY_STEP_TYPES`.

| Step type         | Valid verbs           | What it represents                                                    |
| ----------------- | --------------------- | --------------------------------------------------------------------- |
| `task.start`      | --                    | A task begins.                                                        |
| `task.end`        | --                    | A task completes normally.                                            |
| `task.error`      | --                    | A task terminates with an error.                                      |
| `task.idle`       | --                    | The agent is idle within a task (heartbeat / keepalive).              |
| `step.resource`   | GET/POST/PATCH/DELETE | Read or mutate an external resource (DB, file, API).                  |
| `step.message`    | GET/POST              | Receive (GET) or send (POST) a message.                               |
| `step.self`       | GET/POST/PATCH/DELETE | Read/write the agent's own internal state (memory, scratchpad, plan). |
| `step.model`      | POST                  | Send a prompt to an LLM and receive a completion.                     |
| `step.credential` | GET                   | Retrieve a secret, token, or credential.                              |
| `step.exec`       | --                    | Execute code (run a script, call a function, shell out).              |
| `step.gate`       | --                    | Cross a gate — human approval, policy check, guardrail.               |
| `step.unknown`    | --                    | Uncategorisable behaviour (template fallback).                        |

These combinations are enforced by the `Behavior` model validator, which checks `(step_type, verb)` pairs. Any pair outside the valid set raises on construction. `Behavior` also forbids input keys it does not define, so an unexpected field raises there too rather than being silently dropped.

## Policy enforcement points

Policies are evaluated at two enforcement points:

1. **Agent registration** — once, before the first task begins. Policies with `enforcement_point: agent_registration` run against the agent's metadata (purpose, tools, classification).
2. **Every step** — before each step executes. Policies with `enforcement_point: step_execution` run against the intended Behavior and the task's history.

At `step_execution`, all 12 behaviour types follow the policy-evaluation path. A rule without a step-type filter sees task-boundary behaviours as well as action behaviours. `working_hours_only`, for instance, checks the clock on every behaviour it sees, and `task.idle` keeps that check active during a long pause.

## Properties

Everything beyond the `(step_type, verb)` pair lives in `properties` — a nested dict that policies can inspect. Properties distinguish a `step.resource` reading `customer-data` from one reading `product-data`. The type is the same; the property is different.

Standard property groups:

| Group     | Purpose                                  | Example keys                                      |
| --------- | ---------------------------------------- | ------------------------------------------------- |
| `target`  | The thing being acted on                 | `domain`, `table`, `object_id`, `system`, `trust` |
| `auth`    | Authentication access level              | `access_level` (read/write/admin), `principal`    |
| `data`    | Payload classification                   | `classification` (pii, public), `fields`          |
| `model`   | LLM details (for `step.model`)           | `provider`, `name`, `parameters`                  |
| `exec`    | Execution details (for `step.exec`)      | `runtime`, `isolation`, `side_effect_class`       |
| `guard`   | Gate details (for `step.gate`)           | `gate_type` (human\_approval, policy\_check)      |
| `message` | Message details (for `step.message`)     | `channel`, `sender`, `recipient`                  |
| `usage`   | Usage metrics (for `step.model` outputs) | `prompt_tokens`, `completion_tokens`, `cost_usd`  |

Custom property groups are permitted. The engine passes them through unchanged, and rule functions read them via dot-path accessors (e.g. `target.table`, `data.classification`).

### Worked example

A `step.resource` GET reading customer data:

```python
from kyvvu_engine.schemas import Behavior, StepType, Verb

Behavior(
    agent_id="agent-123",
    task_id="task-abc",
    step_type=StepType.step_resource,
    verb=Verb.GET,
    step_name="read_customer_record",
    input={"customer_id": "CUST-9981"},
    properties={
        "target": {
            "system": "salesforce",
            "table": "customer-data",
            "domain": "internal.crm.acme.com",
        },
        "auth": {"access_level": "read", "principal": "agent-123"},
        "data": {"classification": "pii", "fields": ["name", "email", "phone"]},
    },
)
```

A policy using the `domain_allowlist` rule could check `target.domain`. A policy using `pii_in_request` could scan the input for sensitive patterns. The `history_contains` rule could check whether this behaviour has already occurred in the task.

***

## Mapping from frameworks

Templates bridge framework-specific events to the behavior vocabulary above. Each template is a YAML file with ordered rules that map event types (e.g. LangChain's `on_llm_start`, or a decorator's `step_type`) to `(step_type, verb)` pairs with property extraction. See [Templates](/core-concepts/templates.md) for how this works, and the [Template Authoring Guide](/integrations/authoring.md) for how to write your own.

***

## Next steps

* [Policies and Rules](/core-concepts/policies.md) — how policies use behaviour types and properties to make decisions
* [Templates](/core-concepts/templates.md) — how the SDK maps framework events to this vocabulary
* [Built-in Rules Reference](/policy-authoring/rules-reference.md) — all 27 rules and which behaviour types they operate on
