# Templates

> **Note:** This page covers **behavior templates** — YAML rules that map framework events to Kyvvu Behaviors. For **policy manifests** (compliance policy sets assigned to agents), see [Manifests](/policy-authoring/templates.md).

**What you'll learn:** How YAML templates map framework events to Behaviors, how matching works, and how to customize templates.

***

## What templates do

Templates are the translation layer between your framework's events and Kyvvu's canonical vocabulary. When your agent calls an LLM, reads a database, or sends a message, the SDK needs to know which `(step_type, scope, verb)` tuple to use, and which properties to set. Templates define this mapping.

Without templates, every integration would need hardcoded mappings. With templates, the same SDK can support any framework — you just write a YAML file.

## Built-in templates

The SDK ships with two built-in templates:

```python
from kyvvu.templates import BehaviorTemplate

decorator_template = BehaviorTemplate.from_builtin("decorator")
langchain_template = BehaviorTemplate.from_builtin("langchain")
```

* **`decorator`** — for the `@kv.step` decorator integration. Maps decorator arguments directly to Behavior fields.
* **`langchain`** — for the LangChain/LangGraph callback handler. Maps LangChain callback events (`on_llm_start`, `on_tool_start`, etc.) to Behaviors.

## How matching works

Templates use **first-match-wins** rule evaluation. Each template contains an ordered list of rules. For each framework event, the SDK walks the rules top to bottom and uses the first match.

Each rule has:

* **Conditions** — predicates on the framework event (event type, function name, arguments).
* **Output** — the Behavior fields to set (`step_type`, `scope`, `verb`, `properties`).

If no rule matches, the template falls back to `step.unknown`.

## Deep-merge semantics

When the SDK constructs a Behavior, it deep-merges three sources (in order of priority):

1. **Caller overrides** — values passed explicitly via `@kv.step(properties={...})` or `kv.start_task(properties={...})`.
2. **Template output** — the matched rule's output.
3. **Framework defaults** — base values from the framework event itself.

**Caller overrides win at leaves.** If the template sets `properties.model.provider = "openai"` and the caller sets `properties.model.name = "gpt-4o"`, the result is `{model: {provider: "openai", name: "gpt-4o"}}`. But if the caller sets `properties.model.provider = "anthropic"`, the caller's value wins.

## Two tiers of developer effort

Templates support two levels of detail:

### Lazy (generic fallback)

Use the built-in templates without customization. Every step gets a correct `step_type` and `verb` based on the framework event. Properties are sparse — mostly framework-inferred defaults.

This is fine for getting started and for development-time tracing.

### Rich (named rules with properties)

Write a custom template with rules that match specific functions and set detailed properties — target system, data classification, auth scope, domain. This enables fine-grained policies that check properties like `target.table == "customer-data"` or `target.trust == "external"`.

This is what production deployments use.

## Loading custom templates

Three ways to use a custom template:

```python
# Constructor kwarg
custom = BehaviorTemplate.from_path("/path/to/template.yaml")
kv = Kyvvu(api_key="...", agent_key="bot", template=custom)

# Environment variable
# export KV_TEMPLATE_LOCATION=/path/to/template.yaml
kv = Kyvvu(api_key="...", agent_key="bot")

# Inline from string
custom = BehaviorTemplate.from_string(yaml_content)
```

## Template YAML structure

A minimal template:

```yaml
name: my-agent-template
version: "1.0"

rules:
  - name: llm_call
    conditions:
      step_type: step.model
    output:
      properties:
        model:
          provider: openai
          name: gpt-4o

  - name: db_read
    conditions:
      step_name: read_customer
    output:
      step_type: step.resource
      scope: step
      verb: GET
      properties:
        target:
          system: postgres
          table: customer-data
          trust: internal
        data:
          classification: pii

  - name: fallback
    conditions: {}
    output:
      step_type: step.unknown
```

Rules are evaluated in order. The `fallback` rule with empty conditions matches everything and should be last.

***

## Next steps

* [Python Decorator](/integrations/decorator.md) — how `@kv.step` uses templates
* [LangChain / LangGraph](/integrations/langchain.md) — the LangChain callback handler and its template
* [Writing a New Integration](/integrations/custom.md) — how to author templates for other frameworks


---

# 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/core-concepts/templates.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.
