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

Routines

Routines are graphs of nodes — chat, tool, and routing-only (fork) nodes connected by transitions. This page defines the node types and their runtime completion semantics.

Context — Routines are the structured-flow building block of an agent (the cross-cutting one is policies). This page is the definitive model; Authoring routines is the hands-on companion. If you read only one warning on this page, read the node types.

YAML examples follow manifest schema 6.1.5. Manifest and content shapes are schema-versioned and differ across runtime versions — see Versioning & compatibility.

What a routine is

A routine is a versioned YAML document describing a graph the agent walks through across one or many turns: nodes carry actions, and each node lists its outbound transitions. Execution starts at the node named by entry.

id: car-search
title: Car Search
conditions:
  - >
    The user wants to browse the fleet, find a car, or asks for car
    suggestions — phrases like "what cars do you have", "show me an SUV",
    "I need a 7-seater". Do NOT activate when the user is referring to a
    specific booking they already have.
description: >
  Help the user narrow down the fleet to one or two candidate cars by
  collecting their criteria, searching the catalog, and presenting results
  with prices.

entry: gather-criteria
nodes:
  - id: gather-criteria
    chat_state: >
      Ask the user for their preferences in one short message: category
      (economy / compact / SUV / van / luxury), minimum number of seats,
      transmission preference, and any daily-budget cap in EUR. Tell them
      any field is optional.
    transitions:
      - to: run-search
        condition: >
          The user has provided at least one preference, or has said
          "anything" / "no preference".

  - id: run-search
    tools: cars:search_cars
    tool_instruction: >
      Call search_cars with the filters the user provided. Pass null /
      omit fields the user did not mention. Do not invent constraints.
    transitions:
      - to: present-results

  - id: present-results
    chat_state: >
      Summarise the matching cars in a compact list — one line per car
      with make, model, category, transmission, and daily price in EUR.
      End by asking if the user wants to book one.

Top-level fields

Field
Type
Required
Default
Meaning

title

string

yes

Display name in the platform UI, traces, and logs.

conditions

string or list of strings

yes (≥ 1 non-empty)

When the routine activates. Evaluated like policy conditions; the routine activates when any condition matches.

entry

string

yes

Id of the node where execution starts. Must match a declared node id.

nodes

list of node objects

yes (≥ 1)

The graph (below). Each node is declared exactly once; node ids must be unique.

id

string

no

null

Optional in-document id. Identity actually comes from the catalog name the document is published under — that name is what the manifest's context.routines[].id references.

description

string

no

null

Long-form purpose. Not used for matching.

policies

list of policy objects

no

null

Routine-scoped policies (each requires an explicit id) — see Policies.

autonomous

object

no

null

Makes the routine triggerable as a typed automation — see Autonomous routines.

Node fields

Field
Type
Required
Default
Meaning

id

string

yes

Unique within the routine. Referenced by entry and by transitions[].to.

description

string

no

null

Author note; surfaced in traces, never shown to the customer.

tools

string or list of strings

no

null

TOOL node: tool id(s) to call, service:tool form (a bare string is normalised to a one-element list).

tool_instruction

string

no

null

TOOL node: how to call the tool(s) — parameter mapping, derivation rules. Never shown to the customer. Requires tools.

chat_state

string

no

null

CHAT node: instruction for what the agent should say. Supports ${macro-id} interpolation — see Glossaries & macros.

transitions

list of {to, condition?}

no

[]

Outbound edges. Omitted/empty = terminal node. With 2+ entries, every transition requires a condition.

think

string

no

null

Autonomous routines only — the typed-inference (THINK) node instruction. Not used in conversational routines; see Autonomous routines.

output_schema

object

no

null

Autonomous routines only — JSON Schema validating think's structured output. Required on think: nodes; rejected on any other node.

Machine-validated rules (enforced by the published JSON Schema): unique node ids; entry and every transitions[].to must name declared nodes; tools is mutually exclusive with chat_state; tool_instruction requires tools; a node must carry an action (tools or chat_state) or at least one transition; 2+ transitions ⇒ all conditioned; malformed ${…} macro tokens in chat_state are rejected. (The schema also defines the think/output_schema node used by autonomous routines.)

Node types: read this first

A conversational routine is built from three node types. Each node is exactly one of them, determined by its action field:

Node type
Set by
What it is

CHAT

chat_state

Speaks to the customer. Completes when the agent sends a message fulfilling the instruction. May interpolate ${macro-id}.

TOOL

tools (+ tool_instruction)

Calls one or more tools. Completes when the tool executes — it produces no message of its own.

Routing-only (the fork)

no action field, 2+ conditional transitions

A pure branch point — no tool call, no message. The engine evaluates the outgoing conditions and takes the matching path. This is how a routine forks.

A fourth node type — THINK (typed inference) — exists only for autonomous routines. It has no customer-facing output, so it is not used in conversational routines; if you need a routine to reason over typed data, that's an autonomous routine.

⚠️ The classic bug. tools and chat_state on the same node is rejected by the schema — and for good reason: "call the handoff tool and tell the customer they're being transferred" must be two nodes. A tool node's customer-facing output always belongs in a follow-up chat node.

Runtime semantics by node kind

CHAT node: completes when the agent speaks

The engine generates a message fulfilling the chat_state instruction; that message ends the turn. If the outbound transition's condition depends on the customer's answer, the routine waits on the customer before advancing. Two CHAT nodes can never run in the same turn.

TOOL node: completes when the tool executes

The engine calls the tool(s) per tool_instruction, appends the results to history, and immediately re-evaluates — walking the node's transitions within the same turn. Chains of TOOL nodes execute back-to-back without customer interaction.

Each chained think/tool node consumes one iteration of the per-turn engine loop, bounded by runtime.max_engine_iterations (default 5). A routine that chains more nodes than that back-to-back before reaching a message or terminal node has its turn cut off mid-chain — the engine logs a WARNING and responds anyway with whatever it has, nothing surfaced to the caller. Keep such chains within the cap, or raise it.

(Need a node that reasons over typed data instead of speaking or calling a tool? That's a THINK node, which lives in autonomous routines — not in conversational routines.)

Routing-only node (fork): completes immediately

No action — just conditional transitions. The engine evaluates the outgoing conditions and takes the matching branch. This is the routine's fork: use one wherever the flow splits on a decision rather than on a tool call or a message.

"Completes immediately" means it never produces a message or consumes a turn — it does not mean the branch choice is free. A fork with two or more outgoing transitions still requires a model call to pick between them, the same next-step selection used by other node kinds. Only a node with a single outgoing edge (fork or otherwise) takes the zero-model fast path.

Transitions, terminals, and movement

  • A transition's condition decides when that edge is followed. A node with exactly one transition may omit the condition (unconditional); a node with 2+ transitions must condition every one.

  • No transitions = terminal node. When a terminal node completes, the routine is done. (In autonomous routines, terminal nodes must call built-in:emit_output.)

  • Fan-in and cycles are allowed — any node id can be the target of multiple transitions, including loops back to earlier nodes ("ask again until the data validates").

  • The engine can backtrack: if the customer revisits an earlier topic ("actually, change the dates"), evaluation can re-enter a previous node rather than forcing forward-only movement.

  • Activation and advancement decisions are evaluation-model calls — see Conversation lifecycle.

Referencing from the manifest

Pins are exact versions from the platform catalog. At boot, the server also pre-computes behavioural metadata for every routine, in two sequential stages: customer-dependence is computed first, then node reachability, which reads the customer-dependence result. On a cold cache this is the slow part of startup — see Startup evaluation.

See also

Last updated

Was this helpful?