For the complete documentation index, see llms.txt. This page is also available as Markdown.

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.

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, verb) pair 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 template engine (loading, matching, interpolation) lives in kyvvu_engine.templates. The SDK ships the bundled template YAML files and a small load(name) helper that returns an engine BehaviorTemplate:

from kyvvu.templates import load

decorator_template = load("decorator")
langchain_template = load("langchain")

The SDK bundles four per-integration templates:

  • 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.

  • langgraph — for LangGraph graph executions.

  • crewai — for CrewAI agents.

Each integration (and kyvvu-claude) loads its own template by path. To load any template file directly, use the engine loader:

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:

  • match — predicates on the event context: an exact-equality check on any context key (event, step_type, verb, a dot-path such as serialized.name) and, for names, a name_pattern regex.

  • behavior — the Behavior fields to set: step_type, step_name, verb and properties.

name_pattern is the one regex key, on every surface, tested against the context's name (the decorated function's name, or a callback's tool, model or chain name). It is a case-insensitive re.search, so it matches anywhere in the name; anchor with ^ and $. A context with no name never matches it.

The template does not invent a fallback. If no rule matches, match() returns nothing and the integration decides: a callback handler records the event as step.unknown (and logs a warning once per event), and the decorator builds the step from its own arguments. The built-in templates end with a match: {} catch-all so that the outcome is visible in the template itself.

Where task boundaries come from

An integration's template governs both the steps it records and the task boundaries it opens (task.start, task.end, task.error). The Kyvvu client's own template covers start_task() and friends and the decorator. Each callback handler uses the template passed to it, so a custom template for a handler must contain its boundary rules. See Writing a Custom Template for which boundaries each integration opens.

Deep-merge semantics

When the SDK constructs a Behavior, it deep-merges two 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 behavior.

(A LangChain tool's own metadata["kyvvu"] is a third layer that sits above the template; see the next section.)

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.

Template properties vs. tool metadata

For LangChain and LangGraph, a tool can declare its own Kyvvu attributes under metadata["kyvvu"], co-located with the tool definition. Those attributes deep-merge over the template-matched properties: the tool's value wins on any leaf conflict, siblings from the template are preserved, and a runtime warning is logged when a tool overrides a template-set property. In short, code wins over the org baseline. See LangChain / LangGraph — Attaching Kyvvu attributes to tools for the full picture.

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 access level, 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

A custom template replaces the built-in for the integration it is given to. It does not extend it, and there is no fall-through to the built-in. Start from a copy (kyvvu template show langchain > my.yaml) so the boundary rules are already there.

Two ways to use a custom template:

The default for every template argument is the sentinel kyvvu.default_template ("the built-in, or KV_TEMPLATE_LOCATION"). template=None means no template: the client accepts it for @kv.step and add_step but refuses start_task(), and the callback handlers refuse it.

Template YAML structure

A minimal template:

A template passed to the Kyvvu client must match all four task boundary types by step_type (task.start, task.end, task.error, task.idle); the example above omits them to stay short. Every rule has an id (unique), a match and a behavior. The loader rejects a template that breaks this, naming the rule and the fix: a missing or duplicate id, a missing match or behavior, an unknown rule key, an unknown behavior key, or a step_type or verb outside the vocabulary. conditions and output are not keys; they are match and behavior. A match key that no integration sets is allowed but logged as a warning, so a typo is visible.

Rules are evaluated in order. The fallback rule with an empty match (match: {}) matches everything and should be last.


Next steps

Further reading

  • Template Authoring Guide — step-by-step walkthrough for creating a custom behavioral template, including match semantics, property extraction, and a worked example.

  • Agent Pattern Templates — reference snippets for common agent architectures (RAG, ReAct, human-in-the-loop, multi-agent) that show how to map these patterns to Kyvvu's behavior vocabulary.

Last updated