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

Authoring routines

Building routines node by node: the golden rule, transitions and branching, tool chains, loops, common patterns, anti-patterns, and the pre-submit checklist.

Context — This guide assumes the Routines concept page (node kinds, classification, completion semantics). Here we build up a real routine and collect the patterns that keep flows reliable.

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

The golden rule

A node does exactly one thing. It calls tools, or speaks, or routes. Never two of these at once. (A fourth kind — the typed-inference THINK node — belongs to autonomous routines, not conversational ones.)

Wrong — the schema rejects tools + chat_state on one node, and for good reason:

  - id: handoff
    tools: crm:initiate_human_handoff
    tool_instruction: "Initiate human handoff."
    chat_state: "Inform the customer they are being transferred."  # REJECTED

Right — two nodes connected by a transition:

  - id: handoff-tool
    tools: crm:initiate_human_handoff
    tool_instruction: "Initiate human handoff."
    transitions:
      - to: handoff-msg

  - id: handoff-msg
    chat_state: >
      Inform the customer they are being transferred to a human agent.

Activation conditions

conditions decide when the whole routine engages. Same craft as policy conditions: concrete phrasings, explicit boundaries against sibling routines.

A booking routine and a search routine live side by side precisely because each condition names its own triggers and excludes the other's ("Do NOT activate when the user is referring to a specific booking they already have").

Conditions and chat_state texts reach the model exactly as authored, so YAML block style matters — see policy rule 4 for when to use a literal block (|) versus a folded block (>).

The graph: entry, transitions, terminals

Execution starts at the node named by entry. Edges live on the node that produces them:

The rules to internalise:

  • One transition → condition optional (unconditional advance).

  • Two or more transitions → every one needs a condition. The engine evaluates them and takes the matching branch.

  • No transitions at all → terminal node. The routine completes there.

  • Loops are first-class. Transition back to an earlier node id to re-ask until the answer validates — no special syntax.

Tool nodes: instructions are parameter maps

tool_instruction tells the model how to call the tool — which arguments, derived from where, in what format. It is not customer-facing and should contain zero messaging:

Multiple sequential tools chain naturally (each tool node advances in the same turn). Independent tools can share one node:

Branching: conditions on transitions

The flow splits wherever a node declares multiple conditioned transitions. Action nodes can branch directly:

When a decision point needs no action of its own, use a routing-only node (transitions, no action):

Asking the customer and acting on the answer

A chat node whose transitions depend on the customer's reply is the question-and-dispatch idiom:

The engine waits on the customer after ask-resubmit (the transitions depend on their answer), then takes the matching branch — possibly several turns later, and it can backtrack if they change their mind.

Reusable wording: macro interpolation

When the same explanation must appear verbatim in several flows, publish it as a macro, pin it in the manifest's context.macros, and interpolate it inside chat_state with ${macro-id}:

Only chat_state interpolates macros — tool_instruction and description take literal text.

Anti-patterns

Anti-pattern
Symptom
Fix

Tools + chat_state on one node

Schema rejects it

Split into tool node + chat node connected by a transition

Messaging inside tool_instruction

Tone leaks into tool calls; replies appear before data arrives

Move messaging to the following chat node

Conditions narrating actions ("ask the user X if…")

Transitions that half-do things

Conditions gate; actions act

Mega-nodes ("collect dates, search, present, and offer extras")

The model freelances the ordering

One concern per node

Two chat nodes with no customer-dependent transition between them

Second one never runs in the same turn

Merge the messages or make the dependency explicit

Duplicating a global rule in every routine

Drift between copies

Make it a policy

Deep tool chains exceeding the iteration cap

Turn ends mid-flow / autonomous runs fail with max_engine_iterations_reached

Shorten, parallelise independent tools, or raise runtime.max_engine_iterations

Unconditioned multi-way branches

Schema rejects 2+ transitions without conditions

Condition every branch explicitly

Testing a routine

  1. Deploy it to a staging agent against a stub MCP server (the Quickstart builds one end to end) and walk the happy path through the chat UI.

  2. Probe each branch: phrase inputs that should take every transition, including the "changed my mind" backtrack.

  3. Watch the trace for the turn — it shows activation, node selection, and each tool call; see Observability.

  4. Check boot output: every routine logs Routine '<title>' evaluated: N nodes in Xs at startup — failures there mean structural problems.

Pre-submit checklist

Last updated

Was this helpful?