DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS /// DOCS
ROUTINES·CHAIN ROUTINES

Chain Routines

A Chain Routine — called Chains in the UI — is a multi-step pipeline that sequences Functions, Agent steps, and conditional branches into a single automation. Where a Function does one thing and an Agent Routine sends one prompt, a Chain orchestrates many steps that depend on each other, route based on outputs, and pass data forward.

Chains are the only Routine type with an execution cost: 2 credits per execution, available on paid plans only.


What a Chain is

A Chain is defined as a directed graph of steps. The graph is stored in the chain_definition field on the Routine — a JSON structure that lists each step with its id, type, inputs, and the ids of the steps to run on success and on error:

{
  "steps": [
    {
      "id": "fetch",
      "type": "function",
      "function_id": "<uuid>",
      "input_template": { "tableId": "{{TABLE_ID}}" },
      "on_success": "score",
      "on_error": null
    },
    {
      "id": "score",
      "type": "agent",
      "instruction": "Score the leads in {{fetch.leads}}. Output JSON: { scores: [...] }",
      "on_success": "route",
      "on_error": null
    },
    {
      "id": "route",
      "type": "conditional",
      "condition": "{{score.scores[0].value}} >= 0.7",
      "on_true": "assign_hot",
      "on_false": "send_nurture"
    }
  ]
}

You build a Chain by editing the chain_definition JSON directly in the Routine panel. The definition structure is described below.

When a Chain fires, Onnie walks the graph from the first step, executing each step in sequence, collecting outputs into scoped variables that subsequent steps can read. The entire run is a single routine_run row; individual step results are stored in the run's output payload.

Function steps within a Chain call Supabase directly — no AI dispatch layer is involved. Agent steps use the engine, which means those steps consume AI credits on top of the flat 2-credit execution fee.


Step types

Function step — runs a workspace function. You select the function by id and provide an input template for this step. The template can reference workspace variables and step outputs from earlier steps using the {{variableName}} or {{stepId.field}} syntax. The function's return value becomes a set of step output variables that later steps can reference.

Function steps are deterministic and do not consume AI credits. They run in the same sandboxed environment as standalone Functions: up to 30-second timeout, up to 256 MB memory.

Agent step — runs the Onnie AI agent with a prompt you define for this step. The prompt can interpolate variables and earlier step outputs directly. The agent's final response text becomes the step output, accessible as {{stepId.output}}. Agent steps consume AI credits based on the complexity of the reasoning and the number of tool iterations.

Conditional step — evaluates a JavaScript expression against available variables and routes to one of two branches: on_true or on_false. The expression has access to all step outputs defined up to this point in the graph. Common patterns:

{{enrich.score}} >= 0.7
{{classify.category}} === "priority"
{{fetch.count}} > 0

A conditional step itself does not execute code or consume credits. It only reads a variable and picks the next step.


Variables across steps

Each step's output is automatically available to subsequent steps. The variable name is the step id plus the output field:

Step idReturn valueReference in later steps
fetch{ leads: [...] }{{fetch.leads}}
enrich{ score: 0.87, category: "hot" }{{enrich.score}}, {{enrich.category}}
classifyAgent text output{{classify.output}}

Workspace variables (secrets and config values) are also available in any step using the same {{VAR_NAME}} syntax. They are resolved before the step executes.

Step output variables are transient — they exist for the duration of the Chain run and are not persisted after the run completes. If you need to carry a value beyond the run (so a future run can read it, or so the value appears in a workspace record), write it explicitly: a Function step can write to a table row, or an Agent step can use the remember tool to store it in workspace memory.

For the full variable reference including secret handling and rotation, see Variables.


Cost

Chains cost 2 credits per execution. This flat fee is charged when the run starts, regardless of how many steps execute, whether the run completes successfully, or whether it fails partway through.

Agent steps inside a Chain consume additional AI credits on top of the flat fee. Those credits are billed the same way as a regular chat turn: based on the model, the number of input tokens, and the number of output tokens and tool iterations.

Function steps and Conditional steps do not consume additional credits beyond the 2-credit flat fee.

//WATCH OUT

Chain Routines are available on paid plans only. Free-plan workspaces cannot activate a Chain. Agent Routines and Functions remain free on all plans.

//TIP

To avoid unexpected credit usage from Agent steps, review your Chain's Agent step prompts and estimate how many tool iterations a typical run will require. Run the Chain manually once with Run now before activating a recurring schedule, and check the credits consumed in Run History.


Example: lead enrichment and routing pipeline

Your workspace has an "Inbound Leads" table. Overnight, new rows arrive from a connector. Each morning you want to enrich each lead, score it with AI, and route it: hot leads go to a Task assigned to your sales Onniebot; cold leads get an automated nurture email.

Step 1 — Fetch new leads (Function step, id: fetch)

Queries the Inbound Leads table for rows created in the last 24 hours with status new. Returns { leads: [{ id, name, email, company }] }.

Step 2 — Enrich each lead (Function step, id: enrich)

Iterates over the leads array, calls an external enrichment API for each using the ENRICHMENT_API_KEY workspace secret. Returns { company_size: "mid", industry: "fintech", monthly_traffic: 42000 } per lead.

Step 3 — Score the lead (Agent step, id: score)

Prompt: "Given the lead data and enrichment output below, assign a score from 0 to 1 and write a one-sentence rationale. Output JSON only: { score: number, rationale: string }. Lead: {{fetch.leads[0]}}. Enrichment: {{enrich}}."

The agent scores the lead and its JSON output becomes available as {{score.score}} and {{score.rationale}}.

Step 4 — Route on score (Conditional step)

Expression: {{score.score}} >= 0.7

  • on_true → Step 5a
  • on_false → Step 5b

Step 5a — Create a sales Task (Function step)

Creates a Task in the Sales project. The task body includes the enrichment data and scoring rationale from earlier steps, formatted for quick review. Assigns the Task to the sales Onniebot, which picks it up, does its own research, and posts a structured reply.

Step 5b — Send a nurture email (Function step)

Calls sdk.email.send() with a polite "we'll be in touch" template. The lead is tagged in the Inbound table as nurture_sent.

This Chain runs daily at 07

. The total cost is 2 credits (flat) plus AI credits for the scoring Agent step — typically 5–10 credits per lead scored. For a batch of 20 overnight leads, expect 100–200 credits on a busy morning.