Appearance
Routine YAML reference โ
A custom routine is a saved, multi-step procedure one of your agents runs on your behalf. There are two ways to build one:
- Describe it in chat โ tell your Personal Assistant what you want and it writes the routine for you. That's the Custom routines page, and it's the easiest path.
- Write the YAML yourself โ open a custom routine in the built-in editor and edit its spec directly as text. That's this page: the full schema, every field, and worked examples for power users who'd rather type than talk.
Both paths produce the exact same thing. Anything you can describe in chat you can also write as YAML, and a routine the assistant wrote is just YAML you can open and tweak.
This is the power-user reference
YAML, cron expressions, and {input}/{previous} tokens all show up here โ that's the point. If that's not your thing, the conversational path gets you the same routine without touching a single field.
Opening the editor โ
The editor is a real YAML text editor (syntax highlighting, inline errors) that lives on an agent's Tasks tab.
| Toโฆ | Do this |
|---|---|
| Edit an existing custom routine | Click the Edit button on the routine's card. It loads the routine's current spec as YAML. (On the global Tasks page and the lobby, where there's no per-agent editor, the same thing lives in the card's โฎ "Manage routine" menu โ Edit as text.) |
| Create one from scratch | On an agent's Tasks tab, click + New routine. It seeds a starter template already homed on that agent โ overwrite the fields and Save. |

The editor scrolls top to bottom: your YAML first, then the Automations panel (schedules + triggers โ see Scheduling and Triggering), and the Save and Cancel buttons at the very bottom, after the Automations section โ so a long routine and its automations read as one page.

When you press Save, MyChatBot validates the spec:
- Valid โ the routine is saved (or created) and the card refreshes.
- Invalid โ a red "This routine has problems:" box lists every problem at once, and the editor stays open with your text intact so you can fix them and Save again. Nothing is saved until it's valid.
Only your own routines
The Edit button appears only on custom (account-owned) routines. Built-in routines that ship with an agent have no Edit button โ that's how you know they're read-only; you can't rewrite their steps. The editor header even reminds you: "Advanced editing โ you can also just ask your assistant to change this routine."
Your first routine โ
Here is a complete, valid one-step routine. Every line is explained below.
yaml
name: daily-standup-notes
display_name: Daily standup notes
description: Summarize what happened on the account yesterday in three bullets.
archetype: personal-assistant
steps:
- title: Write the summary
prompt: |
Summarize what happened on my account yesterday in exactly three
short bullets: what customers asked, what went unanswered, and the
one thing worth doing today. If I named a focus area, weight it: {input}| Field | What it is |
|---|---|
name | A slug โ lowercase letters, digits, and hyphens (daily-standup-notes). It's the routine's id, unique within your account. Can't collide with a built-in routine's name. |
display_name | The friendly name shown on the card. Optional โ if you leave it out, it's derived from name. |
description | One or two sentences, in your own words, describing what the routine does. Required. |
archetype | The routine's home agent โ which agent owns it and whose Tasks tab it appears on. Name it by slug (personal-assistant) or by display name (Personal Assistant). |
steps | The list of steps, run top to bottom. 1 to 8 steps. |
steps[].title | A short label for the step, shown in the live progress list. Required. |
steps[].prompt | What the step should do, written like an instruction you'd type into that agent's chat. Required. |
The run flow: press Run on the card, and MyChatBot starts the routine in its own conversation. Step 1's prompt runs on the home agent, its result lands in the thread, and โ since there's only one step โ the routine finishes. Each step is a full, billed agent run and shows up on your Usage page.
Two tokens you can drop into any prompt
{input}โ the run message (whatever you type in the Run box, or the routine'srun_messagedefault, or a schedule's message). Empty if you didn't give one.{previous}โ the previous step's output. On step 1 it's empty (there's no previous step). See the next section.
Multiple steps: passing data with {previous} โ
Steps run in order, and each one can read the one before it through {previous}. That's how you chain work: gather in step 1, transform in step 2, report in step 3.
yaml
name: competitor-price-check
display_name: Weekly competitor price check
description: Pull our prices, compare them against competitors, and flag where we're beaten.
archetype: platform-assistant
run_message: Focus on our three best-selling products.
steps:
- title: Collect our prices
archetype: platform-assistant
prompt: |
List our current products and prices from the connected catalog.
Focus on: {input}
- title: Compare with competitors
archetype: personal-assistant
prompt: |
Here are our prices:
{previous}
Search the web for the same products at our main competitors and
build a short table: product, our price, their price, and the gap.Two things worth calling out:
run_messageis an optional default for{input}. If someone runs this routine without typing anything,{input}becomes "Focus on our three best-selling products." โ so a scheduled or triggered run still has direction.- Each step can run on a different agent. Step 1 runs on the Sales Platform Wizard (
platform-assistant, good with your catalog); step 2 runs on the Personal Assistant (personal-assistant, good at web research). A step's ownarchetypeoverrides the routine-level one; omit it and the step falls back to the home agent. Each step bills on its own agent's model โ see Usage & billing.
Home agent vs. step agent
The top-level archetype is the routine's home โ where the routine lives in the app, and the default agent for any step that doesn't name its own. Each step's archetype is who actually runs that step. If you omit the top-level one entirely, it defaults to step 1's agent.
You can name an agent by its slug or its display name โ use whichever you know. The visible agents on a typical account:
| Slug | Display name |
|---|---|
personal-assistant | Personal Assistant |
platform-assistant | Sales Platform Wizard |
assistant | Chief of Staff |
bulk-text-worker | Bulk Text Worker |
content-director | Content Director |
content-factory | Content Factory |
site-builder | Site Builder |
Any agent you've added from the library or built yourself can run a step too. If you name an agent your account can't see, Save tells you which agents are available.
Picking the model a step runs on โ
By default, each step runs on its agent's usual model โ the one that agent was set up with. You don't have to think about it. But when you want a specific model โ a heavier one for a tricky reasoning step, a cheaper and faster one for a bulk step โ pin it with model.
model works at two levels:
- Routine-level
modelsets the default for every step. - Step-level
modeloverrides it for that one step.
yaml
name: research-and-summarize
description: Research a topic in depth, then write a tight summary.
archetype: personal-assistant
model: claude-sonnet # every step runs on Claude Sonnet by default
steps:
- title: Research
prompt: Research {input} thoroughly and gather the key facts.
- title: Summarize
model: gemini-flash # โฆbut run the quick summary on a cheaper, faster model
prompt: |
Summarize the research below into five bullets:
{previous}How a step's model is chosen โ first match wins:
- the step's own
model, if it has one; - otherwise the routine's
model; - otherwise the step agent's default model (the original behavior โ a routine with no
modelanywhere behaves exactly as before).
Two rules the editor enforces on Save:
- It must be a real model from the catalog. Name it by its alias โ e.g.
claude-sonnet,gpt-5, orgemini-flash. A misspelled or unknown name is rejected, and the error lists valid ones. - It must be able to use tools. Routine steps call tools โ search, browsing, your connected data โ so a model that can't reliably use tools is rejected (it might claim it did something without actually doing it). The general-purpose models are all fine; the ones aimed only at reading images or bulk text aren't.
The card shows what it really runs on
The routine card's "Runs on โฆ" line reflects the model each step actually uses โ so when you pin one, that's what shows, not the agent's default.
Billing follows the model you pick
A heavier model costs more per step; a lighter one costs less. Each step bills on whatever model it runs on โ see Usage & billing.
Human approval gates โ
A step can pause and wait for your OK before it runs. Put an approval on it:
yaml
- title: Publish the page
archetype: site-builder
approval: true
prompt: |
Publish the assembled draft as a live page and give me the link.approval: true gives the pause a standard message. To say exactly what the person is approving, use the object form:
yaml
- title: Send the follow-ups
archetype: platform-assistant
approval:
message: Review the follow-ups above. Approve to send them, or reject to stop.
prompt: |
Send each approved follow-up to its lead through the channel where
we last spoke, and confirm what was sent to whom.When the routine reaches a gated step, it stops and shows an "Your approval is needed" card in the conversation (with your message). Approve runs the step; Reject stops the whole run there. Approvals live in the routine's own conversation, not on the account-wide Approvals page โ see Routines โ Approvals.
The safety rule: anything irreversible needs a gate
A step without an approval gate physically cannot send messages, place or schedule calls, start outreach, publish or change live pages, or write knowledge entries โ even if its prompt tells it to, and even if the prompt claims you already approved. Ungated steps are held to read-and-draft work so a routine can run unattended (on a schedule or trigger) without doing something irreversible while you're away.
If a step must take a real, outside-world action, it needs approval. That's not a suggestion the prompt can talk its way around โ it's enforced. This is also the answer to "why did my step refuse to send?" (see the FAQ).
Early exits: stop when there's nothing to do โ
Sometimes a routine should bail out gracefully โ "no quiet leads this week, so there's nothing to follow up on." That's early_exit. You give it a sentinel (a distinctive token) and a friendly message:
yaml
steps:
- title: Find quiet leads
archetype: platform-assistant
prompt: |
List my leads that went quiet in the last 14 days, one per line.
If there are none at all, reply with exactly NO_LEADS and nothing else.
- title: Draft a follow-up for each
archetype: bulk-text-worker
early_exit:
sentinel: NO_LEADS
message: No quiet leads this week โ nothing to follow up on.
prompt: |
Here are the quiet leads:
{previous}
Write a short, friendly follow-up for each, under 400 characters.How it works: early_exit is checked against the previous step's output, before this step runs. So the pattern is always two steps:
- The step that might find nothing is told to emit the sentinel (here, step 1 answers
NO_LEADSwhen there are no quiet leads). - The next step carries the
early_exit. If the previous step's output contains the sentinel, the routine stops early and shows your message โ step 2 (and everything after) never runs, and never bills.
early_exit can't sit on the first step
The sentinel is matched against the previous step's output, and step 1 has no previous step. Put the early_exit on the step after the one that emits the sentinel. Save will reject it on step 1.
Scheduling it โ
A routine doesn't have to wait for you to press Run. Add an optional top-level schedules: block and it runs on a clock. Each entry is a standard 5-field cron expression plus an optional timezone and run message:
yaml
schedules:
- cron: "0 9 * * 1" # every Monday at 09:00
timezone: Europe/Kyiv
run_message: Look at leads from the last 14 days.| Key | What it is |
|---|---|
cron | A 5-field cron expression: minute hour day month weekday. Quote it โ the leading digits and * aren't valid unquoted YAML. |
timezone | An IANA timezone name (UTC, Europe/Kyiv, America/New_York). Optional; defaults to UTC. |
run_message | What {input} becomes for scheduled runs. Optional; falls back to the routine's own run_message. |
Common cron cadences:
text
0 9 * * * # 09:00 every day
0 9 * * 1 # 09:00 every Monday
*/30 * * * * # every 30 minutes
0 8 1 * * # 08:00 on the 1st of each month
30 6 * * 1-5 # 06:30 MondayโFridaySchedules are reconciled when you Save. Adding an entry creates a schedule; editing one (change the cron or timezone) updates it; removing an entry deletes that schedule. Deleting a schedule is safe โ nothing outside MyChatBot depends on it. You can have up to 5 schedules per routine.
No schedule yet? The editor shows you the shape
When a routine has no schedules, the editor drops in a commented-out example so you can see the exact syntax โ uncomment it, edit the cron, and Save.
The same schedules also appear in the Automations panel below the editor, and you can create them there or by asking your assistant. See Tasks & schedules for how scheduled runs behave.
Triggering it โ
A trigger starts your routine when something happens โ an outside service calling a secret link (a form submission), or an event in a connected app like a Stripe payment or a new Gmail email (app-event triggers) โ rather than on a clock.
In the YAML, triggers are view-only. Any that exist appear as a read-only comment so you can see, at a glance, what starts this routine:
text
# โโ Triggers (view-only โ add or remove in the Automations panel) โโ
# โก new-lead-form โ https://api.mychatbot.app/hooks/<id>/<secret>You add and remove triggers in the Automations panel below the editor (not in the YAML), for two reasons:
- The link carries a secret. A trigger's URL is effectively a password โ anyone who has it can fire your routine. It lives in the panel with a Copy button (viewable there any time), where it doesn't belong pasted into an editable text field you might share.
- Deleting it breaks whatever calls it. An outside form or tool is posting to that URL. Removing a trigger should be a deliberate action in the panel, not a side effect of tidying up your YAML.
To wire one up, open the Automations panel โ Triggers โ Add secret link, copy the URL it reveals, and paste it into your outside tool. (App-event triggers have no URL โ create those by chatting: "when a payment comes in on Stripe, run this routine.") Full details โ queuing, duplicate handling, limits โ are on the Triggers page.

A complete worked example โ
Here's a realistic weekly lead-nurture routine that uses everything above: five steps across three agents, an early exit when there's nothing to do, a single approval gate on the one step that messages customers, and a weekly schedule. This is the capstone โ every line is valid and commented.
yaml
# โโ Weekly lead nurture โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
name: weekly-lead-nurture
display_name: Weekly lead nurture
description: Find leads that went quiet, draft a follow-up for each, send after I approve, then log a summary.
archetype: personal-assistant # home agent โ where this routine lives
run_message: Look at leads from the last 14 days.
steps:
# 1 ยท Gather the leads (read-only). Told to emit a sentinel when there's
# nothing to do, so step 2 can bail out cleanly.
- title: Find quiet leads
archetype: platform-assistant
prompt: |
Look through my leads and chats for people who went quiet or were
never answered in this window: {input}
List each one with a note on where the conversation stalled.
If there are no quiet leads at all, reply with exactly NO_LEADS
and nothing else.
# 2 ยท Stop early if step 1 found nothing โ checked against step 1's output.
- title: Draft a follow-up for each
archetype: bulk-text-worker
early_exit:
sentinel: NO_LEADS
message: No quiet leads this week โ nothing to follow up on.
prompt: |
Here are the quiet leads:
{previous}
Write a short, friendly follow-up for each lead, matched to where
their conversation left off. Keep each under 400 characters.
# 3 ยท Review the drafts (read-only) before anyone approves sending.
- title: Sanity-check the drafts
archetype: personal-assistant
prompt: |
Review these drafts:
{previous}
Flag anything off-tone, duplicated, or missing a clear next step,
then produce the cleaned-up final list, ready to send.
# 4 ยท The ONLY step that touches the outside world โ behind a gate.
- title: Send the approved follow-ups
archetype: platform-assistant
approval:
message: Review the follow-ups above. Approve to send them, or reject to stop.
prompt: |
Send each approved follow-up to its lead through the channel where
we last spoke, and confirm what was sent to whom.
# 5 ยท Log what happened (read-only).
- title: Write a short summary
archetype: personal-assistant
prompt: |
Based on what was sent:
{previous}
Write a two-line summary for my records: how many follow-ups went
out, and anything that needs a human touch next week.
schedules:
- cron: "0 9 * * 1" # every Monday at 09:00
timezone: Europe/Kyiv
run_message: Look at leads from the last 14 days.Read it top to bottom: it collects leads, exits early if there are none, drafts and sanity-checks (both read-only, so they run unattended safely), pauses for your approval before the one step that actually messages people, then logs a summary โ and it does all of this every Monday at 9am on its own.
Field reference โ
Top-level โ
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string (slug) | Yes | โ | ^[a-z0-9][a-z0-9-]*$, โค 64 chars. Unique per account; can't be a built-in routine's name. |
display_name | string | No | derived from name | โค 80 chars. |
description | string | Yes | โ | โค 300 chars. One or two sentences. |
archetype | string | No | step 1's agent | The home agent โ slug or display name of a visible agent. |
model | string | No | each step's agent default | Pins the model every step runs on. A catalog alias (e.g. claude-sonnet, gpt-5, gemini-flash); must be able to use tools. A step's own model overrides it. See Picking the model. |
run_message | string | No | โ | Default value for {input} when a run gives none. โค 2000 chars. |
steps | list | Yes | โ | 1 to 8 steps, run in order. |
schedules | list | No | โ | Up to 5 entries; reconciled on Save (see Scheduling). |
Per step โ
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
title | string | Yes | โ | โค 80 chars. Shown in the live progress list. |
prompt | string | Yes | โ | โค 4000 chars. Supports {input} and {previous}. |
archetype | string | No | the routine's home agent | The agent that runs this step โ slug or display name. |
model | string | No | routine model, else the step agent's default | Pins the model this step runs on. A catalog alias (e.g. claude-sonnet, gpt-5); must be able to use tools. Overrides the routine-level model. See Picking the model. |
approval | true / false / { message } | No | false | A human approval gate before the step runs. message โค 500 chars. Required for any step that sends/publishes/mutates. |
early_exit | { sentinel, message } | No | โ | Stops the routine if the previous step's output contains sentinel. sentinel โค 64 chars, message โค 500 chars. Not allowed on step 1. |
Schedule entry โ
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
cron | string | Yes | โ | 5-field cron: minute hour day month weekday. Quote it. |
timezone | string | No | UTC | IANA name, e.g. Europe/Kyiv. |
run_message | string | No | routine's run_message | What {input} becomes for this schedule's runs. |
name | string | No | auto-generated | Optional label for the schedule, unique within the routine (โค 128 chars). Handy if you keep several โ otherwise leave it out. |
Caps โ
| Limit | Value |
|---|---|
| Steps per routine | 8 |
| Custom routines per account | 10 |
| Schedules per routine | 5 |
| Prompt length | 4000 characters |
| Whole-spec size | 64 KB |
Reserved / auto-computed fields โ
tagโ each step gets an internaltag, derived from itstitle, used to track the step. It's computed for you; if you include one it's ignored. You never need to set it.- Any unknown key โ at the top level or on a step โ is a validation error, so a typo (
prompts:instead ofprompt:) is caught on Save rather than silently ignored.
When Save finds problems โ
Validation reports every problem at once, so you can fix them in one pass rather than one-Save-per-error. Typical messages:
text
This routine has problems:
- 'description' is required (one or two sentences).
- steps[2]: archetype 'growth-hacker' is not available on this account โฆ
- steps[1]: 'early_exit' is not allowed on the first step โฆ
- too many steps: 9 > 8 โฆThe editor keeps your text exactly as you left it while you fix them.
Tips & FAQ โ
Why did my step refuse to send / publish / message anyone? Because it has no approval gate. Ungated steps are locked to read-and-draft work so a routine is safe to run unattended. Add approval: true (or an approval with a message) to that step, and it'll be allowed to act once you approve it. See the safety rule.
Can I edit a routine while a run is paused at an approval gate? Yes โ you can Save changes any time. But a run that's already in flight (including one paused on an approval card) keeps the version of the spec it started with. Your edits take effect on the next run.
Where does the routine "live"? On its home agent โ the top-level archetype. That's whose Tasks tab shows the card. Change archetype and Save to move the routine to a different agent. (Each step still runs on its own step-level agent regardless.)
Do I have to use slugs for agents? No โ a display name works too (Sales Platform Wizard, Personal Assistant), and it's case-insensitive. Slugs are just the canonical form. If you name an agent your account can't see, Save lists the ones you can.
I edited schedules in the YAML and in the Automations panel โ which wins? The last Save wins. The schedules: block and the Automations panel (and the assistant) all edit the same schedules. If you change them in two places around the same time, whichever you Save last is the final state โ so pick one surface per editing session to avoid surprising yourself.
Can I add a trigger by typing it into the YAML? No โ triggers are view-only in the YAML. Add and remove them in the Automations panel, because the link is a secret and deleting one breaks whatever outside tool is calling it. See Triggers.
See also โ
- Custom routines โ the conversational way to build the same thing
- Routines โ how running, progress, approvals, and stopping work
- Triggers โ start a routine when something happens outside
- Tasks & schedules โ how scheduled runs behave
- Your team & the agent library โ the agents a step can run on
- Custom agents โ build an agent to run a routine's steps
- Usage & billing โ how each step bills